GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Rearrange Spinbox layout and expose corner radius property
src/layout.rs | 38 ++++++++++++++++++++++++++
src/widget/display/graph.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++
src/widget/input/spinbox.rs | 54 +++++++++++++++++++++----------------
3 files changed, 134 insertions(+), 23 deletions(-)
diff --git a/src/layout.rs b/src/layout.rs
index 6c3eca3..cd23954 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -53,6 +53,7 @@ static NESTED_SECTION_LABEL_ALIGNMENT: RwLock<u8> = RwLock::new(0);
static LABEL_MARGIN: RwLock<f32> = RwLock::new(6.0);
static BUTTON_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
+static SPINBOX_CORNER_RADIUS: RwLock<f32> = RwLock::new(4.0);
/// Standard line height multiplier for text layout in clear-ui.
pub const TEXT_LINE_HEIGHT_MULTIPLIER: f32 = 1.4;
@@ -145,6 +146,15 @@ pub fn reload_config() {
}
}
}
+ if let Some(rest) = trimmed.strip_prefix("spinbox_corner_radius") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val_str = rest.trim_end_matches('"').trim();
+ if let Ok(val) = val_str.parse::<f32>() {
+ if let Ok(mut lock) = SPINBOX_CORNER_RADIUS.write() {
+ *lock = val;
+ }
+ }
+ }
if let Some(rest) = trimmed.strip_prefix("toggle_height") {
let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
let val_str = rest.trim_end_matches('"').trim();
@@ -883,6 +893,34 @@ pub fn set_button_corner_radius(radius: f32) {
}
}
+pub fn spinbox_corner_radius() -> f32 {
+ use std::sync::Once;
+ static INIT: Once = Once::new();
+ INIT.call_once(|| {
+ if let Some(content) = read_config() {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("spinbox_corner_radius") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val_str = rest.trim_end_matches('"').trim();
+ if let Ok(val) = val_str.parse::<f32>() {
+ if let Ok(mut lock) = SPINBOX_CORNER_RADIUS.write() {
+ *lock = val;
+ }
+ }
+ }
+ }
+ }
+ });
+ *SPINBOX_CORNER_RADIUS.read().unwrap()
+}
+
+pub fn set_spinbox_corner_radius(radius: f32) {
+ if let Ok(mut lock) = SPINBOX_CORNER_RADIUS.write() {
+ *lock = radius;
+ }
+}
+
pub fn color_selector_preview_margin() -> f32 {
use std::sync::Once;
static INIT: Once = Once::new();
diff --git a/src/widget/display/graph.rs b/src/widget/display/graph.rs
index 39130b0..c6dfa4a 100644
--- a/src/widget/display/graph.rs
+++ b/src/widget/display/graph.rs
@@ -172,9 +172,74 @@ impl Graph {
}
(x, y)
}
+
+ pub fn zoom_in(&mut self) {
+ if self.grid_size_x < 400.0 {
+ self.grid_size_x *= 1.1;
+ self.grid_size_y *= 1.1;
+ self.skipped_row_h *= 1.1;
+ self.skipped_col_w *= 1.1;
+ }
+ }
+
+ pub fn zoom_out(&mut self) {
+ if self.grid_size_x > 40.0 {
+ self.grid_size_x /= 1.1;
+ self.grid_size_y /= 1.1;
+ self.skipped_row_h /= 1.1;
+ self.skipped_col_w /= 1.1;
+ }
+ }
+}
+
+fn read_zoom_bindings() -> (String, String) {
+ let mut zoom_in_val = "=".to_string();
+ let mut zoom_out_val = "-".to_string();
+ let paths = [
+ "/home/lsgalante/.config/cce/config.toml",
+ "/home/lsgalante/.config/ccec/config.toml",
+ ];
+ for path in &paths {
+ if let Ok(content) = std::fs::read_to_string(path) {
+ for line in content.lines() {
+ let trimmed = line.trim();
+ if let Some(rest) = trimmed.strip_prefix("zoom_in") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val = rest.trim_end_matches('"').to_string();
+ if !val.is_empty() {
+ zoom_in_val = val;
+ }
+ } else if let Some(rest) = trimmed.strip_prefix("zoom_out") {
+ let rest = rest.trim_start_matches(|c: char| c == ' ' || c == '=' || c == '"');
+ let val = rest.trim_end_matches('"').to_string();
+ if !val.is_empty() {
+ zoom_out_val = val;
+ }
+ }
+ }
+ break;
+ }
+ }
+ (zoom_in_val, zoom_out_val)
}
impl Element for Graph {
+ fn keyboard_input(&mut self, event: &KeyEvent, _ctx: &mut UiContext) -> bool {
+ if event.state == ElementState::Pressed {
+ if let Key::Character(ref ch) = event.logical_key {
+ let (zoom_in_binding, zoom_out_binding) = read_zoom_bindings();
+ if ch == &zoom_in_binding {
+ self.zoom_in();
+ return true;
+ } else if ch == &zoom_out_binding {
+ self.zoom_out();
+ return true;
+ }
+ }
+ }
+ false
+ }
+
fn as_any(&self) -> &dyn std::any::Any { self }
fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
fn as_ptr(&self) -> *mut (dyn Element + 'static) {
diff --git a/src/widget/input/spinbox.rs b/src/widget/input/spinbox.rs
index 46ac008..373110c 100644
--- a/src/widget/input/spinbox.rs
+++ b/src/widget/input/spinbox.rs
@@ -112,6 +112,10 @@ impl Element for Spinbox {
Some(crate::layout::spinbox_height())
}
+ fn corner_radius(&self) -> f32 {
+ crate::layout::spinbox_corner_radius()
+ }
+
fn color(&self) -> [f32; 4] { colors::SPINBOX_BG }
fn value(&self) -> i32 { self.value }
fn widget_font(&self) -> Option<String> { Some("monospace".to_string()) }
@@ -125,9 +129,8 @@ impl Element for Spinbox {
self.hover_inc = false;
return changed || was != self.base.hovered;
}
- let split = self.base.x + self.base.w * 0.55;
- let hd = px >= split && px < split + self.base.w * 0.225;
- let hi = px >= split + self.base.w * 0.225;
+ let hd = px >= self.base.x && px < self.base.x + self.base.w * 0.225;
+ let hi = px >= self.base.x + self.base.w * 0.775;
let changed = hd != self.hover_dec || hi != self.hover_inc;
self.hover_dec = hd;
self.hover_inc = hi;
@@ -145,14 +148,16 @@ impl Element for Spinbox {
if !self.hit_test(px, py, ctx) { return false; }
match state {
ElementState::Pressed => {
- let split = self.base.x + self.base.w * 0.55;
- if px >= split && px < split + self.base.w * 0.225 {
+ let btn_w = self.base.w * 0.225;
+ let split_left = self.base.x + btn_w;
+ let split_right = self.base.x + self.base.w * 0.775;
+ if px < split_left {
self.value = (self.value - self.step).max(self.min);
true
- } else if px >= split + self.base.w * 0.225 {
+ } else if px >= split_right {
self.value = (self.value + self.step).min(self.max);
true
- } else if px < split {
+ } else {
self.editing = true;
if self.decimals > 0 {
let divisor = 10.0f32.powi(self.decimals as i32);
@@ -161,14 +166,12 @@ impl Element for Spinbox {
self.edit_buffer = self.value.to_string();
}
let char_width = 8.4;
- let click_idx = (((px - (self.base.x + 4.0)) / char_width).round() as isize)
+ let click_idx = (((px - (split_left + 4.0)) / char_width).round() as isize)
.max(0)
.min(self.edit_buffer.chars().count() as isize) as usize;
self.cursor_idx = click_idx;
focus::set_focused(self);
true
- } else {
- false
}
}
ElementState::Released => {
@@ -284,8 +287,10 @@ impl Element for Spinbox {
let mut quads = Vec::new();
let top = self.base.label_offset();
let visual_h = self.base.h - top;
- let split = self.base.x + self.base.w * 0.55;
let btn_w = self.base.w * 0.225;
+ let display_w = self.base.w * 0.55;
+ let split_left = self.base.x + btn_w;
+ let split_right = self.base.x + btn_w + display_w;
let inc_col = if self.hover_inc { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
let dec_col = if self.hover_dec { colors::SPINBOX_BUTTON_HOVER } else { colors::SPINBOX_BUTTON };
@@ -295,20 +300,20 @@ impl Element for Spinbox {
colors::SPINBOX_DISPLAY
};
- quads.push((self.base.x, self.base.y + top, self.base.w * 0.55, visual_h, display_bg));
- quads.push((split, self.base.y + top, btn_w, visual_h, dec_col));
- quads.push((split + btn_w, self.base.y + top, btn_w, visual_h, inc_col));
+ quads.push((self.base.x, self.base.y + top, btn_w, visual_h, dec_col));
+ quads.push((split_left, self.base.y + top, display_w, visual_h, display_bg));
+ quads.push((split_right, self.base.y + top, btn_w, visual_h, inc_col));
if self.editing {
let border_color = [0.20, 0.50, 0.85, 1.0];
- quads.push((self.base.x, self.base.y + top, self.base.w * 0.55, 1.0, border_color));
- quads.push((self.base.x, self.base.y + top + visual_h - 1.0, self.base.w * 0.55, 1.0, border_color));
- quads.push((self.base.x, self.base.y + top, 1.0, visual_h, border_color));
- quads.push((self.base.x + self.base.w * 0.55 - 1.0, self.base.y + top, 1.0, visual_h, border_color));
+ quads.push((split_left, self.base.y + top, display_w, 1.0, border_color));
+ quads.push((split_left, self.base.y + top + visual_h - 1.0, display_w, 1.0, border_color));
+ quads.push((split_left, self.base.y + top, 1.0, visual_h, border_color));
+ quads.push((split_left + display_w - 1.0, self.base.y + top, 1.0, visual_h, border_color));
let char_width = 8.4;
- let cursor_x = self.base.x + 4.0 + (self.cursor_idx as f32 * char_width);
- let max_cursor_x = split - 4.0;
+ let cursor_x = split_left + 4.0 + (self.cursor_idx as f32 * char_width);
+ let max_cursor_x = split_left + display_w - 4.0;
let final_cursor_x = cursor_x.min(max_cursor_x);
let cursor_y = self.base.y + top + (visual_h - 14.0) / 2.0;
quads.push((final_cursor_x, cursor_y, 1.5, 14.0, [0.80, 0.80, 0.85, 1.0]));
@@ -334,9 +339,12 @@ impl Element for Spinbox {
let top = self.base.label_offset();
let visual_h = self.base.h - top;
+ let btn_w = self.base.w * 0.225;
+ let split_left = self.base.x + btn_w;
+
labels.push(TextLabel {
text: value_text,
- x: self.base.x + 4.0,
+ x: split_left + 4.0,
y: self.base.y + top + (visual_h - 14.0) / 2.0 - 2.0,
font_size: 14.0,
color: [0xcc, 0xcc, 0xd4],
@@ -344,7 +352,7 @@ impl Element for Spinbox {
if let Some(ref unit) = self.unit {
labels.push(TextLabel {
text: unit.clone(),
- x: self.base.x + 4.0 + 36.0,
+ x: split_left + 4.0 + 36.0,
y: self.base.y + top + (visual_h - 11.0) / 2.0 - 2.0,
font_size: 11.0,
color: [0x73, 0x73, 0x7a],
@@ -353,7 +361,7 @@ impl Element for Spinbox {
labels.push(TextLabel {
text: "-".to_string(),
- x: self.base.x + self.base.w * 0.6625 - 4.0,
+ x: self.base.x + self.base.w * 0.1125 - 4.0,
y: self.base.y + top + (visual_h - 12.0) / 2.0 - 2.0,
font_size: 12.0,
color: [0xcc, 0xcc, 0xd4],