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