Skip to content

Commit 95e1ca1

Browse files
authored
Merge pull request #138 from jchanvfx/context_menu_types_#127
Context menu types #127
2 parents 6b108c2 + c6be6b8 commit 95e1ca1

File tree

8 files changed

+388
-136
lines changed

8 files changed

+388
-136
lines changed

NodeGraphQt/__init__.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,34 @@ def __init__(self):
8080
'"NodeGraphQt.vendor.Qt ({})"'.format(qtpy_ver))
8181

8282
from .base.graph import NodeGraph
83-
from .base.menu import Menu, MenuCommand
83+
from .base.menu import NodesMenu, NodeGraphMenu, NodeGraphCommand
8484
from .base.node import NodeObject, BaseNode, BackdropNode
8585
from .base.port import Port
8686
from .pkg_info import __version__ as VERSION
8787
from .pkg_info import __license__ as LICENSE
8888

8989
# functions
90-
from .base.actions import setup_context_menu
90+
from .base.utils import setup_context_menu
9191

9292
# widgets
9393
from .widgets.node_tree import NodeTreeWidget
9494
from .widgets.properties_bin import PropertiesBinWidget
9595

9696
__version__ = VERSION
9797
__all__ = [
98-
'BackdropNode', 'BaseNode', 'LICENSE', 'Menu', 'MenuCommand', 'NodeGraph',
99-
'NodeObject', 'NodeTreeWidget', 'Port', 'PropertiesBinWidget', 'VERSION',
100-
'constants', 'setup_context_menu'
98+
'BackdropNode',
99+
'BaseNode',
100+
'LICENSE',
101+
'NodeGraph',
102+
'NodeGraphCommand',
103+
'NodeGraphMenu',
104+
'NodeObject',
105+
'NodeTreeWidget',
106+
'NodesMenu',
107+
'Port',
108+
'PropertiesBinWidget',
109+
'VERSION',
110+
'constants',
111+
'setup_context_menu'
101112
]
113+

NodeGraphQt/base/graph.py

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
NodeMovedCmd,
1111
PortConnectedCmd)
1212
from NodeGraphQt.base.factory import NodeFactory
13-
from NodeGraphQt.base.menu import Menu
13+
from NodeGraphQt.base.menu import NodeGraphMenu, NodesMenu
1414
from NodeGraphQt.base.model import NodeGraphModel
1515
from NodeGraphQt.base.node import NodeObject
1616
from NodeGraphQt.base.port import Port
@@ -391,23 +391,75 @@ def end_undo(self):
391391

392392
def context_menu(self):
393393
"""
394-
Returns the node graph root context menu object.
394+
Returns the main context menu from the node graph.
395+
396+
Note:
397+
This is a convenience function to
398+
:meth:`NodeGraphQt.NodeGraph.get_context_menu`
399+
with the arg ``menu="graph"``
400+
401+
Returns:
402+
NodeGraphQt.NodeGraphMenu: context menu object.
403+
"""
404+
return self.get_context_menu('graph')
405+
406+
def context_nodes_menu(self):
407+
"""
408+
Returns the main context menu for the nodes.
409+
410+
Note:
411+
This is a convenience function to
412+
:meth:`NodeGraphQt.NodeGraph.get_context_menu`
413+
with the arg ``menu="nodes"``
395414
396415
Returns:
397-
Menu: context menu object.
416+
NodeGraphQt.NodesMenu: context menu object.
398417
"""
399-
return Menu(self._viewer, self._viewer.context_menu())
418+
return self.get_context_menu('nodes')
400419

401-
def disable_context_menu(self, disabled=True):
420+
def get_context_menu(self, menu):
402421
"""
403-
Disable/Enable node graph context menu.
422+
Returns the context menu specified by the name.
423+
424+
Menu types:
425+
"graph" - context menu from the node graph.
426+
"nodes" - context menu for the nodes.
427+
428+
Args:
429+
menu (str): menu name.
430+
431+
Returns:
432+
NodeGraphMenu or NodesMenu: context menu object.
433+
"""
434+
menus = self._viewer.context_menus()
435+
if menus.get(menu):
436+
if menu == 'graph':
437+
return NodeGraphMenu(self, menus[menu])
438+
elif menu == 'nodes':
439+
return NodesMenu(self, menus[menu])
440+
441+
def disable_context_menu(self, disabled=True, name='all'):
442+
"""
443+
Disable/Enable context menus from the node graph.
444+
445+
Menu Types:
446+
- ``"all"`` all context menus from the node graph.
447+
- ``"graph"`` context menu from the node graph.
448+
- ``"nodes"`` context menu for the nodes.
404449
405450
Args:
406451
disabled (bool): true to enable context menu.
452+
name (str): menu name. (default: ``"all"``)
407453
"""
408-
menu = self._viewer.context_menu()
409-
menu.setDisabled(disabled)
410-
menu.setVisible(not disabled)
454+
if name == 'all':
455+
for k, menu in self._viewer.context_menus().items():
456+
menu.setDisabled(disabled)
457+
menu.setVisible(not disabled)
458+
return
459+
menus = self._viewer.context_menus()
460+
if menus.get(name):
461+
menus[name].setDisabled(disabled)
462+
menus[name].setVisible(not disabled)
411463

