Skip to content

Commit 6738c7f

Browse files
committed
Merge branch 'dev/e-man/rename-backdrops' into 'main'
REMIX-4824 - Monkey patching the OmniGraph original context menu to use omni.kit.context_menu, then adding Rename Backdrop option See merge request lightspeedrtx/lightspeed-kit!1073
2 parents 9fd74ad + 6560af0 commit 6738c7f

File tree

13 files changed

+789
-130
lines changed

13 files changed

+789
-130
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333
- REMIX-4807: Added Escape key support to close Stage Prim Picker dropdown
3434
- REMIX-4793: Added a function to check if tree items need to be expanded in the Stage Manager
3535
- REMIX-4552: Added Visibility Filter to the Stage Manager
36+
- REMIX-4824: Added a backdrop rename popup to the Remix Logic Graph Editor
3637

3738
### Changed
3839
- Update hdremix and omni_core_materials to ext-822f7b6-main
@@ -55,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5556
- Update hdremix and omni_core_materials to ext-83e59c6-main
5657
- REMIX-4801: Replaced decorator-based widget visibility filtering with subscription lifecycle management
5758
- REMIX-4801: Improved Stage Manager selection and expansion performance with async operations
59+
- REMIX-4824: Patched OmniGraph context menu to use omni.kit.context_menu instead of hardcoded ui.Menu/ui.MenuItem
5860

5961
### Fixed
6062
- Improved Pyright configuration by generating a list of search paths

source/extensions/lightspeed.trex.app.style/config/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
authors =["Damien Bataille <[email protected]>"]
33
title = "NVIDIA RTX Remix Style"
44
description = "Global Style for NVIDIA RTX Remix App"
5-
version = "1.19.2"
5+
version = "1.20.0"
66
readme = "docs/README.md"
77
repository = "https://gitlab-master.nvidia.com/lightspeedrtx/lightspeed-kit/-/tree/main/source/extensions/lightspeed.trex.app.style"
88
category = "internal"

source/extensions/lightspeed.trex.app.style/docs/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
33

4+
## [1.20.0]
5+
### Added
6+
- Added BackdropRenamePopup window and background styles
7+
48
## [1.19.2]
59
### Added
610
- Added Edit icon styles for properties panel actions
@@ -198,4 +202,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
198202
## [1.0.0] - 2024-02-28
199203
### Added
200204
- Created
201-

source/extensions/lightspeed.trex.app.style/lightspeed/trex/app/style/trex_style.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,15 @@ def override_dialog_get_style(style_value): # noqa PLW0621
11241124
"border_radius": 4,
11251125
},
11261126
"Rectangle::StagePrimPickerDropdownBackground": {"background_color": _GREY_50},
1127+
# Backdrop Rename Popup
1128+
"Window::BackdropRenamePopup": {
1129+
"background_color": 0x0,
1130+
"border_radius": 4,
1131+
},
1132+
"Rectangle::BackdropRenamePopupBackground": {
1133+
"background_color": _GREY_50,
1134+
"border_radius": 4,
1135+
},
11271136
"TreeView.ScrollingFrame::WelcomePad": {"background_color": 0x0},
11281137
"ViewportStats::FloatField": {
11291138
"background_color": 0,

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

Lines changed: 2 additions & 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.5.1"
4+
version = "1.6.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"]
@@ -27,6 +27,7 @@ icon = "data/icon.svg"
2727
"omni.graph.ui" = {version=">=1.5.0"}
2828
"omni.graph.window.core" = {version=">=1.80.0"}
2929
"omni.graph" = { version = ">=1.139.0" }
30+
"omni.kit.context_menu" = {}
3031
"omni.kit.stage.copypaste" = {} # for "omni.graph.window.core"
3132
"omni.ui" = {}
3233
"omni.usd" = {}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ 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.6.0]
8+
### Added
9+
- Added backdrop rename functionality via F2 hotkey and right-click context menu
10+
- Backdrops can now be renamed directly (changes the prim name)
11+
712
## [1.5.1]
813
### Changed
914
- Improved error dialog texts and messaging for prim selection errors

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
* limitations under the License.
1616
"""
1717

18-
from .extension import RemixLogicGraphExtension, get_instance
18+
from .extension import LOGIC_GRAPH_MENU_GROUP, RemixLogicGraphExtension, get_instance
1919

20-
__all__ = ["RemixLogicGraphExtension", "get_instance"]
20+
__all__ = ["LOGIC_GRAPH_MENU_GROUP", "RemixLogicGraphExtension", "get_instance"]

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
__all__ = ["RemixLogicGraphActions", "RemixLogicGraphHotkeys"]
2121

22-
from typing import Callable, Optional
22+
from typing import Callable
2323

2424
import carb.input
2525
import omni.kit.actions.core
@@ -31,6 +31,8 @@
3131
from omni.kit.hotkeys.core import KeyCombination
3232
from pxr import Sdf
3333

34+
from .backdrop_delegate import trigger_backdrop_rename
35+
3436

3537
class RemixLogicGraphActions(OmniGraphActions):
3638
"""
@@ -44,8 +46,9 @@ class RemixLogicGraphActions(OmniGraphActions):
4446
SELECT_ALL = "og_select_all"
4547
SELECT_NONE = "og_select_none"
4648
DELETE_SELECTION = "og_delete_selection"
49+
RENAME_BACKDROP = "og_rename_backdrop"
4750

