From b1fbb248d4622f58b3cb0893fc5cfb5604d95316 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sat, 20 Mar 2021 17:40:03 +0000 Subject: [PATCH] Basic SpinBox --- README.md | 7 +++ TermTk/TTkWidgets/__init__.py | 1 + TermTk/TTkWidgets/lineedit.py | 8 +-- TermTk/TTkWidgets/spinbox.py | 98 +++++++++++++++++++++++++++++++++++ TermTk/TTkWidgets/window.py | 1 + demo/demo.py | 1 - demo/showcase/formwidgets.py | 5 ++ docs/TODO.md | 6 ++- 8 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 TermTk/TTkWidgets/spinbox.py diff --git a/README.md b/README.md index 941816d5..4e2d43f8 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,13 @@ and inspired by a mix of [Qt5](https://www.riverbankcomputing.com/static/Docs/Py ## Limitations - Only the key combinations forwarded by the terminal emulator used are detected (ALT,CTRL may not be handled) +## Try +Works better on [repl.it](https://repl.it/@EugenioP/pyTermTk) + +But you can try it here: +(the console has some terminal size issues, better to run on the **shell** `python3 demo/demo.py -f`) + + ## [Tutorial](tutorial) Be inspired by the [tutorial examples](https://github.com/ceccopierangiolieugenio/pyTermTk/tree/main/tutorial) diff --git a/TermTk/TTkWidgets/__init__.py b/TermTk/TTkWidgets/__init__.py index 380f971d..80464243 100644 --- a/TermTk/TTkWidgets/__init__.py +++ b/TermTk/TTkWidgets/__init__.py @@ -24,3 +24,4 @@ from .treewidget import * from .graph import * from .menubar import * from .TTkPickers import * +from .spinbox import * diff --git a/TermTk/TTkWidgets/lineedit.py b/TermTk/TTkWidgets/lineedit.py index 770cdd41..a8408202 100644 --- a/TermTk/TTkWidgets/lineedit.py +++ b/TermTk/TTkWidgets/lineedit.py @@ -51,7 +51,7 @@ class TTkLineEdit(TTkWidget): self._inputType = kwargs.get('inputType' , TTkK.Input_Text ) self._text = kwargs.get('text' , '' ) if self._inputType & TTkK.Input_Number and\ - not self._text.isdigit(): self._text = "" + not self._text.lstrip('-').isdigit(): self._text = "" self._offset = 0 self._cursorPos = 0 self._replace=False @@ -134,9 +134,6 @@ class TTkLineEdit(TTkWidget): if evt.key == TTkK.Key_Enter: self.returnPressed.emit() else: - if self._inputType & TTkK.Input_Number and \ - not evt.key.isdigit(): - return text = self._text pre = text[:self._cursorPos] if self._replace: @@ -145,6 +142,9 @@ class TTkLineEdit(TTkWidget): post = text[self._cursorPos:] text = pre + evt.key + post + if self._inputType & TTkK.Input_Number and \ + not text.lstrip('-').isdigit(): + return self.setText(text) self._cursorPos += 1 # Scroll to the right if reached the edge diff --git a/TermTk/TTkWidgets/spinbox.py b/TermTk/TTkWidgets/spinbox.py new file mode 100644 index 00000000..57dfd162 --- /dev/null +++ b/TermTk/TTkWidgets/spinbox.py @@ -0,0 +1,98 @@ +#!/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. + +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.cfg import TTkCfg +from TermTk.TTkCore.log import TTkLog +from TermTk.TTkCore.helper import TTkHelper +from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal +from TermTk.TTkCore.color import TTkColor +from TermTk.TTkLayouts import TTkGridLayout +from TermTk.TTkWidgets.widget import TTkWidget +from TermTk.TTkWidgets.lineedit import TTkLineEdit + +class TTkSpinBox(TTkWidget): + __slots__= ('_lineEdit', '_value', '_maximum', '_minimum', '_mouseDelta', '_valueDelta', '_draggable') + def __init__(self, *args, **kwargs): + TTkWidget.__init__(self, *args, **kwargs) + self._name = kwargs.get('name' , 'TTkSpinBox' ) + self._value = kwargs.get("value",0) + self._maximum = kwargs.get("maximum",99) + self._minimum = kwargs.get("minimum",0) + self.setLayout(TTkGridLayout()) + self.setPadding(0,0,0,2) + self.setMinimumSize(4,1) + self._mouseDelta = 0 + self._valueDelta = 0 + self._draggable = False + self._lineEdit = TTkLineEdit(parent=self, text=str(self._value), inputType=TTkK.Input_Number) + self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus) + self._lineEdit.textEdited.connect(self._textEdited) + + def value(self): + return self._value + + def setValue(val): + self._value = value + + @pyTTkSlot(str) + def _textEdited(self, text): + self._value = int(text) + self._value = min(self._value,self._maximum) + self._value = max(self._value,self._minimum) + self._lineEdit.setText(str(self._value)) + + def mousePressEvent(self, evt): + x,y = evt.x, evt.y + w = self.width() + self._draggable = False + if x==w-2: + self._draggable = True + self._value += 1 + if x==w-1: + self._draggable = True + self._value -= 1 + self._value = min(self._value,self._maximum) + self._value = max(self._value,self._minimum) + self._lineEdit.setText(str(self._value)) + self._mouseDelta = y + self._valueDelta = self._value + return True + + def mouseDragEvent(self, evt): + y = evt.y + if self._draggable: + self._value = self._valueDelta + self._mouseDelta - y + self._value = min(self._value,self._maximum) + self._value = max(self._value,self._minimum) + self._lineEdit.setText(str(self._value)) + return True + + def paintEvent(self): + w = self.width() + self._canvas.drawChar(pos=(w-2,0),char="▲") + self._canvas.drawChar(pos=(w-1,0),char="▼") + + def focusOutEvent(self): + self._draggable = False \ No newline at end of file diff --git a/TermTk/TTkWidgets/window.py b/TermTk/TTkWidgets/window.py index 385edad2..99a7e98e 100644 --- a/TermTk/TTkWidgets/window.py +++ b/TermTk/TTkWidgets/window.py @@ -79,6 +79,7 @@ class TTkWindow(TTkResizableFrame): self.update() def focusOutEvent(self): + self._draggable = False if self._menubarTop: self._menubarTop.setBorderColor(TTkColor.RST) self.update() \ No newline at end of file diff --git a/demo/demo.py b/demo/demo.py index 8670870d..c9953de2 100755 --- a/demo/demo.py +++ b/demo/demo.py @@ -66,7 +66,6 @@ def demoShowcase(root=None, border=True): tabWidget1.addTab(demoTab(), " Tab Test ") tabWidget1.addTab(demoScrollArea(), " Scroll Area ") - return tabWidget1 def main(): diff --git a/demo/showcase/formwidgets.py b/demo/showcase/formwidgets.py index 007d1d90..fbe6982f 100755 --- a/demo/showcase/formwidgets.py +++ b/demo/showcase/formwidgets.py @@ -71,6 +71,11 @@ def demoFormWidgets(root=None): row += 1; win_form1_grid_layout.addWidget(ttk.TTkLabel(text='Line Edit Number Password'),row,0) win_form1_grid_layout.addWidget(ttk.TTkLineEdit(text='Password', inputType=ttk.TTkK.Input_Password+ttk.TTkK.Input_Number),row,2) + row += 1; win_form1_grid_layout.addWidget(ttk.TTkLabel(text='Spinbox (default [0,99])'),row,0) + win_form1_grid_layout.addWidget(ttk.TTkSpinBox(),row,2) + row += 1; win_form1_grid_layout.addWidget(ttk.TTkLabel(text='Spinbox (-20, [-50,+50])'),row,0) + win_form1_grid_layout.addWidget(ttk.TTkSpinBox(value=-20, maximum=50, minimum=-50),row,2) + row += 1; win_form1_grid_layout.addWidget(ttk.TTkLabel(text='Checkbox'),row,0) win_form1_grid_layout.addWidget(ttk.TTkCheckbox(),row,2) row += 1; win_form1_grid_layout.addWidget(ttk.TTkLabel(text='Checkbox Checked'),row,0) diff --git a/docs/TODO.md b/docs/TODO.md index 273420d2..2f744244 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -122,7 +122,7 @@ - [ ] Add Menu - [ ] Keyboard events #### Spin Box - - [ ] Basic Implementation + - [x] Basic Implementation - [ ] Events (Signal/Slots) - [ ] Themes #### Progress Bar @@ -148,3 +148,7 @@ - [ ] Basic Implementation - [ ] Events (Signal/Slots) - [ ] Themes +#### Yes/No Ok/Cancel Picker + - [ ] Basic Implementation + - [ ] Events (Signal/Slots) + - [ ] Themes