diff --git a/TermTk/TTkCore/canvas.py b/TermTk/TTkCore/canvas.py index 311a2e5a..ff4d7ccd 100644 --- a/TermTk/TTkCore/canvas.py +++ b/TermTk/TTkCore/canvas.py @@ -661,7 +661,7 @@ class TTkCanvas: self._data[y+iy][a:b] = canvas._data[iy][xoffset:wslice] self._colors[y+iy][a:b] = canvas._colors[iy][xoffset:wslice] - + for iy in range(yoffset,hslice): # Check the full wide chars on the edge of the two canvasses if ((0 <= a < cw) and self._data[y+iy][a]==''): self._data[y+iy][a] = TTkCfg.theme.unicodeWideOverflowCh[0] diff --git a/TermTk/TTkUiTools/properties/__init__.py b/TermTk/TTkUiTools/properties/__init__.py index 783e1302..257d7529 100644 --- a/TermTk/TTkUiTools/properties/__init__.py +++ b/TermTk/TTkUiTools/properties/__init__.py @@ -22,3 +22,5 @@ from .splitter import TTkSplitterProperties from .texedit import TTkTextEditProperties from .widget import TTkWidgetProperties from .window import TTkWindowProperties + +from .layout import TTkLayoutProperties diff --git a/TermTk/TTkUiTools/properties/layout.py b/TermTk/TTkUiTools/properties/layout.py new file mode 100644 index 00000000..f1f6059a --- /dev/null +++ b/TermTk/TTkUiTools/properties/layout.py @@ -0,0 +1,60 @@ +# 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. + +# 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. + +from TermTk.TTkLayouts.layout import TTkLayout + +TTkLayoutProperties = { + 'Geometry' : { + 'get': { 'cb':TTkLayout.geometry, 'type': [ + { 'name': 'x', 'type':int } , + { 'name': 'y', 'type':int } , + { 'name': 'width', 'type':int } , + { 'name': 'height','type':int } ] }, + 'set': { 'cb':TTkLayout.setGeometry, 'type': [ + { 'name': 'x', 'type':int } , + { 'name': 'y', 'type':int } , + { 'name': 'width', 'type':int } , + { 'name': 'height','type':int } ] }, + } +} diff --git a/TermTk/TTkUiTools/uiloader.py b/TermTk/TTkUiTools/uiloader.py index 24e2feee..4aaa267a 100644 --- a/TermTk/TTkUiTools/uiloader.py +++ b/TermTk/TTkUiTools/uiloader.py @@ -43,12 +43,13 @@ class TTkUiLoader(): kwargs = {} # Init params to be configured with the setter setters = [] + layout = _getLayout(widProp['layout']) for pname in widProp['params']: if 'init' in properties[pname]: initp = properties[pname]['init'] name = initp['name'] if initp['type'] is TTkLayout: - value = globals()[widProp['params'][pname]]() + value = layout elif initp['type'] is TTkColor: value = TTkColor.ansi(widProp['params'][pname]) else: @@ -59,7 +60,7 @@ class TTkUiLoader(): setp = properties[pname]['set'] setcb = setp['cb'] if setp['type'] is TTkLayout: - value = globals()[widProp['params'][pname]]() + value = layout elif setp['type'] is TTkColor: value = TTkColor.ansi(widProp['params'][pname]) else: @@ -76,10 +77,19 @@ class TTkUiLoader(): else: s['cb'](widget, s['value']) TTkLog.debug(widget) - for c in widProp['children']: - widget.layout().addWidget(_getWidget(c)) + # for c in widProp['children']: + # widget.layout().addWidget(_getWidget(c)) return widget + def _getLayout(layprop): + layout = globals()[layprop['class']]() + for c in layprop['children']: + if issubclass(globals()[c['class']],TTkLayout): + layout.addItem(_getLayout(c)) + else: + layout.addWidget(_getWidget(c)) + return layout + widgetProperty = json.loads(text) TTkLog.debug(widgetProperty) # Yaml= diff --git a/TermTk/TTkUiTools/uiproperties.py b/TermTk/TTkUiTools/uiproperties.py index 599e9fd7..067e995a 100644 --- a/TermTk/TTkUiTools/uiproperties.py +++ b/TermTk/TTkUiTools/uiproperties.py @@ -25,6 +25,7 @@ from TermTk.TTkWidgets import * from .properties import * TTkUiProperties = { + # Widgets TTkButton.__name__: TTkButtonProperties, TTkCheckbox.__name__: TTkCheckboxProperties, TTkComboBox.__name__: TTkComboBoxProperties, @@ -39,4 +40,6 @@ TTkUiProperties = { TTkTextEdit.__name__: TTkTextEditProperties, TTkWidget.__name__: TTkWidgetProperties, TTkWindow.__name__: TTkWindowProperties, + # Layouts + TTkLayout.__name__: TTkLayoutProperties, } diff --git a/ttkDesigner/app/designer.py b/ttkDesigner/app/designer.py index 69bb3151..36ed8870 100644 --- a/ttkDesigner/app/designer.py +++ b/ttkDesigner/app/designer.py @@ -105,9 +105,9 @@ class TTkDesigner(TTkGridLayout): rightSplit.addItem(propertyEditor := PropertyEditor()) rightSplit.addWidget(TTkButton(text='E', border=True, maxHeight=3)) - treeInspector.widgetSelected.connect(lambda _,s : s.pushSuperControlWidget()) - treeInspector.widgetSelected.connect(propertyEditor.setDetail) - self._windowEditor.viewport().widgetSelected.connect(propertyEditor.setDetail) + treeInspector.thingSelected.connect(lambda _,s : s.pushSuperControlWidget()) + treeInspector.thingSelected.connect(propertyEditor.setDetail) + self._windowEditor.viewport().thingSelected.connect(propertyEditor.setDetail) self._windowEditor.viewport().weModified.connect(treeInspector.refresh) @@ -162,7 +162,7 @@ class TTkDesigner(TTkGridLayout): widget = TTkUiLoader.loadJson(jj) win = TTkWindow( title="Mr Terminal", - size=(50,20), + size=(80,30), layout=TTkGridLayout(), flags=TTkK.WindowFlag.WindowMaximizeButtonHint|TTkK.WindowFlag.WindowCloseButtonHint) win.layout().addWidget(widget) diff --git a/ttkDesigner/app/propertyeditor.py b/ttkDesigner/app/propertyeditor.py index 9430d3ff..d5d90e04 100644 --- a/ttkDesigner/app/propertyeditor.py +++ b/ttkDesigner/app/propertyeditor.py @@ -264,7 +264,7 @@ class PropertyEditor(ttk.TTkGridLayout): self._detail.clear() for cc in reversed(type(domw).__mro__): # if hasattr(cc,'_ttkProperties'): - if issubclass(cc, ttk.TTkWidget): + if issubclass(cc, ttk.TTkWidget) or issubclass(cc, ttk.TTkLayout): ccName = cc.__name__ classItem = ttk.TTkTreeWidgetItem([ccName,''], expanded=True) self._detail.addTopLevelItem(classItem) diff --git a/ttkDesigner/app/superobj/superlayout.py b/ttkDesigner/app/superobj/superlayout.py index 1c65bbf7..6098ae29 100644 --- a/ttkDesigner/app/superobj/superlayout.py +++ b/ttkDesigner/app/superobj/superlayout.py @@ -26,9 +26,9 @@ import TermTk as ttk import ttkDesigner.app.superobj as so class SuperLayout(ttk.TTkWidget): - def __init__(self, lay, weModified, widgetSelected, *args, **kwargs): + def __init__(self, lay, weModified, thingSelected, *args, **kwargs): self.weModified = weModified - self.widgetSelected = widgetSelected + self.thingSelected = thingSelected self._lay = lay self._superRootWidget = kwargs.get('superRootWidget',False) self._selectable = kwargs.get('selectable', False) @@ -52,7 +52,11 @@ class SuperLayout(ttk.TTkWidget): self.update() def dumpDict(self): - ret = {} + children=[] + for w in self.layout().children(): + children.append(w.widget().dumpDict()) + ret = {'class': 'TTkLayout', + 'children':children} return ret def updateAll(self): @@ -75,7 +79,7 @@ class SuperLayout(ttk.TTkWidget): def mouseReleaseEvent(self, evt) -> bool: if self._superRootWidget or not self._selectable: return False self.pushSuperControlWidget() - # self.widgetSelected.emit(self._lay,self) + self.thingSelected.emit(self._lay,self) return True def mouseDragEvent(self, evt) -> bool: @@ -99,7 +103,7 @@ class SuperLayout(ttk.TTkWidget): hsx,hsy = evt.hotSpot() ttk.TTkLog.debug(f"Drop ({data.__class__.__name__}) -> pos={evt.pos()}") if issubclass(type(data),ttk.TTkLayout): - self.layout().addWidget(sw := so.SuperLayout(lay=data, weModified=self.weModified, widgetSelected=self.widgetSelected, pos=(evt.x-hsx, evt.y-hsy), selectable=True)) + self.layout().addWidget(sw := so.SuperLayout(lay=data, weModified=self.weModified, thingSelected=self.thingSelected, pos=(evt.x-hsx, evt.y-hsy), selectable=True)) self._lay.addItem(data) elif issubclass(type(data), so.SuperLayout): sw = data @@ -117,7 +121,7 @@ class SuperLayout(ttk.TTkWidget): self._lay.addWidget(data) data.move(evt.x-hsx, evt.y-hsy) elif issubclass(type(data),ttk.TTkWidget): - self.layout().addWidget(sw := so.SuperWidget(wid=data, weModified=self.weModified, widgetSelected=self.widgetSelected, pos=(evt.x-hsx, evt.y-hsy))) + self.layout().addWidget(sw := so.SuperWidget(wid=data, weModified=self.weModified, thingSelected=self.thingSelected, pos=(evt.x-hsx, evt.y-hsy))) self._lay.addWidget(data) data.move(evt.x-hsx, evt.y-hsy) else: diff --git a/ttkDesigner/app/superobj/superwidget.py b/ttkDesigner/app/superobj/superwidget.py index cdaa84df..e5ed7c63 100644 --- a/ttkDesigner/app/superobj/superwidget.py +++ b/ttkDesigner/app/superobj/superwidget.py @@ -27,13 +27,13 @@ import TermTk as ttk import ttkDesigner.app.superobj as so class SuperWidget(ttk.TTkWidget): - def __init__(self, wid, weModified, widgetSelected, *args, **kwargs): + def __init__(self, wid, weModified, thingSelected, *args, **kwargs): self.weModified = weModified - self.widgetSelected = widgetSelected + self.thingSelected = thingSelected self._wid = wid self._wid.move(*kwargs['pos']) self._wid._canvas.show() - self._superLayout = so.SuperLayout(lay=self._wid.layout(), weModified=self.weModified, widgetSelected=self.widgetSelected,) + self._superLayout = so.SuperLayout(lay=self._wid.layout(), weModified=self.weModified, thingSelected=self.thingSelected,) self._superRootWidget = kwargs.get('superRootWidget',False) kwargs['layout'] = ttk.TTkGridLayout() kwargs['layout'].addWidget(self._superLayout) @@ -94,9 +94,7 @@ class SuperWidget(ttk.TTkWidget): else: ttk.TTkLog.warn("Type not Recognised") return ret - children = [] - for w in self.layout().children(): - children.append(w.widget().dumpDict()) + params = {} for cc in reversed(type(wid).__mro__): # if hasattr(cc,'_ttkProperties'): @@ -126,7 +124,7 @@ class SuperWidget(ttk.TTkWidget): ret = { 'class' : wid.__class__.__name__, 'params' : params, - 'children': children + 'layout': self._superLayout.dumpDict() } return ret @@ -149,7 +147,7 @@ class SuperWidget(ttk.TTkWidget): def mouseReleaseEvent(self, evt) -> bool: self.pushSuperControlWidget() - self.widgetSelected.emit(self._wid,self) + self.thingSelected.emit(self._wid,self) return True def mouseDragEvent(self, evt) -> bool: diff --git a/ttkDesigner/app/treeinspector.py b/ttkDesigner/app/treeinspector.py index 295a6b9c..9625d161 100644 --- a/ttkDesigner/app/treeinspector.py +++ b/ttkDesigner/app/treeinspector.py @@ -22,7 +22,8 @@ import TermTk as ttk -from .windoweditor import SuperWidget +from .superobj.superwidget import SuperWidget +from .superobj.superlayout import SuperLayout class _TTkTomTreeWidgetItem(ttk.TTkTreeWidgetItem): __slots__ = ('_tomWidget','_tomSuperWidget') @@ -38,7 +39,7 @@ class _TTkTomTreeWidgetItem(ttk.TTkTreeWidgetItem): class TreeInspector(ttk.TTkGridLayout): def __init__(self, windowEditor, *args, **kwargs): super().__init__(*args, **kwargs) - self.widgetSelected = ttk.pyTTkSignal(ttk.TTkWidget, ttk.TTkWidget) + self.thingSelected = ttk.pyTTkSignal(ttk.TTkWidget, ttk.TTkWidget) self._windowEditor = windowEditor self._tomTree = ttk.TTkTree() @@ -48,7 +49,7 @@ class TreeInspector(ttk.TTkGridLayout): @ttk.pyTTkSlot(_TTkTomTreeWidgetItem, int) def _itemSelected(wi, _): if tomw := wi.tomWidget(): - self.widgetSelected.emit(tomw, wi.tomSuperWidget()) + self.thingSelected.emit(tomw, wi.tomSuperWidget()) self._tomTree.itemClicked.connect(_itemSelected) @@ -69,14 +70,14 @@ class TreeInspector(ttk.TTkGridLayout): # # TTkHelper._rootWidget.setEnabled(True) # # TTkHelper._rootWidget._input.inputEvent.connect(TTkHelper._rootWidget._processInput) # ttk.TTkHelper._rootWidget._input.inputEvent.disconnect(self._processInput) - # widget = TTkTomInspector._findWidget(mevt,ttk.TTkHelper._rootWidget.rootLayout()) - # ttk.TTkLog.debug(f"{widget=}") - # if widget: - # self._makeDetail(widget) + # thing = TTkTomInspector._findWidget(mevt,ttk.TTkHelper._rootWidget.rootLayout()) + # ttk.TTkLog.debug(f"{thing=}") + # if thing: + # self._makeDetail(thing) # else: # self._detail = ttk.TTkFrame(title=f"None") # self._splitter.replaceWidget(1,self._detail) - # self._refresh(widget) + # self._refresh(thing) @ttk.pyTTkSlot() def _btnPickCb(self): @@ -84,33 +85,47 @@ class TreeInspector(ttk.TTkGridLayout): pass @ttk.pyTTkSlot() - def refresh(self, widget=None): + def refresh(self, thing=None): self._tomTree.clear() self._tomTree.addTopLevelItem(TreeInspector._getTomTreeItem(self._windowEditor.getTTk().widgetItem())) @staticmethod def _getTomTreeItem(layoutItem, widSelected=None): if layoutItem.layoutItemType == ttk.TTkK.WidgetItem: - superWidget = widget = layoutItem.widget() - if type(superWidget) is SuperWidget: - widget = widget._wid - expanded = True # ttk.TTkHelper.isParent(widSelected,widget) if widSelected else False - top = _TTkTomTreeWidgetItem([ - widget._name, widget.__class__.__name__, - str(widget.isVisible()), - widget.layout().__class__.__name__], - tomWidget=widget, - tomSuperWidget=superWidget, - expanded=expanded) - if issubclass(type(superWidget), SuperWidget): - for c in superWidget._superLayout.layout().children(): + superThing = thing = layoutItem.widget() + if issubclass(type(superThing), SuperWidget): + thing = thing._wid + elif issubclass(type(superThing), SuperLayout): + thing = thing._lay + expanded = True # ttk.TTkHelper.isParent(widSelected,thing) if widSelected else False + if issubclass(type(superThing), SuperWidget): + top = _TTkTomTreeWidgetItem([ + thing._name, thing.__class__.__name__, + str(thing.isVisible()), + thing.layout().__class__.__name__], + tomWidget=thing, + tomSuperWidget=superThing, + expanded=expanded) + elif issubclass(type(superThing), SuperLayout): + top = _TTkTomTreeWidgetItem([ + 'Layout', thing.__class__.__name__, + '', + thing.__class__.__name__], + tomWidget=thing, + tomSuperWidget=superThing, + expanded=expanded) + if issubclass(type(superThing), SuperWidget): + for c in superThing._superLayout.layout().children(): + top.addChild(TreeInspector._getTomTreeItem(c,widSelected)) + elif issubclass(type(superThing), SuperLayout): + for c in superThing.layout().children(): top.addChild(TreeInspector._getTomTreeItem(c,widSelected)) else: - for c in superWidget.layout().children(): + for c in superThing.layout().children(): top.addChild(TreeInspector._getTomTreeItem(c,widSelected)) - # for c in widget.rootLayout().children(): - # if c == widget.layout(): continue + # for c in thing.rootLayout().children(): + # if c == thing.layout(): continue # if c.layoutItemType == ttk.TTkK.LayoutItem: # top.addChild(tc:=_TTkTomTreeWidgetItem(["layout (Other)", c.__class__.__name__, ""])) # for cc in c.children(): diff --git a/ttkDesigner/app/windoweditor.py b/ttkDesigner/app/windoweditor.py index be123ae5..32fd7200 100644 --- a/ttkDesigner/app/windoweditor.py +++ b/ttkDesigner/app/windoweditor.py @@ -32,10 +32,10 @@ import TermTk as ttk class WindowEditorView(ttk.TTkAbstractScrollView): def __init__(self, *args, **kwargs): self.weModified = ttk.pyTTkSignal() - self.widgetSelected = ttk.pyTTkSignal(ttk.TTkWidget, ttk.TTkWidget) + self.thingSelected = ttk.pyTTkSignal(ttk.TTkWidget, ttk.TTkWidget) super().__init__(*args, **kwargs) self.viewChanged.connect(self._viewChangedHandler) - self._ttk = SuperWidget(wid=ttk.TTkWidget(name = 'TTk'), weModified=self.weModified, widgetSelected=self.widgetSelected, pos=(4,2), size=(self.width()-8,self.height()-4), superRootWidget=True) + self._ttk = SuperWidget(wid=ttk.TTkWidget(name = 'TTk'), weModified=self.weModified, thingSelected=self.thingSelected, pos=(4,2), size=(self.width()-8,self.height()-4), superRootWidget=True) self.layout().addWidget(self._ttk) def getTTk(self):