@@ -166,12 +166,14 @@ def itemCollapsed(self) -> pyTTkSignal:
166166
167167 __slots__ = ( '_rootItem' , '_cache' ,
168168 '_header' , '_columnsPos' ,
169+ '_selectionMode' ,
169170 '_selectedId' , '_selected' , '_separatorSelected' ,
170171 '_sortColumn' , '_sortOrder' , '_sortingEnabled' ,
171172 '_dndMode' ,
172173 # Signals
173174 '_itemChanged' , '_itemClicked' , '_itemDoubleClicked' , '_itemExpanded' , '_itemCollapsed' , '_itemActivated'
174175 )
176+
175177 @dataclass (frozen = True )
176178 class _Cache :
177179 item : TTkTreeWidgetItem
@@ -180,6 +182,9 @@ class _Cache:
180182 widgets : list
181183 firstLine : bool
182184
185+ _cache :List [_Cache ]
186+ _selected :List [TTkTreeWidgetItem ]
187+
183188 @dataclass (frozen = True )
184189 class _DropTreeData :
185190 widget : TTkAbstractScrollView
@@ -188,13 +193,16 @@ class _DropTreeData:
188193 def __init__ (self , * ,
189194 header = None ,
190195 sortingEnabled = True ,
196+ selectionMode :TTkK .SelectionMode = TTkK .SelectionMode .SingleSelection ,
191197 dragDropMode :TTkK .DragDropMode = TTkK .DragDropMode .NoDragDrop ,
192198 ** kwargs ) -> None :
193199 '''
194200 :param header: define the header labels of each column, defaults to []
195201 :type header: list[TTkString], optional
196202 :param sortingEnabled: enable the column sorting, defaults to False
197203 :type sortingEnabled: bool, optional
204+ :param selectionMode: This property controls whether the user can select one or many items, defaults to :py:class:`TTkK.SelectionMode.SingleSelection`.
205+ :type selectionMode: :py:class:`TTkK.SelectionMode`, optional
198206 :param dragDropMode: This property holds the drag and drop event the view will act upon, defaults to :py:class:`TTkK.DragDropMode.NoDragDrop`.
199207 :type dragDropMode: :py:class:`TTkK.DragDropMode`, optional
200208 '''
@@ -206,8 +214,9 @@ def __init__(self, *,
206214 self ._itemExpanded = pyTTkSignal (TTkTreeWidgetItem )
207215 self ._itemCollapsed = pyTTkSignal (TTkTreeWidgetItem )
208216
217+ self ._selectionMode = selectionMode
209218 self ._dndMode = dragDropMode
210- self ._selected = None
219+ self ._selected = []
211220 self ._selectedId = None
212221 self ._separatorSelected = None
213222 self ._header = header if header else []
@@ -283,10 +292,18 @@ def indexOfTopLevelItem(self, item:TTkTreeWidgetItem) -> int:
283292 '''indexOfTopLevelItem'''
284293 return self ._rootItem .indexOfChild (item )
285294
295+ def selectionMode (self ) -> TTkK .SelectionMode :
296+ '''selectionMode'''
297+ return self ._selectionMode
298+
299+ def setSelectionMode (self , mode :TTkK .SelectionMode ) -> None :
300+ '''setSelectionMode'''
301+ self ._selectionMode = mode
302+
286303 def selectedItems (self ) -> list [TTkTreeWidgetItem ]:
287304 '''selectedItems'''
288305 if self ._selected :
289- return [ self ._selected ]
306+ return self ._selected
290307 return None
291308
292309 def setHeaderLabels (self , labels :TTkString ) -> None :
@@ -395,11 +412,11 @@ def mouseDoubleClickEvent(self, evt:TTkMouseEvent) -> bool:
395412 self .itemExpanded .emit (item )
396413 else :
397414 self .itemCollapsed .emit (item )
398- if self ._selected :
399- self . _selected .setSelected (False )
415+ for _s in self ._selected :
416+ _s .setSelected (False )
400417 self ._selectedId = y
401- self ._selected = item
402- self . _selected .setSelected (True )
418+ self ._selected = [ item ]
419+ item .setSelected (True )
403420 col = - 1
404421 for i , c in enumerate (self ._columnsPos ):
405422 if x < c :
@@ -449,11 +466,16 @@ def mousePressEvent(self, evt:TTkMouseEvent) -> bool:
449466 else :
450467 self .itemCollapsed .emit (item )
451468 else :
452- if self ._selected :
453- self ._selected .setSelected (False )
454- self ._selectedId = y
455- self ._selected = item
456- self ._selected .setSelected (True )
469+ if self ._selectionMode in (TTkK .SelectionMode .SingleSelection ,TTkK .SelectionMode .MultiSelection ):
470+ if not (
471+ bool (evt .mod & TTkK .ControlModifier ) and
472+ self ._selectionMode == TTkK .SelectionMode .MultiSelection ):
473+ for _s in self ._selected :
474+ _s .setSelected (False )
475+ self ._selected .clear ()
476+ self ._selectedId = y
477+ self ._selected .append (item )
478+ item .setSelected (True )
457479 col = - 1
458480 for i , c in enumerate (self ._columnsPos ):
459481 if x < c :
@@ -492,14 +514,16 @@ def mouseDragEvent(self, evt:TTkMouseEvent) -> bool:
492514 elif ( self ._dndMode & TTkK .DragDropMode .AllowDrag and
493515 evt .key == TTkMouseEvent .LeftButton and self ._selected ):
494516 drag = TTkDrag ()
495- data = TTkTreeWidget ._DropTreeData (widget = self ,items = [self ._selected ])
496- text = self ._selected .data (0 )
497- if text .termWidth () > 30 :
498- text = '[' + text .substring (to = 27 )+ '...]'
499- else :
500- text = '[' + text + ']'
501- pm = TTkCanvas (text .termWidth ()+ 2 ,1 )
502- pm .drawTTkString (pos = (0 ,0 ),text = text )
517+ data = TTkTreeWidget ._DropTreeData (widget = self ,items = self ._selected )
518+ text = [(_n .substring (to = 27 )+ '...' ) if (_n := _s .data (0 )).termWidth ()> 30 else _n for _s in self ._selected [:4 ]]
519+ dh = len (text ) + 2
520+ dw = max (_t .termWidth () for _t in text [:3 ])+ 2
521+ pm = TTkCanvas (width = dw ,height = dh )
522+ for _y ,_t in enumerate (text [:3 ],1 ):
523+ pm .drawTTkString (pos = (1 ,_y ),text = _t )
524+ if len (self ._selected ) > 3 :
525+ pm .drawText (pos = (1 ,4 ),text = '...' )
526+ pm .drawBox (pos = (0 ,0 ),size = (dw ,dh ))
503527 drag .setPixmap (pm )
504528 drag .setData (data )
505529 drag .exec ()
0 commit comments