init
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
//! Theme and colour options example:
|
||||
//! `cargo run --example 7_theme_options`
|
||||
|
||||
use eframe::egui;
|
||||
use grimdock::{
|
||||
ChildSide, PaneId, PaneStyleOverride, PanelContext, PanelStyle, PanelTree, SplitDir, Tab,
|
||||
TabStyleOverride,
|
||||
};
|
||||
|
||||
fn main() -> eframe::Result<()> {
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_title("grimdock 7_theme_options")
|
||||
.with_inner_size([1260.0, 760.0]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"grimdock 7_theme_options",
|
||||
options,
|
||||
Box::new(|cc| Ok(Box::new(App::new(&cc.egui_ctx)))),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
enum TabId {
|
||||
Files,
|
||||
Editor,
|
||||
Search,
|
||||
Preview,
|
||||
Terminal,
|
||||
}
|
||||
|
||||
struct App {
|
||||
tree: PanelTree<TabId>,
|
||||
style: PanelStyle,
|
||||
terminal_pane: PaneId,
|
||||
terminal_override_enabled: bool,
|
||||
terminal_override: PaneStyleOverride,
|
||||
search_override_enabled: bool,
|
||||
search_override: TabStyleOverride,
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn new(ctx: &egui::Context) -> Self {
|
||||
let (tree, terminal_pane) = make_tree();
|
||||
Self {
|
||||
tree,
|
||||
style: PanelStyle::from_visuals(&ctx.style().visuals),
|
||||
terminal_pane,
|
||||
terminal_override_enabled: true,
|
||||
terminal_override: PaneStyleOverride {
|
||||
header_bg: Some(egui::Color32::from_rgb(45, 28, 20)),
|
||||
content_bg: Some(egui::Color32::from_rgb(34, 22, 16)),
|
||||
border_color: Some(egui::Color32::from_rgb(168, 99, 56)),
|
||||
accent_color: Some(egui::Color32::from_rgb(230, 142, 78)),
|
||||
},
|
||||
search_override_enabled: true,
|
||||
search_override: TabStyleOverride {
|
||||
active_bg: Some(egui::Color32::from_rgb(30, 74, 66)),
|
||||
inactive_bg: Some(egui::Color32::from_rgb(24, 52, 48)),
|
||||
hovered_bg: Some(egui::Color32::from_rgb(36, 90, 80)),
|
||||
text_color: Some(egui::Color32::from_rgb(214, 245, 238)),
|
||||
accent_color: Some(egui::Color32::from_rgb(52, 204, 168)),
|
||||
icon_color: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn sync_overrides(&mut self) {
|
||||
if let Some(mut pane) = self.tree.pane_mut(self.terminal_pane) {
|
||||
let mut options = pane.options();
|
||||
options.style_override = self.terminal_override_enabled.then_some(self.terminal_override);
|
||||
pane.set_options(options);
|
||||
}
|
||||
|
||||
if let Some(search_pane_id) = self.tree.find_pane_containing(&TabId::Search) {
|
||||
if let Some(mut pane) = self.tree.pane_mut(search_pane_id) {
|
||||
if let Some(tab) = pane.tabs_mut().iter_mut().find(|tab| tab.id == TabId::Search) {
|
||||
tab.style_override = self.search_override_enabled.then_some(self.search_override);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for App {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
self.sync_overrides();
|
||||
|
||||
egui::Panel::left("theme_controls")
|
||||
.resizable(true)
|
||||
.default_width(360.0)
|
||||
.show(ctx, |ui| {
|
||||
ui.heading("Theme workbench");
|
||||
ui.label("This example exposes the global PanelStyle plus pane and tab color overrides.");
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Use egui visuals").clicked() {
|
||||
self.style = PanelStyle::from_visuals(&ctx.style().visuals);
|
||||
}
|
||||
if ui.button("Use crate defaults").clicked() {
|
||||
self.style = PanelStyle::default();
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.collapsing("Layout metrics", |ui| {
|
||||
ui.add(egui::Slider::new(&mut self.style.header_height, 20.0..=40.0).text("Header height"));
|
||||
ui.add(
|
||||
egui::Slider::new(&mut self.style.collapsed_pane_thickness, 20.0..=60.0)
|
||||
.text("Collapsed thickness"),
|
||||
);
|
||||
ui.add(egui::Slider::new(&mut self.style.handle_width, 2.0..=12.0).text("Handle width"));
|
||||
ui.add(egui::Slider::new(&mut self.style.min_pane_size, 40.0..=160.0).text("Min pane size"));
|
||||
ui.add(egui::Slider::new(&mut self.style.content_inset, 0.0..=20.0).text("Content inset"));
|
||||
corner_radius_slider(ui, "Pane rounding", &mut self.style.pane_rounding);
|
||||
corner_radius_slider(ui, "Tab rounding", &mut self.style.tabs.rounding);
|
||||
corner_radius_slider(ui, "Header button rounding", &mut self.style.header.button.rounding);
|
||||
});
|
||||
|
||||
ui.collapsing("Typography", |ui| {
|
||||
ui.label("Dock chrome text is painted directly by grimdock.");
|
||||
ui.label("Font weight comes from whichever font family your app has loaded.");
|
||||
font_controls(ui, "Tab title", &mut self.style.typography.tab_title_font);
|
||||
font_controls(
|
||||
ui,
|
||||
"Leading text icon",
|
||||
&mut self.style.typography.tab_icon_text_font,
|
||||
);
|
||||
});
|
||||
|
||||
ui.collapsing("Header", |ui| {
|
||||
color_row(ui, "Header bg", &mut self.style.header.bg);
|
||||
color_row(ui, "Header border", &mut self.style.header.border_color);
|
||||
color_row(ui, "Button bg", &mut self.style.header.button.bg);
|
||||
color_row(ui, "Button hover bg", &mut self.style.header.button.hover_bg);
|
||||
color_row(ui, "Button stroke", &mut self.style.header.button.stroke_color);
|
||||
color_row(ui, "Button icon", &mut self.style.header.button.icon_color);
|
||||
color_row(ui, "Button hover icon", &mut self.style.header.button.hover_icon_color);
|
||||
});
|
||||
|
||||
ui.collapsing("Content", |ui| {
|
||||
color_row(ui, "Content bg", &mut self.style.content.bg);
|
||||
color_row(ui, "Content border", &mut self.style.content.border_color);
|
||||
});
|
||||
|
||||
ui.collapsing("Tabs", |ui| {
|
||||
ui.label("Active");
|
||||
color_row(ui, "Active bg", &mut self.style.tabs.active.bg);
|
||||
color_row(ui, "Active text", &mut self.style.tabs.active.text_color);
|
||||
color_row(ui, "Active accent", &mut self.style.tabs.active.accent_color);
|
||||
|
||||
ui.separator();
|
||||
ui.label("Inactive");
|
||||
color_row(ui, "Inactive bg", &mut self.style.tabs.inactive.bg);
|
||||
color_row(ui, "Inactive text", &mut self.style.tabs.inactive.text_color);
|
||||
color_row(ui, "Inactive accent", &mut self.style.tabs.inactive.accent_color);
|
||||
|
||||
ui.separator();
|
||||
ui.label("Hovered");
|
||||
color_row(ui, "Hovered bg", &mut self.style.tabs.hovered.bg);
|
||||
color_row(ui, "Hovered text", &mut self.style.tabs.hovered.text_color);
|
||||
color_row(ui, "Hovered accent", &mut self.style.tabs.hovered.accent_color);
|
||||
});
|
||||
|
||||
ui.collapsing("Handles and overlay", |ui| {
|
||||
color_row(ui, "Handle", &mut self.style.handle.color);
|
||||
color_row(ui, "Handle hover", &mut self.style.handle.hover_color);
|
||||
color_row(ui, "Handle locked", &mut self.style.handle.locked_color);
|
||||
color_row(ui, "Overlay fill", &mut self.style.overlay.fill);
|
||||
color_row(ui, "Overlay stroke", &mut self.style.overlay.stroke.color);
|
||||
ui.add(
|
||||
egui::Slider::new(&mut self.style.overlay.stroke.width, 0.5..=4.0)
|
||||
.text("Overlay stroke width"),
|
||||
);
|
||||
});
|
||||
|
||||
ui.collapsing("Pane override", |ui| {
|
||||
ui.checkbox(&mut self.terminal_override_enabled, "Enable Terminal pane override");
|
||||
color_option_row(ui, "Header bg", &mut self.terminal_override.header_bg);
|
||||
color_option_row(ui, "Content bg", &mut self.terminal_override.content_bg);
|
||||
color_option_row(ui, "Border", &mut self.terminal_override.border_color);
|
||||
color_option_row(ui, "Accent", &mut self.terminal_override.accent_color);
|
||||
});
|
||||
|
||||
ui.collapsing("Tab override", |ui| {
|
||||
ui.checkbox(&mut self.search_override_enabled, "Enable Search tab override");
|
||||
color_option_row(ui, "Active bg", &mut self.search_override.active_bg);
|
||||
color_option_row(ui, "Inactive bg", &mut self.search_override.inactive_bg);
|
||||
color_option_row(ui, "Hovered bg", &mut self.search_override.hovered_bg);
|
||||
color_option_row(ui, "Text", &mut self.search_override.text_color);
|
||||
color_option_row(ui, "Accent", &mut self.search_override.accent_color);
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame::NONE)
|
||||
.show(ctx, |ui| {
|
||||
PanelContext::new(ui, &mut self.tree, &self.style).show(|ui, tab_id| match tab_id {
|
||||
TabId::Files => {
|
||||
ui.heading("Files");
|
||||
ui.label("Use this workbench to tune every main color and size in PanelStyle.");
|
||||
}
|
||||
TabId::Editor => {
|
||||
ui.heading("Editor");
|
||||
ui.label("Drag tabs and resize panes while adjusting the theme controls.");
|
||||
}
|
||||
TabId::Search => {
|
||||
ui.heading("Search");
|
||||
ui.label("This tab can demonstrate per-tab color overrides.");
|
||||
}
|
||||
TabId::Preview => {
|
||||
ui.heading("Preview");
|
||||
ui.label("The dock updates live as you change colors, rounding, and handle styles.");
|
||||
}
|
||||
TabId::Terminal => {
|
||||
ui.heading("Terminal");
|
||||
ui.label("This pane can demonstrate per-pane header/content/accent overrides.");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn color_row(ui: &mut egui::Ui, label: &str, color: &mut egui::Color32) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(label);
|
||||
ui.color_edit_button_srgba(color);
|
||||
});
|
||||
}
|
||||
|
||||
fn color_option_row(ui: &mut egui::Ui, label: &str, color: &mut Option<egui::Color32>) {
|
||||
let mut enabled = color.is_some();
|
||||
ui.horizontal(|ui| {
|
||||
ui.checkbox(&mut enabled, label);
|
||||
if !enabled {
|
||||
*color = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let value = color.get_or_insert(egui::Color32::WHITE);
|
||||
ui.color_edit_button_srgba(value);
|
||||
});
|
||||
}
|
||||
|
||||
fn corner_radius_slider(ui: &mut egui::Ui, label: &str, radius: &mut egui::CornerRadius) {
|
||||
let mut value = radius.nw;
|
||||
ui.add(egui::Slider::new(&mut value, 0..=16).text(label));
|
||||
*radius = egui::CornerRadius::same(value);
|
||||
}
|
||||
|
||||
fn font_controls(ui: &mut egui::Ui, label: &str, font: &mut egui::FontId) {
|
||||
ui.group(|ui| {
|
||||
ui.label(label);
|
||||
ui.add(egui::Slider::new(&mut font.size, 8.0..=24.0).text("Size"));
|
||||
|
||||
let mut family = match &font.family {
|
||||
egui::FontFamily::Proportional => 0,
|
||||
egui::FontFamily::Monospace => 1,
|
||||
egui::FontFamily::Name(_) => 2,
|
||||
};
|
||||
egui::ComboBox::from_label("Family")
|
||||
.selected_text(match family {
|
||||
0 => "Proportional",
|
||||
1 => "Monospace",
|
||||
_ => "Custom",
|
||||
})
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut family, 0, "Proportional");
|
||||
ui.selectable_value(&mut family, 1, "Monospace");
|
||||
ui.selectable_value(&mut family, 2, "Custom");
|
||||
});
|
||||
|
||||
if family == 2 {
|
||||
let mut name = match &font.family {
|
||||
egui::FontFamily::Name(name) => name.to_string(),
|
||||
_ => String::from("bold"),
|
||||
};
|
||||
ui.text_edit_singleline(&mut name);
|
||||
font.family = egui::FontFamily::Name(name.into());
|
||||
} else {
|
||||
font.family = if family == 0 {
|
||||
egui::FontFamily::Proportional
|
||||
} else {
|
||||
egui::FontFamily::Monospace
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn make_tree() -> (PanelTree<TabId>, PaneId) {
|
||||
let mut tree = PanelTree::new(vec![
|
||||
Tab::new("editor", TabId::Editor).with_leading_visual(">"),
|
||||
Tab::new("search", TabId::Search).with_leading_visual("?"),
|
||||
]);
|
||||
|
||||
tree.split_leaf(
|
||||
0,
|
||||
SplitDir::Horizontal,
|
||||
Tab::new("files", TabId::Files).with_leading_visual("#"),
|
||||
ChildSide::First,
|
||||
);
|
||||
|
||||
let editor_pane = tree
|
||||
.find_pane_containing(&TabId::Editor)
|
||||
.expect("editor pane should exist");
|
||||
let terminal_pane = tree
|
||||
.pane_mut(editor_pane)
|
||||
.expect("editor pane should exist")
|
||||
.split(
|
||||
SplitDir::Vertical,
|
||||
Tab::new("terminal", TabId::Terminal).with_leading_visual("$"),
|
||||
ChildSide::Second,
|
||||
);
|
||||
|
||||
if let Some(mut pane) = tree.pane_mut(editor_pane) {
|
||||
pane.push_tab(Tab::new("preview", TabId::Preview).with_leading_visual("*"));
|
||||
}
|
||||
|
||||
(tree, terminal_pane)
|
||||
}
|
||||
Reference in New Issue
Block a user