From 8eef1188ce0262fa9de7a0eb3b56ff9e310e6e51 Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Sat, 20 Jun 2026 10:38:42 +0800 Subject: [PATCH] refactor(editor): unify toolbar icon buttons into one paint_icon_button helper Adds button::paint_icon_button (full icon button = hover/pressed/active feedback on jian Button + centred icon) and paint_icon_button_feedback (the bg+active funnel). toolbar's paint_button now delegates to it instead of hand-rolling active-fill + ghost-feedback + draw_icon separately. All toolbar icon buttons (tool buttons + shape slot) now funnel hover/active rendering through one place. Active highlight now jian Button Primary (r6). Removed dead BUTTON_RADIUS. --- crates/op-editor-ui/src/widgets/button.rs | 56 +++++++++++++++++++++- crates/op-editor-ui/src/widgets/toolbar.rs | 27 +++-------- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/crates/op-editor-ui/src/widgets/button.rs b/crates/op-editor-ui/src/widgets/button.rs index 032e0e931..f4ed8555c 100644 --- a/crates/op-editor-ui/src/widgets/button.rs +++ b/crates/op-editor-ui/src/widgets/button.rs @@ -1,4 +1,5 @@ -use crate::{Color, Rect, RenderBackend, Theme}; +use crate::widgets::icons::{draw_icon, Icon}; +use crate::{Color, Point2D, Rect, RenderBackend, Theme}; use jian_widgets::components::button::{Button, ButtonVariant}; use jian_widgets::{Density, Tokens}; @@ -77,6 +78,59 @@ pub(crate) fn paint_button_feedback_wash( } } +/// Icon-button background + feedback, centralised on jian Button. `active` paints +/// the solid primary highlight (e.g. the selected toolbar tool); inactive uses the +/// ghost hover/press wash. Returns the icon color to stroke on top — every icon +/// button funnels its hover/active rendering through here instead of hand-rolling it. +pub(crate) fn paint_icon_button_feedback( + backend: &mut dyn RenderBackend, + theme: &Theme, + rect: Rect, + hovered: bool, + pressed: bool, + active: bool, +) -> Color { + if active { + Button { + label: "", + icon_d: None, + variant: ButtonVariant::Primary, + enabled: true, + hovered, + pressed, + font_size: 0.0, + } + .paint(backend, rect, &tokens_from_theme(theme)); + theme.primary_foreground + } else { + paint_ghost_button_feedback(backend, theme, rect, hovered, pressed) + } +} + +/// A complete icon button: hover / pressed / active feedback (centralised on +/// jian Button) PLUS the centred icon glyph — so every toolbar and chrome icon +/// button is a single call instead of hand-rolling `feedback + draw_icon` +/// separately in each widget. `active` paints the solid primary highlight. +#[allow(clippy::too_many_arguments)] +pub(crate) fn paint_icon_button( + backend: &mut dyn RenderBackend, + theme: &Theme, + rect: Rect, + icon: Icon, + hovered: bool, + pressed: bool, + active: bool, + icon_size: f32, + stroke_w: f32, +) { + let color = paint_icon_button_feedback(backend, theme, rect, hovered, pressed, active); + let origin = Point2D::new( + rect.origin.x + (rect.size.x - icon_size) / 2.0, + rect.origin.y + (rect.size.y - icon_size) / 2.0, + ); + draw_icon(backend, icon, origin, icon_size, color, stroke_w); +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/op-editor-ui/src/widgets/toolbar.rs b/crates/op-editor-ui/src/widgets/toolbar.rs index dff3ef7b6..e2f612181 100644 --- a/crates/op-editor-ui/src/widgets/toolbar.rs +++ b/crates/op-editor-ui/src/widgets/toolbar.rs @@ -25,7 +25,6 @@ use op_editor_core::Tool; /// Outer column width (matches the TS app's `w-12` toolbar). pub const TOOLBAR_WIDTH: f32 = 44.0; const BUTTON_SIZE: f32 = 32.0; -const BUTTON_RADIUS: f32 = 8.0; const ICON_SIZE: f32 = 18.0; const STROKE_W: f32 = 1.6; const BUTTON_GAP: f32 = 4.0; @@ -454,29 +453,15 @@ fn paint_button( origin: Point2D::new(x, y), size: Point2D::new(BUTTON_SIZE, BUTTON_SIZE), }; - let icon_color = if active { - cx.backend - .fill_round_rect(button_rect, BUTTON_RADIUS, theme.primary); - theme.primary_foreground - } else { - crate::widgets::button::paint_ghost_button_feedback( - cx.backend, - theme, - button_rect, - hovered, - pressed, - ) - }; - let icon_origin = Point2D::new( - x + (BUTTON_SIZE - ICON_SIZE) / 2.0, - y + (BUTTON_SIZE - ICON_SIZE) / 2.0, - ); - draw_icon( + crate::widgets::button::paint_icon_button( cx.backend, + theme, + button_rect, icon, - icon_origin, + hovered, + pressed, + active, ICON_SIZE, - icon_color, STROKE_W, ); }