Browse Source

Reworked DragDrop definitions

pull/305/head
Eugenio Parodi 🌶️ 1 year ago
parent
commit
caef420750
  1. 4
      TermTk/TTkCore/TTkTerm/__init__.py
  2. 98
      TermTk/TTkGui/drag.py
  3. 18
      TermTk/TTkTemplates/dragevents.py
  4. 19
      TermTk/TTkWidgets/listwidget.py
  5. 32
      TermTk/TTkWidgets/tabwidget.py
  6. 31
      demo/showcase/dragndrop.py
  7. 29
      tests/t.ui/test.ui.017.Drag.Drop.001.py

4
TermTk/TTkCore/TTkTerm/__init__.py

@ -1,5 +1,5 @@
# from .inputkey import *
# from .inputmouse import *
from .inputkey import *
from .inputmouse import *
# from .colors import *
from .input import *
from .term import *

98
TermTk/TTkGui/drag.py

@ -20,11 +20,12 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkDrag', 'TTkDropEvent']
__all__ = ['TTkDrag', 'TTkDnDEvent']
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
class _TTkDragDisplayWidget(TTkWidget):
__slots__ = ('_pixmap')
@ -41,30 +42,53 @@ class _TTkDragDisplayWidget(TTkWidget):
_,_,w,h = self.geometry()
canvas.paintCanvas(self._pixmap, (0,0,w,h), (0,0,w,h), (0,0,w,h))
class TTkDrag():
__slots__ = ('_data', '_pixmap', '_showPixmap', '_hotSpot')
def __init__(self):
self._data = None
class TTkDnD():
__slots__ = ('_data')
def __init__(self, data:object=None) -> None:
self._data = data
def setData(self, data:object) -> None:
self._data = data
def data(self) -> object:
return self._data
class TTkDnDEvent(TTkDnD):
__slots__ = ('_pos', 'x', 'y')
def __init__(self, data:object=None, pos:tuple[int,int]=(0,0)) -> None:
self._pos = pos
self.x, self.y = pos
super().__init__(data)
def setPos(self, pos:tuple[int,int]) -> None:
self._pos = pos
self.x, self.y = pos
def pos(self) -> tuple[int,int]:
return self._pos
def copy(self):
ret = TTkDnDEvent(self._data, self._pos)
return ret
class TTkDrag(TTkDnD):
__slots__ = ('_pixmap', '_showPixmap', '_hotSpot')
def __init__(self, data:object=None) -> None:
self._showPixmap = True
self._hotSpot = (0,0)
self._pixmap = _TTkDragDisplayWidget(size=(5,1))
pixmap = TTkCanvas(width=5, height=1)
pixmap.drawText(pos=(0,0), text='[...]')
self._pixmap.setPixmap(pixmap, self._hotSpot)
super().__init__(data)
def setData(self, data):
self._data = data
def data(self):
return self._data
def setHotSpot(self, x,y):
def setHotSpot(self, x,y) -> None:
self._hotSpot = (x,y)
def hotSpot(self):
def hotSpot(self) -> tuple[int,int]:
return self._hotSpot
def setPixmap(self, pixmap):
def setPixmap(self, pixmap:TTkWidget) -> None:
if issubclass(type(pixmap),TTkWidget):
canvas = pixmap.getCanvas()
canvas.updateSize()
@ -74,47 +98,33 @@ class TTkDrag():
pixmap.updateSize()
self._pixmap.setPixmap(pixmap, self._hotSpot)
def pixmap(self):
def pixmap(self) -> TTkWidget:
return self._pixmap
def visible(self):
def visible(self) -> bool:
return self._showPixmap
def showPixmap(self):
def showPixmap(self) -> None:
self._showPixmap = True
def hidePixmap(self):
def hidePixmap(self) -> None:
self._showPixmap = False
def exec(self):
def exec(self) -> None:
TTkHelper.dndInit(self)
@staticmethod
def copy(drag):
ret = TTkDropEvent()
ret._data = drag._data
ret._pixmap = drag._pixmap
ret._hotSpot = drag._hotSpot
def _toDropEvent(self, pos:tuple[int,int]) -> TTkDnDEvent:
ret = TTkDnDEvent(self._data, pos)
return ret
def getDragEnterEvent(self, evt):
ret = TTkDropEvent.copy(self)
ret._pos = (evt.x, evt.y)
ret.x = evt.x
ret.y = evt.y
return ret
def getDragEnterEvent(self, evt:TTkMouseEvent) -> TTkDnDEvent:
return self._toDropEvent((evt.x, evt.y))
def getDragLeaveEvent(self, evt):
return self.getDragEnterEvent(evt)
def getDragLeaveEvent(self, evt:TTkMouseEvent) -> TTkDnDEvent:
return self._toDropEvent((evt.x, evt.y))
def getDragMoveEvent(self, evt):
return self.getDragEnterEvent(evt)
def getDropEvent(self, evt):
return self.getDragEnterEvent(evt)
class TTkDropEvent(TTkDrag):
__slots__ = ('_pos', 'x', 'y')
def getDragMoveEvent(self, evt:TTkMouseEvent) -> TTkDnDEvent:
return self._toDropEvent((evt.x, evt.y))
def pos(self): return self._pos
def getDropEvent(self, evt:TTkMouseEvent) -> TTkDnDEvent:
return self._toDropEvent((evt.x, evt.y))

