Browse Source

Added TTkAbstractScrollViewGridLayout

pull/63/head
Eugenio Parodi 3 years ago
parent
commit
c9491dd8ab
  1. 5
      TermTk/TTkAbstract/__init__.py
  2. 14
      TermTk/TTkAbstract/abstractscrollarea.py
  3. 109
      TermTk/TTkAbstract/abstractscrollview.py
  4. 8
      TermTk/TTkLayouts/layout.py
  5. 7
      TermTk/TTkTestWidgets/__init__.py
  6. 66
      TermTk/TTkTestWidgets/testabstractscroll.py
  7. 2
      TermTk/TTkWidgets/TTkModelView/treewidget.py
  8. 71
      tests/test.metaclass.001.py
  9. 59
      tests/test.ui.021.abstractscroll.01.py
  10. 66
      tests/test.ui.021.abstractscroll.02.py

5
TermTk/TTkAbstract/__init__.py

@ -1,2 +1,3 @@
from .abstractscrollarea import *
from .abstractitemmodel import *
from .abstractscrollview import TTkAbstractScrollViewInterface, TTkAbstractScrollView, TTkAbstractScrollViewGridLayout
from .abstractscrollarea import TTkAbstractScrollArea
from .abstractitemmodel import TTkAbstractItemModel

14
TermTk/TTkAbstract/abstractscrollarea.py

