Browse Source

Finalised signal/slot editor in ttkDesigner

pull/99/head
Eugenio Parodi 3 years ago
parent
commit
9a5984c1ba
  1. 6
      TermTk/TTkUiTools/properties/checkbox.py
  2. 18
      TermTk/TTkUiTools/properties/widget.py
  3. 39
      TermTk/TTkUiTools/uiloader.py
  4. 5
      TermTk/TTkWidgets/widget.py
  5. 0
      tests/timeit/11.signals.slots.01.py
  6. 81
      tests/timeit/11.signals.slots.02.py
  7. 103
      tests/timeit/11.signals.slots.03.py
  8. 17
      ttkDesigner/app/designer.py
  9. 35
      ttkDesigner/app/signalsloteditor.py
  10. 12
      ttkDesigner/app/windoweditor.py

6
TermTk/TTkUiTools/properties/checkbox.py

@ -61,8 +61,8 @@ TTkCheckboxProperties = {
'stateChanged(CheckState)' : {'name' : 'stateChanged', 'type' : TTkK.CheckState},
},
'slots' : {
'setChecked(bool)' : {'cb' : TTkCheckbox.setChecked , 'type' : bool},
'setCheckState(CheckState)' : {'cb' : TTkCheckbox.setCheckState , 'type' : TTkK.CheckState},
'setText(str)' : {'cb' : TTkCheckbox.setText , 'type' : str}
'setChecked(bool)' : {'name' : 'setChecked' , 'type' : bool},
'setCheckState(CheckState)' : {'name' : 'setCheckState' , 'type' : TTkK.CheckState},
'setText(str)' : {'name' : 'setText' , 'type' : str}
}
}

18
TermTk/TTkUiTools/properties/widget.py

@ -108,14 +108,14 @@ TTkWidgetProperties = {
'focusChanged(bool)' : {'name' : 'focusChanged', 'type':bool},
'sizeChanged(int,int)' : {'name' : 'sizeChanged', 'type':(int, int)}
},'slots' : {
'show()' : {'cb': TTkWidget.show, 'type':None},
'hide()' : {'cb': TTkWidget.hide, 'type':None},
'close()' : {'cb': TTkWidget.close, 'type':None},
'setFocus()' : {'cb': TTkWidget.setFocus, 'type':None},
'setVisible(bool)' : {'cb': TTkWidget.setVisible, 'type':bool},
'setEnabled(bool)': {'cb': TTkWidget.setEnabled, 'type':bool},
'setDisabled(bool)': {'cb': TTkWidget.setDisabled,'type':bool},
'raiseWidget()' : {'cb': TTkWidget.raiseWidget,'type':None},
'lowerWidget()' : {'cb': TTkWidget.lowerWidget,'type':None},
'show()' : {'name': 'show', 'type':None},
'hide()' : {'name': 'hide', 'type':None},
'close()' : {'name': 'close', 'type':None},
'setFocus()' : {'name': 'setFocus', 'type':None},
'setVisible(bool)' : {'name': 'setVisible', 'type':bool},
'setEnabled(bool)': {'name': 'setEnabled', 'type':bool},
'setDisabled(bool)': {'name': 'setDisabled', 'type':bool},
'raiseWidget()' : {'name': 'raiseWidget', 'type':None},
'lowerWidget()' : {'name': 'lowerWidget', 'type':None},
}
}

39
TermTk/TTkUiTools/uiloader.py

