use super::config::{ThemeState, rgba, to_rgba};
pub fn render_theme_editor_window(
ui_context: &egui::Context,
theme_state: &mut ThemeState,
) -> bool {
if !theme_state.show_theme_editor {
return false;
}
let mut changed = false;
let mut open = theme_state.show_theme_editor;
egui::Window::new("Theme Editor")
.open(&mut open)
.default_width(340.0)
.resizable(true)
.show(ui_context, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
changed = render_theme_editor(ui, theme_state);
});
});
theme_state.show_theme_editor = open;
changed
}
pub fn render_theme_editor(ui: &mut egui::Ui, theme_state: &mut ThemeState) -> bool {
let mut changed = false;
let current_label = theme_state
.selected_preset_index
.map(|index| theme_state.presets[index].name.clone())
.unwrap_or_else(|| "Custom".to_string());
let presets = &theme_state.presets;
let preset = &mut theme_state.selected_preset_index;
let preview = &mut theme_state.preview_theme_index;
let config = &mut theme_state.current_config;
ui.horizontal(|ui| {
ui.label("Preset:");
let combo_response = egui::ComboBox::from_id_salt("theme_preset_selector")
.selected_text(¤t_label)
.show_ui(ui, |ui| {
for (index, theme_preset) in presets.iter().enumerate() {
let response = ui.selectable_label(*preset == Some(index), &theme_preset.name);
if response.hovered() {
*preview = Some(index);
}
if response.clicked() {
*config = presets[index].clone();
*preset = Some(index);
*preview = None;
changed = true;
}
}
});
if (combo_response.response.changed()
|| !combo_response.response.is_pointer_button_down_on())
&& combo_response.inner.is_none()
{
*preview = None;
}
});
ui.add_space(8.0);
ui.horizontal(|ui| {
ui.label("Dark mode:");
if ui.checkbox(&mut config.dark_mode, "").changed() {
*preset = None;
changed = true;
}
});
ui.add_space(8.0);
macro_rules! override_section {
($ui:expr, $label:expr, $preset:expr, $changed:expr, $( ($kind:ident, $field_label:expr, $field:expr) ),+ $(,)?) => {
egui::CollapsingHeader::new($label)
.default_open(false)
.show($ui, |ui| {
$(
$changed |= override_section!(@render $kind, ui, $field_label, $field, $preset);
)+
});
};
(@render $_kind:ident, $ui:expr, $label:expr, $field:expr, $preset:expr) => {
render_override($ui, $label, $field, $preset)
};
}
override_section!(
ui,
"Global Colors",
preset,
changed,
(color, "Text Override", &mut config.override_text_color),
(color, "Hyperlink", &mut config.hyperlink_color),
(color, "Faint Background", &mut config.faint_bg_color),
(color, "Extreme Background", &mut config.extreme_bg_color),
(color, "Code Background", &mut config.code_bg_color),
(color, "Warning", &mut config.warn_fg_color),
(color, "Error", &mut config.error_fg_color),
(color, "Window Fill", &mut config.window_fill),
(color, "Panel Fill", &mut config.panel_fill),
);
override_section!(
ui,
"Window",
preset,
changed,
(color, "Stroke Color", &mut config.window_stroke_color),
(f32, "Stroke Width", &mut config.window_stroke_width),
(f32, "Corner Radius", &mut config.window_corner_radius),
(color, "Shadow Color", &mut config.window_shadow_color),
(f32, "Shadow Size", &mut config.window_shadow_size),
(f32, "Popup Shadow Size", &mut config.popup_shadow_size),
);
override_section!(
ui,
"Selection",
preset,
changed,
(color, "Background", &mut config.selection_bg_fill),
(color, "Stroke Color", &mut config.selection_stroke_color),
(f32, "Stroke Width", &mut config.selection_stroke_width),
);
override_section!(
ui,
"Non-Interactive",
preset,
changed,
(color, "Background", &mut config.noninteractive_bg_fill),
(
color,
"Weak Background",
&mut config.noninteractive_weak_bg_fill
),
(
color,
"Border Stroke",
&mut config.noninteractive_bg_stroke_color
),
(
f32,
"Border Width",
&mut config.noninteractive_bg_stroke_width
),
(
f32,
"Corner Radius",
&mut config.noninteractive_corner_radius
),
(
color,
"Text Stroke",
&mut config.noninteractive_fg_stroke_color
),
(
f32,
"Text Width",
&mut config.noninteractive_fg_stroke_width
),
(f32, "Expansion", &mut config.noninteractive_expansion),
);
override_section!(
ui,
"Inactive",
preset,
changed,
(color, "Background", &mut config.inactive_bg_fill),
(color, "Weak Background", &mut config.inactive_weak_bg_fill),
(color, "Border Stroke", &mut config.inactive_bg_stroke_color),
(f32, "Border Width", &mut config.inactive_bg_stroke_width),
(f32, "Corner Radius", &mut config.inactive_corner_radius),
(color, "Text Stroke", &mut config.inactive_fg_stroke_color),
(f32, "Text Width", &mut config.inactive_fg_stroke_width),
(f32, "Expansion", &mut config.inactive_expansion),
);
override_section!(
ui,
"Hovered",
preset,
changed,
(color, "Background", &mut config.hovered_bg_fill),
(color, "Weak Background", &mut config.hovered_weak_bg_fill),
(color, "Border Stroke", &mut config.hovered_bg_stroke_color),
(f32, "Border Width", &mut config.hovered_bg_stroke_width),
(f32, "Corner Radius", &mut config.hovered_corner_radius),
(color, "Text Stroke", &mut config.hovered_fg_stroke_color),
(f32, "Text Width", &mut config.hovered_fg_stroke_width),
(f32, "Expansion", &mut config.hovered_expansion),
);
override_section!(
ui,
"Active",
preset,
changed,
(color, "Background", &mut config.active_bg_fill),
(color, "Weak Background", &mut config.active_weak_bg_fill),
(color, "Border Stroke", &mut config.active_bg_stroke_color),
(f32, "Border Width", &mut config.active_bg_stroke_width),
(f32, "Corner Radius", &mut config.active_corner_radius),
(color, "Text Stroke", &mut config.active_fg_stroke_color),
(f32, "Text Width", &mut config.active_fg_stroke_width),
(f32, "Expansion", &mut config.active_expansion),
);
override_section!(
ui,
"Open",
preset,
changed,
(color, "Background", &mut config.open_bg_fill),
(color, "Weak Background", &mut config.open_weak_bg_fill),
(color, "Border Stroke", &mut config.open_bg_stroke_color),
(f32, "Border Width", &mut config.open_bg_stroke_width),
(f32, "Corner Radius", &mut config.open_corner_radius),
(color, "Text Stroke", &mut config.open_fg_stroke_color),
(f32, "Text Width", &mut config.open_fg_stroke_width),
(f32, "Expansion", &mut config.open_expansion),
);
override_section!(
ui,
"Miscellaneous",
preset,
changed,
(f32, "Resize Corner Size", &mut config.resize_corner_size),
(f32, "Text Cursor Width", &mut config.text_cursor_width),
(f32, "Clip Rect Margin", &mut config.clip_rect_margin),
(bool, "Button Frame", &mut config.button_frame),
(
bool,
"Collapsing Header Frame",
&mut config.collapsing_header_frame
),
(bool, "Indent Left Vline", &mut config.indent_has_left_vline),
(bool, "Striped", &mut config.striped),
(
bool,
"Slider Trailing Fill",
&mut config.slider_trailing_fill
),
);
changed
}
trait OverrideValue: Copy {
fn render_editor(ui: &mut egui::Ui, value: &mut Self) -> bool;
fn render_placeholder(ui: &mut egui::Ui);
fn default_value() -> Self;
}
impl OverrideValue for [u8; 4] {
fn render_editor(ui: &mut egui::Ui, value: &mut Self) -> bool {
let mut color = rgba(*value);
if ui.color_edit_button_srgba(&mut color).changed() {
*value = to_rgba(color);
true
} else {
false
}
}
fn render_placeholder(ui: &mut egui::Ui) {
let placeholder = egui::Color32::from_gray(80);
let (rect, _) = ui.allocate_exact_size(egui::vec2(20.0, 20.0), egui::Sense::hover());
ui.painter().rect_stroke(
rect,
egui::CornerRadius::same(2),
egui::Stroke::new(1.0, placeholder),
egui::StrokeKind::Inside,
);
}
fn default_value() -> Self {
[128, 128, 128, 255]
}
}
impl OverrideValue for f32 {
fn render_editor(ui: &mut egui::Ui, value: &mut Self) -> bool {
ui.add(egui::DragValue::new(value).speed(0.1).range(0.0..=100.0))
.changed()
}
fn render_placeholder(ui: &mut egui::Ui) {
ui.add_space(20.0);
}
fn default_value() -> Self {
1.0
}
}
impl OverrideValue for bool {
fn render_editor(ui: &mut egui::Ui, value: &mut Self) -> bool {
ui.checkbox(value, "").changed()
}
fn render_placeholder(ui: &mut egui::Ui) {
ui.add_space(20.0);
}
fn default_value() -> Self {
true
}
}
fn render_override<T: OverrideValue>(
ui: &mut egui::Ui,
label: &str,
value: &mut Option<T>,
selected_preset_index: &mut Option<usize>,
) -> bool {
let mut changed = false;
ui.horizontal(|ui| {
if let Some(current) = value.as_mut() {
if T::render_editor(ui, current) {
*selected_preset_index = None;
changed = true;
}
} else {
T::render_placeholder(ui);
}
ui.label(label);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if value.is_some() {
if ui.small_button("Reset").clicked() {
*value = None;
*selected_preset_index = None;
changed = true;
}
} else if ui.small_button("Set").clicked() {
*value = Some(T::default_value());
*selected_preset_index = None;
changed = true;
}
});
});
changed
}