18
TermTk/TTkTemplates/dragevents.py

@ -23,58 +23,56 @@
__all__ = ['TDragEvents']
class TDragEvents():
def __init__(self) -> None: pass
def dragEnterEvent(self, evt) -> bool:
def dragEnterEvent(self, evt:"TTkDnDEvent") -> bool:
'''
This event handler, can be reimplemented in a subclass to receive drag events for the widget.
.. note:: Reimplement this function to handle this event
:param evt: The drop event
:type evt: :py:class:`TTkDropEvent`
:type evt: :py:class:`TTkDnDEvent`
:return: **True** if the event has been handled
:rtype: bool
'''
return False
def dragLeaveEvent(self, evt) -> bool:
def dragLeaveEvent(self, evt:"TTkDnDEvent") -> bool:
'''
This event handler, can be reimplemented in a subclass to receive drag events for the widget.
.. note:: Reimplement this function to handle this event
:param evt: The drop event
:type evt: :py:class:`TTkDropEvent`
:type evt: :py:class:`TTkDnDEvent`
:return: **True** if the event has been handled
:rtype: bool
'''
return False
def dragMoveEvent(self, evt) -> bool:
def dragMoveEvent(self, evt:"TTkDnDEvent") -> bool:
'''
This event handler, can be reimplemented in a subclass to receive drag events for the widget.
.. note:: Reimplement this function to handle this event
:param evt: The drop event
:type evt: :py:class:`TTkDropEvent`
:type evt: :py:class:`TTkDnDEvent`
:return: **True** if the event has been handled
:rtype: bool
'''
return False
def dropEvent(self, evt) -> bool:
def dropEvent(self, evt:"TTkDnDEvent") -> bool:
'''
This event handler, can be reimplemented in a subclass to receive drag events for the widget.
.. note:: Reimplement this function to handle this event
:param evt: The drop event
:type evt: :py:class:`TTkDropEvent`
:type evt: :py:class:`TTkDnDEvent`
:return: **True** if the event has been handled
:rtype: bool

19
TermTk/TTkWidgets/listwidget.py

@ -31,7 +31,10 @@ 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.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkGui.drag import TTkDrag, TTkDnDEvent
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
@ -79,7 +82,7 @@ class TTkAbstractListItem(TTkWidget):
self._data = data
self.update()
def mousePressEvent(self, evt) -> bool:
def mousePressEvent(self, evt:TTkMouseEvent) -> bool:
self.listItemClicked.emit(self)
return True
@ -363,7 +366,7 @@ class TTkListWidget(TTkAbstractScrollView):
elif index <= offy:
self.viewMoveTo(offx, index)
def mouseDragEvent(self, evt) -> bool:
def mouseDragEvent(self, evt:TTkMouseEvent) -> bool:
if not(self._dndMode & TTkK.DragDropMode.AllowDrag):
return False
if not (items:=self._selectedItems.copy()):
@ -388,26 +391,26 @@ class TTkListWidget(TTkAbstractScrollView):
drag.exec()
return True
def dragEnterEvent(self, evt):
def dragEnterEvent(self, evt:TTkDnDEvent) -> bool:
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):
def dragMoveEvent(self, evt:TTkDnDEvent) -> bool:
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):
def dragLeaveEvent(self, evt:TTkDnDEvent) -> bool:
self._dragPos = None
self.update()
return True
def dropEvent(self, evt) -> bool:
def dropEvent(self, evt:TTkDnDEvent) -> bool:
if not(self._dndMode & TTkK.DragDropMode.AllowDrop):
return False
self._dragPos = None
@ -424,7 +427,7 @@ class TTkListWidget(TTkAbstractScrollView):
return True
return False
def keyEvent(self, evt):
def keyEvent(self, evt:TTkKeyEvent) -> bool:
if not self._highlighted: return False
if ( evt.type == TTkK.Character and evt.key==" " ) or \
( evt.type == TTkK.SpecialKey and evt.key == TTkK.Key_Enter ):

32
TermTk/TTkWidgets/tabwidget.py

@ -29,14 +29,18 @@ from TermTk.TTkCore.cfg import TTkCfg
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.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkGui.drag import TTkDrag, TTkDnDEvent
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.spacer import TTkSpacer
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkWidgets.button import TTkButton
from TermTk.TTkWidgets.menubar import TTkMenuBarButton
from TermTk.TTkLayouts.boxlayout import TTkHBoxLayout
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
@ -102,11 +106,11 @@ class _TTkTabColorButton(TTkContainer):
def text(self) -> TTkString:
return self._text
def mouseReleaseEvent(self, evt):
def mouseReleaseEvent(self, evt:TTkMouseEvent) -> bool:
self.clicked.emit()
return True
def keyEvent(self, evt):
def keyEvent(self, evt:TTkKeyEvent) -> bool:
if ( evt.type == TTkK.Character and evt.key==" " ) or \
( evt.type == TTkK.SpecialKey and evt.key == TTkK.Key_Enter ):
self._keyPressed = True
@ -165,7 +169,7 @@ class TTkTabButton(_TTkTabColorButton):
# This is a hack to force the action aftet the keypress
# And not key release as normally happen to the button
def mousePressEvent(self, evt):
def mousePressEvent(self, evt:TTkMouseEvent) -> bool:
x,y = evt.x,evt.y
w,h = self.size()
self._closeButtonPressed = False
@ -176,7 +180,7 @@ class TTkTabButton(_TTkTabColorButton):
self._closeButtonPressed = True
return True
return super().mouseReleaseEvent(evt)
def mouseReleaseEvent(self, evt):
def mouseReleaseEvent(self, evt:TTkMouseEvent) -> bool:
x,y = evt.x,evt.y
w,h = self.size()
if self._closable and y == (1 if self._border else 0) and w-4<=x<w-1 and self._closeButtonPressed:
@ -185,7 +189,7 @@ class TTkTabButton(_TTkTabColorButton):
return True
self._closeButtonPressed = False
return False
def mouseDragEvent(self, evt) -> bool:
def mouseDragEvent(self, evt:TTkMouseEvent) -> bool:
drag = TTkDrag()
self._closeButtonPressed = False
if tb := self.parentWidget():
@ -266,11 +270,11 @@ class _TTkTabScrollerButton(_TTkTabColorButton):
# This is a hack to force the action aftet the keypress
# And not key release as normally happen to the button
def mousePressEvent(self, evt):
def mousePressEvent(self, evt:TTkMouseEvent) -> bool:
return super().mouseReleaseEvent(evt)
def mouseReleaseEvent(self, evt):
def mouseReleaseEvent(self, evt:TTkMouseEvent) -> bool:
return False
def mouseTapEvent(self, evt) -> bool:
def mouseTapEvent(self, evt:TTkMouseEvent) -> bool:
self.clicked.emit()
return True
@ -504,14 +508,14 @@ class TTkTabBar(TTkContainer):
self._highlighted = self._currentIndex
self._updateTabs()
def wheelEvent(self, evt):
def wheelEvent(self, evt:TTkMouseEvent) -> bool:
if evt.evt == TTkK.WHEEL_Up:
self._moveToTheLeft()
else:
self._andMoveToTheRight()
return True
def keyEvent(self, evt):
def keyEvent(self, evt:TTkKeyEvent) -> bool:
if evt.type == TTkK.SpecialKey:
if evt.key == TTkK.Key_Right:
self._highlighted = min(self._highlighted+1,len(self._tabButtons)-1)
@ -656,10 +660,10 @@ class TTkTabWidget(TTkFrame):
else:
widget.hide()
def keyEvent(self, evt) -> bool:
def keyEvent(self, evt:TTkKeyEvent) -> bool:
return self._tabBar.keyEvent(evt)
def dropEvent(self, evt) -> bool:
def dropEvent(self, evt:TTkDnDEvent) -> bool:
data = evt.data()
x, y = evt.x, evt.y
if not issubclass(type (data),_TTkTabWidgetDragData):

31
demo/showcase/dragndrop.py

@ -31,8 +31,8 @@ sys.path.append(os.path.join(sys.path[0],'../..'))
import TermTk as ttk
class DragThing(ttk.TTkFrame):
def __init__(self, *args, **kwargs):
ttk.TTkFrame.__init__(self, *args, **kwargs)
def __init__(self, **kwargs):
ttk.TTkFrame.__init__(self, **kwargs)
# Define and place 4 images with different Hue Color rotation
ttk.TTkImage(parent=self, pos=( 0, 0), data=ttk.TTkAbout.peppered, rasteriser=ttk.TTkImage.QUADBLOCK)
ttk.TTkImage(parent=self, pos=( 0,10), data=ttk.TTkAbout.peppered, rasteriser=ttk.TTkImage.QUADBLOCK).rotHue(60)
@ -41,22 +41,23 @@ class DragThing(ttk.TTkFrame):
self.setMaximumWidth(30)
self.setMinimumWidth(30)
def mouseDragEvent(self, evt) -> bool:
ttk.TTkLog.debug("Start DnD")
drag = ttk.TTkDrag()
data = ttk.TTkImage(data=ttk.TTkAbout.peppered, rasteriser=ttk.TTkImage.QUADBLOCK)
# Change color if the drag start over the side images,
# based on the same Hue rotation defined in the init
if evt.x <= 15 and evt.y > 10: data.rotHue(60)
elif evt.x > 15 and evt.y <= 10: data.rotHue(90)
elif evt.x > 15 and evt.y > 10: data.rotHue(200)
drag.setPixmap(data)
drag.setData(data)
drag.exec()
def mouseDragEvent(self, evt:ttk.TTkMouseEvent) -> bool:
if evt.key == ttk. TTkMouseEvent.LeftButton:
ttk.TTkLog.debug("Start DnD")
drag = ttk.TTkDrag()
data = ttk.TTkImage(data=ttk.TTkAbout.peppered, rasteriser=ttk.TTkImage.QUADBLOCK)
# Change color if the drag start over the side images,
# based on the same Hue rotation defined in the init
if evt.x <= 15 and evt.y > 10: data.rotHue(60)
elif evt.x > 15 and evt.y <= 10: data.rotHue(90)
elif evt.x > 15 and evt.y > 10: data.rotHue(200)
drag.setPixmap(data)
drag.setData(data)
drag.exec()
return True
class DropThings(ttk.TTkFrame):
def dropEvent(self, evt) -> bool:
def dropEvent(self, evt:ttk.TTkDnDEvent) -> bool:
ttk.TTkLog.debug(f"Drop ({self.title()}) -> pos={evt.pos()}")
data = evt.data()
if issubclass(type(data),ttk.TTkWidget):

29
tests/t.ui/test.ui.017.Drag.Drop.001.py

@ -28,26 +28,37 @@ sys.path.append(os.path.join(sys.path[0],'../..'))
import TermTk as ttk
class DragDrop(ttk.TTkFrame):
def mouseDragEvent(self, evt) -> bool:
ttk.TTkLog.debug("Start DnD")
drag = ttk.TTkDrag()
drag.setData(f"Test Drag ({self.title()})")
drag.exec()
def mouseDragEvent(self, evt:ttk. TTkMouseEvent) -> bool:
if evt.key == ttk. TTkMouseEvent.LeftButton:
ttk.TTkLog.debug("Start Left DnD")
drag = ttk.TTkDrag()
drag.setData(f"Test Drag ({self.title()})")
drag.exec()
elif evt.key == ttk. TTkMouseEvent.RightButton:
ttk.TTkLog.debug("Start Right DnD")
drag = ttk.TTkDrag()
drag.setData(f"Test Drag ({self.title()})")
drag.exec()
elif evt.key == ttk. TTkMouseEvent.MidButton:
ttk.TTkLog.debug("Start Middle DnD")
drag = ttk.TTkDrag()
drag.setData(f"Test Drag ({self.title()})")
drag.exec()
return True
def dragEnterEvent(self, evt) -> bool:
def dragEnterEvent(self, evt:ttk.TTkDnDEvent) -> bool:
ttk.TTkLog.debug(f"Drag Enter ({self.title()}) -> {evt.data()}, pos={evt.pos()}")
return True
def dragLeaveEvent(self, evt) -> bool:
def dragLeaveEvent(self, evt:ttk.TTkDnDEvent) -> bool:
ttk.TTkLog.debug(f"Drag Leave ({self.title()}) -> {evt.data()}, pos={evt.pos()}")
return True
def dragMoveEvent(self, evt) -> bool:
def dragMoveEvent(self, evt:ttk.TTkDnDEvent) -> bool:
ttk.TTkLog.debug(f"Drag Move ({self.title()}) -> {evt.data()}, pos={evt.pos()}")
return True
def dropEvent(self, evt) -> bool:
def dropEvent(self, evt:ttk.TTkDnDEvent) -> bool:
ttk.TTkLog.debug(f"Drop ({self.title()}) -> {evt.data()}, pos={evt.pos()}")
return True

Loading…
Cancel
Save