feat(ui): add configurable Iced themes

This commit is contained in:
Hakan Seven committed 2026-07-28 09:33:12 +03:00
1 parent 73545520c8
commit 4bf14baea4
52 files changed
+3063 -5670

No files matched your search

+197 -350
View File
@@ -8,7 +8,7 @@ use acadrust::types::{Color as AcadColor, LineWeight};
// Ribbon tooltips anchor to the right of their button so the cursor — which
// rests on the button itself — never covers the tip text. (#143)
use iced::widget::tooltip::Position as TipPos;
use iced::widget::{button, column, container, row, svg, text, tooltip};
use iced::widget::{button, column, container, row, text, tooltip};
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
use crate::app::Message;
@@ -77,175 +77,6 @@ pub(super) const PROP_COLOR_ID: &str = "PROP_COLOR";
pub(super) const PROP_LINETYPE_ID: &str = "PROP_LINETYPE";
pub(super) const PROP_LW_ID: &str = "PROP_LW";
// ── Colours ────────────────────────────────────────────────────────────────
/// Light chrome grey for the quick-access file-command icons on the top strip.
pub(super) const QA_ICON_COLOR: Color = Color {
r: 0.82,
g: 0.83,
b: 0.85,
a: 1.0,
};
pub(super) const TOPBAR_BG: Color = Color {
r: 0.17,
g: 0.17,
b: 0.17,
a: 1.0,
};
pub(super) const RIBBON_BG: Color = Color {
r: 0.22,
g: 0.22,
b: 0.22,
a: 1.0,
};
pub(super) const BORDER_DARK: Color = Color {
r: 0.12,
g: 0.12,
b: 0.12,
a: 1.0,
};
pub(super) const ACCENT_BLUE: Color = Color {
r: 0.20,
g: 0.55,
b: 0.90,
a: 1.0,
};
pub(super) const ACCENT_GOLD: Color = Color {
r: 0.90,
g: 0.65,
b: 0.10,
a: 1.0,
};
pub(super) const LABEL_COLOR: Color = Color {
r: 0.82,
g: 0.82,
b: 0.82,
a: 1.0,
};
pub(super) const GROUP_LABEL: Color = Color {
r: 0.50,
g: 0.50,
b: 0.50,
a: 1.0,
};
pub(super) const TOOL_HOVER: Color = Color {
r: 0.32,
g: 0.32,
b: 0.32,
a: 1.0,
};
pub(super) const TOOL_ACTIVE: Color = Color {
r: 0.18,
g: 0.42,
b: 0.70,
a: 1.0,
};
pub(super) const ARROW_COLOR: Color = Color {
r: 0.65,
g: 0.65,
b: 0.65,
a: 1.0,
};
pub(super) const PANEL_BG: Color = Color {
r: 0.16,
g: 0.16,
b: 0.16,
a: 0.98,
};
pub(super) const PANEL_BORDER: Color = Color {
r: 0.32,
g: 0.32,
b: 0.32,
a: 1.0,
};
pub(super) const ROW_HOVER: Color = Color {
r: 0.24,
g: 0.24,
b: 0.24,
a: 1.0,
};
pub(super) const CHECK_COLOR: Color = Color {
r: 0.20,
g: 0.75,
b: 0.35,
a: 1.0,
};
pub(super) const ICON_COLOR: Color = Color {
r: 0.25,
g: 0.75,
b: 0.45,
a: 1.0,
};
pub(super) const LABEL_ON: Color = Color {
r: 0.92,
g: 0.92,
b: 0.92,
a: 1.0,
};
pub(super) const LABEL_OFF: Color = Color {
r: 0.72,
g: 0.72,
b: 0.72,
a: 1.0,
};
// ── Combo / dropdown colors ───────────────────────────────────────────────
pub(super) const COMBO_BG: Color = Color {
r: 0.18,
g: 0.18,
b: 0.18,
a: 1.0,
};
pub(super) const COMBO_HOVER_BG: Color = Color {
r: 0.26,
g: 0.26,
b: 0.26,
a: 1.0,
};
pub(super) const COMBO_OPEN_BG: Color = Color {
r: 0.14,
g: 0.14,
b: 0.14,
a: 1.0,
};
pub(super) const COMBO_BORDER: Color = Color {
r: 0.35,
g: 0.35,
b: 0.35,
a: 1.0,
};
pub(super) const COMBO_ACTIVE_BORDER: Color = Color {
r: 0.45,
g: 0.65,
b: 0.90,
a: 1.0,
};
pub(super) const COMBO_ARROW: Color = Color {
r: 0.70,
g: 0.70,
b: 0.70,
a: 1.0,
};
pub(super) const SWATCH_BORDER: Color = Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.5,
};
pub(super) const TIP_BG: Color = Color {
r: 0.13,
g: 0.13,
b: 0.13,
a: 0.97,
};
pub(super) const HIST_INACTIVE_BG: Color = Color {
r: 0.20,
g: 0.20,
b: 0.20,
a: 1.0,
};
// ── Style context (passed from Ribbon to render_large) ────────────────────
pub(super) struct StyleContext {
@@ -294,11 +125,8 @@ pub(super) fn flush_small_col<'a>(
pub(super) fn make_icon(icon: IconKind, size: f32) -> Element<'static, Message> {
match icon {
IconKind::Glyph(s) => text(s).size(size * 0.7).color(Color::WHITE).into(),
IconKind::Svg(bytes) => {
let handle = svg::Handle::from_memory(bytes);
svg(handle).width(size).height(size).into()
}
IconKind::Glyph(s) => text(s).size(size * 0.7).into(),
IconKind::Svg(bytes) => icons::themed(bytes, size),
}
}
@@ -309,22 +137,19 @@ pub(super) fn start_dimmed(state: &ToggleState, event: &ModuleEvent) -> bool {
&& !matches!(event, ModuleEvent::Command(c) if crate::app::commands::start_allowed(c))
}
/// Label / glyph color for a possibly-dimmed tool.
pub(super) const DIM_TOOL: Color = Color {
r: 0.42,
g: 0.42,
b: 0.45,
a: 1.0,
};
/// `make_icon`, greyed out when `dim` (SVGs render monochrome via tint).
pub(super) fn make_icon_dim(icon: IconKind, size: f32, dim: bool) -> Element<'static, Message> {
if !dim {
return make_icon(icon, size);
}
match icon {
IconKind::Glyph(s) => text(s).size(size * 0.7).color(DIM_TOOL).into(),
IconKind::Svg(bytes) => icons::tinted(bytes, size, DIM_TOOL),
IconKind::Glyph(s) => text(s)
.size(size * 0.7)
.style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.42)),
})
.into(),
IconKind::Svg(bytes) => icons::themed_disabled(bytes, size),
}
}
@@ -349,15 +174,24 @@ pub(super) fn is_active_tool(
// ── Button style ───────────────────────────────────────────────────────────
pub(super) fn tool_btn_style(is_active: bool, status: button::Status) -> button::Style {
pub(super) fn tool_btn_style(
theme: &Theme,
is_active: bool,
status: button::Status,
) -> button::Style {
let palette = theme.extended_palette();
let pair = match (is_active, status) {
(true, _) => palette.primary.weak,
(_, button::Status::Hovered) => palette.background.weak,
(_, button::Status::Pressed) => palette.primary.weak,
_ => palette.background.base,
};
button::Style {
background: Some(Background::Color(match (is_active, status) {
(true, _) => TOOL_ACTIVE,
(_, button::Status::Hovered) => TOOL_HOVER,
(_, button::Status::Pressed) => TOOL_ACTIVE,
_ => Color::TRANSPARENT,
})),
text_color: Color::WHITE,
background: is_active
.then_some(Background::Color(pair.color))
.or_else(|| matches!(status, button::Status::Hovered | button::Status::Pressed)
.then_some(Background::Color(pair.color))),
text_color: pair.text,
border: Border {
radius: 3.0.into(),
color: Color::TRANSPARENT,
@@ -368,21 +202,93 @@ pub(super) fn tool_btn_style(is_active: bool, status: button::Status) -> button:
}
}
// ── Tooltip helpers ────────────────────────────────────────────────────────
pub(super) fn make_tip(tip: String) -> Element<'static, Message> {
text(tip).size(11).color(Color::WHITE).into()
pub(super) fn combo_btn_style(
theme: &Theme,
is_open: bool,
status: button::Status,
radius: f32,
) -> button::Style {
let palette = theme.extended_palette();
let pair = if is_open {
palette.primary.weak
} else if matches!(status, button::Status::Hovered | button::Status::Pressed) {
palette.background.weak
} else {
palette.background.weakest
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
radius: radius.into(),
width: 1.0,
color: if is_open {
palette.primary.base.color
} else {
palette.background.neutral.color
},
},
..Default::default()
}
}
pub(super) fn tip_style(_theme: &Theme) -> container::Style {
pub(super) fn popup_row_style(theme: &Theme, status: button::Status) -> button::Style {
let palette = theme.extended_palette();
let pair = if matches!(status, button::Status::Hovered | button::Status::Pressed) {
palette.background.weak
} else {
palette.background.base
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
..Default::default()
}
}
pub(super) fn popup_panel_style(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(TIP_BG)),
background: Some(Background::Color(palette.background.base.color)),
border: Border {
color: COMBO_BORDER,
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
text_color: Some(Color::WHITE),
..Default::default()
}
}
pub(super) fn muted_text_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.extended_palette().background.base.text.scale_alpha(0.72)),
}
}
pub(super) fn tool_label_style(theme: &Theme, dim: bool) -> iced::widget::text::Style {
iced::widget::text::Style {
color: dim.then_some(
theme.extended_palette().background.base.text.scale_alpha(0.42),
),
}
}
// ── Tooltip helpers ────────────────────────────────────────────────────────
pub(super) fn make_tip(tip: String) -> Element<'static, Message> {
text(tip).size(11).into()
}
pub(super) fn tip_style(theme: &Theme) -> container::Style {
let palette = theme.extended_palette();
container::Style {
background: Some(Background::Color(palette.background.strong.color)),
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
text_color: Some(palette.background.strong.text),
..Default::default()
}
}
@@ -408,7 +314,7 @@ pub(super) fn render_small<'a>(
let tip_text = format!("{}\nCommand: {}", t.label, t.id);
let btn = button(make_icon_dim(t.icon, SMALL_ICON, dim))
.on_press(Message::RibbonToolClick { tool_id, event })
.style(move |_: &Theme, status| tool_btn_style(active, status))
.style(move |theme: &Theme, status| tool_btn_style(theme, active, status))
.width(Length::Fixed(SMALL_W))
.height(ROW_H)
.padding([4, 4]);
@@ -474,31 +380,22 @@ pub(super) fn render_small<'a>(
tool_id: last.to_string(),
event: ModuleEvent::Command(last.to_string()),
})
.style(move |_: &Theme, status| tool_btn_style(active, status))
.style(move |theme: &Theme, status| tool_btn_style(theme, active, status))
.width(Length::Fixed(SMALL_W))
.height(ROW_H)
.padding([4, 4]);
let arr_tip = format!("{} options", cur_label);
let arr_btn = button(
container(icons::arrow_down(8.0, ARROW_COLOR))
container(icons::themed_arrow_down(8.0))
.width(Fill)
.height(Fill)
.align_x(iced::Center)
.align_y(iced::Center),
)
.on_press(Message::ToggleRibbonDropdown(id.to_string()))
.style(move |_: &Theme, status| button::Style {
background: Some(Background::Color(match status {
button::Status::Hovered | button::Status::Pressed => TOOL_HOVER,
_ if dd_open => TOOL_ACTIVE,
_ => Color::TRANSPARENT,
})),
border: Border {
radius: 2.0.into(),
..Default::default()
},
..Default::default()
.style(move |theme: &Theme, status| {
tool_btn_style(theme, dd_open, status)
})
.width(Length::Fixed(ARROW_W))
.height(ROW_H)
@@ -569,7 +466,9 @@ pub(super) fn render_large_dropdown<'a>(
let top_btn = button(
column![
make_icon_dim(cur_icon, LARGE_ICON, dim),
text(label.to_string()).size(10).color(if dim { DIM_TOOL } else { LABEL_COLOR }),
text(label.to_string())
.size(10)
.style(move |theme: &Theme| tool_label_style(theme, dim)),
]
.align_x(iced::Center)
.spacing(3),
@@ -578,7 +477,7 @@ pub(super) fn render_large_dropdown<'a>(
tool_id: last.to_string(),
event: ModuleEvent::Command(last.to_string()),
})
.style(move |_: &Theme, status| tool_btn_style(active, status))
.style(move |theme: &Theme, status| tool_btn_style(theme, active, status))
.width(Length::Fixed(LARGE_W))
.height(Fill)
.padding(Padding {
@@ -589,24 +488,15 @@ pub(super) fn render_large_dropdown<'a>(
});
let arr_btn = button(
container(icons::arrow_down(9.0, ARROW_COLOR))
container(icons::themed_arrow_down(9.0))
.width(Fill)
.height(Fill)
.align_x(iced::Center)
.align_y(iced::Center),
)
.on_press(Message::ToggleRibbonDropdown(id.to_string()))
.style(move |_: &Theme, status| button::Style {
background: Some(Background::Color(match status {
button::Status::Hovered | button::Status::Pressed => TOOL_HOVER,
_ if dd_open => TOOL_ACTIVE,
_ => Color::TRANSPARENT,
})),
border: Border {
radius: 3.0.into(),
..Default::default()
},
..Default::default()
.style(move |theme: &Theme, status| {
tool_btn_style(theme, dd_open, status)
})
.width(Length::Fixed(LARGE_W))
.height(LARGE_ARR)
@@ -659,13 +549,15 @@ pub(super) fn render_large<'a>(
let btn = button(
column![
make_icon_dim(t.icon, LARGE_ICON, dim),
text(t.label).size(10).color(if dim { DIM_TOOL } else { LABEL_COLOR }),
text(t.label)
.size(10)
.style(move |theme: &Theme| tool_label_style(theme, dim)),
]
.align_x(iced::Center)
.spacing(3),
)
.on_press(Message::RibbonToolClick { tool_id, event })
.style(move |_: &Theme, status| tool_btn_style(active, status))
.style(move |theme: &Theme, status| tool_btn_style(theme, active, status))
.width(Length::Fixed(LARGE_W))
.height(Fill)
.padding(Padding {
@@ -737,10 +629,10 @@ pub(super) fn render_large<'a>(
let freeze_icon = icons::raw(icons::layer_freeze(lf), 14.0);
let lock_icon = icons::raw(icons::layer_lock(ll), 14.0);
let swatch = container(text(""))
.style(move |_: &Theme| container::Style {
.style(move |theme: &Theme| container::Style {
background: Some(Background::Color(lc)),
border: Border {
color: SWATCH_BORDER,
color: theme.extended_palette().background.strong.color,
width: 1.0,
radius: 1.0.into(),
},
@@ -758,27 +650,17 @@ pub(super) fn render_large<'a>(
freeze_icon,
lock_icon,
swatch,
container(text(active_layer).size(11).color(Color::WHITE))
container(text(active_layer).size(11))
.width(name_w)
.clip(true),
icons::arrow_down(9.0, COMBO_ARROW),
icons::themed_arrow_down(9.0),
]
.spacing(4)
.align_y(iced::Center),
)
.on_press(Message::ToggleRibbonDropdown(LAYER_COMBO_ID.to_string()))
.style(move |_: &Theme, status| button::Style {
background: Some(Background::Color(match (is_open, status) {
(true, _) => COMBO_OPEN_BG,
(_, button::Status::Hovered) => COMBO_HOVER_BG,
_ => COMBO_BG,
})),
border: Border {
radius: 3.0.into(),
width: 1.0,
color: COMBO_BORDER,
},
..Default::default()
.style(move |theme: &Theme, status| {
combo_btn_style(theme, is_open, status, 3.0)
})
.padding([3, 8])
.width(Fill);
@@ -793,20 +675,16 @@ pub(super) fn render_large<'a>(
let event = t.event.clone();
let icon_el: Element<Message> = if dim {
make_icon_dim(t.icon, 16.0, true)
} else { match t.icon {
IconKind::Glyph(g) => text(g).size(13).color(Color::WHITE).into(),
IconKind::Svg(bytes) => {
iced::widget::svg(iced::widget::svg::Handle::from_memory(bytes))
.width(16)
.height(16)
.into()
}
} };
} else {
make_icon(t.icon, 16.0)
};
let msg = module_event_to_message(event);
tooltip(
button(icon_el)
.on_press(msg)
.style(move |_: &Theme, status| tool_btn_style(is_active, status))
.style(move |theme: &Theme, status| {
tool_btn_style(theme, is_active, status)
})
.padding([2, 5]),
make_tip(tip.to_string()),
TipPos::Right,
@@ -864,7 +742,9 @@ pub(super) fn render_large<'a>(
let mp_btn = button(
column![
make_icon_dim(match_prop.icon, LARGE_ICON, mp_dim),
text(match_prop.label).size(10).color(if mp_dim { DIM_TOOL } else { LABEL_COLOR }),
text(match_prop.label)
.size(10)
.style(move |theme: &Theme| tool_label_style(theme, mp_dim)),
]
.align_x(iced::Center)
.spacing(3),
@@ -873,7 +753,7 @@ pub(super) fn render_large<'a>(
tool_id: mp_id,
event: mp_event,
})
.style(move |_: &Theme, status| tool_btn_style(mp_active, status))
.style(move |theme: &Theme, status| tool_btn_style(theme, mp_active, status))
.width(Length::Fixed(LARGE_W))
.height(Fill)
.padding(Padding {
@@ -895,10 +775,10 @@ pub(super) fn render_large<'a>(
let is_open = open_dd.as_deref() == Some(dd_id);
let swatch_el: Element<'a, Message> = if let Some(c) = swatch {
container(text(""))
.style(move |_: &Theme| container::Style {
.style(move |theme: &Theme| container::Style {
background: Some(Background::Color(c)),
border: Border {
color: SWATCH_BORDER,
color: theme.extended_palette().background.strong.color,
width: 1.0,
radius: 1.0.into(),
},
@@ -913,40 +793,21 @@ pub(super) fn render_large<'a>(
button(
row![
swatch_el,
container(text(label).size(10).color(Color::WHITE))
container(text(label).size(10))
.width(Fill)
.clip(true),
icons::arrow_toggle(
is_open,
8.0,
Color {
r: 0.6,
g: 0.6,
b: 0.6,
a: 1.0,
},
),
if is_open {
icons::themed_arrow_up(8.0)
} else {
icons::themed_arrow_down(8.0)
},
]
.spacing(4)
.align_y(iced::Center),
)
.on_press(Message::ToggleRibbonDropdown(dd_id.to_string()))
.style(move |_: &Theme, status| button::Style {
background: Some(Background::Color(match (is_open, status) {
(true, _) => COMBO_OPEN_BG,
(_, button::Status::Hovered) => COMBO_HOVER_BG,
_ => COMBO_BG,
})),
border: Border {
radius: 2.0.into(),
width: 1.0,
color: if is_open {
COMBO_ACTIVE_BORDER
} else {
COMBO_BORDER
},
},
..Default::default()
.style(move |theme: &Theme, status| {
combo_btn_style(theme, is_open, status, 2.0)
})
.padding([3, 8])
.width(Length::Fixed(PROP_W))
@@ -999,31 +860,21 @@ pub(super) fn render_large<'a>(
// ── combo button ──
let combo_btn = button(
row![
container(text(active.clone()).size(11).color(Color::WHITE))
container(text(active.clone()).size(11))
.width(Fill)
.clip(true),
icons::arrow_toggle(is_open, 9.0, COMBO_ARROW),
if is_open {
icons::themed_arrow_up(9.0)
} else {
icons::themed_arrow_down(9.0)
},
]
.spacing(4)
.align_y(iced::Center),
)
.on_press(Message::ToggleRibbonDropdown(combo_id.to_string()))
.style(move |_: &Theme, status| button::Style {
background: Some(Background::Color(match (is_open, status) {
(true, _) => COMBO_OPEN_BG,
(_, button::Status::Hovered) => COMBO_HOVER_BG,
_ => COMBO_BG,
})),
border: Border {
radius: 3.0.into(),
width: 1.0,
color: if is_open {
COMBO_ACTIVE_BORDER
} else {
COMBO_BORDER
},
},
..Default::default()
.style(move |theme: &Theme, status| {
combo_btn_style(theme, is_open, status, 3.0)
})
.padding([3, 8])
.width(Fill);
@@ -1045,20 +896,16 @@ pub(super) fn render_large<'a>(
let event = t.event.clone();
let icon_el: Element<Message> = if dim {
make_icon_dim(t.icon, 16.0, true)
} else { match t.icon {
IconKind::Glyph(g) => text(g).size(13).color(Color::WHITE).into(),
IconKind::Svg(bytes) => {
iced::widget::svg(iced::widget::svg::Handle::from_memory(bytes))
.width(16)
.height(16)
.into()
}
} };
} else {
make_icon(t.icon, 16.0)
};
let msg = module_event_to_message(event);
tooltip(
button(icon_el)
.on_press(msg)
.style(move |_: &Theme, status| tool_btn_style(is_active, status))
.style(move |theme: &Theme, status| {
tool_btn_style(theme, is_active, status)
})
.padding([2, 5]),
make_tip(tip.to_string()),
TipPos::Right,
@@ -1128,7 +975,11 @@ pub(super) fn quick_access_btn<'a>(
// they read on the dark top strip (raw black is invisible there).
// On the Start tab, commands the start gate refuses render dimmed.
let dim = is_start && !crate::app::commands::start_allowed(cmd);
let icon = icons::tinted(icon_bytes, 16.0, if dim { DIM_TOOL } else { QA_ICON_COLOR });
let icon = if dim {
icons::themed_disabled(icon_bytes, 16.0)
} else {
icons::themed(icon_bytes, 16.0)
};
let btn = button(
container(icon)
.width(Fill)
@@ -1137,22 +988,7 @@ pub(super) fn quick_access_btn<'a>(
.align_y(iced::Center),
)
.on_press(Message::Command(cmd.to_string()))
.style(|_: &Theme, status| button::Style {
background: Some(Background::Color(match status {
button::Status::Hovered | button::Status::Pressed => Color {
r: 0.30,
g: 0.30,
b: 0.30,
a: 1.0,
},
_ => Color::TRANSPARENT,
})),
border: Border {
radius: 2.0.into(),
..Default::default()
},
..Default::default()
})
.style(button::subtle)
.width(Length::Fixed(TOP_HIST_W))
.height(24)
.padding([2, 0]);
@@ -1171,13 +1007,12 @@ pub(super) fn render_history_control<'a>(
) -> Element<'a, Message> {
let dd_open = open_dropdown.as_deref() == Some(dropdown_id);
let active = count > 0;
let icon_color = if active { Color::WHITE } else { LABEL_OFF };
let main_btn = {
let glyph = if dropdown_id == UNDO_HISTORY_ID {
icons::undo(15.0, icon_color)
icons::themed_undo(15.0, active)
} else {
icons::redo(15.0, icon_color)
icons::themed_redo(15.0, active)
};
let btn = button(
container(glyph)
@@ -1186,7 +1021,9 @@ pub(super) fn render_history_control<'a>(
.align_x(iced::Center)
.align_y(iced::Center),
)
.style(move |_: &Theme, status| top_hist_btn_style(active, dd_open, status))
.style(move |theme: &Theme, status| {
top_hist_btn_style(theme, active, dd_open, status)
})
.width(Length::Fixed(TOP_HIST_W))
.height(24)
.padding([2, 0]);
@@ -1211,16 +1048,19 @@ pub(super) fn render_history_control<'a>(
let arrow_btn = {
let btn = button(
container(icons::arrow_down(
8.0,
if active { ARROW_COLOR } else { LABEL_OFF },
))
container(if active {
icons::themed_arrow_down(8.0)
} else {
icons::themed_disabled_arrow_down(8.0)
})
.width(Fill)
.height(Fill)
.align_x(iced::Center)
.align_y(iced::Center),
)
.style(move |_: &Theme, status| top_hist_btn_style(active, dd_open, status))
.style(move |theme: &Theme, status| {
top_hist_btn_style(theme, active, dd_open, status)
})
.width(Length::Fixed(TOP_ARR_W))
.height(24)
.padding(0);
@@ -1243,19 +1083,26 @@ pub(super) fn render_history_control<'a>(
}
pub(super) fn top_hist_btn_style(
theme: &Theme,
active: bool,
open: bool,
status: button::Status,
) -> button::Style {
let palette = theme.extended_palette();
let pair = match (active, open, status) {
(false, _, _) => palette.background.weakest,
(_, true, _) => palette.primary.weak,
(_, _, button::Status::Hovered) => palette.background.weak,
(_, _, button::Status::Pressed) => palette.primary.weak,
_ => palette.background.base,
};
button::Style {
background: Some(Background::Color(match (active, open, status) {
(false, _, _) => HIST_INACTIVE_BG,
(_, true, _) => TOOL_ACTIVE,
(_, _, button::Status::Hovered) => TOOL_HOVER,
(_, _, button::Status::Pressed) => TOOL_ACTIVE,
_ => Color::TRANSPARENT,
})),
text_color: Color::WHITE,
background: (!active || open || matches!(
status,
button::Status::Hovered | button::Status::Pressed
))
.then_some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
radius: 3.0.into(),
color: Color::TRANSPARENT,