Skip to content

Commit f9c97bf

Browse files
committed
Merge branch 'dev/ptrottier/logic_hotkey_fixes' into 'main'
REMIX-4774: Remix Logic hotkey fixes See merge request lightspeedrtx/lightspeed-kit!1052
2 parents 42e1284 + c9f478f commit f9c97bf

File tree

5 files changed

+160
-11
lines changed

5 files changed

+160
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
- Small improvements for Remix Logic: added delete button, hid unused ui, stage manager refresh filtering
2828
- REMIX-4719: Added Stage Manager Remix Logic Graph Interaction Action Plugin, And Logic Graph Filter
2929
- REMIX-4245: Added a generic Stage Prim Picker widget and implemented it in the Remix Logic Properties Panel.
30+
- REMIX-4774: Added select all, select none, and delete selection actions & hotkeys to the Remix Logic Graph Editor
3031

3132
### Changed
3233
- Update hdremix and omni_core_materials to ext-822f7b6-main

source/extensions/lightspeed.trex.logic.widget/config/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
title = "Remix Logic Graph Editor"
33
description = "Component editor window for Remix Component Graphs"
4-
version = "1.1.1"
4+
version = "1.2.0"
55
authors = ["Chris Grebeldinger <[email protected]>", "Dean Edmonds <[email protected]>", "Nicolas Kendall-Bar <[email protected]>"]
66
repository = "https://gitlab-master.nvidia.com/lightspeedrtx/lightspeed-kit/-/tree/main/source/extensions/lightspeed.trex.logic.widget"
77
keywords = ["graph", "logic", "component", "remix", "ui"]