@ -33,6 +33,10 @@ from TermTk.TTkUiTools.uiproperties import TTkUiProperties
class TTkUiLoader():
@staticmethod
def loadJson(text):
return TTkUiLoader.loadDict(json.loads(text))
@staticmethod
def loadDict(ui):
def _getWidget(widProp):
properties = {}
ttkClass = globals()[widProp['class']]
@ -137,10 +141,39 @@ class TTkUiLoader():
layout.addWidget(w)
return layout
widgetProperty = json.loads(text)
TTkLog.debug(widgetProperty)
TTkLog.debug(ui)
widget = _getWidget(ui['tui'])
def _getSignal(sender, name):
for cc in reversed(type(sender).__mro__):
if cc.__name__ in TTkUiProperties:
if not name in TTkUiProperties[cc.__name__]['signals']:
continue
signame = TTkUiProperties[cc.__name__]['signals'][name]['name']
return getattr(sender,signame)
return None
def _getSlot(receiver, name):
for cc in reversed(type(receiver).__mro__):
if cc.__name__ in TTkUiProperties:
if not name in TTkUiProperties[cc.__name__]['slots']:
continue
slotname = TTkUiProperties[cc.__name__]['slots'][name]['name']
return getattr(receiver,slotname)
return None
for conn in ui['connections']:
sender = widget.getWidgetByName(conn['sender'])
receiver = widget.getWidgetByName(conn['receiver'])
signal = conn['signal']
slot = conn['slot']
if None in (sender,receiver): continue
_getSignal(sender,signal).connect(_getSlot(receiver,slot))
return widget
return _getWidget(widgetProperty)

5
TermTk/TTkWidgets/widget.py

@ -712,3 +712,8 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
def setToolTip(self, toolTip):
self._toolTip = toolTip
def getWidgetByName(self, name):
for w in self.rootLayout().iterWidgets(onlyVisible=False, recurse=True):
if w._name == name:
return w
return None

0
tests/timeit/11.signals.slots.py → tests/timeit/11.signals.slots.01.py

81
tests/timeit/11.signals.slots.02.py

@ -0,0 +1,81 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys, os
import timeit
import random
import unicodedata
sys.path.append(os.path.join(sys.path[0],'../..'))
sys.path.append(os.path.join(sys.path[0],'.'))
import TermTk as ttk
def f1(a): return a
def f2(a,b): return a+b
def f3(a,b,c): return a+b+c
def f4(a,b,c,d): return a+b+c+d
def c1(*args,**argv): return f1(*args[:1])
def c2(*args,**argv): return f2(*args[:2])
def c3(*args,**argv): return f3(*args[:3])
def c4(*args,**argv): return f4(*args[:4])
def d1(*args,**argv): return f1(*args)
def d2(*args,**argv): return f2(*args)
def d3(*args,**argv): return f3(*args)
def d4(*args,**argv): return f4(*args)
def test1(v): return d1(1)
def test2(v): return d2(1,2)
def test3(v): return d3(1,2,3)
def test4(v): return d4(1,2,3,4)
def test5(v): return c1(1,2,3,4)
def test6(v): return c2(1,2,3,4)
def test7(v): return c3(1,2,3,4)
def test8(v): return c4(1,2,3,4)
loop = 200000
a=1
result = timeit.timeit('test1(a)', globals=globals(), number=loop)
print(f"1a s {result / loop:.10f} - {result / loop} {test1(a)}")
result = timeit.timeit('test2(a)', globals=globals(), number=loop)
print(f"2a {result / loop:.10f} - {result / loop} {test2(a)}")
result = timeit.timeit('test3(a)', globals=globals(), number=loop)
print(f"3a s {result / loop:.10f} - {result / loop} {test3(a)}")
result = timeit.timeit('test4(a)', globals=globals(), number=loop)
print(f"4a {result / loop:.10f} - {result / loop} {test4(a)}")
result = timeit.timeit('test5(a)', globals=globals(), number=loop)
print(f"5a s {result / loop:.10f} - {result / loop} {test5(a)}")
result = timeit.timeit('test6(a)', globals=globals(), number=loop)
print(f"6a {result / loop:.10f} - {result / loop} {test6(a)}")
result = timeit.timeit('test7(a)', globals=globals(), number=loop)
print(f"7a s {result / loop:.10f} - {result / loop} {test7(a)}")
result = timeit.timeit('test8(a)', globals=globals(), number=loop)
print(f"8a {result / loop:.10f} - {result / loop} {test8(a)}")

103
tests/timeit/11.signals.slots.03.py