@ -28,7 +28,7 @@ from TermTk.TTkCore.signal import pyTTkSlot
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollViewInterface
class TTkAbstractScrollArea(TTkWidget):
__slots__ = (
@ -39,7 +39,6 @@ class TTkAbstractScrollArea(TTkWidget):
def __init__(self, *args, **kwargs):
self._viewport = None
super().__init__(*args, **kwargs)
self._name = kwargs.get('name' , 'TTkAbstractScrollArea')
self.setLayout(TTkGridLayout())
self._verticalScrollBar = TTkScrollBar(orientation=TTkK.VERTICAL)
self._horizontalScrollBar = TTkScrollBar(orientation=TTkK.HORIZONTAL)
@ -99,13 +98,18 @@ class TTkAbstractScrollArea(TTkWidget):
self._viewport.viewMoveTo(val, oy)
def setViewport(self, viewport):
if not isinstance(viewport, TTkAbstractScrollView):
raise TypeError("TTkAbstractScrollView is required in TTkAbstractScrollArea.setVewport(viewport)")
if not isinstance(viewport, TTkAbstractScrollViewInterface):
raise TypeError("TTkAbstractScrollViewInterface is required in TTkAbstractScrollArea.setVewport(viewport)")
self._viewport = viewport
self._viewport.viewChanged.connect(self._viewportChanged)
self._verticalScrollBar.sliderMoved.connect(self._vscrollMoved)
self._horizontalScrollBar.sliderMoved.connect(self._hscrollMoved)
self.layout().addWidget(viewport,0,0)
# TODO: Remove this check once
# unified "addWidget" and "addItem" in the TTKGridLayout
if isinstance(viewport, TTkWidget):
self.layout().addWidget(viewport,0,0)
else:
self.layout().addItem(viewport,0,0)
self.layout().addWidget(self._verticalScrollBar,0,1)
self.layout().addWidget(self._horizontalScrollBar,1,0)

109
TermTk/TTkAbstract/abstractscrollview.py

@ -23,11 +23,28 @@
# SOFTWARE.
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
class TTkAbstractScrollView(TTkWidget):
class TTkAbstractScrollViewInterface():
# Override this function
def viewFullAreaSize(self) -> (int, int):
raise NotImplementedError()
# Override this function
def viewDisplayedSize(self) -> (int, int):
raise NotImplementedError()
@pyTTkSlot(int, int)
def viewMoveTo(self, x, y):
raise NotImplementedError()
def getViewOffsets(self):
return self._viewOffsetX, self._viewOffsetY
class TTkAbstractScrollView(TTkWidget, TTkAbstractScrollViewInterface):
__slots__ = (
'_viewOffsetX', '_viewOffsetY',
# Signals
@ -38,23 +55,13 @@ class TTkAbstractScrollView(TTkWidget):
self.viewMovedTo = pyTTkSignal(int, int) # x, y
self.viewSizeChanged = pyTTkSignal(int, int) # w, h
self.viewChanged = pyTTkSignal()
super().__init__(*args, **kwargs)
self._name = kwargs.get('name' , 'TTkAbstractScrollView')
TTkWidget.__init__(self, *args, **kwargs)
self._viewOffsetX = 0
self._viewOffsetY = 0
# Override this function
def viewFullAreaSize(self) -> (int, int):
raise NotImplementedError()
# Override this function
def viewDisplayedSize(self) -> (int, int):
raise NotImplementedError()
@pyTTkSlot(int, int)
def viewMoveTo(self, x, y):
fw, fh = self.viewFullAreaSize()
fw, fh = self.viewFullAreaSize()
dw, dh = self.viewDisplayedSize()
rangex = fw - dw
rangey = fh - dh
@ -84,6 +91,76 @@ class TTkAbstractScrollView(TTkWidget):
self.viewSizeChanged.emit(w,h)
self.viewChanged.emit()
def getViewOffsets(self):
return self._viewOffsetX, self._viewOffsetY
class TTkAbstractScrollViewGridLayout(TTkGridLayout, TTkAbstractScrollViewInterface):
__slots__ = (
'_viewOffsetX', '_viewOffsetY',
# Signals
'viewMovedTo', 'viewSizeChanged', 'viewChanged')
def __init__(self, *args, **kwargs):
# Signals
self.viewMovedTo = pyTTkSignal(int, int) # x, y
self.viewSizeChanged = pyTTkSignal(int, int) # w, h
self.viewChanged = pyTTkSignal()
TTkGridLayout.__init__(self, *args, **kwargs)
self._viewOffsetX = 0
self._viewOffsetY = 0
@pyTTkSlot(int, int)
def viewMoveTo(self, x, y):
fw, fh = self.viewFullAreaSize()
dw, dh = self.viewDisplayedSize()
rangex = fw - dw
rangey = fh - dh
# TTkLog.debug(f"x:{x},y:{y}, full:{fw,fh}, display:{dw,dh}, range:{rangex,rangey}")
x = max(0,min(rangex,x))
y = max(0,min(rangey,y))
# TTkLog.debug(f"x:{x},y:{y}, wo:{self._viewOffsetX,self._viewOffsetY}")
if self._viewOffsetX == x and \
self._viewOffsetY == y: # Nothong to do
return
for widget in self.iterWidgets():
widget.viewMoveTo(x,y)
self._viewOffsetX = x
self._viewOffsetY = y
self.viewMovedTo.emit(x,y)
self.viewChanged.emit()
self.update()
def setGeometry(self, x, y, w, h):
TTkGridLayout.setGeometry(self, x, y, w, h)
self.viewChanged.emit()
def _viewChanged(self):
pass
#self.viewChanged.emit()
def addWidget(self, widget, row=None, col=None, rowspan=1, colspan=1):
if not issubclass(type(widget),TTkAbstractScrollViewInterface):
raise TypeError("TTkAbstractScrollViewInterface is required in TTkAbstractScrollViewGridLayout.addWidget(...)")
widget.viewChanged.connect(self._viewChanged)
return TTkGridLayout.addWidget(self, widget, row, col, rowspan, colspan)
def addItem(self, item, row=None, col=None, rowspan=1, colspan=1):
if not issubclass(type(item),TTkAbstractScrollViewInterface):
raise TypeError("TTkAbstractScrollViewInterface is required in TTkAbstractScrollViewGridLayout.addItem(...)")
return TTkGridLayout.addItem(self, item, row, col, rowspan, colspan)
# Override this function
def viewFullAreaSize(self) -> (int, int):
w,h=0,0
for widget in self.iterWidgets():
ww,wh = widget.viewFullAreaSize()
w = max(w,ww)
h = max(h,wh)
return w,h
# Override this function
def viewDisplayedSize(self) -> (int, int):
w,h=0,0
for widget in self.iterWidgets():
ww,wh = widget.viewDisplayedSize()
w = max(w,ww)
h = max(h,wh)
return w,h

8
TermTk/TTkLayouts/layout.py

@ -220,6 +220,10 @@ class TTkLayout(TTkLayoutItem):
self.insertItem(len(self._items),item)
def insertItem(self, index, item):
if not issubclass(type(widget := item), TTkLayoutItem):
if widget.parentWidget() and widget.parentWidget().layout():
widget.parentWidget().layout().removeWidget(self)
item = widget.widgetItem()
self._items.insert(index, item)
self._zSortItems()
self.update()
@ -238,9 +242,7 @@ class TTkLayout(TTkLayoutItem):
self.insertWidget(len(self._items),widget)
def insertWidget(self, index, widget):
if widget.parentWidget() and widget.parentWidget().layout():
widget.parentWidget().layout().removeWidget(self)
self.insertItem(index, widget.widgetItem())
self.insertItem(index, widget)
def removeItem(self, item):
if item in self._items:

7
TermTk/TTkTestWidgets/__init__.py

@ -1,4 +1,5 @@
from .logviewer import *
from .testwidget import *
from .testwidgetsizes import *
from .logviewer import TTkLogViewer
from .testwidget import TTkTestWidget
from .testwidgetsizes import TTkTestWidgetSizes
from .testabstractscroll import TTkTestAbstractScrollWidget
from .keypressview import TTkKeyPressView

66
TermTk/TTkTestWidgets/testabstractscroll.py

@ -0,0 +1,66 @@
#!/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.
from TermTk.TTkCore.signal import pyTTkSlot
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
class TTkTestAbstractScrollWidget(TTkAbstractScrollView):
ID = 1
__slots__ = ('_areaPos','_areaSize')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._name = kwargs.get('name' , f"TTkTestAbstractScrollWidget-{TTkTestAbstractScrollWidget.ID}" )
self._areaSize = kwargs.get('areaSize',(10,10))
self._areaPos = kwargs.get('areaPos',(0,0))
TTkTestAbstractScrollWidget.ID+=1
self.viewChanged.connect(self._viewChangedHandler)
@pyTTkSlot()
def _viewChangedHandler(self):
self._areaPos = self.getViewOffsets()
self.update()
def paintEvent(self):
self._canvas.drawBox(pos=(0,0),size=(self._width,self._height))
t,_,l,_ = self.getPadding()
self._canvas.drawText(pos=(l+1,t+1+0), text=f"Test Widget [{self._name}]")
self._canvas.drawText(pos=(l+1,t+1+1), text=f"x,y ({self._x},{self._y})")
self._canvas.drawText(pos=(l+1,t+1+2), text=f"w,h ({self._width},{self._height})")
self._canvas.drawText(pos=(l+1,t+1+3), text=f"max w,h ({self._maxw},{self._maxh})")
self._canvas.drawText(pos=(l+1,t+1+4), text=f"min w,h ({self._minw},{self._minh})")
self._canvas.drawText(pos=(l+1,t+1+5), text=f"areaSize {self._areaSize}")
self._canvas.drawText(pos=(l+1,t+1+6), text=f"areaPos1 {self._areaPos}")
self._canvas.drawText(pos=(l+1,t+1+7), text=f"areaPos2 ({self._areaPos[0]+self._width},{self._areaPos[1]+self._height})")
def mousePressEvent(self, evt): return True
def mouseReleaseEvent(self, evt): return True
def viewFullAreaSize(self) -> (int, int):
return self._areaSize
def viewDisplayedSize(self) -> (int, int):
return self.size()

2
TermTk/TTkWidgets/TTkModelView/treewidget.py

@ -25,7 +25,7 @@
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkWidgets.TTkModelView.treewidgetitem import TTkTreeWidgetItem
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollView
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from dataclasses import dataclass

71
tests/test.metaclass.001.py

@ -0,0 +1,71 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2022 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.
class A_Meta(type):
def __new__(mcs, name, bases, d):
print(f"{mcs=}")
print(f"{name=}")
print(f"{bases=}")
print(f"{d=}")
return type.__new__(mcs, name, bases, d)
class A(metaclass=A_Meta):
def __init__(self, *args, **kwargs):
pass
def test(self):
pass
print(f"{A=}")
a = A(1,2,3,4)
print(f"{a=}\n")
class B(A_Meta):
def __init__(self, *args, **kwargs):
pass
def test(self):
pass
b = B("NB",(),{})
print(f"{b=}\n")
class C():
def __init__(self) -> None:
print(f"C {type(self)=}")
class D():
def __init__(self) -> None:
print(f"D {type(self)=}")
class E(C,D):
def __init__(self) -> None:
print(f"{super()=}")
super().__init__()
def pippo(self):
print(f"{super()=}")
e = E()
e.pippo()
print(f"{issubclass(E,D)=} {issubclass(E,C)=}")

59
tests/test.ui.021.abstractscroll.01.py

@ -0,0 +1,59 @@
#!/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, argparse, math, random
sys.path.append(os.path.join(sys.path[0],'..'))
import TermTk as ttk
class ScrollAreaTest(ttk.TTkAbstractScrollArea):
__slots__ = ('_areaView')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'parent' in kwargs: kwargs.pop('parent')
self.setFocusPolicy(ttk.TTkK.ClickFocus)
self.setViewport(ttk.TTkTestAbstractScrollWidget(areaSize=(100,40), areaPos=(10,5)))
def demoScrollArea(root= None):
scrollArea = ScrollAreaTest(parent=root)
return scrollArea
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-f', help='Full Screen', action='store_true')
args = parser.parse_args()
ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
if args.f:
rootGraph = root
root.setLayout(ttk.TTkGridLayout())
else:
rootGraph = ttk.TTkWindow(parent=root,pos=(1,1), size=(50,20), title="Test Graph", border=True, layout=ttk.TTkGridLayout())
demoScrollArea(rootGraph)
root.mainloop()
if __name__ == "__main__":
main()

66
tests/test.ui.021.abstractscroll.02.py

@ -0,0 +1,66 @@
#!/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, argparse, math, random
sys.path.append(os.path.join(sys.path[0],'..'))
import TermTk as ttk
class ScrollAreaTest(ttk.TTkAbstractScrollArea):
__slots__ = ('_areaView')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'parent' in kwargs: kwargs.pop('parent')
self.setFocusPolicy(ttk.TTkK.ClickFocus)
scrollLayout = ttk.TTkAbstractScrollViewGridLayout()
w1 = ttk.TTkTestAbstractScrollWidget(areaSize=(100,40), areaPos=(10,5))
w2 = ttk.TTkTestAbstractScrollWidget(areaSize=(100,40), areaPos=(10,5), maxWidth=30)
w3 = ttk.TTkTestAbstractScrollWidget(areaSize=( 50,20), areaPos=(10,5))
scrollLayout.addWidget(w1,0,0,2,1)
scrollLayout.addWidget(w2,0,1)
scrollLayout.addWidget(w3,1,1)
self.setViewport(scrollLayout)
def demoScrollArea(root= None):
scrollArea = ScrollAreaTest(parent=root)
return scrollArea
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-f', help='Full Screen', action='store_true')
args = parser.parse_args()
ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
if args.f:
rootGraph = root
root.setLayout(ttk.TTkGridLayout())
else:
rootGraph = ttk.TTkWindow(parent=root,pos=(1,1), size=(55,20), title="Test Graph", border=True, layout=ttk.TTkGridLayout())
demoScrollArea(rootGraph)
root.mainloop()
if __name__ == "__main__":
main()
Loading…
Cancel
Save