diff --git a/Makefile b/Makefile index 1b4a8451..9bc6681c 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,13 @@ pip install -r docs/requirements.txt # Add "Signal" option in the method domains patch -p3 -d .venv/lib/python3*/ < docs/sphynx.001.signal.patch + # Update/Regen + # # Docs + # pip install sphinx sphinx-epytext sphinx-autodocgen sphinx-rtd-theme + # # Test + # pip install flake8 pytest + # # Build + # pip install build twine # Regen requirements; # pip freeze > docs/requirements.txt diff --git a/TermTk/TTkCore/draw.py b/TermTk/TTkCore/draw.py deleted file mode 100644 index f6922bfc..00000000 --- a/TermTk/TTkCore/draw.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -# MIT License -# -# Copyright (c) 2021 Eugenio Parodi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - diff --git a/TermTk/TTkCore/ttk.py b/TermTk/TTkCore/ttk.py index ae70458b..a84e84da 100644 --- a/TermTk/TTkCore/ttk.py +++ b/TermTk/TTkCore/ttk.py @@ -45,6 +45,7 @@ class TTk(TTkWidget): '_events', '_key_events', '_mouse_events', '_screen_events', '_title', '_sigmask', + '_lastMultiTap', #Signals 'eventKeyPress', 'eventMouse' ) @@ -114,7 +115,7 @@ class TTk(TTkWidget): self._running = True # Keep track of the multiTap to avoid the extra key release - lastMultiTap = False + self._lastMultiTap = False TTkTerm.init(title=self._title, sigmask=self._sigmask) self._mainloop() #except Exception as e: @@ -128,77 +129,9 @@ class TTk(TTkWidget): # Main Loop evt = self._events.get() if evt is TTkK.MOUSE_EVENT: - mevt = self._mouse_events.get() - self.eventMouse.emit(mevt) - - # Upload the global mouse position - # Mainly used by the drag pixmap display - TTkHelper.setMousePos((mevt.x,mevt.y)) - - # Avoid to broadcast a key release after a multitap event - if mevt.evt == TTkK.Release and lastMultiTap: continue - lastMultiTap = mevt.tap > 1 - - if ( TTkHelper.isDnD() and - mevt.evt != TTkK.Drag and - mevt.evt != TTkK.Release ): - # Clean Drag Drop status for any event that is not - # Mouse Drag, Key Release - TTkHelper.dndEnd() - - # Mouse Events forwarded straight to the Focus widget: - # - Drag - # - Move - # - Release - focusWidget = TTkHelper.getFocus() - if ( focusWidget is not None and - mevt.evt != TTkK.Press and - mevt.key != TTkK.Wheel and - not TTkHelper.isDnD() ) : - x,y = TTkHelper.absPos(focusWidget) - nmevt = mevt.clone(pos=(mevt.x-x, mevt.y-y)) - focusWidget.mouseEvent(nmevt) - else: - # Sometimes the release event is not retrieved - if ( focusWidget and - focusWidget._pendingMouseRelease and - not TTkHelper.isDnD() ): - focusWidget.mouseEvent(nmevt.clone(evt=TTkK.Release)) - focusWidget._pendingMouseRelease = False - # Adding this Crappy logic to handle a corner case in the drop routine - # where the mouse is leaving any widget able to handle the drop event - if not self.mouseEvent(mevt): - if dndw := TTkHelper.dndWidget(): - dndw.dragLeaveEvent(TTkHelper.dndGetDrag().getDragLeaveEvent(mevt)) - TTkHelper.dndEnter(None) - if mevt.evt == TTkK.Press and focusWidget: - focusWidget.clearFocus() - - # Clean the Drag and Drop in case of mouse release - if mevt.evt == TTkK.Release: - TTkHelper.dndEnd() + self._mouse_event() elif evt is TTkK.KEY_EVENT: - keyHandled = False - kevt = self._key_events.get() - self.eventKeyPress.emit(kevt) - # TTkLog.debug(f"Key: {kevt}") - focusWidget = TTkHelper.getFocus() - # TTkLog.debug(f"{focusWidget}") - if focusWidget is not None: - TTkHelper.execShortcut(kevt.key,focusWidget) - keyHandled = focusWidget.keyEvent(kevt) - else: - TTkHelper.execShortcut(kevt.key) - # Handle Next Focus Key Binding - if not keyHandled and \ - ((kevt.key == TTkK.Key_Tab and kevt.mod == TTkK.NoModifier) or - ( kevt.key == TTkK.Key_Right )): - TTkHelper.nextFocus(focusWidget if focusWidget else self) - # Handle Prev Focus Key Binding - if not keyHandled and \ - ((kevt.key == TTkK.Key_Tab and kevt.mod == TTkK.ShiftModifier) or - ( kevt.key == TTkK.Key_Left )): - TTkHelper.prevFocus(focusWidget if focusWidget else self) + self._key_event() elif evt is TTkK.TIME_EVENT: size = os.get_terminal_size() self.setGeometry(0,0,size.columns,size.lines) @@ -216,6 +149,79 @@ class TTk(TTkWidget): TTkLog.error(f"Unhandled Event {evt}") break + def _mouse_event(self): + mevt = self._mouse_events.get() + self.eventMouse.emit(mevt) + # Upload the global mouse position + # Mainly used by the drag pixmap display + TTkHelper.setMousePos((mevt.x,mevt.y)) + + # Avoid to broadcast a key release after a multitap event + if mevt.evt == TTkK.Release and self._lastMultiTap: return + self._lastMultiTap = mevt.tap > 1 + + if ( TTkHelper.isDnD() and + mevt.evt != TTkK.Drag and + mevt.evt != TTkK.Release ): + # Clean Drag Drop status for any event that is not + # Mouse Drag, Key Release + TTkHelper.dndEnd() + + # Mouse Events forwarded straight to the Focus widget: + # - Drag + # - Move + # - Release + focusWidget = TTkHelper.getFocus() + if ( focusWidget is not None and + mevt.evt != TTkK.Press and + mevt.key != TTkK.Wheel and + not TTkHelper.isDnD() ) : + x,y = TTkHelper.absPos(focusWidget) + nmevt = mevt.clone(pos=(mevt.x-x, mevt.y-y)) + focusWidget.mouseEvent(nmevt) + else: + # Sometimes the release event is not retrieved + if ( focusWidget and + focusWidget._pendingMouseRelease and + not TTkHelper.isDnD() ): + focusWidget.mouseEvent(mevt.clone(evt=TTkK.Release)) + focusWidget._pendingMouseRelease = False + # Adding this Crappy logic to handle a corner case in the drop routine + # where the mouse is leaving any widget able to handle the drop event + if not self.mouseEvent(mevt): + if dndw := TTkHelper.dndWidget(): + dndw.dragLeaveEvent(TTkHelper.dndGetDrag().getDragLeaveEvent(mevt)) + TTkHelper.dndEnter(None) + if mevt.evt == TTkK.Press and focusWidget: + focusWidget.clearFocus() + + # Clean the Drag and Drop in case of mouse release + if mevt.evt == TTkK.Release: + TTkHelper.dndEnd() + + def _key_event(self): + kevt = self._key_events.get() + self.eventKeyPress.emit(kevt) + keyHandled = False + # TTkLog.debug(f"Key: {kevt}") + focusWidget = TTkHelper.getFocus() + # TTkLog.debug(f"{focusWidget}") + if focusWidget is not None: + TTkHelper.execShortcut(kevt.key,focusWidget) + keyHandled = focusWidget.keyEvent(kevt) + else: + TTkHelper.execShortcut(kevt.key) + # Handle Next Focus Key Binding + if not keyHandled and \ + ((kevt.key == TTkK.Key_Tab and kevt.mod == TTkK.NoModifier) or + ( kevt.key == TTkK.Key_Right or kevt.key == TTkK.Key_Down)): + TTkHelper.nextFocus(focusWidget if focusWidget else self) + # Handle Prev Focus Key Binding + if not keyHandled and \ + ((kevt.key == TTkK.Key_Tab and kevt.mod == TTkK.ShiftModifier) or + ( kevt.key == TTkK.Key_Left or kevt.key == TTkK.Key_Up)): + TTkHelper.prevFocus(focusWidget if focusWidget else self) + def _time_event(self): self._events.put(TTkK.TIME_EVENT) @@ -238,9 +244,6 @@ class TTk(TTkWidget): self._input.get_key(_inputCallback) self._input.close() - def _canvas_thread(self): - pass - def quit(self): '''Tells the application to exit with a return code.''' self._events.put(TTkK.QUIT_EVENT) diff --git a/TermTk/TTkWidgets/button.py b/TermTk/TTkWidgets/button.py index 45a46edd..f19aea5f 100644 --- a/TermTk/TTkWidgets/button.py +++ b/TermTk/TTkWidgets/button.py @@ -222,7 +222,7 @@ class TTkButton(TTkWidget): if self._border: self._canvas.drawButtonBox(pos=(0,0),size=(self._width,self._height),color=borderColor, grid=grid) for i in range(1,h-1): - self._canvas.drawText(pos=(1,i) ,text=" "*w) + self._canvas.drawText(pos=(1,i) ,text=TTkString(" "*w, textColor)) self._canvas.drawText(pos=(1,y) ,text=text) else: self._canvas.drawText(pos=(1,1) ,text=text)