@ -0,0 +1,103 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys, os
import timeit
import random
import unicodedata
sys.path.append(os.path.join(sys.path[0],'../..'))
sys.path.append(os.path.join(sys.path[0],'.'))
import TermTk as ttk
def f1(a): return a
def f2(a,b): return a+b
def f3(a,b,c): return a+b+c
def f4(a,b,c,d): return a+b+c+d
ccb = {f1:1, f2:2, f3:3, f4:4}
def c1(*args,**argv): return f1(*args[:1])
def c2(*args,**argv): return f2(*args[:2])
def c3(*args,**argv): return f3(*args[:3])
def c4(*args,**argv): return f4(*args[:4])
def d1(*args,**argv): return f1(*args)
def d2(*args,**argv): return f2(*args)
def d3(*args,**argv): return f3(*args)
def d4(*args,**argv): return f4(*args)
def e1(*args,**argv):
f1(1)
f2(1,2)
f3(1,2,3)
f4(1,2,3,4)
def e2(*args,**argv):
for cb in ccb:
nargs = ccb[cb]
cb(*args[:nargs])
def e3(*args,**argv):
for cb in ccb.copy():
nargs = ccb[cb]
cb(*args[:nargs])
def e4(*args,**argv):
for cb,n in ccb.copy().items():
cb(*args[:n])
def test1(v): return d1(1)
def test2(v): return d2(1,2)
def test3(v): return d3(1,2,3)
def test4(v): return d4(1,2,3,4)
def test5(v): return e1(1,2,3,4)
def test6(v): return e2(1,2,3,4)
def test7(v): return e3(1,2,3,4)
def test8(v): return e4(1,2,3,4)
loop = 200000
a=1
result = timeit.timeit('test1(a)', globals=globals(), number=loop)
print(f"1a s {result / loop:.10f} - {result / loop} {test1(a)}")
result = timeit.timeit('test2(a)', globals=globals(), number=loop)
print(f"2a {result / loop:.10f} - {result / loop} {test2(a)}")
result = timeit.timeit('test3(a)', globals=globals(), number=loop)
print(f"3a s {result / loop:.10f} - {result / loop} {test3(a)}")
result = timeit.timeit('test4(a)', globals=globals(), number=loop)
print(f"4a {result / loop:.10f} - {result / loop} {test4(a)}")
result = timeit.timeit('test5(a)', globals=globals(), number=loop)
print(f"5a s {result / loop:.10f} - {result / loop} {test5(a)}")
result = timeit.timeit('test6(a)', globals=globals(), number=loop)
print(f"6a {result / loop:.10f} - {result / loop} {test6(a)}")
result = timeit.timeit('test7(a)', globals=globals(), number=loop)
print(f"7a s {result / loop:.10f} - {result / loop} {test7(a)}")
result = timeit.timeit('test8(a)', globals=globals(), number=loop)
print(f"8a {result / loop:.10f} - {result / loop} {test8(a)}")

17
ttkDesigner/app/designer.py