48-
def __init__(self, extension_id: str, filter_fn: Optional[Callable[[Sdf.Path, Sdf.PrimSpec], bool]] = None):
51+
def __init__(self, extension_id: str, filter_fn: Callable[[Sdf.Path, Sdf.PrimSpec], bool] | None = None):
4952
super().__init__(extension_id, filter_fn)
5053

5154
action_registry = omni.kit.actions.core.get_action_registry()
@@ -78,6 +81,15 @@ def __init__(self, extension_id: str, filter_fn: Optional[Callable[[Sdf.Path, Sd
7881
tag=actions_tag,
7982
)
8083

84+
action_registry.register_action(
85+
self._extension_id,
86+
RemixLogicGraphActions.RENAME_BACKDROP,
87+
self.rename_backdrop,
88+
display_name="Rename Backdrop",
89+
description="Rename the selected backdrop.",
90+
tag=actions_tag,
91+
)
92+
8193
def select_all(self):
8294
"""Select all the nodes in the graph."""
8395
widget = self._get_widget()
@@ -105,6 +117,18 @@ def delete_selection(self):
105117
paths = [n.GetPath() for n in selected_non_graph_items]
106118
omni.kit.commands.execute("DeletePrims", paths=paths)
107119

120+
def rename_backdrop(self):
121+
"""Rename the selected backdrop using inline editing."""
122+
widget = self._get_widget()
123+
if not widget:
124+
return
125+
126+
view = widget._graph_view # noqa: SLF001, PLW0212
127+
if view and view.selection and len(view.selection) == 1:
128+
prim = view.selection[0]
129+
if hasattr(prim, "GetTypeName") and prim.GetTypeName() == "Backdrop":
130+
trigger_backdrop_rename(prim.GetPath())
131+
108132

109133
class RemixLogicGraphHotkeys(OmniGraphHotkeys):
110134
"""
@@ -119,6 +143,7 @@ class RemixLogicGraphHotkeys(OmniGraphHotkeys):
119143
),
120144
RemixLogicGraphActions.SELECT_NONE: KeyCombination(carb.input.KeyboardInput.ESCAPE),
121145
RemixLogicGraphActions.DELETE_SELECTION: KeyCombination(carb.input.KeyboardInput.DEL),
146+
RemixLogicGraphActions.RENAME_BACKDROP: KeyCombination(carb.input.KeyboardInput.F2),
122147
}
123148

124149
def _register(self):
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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__ = ["RemixBackdropDelegate", "trigger_backdrop_rename", "clear_edit_triggers"]
21+
22+
import weakref
23+
from functools import partial
24+
from typing import Callable
25+
26+
import omni.ui as ui
27+
from omni.kit.graph.delegate.modern import HEADER, HIGHLIGHT_THICKNESS, PORT_VISIBLE_MIN
28+
from omni.kit.graph.delegate.modern.backdrop_delegate import BackdropDelegate, color_to_hex, darker_color, hex_to_color
29+
from omni.kit.widget.graph.abstract_graph_node_delegate import GraphNodeDescription
30+
from pxr import Sdf
31+
32+
# Registry of inline edit trigger callbacks, keyed by prim path.
33+
# Uses weak references to UI widgets to allow garbage collection.
34+
_edit_triggers: dict[Sdf.Path, tuple[weakref.ref, Callable]] = {}
35+
36+
37+
def trigger_backdrop_rename(prim_path: Sdf.Path) -> bool:
38+
"""Trigger inline rename for a backdrop at the given path. Returns True if successful."""
39+
if prim_path not in _edit_triggers:
40+
return False
41+
42+
widget_ref, trigger_fn = _edit_triggers[prim_path]
43+
if widget_ref() is None:
44+
# Widget was garbage collected, clean up the stale entry
45+
del _edit_triggers[prim_path]
46+
return False
47+
48+
trigger_fn()
49+
return True
50+
51+
52+
def clear_edit_triggers():
53+
"""Clear all edit triggers. Call on extension shutdown to prevent memory leaks."""
54+
_edit_triggers.clear()
55+
56+
57+
class RemixBackdropDelegate(BackdropDelegate):
58+
"""
59+
Custom BackdropDelegate that fixes the inline rename field styling.
60+
The original BackdropDelegate creates a StringField with no background,
61+
making it unreadable when overlapping the label.
62+
"""
63+
64+
def node_header(self, model, node_desc: GraphNodeDescription):
65+
"""Override to add proper background styling to the rename StringField."""
66+
border_default = 0xFFD8B74B
67+
68+
def set_color(model, node, item_model):
69+
sub_models = item_model.get_item_children()
70+
rgb = (
71+
item_model.get_item_value_model(sub_models[0]).as_float,
72+
item_model.get_item_value_model(sub_models[1]).as_float,
73+
item_model.get_item_value_model(sub_models[2]).as_float,
74+
)
75+
model[node].display_color = rgb
76+
model.selection = []
77+
model._item_changed(None) # noqa: SLF001, PLW0212
78+
79+
header = ui.VStack()
80+
with header:
81+
node = node_desc.node
82+
node_name = model[node].name
83+
node_category = str(model[node].type)
84+
85+
display_color = model[node].display_color
86+
if display_color:
87+
style = {
88+
f"Graph.Node.Category::{node_category}": {"background_color": color_to_hex(display_color)},
89+
f"Graph.Node.Secondary::{node_category}": {"background_color": darker_color(display_color)},
90+
}
91+
field_bg = darker_color(display_color)
92+
else:
93+
style = {}
94+
field_bg = 0xFF303030
95+
96+
ui.Spacer(height=HIGHLIGHT_THICKNESS)
97+
with ui.ZStack():
98+
self.build_tooltip([node_name, node_category])
99+
with ui.VStack():
100+
with ui.ZStack(height=HEADER["sec_height"]):
101+
ui.Rectangle(style=style, name=node_category, style_type_name_override="Graph.Node.Secondary")
102+
with ui.VStack():
103+
ui.Spacer()
104+
with ui.HStack(height=14):
105+
ui.Spacer(width=3)
106+
color_widget = ui.ColorWidget(height=14, width=14)
107+
108+
sub_models = color_widget.model.get_item_children()
109+
border_color = model[node].display_color or hex_to_color(border_default)
110+
111+
color_widget.model.get_item_value_model(sub_models[0]).as_float = border_color[0]
112+
color_widget.model.get_item_value_model(sub_models[1]).as_float = border_color[1]
113+
color_widget.model.get_item_value_model(sub_models[2]).as_float = border_color[2]
114+
color_widget.model.add_end_edit_fn(lambda m, i: set_color(model, node, m))
115+
116+
with ui.ZStack():
117+
label = ui.Label(
118+
node_name,
119+
visible_min=PORT_VISIBLE_MIN,
120+
style_type_name_override="Graph.Node.Label",
121+
style={"margin_width": HEADER["margin_to_left"]},
122+
)
123+
124+
# Styled rename field - key fix: add background color
125+
label_field = ui.StringField(
126+
style={
127+
"background_color": field_bg,
128+
"border_radius": 2,
129+
"padding": 2,
130+
}
131+
)
132+
label_field.visible = False
133+
134+
def show_edit_field(field, label_widget, name, *args):
135+
field.model.set_value(name)
136+
field.visible = True
137+
label_widget.visible = False
138+
field.focus_keyboard()
139+
140+
trigger_fn = partial(show_edit_field, label_field, label, node_name)
141+
label.set_mouse_double_clicked_fn(trigger_fn)
142+
143+
# Register trigger for context menu access
144+
# (with weak ref to detect widget destruction)
145+
prim_path = node.GetPath()
146+
_edit_triggers[prim_path] = (weakref.ref(label_field), trigger_fn)
147+
148+
def label_edited(field, label_widget, *args):
149+
field.visible = False
150+
label_widget.visible = True
151+
model[node].name = field.model.as_string
152+
model._item_changed(None) # noqa: SLF001, PLW0212
153+
154+
label_field.model.add_end_edit_fn(partial(label_edited, label_field, label))
155+
ui.Spacer()
156+
ui.Spacer()
157+
ui.Rectangle(
158+
height=HEADER["height"],
159+
style=style,
160+
name=node_category,
161+
style_type_name_override="Graph.Node.Category",
162+
)
163+
ui.Spacer(height=HIGHLIGHT_THICKNESS)
164+
return header

0 commit comments

Comments
 (0)