412464
def acyclic(self):
413465
"""

NodeGraphQt/base/menu.py

Lines changed: 134 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,45 @@
11
#!/usr/bin/python
22
from distutils.version import LooseVersion
33

4-
from NodeGraphQt import QtGui, QtCore, QtWidgets
5-
from NodeGraphQt.widgets.stylesheet import STYLE_QMENU
4+
from NodeGraphQt import QtGui, QtCore
5+
from NodeGraphQt.errors import NodeMenuError
6+
from NodeGraphQt.widgets.actions import BaseMenu, GraphAction, NodeAction
67

78

8-
class Menu(object):
9+
class NodeGraphMenu(object):
910
"""
10-
base class for a menu item.
11+
The ``NodeGraphMenu`` is the context menu triggered from the node graph.
12+
13+
example to accessing the node graph context menu.
14+
15+
.. code-block:: python
16+
:linenos:
17+
18+
from NodeGraphQt import NodeGraph
19+
20+
node_graph = NodeGraph()
21+
22+
# get the context menu for the node graph.
23+
context_menu = node_graph.get_context_menu('graph')
1124
"""
1225

13-
def __init__(self, viewer, qmenu):
14-
self.__viewer = viewer
15-
self.__qmenu = qmenu
26+
def __init__(self, graph, qmenu):
27+
self._graph = graph
28+
self._qmenu = qmenu
1629

1730
def __repr__(self):
18-
cls_name = self.__class__.__name__
19-
return '<{}("{}") object at {}>'.format(cls_name, self.name(), hex(id(self)))
31+
return '<{}("{}") object at {}>'.format(
32+
self.__class__.__name__, self.name(), hex(id(self)))
2033

2134
@property
2235
def qmenu(self):
23-
return self.__qmenu
36+
"""
37+
The underlying qmenu.
38+
39+
Returns:
40+
BaseMenu: qmenu object.
41+
"""
42+
return self._qmenu
2443

2544
def name(self):
2645
"""
@@ -39,11 +58,11 @@ def get_menu(self, name):
3958
name (str): name of the menu.
4059
4160
Returns:
42-
NodeGraphQt.Menu: menu item.
61+
NodeGraphQt.NodeGraphMenu: menu item.
4362
"""
44-
for action in self.qmenu.actions():
45-
if action.menu() and action.menu().title() == name:
46-
return Menu(self.__viewer, action.menu())
63+
menu = self.qmenu.get_menu(name)
64+
if menu:
65+
return NodeGraphMenu(self._graph, menu)
4766

4867
def get_command(self, name):
4968
"""
@@ -57,7 +76,7 @@ def get_command(self, name):
5776
"""
5877
for action in self.qmenu.actions():
5978
if not action.menu() and action.text() == name:
60-
return MenuCommand(self.__viewer, action)
79+
return NodeGraphCommand(self._graph, action)
6180

6281
def all_commands(self):
6382
"""
@@ -76,7 +95,7 @@ def get_actions(menu):
7695
actions += get_actions(action.menu())
7796
return actions
7897
child_actions = get_actions(self.qmenu)
79-
return [MenuCommand(self.__viewer, a) for a in child_actions]
98+
return [NodeGraphCommand(self._graph, a) for a in child_actions]
8099

81100
def add_menu(self, name):
82101
"""
@@ -86,34 +105,34 @@ def add_menu(self, name):
86105
name (str): menu name.
87106
88107
Returns:
89-
NodeGraphQt.Menu: the appended menu item.
108+
NodeGraphQt.NodeGraphMenu: the appended menu item.
90109
"""
91-
menu = QtWidgets.QMenu(name, self.qmenu)
92-
menu.setStyleSheet(STYLE_QMENU)
110+
menu = BaseMenu(name, self.qmenu)
93111
self.qmenu.addMenu(menu)
94-
return Menu(self.__viewer, menu)
112+
return NodeGraphMenu(self._graph, menu)
95113

