11#!/usr/bin/python
2- from NodeGraphQt import QtCore , QtWidgets
2+ from NodeGraphQt import QtCore , QtWidgets , QtGui
33
4- from NodeGraphQt .widgets .stylesheet import STYLE_TABSEARCH , STYLE_TABSEARCH_LIST
4+ from NodeGraphQt .widgets .stylesheet import STYLE_TABSEARCH , STYLE_TABSEARCH_LIST , STYLE_QMENU
55
66
77class TabSearchCompleter (QtWidgets .QCompleter ):
@@ -22,17 +22,20 @@ def __init__(self, nodes=None, parent=None):
2222 def splitPath (self , path ):
2323 self ._local_completion_prefix = path
2424 self .updateModel ()
25+
2526 if self ._filter_model .rowCount () == 0 :
2627 self ._using_orig_model = False
27- self ._filter_model .setSourceModel (QtCore .QStringListModel ([path ]))
28- return [path ]
28+ self ._filter_model .setSourceModel (QtCore .QStringListModel ([]))
29+ return []
2930 return []
3031
31- def updateModel (self ):
32+ def updateModel (self , text = None ):
3233 if not self ._using_orig_model :
3334 self ._filter_model .setSourceModel (self ._source_model )
3435
35- pattern = QtCore .QRegExp (self ._local_completion_prefix ,
36+ text = text or self ._local_completion_prefix
37+ print (text )
38+ pattern = QtCore .QRegExp (text ,
3639 QtCore .Qt .CaseInsensitive ,
3740 QtCore .QRegExp .FixedString )
3841 self ._filter_model .setFilterRegExp (pattern )
@@ -70,24 +73,35 @@ def __init__(self, parent=None, node_dict=None):
7073 popup .setStyleSheet (STYLE_TABSEARCH_LIST )
7174 popup .clicked .connect (self ._on_search_submitted )
7275 self .returnPressed .connect (self ._on_search_submitted )
76+ self .textChanged .connect (self ._on_text_changed )
7377
7478 def __repr__ (self ):
7579 return '<{} at {}>' .format (self .__class__ .__name__ , hex (id (self )))
7680
7781 def _on_search_submitted (self , index = 0 ):
7882 node_type = self ._node_dict .get (self .text ())
83+ if not node_type :
84+ model = self ._completer .popup ().model ()
85+ text = model .data (model .index (0 , 0 ))
86+ node_type = self ._node_dict .get (text )
87+
7988 if node_type :
8089 self .search_submitted .emit (node_type )
90+
8191 self .close ()
8292 self .parentWidget ().clearFocus ()
8393
94+ def _on_text_changed (self , text ):
95+ if not text :
96+ # TODO: show all items
97+ pass
98+
8499 def showEvent (self , event ):
85100 super (TabSearchWidget , self ).showEvent (event )
86- self .setSelection (0 , len (self .text ()))
87101 self .setFocus ()
88- if not self .text ():
89- self .completer ().popup ().show ()
90- self .completer ().complete ()
102+ self .setText ( "" )
103+ self .completer ().popup ().show ()
104+ self .completer ().complete ()
91105
92106 def mousePressEvent (self , event ):
93107 if not self .text ():
@@ -104,3 +118,124 @@ def set_nodes(self, node_dict=None):
104118 node_names = sorted (self ._node_dict .keys ())
105119 self ._model .setStringList (node_names )
106120 self ._completer .setModel (self ._model )
121+
122+
123+ class TabSearchMenuWidget (QtWidgets .QLineEdit ):
124+ search_submitted = QtCore .Signal (str )
125+
126+ def __init__ (self , parent = None , node_dict = None ):
127+ super (TabSearchMenuWidget , self ).__init__ (parent )
128+ self .setAttribute (QtCore .Qt .WA_MacShowFocusRect , 0 )
129+ self .setStyleSheet (STYLE_TABSEARCH )
130+ self .setMinimumSize (200 , 22 )
131+ self .setTextMargins (2 , 0 , 2 , 0 )
132+
133+ self ._node_dict = node_dict or {}
134+ if self ._node_dict :
135+ self ._generate_items_from_node_dict ()
136+
137+ self .SearchMenu = QtWidgets .QMenu ()
138+ searchWidget = QtWidgets .QWidgetAction (self )
139+ searchWidget .setDefaultWidget (self )
140+ self .SearchMenu .addAction (searchWidget )
141+ self .SearchMenu .setStyleSheet (STYLE_QMENU )
142+
143+ self ._actions = []
144+ self ._menus = {}
145+ self ._searched_actions = []
146+
147+ self .returnPressed .connect (self ._on_search_submitted )
148+ self .textChanged .connect (self ._on_text_changed )
149+
150+ def __repr__ (self ):
151+ return '<{} at {}>' .format (self .__class__ .__name__ , hex (id (self )))
152+
153+ def _on_text_changed (self ,text ):
154+ self ._clear_actions ()
155+
156+ if not text :
157+ self ._set_menu_visible (True )
158+ return
159+
160+ self ._set_menu_visible (False )
161+
162+ self ._searched_actions = [action for action in self ._actions \
163+ if text .lower () in action .text ().lower ()]
164+
165+ self .SearchMenu .addActions (self ._searched_actions )
166+
167+ def _clear_actions (self ):
168+ for action in self ._searched_actions :
169+ self .SearchMenu .removeAction (action )
170+ self ._searched_actions = []
171+
172+ def _set_menu_visible (self ,visible ):
173+ for menu in self ._menus .values ():
174+ menu .menuAction ().setVisible (visible )
175+
176+ def _close (self ):
177+ self ._set_menu_visible (False )
178+ self .SearchMenu .setVisible (False )
179+ self .SearchMenu .menuAction ().setVisible (False )
180+
181+ def _show (self ):
182+ self .SearchMenu .exec_ (QtGui .QCursor .pos ())
183+ self .setText ("" )
184+ self .setFocus ()
185+ self ._set_menu_visible (True )
186+
187+ def _on_search_submitted (self ):
188+ action = self .sender ()
189+ if type (action ) is not QtWidgets .QAction :
190+ if len (self ._searched_actions ) > 0 :
191+ action = self ._searched_actions [0 ]
192+ else :
193+ self ._close ()
194+ return
195+
196+ text = action .text ()
197+ node_type = self ._node_dict .get (text )
198+ if node_type :
199+ self .search_submitted .emit (node_type )
200+
201+ self ._close ()
202+
203+ def _generate_items_from_node_dict (self ):
204+ node_names = sorted (self ._node_dict .keys ())
205+ node_types = sorted (self ._node_dict .values ())
206+
207+ for node_type in node_types :
208+ menu_name = "." .join (node_type .split ("." )[:- 1 ])
209+ if menu_name not in self ._menus .keys ():
210+ new_menu = QtWidgets .QMenu (menu_name )
211+ new_menu .setStyleSheet (STYLE_QMENU )
212+ self ._menus [menu_name ] = new_menu
213+ self .SearchMenu .addMenu (new_menu )
214+
215+ for name in node_names :
216+ action = QtWidgets .QAction (name , self )
217+ action .setText (name )
218+ action .triggered .connect (self ._on_search_submitted )
219+ self ._actions .append (action )
220+
221+ menu_name = self ._node_dict [name ]
222+ menu_name = "." .join (menu_name .split ("." )[:- 1 ])
223+
224+ if menu_name in self ._menus .keys ():
225+ self ._menus [menu_name ].addAction (action )
226+ else :
227+ self .SearchMenu .addAction (action )
228+
229+ def set_nodes (self , node_dict = None ):
230+ if not self ._node_dict :
231+ self ._node_dict = {}
232+ for name , node_types in node_dict .items ():
233+ if len (node_types ) == 1 :
234+ self ._node_dict [name ] = node_types [0 ]
235+ continue
236+ for node_id in node_types :
237+ self ._node_dict ['{} ({})' .format (name , node_id )] = node_id
238+ self ._generate_items_from_node_dict ()
239+
240+ self ._show ()
241+
0 commit comments