From a4dda2488c3af8927479bd4c3d3041b192a58334 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Mon, 19 Dec 2022 22:44:53 +0000 Subject: [PATCH 1/4] Fix ColorPicker colortext parsing --- TermTk/TTkWidgets/TTkPickers/colorpicker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TermTk/TTkWidgets/TTkPickers/colorpicker.py b/TermTk/TTkWidgets/TTkPickers/colorpicker.py index e26a0b2d..ad43daba 100644 --- a/TermTk/TTkWidgets/TTkPickers/colorpicker.py +++ b/TermTk/TTkWidgets/TTkPickers/colorpicker.py @@ -308,8 +308,8 @@ class TTkColorDialogPicker(TTkWindow,TColor): @pyTTkSlot() def _leHTMLChanged(): text = leHTML.text() - if re.match('#[a-f0-9]{6}', text.lower()): - _controlSetRGBColor(int(text[1:], 16)) + if re.match('#[a-f0-9]{6}', str(text).lower()): + _controlSetRGBColor(int(str(text)[1:], 16)) leHTML.returnPressed.connect(_leHTMLChanged) From a4b9ae93d0c63496d8d9ed7ee743ef9dc4b8ff3d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 20 Dec 2022 00:26:57 +0000 Subject: [PATCH 2/4] Added Window Flags --- TermTk/TTkCore/canvas.py | 12 +-- TermTk/TTkCore/constant.py | 16 ++-- TermTk/TTkCore/helper.py | 10 +-- TermTk/TTkWidgets/TTkPickers/colorpicker.py | 2 +- TermTk/TTkWidgets/TTkPickers/filepicker.py | 4 +- TermTk/TTkWidgets/widget.py | 24 ++---- TermTk/TTkWidgets/window.py | 89 ++++++++++++++++++--- demo/demo.py | 8 +- demo/showcase/windowsflags.py | 86 ++++++++++++++++++++ 9 files changed, 197 insertions(+), 54 deletions(-) create mode 100755 demo/showcase/windowsflags.py diff --git a/TermTk/TTkCore/canvas.py b/TermTk/TTkCore/canvas.py index 3172906a..3896eaf6 100644 --- a/TermTk/TTkCore/canvas.py +++ b/TermTk/TTkCore/canvas.py @@ -192,10 +192,10 @@ class TTkCanvas: else: self._colors[y][x+i] = colors[i].mod(x+i,y) # Check the full wide chars on the edge of the two canvasses - if self._data[y][x+a] == '': + if 0 <= (x+a) < self._width and self._data[y][x+a] == '': self._data[y][x+a] = TTkCfg.theme.unicodeWideOverflowCh[0] self._colors[y][x+a] = TTkCfg.theme.unicodeWideOverflowColor - if TTkString._isWideCharData(self._data[y][x+b-1]): + if 0 <= (x+b-1) < self._width and TTkString._isWideCharData(self._data[y][x+b-1]): self._data[y][x+b-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y][x+b-1] = TTkCfg.theme.unicodeWideOverflowColor @@ -614,16 +614,16 @@ class TTkCanvas: self._colors[y+iy][a:b] = canvas._colors[iy][xoffset:wslice] # Check the full wide chars on the edge of the two canvasses - if self._data[y+iy][a]=='': + if 0 <= a < self._width and self._data[y+iy][a]=='': self._data[y+iy][a] = TTkCfg.theme.unicodeWideOverflowCh[0] self._colors[y+iy][a] = TTkCfg.theme.unicodeWideOverflowColor - if TTkString._isWideCharData(self._data[y+iy][b-1]): + if 0 < b <= self._width and TTkString._isWideCharData(self._data[y+iy][b-1]): self._data[y+iy][b-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y+iy][b-1] = TTkCfg.theme.unicodeWideOverflowColor - if TTkString._isWideCharData(self._data[y+iy][a-1]): + if 0 < a <= self._width and TTkString._isWideCharData(self._data[y+iy][a-1]): self._data[y+iy][a-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y+iy][a-1] = TTkCfg.theme.unicodeWideOverflowColor - if ( b +# +# 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. + +import sys, os + +sys.path.append(os.path.join(sys.path[0],'../../tmp')) +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + + +class WindowFlagsTest(ttk.TTkWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + rb = ttk.TTkCheckbox( + parent=self, pos=(0,0), size=(20,1), text='Reduce Button', + checked=bool(self.windowFlag()&ttk.TTkK.WindowFlag.WindowReduceButtonHint)) + minb = ttk.TTkCheckbox( + parent=self, pos=(0,1), size=(20,1), text='Minimize Button', + checked=bool(self.windowFlag()&ttk.TTkK.WindowFlag.WindowMinimizeButtonHint)) + maxb = ttk.TTkCheckbox( + parent=self, pos=(0,2), size=(20,1), text='Maximize Button', + checked=bool(self.windowFlag()&ttk.TTkK.WindowFlag.WindowMaximizeButtonHint)) + cb = ttk.TTkCheckbox( + parent=self, pos=(0,3), size=(20,1), text='Close Button', + checked=bool(self.windowFlag()&ttk.TTkK.WindowFlag.WindowCloseButtonHint)) + + def _cbStateChanged(state,field): + if state==ttk.TTkK.Checked: + self.setWindowFlag(self.windowFlag()|field) + else: + self.setWindowFlag(self.windowFlag()&(~field)) + + rb.stateChanged.connect( lambda x: _cbStateChanged(x,ttk.TTkK.WindowFlag.WindowReduceButtonHint)) + minb.stateChanged.connect(lambda x: _cbStateChanged(x,ttk.TTkK.WindowFlag.WindowMinimizeButtonHint)) + maxb.stateChanged.connect(lambda x: _cbStateChanged(x,ttk.TTkK.WindowFlag.WindowMaximizeButtonHint)) + cb.stateChanged.connect( lambda x: _cbStateChanged(x,ttk.TTkK.WindowFlag.WindowCloseButtonHint)) + + + +def demoWindowsFlags(root=None): + frame = ttk.TTkFrame(parent=root, border=False) + + WindowFlagsTest(parent=frame, pos = (0,0), size=(40,8), title="Test Window 1") + WindowFlagsTest(parent=frame, pos = (2,2), size=(40,8), title="Test Window 2", + flags = ttk.TTkK.WindowFlag.WindowMaximizeButtonHint | ttk.TTkK.WindowFlag.WindowCloseButtonHint) + WindowFlagsTest(parent=frame, pos = (4,4), size=(40,8), title="Test Window 3", + flags = ttk.TTkK.NONE) + WindowFlagsTest(parent=frame, pos = (6,6), size=(40,8), title="Test Window 4", + flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) + WindowFlagsTest(parent=frame, pos = (8,8), size=(40,8), title="Test Window 5", + flags = ttk.TTkK.WindowFlag.WindowReduceButtonHint) + + return frame + + + +def main(): + ttk.TTkLog.use_default_file_logging() + root = ttk.TTk() + win1 = ttk.TTkWindow(parent=root,pos = (1,1), size=(60,30), title="Test Window Flags", border=True, layout=ttk.TTkGridLayout(), flags=ttk.TTkK.NONE) + demoWindowsFlags(win1) + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file From a181ce067666ef27fdb6c2f4e01f846bd85f3b0c Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 20 Dec 2022 00:33:07 +0000 Subject: [PATCH 3/4] Added edemo comments --- demo/showcase/windowsflags.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/demo/showcase/windowsflags.py b/demo/showcase/windowsflags.py index dc3aedda..254050c2 100755 --- a/demo/showcase/windowsflags.py +++ b/demo/showcase/windowsflags.py @@ -28,7 +28,7 @@ sys.path.append(os.path.join(sys.path[0],'../../tmp')) sys.path.append(os.path.join(sys.path[0],'../..')) import TermTk as ttk - +# Testing Window with a checkbox to enable/disable any control button class WindowFlagsTest(ttk.TTkWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -45,6 +45,7 @@ class WindowFlagsTest(ttk.TTkWindow): parent=self, pos=(0,3), size=(20,1), text='Close Button', checked=bool(self.windowFlag()&ttk.TTkK.WindowFlag.WindowCloseButtonHint)) + # Set the window flag/field based on the checkbox state def _cbStateChanged(state,field): if state==ttk.TTkK.Checked: self.setWindowFlag(self.windowFlag()|field) @@ -61,13 +62,18 @@ class WindowFlagsTest(ttk.TTkWindow): def demoWindowsFlags(root=None): frame = ttk.TTkFrame(parent=root, border=False) + # Standard window (the close button is enabled by default) WindowFlagsTest(parent=frame, pos = (0,0), size=(40,8), title="Test Window 1") + # Enable Max anc Close button WindowFlagsTest(parent=frame, pos = (2,2), size=(40,8), title="Test Window 2", flags = ttk.TTkK.WindowFlag.WindowMaximizeButtonHint | ttk.TTkK.WindowFlag.WindowCloseButtonHint) + # Disable all the control buttons WindowFlagsTest(parent=frame, pos = (4,4), size=(40,8), title="Test Window 3", flags = ttk.TTkK.NONE) + # Enable only the Max and Min Buttons WindowFlagsTest(parent=frame, pos = (6,6), size=(40,8), title="Test Window 4", flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) + # Enable only the Minimize button WindowFlagsTest(parent=frame, pos = (8,8), size=(40,8), title="Test Window 5", flags = ttk.TTkK.WindowFlag.WindowReduceButtonHint) From 18546049725e4eb4e06ca071795f3d7ab939f23d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 20 Dec 2022 10:01:53 +0000 Subject: [PATCH 4/4] Fix canvas corner case failure --- Makefile | 2 +- TermTk/TTkCore/canvas.py | 25 ++++++++++--------------- tests/pytest/test_001_demo.py | 11 +++++++++++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index ac6fbdbf..d5faff06 100644 --- a/Makefile +++ b/Makefile @@ -97,5 +97,5 @@ test: .venv flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude .venv,build,tmp ; \ pytest tests/pytest/test_003_string.py ; \ pytest tests/pytest/test_002_textedit.py ; \ - pytest tests/pytest/test_001_demo.py ; + pytest -v tests/pytest/test_001_demo.py ; diff --git a/TermTk/TTkCore/canvas.py b/TermTk/TTkCore/canvas.py index 3896eaf6..a0b45667 100644 --- a/TermTk/TTkCore/canvas.py +++ b/TermTk/TTkCore/canvas.py @@ -192,10 +192,10 @@ class TTkCanvas: else: self._colors[y][x+i] = colors[i].mod(x+i,y) # Check the full wide chars on the edge of the two canvasses - if 0 <= (x+a) < self._width and self._data[y][x+a] == '': + if ((0 <= (x+a) < self._width) and self._data[y][x+a] == ''): self._data[y][x+a] = TTkCfg.theme.unicodeWideOverflowCh[0] self._colors[y][x+a] = TTkCfg.theme.unicodeWideOverflowColor - if 0 <= (x+b-1) < self._width and TTkString._isWideCharData(self._data[y][x+b-1]): + if ((0 <= (x+b-1) < self._width) and TTkString._isWideCharData(self._data[y][x+b-1])): self._data[y][x+b-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y][x+b-1] = TTkCfg.theme.unicodeWideOverflowColor @@ -598,15 +598,10 @@ class TTkCanvas: w = min(w,self._width-x) h = min(h,self._height-y) - # if x>=self._width: x=self._width-1 - # if y>=self._height: y=self._height-1 - # if w>=self._width-x: w=self._width-x - # if h>=self._height-y: h=self._height-y - - xoffset = 0 if x>=bx else bx-x - yoffset = 0 if y>=by else by-y - wslice = w if x+w < bx+bw else bx+bw-x - hslice = h if y+h < by+bh else by+bh-y + xoffset = min(max(0,bx-x),canvas._width-1) + yoffset = min(max(0,by-y),canvas._height-1) + wslice = min(w if x+w < bx+bw else bx+bw-x,canvas._width) + hslice = min(h if y+h < by+bh else by+bh-y,canvas._height) for iy in range(yoffset,hslice): a, b = x+xoffset, x+wslice @@ -614,16 +609,16 @@ class TTkCanvas: self._colors[y+iy][a:b] = canvas._colors[iy][xoffset:wslice] # Check the full wide chars on the edge of the two canvasses - if 0 <= a < self._width and self._data[y+iy][a]=='': + if ((0 <= a < self._width) and self._data[y+iy][a]==''): self._data[y+iy][a] = TTkCfg.theme.unicodeWideOverflowCh[0] self._colors[y+iy][a] = TTkCfg.theme.unicodeWideOverflowColor - if 0 < b <= self._width and TTkString._isWideCharData(self._data[y+iy][b-1]): + if ((0 < b <= self._width) and TTkString._isWideCharData(self._data[y+iy][b-1])): self._data[y+iy][b-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y+iy][b-1] = TTkCfg.theme.unicodeWideOverflowColor - if 0 < a <= self._width and TTkString._isWideCharData(self._data[y+iy][a-1]): + if ((0 < a <= self._width) and TTkString._isWideCharData(self._data[y+iy][a-1])): self._data[y+iy][a-1] = TTkCfg.theme.unicodeWideOverflowCh[1] self._colors[y+iy][a-1] = TTkCfg.theme.unicodeWideOverflowColor - if 0 <= b < self._width and self._data[y+iy][b]=='': + if ((0 <= b < self._width) and self._data[y+iy][b]==''): self._data[y+iy][b] = TTkCfg.theme.unicodeWideOverflowCh[0] self._colors[y+iy][b] = TTkCfg.theme.unicodeWideOverflowColor diff --git a/tests/pytest/test_001_demo.py b/tests/pytest/test_001_demo.py index d5428f06..37b99768 100755 --- a/tests/pytest/test_001_demo.py +++ b/tests/pytest/test_001_demo.py @@ -153,7 +153,18 @@ def test_demo(): assert demo.demoShowcase(root) != None root.quit() +def message_handler(mode, context, message): + msgType = "NONE" + if mode == demo.ttk.TTkLog.InfoMsg: msgType = "[INFO]" + elif mode == demo.ttk.TTkLog.WarningMsg: msgType = "[WARNING]" + elif mode == demo.ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]" + elif mode == demo.ttk.TTkLog.FatalMsg: msgType = "[FATAL]" + elif mode == demo.ttk.TTkLog.ErrorMsg: msgType = "[ERROR]" + print(f"{msgType} {context.file} {message}") + def test_recording1(): + # demo.ttk.TTkLog.use_default_file_logging() + demo.ttk.TTkLog.installMessageHandler(message_handler) root = TTkRecord(title="pyTermTk Demo Record", record=False) root.loadQueue(open('tmp/test.input.bin', 'rb')) winTabbed1 = demo.ttk.TTkWindow(parent=root,pos=(0,0), size=(80,24), title="pyTermTk Showcase", border=True, layout=demo.ttk.TTkGridLayout())