Browse Source

feat(Tree): add multiselect (#436)

pull/437/head
Pier CeccoPierangioliEugenio 7 months ago committed by GitHub
parent
commit
de0aefc11e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 62
      libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py
  2. 8
      libs/pyTermTk/TermTk/TTkWidgets/texedit.py

62
libs/pyTermTk/TermTk/TTkWidgets/TTkModelView/treewidget.py

@ -166,12 +166,14 @@ class TTkTreeWidget(TTkAbstractScrollView):
__slots__ = ( '_rootItem', '_cache', __slots__ = ( '_rootItem', '_cache',
'_header', '_columnsPos', '_header', '_columnsPos',
'_selectionMode',
'_selectedId', '_selected', '_separatorSelected', '_selectedId', '_selected', '_separatorSelected',
'_sortColumn', '_sortOrder', '_sortingEnabled', '_sortColumn', '_sortOrder', '_sortingEnabled',
'_dndMode', '_dndMode',
# Signals # Signals
'_itemChanged', '_itemClicked', '_itemDoubleClicked', '_itemExpanded', '_itemCollapsed', '_itemActivated' '_itemChanged', '_itemClicked', '_itemDoubleClicked', '_itemExpanded', '_itemCollapsed', '_itemActivated'
) )
@dataclass(frozen=True) @dataclass(frozen=True)
class _Cache: class _Cache:
item: TTkTreeWidgetItem item: TTkTreeWidgetItem
@ -180,6 +182,9 @@ class TTkTreeWidget(TTkAbstractScrollView):
widgets: list widgets: list
firstLine: bool firstLine: bool
_cache:List[_Cache]
_selected:List[TTkTreeWidgetItem]
@dataclass(frozen=True) @dataclass(frozen=True)
class _DropTreeData: class _DropTreeData:
widget: TTkAbstractScrollView widget: TTkAbstractScrollView
@ -188,6 +193,7 @@ class TTkTreeWidget(TTkAbstractScrollView):
def __init__(self, *, def __init__(self, *,
header=None, header=None,
sortingEnabled=True, sortingEnabled=True,
selectionMode:TTkK.SelectionMode=TTkK.SelectionMode.SingleSelection,
dragDropMode:TTkK.DragDropMode=TTkK.DragDropMode.NoDragDrop, dragDropMode:TTkK.DragDropMode=TTkK.DragDropMode.NoDragDrop,
**kwargs) -> None: **kwargs) -> None:
''' '''
@ -195,6 +201,8 @@ class TTkTreeWidget(TTkAbstractScrollView):
:type header: list[TTkString], optional :type header: list[TTkString], optional
:param sortingEnabled: enable the column sorting, defaults to False :param sortingEnabled: enable the column sorting, defaults to False
:type sortingEnabled: bool, optional :type sortingEnabled: bool, optional
:param selectionMode: This property controls whether the user can select one or many items, defaults to :py:class:`TTkK.SelectionMode.SingleSelection`.
:type selectionMode: :py:class:`TTkK.SelectionMode`, optional
:param dragDropMode: This property holds the drag and drop event the view will act upon, defaults to :py:class:`TTkK.DragDropMode.NoDragDrop`. :param dragDropMode: This property holds the drag and drop event the view will act upon, defaults to :py:class:`TTkK.DragDropMode.NoDragDrop`.
:type dragDropMode: :py:class:`TTkK.DragDropMode`, optional :type dragDropMode: :py:class:`TTkK.DragDropMode`, optional
''' '''
@ -206,8 +214,9 @@ class TTkTreeWidget(TTkAbstractScrollView):
self._itemExpanded = pyTTkSignal(TTkTreeWidgetItem) self._itemExpanded = pyTTkSignal(TTkTreeWidgetItem)
self._itemCollapsed = pyTTkSignal(TTkTreeWidgetItem) self._itemCollapsed = pyTTkSignal(TTkTreeWidgetItem)
self._selectionMode = selectionMode
self._dndMode = dragDropMode self._dndMode = dragDropMode
self._selected = None self._selected = []
self._selectedId = None self._selectedId = None
self._separatorSelected = None self._separatorSelected = None
self._header = header if header else [] self._header = header if header else []
@ -283,10 +292,18 @@ class TTkTreeWidget(TTkAbstractScrollView):
'''indexOfTopLevelItem''' '''indexOfTopLevelItem'''
return self._rootItem.indexOfChild(item) return self._rootItem.indexOfChild(item)
def selectionMode(self) -> TTkK.SelectionMode:
'''selectionMode'''
return self._selectionMode
def setSelectionMode(self, mode:TTkK.SelectionMode) -> None:
'''setSelectionMode'''
self._selectionMode = mode
def selectedItems(self) -> list[TTkTreeWidgetItem]: def selectedItems(self) -> list[TTkTreeWidgetItem]:
'''selectedItems''' '''selectedItems'''
if self._selected: if self._selected:
return [self._selected] return self._selected
return None return None
def setHeaderLabels(self, labels:TTkString) -> None: def setHeaderLabels(self, labels:TTkString) -> None:
@ -395,11 +412,11 @@ class TTkTreeWidget(TTkAbstractScrollView):
self.itemExpanded.emit(item) self.itemExpanded.emit(item)
else: else:
self.itemCollapsed.emit(item) self.itemCollapsed.emit(item)
if self._selected: for _s in self._selected:
self._selected.setSelected(False) _s.setSelected(False)
self._selectedId = y self._selectedId = y
self._selected = item self._selected = [item]
self._selected.setSelected(True) item.setSelected(True)
col = -1 col = -1
for i, c in enumerate(self._columnsPos): for i, c in enumerate(self._columnsPos):
if x < c: if x < c:
@ -449,11 +466,16 @@ class TTkTreeWidget(TTkAbstractScrollView):
else: else:
self.itemCollapsed.emit(item) self.itemCollapsed.emit(item)
else: else:
if self._selected: if self._selectionMode in (TTkK.SelectionMode.SingleSelection,TTkK.SelectionMode.MultiSelection):
self._selected.setSelected(False) if not (
self._selectedId = y bool(evt.mod & TTkK.ControlModifier) and
self._selected = item self._selectionMode == TTkK.SelectionMode.MultiSelection ):
self._selected.setSelected(True) for _s in self._selected:
_s.setSelected(False)
self._selected.clear()
self._selectedId = y
self._selected.append(item)
item.setSelected(True)
col = -1 col = -1
for i, c in enumerate(self._columnsPos): for i, c in enumerate(self._columnsPos):
if x < c: if x < c:
@ -492,14 +514,16 @@ class TTkTreeWidget(TTkAbstractScrollView):
elif ( self._dndMode & TTkK.DragDropMode.AllowDrag and elif ( self._dndMode & TTkK.DragDropMode.AllowDrag and
evt.key == TTkMouseEvent.LeftButton and self._selected ): evt.key == TTkMouseEvent.LeftButton and self._selected ):
drag = TTkDrag() drag = TTkDrag()
data = TTkTreeWidget._DropTreeData(widget=self,items=[self._selected]) data = TTkTreeWidget._DropTreeData(widget=self,items=self._selected)
text = self._selected.data(0) text = [(_n.substring(to=27)+'...') if (_n:=_s.data(0)).termWidth()>30 else _n for _s in self._selected[:4]]
if text.termWidth() > 30: dh = len(text) + 2
text = '['+text.substring(to=27)+'...]' dw = max(_t.termWidth() for _t in text[:3])+2
else: pm = TTkCanvas(width=dw,height=dh)
text = '['+text+']' for _y,_t in enumerate(text[:3],1):
pm = TTkCanvas(text.termWidth()+2,1) pm.drawTTkString(pos=(1,_y),text=_t)
pm.drawTTkString(pos=(0,0),text=text) if len(self._selected) > 3:
pm.drawText(pos=(1,4),text='...')
pm.drawBox(pos=(0,0),size=(dw,dh))
drag.setPixmap(pm) drag.setPixmap(pm)
drag.setData(data) drag.setData(data)
drag.exec() drag.exec()

8
libs/pyTermTk/TermTk/TTkWidgets/texedit.py

@ -1191,7 +1191,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
This signal is emitted if the current character color has changed, This signal is emitted if the current character color has changed,
for example caused by a change of the cursor position. for example caused by a change of the cursor position.
:param color: the new color :param color: the new color
:type color: :py:class:`TTkColor` :type color: :py:class:`TTkColor`
''' '''
@ -1202,7 +1202,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
.. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.cursorPositionChanged` .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.cursorPositionChanged`
This signal is emitted whenever the position of the cursor changed. This signal is emitted whenever the position of the cursor changed.
:param cursor: the cursor changed. :param cursor: the cursor changed.
:type cursor: :py:class:`TTkTextCursor` :type cursor: :py:class:`TTkTextCursor`
''' '''
@ -1214,7 +1214,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
This signal is emitted whenever undo operations become available (available is true) This signal is emitted whenever undo operations become available (available is true)
or unavailable (available is false). or unavailable (available is false).
:param available: the availability of undo :param available: the availability of undo
:type available: bool :type available: bool
''' '''
@ -1226,7 +1226,7 @@ class TTkTextEdit(TTkAbstractScrollArea):
This signal is emitted whenever redo operations become available (available is true) This signal is emitted whenever redo operations become available (available is true)
or unavailable (available is false). or unavailable (available is false).
:param available: the availability of redo :param available: the availability of redo
:type available: bool :type available: bool
''' '''

Loading…
Cancel
Save