diff --git a/src/control_center.rs b/src/control_center.rs index f698b992..a78884f8 100644 --- a/src/control_center.rs +++ b/src/control_center.rs @@ -2,8 +2,8 @@ use { crate::{ control_center::{ cc_color_management::ColorManagementPane, cc_compositor::CompositorPane, - cc_gpus::GpusPane, cc_idle::IdlePane, cc_input::InputPane, cc_outputs::OutputsPane, - cc_xwayland::XwaylandPane, + cc_gpus::GpusPane, cc_idle::IdlePane, cc_input::InputPane, + cc_look_and_feel::LookAndFeelPane, cc_outputs::OutputsPane, cc_xwayland::XwaylandPane, }, egui_adapter::egui_platform::{ EggError, EggWindow, EggWindowOwner, @@ -39,6 +39,7 @@ mod cc_compositor; mod cc_gpus; mod cc_idle; mod cc_input; +mod cc_look_and_feel; mod cc_outputs; mod cc_sidebar; mod cc_xwayland; @@ -81,6 +82,7 @@ bitflags! { CCI_OUTPUTS, CCI_GPUS, CCI_INPUT, + CCI_LOOK_AND_FEEL, } pub struct ControlCenter { @@ -128,6 +130,7 @@ enum PaneType { Outputs(Box), GPUs(GpusPane), Input(InputPane), + LookAndFeel(LookAndFeelPane), } struct CcBehavior<'a> { @@ -153,6 +156,7 @@ impl Pane { PaneType::Outputs(v) => v.title(res), PaneType::GPUs(v) => v.title(res), PaneType::Input(v) => v.title(res), + PaneType::LookAndFeel(v) => v.title(res), } } @@ -165,6 +169,7 @@ impl Pane { PaneType::Outputs(p) => p.show(&mut self.ps, ui), PaneType::GPUs(p) => p.show(ui), PaneType::Input(p) => p.show(&mut self.ps, ui), + PaneType::LookAndFeel(p) => p.show(ui), } } } @@ -179,6 +184,7 @@ impl PaneType { PaneType::Outputs(_) => CCI_OUTPUTS, PaneType::GPUs(_) => CCI_GPUS, PaneType::Input(_) => CCI_INPUT, + PaneType::LookAndFeel(_) => CCI_LOOK_AND_FEEL, } } } diff --git a/src/control_center/cc_look_and_feel.rs b/src/control_center/cc_look_and_feel.rs new file mode 100644 index 00000000..636e80da --- /dev/null +++ b/src/control_center/cc_look_and_feel.rs @@ -0,0 +1,163 @@ +use { + crate::{ + cmm::cmm_eotf::Eotf, + control_center::{ + ControlCenterInner, bool, bool_ui, combo_box, drag_value, grid, grid_label, row, + text_edit, tip, + }, + gfx_api::AlphaMode, + state::State, + theme::{Color, ThemeColor, ThemeSized}, + utils::static_text::StaticText, + }, + egui::Ui, + isnt::std_1::primitive::IsntStrExt, + linearize::LinearizeExt, + std::rc::Rc, +}; + +pub struct LookAndFeelPane { + state: Rc, +} + +impl ControlCenterInner { + pub fn create_look_and_feel_pane(self: &Rc) -> LookAndFeelPane { + LookAndFeelPane { + state: self.state.clone(), + } + } +} + +impl LookAndFeelPane { + pub fn title(&self, res: &mut String) { + res.push_str("Look and Feel"); + } + + pub fn show(&mut self, ui: &mut Ui) { + let t = &self.state.theme; + grid(ui, "settings", |ui| { + bool(ui, "Show Bar", self.state.show_bar.get(), |v| { + self.state.set_show_bar(v) + }); + combo_box(ui, "Bar Position", t.bar_position.get(), |p| { + self.state.set_bar_position(p); + }); + bool(ui, "Show Titles", t.show_titles.get(), |v| { + self.state.set_show_titles(v) + }); + bool_ui( + ui, + "Primary Selection", + |ui| { + tip(ui, |ui| { + ui.label("Requires applications to be restarted."); + }); + }, + self.state.enable_primary_selection.get(), + |v| self.state.set_primary_selection_enabled(v), + ); + bool_ui( + ui, + "UI Drag", + |ui| { + tip(ui, |ui| { + ui.label("Allows dragging workspaces and tiled windows with the mouse."); + }); + }, + self.state.ui_drag_enabled.get(), + |v| self.state.set_ui_drag_enabled(v), + ); + drag_value( + ui, + "UI Drag Threshold (px)", + self.state.ui_drag_threshold_squared.get().isqrt(), + 1..=i32::MAX, + 1.0, + |v| { + self.state.set_ui_drag_threshold(v); + }, + ); + bool_ui( + ui, + "Float Pin Icon", + |ui| { + tip(ui, |ui| { + ui.label("Show the pin icon even if the window is not pinned."); + ui.label("Pinned floating windows are shown on all workspaces."); + }); + }, + self.state.show_pin_icon.get(), + |v| self.state.set_show_pin_icon(v), + ); + bool_ui( + ui, + "Float Above Fullscreen", + |ui| { + tip(ui, |ui| { + ui.label("Show floating windows above fullscreen windows."); + }); + }, + self.state.float_above_fullscreen.get(), + |v| self.state.set_float_above_fullscreen(v), + ); + row(ui, "Font", |ui| { + let mut v = self.state.theme.font.get().to_string(); + if text_edit(ui, &mut v).changed() { + self.state.set_font(&v); + } + }); + row(ui, "Title Font", |ui| { + let mut v = t + .title_font + .get() + .map(|v| v.to_string()) + .unwrap_or_default(); + if text_edit(ui, &mut v).changed() { + self.state.set_title_font(v.is_not_empty().then_some(&v)); + } + }); + row(ui, "Bar Font", |ui| { + let mut v = t.bar_font.get().map(|v| v.to_string()).unwrap_or_default(); + if text_edit(ui, &mut v).changed() { + self.state.set_bar_font(v.is_not_empty().then_some(&v)); + } + }); + }); + if ui.button("Reset Sizes").clicked() { + self.state.reset_sizes(); + } + if ui.button("Reset Colors").clicked() { + self.state.reset_colors(); + } + if ui.button("Reset Fonts").clicked() { + self.state.reset_fonts(); + } + ui.collapsing("Sizes", |ui| { + grid(ui, "Sizes", |ui| { + for v in ThemeSized::variants() { + let f = v.field(&self.state.theme); + drag_value(ui, v.text(), f.get(), v.min()..=v.max(), 1.0, |i| { + self.state.set_size(v, i); + }); + } + }); + }); + ui.collapsing("Colors", |ui| { + grid(ui, "Colors", |ui| { + for tc in ThemeColor::variants() { + let f = tc.field(t); + let mut v = f.get().to_array(Eotf::Linear); + grid_label(ui, tc.text()); + let changed = ui.color_edit_button_rgba_premultiplied(&mut v).changed(); + ui.end_row(); + if changed { + let [r, g, b, a] = v; + let c = + Color::new(Eotf::Linear, AlphaMode::PremultipliedOptical, r, g, b, a); + self.state.set_color(tc, c); + } + } + }); + }); + } +} diff --git a/src/control_center/cc_sidebar.rs b/src/control_center/cc_sidebar.rs index 22183ba4..6215bb2a 100644 --- a/src/control_center/cc_sidebar.rs +++ b/src/control_center/cc_sidebar.rs @@ -15,6 +15,7 @@ enum PaneName { Outputs, GPUs, Input, + LookAndFeel, } impl PaneName { @@ -27,6 +28,7 @@ impl PaneName { PaneName::Outputs => "Outputs", PaneName::GPUs => "GPUs", PaneName::Input => "Input", + PaneName::LookAndFeel => "Look and Feel", } } } @@ -66,6 +68,9 @@ impl ControlCenterInner { } PaneName::GPUs => PaneType::GPUs(self.create_gpus_pane()), PaneName::Input => PaneType::Input(self.create_input_pane()), + PaneName::LookAndFeel => { + PaneType::LookAndFeel(self.create_look_and_feel_pane()) + } }; self.open(tree, ty); ui.ctx().request_repaint(); diff --git a/src/state.rs b/src/state.rs index ae17cd5a..ad537ee1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -17,8 +17,8 @@ use { compositor::{LIBEI_SOCKET, LogLevel}, config::ConfigProxy, control_center::{ - CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_GPUS, CCI_IDLE, CCI_OUTPUTS, CCI_XWAYLAND, - ControlCenters, + CCI_COLOR_MANAGEMENT, CCI_COMPOSITOR, CCI_GPUS, CCI_IDLE, CCI_LOOK_AND_FEEL, + CCI_OUTPUTS, CCI_XWAYLAND, ControlCenters, }, copy_device::CopyDeviceRegistry, cpu_worker::CpuWorker, @@ -1739,6 +1739,7 @@ impl State { pub fn set_primary_selection_enabled(&self, enabled: bool) { self.enable_primary_selection.set(enabled); self.expose_new_singletons(); + self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_explicit_sync_enabled(&self, enabled: bool) { @@ -1774,6 +1775,7 @@ impl State { self.root.clone().node_visit(&mut V); self.damage(self.root.extents.get()); self.icons.clear(); + self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn reset_colors(&self) { @@ -1838,6 +1840,7 @@ impl State { self.root.clone().node_visit(&mut V); self.damage(self.root.extents.get()); self.icons.update_sizes(self); + self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_show_bar(&self, show: bool) { @@ -1852,15 +1855,18 @@ impl State { pub fn set_ui_drag_enabled(&self, enabled: bool) { self.ui_drag_enabled.set(enabled); + self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_ui_drag_threshold(&self, threshold: i32) { self.ui_drag_threshold_squared .set(threshold.saturating_mul(threshold)); + self.trigger_cci(CCI_LOOK_AND_FEEL); } pub fn set_show_pin_icon(&self, show: bool) { self.show_pin_icon.set(show); + self.trigger_cci(CCI_LOOK_AND_FEEL); for stacked in self.root.stacked.iter() { if let Some(float) = stacked.deref().clone().node_into_float() { float.schedule_render_titles(); @@ -1870,6 +1876,7 @@ impl State { pub fn set_float_above_fullscreen(&self, v: bool) { self.float_above_fullscreen.set(v); + self.trigger_cci(CCI_LOOK_AND_FEEL); for seat in self.globals.seats.lock().values() { seat.emulate_cursor_moved(); seat.trigger_tree_changed(false); @@ -1883,6 +1890,7 @@ impl State { } fn fonts_changed(&self) { + self.trigger_cci(CCI_LOOK_AND_FEEL); struct V; impl NodeVisitorBase for V { fn visit_container(&mut self, node: &Rc) {