@ -20,6 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import json
from TermTk import TTk, TTkK, TTkLog, TTkCfg, TTkColor, TTkTheme, TTkTerm, TTkHelper
from TermTk import TTkString
from TermTk import TTkColorGradient
@ -72,7 +74,7 @@ from .signalsloteditor import SignalSlotEditor
#
class TTkDesigner(TTkGridLayout):
__slots__ = ('_pippo', '_main', '_windowEditor', '_toolBar')
__slots__ = ('_pippo', '_main', '_windowEditor', '_toolBar', '_sigslotEditor')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -88,10 +90,9 @@ class TTkDesigner(TTkGridLayout):
# sa.viewport().layout().addWidget(WindowEditor())
self._main = TTkVBoxLayout()
self._toolBar = TTkHBoxLayout()
self._windowEditor = WindowEditor()
self._sigslotEditor = SignalSlotEditor(self._windowEditor.viewport())
self._main.addItem(self._toolBar)
self._main.addWidget(self._windowEditor)
@ -100,14 +101,14 @@ class TTkDesigner(TTkGridLayout):
centralSplit.addWidget(self._main)
centralSplit.addWidget(bottonTabWidget := TTkTabWidget(border=False))
# centralSplit.addWidget(TTkLogViewer())
bottonTabWidget.addTab(sigslotEditor := SignalSlotEditor(self._windowEditor.viewport()),'Signal/Slot Editor')
bottonTabWidget.addTab(self._sigslotEditor,'Signal/Slot Editor')
bottonTabWidget.addTab(TTkLogViewer(),'Logs')
mainSplit.addWidget(rightSplit := TTkSplitter(orientation=TTkK.VERTICAL))
rightSplit.addItem(treeInspector := TreeInspector(self._windowEditor.viewport()))
rightSplit.addItem(propertyEditor := PropertyEditor())
# rightSplit.addItem(sigslotEditor := SignalSlotEditor(self._windowEditor.viewport()))
# rightSplit.addItem(self._sigslotEditor)
treeInspector.thingSelected.connect(lambda _,s : s.pushSuperControlWidget())
treeInspector.thingSelected.connect(propertyEditor.setDetail)
@ -160,9 +161,13 @@ class TTkDesigner(TTkGridLayout):
SuperWidget.toggleHighlightLayout.emit(state)
def preview(self, btn=None):
jj = self._windowEditor.getJson()
tui = self._windowEditor.dumpDict()
connections = self._sigslotEditor.dumpDict()
# for line in jj.split('\n'):
# TTkLog.debug(f"{line}")
newUI = {'tui':tui,'connections':connections}
jj = json.dumps(newUI, indent=1)
widget = TTkUiLoader.loadJson(jj)
win = TTkWindow(
title="Mr Terminal",

35
ttkDesigner/app/signalsloteditor.py

@ -43,6 +43,35 @@ class _SignalSlotItem(ttk.TTkTreeWidgetItem):
self.updateWidgets()
super().__init__([self._sender,self._signal,self._receiver,self._slot], *args, **kwargs)
def isValid(self):
curSender = str(self._sender.currentText())
curReceiver = str(self._receiver.currentText())
curSignal = str(self._signal.currentText())
curSlot = str(self._slot.currentText())
if curSender=='<sender>' or curReceiver == '<receiver>':
return False
ret = False
for ccName in self._signalData:
if curSignal in self._signalData[ccName]:
ret = True
break
for ccName in self._slotData:
if curSlot in self._slotData[ccName]:
ret &= True
break
return ret
def dumpDict(self):
curSender = str(self._sender.currentText())
curReceiver = str(self._receiver.currentText())
curSignal = str(self._signal.currentText())
curSlot = str(self._slot.currentText())
return {
'sender': curSender,
'receiver': curReceiver,
'signal': curSignal,
'slot': curSlot }
def updateWidgets(self):
names = [w.name() for w in self._getWidgets()]
self._sender.addItems(names)
@ -173,3 +202,9 @@ class SignalSlotEditor(ttk.TTkWidget):
self._items.append(item)
self._detail.addTopLevelItem(item)
def dumpDict(self):
ret = []
for i in self._items:
if i.isValid():
ret.append(i.dumpDict())
return ret

12
ttkDesigner/app/windoweditor.py

@ -20,10 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Yaml is not included by default
# import yaml
import json
from .superobj import SuperWidget
import TermTk as ttk
@ -41,8 +37,8 @@ class WindowEditorView(ttk.TTkAbstractScrollView):
def getTTk(self):
return self._ttk
def getJson(self):
return json.dumps(self._ttk.dumpDict(), indent=1)
def dumpDict(self):
return self._ttk.dumpDict()
def resizeEvent(self, w, h):
self._ttk.resize(w-8,h-4)
@ -68,5 +64,5 @@ class WindowEditor(ttk.TTkAbstractScrollArea):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setViewport(wev := WindowEditorView())
self.getTTk = wev.getTTk
self.getJson = wev.getJson
self.getTTk = wev.getTTk
self.dumpDict = wev.dumpDict

Loading…
Cancel
Save