source/extensions/lightspeed.trex.logic.widget/docs/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ This document records all notable changes to the **lightspeed.trex.logic.widget*
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com). The project adheres to [Semantic Versioning](https://semver.org).
66

7+
## [1.2.0]
8+
### Added
9+
- Added missing (select all, select none, and delete selection) actions & hotkeys to the Logic Graph widget
10+
711
## [1.1.1]
812
### Removed
913
- Removed Variables panel and Edit toolbar button from Logic Graph widget
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
"""
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
"""
17+
18+
from __future__ import annotations
19+
20+
__all__ = ["RemixLogicGraphActions", "RemixLogicGraphHotkeys"]
21+
22+
from typing import Callable, Optional
23+
24+
import carb.input
25+
import omni.kit.actions.core
26+
import omni.kit.app
27+
import omni.kit.commands
28+
from omni.graph.window.core import OmniGraphActions, OmniGraphHotkeys
29+
from omni.graph.window.core.hotkeys import _HOTKEYS_EXT
30+
from omni.graph.window.core.virtual_node_helper import VirtualNodeHelper
31+
from omni.kit.hotkeys.core import KeyCombination
32+
from pxr import Sdf
33+
34+
35+
class RemixLogicGraphActions(OmniGraphActions):
36+
"""
37+
Extended OmniGraph actions that include select all, select none, and delete selection.
38+
39+
Inherits from OmniGraphActions and adds the missing actions that are shown in the
40+
context menu but not registered as hotkey-able actions.
41+
"""
42+
43+
# Additional action names
44+
SELECT_ALL = "og_select_all"
45+
SELECT_NONE = "og_select_none"
46+
DELETE_SELECTION = "og_delete_selection"
47+
48+
def __init__(self, extension_id: str, filter_fn: Optional[Callable[[Sdf.Path, Sdf.PrimSpec], bool]] = None):
49+
super().__init__(extension_id, filter_fn)
50+
51+
action_registry = omni.kit.actions.core.get_action_registry()
52+
actions_tag = "OmniGraph Actions"
53+
54+
action_registry.register_action(
55+
self._extension_id,
56+
RemixLogicGraphActions.SELECT_ALL,
57+
self.select_all,
58+
display_name="Select All",
59+
description="Select all nodes in the graph.",
60+
tag=actions_tag,
61+
)
62+
63+
action_registry.register_action(
64+
self._extension_id,
65+
RemixLogicGraphActions.SELECT_NONE,
66+
self.select_none,
67+
display_name="Select None",
68+
description="Clear the node selection.",
69+
tag=actions_tag,
70+
)
71+
72+
action_registry.register_action(
73+
self._extension_id,
74+
RemixLogicGraphActions.DELETE_SELECTION,
75+
self.delete_selection,
76+
display_name="Delete Selection",
77+
description="Delete selected nodes.",
78+
tag=actions_tag,
79+
)
80+
81+
def select_all(self):
82+
"""Select all the nodes in the graph."""
83+
widget = self._get_widget()
84+
if widget:
85+
model = widget.model
86+
current_graph = widget.current_compound
87+
model.selection = model[current_graph].nodes
88+
89+
def select_none(self):
90+
"""Clear the node selection."""
91+
widget = self._get_widget()
92+
if widget:
93+
model = widget.model
94+
model.selection = []
95+
96+
def delete_selection(self):
97+
"""Delete the selected nodes, excluding virtual nodes."""
98+
widget = self._get_widget()
99+
if widget:
100+
view = widget._graph_view # noqa: protected-access
101+
selected_view_items = view.selection or []
102+
# Filter out virtual nodes (input/output proxy nodes) - matches context menu logic
103+
selected_non_graph_items = [p for p in selected_view_items if not VirtualNodeHelper.is_virtual_node(p)]
104+
if selected_non_graph_items:
105+
paths = [n.GetPath() for n in selected_non_graph_items]
106+
omni.kit.commands.execute("DeletePrims", paths=paths)
107+
108+
109+
class RemixLogicGraphHotkeys(OmniGraphHotkeys):
110+
"""
111+
Extended hotkey bindings for Remix Logic Graph editor.
112+
113+
Includes the default OmniGraph hotkeys plus select all, select none, and delete selection.
114+
"""
115+
116+
_ADDITIONAL_HOTKEYS = {
117+
RemixLogicGraphActions.SELECT_ALL: KeyCombination(
118+
carb.input.KeyboardInput.A, modifiers=carb.input.KEYBOARD_MODIFIER_FLAG_CONTROL
119+
),
120+
RemixLogicGraphActions.SELECT_NONE: KeyCombination(carb.input.KeyboardInput.ESCAPE),
121+
RemixLogicGraphActions.DELETE_SELECTION: KeyCombination(carb.input.KeyboardInput.DEL),
122+
}
123+
124+
def _register(self):
125+
# Register base hotkeys first
126+
super()._register()
127+
128+
# Register additional hotkeys
129+
ext_manager = omni.kit.app.get_app_interface().get_extension_manager()
130+
if not ext_manager.is_extension_enabled(_HOTKEYS_EXT):
131+
return
132+
import omni.kit.hotkeys.core as hotkeys
133+
134+
hotkey_registry = hotkeys.get_hotkey_registry()
135+
ext_actions = omni.kit.actions.core.get_action_registry().get_all_actions_for_extension(self._extension_id)
136+
hotkey_filter = hotkeys.HotkeyFilter(windows=[self._window_name])
137+
138+
for action in ext_actions:
139+
key = self._ADDITIONAL_HOTKEYS.get(action.id, None)
140+
if not key:
141+
continue
142+
143+
hotkey_registry.register_hotkey(
144+
hotkey_ext_id=self._extension_id,
145+
key=key,
146+
action_ext_id=action.extension_id,
147+
action_id=action.id,
148+
filter=hotkey_filter,
149+
)

source/extensions/lightspeed.trex.logic.widget/lightspeed/trex/logic/widget/extension.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,10 @@
3333
import omni.ui as ui
3434
from lightspeed.common.constants import GlobalEventNames, WindowNames
3535
from lightspeed.events_manager import get_instance as _get_event_manager_instance
36-
from omni.graph.window.core import (
37-
OmniGraphActions,
38-
OmniGraphCatalogTreeDelegate,
39-
OmniGraphHotkeys,
40-
graph_config,
41-
register_stage_graph_opener,
42-
)
36+
from omni.graph.window.core import OmniGraphCatalogTreeDelegate, graph_config, register_stage_graph_opener
4337
from pxr import Sdf, Usd
4438

39+
from .actions import RemixLogicGraphActions, RemixLogicGraphHotkeys
4540
from .catalog_model import OmniGraphNodeQuickSearchModel
4641
from .graph_widget import RemixLogicGraphWidget
4742
from .graph_window import RemixLogicGraphWindow
@@ -88,9 +83,9 @@ def on_startup(self, ext_id: str):
8883
self._quicksearch_pos = (None, None)
8984
self._stage_opener_sub = None
9085

91-
# Use the default OG actions and hotkeys, unmodified.
92-
self._actions = OmniGraphActions(ext_id, filter_fn=self._make_paste_filter())
93-
self._hotkeys = OmniGraphHotkeys(ext_id, WindowNames.REMIX_LOGIC_GRAPH)
86+
# Use extended actions and hotkeys that include select all, select none, and delete selection.
87+
self._actions = RemixLogicGraphActions(ext_id, filter_fn=self._make_paste_filter())
88+
self._hotkeys = RemixLogicGraphHotkeys(ext_id, WindowNames.REMIX_LOGIC_GRAPH)
9489

9590
self._workspace = RemixLogicGraphWorkspaceWindow()
9691
self._workspace.create_window()

0 commit comments

Comments
 (0)