Skip to content

Commit

Permalink
Merge pull request #186 from ceccopierangiolieugenio/dev
Browse files Browse the repository at this point in the history
Dev Branch
  • Loading branch information
ceccopierangiolieugenio authored Oct 10, 2023
2 parents 0e5162f + 14536dd commit a0d6ee5
Show file tree
Hide file tree
Showing 16 changed files with 535 additions and 65 deletions.
1 change: 0 additions & 1 deletion TermTk/TTkCore/canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class TTkCanvas:
'''
__slots__ = (
'_width', '_height', '_newWidth', '_newHeight',
'_theme',
'_data', '_colors',
'_bufferedData', '_bufferedColors',
'_visible', '_transparent', '_doubleBuffer')
Expand Down
12 changes: 12 additions & 0 deletions TermTk/TTkCore/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ class InsertPolicy(int):
# InsertAlphabetically = 0x06
# '''The string is inserted in the alphabetic order in the combobox.'''

class DragDropMode(int):
'''Specifies the Drag and Drop mode allowed by this widget'''
NoDragDrop = 0x00
'''No Drag and Drop is allowed'''
AllowDrag = 0x01
'''Drag allowed'''
AllowDrop = 0x02
'''Drop allowed'''
NoDragDrop = DragDropMode.NoDragDrop
AllowDrag = DragDropMode.AllowDrag
AllowDrop = DragDropMode.AllowDrop

class ChildIndicatorPolicy(int):
ShowIndicator = 0x00 #The controls for expanding and collapsing will be shown for this item even if there are no children.
DontShowIndicator = 0x01 #The controls for expanding and collapsing will never be shown even if there are children. If the node is forced open the user will not be able to expand or collapse the item.
Expand Down
46 changes: 45 additions & 1 deletion TermTk/TTkUiTools/properties/list_.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,48 @@

__all__ = ['TTkListProperties']

TTkListProperties = {'properties' : {},'signals' : {},'slots' : {}}
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkWidgets.list_ import TTkList
from TermTk.TTkWidgets.listwidget import TTkListWidget, TTkAbstractListItem


TTkListProperties = {
'properties' : {
'Selection Mode' : {
'init': {'name':'selectionMode', 'type':'singleflag',
'flags':{
'Single Seelction' : TTkK.SingleSelection,
'Multi Selection' : TTkK.MultiSelection,
}},
'get': {'cb':lambda w: w.selectionMode(), 'type':'singleflag',
'flags':{
'Single Seelction' : TTkK.SingleSelection,
'Multi Selection' : TTkK.MultiSelection,
}},
'set': {'cb':lambda w,v: w.setSelectionMode(v), 'type':'singleflag',
'flags':{
'Single Seelction' : TTkK.SingleSelection,
'Multi Selection' : TTkK.MultiSelection,
}}},
'DnD Mode' : {
'init': {'name':'dragDropMode', 'type':'multiflags',
'flags':{
'Allow Drag' : TTkK.DragDropMode.AllowDrag,
'Allow Drop' : TTkK.DragDropMode.AllowDrop,
}},
'get': {'cb':lambda w: w.dragDropMode(), 'type':'multiflags',
'flags':{
'Allow Drag' : TTkK.DragDropMode.AllowDrag,
'Allow Drop' : TTkK.DragDropMode.AllowDrop,
}},
'set': {'cb':lambda w,v: w.setDragDropMode(v), 'type':'multiflags',
'flags':{
'Allow Drag' : TTkK.DragDropMode.AllowDrag,
'Allow Drop' : TTkK.DragDropMode.AllowDrop,
}}},
},
'signals' : {
'itemClicked(TTkAbstractListItem)' : {'name': 'itemClicked', 'type' : TTkAbstractListItem},
'textClicked(str)' : {'name': 'textClicked', 'type' : str},
},
'slots' : {}}
4 changes: 2 additions & 2 deletions TermTk/TTkWidgets/kodetab.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ def _importMenu(self, kt):
kt._tabBarTopLayout.update()

def dragEnterEvent(self, evt) -> bool:
TTkLog.debug(f"leave")
TTkLog.debug(f"Drag Enter")
return True

def dragLeaveEvent(self, evt) -> bool:
TTkLog.debug(f"leave")
TTkLog.debug(f"Drag Leave")
self._frameOverlay = None
self.update()
return True
Expand Down
15 changes: 12 additions & 3 deletions TermTk/TTkWidgets/list_.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ class TTkList(TTkAbstractScrollArea):
__slots__ = (
'_listView', 'itemClicked', 'textClicked',
# Forwarded Methods
'items', 'addItem', 'addItemAt', 'indexOf', 'itemAt',
'moveItem', 'removeAt', 'removeItem',
'setSelectionMode', 'selectedItems', 'selectedLabels',
'items',
'dragDropMode', 'setDragDropMode',
'addItem', 'addItemAt', 'addItems', 'addItemsAt',
'indexOf', 'itemAt', 'moveItem',
'removeAt', 'removeItem', 'removeItems',
'selectionMode', 'setSelectionMode', 'selectedItems', 'selectedLabels',
'setCurrentRow', 'setCurrentItem', )

def __init__(self, *args, **kwargs):
Expand All @@ -51,11 +54,17 @@ def __init__(self, *args, **kwargs):
self.moveItem = self._listView.moveItem
self.removeAt = self._listView.removeAt
self.removeItem = self._listView.removeItem
self.removeItems = self._listView.removeItems
self.addItem = self._listView.addItem
self.addItems = self._listView.addItems
self.addItemAt = self._listView.addItemAt
self.addItemsAt = self._listView.addItemsAt
self.selectionMode = self._listView.selectionMode
self.setSelectionMode = self._listView.setSelectionMode
self.selectedItems = self._listView.selectedItems
self.selectedLabels = self._listView.selectedLabels
self.setCurrentRow = self._listView.setCurrentRow
self.setCurrentItem = self._listView.setCurrentItem
self.dragDropMode = self._listView.dragDropMode
self.setDragDropMode = self._listView.setDragDropMode

178 changes: 149 additions & 29 deletions TermTk/TTkWidgets/listwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,27 @@

__all__ = ['TTkAbstractListItem', 'TTkListWidget']

from dataclasses import dataclass

from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.string import TTkString
from TermTk.TTkGui.drag import TTkDrag
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.label import TTkLabel
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView

class TTkAbstractListItem(TTkWidget):
'''TTkAbstractListItem'''

classStyle = TTkWidget.classStyle | {
'default': {'color': TTkColor.RST},
'highlighted': {'color': TTkColor.fg('#00FF00')+TTkColor.bg('#0055FF')+TTkColor.UNDERLINE},
'hover': {'color': TTkColor.fg('#00FF00')+TTkColor.bg('#0088FF')},
'selected': {'color': TTkColor.fg('#00FF00')+TTkColor.bg('#0055FF')},
'highlighted': {'color': TTkColor.bg('#008855')+TTkColor.UNDERLINE},
'hover': {'color': TTkColor.bg('#0088FF')},
'selected': {'color': TTkColor.bg('#0055FF')},
'clicked': {'color': TTkColor.fg('#FFFF00')},
'disabled': {'color': TTkColor.fg('#888888')},
}
Expand Down Expand Up @@ -92,29 +95,40 @@ def _setHighlighted(self, highlighted):
self.update()

def paintEvent(self, canvas):
style = self.currentStyle()
if style == self.classStyle['hover']:
pass
elif self._highlighted:
style = self.style()['highlighted']
elif self._selected:
style = self.style()['selected']
color = (style:=self.currentStyle())['color']
if self._highlighted:
color = color+self.style()['highlighted']['color']
if self._selected:
color = color+self.style()['selected']['color']
if style==self.style()['hover']:
color = color+self.style()['hover']['color']

w = self.width()

canvas.drawTTkString(pos=(0,0), width=w, color=style['color'] ,text=self._text)
canvas.drawTTkString(pos=(0,0), width=w, color=color ,text=self._text)

class TTkListWidget(TTkAbstractScrollView):
@dataclass(frozen=True)
class _DropListData:
widget: TTkAbstractScrollView
items: list

'''TTkListWidget'''
__slots__ = ('itemClicked', 'textClicked', '_selectedItems', '_selectionMode', '_highlighted', '_items')
__slots__ = ('itemClicked', 'textClicked',
'_selectedItems', '_selectionMode',
'_highlighted', '_items',
'_dragPos', '_dndMode')
def __init__(self, *args, **kwargs):
# Default Class Specific Values
self._selectionMode = kwargs.get("selectionMode", TTkK.SingleSelection)
self._selectedItems = []
self._items = []
self._highlighted = None
self._dragPos = None
self._dndMode = kwargs.get("dragDropMode",
TTkK.DragDropMode.AllowDrag | TTkK.DragDropMode.AllowDrop )
# Signals
self.itemClicked = pyTTkSignal(TTkWidget)
self.itemClicked = pyTTkSignal(TTkAbstractListItem)
self.textClicked = pyTTkSignal(str)
# Init Super
TTkAbstractScrollView.__init__(self, *args, **kwargs)
Expand Down Expand Up @@ -149,6 +163,18 @@ def _labelSelectedHandler(self, label:TTkAbstractListItem):
self.itemClicked.emit(label)
self.textClicked.emit(label.text())

def dragDropMode(self):
'''dragDropMode'''
return self._dndMode

def setDragDropMode(self, dndMode):
'''setDragDropMode'''
self._dndMode = dndMode

def selectionMode(self):
'''selectionMode'''
return self._selectionMode

def setSelectionMode(self, mode):
'''setSelectionMode'''
self._selectionMode = mode
Expand Down Expand Up @@ -186,23 +212,35 @@ def addItem(self, item, data=None):
'''addItem'''
self.addItemAt(item, len(self._items), data)

def addItems(self, items):
'''addItems'''
self.addItemAt(items, len(self._items))

def _placeItems(self):
minw = self.width()
for item in self._items:
minw = max(minw,item.minimumWidth())
for y,item in enumerate(self._items):
item.setGeometry(0,y,minw,1)
self.viewChanged.emit()
self.update()

def addItemAt(self, item, pos, data=None):
'''addItemAt'''
if isinstance(item, str) or isinstance(item, TTkString):
#label = TTkAbstractListItem(text=item, width=max(len(item),self.width()))
label = TTkAbstractListItem(text=item, data=data)
return self.addItemAt(label,pos)
item.listItemClicked.connect(self._labelSelectedHandler)
self._items.insert(pos,item)
self.layout().addWidget(item)
item = TTkAbstractListItem(text=item, data=data)
return self.addItemsAt([item],pos)

def addItemsAt(self, items, pos):
'''addItemsAt'''
for item in items:
if not issubclass(type(item),TTkAbstractListItem):
TTkLog.error(f"{item=} is not an TTkAbstractListItem")
return
for item in items:
item.listItemClicked.connect(self._labelSelectedHandler)
self._items[pos:pos] = items
self.layout().addWidgets(items)
self._placeItems()

def indexOf(self, item):
Expand All @@ -226,15 +264,20 @@ def moveItem(self, fr, to):

def removeItem(self, item):
'''removeItem'''
item.listItemClicked.disconnect(self._labelSelectedHandler)
item._setSelected(False)
item._setHighlighted(False)
self.layout().removeWidget(item)
self._items.remove(item)
if item in self._selectedItems:
self._selectedItems.remove(item)
if item == self._highlighted:
self._highlighted = None
self.removeItems([item])

def removeItems(self, items):
'''removeItems'''
self.layout().removeWidgets(items)
for item in items.copy():
item.listItemClicked.disconnect(self._labelSelectedHandler)
item._setSelected(False)
item._setHighlighted(False)
self._items.remove(item)
if item in self._selectedItems:
self._selectedItems.remove(item)
if item == self._highlighted:
self._highlighted = None
self._placeItems()

def removeAt(self, pos):
Expand All @@ -261,6 +304,67 @@ def _moveToHighlighted(self):
elif index <= offy:
self.viewMoveTo(offx, index)

def mouseDragEvent(self, evt) -> bool:
if not(self._dndMode & TTkK.DragDropMode.AllowDrag):
return False
if not (items:=self._selectedItems.copy()):
return True
drag = TTkDrag()
data =TTkListWidget._DropListData(widget=self,items=items)
h = min(3,ih:=len(items)) + 2 + (1 if ih>3 else 0)
w = min(20,iw:=max([it.text().termWidth() for it in items[:3]])) + 2
pm = TTkCanvas(width=w,height=h)
for y,it in enumerate(items[:3],1):
txt = it.text()
if txt.termWidth() < 20:
pm.drawText(pos=(1,y), text=it.text())
else:
pm.drawText(pos=(1,y), text=it.text(), width=17)
pm.drawText(pos=(18,y), text='...')
if ih>3:
pm.drawText(pos=(1,4), text='...')
pm.drawBox(pos=(0,0),size=(w,h))
drag.setPixmap(pm)
drag.setData(data)
drag.exec()
return True

def dragEnterEvent(self, evt):
if not(self._dndMode & TTkK.DragDropMode.AllowDrop):
return False
if issubclass(type(evt.data()),TTkListWidget._DropListData):
return self.dragMoveEvent(evt)
return False

def dragMoveEvent(self, evt):
offx,offy = self.getViewOffsets()
y=min(evt.y+offy,len(self._items))
self._dragPos = (offx+evt.x, y)
self.update()
return True

def dragLeaveEvent(self, evt):
self._dragPos = None
self.update()
return True

def dropEvent(self, evt) -> bool:
if not(self._dndMode & TTkK.DragDropMode.AllowDrop):
return False
self._dragPos = None
if not issubclass(type(evt.data()) ,TTkListWidget._DropListData):
return False
offx,offy = self.getViewOffsets()
wid = evt.data().widget
items = evt.data().items
if wid and items:
wid.removeItems(items)
for it in items:
it.setCurrentStyle(it.style()['default'])
self.addItemsAt(items,offy+evt.y)
return True
return False

def keyEvent(self, evt):
if not self._highlighted: return False
if ( evt.type == TTkK.Character and evt.key==" " ) or \
Expand Down Expand Up @@ -309,3 +413,19 @@ def focusInEvent(self):
def focusOutEvent(self):
if self._highlighted:
self._highlighted._setHighlighted(False)
self._dragPos = None

# Stupid hack to paint on top of the child widgets
def paintChildCanvas(self):
super().paintChildCanvas()
if self._dragPos:
canvas = self.getCanvas()
x,y = self._dragPos
offx,offy = self.getViewOffsets()
p1 = (0,y-offy-1)
p2 = (0,y-offy)
canvas.drawText(pos=p1,text="╙─╼", color=TTkColor.fg("#FFFF00")+TTkColor.bg("#008855"))
canvas.drawText(pos=p2,text="╓─╼", color=TTkColor.fg("#FFFF00")+TTkColor.bg("#008855"))



Loading

0 comments on commit a0d6ee5

Please sign in to comment.