Skip to content

Commit 267bfa4

Browse files
committed
Context menu plugin + viewport cursor polish
New renzora_context_menu plugin: right-click-tap on the viewport opens a searchable menu. Two modes, picked by selection state: - Nothing selected: Add menu sourced from SpawnRegistry (selected preset spawns at the ground-plane hit and is selected). - Something selected: Entity actions (Focus, Duplicate, Deselect, Delete) that dispatch existing EditorActions via KeyBindings, so user rebinds and existing consumers apply unchanged. Right-click is shared with camera orbit — the menu only opens on a tap (press + release with minimal motion). Motion is read from MouseMotion events so cursor lock during orbit doesn't freeze detection. Each open uses a fresh Area id so egui doesn't cache layout from the previous render (was making the Add menu inherit the smaller Entity menu height). Scroll area fills frame width. Dispatch channel fix: KeyBindings::just_pressed / is_plugin_dispatched now consume entries on read, and the Last-schedule sweep was removed. The sweep was wiping dispatches made from EguiPrimaryContextPass (menu clicks, command palette) before any Update-schedule consumer ran. Viewport cursor UX: - Crosshair cursor whenever the pointer is inside the viewport rect (new ViewportOverlayRegistry drawer). - Modal transforms hide the OS cursor for all three modes (G / R / S); previously Scale kept it visible. - Modal transforms also hide the immediate-mode axis / plane lines drawn by draw_line_gizmos — they were sitting under the modal HUD. - Brush tools (TerrainSculpt / TerrainPaint / FoliagePaint) hide the cursor while hovering the viewport; new system tracks ownership so it doesn't fight modal_transform's cursor visibility flips. Default binding change: ToggleWireframe moved from Z to Alt+Z, ToggleLighting from Shift+Z to Alt+Shift+Z. Bare Z was firing the wireframe toggle during transform-tool editing.
1 parent 43b6740 commit 267bfa4

8 files changed

Lines changed: 652 additions & 14 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"crates/editor/renzora_test_component",
1414
"crates/editor/renzora_mesh_draw",
1515
"crates/editor/renzora_command_palette",
16+
"crates/editor/renzora_context_menu",
1617
"crates/editor/renzora_viewport",
1718
"crates/editor/renzora_hierarchy",
1819
"crates/editor/renzora_asset_browser",

crates/core/renzora_core/src/keybindings.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,10 @@ impl Default for KeyBindings {
332332

333333
// View defaults
334334
bindings.insert(EditorAction::ToggleBottomPanel, KeyBinding::new(KeyCode::Backquote).ctrl());
335-
bindings.insert(EditorAction::ToggleWireframe, KeyBinding::new(KeyCode::KeyZ));
336-
bindings.insert(EditorAction::ToggleLighting, KeyBinding::new(KeyCode::KeyZ).shift());
335+
// Z alone used to toggle wireframe but clashed with stray Z presses
336+
// near Ctrl+Z (undo) and the gizmo tools. Use Alt-modified forms.
337+
bindings.insert(EditorAction::ToggleWireframe, KeyBinding::new(KeyCode::KeyZ).alt());
338+
bindings.insert(EditorAction::ToggleLighting, KeyBinding::new(KeyCode::KeyZ).alt().shift());
337339
bindings.insert(EditorAction::ToggleGrid, KeyBinding::new(KeyCode::KeyH));
338340

339341
// Play mode
@@ -373,9 +375,18 @@ impl KeyBindings {
373375
/// Check if an action key was just pressed this frame (with exact modifier check).
374376
/// Also returns true if the action was programmatically dispatched this
375377
/// frame (e.g. from the command palette) via [`Self::dispatch`].
378+
///
379+
/// Programmatic dispatches are consumed on read (removed from the
380+
/// pending set) so the action fires exactly once regardless of which
381+
/// schedule the dispatch originated from. This avoids a frame-timing
382+
/// issue where dispatches from `EguiPrimaryContextPass` could be
383+
/// swept out by the `Last`-schedule cleaner before any Update-schedule
384+
/// consumer ran.
376385
pub fn just_pressed(&self, action: EditorAction, keyboard: &ButtonInput<KeyCode>) -> bool {
377-
if self.dispatched.lock().map_or(false, |d| d.contains(&action)) {
378-
return true;
386+
if let Ok(mut set) = self.dispatched.lock() {
387+
if set.remove(&action) {
388+
return true;
389+
}
379390
}
380391
if let Some(binding) = self.bindings.get(&action) {
381392
let key_just_pressed = keyboard.just_pressed(binding.key);
@@ -410,9 +421,13 @@ impl KeyBindings {
410421
}
411422

412423
/// True if a plugin shortcut was dispatched this frame. Used by the
413-
/// plugin shortcut dispatcher in the editor SDK.
424+
/// plugin shortcut dispatcher in the editor SDK. Consumes the entry
425+
/// on read (same reason as [`Self::just_pressed`]).
414426
pub fn is_plugin_dispatched(&self, id: &'static str) -> bool {
415-
self.dispatched_plugin.lock().map_or(false, |d| d.contains(id))
427+
if let Ok(mut set) = self.dispatched_plugin.lock() {
428+
return set.remove(id);
429+
}
430+
false
416431
}
417432

418433
/// Get the binding for an action
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "renzora_context_menu"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["dylib"]
8+
9+
[dependencies]
10+
bevy = { workspace = true }
11+
renzora = { path = "../../renzora", default-features = false, features = ["editor"] }

0 commit comments

Comments
 (0)