From 286d71aa4e297b4a48626cdb3314c69d2e53b431 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Fri, 11 Aug 2023 19:03:35 +0100 Subject: [PATCH 01/11] Added amiga workbench tmux prototype --- multiplexers/basic/main.py | 82 ++++++++++++ multiplexers/workbench/eumigo.ansi | 22 ++++ multiplexers/workbench/eumigo.txt | 53 ++++++++ multiplexers/workbench/main.py | 92 +++++++++++++ multiplexers/workbench/wblib/__init__.py | 5 + multiplexers/workbench/wblib/colors.py | 46 +++++++ multiplexers/workbench/wblib/iconbutton.py | 45 +++++++ multiplexers/workbench/wblib/loader.py | 112 ++++++++++++++++ multiplexers/workbench/wblib/scrollbar.py | 44 +++++++ multiplexers/workbench/wblib/theme.py | 32 +++++ multiplexers/workbench/wblib/window.py | 146 +++++++++++++++++++++ 11 files changed, 679 insertions(+) create mode 100644 multiplexers/basic/main.py create mode 100644 multiplexers/workbench/eumigo.ansi create mode 100644 multiplexers/workbench/eumigo.txt create mode 100755 multiplexers/workbench/main.py create mode 100644 multiplexers/workbench/wblib/__init__.py create mode 100644 multiplexers/workbench/wblib/colors.py create mode 100644 multiplexers/workbench/wblib/iconbutton.py create mode 100644 multiplexers/workbench/wblib/loader.py create mode 100644 multiplexers/workbench/wblib/scrollbar.py create mode 100644 multiplexers/workbench/wblib/theme.py create mode 100644 multiplexers/workbench/wblib/window.py diff --git a/multiplexers/basic/main.py b/multiplexers/basic/main.py new file mode 100644 index 00000000..ae3eb7ee --- /dev/null +++ b/multiplexers/basic/main.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2023 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. + +import os +import pty +import sys +import threading +import argparse +from select import select + +sys.path.append(os.path.join(sys.path[0],'..')) +import TermTk as ttk + +parser = argparse.ArgumentParser() +parser.add_argument('-d', help='Debug (Add LogViewer Panel)', action='store_true') +args = parser.parse_args() + +# ttk.TTkLog.use_default_file_logging() +root = ttk.TTk(layout=ttk.TTkGridLayout()) + +split = ttk.TTkSplitter(parent=root, orientation=ttk.TTkK.VERTICAL) + +split.addItem(top := ttk.TTkLayout()) + +if args.d: + split.addWidget(ttk.TTkLogViewer(follow=False ), title='Log', size=20) + +quitBtn = ttk.TTkButton(text="QUIT", border=True) +quitBtn.clicked.connect(ttk.TTkHelper.quit) + +cb_c = ttk.TTkCheckbox(pos=(0,3),size=(20,1), text="CTRL-C (VINTR) ", checked=ttk.TTkK.Checked) +cb_s = ttk.TTkCheckbox(pos=(0,4),size=(20,1), text="CTRL-S (VSTOP) ", checked=ttk.TTkK.Checked) +cb_z = ttk.TTkCheckbox(pos=(0,5),size=(20,1), text="CTRL-Z (VSUSP) ", checked=ttk.TTkK.Checked) +cb_q = ttk.TTkCheckbox(pos=(0,6),size=(20,1), text="CTRL-Q (VSTART)", checked=ttk.TTkK.Checked) + +cb_c.stateChanged.connect(lambda x: ttk.TTkTerm.setSigmask(ttk.TTkTerm.Sigmask.CTRL_C,x==ttk.TTkK.Checked)) +cb_s.stateChanged.connect(lambda x: ttk.TTkTerm.setSigmask(ttk.TTkTerm.Sigmask.CTRL_S,x==ttk.TTkK.Checked)) +cb_z.stateChanged.connect(lambda x: ttk.TTkTerm.setSigmask(ttk.TTkTerm.Sigmask.CTRL_Z,x==ttk.TTkK.Checked)) +cb_q.stateChanged.connect(lambda x: ttk.TTkTerm.setSigmask(ttk.TTkTerm.Sigmask.CTRL_Q,x==ttk.TTkK.Checked)) + +win1 = ttk.TTkWindow(pos=(90,5), size=(70,15), title="Terminallo n.1", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) +term1 = ttk.TTkTerminal(parent=win1) +term1.runShell() + +win2 = ttk.TTkWindow(pos=(0,0), size=(150,30), title="Terminallo n.2", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) +term2 = ttk.TTkTerminal(parent=win2) +term2.runShell() + +win3 = ttk.TTkWindow(pos=(92,8), size=(70,15), title="Terminallo n.3", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) +term3 = ttk.TTkTerminal(parent=win3) +term3.runShell() + +win4 = ttk.TTkWindow(pos=(94,11), size=(70,15), title="Terminallo n.4", border=True, layout=ttk.TTkVBoxLayout(), flags = ttk.TTkK.WindowFlag.WindowMinMaxButtonsHint) +term4 = ttk.TTkTerminal(parent=win4) +term4.runShell() + +top.addWidgets([quitBtn, cb_c, cb_s, cb_z, cb_q, win1, win2, win3, win4]) + +term2.setFocus() + +root.mainloop() \ No newline at end of file diff --git a/multiplexers/workbench/eumigo.ansi b/multiplexers/workbench/eumigo.ansi new file mode 100644 index 00000000..8d0b12e9 --- /dev/null +++ b/multiplexers/workbench/eumigo.ansi @@ -0,0 +1,22 @@ + ▛▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄🬿  + ▛▜  ▌▌    ▀▀▀▀▀    🭢🭕🭏🬼 + ▛▌▝▀▜▜▌▌           🭥🭌 + ▌▙▖▐▝▜▌     ▀▀▀      + ▛▀▘▝▘▄▄▟▀▄▀▀▀▀▜  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀    +  ▛▀▀▀▘▄▀▀▀▄▖▀▄▄▄▄▄▖▀▜   + ▛▀▄▄▄▄▛▚▄▟▟▙▙▙▞▜▌▛▛▘▄▟   + ▌▟▝▀▀▌▟▐▝▀▀▀▀▘▌▞▀▛▄▟   + ▌▌▐▀▀▀▌▐▝▀▀▀▀▀▀▘▌▀▐▟   + ▙▛▀▀▀▌▐▀▜▀▀▀▀▀▛▌▛▐ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄    + ▙▌▗▐▐▙▝▀▀▀▀▀▀▀▌▗▌▐  ▀▄ █ ██ █ ▖ █ █ ▝▀▀▄ ██     + ▙▄▖▐▐▙▟▐▐▄▄▄▌▙▟▌▖▖▜ ▗▛█ ██ █ █ █ ▗▄█ █▀▀█ ██     +  ▀▀▀▀▙▖▐▐▐▙▐▐▗▄▄▌▐▌▌▌▌▜▝▘ █ ██ ▝▀▝▀▀ ▀▀ ▀ ▀▀ ██     +▛▛▀▛▀▀▀▀▀▌▐▐▐▐▙▝▐▄▖▌▟▌▌▌▌▐▟ ██ ██     +▛▘▛▛▀▀▀▀▀▘▖▐▐▐▐▌▐▗▌▌▟▌▌▌▌▐ ████████ ███████ █   + ▌▌▌▌▌▌▌▀▀▌▐▐▐▐▌▐▐▌▌▜▌▌▌▌▐     +▙▙▙▙▙▖▌▌▌▖▙▌▐▐▐▜▐▐▙▌▐▌▌▌▌▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▙▄▄▄▄▄▄▄▄▄▌▐▐▜▀▐▐▄▌▐▘▌▌▌▐▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟ +  ▙▄▙▄▄▄▄▄▌▐▐▀▛▐▐▀▌▛▘▌▌▌▐▐▗▄▄ 🭖🭩🭡 🭇▖ ▖▖  +  ▄▄▄▄▄▙▖▜▀▌▐▀▀▘▘▀▀▀▗▟▟▟ 🭦█🭛 ▌● ▞▖  +  ▙▄▄▄▙▄▄▄▄▄▄▄▄▄▄▄▟▟▟  +  ▙▄▄▄▄▄▄▄▄▄▄▄▄▟  \ No newline at end of file diff --git a/multiplexers/workbench/eumigo.txt b/multiplexers/workbench/eumigo.txt new file mode 100644 index 00000000..ac4a14f3 --- /dev/null +++ b/multiplexers/workbench/eumigo.txt @@ -0,0 +1,53 @@ + + + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄🬿 + █ █ ▄▄▄▄ █ 🭢🭕🭏🬼 + █ █ █ █ █ 🭥🭌 + █ █ █▄▄█ █ █ + █ █▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█ █ + █ █ + █ █ + █ █ + █ █ + █ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ █ + █ █ █ █ + █ █ █ █ + █ █ █ █ + █ █ █ █ + █ █ █ █ + █ █ █ █ + █ █ █ █ + █▄▄▄▄▄█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█▄▄▄▄█ + + 🭖🭏🭡 🭖🭩🭡 🭇▖ ▖▖ + 🭤🭓🭛 🭦█🭛 ▌● ▞▖ + + 🭇🬼 + 🭃🭌 ▄🬿 + 🭥🭒█ 🭢🭕🭏🬼 + 🭋🭍🭑🬽🭢🭕 🭥🭌 🬿 + 🭅███🭀 🭥🭒🭒█🭏🬼 🭒 +🭋██🭥██🭐 🭢🭕█🭌🬿 + + + 🭇🬼 🭇 __X__ 🬼 🬼 X + 🭃🭌🬿 🭃 🭌🬿 🭌 🬿 X + 🭥🭒█🭏🬼 🭥🭒 🭏🬼 🭏 🬼 X + 🭋🭍🭑🬽🭢🭕█🭌🬿 🭋🭍🭑🬽 🭢🭕 🭌🬿 🭌 🬿 X + 🭅███🭀 🭥🭒█🭏🬼 🭅███🭀 🭥🭒 🭏🬼 🭏 🬼 X +🭋████🭐 🭢🭕█🭌🬿 🭋████🭐 🭢🭕 🭌🬿 🭌 🬿 X + + + + 🬼 🭇 🭗 🭢 + 🬽 🭈 🭘 🭣 + 🬾 🭉 🭙 🭤 + 🬿 🭊 🭚 🭥 + 🭀 🭋 🭛 🭦 + 🭌 🭁 🭝 🭒 + 🭍 🭂 🭞 🭓 + 🭎 🭃 🭟 🭔 + 🭏 🭄 🭠 🭕 + 🭐 🭅 🭡 🭖 + 🭑 🭆 🭜 🭧 + diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py new file mode 100755 index 00000000..e40ecabc --- /dev/null +++ b/multiplexers/workbench/main.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2023 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. + +import os +import pty +import sys +import threading +import argparse +from select import select + + +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + +from TermTk.TTkCore.canvas import TTkCanvas + +from wblib import * + +# parser = argparse.ArgumentParser() +# parser.add_argument('-d', help='Debug (Add LogViewer Panel)', action='store_true') +# args = parser.parse_args() + +# class WBWindow(ttk.TTkWindow): + +class WorkBench(ttk.TTkWidget): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setPadding(1,0,0,0) + def paintEvent(self, canvas: TTkCanvas): + w,h = self.size() + canvas.fill(color=bgBLUE) + # draw the title + canvas.drawText( + text=" pyTermTk Workbench. Version 1.0 plenty of free memory", + width=w, + color=bgWHITE+fgBLUE) + + canvas.drawText( + text="│◪│◩│", + pos=(w-5,0), + color=bgWHITE+fgBLUE) + +class TTkWorkbench(ttk.TTk): + def paintEvent(self, canvas: TTkCanvas): + canvas.fill(color=bgBLUE) + +root = TTkWorkbench(layout=ttk.TTkGridLayout()) +root.setPadding(3,3,15,10) + +wbl = WBLoader(size=root.size()) +root.rootLayout().addWidget(wbl) + +wb = WorkBench(parent=root) + +win2 = WBWindow(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench",) + + +win3 = WBWindow(parent=wb, pos=(15,10), size=(70,25), + wbbg=bgBLACK+fgWHITE, + title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) +term3 = ttk.TTkTerminal(parent=win3) +term3.runShell() + +win1 = WBWindow(parent=wb, pos=(10,5), size=(60,20), + wbbg=bgBLACK+fgWHITE, + title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) +term1 = ttk.TTkTerminal(parent=win1) +term1.runShell() + + +root.mainloop() \ No newline at end of file diff --git a/multiplexers/workbench/wblib/__init__.py b/multiplexers/workbench/wblib/__init__.py new file mode 100644 index 00000000..ae7e8e15 --- /dev/null +++ b/multiplexers/workbench/wblib/__init__.py @@ -0,0 +1,5 @@ +from .colors import * +from .window import * +from .scrollbar import * +from .iconbutton import * +from .loader import * \ No newline at end of file diff --git a/multiplexers/workbench/wblib/colors.py b/multiplexers/workbench/wblib/colors.py new file mode 100644 index 00000000..804afa3b --- /dev/null +++ b/multiplexers/workbench/wblib/colors.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2023 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. + +import os +import sys + +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + +# Colors: +# Blue: 0055aa +# Orange: ff8800 + +__all__ = [ + 'fgBLUE','fgORANGE','fgBLACK','fgWHITE', + 'bgBLUE','bgORANGE','bgBLACK','bgWHITE'] + +fgBLUE = ttk.TTkColor.fg('#0055aa') +fgORANGE = ttk.TTkColor.fg('#0055aa') +fgBLACK = ttk.TTkColor.fg('#000000') +fgWHITE = ttk.TTkColor.fg('#ffffff') +bgBLUE = ttk.TTkColor.bg('#0055aa') +bgORANGE = ttk.TTkColor.bg('#0055aa') +bgBLACK = ttk.TTkColor.bg('#000000') +bgWHITE = ttk.TTkColor.bg('#ffffff') diff --git a/multiplexers/workbench/wblib/iconbutton.py b/multiplexers/workbench/wblib/iconbutton.py new file mode 100644 index 00000000..7ecd39c7 --- /dev/null +++ b/multiplexers/workbench/wblib/iconbutton.py @@ -0,0 +1,45 @@ +# 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.signal import pyTTkSlot, pyTTkSignal +from TermTk.TTkCore.color import TTkColor +from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkWidgets.widget import TTkWidget +from TermTk.TTkWidgets.scrollbar import TTkScrollBar + +from .colors import * + +__all__ = ['WBIconButton'] + +class WBIconButton(TTkWidget): + __slots__ = ('_text') + def __init__(self, text="", **kwargs): + self._text = text + super().__init__(**kwargs) + self.getCanvas().setTransparent(True) + self.resize(len(text),3) + + def paintEvent(self, canvas: TTkCanvas): + canvas.drawText(text="-----", pos=(0,0)) + canvas.drawText(text="-----", pos=(0,1)) + canvas.drawText(text=self._text, pos=(0,2)) \ No newline at end of file diff --git a/multiplexers/workbench/wblib/loader.py b/multiplexers/workbench/wblib/loader.py new file mode 100644 index 00000000..d052aa8e --- /dev/null +++ b/multiplexers/workbench/wblib/loader.py @@ -0,0 +1,112 @@ +# 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 import TTkUtil, TTkWidget, TTkLabel, TTkCanvas + +from .colors import * + +__all__ = ['WBLoader'] + +class WBLoader(TTkWidget): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # ANSII dumb.image.tool.py + data = TTkUtil.base64_deflate_2_obj( + "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") + + w,h = self.size() + l = TTkLabel(parent=self, text=data) + lw,lh = l.size() + l.move((w-lw)//2,(h-lh)//2) + + # + # ▀▄ █ ██ █ ▖ █ █ ▝▀▀▄ ██ + # ▗▛█ ██ █ █ █ ▗▄█ █▀▀█ ██ + # ▝▘ █ ██ ▝▀▝▀▀ ▀▀ ▀ ▀▀ ██ + # ██ ██ + # ████████ ████████ + # + # + # ████████╗ ████████╗ + # ╚══██╔══╝ ╚══██╔══╝ + # ██║ ▄▄ ▄ ▄▄ ▄▄▖▄▖ ██║ █ ▗▖ + # ▞▀▚ ▖▗ ██║ █▄▄█ █▀▘ █ █ █ ██║ █▟▘ + # ▙▄▞▐▄▟ ██║ ▀▄▄▖ █ █ ▝ █ ██║ █ ▀▄ + # ▌ ▐ ╚═╝ ╚═╝ + # ▚▄▄▘ + + def mouseReleaseEvent(self, evt) -> bool: + self.close() + return True + + def paintEvent(self, canvas: TTkCanvas): + canvas.fill(color=bgWHITE) \ No newline at end of file diff --git a/multiplexers/workbench/wblib/scrollbar.py b/multiplexers/workbench/wblib/scrollbar.py new file mode 100644 index 00000000..7e0b7849 --- /dev/null +++ b/multiplexers/workbench/wblib/scrollbar.py @@ -0,0 +1,44 @@ +# 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.signal import pyTTkSlot, pyTTkSignal +from TermTk.TTkCore.color import TTkColor +from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkWidgets.widget import TTkWidget +from TermTk.TTkWidgets.scrollbar import TTkScrollBar + +import wblib.theme as draw_custom +from TermTk.TTkTheme.theme import TTkTheme + +from .colors import * + +__all__ = ['WBScrollBar'] + +CUSTOM_THEME = TTkTheme.NERD | {'draw':draw_custom} + +TTkTheme.loadTheme( CUSTOM_THEME ) + +class WBScrollBar(TTkScrollBar): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._color = self._focusColor = fgBLUE+bgWHITE diff --git a/multiplexers/workbench/wblib/theme.py b/multiplexers/workbench/wblib/theme.py new file mode 100644 index 00000000..e20e1f1e --- /dev/null +++ b/multiplexers/workbench/wblib/theme.py @@ -0,0 +1,32 @@ +# 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.TTkTheme.theme import TTkTheme + +class TTkTheme(TTkTheme.NERD['draw'].TTkTheme): + # hscroll = ('←','┄','▓','→') + # vscroll = ('↑','┊','▓','↓') + # hscroll = ('<','┄','░','>') + # vscroll = ('∆','┊','░','∇') + hscroll = ('<','┄','⣿','>') + vscroll = ('∆','┊','⣿','∇') \ No newline at end of file diff --git a/multiplexers/workbench/wblib/window.py b/multiplexers/workbench/wblib/window.py new file mode 100644 index 00000000..f9266bb0 --- /dev/null +++ b/multiplexers/workbench/wblib/window.py @@ -0,0 +1,146 @@ +# 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.cfg import TTkCfg +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.color import TTkColor +from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkLayouts import TTkGridLayout, TTkLayout +from TermTk.TTkWidgets.button import TTkButton +from TermTk.TTkWidgets.resizableframe import TTkResizableFrame + +from .colors import * +from .scrollbar import * + +__all__ = ['WBWindow'] + + +class _MinimizedButton(TTkButton): + __slots__ = ('_windowWidget') + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._windowWidget = kwargs.get('windowWidget') + def _cb(): + self._windowWidget.show() + self.close() + self.clicked.connect(_cb) + +class WBWindow(TTkResizableFrame): + '''TTkWindow''' + __slots__ = ( + '_title', '_mouseDelta', '_draggable', + '_btnClose', '_btnMax', '_btnMin', '_btnReduce', + '_flags', '_winTopLayout', + '_sbRight', '_sbBottom', + '_maxBk', '_redBk', + '_wbbg') + def __init__(self, wbbg=fgWHITE+bgBLUE, *args, **kwargs): + self._winTopLayout = TTkGridLayout() + self._wbbg = wbbg + super().__init__(*args, **kwargs) + self._flags = TTkK.NONE + self.setPadding(1,1,1,1) + self._mouseDelta = (0,0) + self.setFocusPolicy(TTkK.ClickFocus) + self._draggable = False + self._sbRight = WBScrollBar(orientation=TTkK.VERTICAL) + self._sbBottom = WBScrollBar(orientation=TTkK.HORIZONTAL) + self._sbRight.setPageStep(60) + self._sbRight.setRange(0, 100) + self._sbBottom.setPageStep(60) + self._sbBottom.setRange(0, 100) + self.rootLayout().addWidgets([self._sbRight,self._sbBottom]) + w,h = self.size() + self._sbRight.setGeometry( w-1, 1, 1, h-2) + self._sbBottom.setGeometry( 0 , h-1, w-1, 1 ) + + def resizeEvent(self, w, h): + self._maxBk = None + self._redBk = None + self._winTopLayout.setGeometry(1,1,w-2,1) + self._sbRight.setGeometry( w-1, 1, 1, h-2) + self._sbBottom.setGeometry( 0 , h-1, w-1, 1 ) + super().resizeEvent(w,h) + + def mousePressEvent(self, evt): + self._mouseDelta = (evt.x, evt.y) + self._draggable = False + w,_ = self.size() + x,y = evt.x, evt.y + # If the mouse position is inside the header box enable the dragging feature + if y==0 and 1<=xw-4: + self.lowerWidget() + return True + self._draggable = True + return True + return TTkResizableFrame.mousePressEvent(self, evt) + + def mouseDragEvent(self, evt): + if self._draggable: + x,y = self.pos() + dx = evt.x-self._mouseDelta[0] + dy = evt.y-self._mouseDelta[1] + self.move(x+dx, y+dy) + return True + return TTkResizableFrame.mouseDragEvent(self, evt) + + def focusInEvent(self): + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.fg("#ffff55")) + self.update() + + def focusOutEvent(self): + self._draggable = False + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.RST) + self.update() + + def paintEvent(self, canvas=TTkCanvas): + if self.hasFocus(): + color = TTkCfg.theme.windowBorderColorFocus + titleChar = '☰' + else: + color = TTkCfg.theme.windowBorderColor + # titleChar = '☷' + titleChar = '⚏' + + w,h = self.size() + + + canvas.fill(color=bgBLUE) + canvas.fill(char='▎',pos=(0,1), size=(1,h-2), color=self._wbbg) + # draw the title ┃ │ + canvas.drawText( + text=f"│▣│ {self._title} {titleChar*w}", + # text=f"│⚀│ {self._title} {titleChar*w}", + color=bgWHITE+fgBLUE) + + canvas.drawText( + text="│◪│◩│", + pos=(w-5,0), + color=bgWHITE+fgBLUE) + + canvas.drawChar(pos=(w-1,h-1),char='⇱',color=fgBLUE+bgWHITE) \ No newline at end of file From d4a3374b77d37368a57c724434ccf09f9d09661d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Mon, 21 Aug 2023 17:46:19 +0100 Subject: [PATCH 02/11] added keypressview in the workbench --- multiplexers/workbench/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index e40ecabc..ede9b2ee 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -88,5 +88,10 @@ win1 = WBWindow(parent=wb, pos=(10,5), size=(60,20), term1 = ttk.TTkTerminal(parent=win1) term1.runShell() +wink = WBWindow(parent=wb, pos=(10,30), size=(70,6), + wbbg=bgBLACK+fgWHITE, + title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) +ttk.TTkKeyPressView(parent=wink) + root.mainloop() \ No newline at end of file From 41f13bed4743acf3067d0937593f0812f19976bd Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Fri, 1 Sep 2023 10:30:58 +0100 Subject: [PATCH 03/11] adapted main to the new conteiner widget --- multiplexers/workbench/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index ede9b2ee..2eca5641 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -43,7 +43,7 @@ from wblib import * # class WBWindow(ttk.TTkWindow): -class WorkBench(ttk.TTkWidget): +class WorkBench(ttk.TTkContainer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setPadding(1,0,0,0) From fb5e394b125be0b933125d925f72484bb34ed660 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Fri, 8 Sep 2023 16:00:26 +0100 Subject: [PATCH 04/11] improved the workench and adapted to the new style --- multiplexers/workbench/main.py | 39 +++++++------- multiplexers/workbench/wblib/colors.py | 5 +- multiplexers/workbench/wblib/iconbutton.py | 42 ++++++++++++--- multiplexers/workbench/wblib/loader.py | 19 ++++--- multiplexers/workbench/wblib/window.py | 59 +++++++++++++++------- 5 files changed, 109 insertions(+), 55 deletions(-) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index 2eca5641..2ae7ef2b 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -65,7 +65,7 @@ class TTkWorkbench(ttk.TTk): def paintEvent(self, canvas: TTkCanvas): canvas.fill(color=bgBLUE) -root = TTkWorkbench(layout=ttk.TTkGridLayout()) +root = TTkWorkbench(layout=ttk.TTkGridLayout(), mouseTrack=True) root.setPadding(3,3,15,10) wbl = WBLoader(size=root.size()) @@ -73,25 +73,22 @@ root.rootLayout().addWidget(wbl) wb = WorkBench(parent=root) -win2 = WBWindow(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench",) - - -win3 = WBWindow(parent=wb, pos=(15,10), size=(70,25), - wbbg=bgBLACK+fgWHITE, - title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) -term3 = ttk.TTkTerminal(parent=win3) -term3.runShell() - -win1 = WBWindow(parent=wb, pos=(10,5), size=(60,20), - wbbg=bgBLACK+fgWHITE, - title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) -term1 = ttk.TTkTerminal(parent=win1) -term1.runShell() - -wink = WBWindow(parent=wb, pos=(10,30), size=(70,6), - wbbg=bgBLACK+fgWHITE, - title="Terminallo n.1",layout=ttk.TTkVBoxLayout()) -ttk.TTkKeyPressView(parent=wink) - +ttk.pyTTkSlot() +def _openTerminal(term=[]): + _x,_y = 15,5 + while (_x,_y) in [_t['pos'] for _t in term]: + _x += 4 + _y += 2 + _win = WBWindow(parent=wb, pos=(_x,_y), size=(60,20), + whiteBg=False, + title=f"Terminallo n.{len(term)+1}",layout=ttk.TTkVBoxLayout()) + _term = ttk.TTkTerminal(parent=_win) + _term.runShell() + _term.bell.connect(lambda : ttk.TTkLog.debug("BELL!!! 🔔🔔🔔")) + _term.titleChanged.connect(_win.setTitle) + term.append({'pos':(_x,_y),'term':_term,'win':_win}) + +winWb = WBWindow(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench") +WBIconButton(parent=winWb, text="Terminal").clicked.connect(_openTerminal) root.mainloop() \ No newline at end of file diff --git a/multiplexers/workbench/wblib/colors.py b/multiplexers/workbench/wblib/colors.py index 804afa3b..b5f9ab7a 100644 --- a/multiplexers/workbench/wblib/colors.py +++ b/multiplexers/workbench/wblib/colors.py @@ -37,10 +37,11 @@ __all__ = [ 'bgBLUE','bgORANGE','bgBLACK','bgWHITE'] fgBLUE = ttk.TTkColor.fg('#0055aa') -fgORANGE = ttk.TTkColor.fg('#0055aa') +fgORANGE = ttk.TTkColor.fg('#ff8800') fgBLACK = ttk.TTkColor.fg('#000000') fgWHITE = ttk.TTkColor.fg('#ffffff') + bgBLUE = ttk.TTkColor.bg('#0055aa') -bgORANGE = ttk.TTkColor.bg('#0055aa') +bgORANGE = ttk.TTkColor.bg('#ff8800') bgBLACK = ttk.TTkColor.bg('#000000') bgWHITE = ttk.TTkColor.bg('#ffffff') diff --git a/multiplexers/workbench/wblib/iconbutton.py b/multiplexers/workbench/wblib/iconbutton.py index 7ecd39c7..a81909f1 100644 --- a/multiplexers/workbench/wblib/iconbutton.py +++ b/multiplexers/workbench/wblib/iconbutton.py @@ -24,6 +24,7 @@ from TermTk.TTkCore.constant import TTkK from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal from TermTk.TTkCore.color import TTkColor from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkCore.string import TTkString from TermTk.TTkWidgets.widget import TTkWidget from TermTk.TTkWidgets.scrollbar import TTkScrollBar @@ -32,14 +33,43 @@ from .colors import * __all__ = ['WBIconButton'] class WBIconButton(TTkWidget): - __slots__ = ('_text') - def __init__(self, text="", **kwargs): + IconTerminal = 0x01 + + _iconS = { IconTerminal: [ + # TTkString("🬦" "🬹🬹🬹🬹🬹🬹" "🬓"), + TTkString("▗" "▄▄▄▄▄▄" "▖"), + TTkString("▐")+ TTkString(" C:\ ",fgORANGE+bgWHITE+TTkColor.BOLD)+ TTkString("▌",fgWHITE+bgBLACK), + TTkString("🬉")+ TTkString("🬎🬎🬎🬎🬎🬎", fgWHITE+bgBLACK)+ TTkString("🬄",fgWHITE+bgBLACK)] + # TTkString("┌──────┐"), + # TTkString("│ C:\ │"), + # TTkString("└──────┘")] + } + + classStyle = { + 'default': {'color': fgWHITE+bgBLUE}, + 'disabled': {'color': fgWHITE+bgBLUE}, + 'focus': {'color': fgWHITE+bgBLUE}, + 'clicked': {'color': fgWHITE+bgBLACK}, + } + + __slots__ = ('_text', '_icon', 'clicked') + def __init__(self, text="", icon=IconTerminal, **kwargs): + self.clicked = pyTTkSignal() self._text = text + self._icon = WBIconButton._iconS[icon] super().__init__(**kwargs) self.getCanvas().setTransparent(True) - self.resize(len(text),3) + self.resize(len(text),len(self._icon)+1) + + def mouseDoubleClickEvent(self, evt) -> bool: + self.clicked.emit() + return True def paintEvent(self, canvas: TTkCanvas): - canvas.drawText(text="-----", pos=(0,0)) - canvas.drawText(text="-----", pos=(0,1)) - canvas.drawText(text=self._text, pos=(0,2)) \ No newline at end of file + style = self.currentStyle() + color = style['color'] + + y=-1 + for y,l in enumerate(self._icon): + canvas.drawTTkString(text=l, pos=(0,y),color=color) + canvas.drawText(text=self._text, pos=(0,y+1),color=color) \ No newline at end of file diff --git a/multiplexers/workbench/wblib/loader.py b/multiplexers/workbench/wblib/loader.py index d052aa8e..cfa8c72e 100644 --- a/multiplexers/workbench/wblib/loader.py +++ b/multiplexers/workbench/wblib/loader.py @@ -20,13 +20,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from TermTk import TTkUtil, TTkWidget, TTkLabel, TTkCanvas +from TermTk import TTkUtil, TTkWidget, TTkLabel, TTkCanvas, TTkString from .colors import * __all__ = ['WBLoader'] class WBLoader(TTkWidget): + __slots__ = ('_data') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -83,10 +84,7 @@ class WBLoader(TTkWidget): "6BRGSodjmgRv5h6h7HwYjO4/SNzM5Ky/+WyAwofNiveesfHqkWXInDCVJLD+nAsd4F24iLb2m+bwZGi4U674UR/G9hOZuqErc+P56zvvfDNhplNxl3j0rvAlu/aIO5k3" + "+5lvbuVvvLm9kxuPaYD11gLac/Mj/H3EO9/o+nqeQotm/um3/wW9x45d") - w,h = self.size() - l = TTkLabel(parent=self, text=data) - lw,lh = l.size() - l.move((w-lw)//2,(h-lh)//2) + self._data = TTkString(data).split('\n') # # ▀▄ █ ██ █ ▖ █ █ ▝▀▀▄ ██ @@ -104,9 +102,16 @@ class WBLoader(TTkWidget): # ▌ ▐ ╚═╝ ╚═╝ # ▚▄▄▘ - def mouseReleaseEvent(self, evt) -> bool: + def mousePressEvent(self, evt) -> bool: self.close() return True def paintEvent(self, canvas: TTkCanvas): - canvas.fill(color=bgWHITE) \ No newline at end of file + w,h = self.size() + dw = self._data[0].termWidth() + dh = len(self._data) + x = (w-dw)//2 + y = (h-dh)//2 + canvas.fill(color=bgWHITE) + for dy, txt in enumerate(self._data,y): + canvas.drawTTkString(pos=(x,dy), text=txt) diff --git a/multiplexers/workbench/wblib/window.py b/multiplexers/workbench/wblib/window.py index f9266bb0..cd605e6d 100644 --- a/multiplexers/workbench/wblib/window.py +++ b/multiplexers/workbench/wblib/window.py @@ -45,18 +45,44 @@ class _MinimizedButton(TTkButton): self.clicked.connect(_cb) class WBWindow(TTkResizableFrame): - '''TTkWindow''' + '''WBWindow''' + + _styleBgWhite = { + 'default': {'color': fgWHITE+bgBLUE}, + 'disabled': {'color': fgWHITE+bgBLUE}, + 'focus': {'color': fgWHITE+bgBLUE}, + } + + _styleBgNone = { + 'default': {'color': fgWHITE}, + 'disabled': {'color': fgWHITE}, + 'focus': {'color': fgWHITE}, + } + + classStyle = { + 'default': {'titleChar': '⚏', + 'borderColor': bgWHITE+fgBLUE}, + 'disabled': {'titleChar': '⚏', + 'borderColor':bgWHITE+fgBLUE}, + 'focus': {'titleChar': '☰', + 'borderColor': bgWHITE+fgBLUE} + } + __slots__ = ( '_title', '_mouseDelta', '_draggable', '_btnClose', '_btnMax', '_btnMin', '_btnReduce', '_flags', '_winTopLayout', - '_sbRight', '_sbBottom', - '_maxBk', '_redBk', - '_wbbg') - def __init__(self, wbbg=fgWHITE+bgBLUE, *args, **kwargs): + '_sbRight', '_sbBottom') + + def __init__(self, whiteBg=True, *args, **kwargs): self._winTopLayout = TTkGridLayout() - self._wbbg = wbbg super().__init__(*args, **kwargs) + + if whiteBg: + self.mergeStyle(self._styleBgWhite) + else: + self.mergeStyle(self._styleBgNone) + self._flags = TTkK.NONE self.setPadding(1,1,1,1) self._mouseDelta = (0,0) @@ -74,8 +100,6 @@ class WBWindow(TTkResizableFrame): self._sbBottom.setGeometry( 0 , h-1, w-1, 1 ) def resizeEvent(self, w, h): - self._maxBk = None - self._redBk = None self._winTopLayout.setGeometry(1,1,w-2,1) self._sbRight.setGeometry( w-1, 1, 1, h-2) self._sbBottom.setGeometry( 0 , h-1, w-1, 1 ) @@ -119,28 +143,25 @@ class WBWindow(TTkResizableFrame): self.update() def paintEvent(self, canvas=TTkCanvas): - if self.hasFocus(): - color = TTkCfg.theme.windowBorderColorFocus - titleChar = '☰' - else: - color = TTkCfg.theme.windowBorderColor - # titleChar = '☷' - titleChar = '⚏' + style = self.currentStyle() + color = style['color'] + borderColor = style['borderColor'] + titleChar = style['titleChar'] w,h = self.size() canvas.fill(color=bgBLUE) - canvas.fill(char='▎',pos=(0,1), size=(1,h-2), color=self._wbbg) + canvas.fill(char='▎',pos=(0,1), size=(1,h-2), color=color) # draw the title ┃ │ canvas.drawText( text=f"│▣│ {self._title} {titleChar*w}", # text=f"│⚀│ {self._title} {titleChar*w}", - color=bgWHITE+fgBLUE) + color=borderColor) canvas.drawText( text="│◪│◩│", pos=(w-5,0), - color=bgWHITE+fgBLUE) + color=borderColor) - canvas.drawChar(pos=(w-1,h-1),char='⇱',color=fgBLUE+bgWHITE) \ No newline at end of file + canvas.drawChar(pos=(w-1,h-1),char='⇱',color=borderColor) \ No newline at end of file From 205efc9b2e3f1e90c2b8d369c7812046a254c20b Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sat, 9 Sep 2023 19:00:25 +0100 Subject: [PATCH 05/11] Added mouse debug --- TermTk/TTkWidgets/TTkTerminal/terminal.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TermTk/TTkWidgets/TTkTerminal/terminal.py b/TermTk/TTkWidgets/TTkTerminal/terminal.py index 2f297a1b..fec583e7 100644 --- a/TermTk/TTkWidgets/TTkTerminal/terminal.py +++ b/TermTk/TTkWidgets/TTkTerminal/terminal.py @@ -63,12 +63,14 @@ class _termLog(): error = TTkLog.error warn = TTkLog.warn fatal = TTkLog.fatal + # mouse = TTkLog.error debug = lambda _:None info = lambda _:None # error = lambda _:None # warn = lambda _:None # fatal = lambda _:None + mouse = lambda _:None class TTkTerminal(TTkWidget): @dataclass @@ -831,7 +833,7 @@ class TTkTerminal(TTkWidget): return True if ( not self._mouse.reportDrag and evt.evt in (TTkK.Drag, TTkK.Move)): - _termLog.error(f"{self._mouse.reportDrag=} {evt.evt in (TTkK.Drag, TTkK.Move)=}") + _termLog.mouse(f"{self._mouse.reportDrag=} {evt.evt in (TTkK.Drag, TTkK.Move)=}") return True x,y = evt.x+1, evt.y+1 @@ -854,7 +856,7 @@ class TTkTerminal(TTkWidget): TTkK.WHEEL_Up: (k, 0,'M'), TTkK.WHEEL_Down:(k, 1,'M')}.get( evt.evt,(0,0,'M')) - _termLog.error(f'Mouse: [<{k+km};{x};{y}{pr}') + _termLog.mouse(f'Mouse: [<{k+km};{x};{y}{pr}') self._inout.write(f'\033[<{k+km};{x};{y}{pr}'.encode()) else: head = { @@ -869,7 +871,7 @@ class TTkTerminal(TTkWidget): bah = bytearray(head) bah.append((x+32)%0xff) bah.append((y+32)%0xff) - _termLog.error(f'Mouse: '+bah.decode().replace('\033','')) + _termLog.mouse(f'Mouse: '+bah.decode().replace('\033','')) self._inout.write(bah) return True From 8f991791f0f2e2fa6d6ae291b1cbdae96837d0d2 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 10 Sep 2023 13:14:22 +0100 Subject: [PATCH 06/11] Added few controls and icons in the workbench crap --- multiplexers/workbench/main.py | 110 ++++++++++++++++++++- multiplexers/workbench/wblib/iconbutton.py | 19 +++- 2 files changed, 124 insertions(+), 5 deletions(-) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index 2ae7ef2b..a1b12885 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -44,27 +44,73 @@ from wblib import * # class WBWindow(ttk.TTkWindow): class WorkBench(ttk.TTkContainer): + __slots__ = ('_barSelected', '_barPosition', '_backLayout') def __init__(self, *args, **kwargs): + self._barselected = False + self._barPosition = 0 + self._backLayout = ttk.TTkLayout() + self._backLayout.setGeometry(0,0,0,0) super().__init__(*args, **kwargs) self.setPadding(1,0,0,0) + self.setFocusPolicy(ttk.TTkK.ClickFocus) + self.rootLayout().addItem(self._backLayout) + + _win = ttk.TTkWindow(pos=(10,0), size=(100,30),title=f"Loader Demo", layout=ttk.TTkGridLayout()) + WBLoader(parent=_win) + self._backLayout.addWidget(_win) + + if os.path.isfile(_fileName := os.path.join(sys.path[0],"dontsavethisfile.txt")): + with open(_fileName,'r') as f: + data = ttk.TTkUtil.base64_deflate_2_obj(f.read()) + _win = ttk.TTkWindow(pos=(10,0), size=(100,30),title=f"Guru Meditation", layout=ttk.TTkGridLayout()) + _sa = ttk.TTkScrollArea(parent=_win) + ttk.TTkImage(parent=_sa.viewport(), data=data) + self._backLayout.addWidget(_win) + + def mousePressEvent(self, evt): + self._barSelected = evt.y == self._barPosition + return True + + def mouseReleaseEvent(self, evt) -> bool: + self._barSelected = False + return True + + def mouseDragEvent(self, evt): + if not self._barSelected: return True + w,h = self.size() + y = max(0,min(evt.y,h-1)) + self.setPadding(y+1,0,0,0) + self._barPosition = y + self._backLayout.setGeometry(0,0,w,y) + self.update() + return True + def paintEvent(self, canvas: TTkCanvas): w,h = self.size() - canvas.fill(color=bgBLUE) + + canvas.fill(size=(w,self._barPosition)) + canvas.fill(pos=(0,self._barPosition),color=bgBLUE) # draw the title canvas.drawText( + pos=(0,self._barPosition), text=" pyTermTk Workbench. Version 1.0 plenty of free memory", width=w, color=bgWHITE+fgBLUE) canvas.drawText( + pos=(w-5,self._barPosition), text="│◪│◩│", - pos=(w-5,0), color=bgWHITE+fgBLUE) class TTkWorkbench(ttk.TTk): def paintEvent(self, canvas: TTkCanvas): canvas.fill(color=bgBLUE) +logWin = WBWindow(pos=(10,10), size=(60,20), + whiteBg=False, + title=f"Key Press Viewer",layout=ttk.TTkVBoxLayout()) +logViewer = ttk.TTkLogViewer(parent=logWin) + root = TTkWorkbench(layout=ttk.TTkGridLayout(), mouseTrack=True) root.setPadding(3,3,15,10) @@ -87,8 +133,66 @@ def _openTerminal(term=[]): _term.bell.connect(lambda : ttk.TTkLog.debug("BELL!!! 🔔🔔🔔")) _term.titleChanged.connect(_win.setTitle) term.append({'pos':(_x,_y),'term':_term,'win':_win}) + _win.raiseWidget() + +ttk.pyTTkSlot() +def _openInputViewer(): + _win = WBWindow(parent=wb, pos=(10,10), size=(60,6), + whiteBg=False, + title=f"Key Press Viewer",layout=ttk.TTkVBoxLayout()) + ttk.TTkKeyPressView(parent=_win) + _win.raiseWidget() + +def _openPreferences(): + _style = {'default': {'color': fgWHITE+bgBLUE},} + _win = WBWindow(parent=wb, pos=(10,10), size=(60,7),title=f"Preferences") + ttk.TTkLabel(parent=_win, pos=(0,0), text="Padding").setStyle(_style) + ttk.TTkLabel(parent=_win, pos=(2,1), text="Top" ).setStyle(_style) + ttk.TTkLabel(parent=_win, pos=(2,2), text="Bottom" ).setStyle(_style) + ttk.TTkLabel(parent=_win, pos=(2,3), text="Left" ).setStyle(_style) + ttk.TTkLabel(parent=_win, pos=(2,4), text="Right" ).setStyle(_style) + + ttk.TTkLabel(parent=_win, pos=(30,0), text="Style\nComing soon...\nOr Not").setStyle(_style) + + t,b,l,r = root.getPadding() + _sbT = ttk.TTkSpinBox(parent=_win, pos=(10,1), size=(6,1), value=t, maximum=30, minimum=0) + _sbB = ttk.TTkSpinBox(parent=_win, pos=(10,2), size=(6,1), value=b, maximum=30, minimum=0) + _sbL = ttk.TTkSpinBox(parent=_win, pos=(10,3), size=(6,1), value=l, maximum=30, minimum=0) + _sbR = ttk.TTkSpinBox(parent=_win, pos=(10,4), size=(6,1), value=r, maximum=30, minimum=0) + + _sbT.setStyle(_style) + _sbB.setStyle(_style) + _sbL.setStyle(_style) + _sbR.setStyle(_style) + + def _updatePadding(_,_sbT=_sbT,_sbB=_sbB,_sbL=_sbL,_sbR=_sbR): + root.setPadding(_sbT.value(),_sbB.value(),_sbL.value(),_sbR.value()) + + _sbT.valueChanged.connect(_updatePadding) + _sbB.valueChanged.connect(_updatePadding) + _sbL.valueChanged.connect(_updatePadding) + _sbR.valueChanged.connect(_updatePadding) + + _win.raiseWidget() + + + +ttk.pyTTkSlot() +def _openLogViewer(): + wb.layout().addWidget(logWin) + logWin.show() + logWin.resize(80,30) + logViewer.update() + logWin.raiseWidget() winWb = WBWindow(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench") -WBIconButton(parent=winWb, text="Terminal").clicked.connect(_openTerminal) +WBIconButton(parent=winWb, + text="Terminal").clicked.connect(_openTerminal) +WBIconButton(parent=winWb, pos=(10,0), icon=WBIconButton.IconInputLog, + text="Input Viewer").clicked.connect(_openInputViewer) +WBIconButton(parent=winWb, pos=(25,0), icon=WBIconButton.IconLogViewer, + text="Log Viewer").clicked.connect(_openLogViewer) +WBIconButton(parent=winWb, pos=(0,6), icon=WBIconButton.IconPreferences, + text="Preferences").clicked.connect(_openPreferences) root.mainloop() \ No newline at end of file diff --git a/multiplexers/workbench/wblib/iconbutton.py b/multiplexers/workbench/wblib/iconbutton.py index a81909f1..cf4d753c 100644 --- a/multiplexers/workbench/wblib/iconbutton.py +++ b/multiplexers/workbench/wblib/iconbutton.py @@ -33,16 +33,31 @@ from .colors import * __all__ = ['WBIconButton'] class WBIconButton(TTkWidget): - IconTerminal = 0x01 + IconTerminal = 0x01 + IconPreferences = 0x02 + IconInputLog = 0x03 + IconLogViewer = 0x03 _iconS = { IconTerminal: [ # TTkString("🬦" "🬹🬹🬹🬹🬹🬹" "🬓"), TTkString("▗" "▄▄▄▄▄▄" "▖"), TTkString("▐")+ TTkString(" C:\ ",fgORANGE+bgWHITE+TTkColor.BOLD)+ TTkString("▌",fgWHITE+bgBLACK), - TTkString("🬉")+ TTkString("🬎🬎🬎🬎🬎🬎", fgWHITE+bgBLACK)+ TTkString("🬄",fgWHITE+bgBLACK)] + TTkString("🬉")+ TTkString("🬎🬎🬎🬎🬎🬎", fgWHITE+bgBLACK)+ TTkString("🬄",fgWHITE+bgBLACK)], # TTkString("┌──────┐"), # TTkString("│ C:\ │"), # TTkString("└──────┘")] + IconPreferences: [ + TTkString(" ┌───┐"), + TTkString(" │ ? │"), + TTkString(" └───┘")], + IconInputLog: [ + TTkString("┌────────┐"), + TTkString("│ ABC... │"), + TTkString("└────────┘")], + IconLogViewer: [ + TTkString("┌──────┐"), + TTkString("│ LOGS │"), + TTkString("└──────┘")], } classStyle = { From eb8d47626aa6a208eef249f42694461a92ac529d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Wed, 13 Sep 2023 17:10:57 +0100 Subject: [PATCH 07/11] Added scrolling to the workbench --- multiplexers/workbench/main.py | 36 +-- multiplexers/workbench/wblib/__init__.py | 1 + multiplexers/workbench/wblib/scrollbar.py | 9 +- multiplexers/workbench/wblib/scrollwin.py | 259 ++++++++++++++++++++++ 4 files changed, 288 insertions(+), 17 deletions(-) create mode 100644 multiplexers/workbench/wblib/scrollwin.py diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index a1b12885..fbcebded 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -34,6 +34,8 @@ sys.path.append(os.path.join(sys.path[0],'../..')) import TermTk as ttk from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkTestWidgets.logviewer import _TTkLogViewer + from wblib import * @@ -106,10 +108,10 @@ class TTkWorkbench(ttk.TTk): def paintEvent(self, canvas: TTkCanvas): canvas.fill(color=bgBLUE) -logWin = WBWindow(pos=(10,10), size=(60,20), +logWin = WBScrollWin(pos=(10,10), size=(60,20), whiteBg=False, title=f"Key Press Viewer",layout=ttk.TTkVBoxLayout()) -logViewer = ttk.TTkLogViewer(parent=logWin) +logWin.setViewport(_TTkLogViewer()) root = TTkWorkbench(layout=ttk.TTkGridLayout(), mouseTrack=True) root.setPadding(3,3,15,10) @@ -125,10 +127,10 @@ def _openTerminal(term=[]): while (_x,_y) in [_t['pos'] for _t in term]: _x += 4 _y += 2 - _win = WBWindow(parent=wb, pos=(_x,_y), size=(60,20), + _win = WBScrollWin(parent=wb, pos=(_x,_y), size=(60,20), whiteBg=False, title=f"Terminallo n.{len(term)+1}",layout=ttk.TTkVBoxLayout()) - _term = ttk.TTkTerminal(parent=_win) + _win.setViewport(_term := ttk.TTkTerminalView()) _term.runShell() _term.bell.connect(lambda : ttk.TTkLog.debug("BELL!!! 🔔🔔🔔")) _term.titleChanged.connect(_win.setTitle) @@ -182,17 +184,23 @@ def _openLogViewer(): wb.layout().addWidget(logWin) logWin.show() logWin.resize(80,30) - logViewer.update() logWin.raiseWidget() -winWb = WBWindow(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench") -WBIconButton(parent=winWb, - text="Terminal").clicked.connect(_openTerminal) -WBIconButton(parent=winWb, pos=(10,0), icon=WBIconButton.IconInputLog, - text="Input Viewer").clicked.connect(_openInputViewer) -WBIconButton(parent=winWb, pos=(25,0), icon=WBIconButton.IconLogViewer, - text="Log Viewer").clicked.connect(_openLogViewer) -WBIconButton(parent=winWb, pos=(0,6), icon=WBIconButton.IconPreferences, - text="Preferences").clicked.connect(_openPreferences) +winWb = WBScrollWin(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench") + +winWb.viewport().addWidget(_bttn:=WBIconButton(text="Terminal")) +_bttn.clicked.connect(_openTerminal) + +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(10,0), icon=WBIconButton.IconInputLog, + text="Input Viewer")) +_bttn.clicked.connect(_openInputViewer) + +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(25,0), icon=WBIconButton.IconLogViewer, + text="Log Viewer")) +_bttn.clicked.connect(_openLogViewer) + +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(0,6), icon=WBIconButton.IconPreferences, + text="Preferences")) +_bttn.clicked.connect(_openPreferences) root.mainloop() \ No newline at end of file diff --git a/multiplexers/workbench/wblib/__init__.py b/multiplexers/workbench/wblib/__init__.py index ae7e8e15..c684a511 100644 --- a/multiplexers/workbench/wblib/__init__.py +++ b/multiplexers/workbench/wblib/__init__.py @@ -1,5 +1,6 @@ from .colors import * from .window import * +from .scrollwin import * from .scrollbar import * from .iconbutton import * from .loader import * \ No newline at end of file diff --git a/multiplexers/workbench/wblib/scrollbar.py b/multiplexers/workbench/wblib/scrollbar.py index 7e0b7849..a5987afe 100644 --- a/multiplexers/workbench/wblib/scrollbar.py +++ b/multiplexers/workbench/wblib/scrollbar.py @@ -39,6 +39,9 @@ CUSTOM_THEME = TTkTheme.NERD | {'draw':draw_custom} TTkTheme.loadTheme( CUSTOM_THEME ) class WBScrollBar(TTkScrollBar): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._color = self._focusColor = fgBLUE+bgWHITE + classStyle = { + 'default': {'color': bgWHITE+fgBLUE}, + 'disabled': {'color': bgWHITE+fgBLUE}, + 'focus': {'color': bgWHITE+fgBLUE}, + } + diff --git a/multiplexers/workbench/wblib/scrollwin.py b/multiplexers/workbench/wblib/scrollwin.py new file mode 100644 index 00000000..a5063636 --- /dev/null +++ b/multiplexers/workbench/wblib/scrollwin.py @@ -0,0 +1,259 @@ +# 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.cfg import TTkCfg +from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkCore.color import TTkColor +from TermTk.TTkCore.canvas import TTkCanvas +from TermTk.TTkLayouts import TTkGridLayout, TTkLayout +from TermTk.TTkWidgets.widget import TTkWidget +from TermTk.TTkWidgets.button import TTkButton +from TermTk.TTkWidgets.resizableframe import TTkResizableFrame +from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea +from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollViewLayout, TTkAbstractScrollViewInterface + + +from .colors import * +from .scrollbar import * + +__all__ = ['WBScrollWin'] + + +class _MinimizedButton(TTkButton): + __slots__ = ('_windowWidget') + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._windowWidget = kwargs.get('windowWidget') + def _cb(): + self._windowWidget.show() + self.close() + self.clicked.connect(_cb) + +class WBScrollWin(TTkResizableFrame): + '''WBScrollWin''' + + _styleScrollBar = { + 'default': {'color': bgWHITE+fgBLUE}, + 'disabled': {'color': bgWHITE+fgBLUE}, + 'focus': {'color': bgWHITE+fgBLUE}, + } + + _styleBgWhite = { + 'default': {'color': fgWHITE+bgBLUE}, + 'disabled': {'color': fgWHITE+bgBLUE}, + 'focus': {'color': fgWHITE+bgBLUE}, + } + + _styleBgNone = { + 'default': {'color': fgWHITE}, + 'disabled': {'color': fgWHITE}, + 'focus': {'color': fgWHITE}, + } + + classStyle = { + 'default': {'titleChar': '⚏', + 'borderColor': bgWHITE+fgBLUE}, + 'disabled': {'titleChar': '⚏', + 'borderColor':bgWHITE+fgBLUE}, + 'focus': {'titleChar': '☰', + 'borderColor': bgWHITE+fgBLUE} + } + + __slots__ = ( + # Copied from Scroll Area + '_viewport', + '_verticalScrollBar', + '_horizontalScrollBar', + + # Copied from Window + '_mouseDelta', '_draggable', + '_btnClose', '_btnMax', '_btnMin', '_btnReduce', + '_flags', '_winTopLayout', + '_sbRight', '_sbBottom') + + def __init__(self, whiteBg=True, *args, **kwargs): + self._winTopLayout = TTkGridLayout() + self._viewport = TTkAbstractScrollViewLayout() + + super().__init__(*args, **kwargs|{'layout':TTkGridLayout()}) + + self._verticalScrollBar = WBScrollBar(orientation=TTkK.VERTICAL) + self._horizontalScrollBar = WBScrollBar(orientation=TTkK.HORIZONTAL) + + self.rootLayout().addWidgets([self._verticalScrollBar, self._horizontalScrollBar]) + + self.layout().addItem(self._viewport) + + if whiteBg: + self.mergeStyle(self._styleBgWhite) + else: + self.mergeStyle(self._styleBgNone) + + self._flags = TTkK.NONE + self.setPadding(1,1,1,1) + self._mouseDelta = (0,0) + self.setFocusPolicy(TTkK.ClickFocus) + self._draggable = False + + self._resizeEvent() + + def setViewport(self, viewport): + if not isinstance(viewport, TTkAbstractScrollViewInterface): + raise TypeError("TTkAbstractScrollViewInterface is required in TTkAbstractScrollArea.setVewport(viewport)") + if self._viewport: + self._viewport.viewChanged.disconnect(self._viewportChanged) + if isinstance(self._viewport, TTkWidget): + self.layout().removeWidget(self._viewport) + else: + self.layout().removeItem(self._viewport) + self._viewport = viewport + self._viewport.viewChanged.connect(self._viewportChanged) + self._verticalScrollBar.sliderMoved.connect(self._vscrollMoved) + self._horizontalScrollBar.sliderMoved.connect(self._hscrollMoved) + if isinstance(viewport, TTkWidget): + self.layout().addWidget(viewport) + else: + self.layout().addItem(viewport) + self._resizeEvent() + + def viewport(self): + return self._viewport + + def _resizeEvent(self): + w,h = self.size() + self._verticalScrollBar.setGeometry( w-1, 1, 1, h-2) + self._horizontalScrollBar.setGeometry( 0 , h-1, w-1, 1 ) + # if self._viewport: + # self._viewport.setGeometry(0,0,w-2,h-2) + self._winTopLayout.setGeometry(1,1,w-2,1) + + def resizeEvent(self, w, h): + super().resizeEvent(w,h) + self._resizeEvent() + + @pyTTkSlot() + def _viewportChanged(self): + if not self.isVisible(): return + w,h = self.size() + fw, fh = self._viewport.viewFullAreaSize() + dw, dh = self._viewport.viewDisplayedSize() + ox, oy = self._viewport.getViewOffsets() + if 0 in [fw,fh,dw,dh]: + return + hpage = dw + vpage = dh + hrange = fw - dw + vrange = fh - dh + # TTkLog.debug(f"f:{fw,fh=}, d:{dw,dh=}, o:{ox,oy=}") + self._verticalScrollBar.setPageStep(vpage) + self._verticalScrollBar.setRange(0, vrange) + self._verticalScrollBar.setValue(oy) + self._horizontalScrollBar.setPageStep(hpage) + self._horizontalScrollBar.setRange(0, hrange) + self._horizontalScrollBar.setValue(ox) + + self._resizeEvent() + + @pyTTkSlot(int) + def _vscrollMoved(self, val): + ox, _ = self._viewport.getViewOffsets() + self._viewport.viewMoveTo(ox, val) + + @pyTTkSlot(int) + def _hscrollMoved(self, val): + _, oy = self._viewport.getViewOffsets() + self._viewport.viewMoveTo(val, oy) + + def update(self, repaint=True, updateLayout=False, updateParent=False): + if self._viewport: + self._viewport.update(repaint, updateLayout, updateParent) + return super().update(repaint, updateLayout, updateParent) + + def mousePressEvent(self, evt): + self._mouseDelta = (evt.x, evt.y) + self._draggable = False + w,_ = self.size() + x,y = evt.x, evt.y + # If the mouse position is inside the header box enable the dragging feature + if y==0 and 1<=xw-4: + self.lowerWidget() + return True + self._draggable = True + return True + return TTkResizableFrame.mousePressEvent(self, evt) + + def mouseDragEvent(self, evt): + if self._draggable: + x,y = self.pos() + dx = evt.x-self._mouseDelta[0] + dy = evt.y-self._mouseDelta[1] + self.move(x+dx, y+dy) + return True + return TTkResizableFrame.mouseDragEvent(self, evt) + + def focusInEvent(self): + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.fg("#ffff55")) + self.update() + + def focusOutEvent(self): + self._draggable = False + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.RST) + self.update() + + # # Stupid hack to paint on top of the child widgets + # def paintChildCanvas(self): + # super().paintChildCanvas() + # style = self.currentStyle() + # borderColor = style['borderColor'] + # w,h = self.size() + # canvas = self.getCanvas() + # canvas.drawChar(pos=(w-1,h-1),char='⇱',color=borderColor) + + def paintEvent(self, canvas=TTkCanvas): + style = self.currentStyle() + color = style['color'] + borderColor = style['borderColor'] + titleChar = style['titleChar'] + + w,h = self.size() + + canvas.fill(color=bgBLUE) + canvas.fill(char='▎',pos=(0,1), size=(1,h-2), color=color) + # draw the title ┃ │ + canvas.drawText( + text=f"│▣│ {self._title} {titleChar*w}", + # text=f"│⚀│ {self._title} {titleChar*w}", + color=borderColor) + + canvas.drawText( + text="│◪│◩│", + pos=(w-5,0), + color=borderColor) + + canvas.drawChar(pos=(w-1,h-1),char='⇱',color=borderColor) \ No newline at end of file From a88ec38be734f102b0a95188aa7fec1bf1a59d00 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Wed, 13 Sep 2023 17:39:40 +0100 Subject: [PATCH 08/11] fixed few things --- multiplexers/workbench/main.py | 7 ++-- multiplexers/workbench/wblib/scrollwin.py | 41 ++++++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index fbcebded..23eeb94b 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -188,14 +188,15 @@ def _openLogViewer(): winWb = WBScrollWin(parent=wb, pos=(5,2), size=(50,15), title="euWorkbench") -winWb.viewport().addWidget(_bttn:=WBIconButton(text="Terminal")) +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(3,0), icon=WBIconButton.IconTerminal, + text="Terminal")) _bttn.clicked.connect(_openTerminal) -winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(10,0), icon=WBIconButton.IconInputLog, +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(18,0), icon=WBIconButton.IconInputLog, text="Input Viewer")) _bttn.clicked.connect(_openInputViewer) -winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(25,0), icon=WBIconButton.IconLogViewer, +winWb.viewport().addWidget(_bttn:=WBIconButton(pos=(35,3), icon=WBIconButton.IconLogViewer, text="Log Viewer")) _bttn.clicked.connect(_openLogViewer) diff --git a/multiplexers/workbench/wblib/scrollwin.py b/multiplexers/workbench/wblib/scrollwin.py index a5063636..48ae9da6 100644 --- a/multiplexers/workbench/wblib/scrollwin.py +++ b/multiplexers/workbench/wblib/scrollwin.py @@ -30,7 +30,7 @@ from TermTk.TTkWidgets.widget import TTkWidget from TermTk.TTkWidgets.button import TTkButton from TermTk.TTkWidgets.resizableframe import TTkResizableFrame from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea -from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollViewLayout, TTkAbstractScrollViewInterface +from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewLayout, TTkAbstractScrollViewInterface from .colors import * @@ -49,6 +49,40 @@ class _MinimizedButton(TTkButton): self.close() self.clicked.connect(_cb) +class WBScrollWiewport(TTkAbstractScrollView): + classStyle = { + 'default': {'color': fgWHITE+bgBLUE}, + 'disabled': {'color': fgWHITE+bgBLUE}, + 'focus': {'color': fgWHITE+bgBLUE}, + } + + __slots__ = () + def __init__(self, *args, **kwargs): + TTkAbstractScrollView.__init__(self, *args, **kwargs) + self.viewChanged.connect(self._viewChangedHandler) + + @pyTTkSlot() + def _viewChangedHandler(self): + x,y = self.getViewOffsets() + self.layout().setOffset(-x,-y) + + def viewFullAreaSize(self) -> (int, int): + _,_,w,h = self.layout().fullWidgetAreaGeometry() + return w , h + + def viewDisplayedSize(self) -> (int, int): + return self.size() + + def maximumWidth(self): return 0x10000 + def maximumHeight(self): return 0x10000 + def minimumWidth(self): return 0 + def minimumHeight(self): return 0 + + def paintEvent(self, canvas: TTkCanvas): + style = self.currentStyle() + color = style['color'] + canvas.fill(color=color) + class WBScrollWin(TTkResizableFrame): '''WBScrollWin''' @@ -93,7 +127,7 @@ class WBScrollWin(TTkResizableFrame): def __init__(self, whiteBg=True, *args, **kwargs): self._winTopLayout = TTkGridLayout() - self._viewport = TTkAbstractScrollViewLayout() + self._viewport = WBScrollWiewport() super().__init__(*args, **kwargs|{'layout':TTkGridLayout()}) @@ -102,7 +136,6 @@ class WBScrollWin(TTkResizableFrame): self.rootLayout().addWidgets([self._verticalScrollBar, self._horizontalScrollBar]) - self.layout().addItem(self._viewport) if whiteBg: self.mergeStyle(self._styleBgWhite) @@ -115,7 +148,7 @@ class WBScrollWin(TTkResizableFrame): self.setFocusPolicy(TTkK.ClickFocus) self._draggable = False - self._resizeEvent() + self.setViewport(self._viewport) def setViewport(self, viewport): if not isinstance(viewport, TTkAbstractScrollViewInterface): From 9bb2497d83c89302234b81664206891b32a964a0 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Thu, 14 Sep 2023 19:32:29 +0100 Subject: [PATCH 09/11] Removed useless impoort added automatically by some fucking DevGUI --- demo/demo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/demo/demo.py b/demo/demo.py index 91064414..b6c787ba 100755 --- a/demo/demo.py +++ b/demo/demo.py @@ -22,7 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from cgitb import text import sys, os, argparse import re import random From ee02e887e468e4314d604db5fc0006058ea85e47 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Thu, 26 Oct 2023 23:33:28 +0100 Subject: [PATCH 10/11] Fix error in the workbench --- multiplexers/workbench/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index 23eeb94b..50069311 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -52,6 +52,7 @@ class WorkBench(ttk.TTkContainer): self._barPosition = 0 self._backLayout = ttk.TTkLayout() self._backLayout.setGeometry(0,0,0,0) + self._barSelected = False super().__init__(*args, **kwargs) self.setPadding(1,0,0,0) self.setFocusPolicy(ttk.TTkK.ClickFocus) From bd9144871dd15c8d53ba5eea45eb21efbe0137f5 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 29 Oct 2023 20:36:29 +0000 Subject: [PATCH 11/11] Kind of finalised the workbench --- TermTk/TTkWidgets/TTkTerminal/__init__.py | 1 + multiplexers/workbench/main.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/TermTk/TTkWidgets/TTkTerminal/__init__.py b/TermTk/TTkWidgets/TTkTerminal/__init__.py index d3877f7c..99e1c4ba 100644 --- a/TermTk/TTkWidgets/TTkTerminal/__init__.py +++ b/TermTk/TTkWidgets/TTkTerminal/__init__.py @@ -1 +1,2 @@ from .terminal import * +from .terminalview import * diff --git a/multiplexers/workbench/main.py b/multiplexers/workbench/main.py index 50069311..02a896ec 100755 --- a/multiplexers/workbench/main.py +++ b/multiplexers/workbench/main.py @@ -122,8 +122,11 @@ root.rootLayout().addWidget(wbl) wb = WorkBench(parent=root) +clipboard = ttk.TTkClipboard() + ttk.pyTTkSlot() def _openTerminal(term=[]): + global clipboard _x,_y = 15,5 while (_x,_y) in [_t['pos'] for _t in term]: _x += 4 @@ -135,6 +138,7 @@ def _openTerminal(term=[]): _term.runShell() _term.bell.connect(lambda : ttk.TTkLog.debug("BELL!!! 🔔🔔🔔")) _term.titleChanged.connect(_win.setTitle) + _term.textSelected.connect(clipboard.setText) term.append({'pos':(_x,_y),'term':_term,'win':_win}) _win.raiseWidget()