96114
def add_command(self, name, func=None, shortcut=None):
97115
"""
98116
Adds a command to the menu.
99117
100118
Args:
101119
name (str): command name.
102-
func (function): command function.
103-
shortcut (str): function shotcut key.
120+
func (function): command function eg. "func(``graph``)".
121+
shortcut (str): shotcut key.
104122
105123
Returns:
106124
NodeGraphQt.MenuCommand: the appended command.
107125
"""
108-
action = QtWidgets.QAction(name, self.__viewer)
126+
action = GraphAction(name, self._graph.viewer())
127+
action.graph = self._graph
109128
if LooseVersion(QtCore.qVersion()) >= LooseVersion('5.10'):
110129
action.setShortcutVisibleInContextMenu(True)
111130
if shortcut:
112131
action.setShortcut(shortcut)
113132
if func:
114-
action.triggered.connect(func)
133+
action.executed.connect(func)
115134
qaction = self.qmenu.addAction(action)
116-
return MenuCommand(self.__viewer, qaction)
135+
return NodeGraphCommand(self._graph, qaction)
117136

118137
def add_separator(self):
119138
"""
@@ -122,22 +141,104 @@ def add_separator(self):
122141
self.qmenu.addSeparator()
123142

124143

125-
class MenuCommand(object):
144+
class NodesMenu(NodeGraphMenu):
145+
"""
146+
The ``NodesMenu`` is the context menu triggered from the nodes.
147+
148+
**Inherited from:** :class:`NodeGraphQt.NodeGraphMenu`
149+
150+
example for adding a command to the nodes context menu.
151+
152+
.. code-block:: python
153+
:linenos:
154+
155+
from NodeGraphQt import BaseNode, NodeGraph
156+
157+
# example node.
158+
class MyNode(BaseNode):
159+
160+
__identifier__ = 'com.chantasticvfx'
161+
NODE_NAME = 'my node'
162+
163+
def __init__(self):
164+
super(MyNode, self).__init__()
165+
self.add_input('in')
166+
self.add_output('out')
167+
168+
# create node graph.
169+
node_graph = NodeGraph()
170+
171+
# register example node.
172+
node_graph.register_node(MyNode)
173+
174+
# get the context menu for the nodes.
175+
nodes_menu = node_graph.get_context_menu('nodes')
176+
177+
# create a command
178+
def test_func(graph, node):
179+
print('Clicked on node: {}'.format(node.name()))
180+
181+
nodes_menu.add_command('test',
182+
func=test_func,
183+
node_type='com.chantasticvfx.MyNode')
184+
126185
"""
127-
base class for a menu command.
186+
187+
def add_command(self, name, func=None, node_type=None):
188+
"""
189+
Re-implemented to add a command to the specified node type menu.
190+
191+
Args:
192+
name (str): command name.
193+
func (function): command function eg. "func(``graph``, ``node``)".
194+
node_type (str): specified node type for the command.
195+
196+
Returns:
197+
NodeGraphQt.MenuCommand: the appended command.
198+
"""
199+
if not node_type:
200+
raise NodeMenuError('Node type not specified!')
201+
202+
node_menu = self.qmenu.get_menu(node_type)
203+
if not node_menu:
204+
node_menu = BaseMenu(node_type, self.qmenu)
205+
self.qmenu.addMenu(node_menu)
206+
207+
if not self.qmenu.isEnabled():
208+
self.qmenu.setDisabled(False)
209+
210+
action = NodeAction(name, self._graph.viewer())
211+
action.graph = self._graph
212+
if LooseVersion(QtCore.qVersion()) >= LooseVersion('5.10'):
213+
action.setShortcutVisibleInContextMenu(True)
214+
if func:
215+
action.executed.connect(func)
216+
qaction = node_menu.addAction(action)
217+
return NodeGraphCommand(self._graph, qaction)
218+
219+
220+
class NodeGraphCommand(object):
221+
"""
222+
Node graph menu command.
128223
"""
129224

130-
def __init__(self, viewer, qaction):
131-
self.__viewer = viewer
132-
self.__qaction = qaction
225+
def __init__(self, graph, qaction):
226+
self._graph = graph
227+
self._qaction = qaction
133228

134229
def __repr__(self):
135-
cls_name = self.__class__.__name__
136-
return 'NodeGraphQt.{}(\'{}\')'.format(cls_name, self.name())
230+
return '<{}("{}") object at {}>'.format(
231+
self.__class__.__name__, self.name(), hex(id(self)))
137232

138233
@property
139234
def qaction(self):
140-
return self.__qaction
235+
"""
236+
The underlying qaction.
237+
238+
Returns:
239+
BaseAction: qaction object.
240+
"""
241+
return self._qaction
141242

142243
def name(self):
143244
"""

0 commit comments

Comments
 (0)