git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

commit151de5b139a9072c21fd1705bdaf582096c03c50
parent0f1cb64b42
authorLucas Galante <[email protected]>
date2026-05-23 19:01
Add viewport background color parameters to configure popup

 src/main.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 10 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index cce367b..f3efa64 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -227,6 +227,10 @@ struct ConfigDialog {
     show_origin_enabled: bool,
     show_origin_pending: Option<bool>,
     show_origin_hovered: bool,
+    viewport_r: f32,
+    viewport_g: f32,
+    viewport_b: f32,
+    viewport_color_pending: Option<(usize, f32)>,
 }
 
 impl ConfigDialog {
@@ -259,6 +263,10 @@ impl ConfigDialog {
             show_origin_enabled: true,
             show_origin_pending: None,
             show_origin_hovered: false,
+            viewport_r: 0.05,
+            viewport_g: 0.05,
+            viewport_b: 0.10,
+            viewport_color_pending: None,
         }
     }
 
@@ -277,6 +285,11 @@ impl ConfigDialog {
         let row1_y = py + 178.0; // Grid Y
         let row2_y = py + 200.0; // Skipped Row H
         let row3_y = py + 222.0; // Skipped Col W
+
+        let v_row0_y = py + 226.0; // Background R
+        let v_row1_y = py + 248.0; // Background G
+        let v_row2_y = py + 270.0; // Background B
+
         vec![
             (0, px + 160.0, row0_y - 2.0),
             (1, px + 210.0, row0_y - 2.0),
@@ -286,6 +299,13 @@ impl ConfigDialog {
             (5, px + 210.0, row2_y - 2.0),
             (6, px + 160.0, row3_y - 2.0),
             (7, px + 210.0, row3_y - 2.0),
+
+            (8, px + 160.0, v_row0_y - 2.0),
+            (9, px + 210.0, v_row0_y - 2.0),
+            (10, px + 160.0, v_row1_y - 2.0),
+            (11, px + 210.0, v_row1_y - 2.0),
+            (12, px + 160.0, v_row2_y - 2.0),
+            (13, px + 210.0, v_row2_y - 2.0),
         ]
     }
 
@@ -348,11 +368,20 @@ impl Widget for ConfigDialog {
             1 => self.grid_size_y = val,
             2 => self.skipped_row_h = val,
             3 => self.skipped_col_w = val,
+            4 => self.viewport_r = val,
+            5 => self.viewport_g = val,
+            6 => self.viewport_b = val,
             _ => {}
         }
     }
     fn take_config_spin(&mut self) -> Option<(usize, f32)> {
-        self.grid_size_pending.take()
+        if let Some(v) = self.grid_size_pending.take() {
+            Some(v)
+        } else if let Some(v) = self.viewport_color_pending.take() {
+            Some(v)
+        } else {
+            None
+        }
     }
 
     fn hit_test(&self, px: f32, py: f32) -> bool {
@@ -401,7 +430,7 @@ impl Widget for ConfigDialog {
             self.network_grid_hovered = px >= ppx + 16.0 && px < ppx + 200.0
                 && py >= row2_y - 2.0 && py < row2_y + 18.0;
             for &(btn_id, bx, by) in &self.spin_btns(ppx, ppy) {
-                if px >= bx && px < bx + 22.0 && py >= by && py < by + 20.0 {
+                if btn_id < 8 && px >= bx && px < bx + 22.0 && py >= by && py < by + 20.0 {
                     self.hovered_spin_btn = Some(btn_id);
                     break;
                 }
@@ -416,6 +445,12 @@ impl Widget for ConfigDialog {
             let row3_y = ppy + 132.0;
             self.show_origin_hovered = px >= ppx + 16.0 && px < ppx + 200.0
                 && py >= row3_y - 2.0 && py < row3_y + 18.0;
+            for &(btn_id, bx, by) in &self.spin_btns(ppx, ppy) {
+                if btn_id >= 8 && px >= bx && px < bx + 22.0 && py >= by && py < by + 20.0 {
+                    self.hovered_spin_btn = Some(btn_id);
+                    break;
+                }
+            }
         }
 
         was != self.hovered || old_close != self.close_hovered || old_tab != self.hovered_tab
@@ -503,6 +538,25 @@ impl Widget for ConfigDialog {
                 self.show_origin_pending = Some(self.show_origin_enabled);
                 return true;
             }
+            for &(btn_id, bx, by) in &self.spin_btns(ppx, ppy) {
+                if btn_id >= 8 && px >= bx && px < bx + 22.0 && py >= by && py < by + 20.0 {
+                    let (val, delta, min_val, max_val, pending_id) = match btn_id {
+                        8 => (&mut self.viewport_r, -0.05, 0.0, 1.0, 4),
+                        9 => (&mut self.viewport_r, 0.05, 0.0, 1.0, 4),
+                        10 => (&mut self.viewport_g, -0.05, 0.0, 1.0, 5),
+                        11 => (&mut self.viewport_g, 0.05, 0.0, 1.0, 5),
+                        12 => (&mut self.viewport_b, -0.05, 0.0, 1.0, 6),
+                        13 => (&mut self.viewport_b, 0.05, 0.0, 1.0, 6),
+                        _ => unreachable!(),
+                    };
+                    let new = (*val + delta).clamp(min_val, max_val);
+                    if (new - *val).abs() > 0.001 {
+                        *val = new;
+                        self.viewport_color_pending = Some((pending_id, *val));
+                    }
+                    return true;
+                }
+            }
         }
         false
     }
@@ -578,6 +632,20 @@ impl Widget for ConfigDialog {
                 let row3_y = py + 132.0;
                 quads.push((px + 14.0, row3_y - 2.0, 186.0, 20.0, [0.25, 0.25, 0.35, 0.4]));
             }
+            if let Some(sb) = self.hovered_spin_btn {
+                for &(btn_id, bx, by) in &self.spin_btns(px, py) {
+                    if btn_id == sb {
+                        quads.push((bx, by, 22.0, 20.0, [0.35, 0.35, 0.45, 0.5]));
+                        break;
+                    }
+                }
+            }
+            let preview_x = px + 300.0;
+            let preview_y = py + 226.0;
+            let preview_w = 120.0;
+            let preview_h = 64.0;
+            quads.push((preview_x - 2.0, preview_y - 2.0, preview_w + 4.0, preview_h + 4.0, [0.35, 0.35, 0.45, 1.0]));
+            quads.push((preview_x, preview_y, preview_w, preview_h, [self.viewport_r, self.viewport_g, self.viewport_b, 1.0]));
         }
 
         quads
@@ -647,6 +715,25 @@ impl Widget for ConfigDialog {
             labels.push(TextLabel { text: cube_text.into(), x: px + 20.0, y: content_y + 50.0, font_size: 12.0, color: [0xaa, 0xaa, 0xbb] });
             let origin_text = if self.show_origin_enabled { "[\u{2713}] Show Origin Axes" } else { "[ ] Show Origin Axes" };
             labels.push(TextLabel { text: origin_text.into(), x: px + 20.0, y: content_y + 74.0, font_size: 12.0, color: [0xaa, 0xaa, 0xbb] });
+
+            labels.push(TextLabel { text: "Background Color".into(), x: px + 16.0, y: content_y + 110.0, font_size: 12.0, color: [0x88, 0x88, 0x99] });
+
+            labels.push(TextLabel { text: "Red:".into(), x: px + 16.0, y: content_y + 132.0, font_size: 12.0, color: [0xbb, 0xbb, 0xcc] });
+            labels.push(TextLabel { text: "\u{2212}".into(), x: px + 170.0, y: content_y + 132.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+            labels.push(TextLabel { text: format!("{:.2}", self.viewport_r), x: px + 188.0, y: content_y + 132.0, font_size: 12.0, color: [0xdd, 0xdd, 0x88] });
+            labels.push(TextLabel { text: "+".into(), x: px + 220.0, y: content_y + 132.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+
+            labels.push(TextLabel { text: "Green:".into(), x: px + 16.0, y: content_y + 154.0, font_size: 12.0, color: [0xbb, 0xbb, 0xcc] });
+            labels.push(TextLabel { text: "\u{2212}".into(), x: px + 170.0, y: content_y + 154.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+            labels.push(TextLabel { text: format!("{:.2}", self.viewport_g), x: px + 188.0, y: content_y + 154.0, font_size: 12.0, color: [0xdd, 0xdd, 0x88] });
+            labels.push(TextLabel { text: "+".into(), x: px + 220.0, y: content_y + 154.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+
+            labels.push(TextLabel { text: "Blue:".into(), x: px + 16.0, y: content_y + 176.0, font_size: 12.0, color: [0xbb, 0xbb, 0xcc] });
+            labels.push(TextLabel { text: "\u{2212}".into(), x: px + 170.0, y: content_y + 176.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+            labels.push(TextLabel { text: format!("{:.2}", self.viewport_b), x: px + 188.0, y: content_y + 176.0, font_size: 12.0, color: [0xdd, 0xdd, 0x88] });
+            labels.push(TextLabel { text: "+".into(), x: px + 220.0, y: content_y + 176.0, font_size: 12.0, color: [0xcc, 0xcc, 0xd4] });
+
+            labels.push(TextLabel { text: "Preview:".into(), x: px + 300.0, y: content_y + 110.0, font_size: 12.0, color: [0x88, 0x88, 0x99] });
         } else {
             labels.push(TextLabel { text: "Keyboard Shortcuts".into(), x: px + 16.0, y: content_y, font_size: 13.0, color: [0xcc, 0xcc, 0xd4] });
             let shortcuts = [
@@ -1401,6 +1488,7 @@ struct State {
     show_grid: bool,
     show_cube: bool,
     show_origin: bool,
+    viewport_bg_color: [f32; 3],
     vertex_buffer_origin: wgpu::Buffer,
     vertex_count_origin: u32,
 
@@ -2298,6 +2386,7 @@ fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec<Vec<String
             show_grid: true,
             show_cube: false,
             show_origin: true,
+            viewport_bg_color: [0.05, 0.05, 0.10],
             vertex_buffer_origin,
             vertex_count_origin,
             fs_root,
@@ -2573,6 +2662,9 @@ fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec<Vec<String
                     self.widgets[CONFIG_DIALOG_IDX].set_config_spin(1, self.grid_size_y);
                     self.widgets[CONFIG_DIALOG_IDX].set_config_spin(2, self.skipped_row_h);
                     self.widgets[CONFIG_DIALOG_IDX].set_config_spin(3, self.skipped_col_w);
+                    self.widgets[CONFIG_DIALOG_IDX].set_config_spin(4, self.viewport_bg_color[0]);
+                    self.widgets[CONFIG_DIALOG_IDX].set_config_spin(5, self.viewport_bg_color[1]);
+                    self.widgets[CONFIG_DIALOG_IDX].set_config_spin(6, self.viewport_bg_color[2]);
                     self.widgets[CONFIG_DIALOG_IDX].set_visible(true);
                 }
                 self.upload_vertices();
@@ -3622,7 +3714,12 @@ fn geometry_to_spreadsheet_data(geom: &Geometry) -> (Vec<String>, Vec<Vec<String
                         view: &view,
                         resolve_target: None,
                         ops: wgpu::Operations {
-                            load: wgpu::LoadOp::Clear(wgpu::Color { r: 0.05, g: 0.05, b: 0.10, a: 1.0 }),
+                            load: wgpu::LoadOp::Clear(wgpu::Color {
+                                r: self.viewport_bg_color[0] as f64,
+                                g: self.viewport_bg_color[1] as f64,
+                                b: self.viewport_bg_color[2] as f64,
+                                a: 1.0,
+                            }),
                             store: wgpu::StoreOp::Store,
                         },
                     })],
@@ -3798,13 +3895,7 @@ impl ApplicationHandler for App {
                                     changed = true;
                                 }
                                 3 => { // Configure
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_toggle(0, state.grid_snap_enabled);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_toggle(1, state.network_grid_visible);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_spin(0, state.grid_size_x);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_spin(1, state.grid_size_y);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_spin(2, state.skipped_row_h);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_config_spin(3, state.skipped_col_w);
-                                    state.widgets[CONFIG_DIALOG_IDX].set_visible(true);
+                                    state.execute_action(Action::ToggleConfigure);
                                     changed = true;
                                 }
                                 4 => { // Exit
@@ -3911,6 +4002,9 @@ impl ApplicationHandler for App {
                             1 => state.grid_size_y = val,
                             2 => state.skipped_row_h = val,
                             3 => state.skipped_col_w = val,
+                            4 => state.viewport_bg_color[0] = val,
+                            5 => state.viewport_bg_color[1] = val,
+                            6 => state.viewport_bg_color[2] = val,
                             _ => {}
                         }
                         for &i in &state.node_slots {