fix(panels): hover highlight for the Effects add-menu rows

The Effects "+" add-menu (Drop Shadow / Layer Blur) painted flat rows
with no hover feedback, unlike the sibling property-panel dropdowns.
Add effect_add_menu_hover to editor_ui (cleared on toggle/close), a
PropertyPanel::effect_add_menu_row_at hit helper, and a native
update_effect_add_menu_hover cursor-move pass (mirroring the export
picker) that highlights the hovered row with the standard muted wash.
This commit is contained in:
Kayshen-X 2026-07-05 17:55:12 +08:00
parent 5755719696
commit bf955e4dc2
5 changed files with 82 additions and 1 deletions

View file

@ -1040,6 +1040,10 @@ pub struct EditorUiState {
/// Whether the Effects section's "+" add-menu (Drop Shadow / Layer
/// Blur choice) is open. `false` = closed.
pub effect_add_picker_open: bool,
/// Row index hovered in the Effects add-menu (`None` = none), so the
/// popover highlights the row under the cursor like the other
/// property-panel dropdowns.
pub effect_add_menu_hover: Option<usize>,
/// Fill/stroke colour-variable dropdown currently open in the
/// PropertyPanel; `None` means closed.
pub property_color_variable_picker_open: Option<crate::ui_draft::ColorTarget>,
@ -1351,6 +1355,7 @@ impl Default for EditorUiState {
fill_type_picker: jian_widgets::components::select::SelectState::default(),
fill_type_picker_index: 0,
effect_add_picker_open: false,
effect_add_menu_hover: None,
property_color_variable_picker_open: None,
image_fill_popover_open: false,
font_picker: jian_widgets::components::select::SelectState::default(),
@ -1478,6 +1483,7 @@ impl EditorUiState {
/// Toggle the Effects "+" add-menu (Drop Shadow / Layer Blur).
pub fn toggle_effect_add_picker(&mut self) {
self.effect_add_picker_open = !self.effect_add_picker_open;
self.effect_add_menu_hover = None;
}
/// Close the Effects add-menu. Returns true when it was open (so
@ -1485,6 +1491,7 @@ impl EditorUiState {
pub fn close_effect_add_picker(&mut self) -> bool {
let was = self.effect_add_picker_open;
self.effect_add_picker_open = false;
self.effect_add_menu_hover = None;
was
}

View file

@ -217,6 +217,9 @@ pub struct PropertyPanel {
/// Row index the cursor is over in the open Export select
/// popup — `None` when no popup is open or no row is hovered.
pub export_picker_hover: Option<usize>,
/// Row index the cursor is over in the open Effects "+" add-menu
/// (`None` when closed or no row hovered) — drives the row highlight.
pub effect_add_menu_hover: Option<usize>,
/// Vertical scroll offset (px, ≥ 0) — paint + hit-test shift the
/// section content up by this so a tall inspector stays usable.
pub scroll: f32,
@ -492,6 +495,7 @@ impl PropertyPanel {
export_scale_picker_open: ui.export_scale_picker_open,
export_format_picker_open: ui.export_format_picker_open,
export_picker_hover: ui.export_picker_hover,
effect_add_menu_hover: ui.effect_add_menu_hover,
scroll: ui.property_panel_scroll.offset.max(0.0),
locale: ui.locale,
// Inert in the multi-select aggregate view.
@ -554,6 +558,16 @@ impl PropertyPanel {
}
}
/// Row index under `point` in the open Effects add-menu — drives the
/// hover highlight (mirrors [`Self::export_picker_row_at`]).
pub fn effect_add_menu_row_at(&self, panel_rect: Rect, point: Point2D) -> Option<usize> {
let add_rect = self.effect_add_button_rect(self.scrolled_rect(panel_rect))?;
let menu = crate::widgets::property_panel_effects::effect_add_menu_rect(add_rect);
crate::widgets::property_panel_effects::effect_add_menu_row_rects(menu)
.into_iter()
.position(|(_, row)| row.contains(point))
}
/// The Effects section "+" button rect — `scrolled` is the already
/// scroll-adjusted panel rect (`scrolled_rect`). The anchor the
/// add-menu popover drops from.
@ -1288,6 +1302,7 @@ impl Widget for PropertyPanel {
cx,
&self.theme,
add_rect,
self.effect_add_menu_hover,
);
}
}

View file

@ -94,7 +94,14 @@ pub(crate) fn effect_add_menu_row_rects(menu: Rect) -> Vec<(PropertyPanelAction,
/// Paint the Effects "+" add-menu popover (Drop Shadow / Layer Blur)
/// anchored to `add_rect`. Caller gates this on the picker being open.
pub(crate) fn paint_effect_add_menu(cx: &mut PaintCx<'_>, theme: &Theme, add_rect: Rect) {
/// `hover` is the row index under the cursor (`None` = none), highlighted
/// with the same `muted` row wash the other property-panel dropdowns use.
pub(crate) fn paint_effect_add_menu(
cx: &mut PaintCx<'_>,
theme: &Theme,
add_rect: Rect,
hover: Option<usize>,
) {
let menu = effect_add_menu_rect(add_rect);
cx.backend
.fill_round_rect(menu, INPUT_RADIUS, theme.popover);
@ -102,6 +109,13 @@ pub(crate) fn paint_effect_add_menu(cx: &mut PaintCx<'_>, theme: &Theme, add_rec
.stroke_round_rect(menu, INPUT_RADIUS, theme.border, 1.0);
for (i, (_, label)) in EFFECT_ADD_MENU_ROWS.iter().enumerate() {
let ry = menu.origin.y + 4.0 + i as f32 * EFFECT_ADD_MENU_ROW_H;
if hover == Some(i) {
let row = Rect {
origin: Point2D::new(menu.origin.x + 4.0, ry),
size: Point2D::new(menu.size.x - 8.0, EFFECT_ADD_MENU_ROW_H),
};
cx.backend.fill_round_rect(row, 6.0, theme.muted);
}
let text = TextLayout::single_run(
label,
"system-ui",

View file

@ -246,6 +246,45 @@ impl WidgetHostNative {
}
}
/// Update the Effects "+" add-menu hovered row from the cursor
/// position (mirrors [`Self::update_export_picker_hover`]). Returns
/// `true` when the hover changed.
pub(in crate::widget_host) fn update_effect_add_menu_hover(
&mut self,
x: f32,
y: f32,
viewport_w: f32,
viewport_h: f32,
) -> bool {
use op_editor_ui::widgets::{PropertyPanel, TOP_BAR_HEIGHT};
use op_editor_ui::{Point2D, Rect};
if !self.editor_state.editor_ui.effect_add_picker_open {
return false;
}
self.refresh_layout_scene();
let Some(panel) = PropertyPanel::for_selection(&self.editor_state) else {
return false;
};
let property_rect = Rect {
origin: Point2D::new(
viewport_w - self.editor_state.editor_ui.property_panel_width,
TOP_BAR_HEIGHT,
),
size: Point2D::new(
self.editor_state.editor_ui.property_panel_width,
(viewport_h - TOP_BAR_HEIGHT).max(0.0),
),
};
let new_hover = panel.effect_add_menu_row_at(property_rect, Point2D::new(x, y));
if new_hover != self.editor_state.editor_ui.effect_add_menu_hover {
self.editor_state.editor_ui.effect_add_menu_hover = new_hover;
self.mark_dirty();
true
} else {
false
}
}
/// Update the layer-panel hover id from the current cursor
/// position. Returns `true` if the hover state changed.
pub fn update_layer_hover(&mut self, x: f32, y: f32, viewport_w: f32, viewport_h: f32) -> bool {

View file

@ -792,6 +792,12 @@ impl WidgetHostNative {
{
return true;
}
// Effects "+" add-menu row hover (no-op when closed).
if !over_topmost
&& self.update_effect_add_menu_hover(x, y, self.last_viewport_w, self.last_viewport_h)
{
return true;
}
// Padding-mode gear popover row hover (no-op when closed).
if self.update_padding_mode_popover_hover(x, y) {
return true;