diff --git a/TermTk/TTkUiTools/properties/table.py b/TermTk/TTkUiTools/properties/table.py new file mode 100644 index 00000000..e917bdb6 --- /dev/null +++ b/TermTk/TTkUiTools/properties/table.py @@ -0,0 +1,66 @@ +# MIT License +# +# Copyright (c) 2024 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. + +__all__ = ['TTkTableProperties'] + +from TermTk.TTkCore.constant import TTkK +from TermTk.TTkWidgets.TTkModelView.table import TTkTable +from TermTk.TTkWidgets.TTkModelView.tablewidget import TTkTableWidget + + +TTkTableProperties = { + 'properties' : { + 'H-Separator' : { + 'init': {'name':'hSeparator', 'type':bool } , + 'get': { 'cb':TTkTableWidget.hSeparatorVisibility, 'type':bool, 'fw_obj':TTkTable.viewport } , + 'set': { 'cb':TTkTableWidget.setHSeparatorVisibility, 'type':bool, 'fw_obj':TTkTable.viewport } }, + 'V-Separator' : { + 'init': {'name':'vSeparator', 'type':bool } , + 'get': { 'cb':TTkTableWidget.vSeparatorVisibility, 'type':bool, 'fw_obj':TTkTable.viewport } , + 'set': { 'cb':TTkTableWidget.setVSeparatorVisibility, 'type':bool, 'fw_obj':TTkTable.viewport } }, + 'Sorting' : { + 'init': {'name':'sortingEnabled', 'type':bool } , + 'get': { 'cb':TTkTableWidget.isSortingEnabled, 'type':bool, 'fw_obj':TTkTable.viewport } , + 'set': { 'cb':TTkTableWidget.setSortingEnabled, 'type':bool, 'fw_obj':TTkTable.viewport } }, + },'signals' : { + 'cellChanged(int,int)' : {'name' : 'cellChanged' , 'type':(int, int)}, + 'cellClicked(int,int)' : {'name' : 'cellClicked' , 'type':(int, int)}, + 'cellDoubleClicked(int,int)' : {'name' : 'cellDoubleClicked' , 'type':(int, int)}, + 'cellEntered(int,int)' : {'name' : 'cellEntered' , 'type':(int, int)}, + 'currentCellChanged(int,int,int,int)' : {'name' : 'currentCellChanged', 'type':(int, int, int, int)}, + },'slots' : { + 'undo()' : {'name' : 'undo' , 'type': None }, + 'redo()' : {'name' : 'redo' , 'type': None }, + 'copy()' : {'name' : 'copy' , 'type': None }, + 'cut()' : {'name' : 'cut' , 'type': None }, + 'paste()' : {'name' : 'paste' , 'type': None }, + + 'setSortingEnabled(bool)' : {'name' : 'copy' , 'type': bool }, + 'sortByColumn(int,SortOrder)' : {'name' : 'copy' , 'type': (int,TTkK.SortOrder), }, + 'setColumnWidth(int,int)' : {'name' : 'copy' , 'type': (int,int) }, + 'resizeColumnToContents(int)' : {'name' : 'copy' , 'type': int }, + 'resizeColumnsToContents()' : {'name' : 'copy' , 'type': None }, + 'setRowHeight(int,int)' : {'name' : 'copy' , 'type': (int,int) }, + 'resizeRowToContents(int)' : {'name' : 'copy' , 'type': int }, + 'resizeRowsToContents()' : {'name' : 'copy' , 'type': None }, + } +} diff --git a/TermTk/TTkUiTools/uiproperties.py b/TermTk/TTkUiTools/uiproperties.py index 4dbf2c77..645cefdf 100644 --- a/TermTk/TTkUiTools/uiproperties.py +++ b/TermTk/TTkUiTools/uiproperties.py @@ -53,6 +53,10 @@ from .properties.texedit import * from .properties.widget import * from .properties.window import * +from .properties.table import * +# from .properties.tree import * +# from .properties.terminal import * + # Pickers from .properties.colorpicker import * from .properties.filepicker import * @@ -84,4 +88,6 @@ TTkUiProperties = { TTkFileButtonPicker.__name__ : TTkFileButtonPickerProperties, # Layouts TTkLayout.__name__: TTkLayoutProperties, + # Models + TTkTable.__name__: TTkTableProperties, } diff --git a/TermTk/TTkWidgets/TTkModelView/tablewidget.py b/TermTk/TTkWidgets/TTkModelView/tablewidget.py index 6f339224..1bf27670 100644 --- a/TermTk/TTkWidgets/TTkModelView/tablewidget.py +++ b/TermTk/TTkWidgets/TTkModelView/tablewidget.py @@ -819,7 +819,7 @@ class TTkTableWidget(TTkAbstractScrollView): self.update() return super().leaveEvent(evt) - @pyTTkSlot(int) + @pyTTkSlot(int,int) def setColumnWidth(self, column:int, width: int) -> None: ''' Sets the width of the given column. diff --git a/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py b/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py index a15823ef..6974a8d0 100644 --- a/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py +++ b/TermTk/TTkWidgets/TTkTerminal/terminalhelper.py @@ -198,9 +198,9 @@ class TTkTerminalHelper(): TTkTerminal ╔═══════╗ pty - ║ C:\ ║ --[ KeyPresses, MouseEvents, ResizeSignal, ... ]--> ┌────┈┄╶ + ║ C:\ ║ --[ KeyPresses, MouseEvents, ResizeSignal, ... ]--> ┌──── ── ─ ─ ║ ║ <---------[ Output, Ansi escape codes, ... ]------- │ bash, sh, ... - ╚═══════╝ └────┈┄╶ + ╚═══════╝ └──── ── ─ ─ .. caution:: Do not touch this! (unless you know what you are doing) ''' diff --git a/docs/source/index.rst b/docs/source/index.rst index 5903bfcc..ebeb6226 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -107,7 +107,8 @@ API Reference .. # :toctree: _autosummary .. # :template: custom-class-template.01.rst .. # -.. # TTkCore.TTkK +.. # TTkCore.pyTTkSignal +.. # TTkCore.pyTTkSlot .. # .. # TTkWidgets.TTkAppTemplate .. # TTkWidgets.TTkMenuBar diff --git a/tools/ttkDesigner/app/propertyeditor.py b/tools/ttkDesigner/app/propertyeditor.py index 527a6ada..96fa54e4 100644 --- a/tools/ttkDesigner/app/propertyeditor.py +++ b/tools/ttkDesigner/app/propertyeditor.py @@ -41,7 +41,7 @@ class PropertyEditor(ttk.TTkGridLayout): self._makeDetail(widget, *superWidget.getSuperProperties()) - def _makeDetail(self, domw, additions, exceptions, exclude): + def _makeDetail(self, domwBase, additions, exceptions, exclude): def _boundValue(_f,_w,_v): def _ret(): _f(_w,_v) @@ -77,7 +77,7 @@ class PropertyEditor(ttk.TTkGridLayout): # • Text │[X] 0x0001 # • Number │[ ] 0x0002 # • Password │[ ] 0x0004 - def _processMultiFlag(name, prop): + def _processMultiFlag(name, prop, domw): flags = prop['get']['flags'] ret = ttk.TTkTreeWidgetItem([name,f" - (0x{prop['get']['cb'](domw):04X})"],expanded=True) # value = ttk.TTkFrame(layout=ttk.TTkVBoxLayout(), height=len(flags), border=False) @@ -99,7 +99,7 @@ class PropertyEditor(ttk.TTkGridLayout): # ││Unchecked │ │ # ││Partially Checked │ │ # │└───────────────────┘ │ - def _processSingleFlag(name, prop): + def _processSingleFlag(name, prop, domw): flags = prop['get']['flags'] items = [(k,v) for k,v in flags.items()] if 'set' in prop: @@ -123,7 +123,7 @@ class PropertyEditor(ttk.TTkGridLayout): # { 'name': 'x', 'type':int } , # { 'name': 'y', 'type':int } ] } }, # - def _processList(name, prop): + def _processList(name, prop, domw): def _getter(_i, _p): def _ret(_w): return _p['get']['cb'](_w)[_i] @@ -146,42 +146,42 @@ class PropertyEditor(ttk.TTkGridLayout): 'set' : { 'cb': _setter(_i, prop), 'type':_prop['type'] } } # ret.addChild(ttk.TTkTreeWidgetItem([_prop['name'],f"{curVal[_i]}"])) - ret.addChild(_processProp(_prop['name'], _newProp)) + ret.addChild(_processProp(_prop['name'], _newProp, domw)) return ret # Dict Fields - def _processDict(name, prop): + def _processDict(name, prop, domw): curVal = prop['get']['cb'](domw) value = ttk.TTkLabel(text=f"{curVal} - TBD") ret = ttk.TTkTreeWidgetItem([name,value]) return ret # Boolean Fields - def _processBool(name, prop): + def _processBool(name, prop, domw): getval = prop['get']['cb'](domw) value = ttk.TTkCheckbox(text=f" {p}", checked=getval, height=1) value.stateChanged.connect(_bound(prop['set']['cb'],domw, lambda v:v==ttk.TTkK.Checked)) return ttk.TTkTreeWidgetItem([name,value]) # Integer Fields - def _processInt(name, prop): + def _processInt(name, prop, domw): getval = prop['get']['cb'](domw) value = ttk.TTkSpinBox(value=getval, height=1, maximum=0x10000, minimum=-0x10000) value.valueChanged.connect(_bound(prop['set']['cb'],domw,lambda v:v)) return ttk.TTkTreeWidgetItem([name,value]) # String Fields - def _processStr(name, prop): + def _processStr(name, prop, domw): getval = prop['get']['cb'](domw) value = ttk.TTkLineEdit(text=getval, height=len(getval.split('\n'))) value.textChanged.connect(_boundLineEdit(prop['set']['cb'],domw,value)) return ttk.TTkTreeWidgetItem([name,value]) # String Fields - def _processTTkString(name, prop, multiLine=True): + def _processTTkString(name, prop, domw, multiLine=True): getval = prop['get']['cb'](domw) value = ttk.TTkTextPicker(text=getval, height=len(getval.split('\n')), autoSize=True, multiLine=multiLine) value.textChanged.connect(_boundTextEdit(prop['set']['cb'],domw,value)) return ttk.TTkTreeWidgetItem([name,value]) # Color Fields - def _processTTkColor(name, prop): + def _processTTkColor(name, prop, domw): getval = prop['get']['cb'](domw) value = ttk.TTkContainer(layout=ttk.TTkHBoxLayout(), height=1) value.layout().addWidget(_cb := ttk.TTkColorButtonPicker(color=getval, height=1)) @@ -191,19 +191,19 @@ class PropertyEditor(ttk.TTkGridLayout): _rc.clicked.connect(lambda :_cb.setColor(ttk.TTkColor.RST)) return ttk.TTkTreeWidgetItem([name,value]) # Layout field - def _processTTkLayout(name, prop): + def _processTTkLayout(name, prop, domw): value = ttk.TTkComboBox(list=['TTkLayout','TTkGridLayout','TTkHBoxLayout','TTkVBoxLayout'], height=1) value.setCurrentText(prop['get']['cb'](domw).__class__.__name__) value.currentTextChanged.connect(_bound(prop['set']['cb'],domw, lambda v:globals()[v]())) return ttk.TTkTreeWidgetItem([name,value]) # Add a button Control - def _processButton(name, prop): + def _processButton(name, prop, domw): value = ttk.TTkButton(text=f" {prop['get']['text']}", border=False) value.clicked.connect(lambda :prop['get']['cb'](domw)) return ttk.TTkTreeWidgetItem([name,value]) # Unrecognised Field - def _processUnknown(name, prop): + def _processUnknown(name, prop, domw): getval = prop['get']['cb'](domw) if type(prop['get']['type']) == str: getval = f"{prop['get']['type']} = {getval}" @@ -212,38 +212,40 @@ class PropertyEditor(ttk.TTkGridLayout): value = ttk.TTkLabel(minSize=(30,1), maxHeight=1, text=f"{getval}", height=1) return ttk.TTkTreeWidgetItem([name,value]) - def _processProp(name, prop): + def _processProp(name, prop, domw): + if 'fw_obj' in prop['get']: + domw = prop['get']['fw_obj'](domw) if 'get' in prop: if prop['get']['type'] == 'multiflags': - return _processMultiFlag(name, prop) + return _processMultiFlag(name, prop, domw) elif prop['get']['type'] == 'singleflag': - return _processSingleFlag(name, prop) + return _processSingleFlag(name, prop, domw) elif prop['get']['type'] == bool and 'set' in prop: - return _processBool(name, prop) + return _processBool(name, prop, domw) elif prop['get']['type'] == int and 'set' in prop: - return _processInt(name, prop) + return _processInt(name, prop, domw) elif prop['get']['type'] == str and 'set' in prop: - return _processStr(name, prop) + return _processStr(name, prop, domw) elif prop['get']['type'] == ttk.TTkString and 'set' in prop: - return _processTTkString(p,prop,multiLine=True) + return _processTTkString(p,prop,domw,multiLine=True) elif prop['get']['type'] == 'singleLineTTkString': - return _processTTkString(p,prop,multiLine=False) + return _processTTkString(p,prop,domw,multiLine=False) elif prop['get']['type'] == ttk.TTkColor and 'set' in prop: - return _processTTkColor(name, prop) + return _processTTkColor(name, prop, domw) elif prop['get']['type'] == ttk.TTkLayout and 'set' in prop: - return _processTTkLayout(name, prop) + return _processTTkLayout(name, prop, domw) elif type(prop['get']['type']) == list: - return _processList(name, prop) + return _processList(name, prop, domw) elif type(prop['get']['type']) == dict: - return _processDict(name, prop) + return _processDict(name, prop, domw) elif prop['get']['type'] == 'button': - return _processButton(p,prop) + return _processButton(p, prop, domw) else: - return _processUnknown(name, prop) + return _processUnknown(name, prop, domw) proplist = exclude self._detail.clear() - for cc in reversed(type(domw).__mro__): + for cc in reversed(type(domwBase).__mro__): # if hasattr(cc,'_ttkProperties'): if issubclass(cc, ttk.TTkWidget) or issubclass(cc, ttk.TTkLayout): ccName = cc.__name__ @@ -254,7 +256,7 @@ class PropertyEditor(ttk.TTkGridLayout): for p in additions[ccName]: if p not in proplist: proplist.append(p) - classItem.addChild(_processProp(p, additions[ccName][p])) + classItem.addChild(_processProp(p, additions[ccName][p], domwBase)) for p in ttk.TTkUiProperties[ccName]['properties']: if p in exceptions: prop = exceptions[p] @@ -262,4 +264,4 @@ class PropertyEditor(ttk.TTkGridLayout): prop = ttk.TTkUiProperties[ccName]['properties'][p] if p not in proplist: proplist.append(p) - classItem.addChild(_processProp(p, prop)) + classItem.addChild(_processProp(p, prop, domwBase)) diff --git a/tools/ttkDesigner/app/superobj/superobj.py b/tools/ttkDesigner/app/superobj/superobj.py index a2e4674f..227c1f8f 100644 --- a/tools/ttkDesigner/app/superobj/superobj.py +++ b/tools/ttkDesigner/app/superobj/superobj.py @@ -65,19 +65,22 @@ class SuperObject(): prop = ttk.TTkUiProperties[ccName]['properties'][p] propType = prop['get']['type'] propCb = prop['get']['cb'] + objCb = obj + if 'fw_obj' in prop['get']: + objCb = prop['get']['fw_obj'](objCb) # ttk.TTkLog.debug(ccName) if propType in (int,str,float,bool): - params |= {p: _dumpPrimitive(propCb(obj))} + params |= {p: _dumpPrimitive(propCb(objCb))} elif type(propType) in (list,tuple): - params |= {p: _dumpList(propCb(obj), propType)} + params |= {p: _dumpList(propCb(objCb), propType)} elif propType is ttk.TTkLayout: - params |= {p: _dumpTTkLayout(propCb(obj))} + params |= {p: _dumpTTkLayout(propCb(objCb))} elif propType in (ttk.TTkString,'singleLineTTkString'): - params |= {p: _dumpTTkString(propCb(obj))} + params |= {p: _dumpTTkString(propCb(objCb))} elif propType is ttk.TTkColor: - params |= {p: _dumpTTkColor(propCb(obj))} + params |= {p: _dumpTTkColor(propCb(objCb))} elif propType in ('singleflag','multiflags'): - params |= {p: _dumpFlag(propCb(obj))} + params |= {p: _dumpFlag(propCb(objCb))} else: ttk.TTkLog.warn("Type not Recognised") return params diff --git a/tools/ttkDesigner/app/superobj/superwidgetabstractscrollarea.py b/tools/ttkDesigner/app/superobj/superwidgetabstractscrollarea.py index bcf33ad8..7db84bbd 100644 --- a/tools/ttkDesigner/app/superobj/superwidgetabstractscrollarea.py +++ b/tools/ttkDesigner/app/superobj/superwidgetabstractscrollarea.py @@ -39,6 +39,6 @@ class SuperWidgetAbstractScrollArea(so.SuperWidgetContainer): wid = self._wid ret = { 'class' : wid.__class__.__name__, - 'params' : SuperObject.dumpParams(wid,exclude=['Layout','Padding']), + 'params' : SuperObject.dumpParams(obj=wid, exclude=['Layout','Padding']), } return ret diff --git a/tools/ttkDesigner/app/widgetbox.py b/tools/ttkDesigner/app/widgetbox.py index a8002313..ac11de9b 100644 --- a/tools/ttkDesigner/app/widgetbox.py +++ b/tools/ttkDesigner/app/widgetbox.py @@ -65,6 +65,9 @@ dWidgets = { "Tab Widget" : { "class":ttk.TTkTabWidget, "params":{'size':(20,3)}, "disabled": True}, "Widget" : { "class":ttk.TTkWidget, "params":{'size':(20,5)}}, }, + 'Model View':{ + "Table" : { "class":ttk.TTkTable, "params":{'size':( 20,5)}}, + }, 'Pickers':{ "Color Picker" : { "class":ttk.TTkColorButtonPicker, "params":{'size':( 6,3), 'border':True}}, "Color Picker Slim": { "class":ttk.TTkColorButtonPicker, "params":{'size':( 6,1), 'border':False}},