feat(variables): per-row hover on the theme-preset dropdown
The preset dropdown tracked no live row hover (a documented gap). Add a variables_preset_menu_hover state, update it on cursor-move via the existing ThemePresetMenu hit-test (swallowing moves over the menu like a top-most overlay), and paint a jian button_hover wash on the hovered row (inset a few px so it reads as a padded highlight, not edge-to-edge).
This commit is contained in:
parent
34dcd0547f
commit
153e3f72a8
|
|
@ -1031,6 +1031,9 @@ pub struct EditorUiState {
|
|||
/// Whether the Variables right-rail panel is explicitly open.
|
||||
pub variables_panel_open: bool,
|
||||
pub variables_preset_menu_open: bool,
|
||||
/// Which row inside the open theme-preset dropdown the cursor is over —
|
||||
/// drives the per-row hover wash.
|
||||
pub variables_preset_menu_hover: Option<crate::variables_panel_state::PresetMenuButton>,
|
||||
pub variables_add_menu_open: bool,
|
||||
/// Whether the preset dropdown's save-as-name input is showing
|
||||
/// (TS `showPresetNameInput`). This legacy preset-name draft still
|
||||
|
|
@ -1293,6 +1296,7 @@ impl Default for EditorUiState {
|
|||
axis_dropdown_open: None,
|
||||
variables_panel_open: false,
|
||||
variables_preset_menu_open: false,
|
||||
variables_preset_menu_hover: None,
|
||||
variables_add_menu_open: false,
|
||||
variables_preset_name_focus: false,
|
||||
pending_theme_preset_io: None,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use crate::widgets::icons::{draw_icon, Icon};
|
|||
use crate::widgets::PaintCx;
|
||||
use crate::{Color, Point2D, Rect, TextLayout};
|
||||
use op_editor_core::editor_ui_state::Locale;
|
||||
use op_editor_core::variables_panel_state::PresetMenuButton;
|
||||
use op_editor_core::EditorState;
|
||||
|
||||
/// TS `w-56` = 14rem = 224 px.
|
||||
|
|
@ -73,6 +74,7 @@ pub struct ThemePresetMenu {
|
|||
name_input_active: bool,
|
||||
name_draft: String,
|
||||
caret_pos: usize,
|
||||
hover: Option<PresetMenuButton>,
|
||||
}
|
||||
|
||||
impl ThemePresetMenu {
|
||||
|
|
@ -89,6 +91,22 @@ impl ThemePresetMenu {
|
|||
String::new()
|
||||
},
|
||||
caret_pos: state.ui.property_caret_pos,
|
||||
hover: state.editor_ui.variables_preset_menu_hover,
|
||||
}
|
||||
}
|
||||
|
||||
/// The full-width rect of the currently-hovered row (for the hover wash), or
|
||||
/// `None` when nothing is hovered / the name input is active.
|
||||
fn hover_row_rect(&self, menu: Rect) -> Option<Rect> {
|
||||
match self.hover? {
|
||||
PresetMenuButton::SaveCurrent => Some(self.save_row_rect(menu)),
|
||||
PresetMenuButton::Load(i) | PresetMenuButton::Delete(i) => {
|
||||
(i < self.preset_names.len()).then(|| self.preset_row_rect(menu, i))
|
||||
}
|
||||
PresetMenuButton::Import => Some(self.import_row_rect(menu)),
|
||||
PresetMenuButton::Export => Some(self.export_row_rect(menu)),
|
||||
// The name-input row owns its own focus chrome — no row wash.
|
||||
PresetMenuButton::NameInput => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,6 +230,16 @@ impl ThemePresetMenu {
|
|||
cx.backend
|
||||
.stroke_round_rect(menu, RADIUS, theme.border, 1.0);
|
||||
|
||||
// Hovered-row wash (inset a few px so it reads as a padded highlight,
|
||||
// not edge-to-edge) — drawn under the row content, jian-consistent.
|
||||
if let Some(hr) = self.hover_row_rect(menu) {
|
||||
let wash = Rect {
|
||||
origin: Point2D::new(hr.origin.x + 4.0, hr.origin.y + 1.0),
|
||||
size: Point2D::new(hr.size.x - 8.0, hr.size.y - 2.0),
|
||||
};
|
||||
cx.backend.fill_round_rect(wash, 6.0, theme.button_hover);
|
||||
}
|
||||
|
||||
// Save row — button or inline name input.
|
||||
let save = self.save_row_rect(menu);
|
||||
if self.name_input_active {
|
||||
|
|
|
|||
|
|
@ -652,6 +652,19 @@ impl WidgetHostNative {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
// Preset dropdown is a top-most overlay over the variables panel — track
|
||||
// its per-row hover and swallow moves over it first.
|
||||
if self.editor_state.editor_ui.variables_preset_menu_open
|
||||
&& self.update_variables_preset_menu_hover(
|
||||
x,
|
||||
self.last_viewport_w,
|
||||
self.last_viewport_h,
|
||||
y,
|
||||
)
|
||||
{
|
||||
self.clear_lower_overlay_hover();
|
||||
return true;
|
||||
}
|
||||
if self.editor_state.editor_ui.variables_panel_open {
|
||||
let point = Point2D::new(x, y);
|
||||
if let Some(panel_rect) =
|
||||
|
|
|
|||
|
|
@ -12,9 +12,24 @@
|
|||
|
||||
use super::WidgetHostNative;
|
||||
use op_editor_core::editor_ui_state::ThemePresetIo;
|
||||
use op_editor_core::variables_panel_state::PresetMenuButton;
|
||||
use op_editor_ui::widgets::{PresetMenuHit, ThemePresetMenu};
|
||||
use op_editor_ui::{Point2D, Rect};
|
||||
|
||||
/// Map a press hit inside the preset dropdown to the persistent hover-row enum
|
||||
/// (the `Blank` swallow target has no row, so it clears the hover).
|
||||
fn preset_hit_to_button(hit: PresetMenuHit) -> Option<PresetMenuButton> {
|
||||
match hit {
|
||||
PresetMenuHit::SaveCurrent => Some(PresetMenuButton::SaveCurrent),
|
||||
PresetMenuHit::NameInput => Some(PresetMenuButton::NameInput),
|
||||
PresetMenuHit::Load(i) => Some(PresetMenuButton::Load(i)),
|
||||
PresetMenuHit::Delete(i) => Some(PresetMenuButton::Delete(i)),
|
||||
PresetMenuHit::Import => Some(PresetMenuButton::Import),
|
||||
PresetMenuHit::Export => Some(PresetMenuButton::Export),
|
||||
PresetMenuHit::Blank => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetHostNative {
|
||||
/// Anchor rect of the variables panel's preset button.
|
||||
///
|
||||
|
|
@ -81,6 +96,31 @@ impl WidgetHostNative {
|
|||
Some((menu, rect))
|
||||
}
|
||||
|
||||
/// Update the per-row hover for the open preset dropdown on a cursor move.
|
||||
/// Returns `true` when the cursor is over the menu (the move is swallowed,
|
||||
/// like any top-most overlay).
|
||||
pub(in crate::widget_host) fn update_variables_preset_menu_hover(
|
||||
&mut self,
|
||||
x: f32,
|
||||
viewport_w: f32,
|
||||
viewport_h: f32,
|
||||
y: f32,
|
||||
) -> bool {
|
||||
let Some((menu, menu_rect)) = self.variables_preset_menu_with_rect(viewport_w, viewport_h)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let point = Point2D::new(x, y);
|
||||
let new_hover = menu
|
||||
.hit_test(menu_rect, point)
|
||||
.and_then(preset_hit_to_button);
|
||||
if new_hover != self.editor_state.editor_ui.variables_preset_menu_hover {
|
||||
self.editor_state.editor_ui.variables_preset_menu_hover = new_hover;
|
||||
self.mark_dirty();
|
||||
}
|
||||
menu_rect.contains(point)
|
||||
}
|
||||
|
||||
/// Press routing for the open preset dropdown. Runs BEFORE
|
||||
/// `dispatch_variables_panel_press` so the functional rows win
|
||||
/// over the panel's stub `TogglePresetMenu` mapping. Returns
|
||||
|
|
|
|||
Loading…
Reference in a new issue