Skip to content

Commit

Permalink
Documented the Drag and Drop and added a bunch of examples and fixed …
Browse files Browse the repository at this point in the history
…its handling and improved the logging
  • Loading branch information
ceccopierangiolieugenio committed Jan 3, 2025
1 parent 5c7a656 commit 2f8c05f
Show file tree
Hide file tree
Showing 18 changed files with 1,141 additions and 126 deletions.
9 changes: 9 additions & 0 deletions TermTk/TTkCore/TTkTerm/inputmouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ def __init__(self, x: int, y: int, key: int, evt: int, mod: int, tap: int, raw:
self.mod = mod
self.raw = raw
self.tap = tap

def pos(self) -> tuple[int,int]:
'''
Returns the position of the mouse cursor relative to the current widget.
:return: the position.
:rtype: tuple[int,int]
'''
return (self.x, self.y)

def clone(self, pos=None, evt=None):
x,y = pos or (self.x, self.y)
Expand Down
5 changes: 3 additions & 2 deletions TermTk/TTkCore/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ def _process_msg(mode: int, msg: str):
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe,1)
if len(calframe) > 2:
ctx = _TTkContext(calframe[2])
cb(mode, ctx, msg)
ctx = _TTkContext(calframe[2])
for txt in str(msg).split('\n'):
cb(mode, ctx, txt)

@staticmethod
def debug(msg):
Expand Down
2 changes: 2 additions & 0 deletions TermTk/TTkTemplates/dragevents.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def dragLeaveEvent(self, evt:TTkDnDEvent) -> bool:
.. note:: Reimplement this function to handle this event
.. note:: This event is triggered only if :py:meth:`TDragEvents.dragEnterEvent` or :py:meth:`TDragEvents.dragMoveEvent` were previously handled inside this widget.
:param evt: The drop event
:type evt: :py:class:`TTkDnDEvent`
Expand Down
103 changes: 2 additions & 101 deletions TermTk/TTkWidgets/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,107 +292,8 @@ def _mouseEventLayoutHandle(evt, layout):
return True
return False

_mouseOver = None
_mouseOverTmp = None
_mouseOverProcessed = False
def mouseEvent(self, evt: TTkMouseEvent) -> bool:
''' .. caution:: Don't touch this! '''
if not self._enabled: return False

# Saving self in this global variable
# So that after the "_mouseEventLayoutHandle"
# this tmp value will hold the last widget below the mouse
TTkWidget._mouseOverTmp = self

# Mouse Drag has priority because it
# should be handled by the focused widget and
# not pushed to the unfocused childs
# unless there is a Drag and Drop event ongoing
if evt.evt == TTkK.Drag and not TTkHelper.isDnD():
if self.mouseDragEvent(evt):
return True

if self.rootLayout() is not None:
if TTkContainer._mouseEventLayoutHandle(evt, self.rootLayout()):
return True

# If there is an overlay and it is modal,
# return False if this widget is not part of any
# of the widgets above the modal
if not TTkHelper.checkModalOverlay(self):
return False

# Handle Drag and Drop Events
if TTkHelper.isDnD():
ret = False
if evt.evt == TTkK.Drag:
dndw = TTkHelper.dndWidget()
if dndw == self:
if self.dragMoveEvent(TTkHelper.dndGetDrag().getDragMoveEvent(evt)):
return True
else:
if self.dragEnterEvent(TTkHelper.dndGetDrag().getDragEnterEvent(evt)):
if dndw:
ret = dndw.dragLeaveEvent(TTkHelper.dndGetDrag().getDragLeaveEvent(evt))
TTkHelper.dndEnter(self)
return True
if evt.evt == TTkK.Release:
if self.dropEvent(TTkHelper.dndGetDrag().getDropEvent(evt)):
return True
return ret

