forked from 1b-agent/opencadstudio-upstream
feat(ui): add configurable Iced themes
This commit is contained in:
1 parent
73545520c8
commit
4bf14baea4
52 files changed
+3063
-5670
No files matched your search
@@ -15,7 +15,7 @@ use iced::advanced::layout::{self, Layout};
|
||||
use iced::advanced::widget::{self, Widget};
|
||||
use iced::advanced::{mouse, overlay, renderer, Clipboard, Renderer as _, Shell};
|
||||
use iced::{
|
||||
Background, Border, Color, Element, Event, Length, Point, Rectangle, Renderer, Shadow, Size,
|
||||
Background, Border, Element, Event, Length, Point, Rectangle, Renderer, Shadow, Size,
|
||||
Theme, Vector,
|
||||
};
|
||||
|
||||
@@ -113,8 +113,6 @@ pub struct CollapsePanels<'a> {
|
||||
open: Option<String>,
|
||||
/// Fallback row height, used only when there are no panels to measure.
|
||||
row_h: f32,
|
||||
/// Colour of the 1px divider drawn between panels.
|
||||
divider: Color,
|
||||
/// Chosen degradation level per panel; set during layout.
|
||||
levels: RefCell<Vec<u8>>,
|
||||
/// If set, the measured row height is written here each layout (read when
|
||||
@@ -129,13 +127,12 @@ pub struct CollapsePanels<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CollapsePanels<'a> {
|
||||
pub fn new(panels: Vec<Panel<'a>>, open: Option<String>, row_h: f32, divider: Color) -> Self {
|
||||
pub fn new(panels: Vec<Panel<'a>>, open: Option<String>, row_h: f32) -> Self {
|
||||
let n = panels.len();
|
||||
Self {
|
||||
panels,
|
||||
open,
|
||||
row_h,
|
||||
divider,
|
||||
levels: RefCell::new(vec![FULL; n]),
|
||||
height_out: None,
|
||||
tight_out: None,
|
||||
@@ -480,7 +477,7 @@ impl<'a> Widget<Message, Theme, Renderer> for CollapsePanels<'a> {
|
||||
shadow: Shadow::default(),
|
||||
snap: true,
|
||||
},
|
||||
Background::Color(self.divider),
|
||||
Background::Color(theme.extended_palette().background.neutral.color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+152
-326
@@ -12,7 +12,7 @@ use std::sync::Arc;
|
||||
use rustc_hash::FxHashMap as HashMap;
|
||||
|
||||
use acadrust::types::{Color as AcadColor, LineWeight};
|
||||
use iced::widget::{button, column, container, mouse_area, row, scrollable, svg, text};
|
||||
use iced::widget::{button, column, container, mouse_area, row, scrollable, text};
|
||||
use iced::{Background, Border, Color, Element, Fill, Length, Padding, Theme};
|
||||
|
||||
use crate::app::Message;
|
||||
@@ -419,58 +419,41 @@ impl Ribbon {
|
||||
|
||||
let is_active = i == self.active;
|
||||
let is_contextual = module.id() == "layout";
|
||||
let accent = if is_contextual {
|
||||
ACCENT_GOLD
|
||||
} else {
|
||||
ACCENT_BLUE
|
||||
};
|
||||
let text_inactive = if is_contextual {
|
||||
Color {
|
||||
r: 0.90,
|
||||
g: 0.72,
|
||||
b: 0.30,
|
||||
a: 1.0,
|
||||
}
|
||||
} else {
|
||||
Color {
|
||||
r: 0.75,
|
||||
g: 0.75,
|
||||
b: 0.75,
|
||||
a: 1.0,
|
||||
}
|
||||
};
|
||||
let hover_bg = if is_contextual {
|
||||
Color {
|
||||
r: 0.28,
|
||||
g: 0.24,
|
||||
b: 0.12,
|
||||
a: 1.0,
|
||||
}
|
||||
} else {
|
||||
Color {
|
||||
r: 0.25,
|
||||
g: 0.25,
|
||||
b: 0.25,
|
||||
a: 1.0,
|
||||
}
|
||||
};
|
||||
let btn = container(
|
||||
button(text(module.title()).size(12))
|
||||
.on_press(Message::RibbonSelectTab(i))
|
||||
.style(move |_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match (is_active, status) {
|
||||
(true, _) => RIBBON_BG,
|
||||
(false, button::Status::Hovered) => hover_bg,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
text_color: if is_active {
|
||||
Color::WHITE
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.extended_palette();
|
||||
let accent = if is_contextual {
|
||||
palette.warning.base
|
||||
} else {
|
||||
text_inactive
|
||||
palette.primary.base
|
||||
};
|
||||
let pair = match (is_active, status) {
|
||||
(true, _) => palette.background.weakest,
|
||||
(false, button::Status::Hovered) => {
|
||||
if is_contextual {
|
||||
palette.warning.weak
|
||||
} else {
|
||||
palette.background.weak
|
||||
}
|
||||
}
|
||||
_ => palette.background.base,
|
||||
};
|
||||
button::Style {
|
||||
background: (is_active
|
||||
|| matches!(status, button::Status::Hovered))
|
||||
.then_some(Background::Color(pair.color)),
|
||||
text_color: if is_active {
|
||||
pair.text
|
||||
} else if is_contextual {
|
||||
accent.color
|
||||
} else {
|
||||
palette.background.base.text.scale_alpha(0.72)
|
||||
},
|
||||
border: Border {
|
||||
color: if is_active {
|
||||
accent
|
||||
accent.color
|
||||
} else {
|
||||
Color::TRANSPARENT
|
||||
},
|
||||
@@ -479,13 +462,18 @@ impl Ribbon {
|
||||
},
|
||||
shadow: iced::Shadow::default(),
|
||||
snap: false,
|
||||
}
|
||||
})
|
||||
.padding([5, 14]),
|
||||
)
|
||||
.style(move |_: &Theme| container::Style {
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
border: Border {
|
||||
color: if is_active {
|
||||
accent
|
||||
if is_contextual {
|
||||
theme.extended_palette().warning.base.color
|
||||
} else {
|
||||
theme.extended_palette().primary.base.color
|
||||
}
|
||||
} else {
|
||||
Color::TRANSPARENT
|
||||
},
|
||||
@@ -514,9 +502,11 @@ impl Ribbon {
|
||||
// persisted (see `Ribbon::set_collapse_mode`). It hides itself once the
|
||||
// tool row is tight, giving the cramped tab row its space back.
|
||||
let dd_open = self.open_dropdown.as_deref() == Some(COLLAPSE_MODE_ID);
|
||||
let mode_btn = button(crate::ui::icons::arrow_down(10.0, ARROW_COLOR))
|
||||
let mode_btn = button(crate::ui::icons::themed_arrow_down(10.0))
|
||||
.on_press(Message::ToggleRibbonDropdown(COLLAPSE_MODE_ID.to_string()))
|
||||
.style(move |_: &Theme, status| top_hist_btn_style(true, dd_open, status))
|
||||
.style(move |theme: &Theme, status| {
|
||||
top_hist_btn_style(theme, true, dd_open, status)
|
||||
})
|
||||
.height(24)
|
||||
.padding([2, 8]);
|
||||
let mode_dd = PosReport::new(COLLAPSE_MODE_ID, mode_btn);
|
||||
@@ -534,8 +524,10 @@ impl Ribbon {
|
||||
}
|
||||
|
||||
let tab_bar = container(tab_row)
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(TOPBAR_BG)),
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.base.color,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.padding(Padding {
|
||||
@@ -653,10 +645,12 @@ impl Ribbon {
|
||||
self.active_lineweight,
|
||||
&style_ctx,
|
||||
))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(RIBBON_BG)),
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
)),
|
||||
border: Border {
|
||||
color: BORDER_DARK,
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
@@ -666,7 +660,7 @@ impl Ribbon {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H, BORDER_DARK)
|
||||
CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H)
|
||||
.report_height(self.tool_bar_h.clone())
|
||||
.report_tight(self.collapse_tight.clone())
|
||||
.mode(self.collapse_mode)
|
||||
@@ -676,10 +670,12 @@ impl Ribbon {
|
||||
};
|
||||
|
||||
let tool_bar = container(tool_area)
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(RIBBON_BG)),
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.extended_palette().background.weakest.color,
|
||||
)),
|
||||
border: Border {
|
||||
color: BORDER_DARK,
|
||||
color: theme.extended_palette().background.neutral.color,
|
||||
width: 1.0,
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
@@ -712,19 +708,13 @@ impl Ribbon {
|
||||
.enumerate()
|
||||
.map(|(idx, label)| {
|
||||
let step = idx + 1;
|
||||
button(text(label.clone()).size(11).color(LABEL_ON))
|
||||
button(text(label.clone()).size(11))
|
||||
.on_press(if is_undo {
|
||||
Message::UndoMany(step)
|
||||
} else {
|
||||
Message::RedoMany(step)
|
||||
})
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([5, 10])
|
||||
.into()
|
||||
@@ -732,15 +722,7 @@ impl Ribbon {
|
||||
.collect();
|
||||
|
||||
let panel = container(column(rows))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(170.0));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(open_id, 170.0, win.0);
|
||||
@@ -755,27 +737,16 @@ impl Ribbon {
|
||||
let rows: Vec<Element<Message>> = CollapseMode::ALL
|
||||
.iter()
|
||||
.map(|&m| {
|
||||
let mark: Element<Message> = if m == current {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
};
|
||||
button(
|
||||
row![
|
||||
container(mark).width(Length::Fixed(16.0)),
|
||||
text(m.label()).size(11).color(LABEL_ON),
|
||||
crate::ui::icons::themed_check_cell(m == current),
|
||||
text(m.label()).size(11),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::SetRibbonCollapseMode(m))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([5, 10])
|
||||
.into()
|
||||
@@ -783,15 +754,7 @@ impl Ribbon {
|
||||
.collect();
|
||||
|
||||
let panel = container(column(rows))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(W));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(open_id, W, win.0);
|
||||
@@ -852,28 +815,25 @@ impl Ribbon {
|
||||
.iter()
|
||||
.map(|(cmd, label, item_icon)| {
|
||||
let is_current = *cmd == last_cmd;
|
||||
let checkmark: Element<'_, Message> = container(if is_current {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
})
|
||||
.width(Length::Fixed(14.0))
|
||||
.into();
|
||||
let icon_el: Element<Message> = match *item_icon {
|
||||
IconKind::Glyph(s) => text(s)
|
||||
.size(13)
|
||||
.color(ICON_COLOR)
|
||||
let checkmark: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_current);
|
||||
let icon_el: Element<Message> =
|
||||
container(make_icon(*item_icon, 20.0))
|
||||
.width(Length::Fixed(20.0))
|
||||
.into(),
|
||||
IconKind::Svg(bytes) => {
|
||||
let handle = svg::Handle::from_memory(bytes);
|
||||
svg(handle).width(20).height(20).into()
|
||||
}
|
||||
};
|
||||
.into();
|
||||
let label_el =
|
||||
text(*label)
|
||||
.size(11)
|
||||
.color(if is_current { LABEL_ON } else { LABEL_OFF });
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_current).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
.scale_alpha(0.72),
|
||||
),
|
||||
});
|
||||
|
||||
button(
|
||||
row![checkmark, icon_el, label_el]
|
||||
@@ -884,13 +844,7 @@ impl Ribbon {
|
||||
dropdown_id: dd_id,
|
||||
cmd: *cmd,
|
||||
})
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 10])
|
||||
.into()
|
||||
@@ -898,15 +852,7 @@ impl Ribbon {
|
||||
.collect();
|
||||
|
||||
let panel = container(column(rows))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(190.0));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(open_id, 190.0, win.0);
|
||||
@@ -925,13 +871,7 @@ impl Ribbon {
|
||||
let icon_btn = |bytes: &'static [u8], msg: Message| -> Element<'_, Message> {
|
||||
button(crate::ui::icons::raw(bytes, 14.0))
|
||||
.on_press(msg)
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.padding([2, 4])
|
||||
.into()
|
||||
};
|
||||
@@ -952,10 +892,10 @@ impl Ribbon {
|
||||
let name = info.name.clone();
|
||||
|
||||
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(),
|
||||
},
|
||||
@@ -976,29 +916,27 @@ impl Ribbon {
|
||||
crate::ui::icons::layer_lock(ll),
|
||||
Message::LayerToggleLock(index),
|
||||
);
|
||||
let checkmark: Element<'_, Message> = container(if is_active {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
})
|
||||
.width(Length::Fixed(14.0))
|
||||
.into();
|
||||
let checkmark: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_active);
|
||||
let label =
|
||||
text(&info.name)
|
||||
.size(11)
|
||||
.color(if is_active { LABEL_ON } else { LABEL_OFF });
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_active).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
.scale_alpha(0.72),
|
||||
),
|
||||
});
|
||||
|
||||
// The swatch + label area selects the layer as active; the
|
||||
// icon buttons above handle their own toggles.
|
||||
let select = button(row![swatch, label].spacing(5).align_y(iced::Center))
|
||||
.on_press(Message::RibbonLayerChanged(name))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 4]);
|
||||
|
||||
@@ -1021,34 +959,7 @@ impl Ribbon {
|
||||
let search = iced::widget::text_input("Search layers…", &self.layer_filter)
|
||||
.on_input(Message::RibbonLayerFilterChanged)
|
||||
.size(11)
|
||||
.padding([4, 6])
|
||||
.style(|_: &Theme, _| iced::widget::text_input::Style {
|
||||
background: Background::Color(Color {
|
||||
r: 0.10,
|
||||
g: 0.10,
|
||||
b: 0.10,
|
||||
a: 1.0,
|
||||
}),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 2.0.into(),
|
||||
},
|
||||
icon: Color::WHITE,
|
||||
placeholder: Color {
|
||||
r: 0.45,
|
||||
g: 0.45,
|
||||
b: 0.45,
|
||||
a: 1.0,
|
||||
},
|
||||
value: Color::WHITE,
|
||||
selection: Color {
|
||||
r: 0.20,
|
||||
g: 0.44,
|
||||
b: 0.72,
|
||||
a: 0.5,
|
||||
},
|
||||
});
|
||||
.padding([4, 6]);
|
||||
let panel = container(
|
||||
column![
|
||||
container(search).padding([4, 4]),
|
||||
@@ -1056,15 +967,7 @@ impl Ribbon {
|
||||
]
|
||||
.spacing(2),
|
||||
)
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(220.0));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(LAYER_COMBO_ID, 220.0, win.0);
|
||||
@@ -1113,35 +1016,29 @@ impl Ribbon {
|
||||
};
|
||||
let active = ctx.active_for(style_key).to_string();
|
||||
|
||||
let row_style = |_: &Theme, status: button::Status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut rows: Vec<Element<Message>> = ctx
|
||||
.names_for(style_key)
|
||||
.iter()
|
||||
.map(|name| {
|
||||
let is_sel = name.as_str() == active.as_str();
|
||||
let n = name.clone();
|
||||
let checkmark: Element<Message> = container(if is_sel {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
})
|
||||
.width(Length::Fixed(14.0))
|
||||
.into();
|
||||
let checkmark: Element<Message> =
|
||||
crate::ui::icons::themed_check_cell(is_sel);
|
||||
button(
|
||||
row![
|
||||
checkmark,
|
||||
text(name.clone()).size(11).color(if is_sel {
|
||||
LABEL_ON
|
||||
} else {
|
||||
LABEL_OFF
|
||||
}),
|
||||
text(name.clone())
|
||||
.size(11)
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_sel).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
.scale_alpha(0.72),
|
||||
),
|
||||
}),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center),
|
||||
@@ -1150,7 +1047,7 @@ impl Ribbon {
|
||||
key: style_key,
|
||||
name: n,
|
||||
})
|
||||
.style(row_style)
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 10])
|
||||
.into()
|
||||
@@ -1159,9 +1056,9 @@ impl Ribbon {
|
||||
|
||||
if let Some(mgr) = manager_cmd {
|
||||
rows.push(
|
||||
button(text("Manage…").size(11).color(LABEL_ON))
|
||||
button(text("Manage…").size(11))
|
||||
.on_press(Message::Command(mgr.to_string()))
|
||||
.style(row_style)
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 10])
|
||||
.into(),
|
||||
@@ -1169,15 +1066,7 @@ impl Ribbon {
|
||||
}
|
||||
|
||||
let panel = container(column(rows))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(LARGE_W * 2.3));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(open_id, LARGE_W * 2.3, win.0);
|
||||
@@ -1200,15 +1089,7 @@ impl Ribbon {
|
||||
);
|
||||
|
||||
let panel = container(picker)
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(200.0));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(PROP_COLOR_ID, 200.0, win.0);
|
||||
@@ -1243,23 +1124,22 @@ impl Ribbon {
|
||||
.into_iter()
|
||||
.map(|lt| {
|
||||
let is_cur = lt.name == *active_lt;
|
||||
let check: Element<'_, Message> = container(if is_cur {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
})
|
||||
.width(Length::Fixed(14.0))
|
||||
.into();
|
||||
let check: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_cur);
|
||||
let name_col = text(lt.name.clone())
|
||||
.size(11)
|
||||
.color(if is_cur { LABEL_ON } else { LABEL_OFF })
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_cur).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
.scale_alpha(0.72),
|
||||
),
|
||||
})
|
||||
.width(Length::Fixed(90.0));
|
||||
let art_col = text(lt.art.clone()).size(9).color(Color {
|
||||
r: 0.55,
|
||||
g: 0.55,
|
||||
b: 0.55,
|
||||
a: 1.0,
|
||||
});
|
||||
let art_col = text(lt.art.clone()).size(9).style(muted_text_style);
|
||||
let name = lt.name.clone();
|
||||
button(
|
||||
row![check, name_col, art_col]
|
||||
@@ -1267,13 +1147,7 @@ impl Ribbon {
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::RibbonLinetypeChanged(name))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 6])
|
||||
.into()
|
||||
@@ -1281,15 +1155,7 @@ impl Ribbon {
|
||||
.collect();
|
||||
|
||||
let list = container(scrollable(column(rows)).height(Length::Fixed(200.0)))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(220.0));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(PROP_LINETYPE_ID, 220.0, win.0);
|
||||
@@ -1308,31 +1174,29 @@ impl Ribbon {
|
||||
.map(|item| {
|
||||
let is_cur = item.0 == active_lw;
|
||||
let label = item.to_string();
|
||||
let check: Element<'_, Message> = container(if is_cur {
|
||||
crate::ui::icons::tinted(crate::ui::icons::CHECK, 11.0, CHECK_COLOR)
|
||||
} else {
|
||||
iced::widget::Space::new().width(0).into()
|
||||
})
|
||||
.width(Length::Fixed(14.0))
|
||||
.into();
|
||||
let check: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_cur);
|
||||
button(
|
||||
row![
|
||||
check,
|
||||
text(label)
|
||||
.size(11)
|
||||
.color(if is_cur { LABEL_ON } else { LABEL_OFF })
|
||||
.style(move |theme: &Theme| iced::widget::text::Style {
|
||||
color: (!is_cur).then_some(
|
||||
theme
|
||||
.extended_palette()
|
||||
.background
|
||||
.base
|
||||
.text
|
||||
.scale_alpha(0.72),
|
||||
),
|
||||
})
|
||||
]
|
||||
.spacing(5)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::RibbonLineweightChanged(item.0))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered | button::Status::Pressed => ROW_HOVER,
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_row_style)
|
||||
.width(Fill)
|
||||
.padding([4, 8])
|
||||
.into()
|
||||
@@ -1350,15 +1214,7 @@ impl Ribbon {
|
||||
win: (f32, f32),
|
||||
) -> Option<Element<'a, Message>> {
|
||||
let panel = container(column(rows))
|
||||
.style(|_: &Theme| container::Style {
|
||||
background: Some(Background::Color(PANEL_BG)),
|
||||
border: Border {
|
||||
color: PANEL_BORDER,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(popup_panel_style)
|
||||
.width(Length::Fixed(width));
|
||||
|
||||
let (align_right, h_pad, top) = self.dd_anchor(dd_id, width, win.0);
|
||||
@@ -1439,7 +1295,7 @@ fn render_group<'a>(
|
||||
|
||||
column![
|
||||
tools_el,
|
||||
container(text(group.title).size(9).color(GROUP_LABEL)).padding([1, 4]),
|
||||
container(text(group.title).size(9).style(muted_text_style)).padding([1, 4]),
|
||||
]
|
||||
.align_x(iced::Center)
|
||||
.spacing(0)
|
||||
@@ -1526,8 +1382,8 @@ fn collapse_button<'a>(
|
||||
column![
|
||||
icon,
|
||||
row![
|
||||
text(title.to_string()).size(9).color(GROUP_LABEL),
|
||||
crate::ui::icons::arrow_down(8.0, GROUP_LABEL),
|
||||
text(title.to_string()).size(9).style(muted_text_style),
|
||||
crate::ui::icons::themed_secondary_arrow_down(8.0),
|
||||
]
|
||||
.spacing(3)
|
||||
.align_y(iced::Center),
|
||||
@@ -1536,22 +1392,7 @@ fn collapse_button<'a>(
|
||||
.spacing(2),
|
||||
)
|
||||
.on_press(Message::ToggleRibbonPanel(title.to_string()))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered => Color {
|
||||
r: 0.25,
|
||||
g: 0.25,
|
||||
b: 0.25,
|
||||
a: 1.0,
|
||||
},
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
border: Border {
|
||||
radius: 2.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(button::subtle)
|
||||
.padding([3, 5])
|
||||
.into();
|
||||
}
|
||||
@@ -1594,29 +1435,14 @@ fn collapse_button<'a>(
|
||||
|
||||
let opener = button(
|
||||
row![
|
||||
text(title.to_string()).size(9).color(GROUP_LABEL),
|
||||
crate::ui::icons::arrow_down(8.0, GROUP_LABEL),
|
||||
text(title.to_string()).size(9).style(muted_text_style),
|
||||
crate::ui::icons::themed_secondary_arrow_down(8.0),
|
||||
]
|
||||
.spacing(3)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.on_press(Message::ToggleRibbonPanel(title.to_string()))
|
||||
.style(|_: &Theme, status| button::Style {
|
||||
background: Some(Background::Color(match status {
|
||||
button::Status::Hovered => Color {
|
||||
r: 0.25,
|
||||
g: 0.25,
|
||||
b: 0.25,
|
||||
a: 1.0,
|
||||
},
|
||||
_ => Color::TRANSPARENT,
|
||||
})),
|
||||
border: Border {
|
||||
radius: 2.0.into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.style(button::subtle)
|
||||
.padding([1, 4]);
|
||||
|
||||
// The large face fills a fixed slot so a collapsed panel is shorter than a full
|
||||
|
||||
+197
-350
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user