From 46c2ced6ab180a681f76e8d6818b8922dcba36e1 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Sun, 4 Feb 2024 12:02:34 +0000 Subject: [PATCH 1/4] Prototyping the undo in ttkDesignner --- ttkDesigner/app/designer.py | 47 ++++++++++++++++++++---- ttkDesigner/app/superobj/supercontrol.py | 10 +++-- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/ttkDesigner/app/designer.py b/ttkDesigner/app/designer.py index f9b9fc36..985de71e 100644 --- a/ttkDesigner/app/designer.py +++ b/ttkDesigner/app/designer.py @@ -23,25 +23,22 @@ import os import json -from TermTk import TTk, TTkK, TTkLog, TTkCfg, TTkColor, TTkTheme, TTkTerm, TTkHelper +from TermTk import TTkK, TTkLog, TTkColor, TTkHelper, TTkShortcut from TermTk import TTkString -from TermTk import TTkColorGradient from TermTk import pyTTkSlot, pyTTkSignal from TermTk import TTkWidget, TTkFrame, TTkButton, TTkLabel, TTkMenuButton from TermTk import TTkTabWidget -from TermTk import TTkAbstractScrollArea, TTkAbstractScrollView, TTkScrollArea from TermTk import TTkFileDialogPicker, TTkMessageBox -from TermTk import TTkFileTree, TTkTextEdit -from TermTk import TTkLayout, TTkGridLayout, TTkVBoxLayout, TTkHBoxLayout +from TermTk import TTkGridLayout, TTkVBoxLayout, TTkHBoxLayout from TermTk import TTkSplitter from TermTk import TTkLogViewer from TermTk import TTkUiLoader, TTkUtil from .cfg import * from .about import * -from .widgetbox import DragDesignItem, WidgetBox, WidgetBoxScrollArea +from .widgetbox import WidgetBoxScrollArea from .windoweditor import WindowEditor from .treeinspector import TreeInspector from .propertyeditor import PropertyEditor @@ -51,6 +48,8 @@ from .superobj import SuperWidget, SuperWidgetFrame +import pickle + # # Mimic the QT Designer layout # @@ -78,11 +77,16 @@ # class TTkDesigner(TTkGridLayout): - __slots__ = ('_pippo', '_main', '_windowEditor', '_toolBar', '_fileNameLabel', '_sigslotEditor', '_treeInspector', '_fileName', '_currentPath', '_notepad', + __slots__ = ('_main', '_toolBar', '_fileNameLabel', + '_sigslotEditor', '_treeInspector', '_windowEditor', '_notepad', + '_fileName', '_currentPath', + '_snapshot', '_snapId', # Signals 'weModified', 'thingSelected', 'widgetNameChanged' ) def __init__(self, fileName=None, *args, **kwargs): + self._snapshot = [] + self._snapId = -1 self._fileName = "untitled.tui.json" self._currentPath = self._currentPath = os.path.abspath('.') @@ -131,6 +135,7 @@ def __init__(self, fileName=None, *args, **kwargs): self.thingSelected.connect(propertyEditor.setDetail) self.weModified.connect(self._treeInspector.refresh) + self.weModified.connect(self._takeSnapshot) fileMenu = topMenuFrame.newMenubarTop().addMenu("&File") fileMenu.addMenu("New").menuButtonClicked.connect(self.new) @@ -176,9 +181,37 @@ def _showAboutTTk(btn): self._toolBar.addWidget(self._fileNameLabel) + TTkShortcut(TTkK.CTRL | TTkK.Key_Z).activated.connect(self.undo) + self._takeSnapshot() + if fileName: self._openFile(fileName) + @pyTTkSlot() + def _takeSnapshot(self): + tui = self._windowEditor.dumpDict() + connections = self._sigslotEditor.dumpDict() + data = { + 'version':'2.0.0', + 'tui':tui, + 'connections':connections} + TTkLog.debug(f"{len(pickle.dumps(data))=} {len(self._snapshot)=}") + self._snapId += 1 + self._snapshot = self._snapshot[:self._snapId]+[data] + + def undo(self): + TTkLog.debug(f"Undo: {len(self._snapshot)=}") + if not self._snapshot: return + if self._snapId <= 0: return + self.weModified.disconnect(self._takeSnapshot) + self._snapId -= 1 + data = self._snapshot[self._snapId] + sw = SuperWidget.loadDict(self, self._windowEditor.viewport(), data['tui']) + self._windowEditor.importSuperWidget(sw) + self._sigslotEditor.importConnections(data['connections']) + self._treeInspector.refresh() + self.weModified.connect(self._takeSnapshot) + def getWidgets(self): widgets = set() def _getMenu(menu): diff --git a/ttkDesigner/app/superobj/supercontrol.py b/ttkDesigner/app/superobj/supercontrol.py index 4c696c31..b25c31e7 100644 --- a/ttkDesigner/app/superobj/supercontrol.py +++ b/ttkDesigner/app/superobj/supercontrol.py @@ -88,14 +88,16 @@ def keyEvent(self, evt): return True bkPos = self.pos() x,y = 0,0 - if evt.key == ttk.TTkK.Key_Up: y=-1 - elif evt.key == ttk.TTkK.Key_Down: y=1 + if evt.key == ttk.TTkK.Key_Up: y=-1 + elif evt.key == ttk.TTkK.Key_Down: y= 1 elif evt.key == ttk.TTkK.Key_Left: x=-1 - elif evt.key == ttk.TTkK.Key_Right: x=1 + elif evt.key == ttk.TTkK.Key_Right: x= 1 + else: return super().keyEvent(evt) if any((x,y)): self.move(bkPos[0]+x, bkPos[1]+y) self._alignWidToPos(bkPos) - return True + return True + return super().keyEvent(evt) def paintEvent(self, canvas): w,h = self.size() From 9449d4744aa6e85ca82c789a8008fe4b5355a04d Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 6 Feb 2024 09:06:36 +0000 Subject: [PATCH 2/4] Fix typo causing test error --- tests/timeit/24.socket.01.client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/timeit/24.socket.01.client.py b/tests/timeit/24.socket.01.client.py index 517d6906..3c82adc6 100755 --- a/tests/timeit/24.socket.01.client.py +++ b/tests/timeit/24.socket.01.client.py @@ -37,7 +37,6 @@ def test1(): sock.sendall(bytes(data + "\n", "utf-8")) received = str(sock.recv(1024), "utf-8") return len(received) -https://github.com/ceccopierangiolieugenio/pyTermTk/issues/210 a = {} From 43c646cac044f6318e77b889384d2f62a92f0bc2 Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 6 Feb 2024 10:10:04 +0000 Subject: [PATCH 3/4] Added undo/redo in the ttkDesigner --- ttkDesigner/app/designer.py | 74 ++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/ttkDesigner/app/designer.py b/ttkDesigner/app/designer.py index 985de71e..192545da 100644 --- a/ttkDesigner/app/designer.py +++ b/ttkDesigner/app/designer.py @@ -138,20 +138,23 @@ def __init__(self, fileName=None, *args, **kwargs): self.weModified.connect(self._takeSnapshot) fileMenu = topMenuFrame.newMenubarTop().addMenu("&File") - fileMenu.addMenu("New").menuButtonClicked.connect(self.new) - fileMenu.addMenu("Open").menuButtonClicked.connect(self.open) - fileMenu.addMenu("Save").menuButtonClicked.connect(self.save) - fileMenu.addMenu("Save As...").menuButtonClicked.connect(self.saveAs) + fileMenu.addMenu("&New").menuButtonClicked.connect(self.new) + fileMenu.addMenu("&Open").menuButtonClicked.connect(self.open) + fileMenu.addMenu("&Save").menuButtonClicked.connect(self.save) + fileMenu.addMenu("Save &As...").menuButtonClicked.connect(self.saveAs) fileMenu.addSpacer() - fileMenu.addMenu("Import 🎁").menuButtonClicked.connect(self.importDictWin) - fileMenu.addMenu("Export 📦").menuButtonClicked.connect(self.quickExport) + fileMenu.addMenu("&Import 🎁").menuButtonClicked.connect(self.importDictWin) + fileMenu.addMenu("&Export 📦").menuButtonClicked.connect(self.quickExport) fileMenu.addSpacer() - fileMenu.addMenu("Exit").menuButtonClicked.connect(TTkHelper.quit) + fileMenu.addMenu("E&xit").menuButtonClicked.connect(TTkHelper.quit) - extraMenu = topMenuFrame.newMenubarTop().addMenu("E&xtra") - extraMenu.addMenu("Scratchpad").menuButtonClicked.connect(self.scratchpad) + extraMenu = topMenuFrame.newMenubarTop().addMenu("E&dit") + extraMenu.addMenu("&Undo (CTRL+Z)").menuButtonClicked.connect(self.undo) + extraMenu.addMenu("&Redo (CTRL+Y)").menuButtonClicked.connect(self.redo) extraMenu.addSpacer() - extraMenu.addMenu("Preview...").menuButtonClicked.connect(self.preview) + extraMenu.addMenu("&Scratchpad 📝").menuButtonClicked.connect(self.scratchpad) + extraMenu.addSpacer() + extraMenu.addMenu("&Preview...").menuButtonClicked.connect(self.preview) def _showAbout(btn): TTkHelper.overlay(None, About(), 30,10) @@ -182,11 +185,31 @@ def _showAboutTTk(btn): self._toolBar.addWidget(self._fileNameLabel) TTkShortcut(TTkK.CTRL | TTkK.Key_Z).activated.connect(self.undo) + TTkShortcut(TTkK.CTRL | TTkK.Key_Y).activated.connect(self.redo) self._takeSnapshot() if fileName: self._openFile(fileName) + # Snapshot Logic: + # _snapshots = [ s0 , s1 , s2 , s3 , s4 , s5 , s6 ] + # _snapId = 3 ^ + # + # Undo: + # _snapId-- = 2 ^ = s2 + # load s2 + # + # Redo: + # _snapId++ = 4 ^ = s4 + # load s4 + # + # Take Snapshot: + # Remove the forward Snapshots: + # _snapshots = [ s0 , s1 , s2 , s3 ] + # Append The new one and update snapId + # _snapshots = [ s0 , s1 , s2 , s3 , s4+ ] + # _snapId++ = 4 + @pyTTkSlot() def _takeSnapshot(self): tui = self._windowEditor.dumpDict() @@ -196,15 +219,14 @@ def _takeSnapshot(self): 'tui':tui, 'connections':connections} TTkLog.debug(f"{len(pickle.dumps(data))=} {len(self._snapshot)=}") - self._snapId += 1 - self._snapshot = self._snapshot[:self._snapId]+[data] + if ( self._snapshot and + 0 <= self._snapId < len(self._snapshot) and + data == self._snapshot[self._snapId]): return + self._snapshot = self._snapshot[:self._snapId+1]+[data] + self._snapId = len(self._snapshot)-1 - def undo(self): - TTkLog.debug(f"Undo: {len(self._snapshot)=}") - if not self._snapshot: return - if self._snapId <= 0: return + def _loadSnapshot(self): self.weModified.disconnect(self._takeSnapshot) - self._snapId -= 1 data = self._snapshot[self._snapId] sw = SuperWidget.loadDict(self, self._windowEditor.viewport(), data['tui']) self._windowEditor.importSuperWidget(sw) @@ -212,6 +234,22 @@ def undo(self): self._treeInspector.refresh() self.weModified.connect(self._takeSnapshot) + @pyTTkSlot() + def undo(self): + TTkLog.debug(f"Undo: {len(self._snapshot)=}") + if not self._snapshot: return + if self._snapId <= 0: return + self._snapId -= 1 + self._loadSnapshot() + + @pyTTkSlot() + def redo(self): + TTkLog.debug(f"Undo: {len(self._snapshot)=}") + if not self._snapshot: return + if self._snapId >= len(self._snapshot)-1: return + self._snapId += 1 + self._loadSnapshot() + def getWidgets(self): widgets = set() def _getMenu(menu): @@ -270,7 +308,7 @@ def quickExport(self): @pyTTkSlot() def scratchpad(self): win = TTkWindow( - title="Mr Scratchpad", + title="Mr Scratchpad 📝", size=(80,30), layout=self._notepad, flags=TTkK.WindowFlag.WindowMaximizeButtonHint|TTkK.WindowFlag.WindowCloseButtonHint) From d73b89a081b64d6066ea684cd9675b8becb1725e Mon Sep 17 00:00:00 2001 From: Eugenio Parodi Date: Tue, 6 Feb 2024 10:25:53 +0000 Subject: [PATCH 4/4] added gitignore --- multiplexers/workbench/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 multiplexers/workbench/.gitignore diff --git a/multiplexers/workbench/.gitignore b/multiplexers/workbench/.gitignore new file mode 100644 index 00000000..63378e5d --- /dev/null +++ b/multiplexers/workbench/.gitignore @@ -0,0 +1 @@ +dontsavethisfile.txt \ No newline at end of file