# handle Enter/Leave Events
# _mouseOverTmp hold the top widget under the mouse
# if different than self it means that it is a child
if evt.evt == TTkK.Move:
if not TTkWidget._mouseOverProcessed:
if TTkWidget._mouseOver != TTkWidget._mouseOverTmp == self:
if TTkWidget._mouseOver:
# TTkLog.debug(f"Leave: {TTkWidget._mouseOver._name}")
TTkWidget._mouseOver.leaveEvent(evt)
TTkWidget._mouseOver = self
# TTkLog.debug(f"Enter: {TTkWidget._mouseOver._name}")
TTkHelper.toolTipClose()
if self._toolTip and self._toolTip != '':
TTkHelper.toolTipTrigger(self._toolTip)
# TTkHelper.triggerToolTip(self._name)
TTkWidget._mouseOver.enterEvent(evt)
TTkWidget._mouseOverProcessed = True
if self.mouseMoveEvent(evt):
return True
else:
TTkHelper.toolTipClose()

if evt.evt == TTkK.Release:
self._pendingMouseRelease = False
self._processStyleEvent(TTkWidget._S_NONE)
if self.mouseReleaseEvent(evt):
return True

if evt.evt == TTkK.Press:
# in case of parent focus, check the parent that can accept the focus
w = self
while w._parent and (w.focusPolicy() & TTkK.ParentFocus) == TTkK.ParentFocus:
w = w._parent
if w.focusPolicy() & TTkK.ClickFocus == TTkK.ClickFocus:
w.setFocus()
w.raiseWidget()
self._processStyleEvent(TTkWidget._S_PRESSED)
if evt.tap == 2 and self.mouseDoubleClickEvent(evt):
#self._pendingMouseRelease = True
return True
if evt.tap > 1 and self.mouseTapEvent(evt):
return True
if evt.tap == 1 and self.mousePressEvent(evt):
# TTkLog.debug(f"Click {self._name}")
self._pendingMouseRelease = True
return True

if evt.key == TTkK.Wheel:
if self.wheelEvent(evt):
return True

return False
def _mouseEventParseChildren(self, evt:TTkMouseEvent) -> bool:
return TTkContainer._mouseEventLayoutHandle(evt, self.rootLayout())

def setLayout(self, layout:TTkLayout) -> None:
'''
Expand Down
13 changes: 10 additions & 3 deletions TermTk/TTkWidgets/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ def pasteEvent(self, txt:str) -> None:
'''
return False

def _mouseEventParseChildren(self, evt:TTkMouseEvent) -> bool:
return False

_mouseOver = None
_mouseOverTmp = None
_mouseOverProcessed = False
Expand All @@ -416,6 +419,9 @@ def mouseEvent(self, evt:TTkMouseEvent) -> bool:
# if TTkWidget._mouseEventLayoutHandle(evt, self.rootLayout()):
# return True

if self._mouseEventParseChildren(evt):
return True

# If there is an overlay and it is modal,
# return False if this widget is not part of any
# of the widgets above the modal
Expand All @@ -428,10 +434,11 @@ def mouseEvent(self, evt:TTkMouseEvent) -> bool:
if evt.evt == TTkK.Drag:
dndw = TTkHelper.dndWidget()
if dndw == self:
if self.dragMoveEvent(TTkHelper.dndGetDrag().getDragMoveEvent(evt)):
return True
self.dragMoveEvent(TTkHelper.dndGetDrag().getDragMoveEvent(evt))
return True
else:
if self.dragEnterEvent(TTkHelper.dndGetDrag().getDragEnterEvent(evt)):
if ( self.dragEnterEvent(TTkHelper.dndGetDrag().getDragEnterEvent(evt)) or
self.dragMoveEvent(TTkHelper.dndGetDrag().getDragMoveEvent(evt))):
if dndw:
ret = dndw.dragLeaveEvent(TTkHelper.dndGetDrag().getDragLeaveEvent(evt))
TTkHelper.dndEnter(self)
Expand Down
5 changes: 4 additions & 1 deletion demo/showcase/dragndrop.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ def dropEvent(self, evt:ttk.TTkDnDEvent) -> bool:
data = evt.data()
if issubclass(type(data),ttk.TTkWidget):
self.layout().addWidget(data)
data.move(evt.x,evt.y)
# Since the frame by default has a padding of 1
# I align the button to the mouse coordinates by subtracting the Top/Left padding size
t,b,l,r = self.getPadding()
data.move(evt.x-l, evt.y-t)
self.update()
return True
return False
Expand Down
Loading

0 comments on commit 2f8c05f

Please sign in to comment.