Browse Source

Moved all the layout logic in the container widget

pull/167/head
Eugenio Parodi 3 years ago
parent
commit
8bc51f2da9
  1. 3
      TermTk/TTkAbstract/abstractscrollarea.py
  2. 5
      TermTk/TTkAbstract/abstractscrollview.py
  3. 3
      TermTk/TTkCore/ttk.py
  4. 4
      TermTk/TTkLayouts/layout.py
  5. 2
      TermTk/TTkTestWidgets/__init__.py
  6. 4
      TermTk/TTkTestWidgets/tominspector.py
  7. 1
      TermTk/TTkUiTools/properties/__init__.py
  8. 47
      TermTk/TTkUiTools/properties/container.py
  9. 15
      TermTk/TTkUiTools/properties/widget.py
  10. 1
      TermTk/TTkUiTools/uiproperties.py
  11. 2
      TermTk/TTkWidgets/TTkModelView/treewidget.py
  12. 11
      TermTk/TTkWidgets/__init__.py
  13. 423
      TermTk/TTkWidgets/container.py
  14. 22
      TermTk/TTkWidgets/frame.py
  15. 6
      TermTk/TTkWidgets/spinbox.py
  16. 4
      TermTk/TTkWidgets/splitter.py
  17. 5
      TermTk/TTkWidgets/tabwidget.py
  18. 199
      TermTk/TTkWidgets/widget.py
  19. 8
      demo/demo.py

3
TermTk/TTkAbstract/abstractscrollarea.py

@ -24,11 +24,12 @@ from TermTk.TTkCore.constant import TTkK
# from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.signal import pyTTkSlot
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollViewInterface
class TTkAbstractScrollArea(TTkWidget):
class TTkAbstractScrollArea(TTkContainer):
__slots__ = (
'_processing', # this flag is required to avoid unnecessary loop on edge cases
'_viewport',

5
TermTk/TTkAbstract/abstractscrollview.py

@ -26,6 +26,7 @@ from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
class TTkAbstractScrollViewInterface():
@ -44,7 +45,7 @@ class TTkAbstractScrollViewInterface():
def getViewOffsets(self):
return self._viewOffsetX, self._viewOffsetY
class TTkAbstractScrollView(TTkWidget, TTkAbstractScrollViewInterface):
class TTkAbstractScrollView(TTkContainer, TTkAbstractScrollViewInterface):
__slots__ = (
'_viewOffsetX', '_viewOffsetY',
# Signals
@ -55,7 +56,7 @@ class TTkAbstractScrollView(TTkWidget, TTkAbstractScrollViewInterface):
self.viewMovedTo = pyTTkSignal(int, int) # x, y
self.viewSizeChanged = pyTTkSignal(int, int) # w, h
self.viewChanged = pyTTkSignal()
TTkWidget.__init__(self, *args, **kwargs)
TTkContainer.__init__(self, *args, **kwargs)
self._viewOffsetX = 0
self._viewOffsetY = 0

3
TermTk/TTkCore/ttk.py

@ -42,8 +42,9 @@ from TermTk.TTkCore.timer import TTkTimer
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkTheme.theme import TTkTheme
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
class TTk(TTkWidget):
class TTk(TTkContainer):
class _mouseCursor(TTkWidget):
__slots__ = ('_cursor','_color')
def __init__(self, input):

4
TermTk/TTkLayouts/layout.py

@ -213,8 +213,8 @@ class TTkLayout(TTkLayoutItem):
if child._layoutItemType == TTkK.WidgetItem:
if onlyVisible and not child.widget().isVisible(): continue
yield child.widget()
if recurse:
yield from child.widget().rootLayout().iterWidgets()
if recurse and hasattr(cw:=child.widget(),'rootLayout'):
yield from cw.rootLayout().iterWidgets()
if child._layoutItemType == TTkK.LayoutItem and recurse:
yield from child.iterWidgets()

2
TermTk/TTkTestWidgets/__init__.py

@ -3,4 +3,4 @@ from .testwidget import TTkTestWidget
from .testwidgetsizes import TTkTestWidgetSizes
from .testabstractscroll import TTkTestAbstractScrollWidget
from .keypressview import TTkKeyPressView
from .tominspector import TTkTomInspector
# from .tominspector import TTkTomInspector

4
TermTk/TTkTestWidgets/tominspector.py

@ -37,7 +37,7 @@ from TermTk.TTkWidgets.lineedit import TTkLineEdit
from TermTk.TTkWidgets.combobox import TTkComboBox
from TermTk.TTkWidgets.checkbox import TTkCheckbox
from TermTk.TTkWidgets.spinbox import TTkSpinBox
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.splitter import TTkSplitter
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkWidgets.button import TTkButton
@ -142,7 +142,7 @@ class _TTkDomTreeWidgetItem(TTkTreeWidgetItem):
def domWidget(self):
return self._domWidget
class TTkTomInspector(TTkWidget):
class TTkTomInspector(TTkContainer):
__slots__ = ('_domTree','_detail','_splitter')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

1
TermTk/TTkUiTools/properties/__init__.py

@ -2,6 +2,7 @@
from .button import TTkButtonProperties
from .checkbox import TTkCheckboxProperties
from .combobox import TTkComboBoxProperties
from .container import TTkContainerProperties
from .frame import TTkFrameProperties
# from .graph import
# from .image import

47
TermTk/TTkUiTools/properties/container.py

@ -0,0 +1,47 @@
# MIT License
#
# Copyright (c) 2023 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.string import TTkString
from TermTk.TTkLayouts.layout import TTkLayout
from TermTk.TTkWidgets.container import TTkContainer
TTkContainerProperties = {
'properties' : {
'Padding': {
'get': { 'cb':TTkContainer.getPadding, 'type': [
{ 'name': 'top', 'type':int } ,
{ 'name': 'bottom', 'type':int } ,
{ 'name': 'left', 'type':int } ,
{ 'name': 'right', 'type':int } ] },
'set': { 'cb':TTkContainer.setPadding, 'type': [
{ 'name': 'top', 'type':int } ,
{ 'name': 'bottom', 'type':int } ,
{ 'name': 'left', 'type':int } ,
{ 'name': 'right', 'type':int } ] } },
'Layout' : {
'init': {'name':'layout', 'type':TTkLayout} ,
'get': { 'cb':TTkContainer.layout, 'type':TTkLayout} ,
'set': { 'cb':TTkContainer.setLayout, 'type':TTkLayout} },
},'signals' : {
},'slots' : {
}
}

15
TermTk/TTkUiTools/properties/widget.py

@ -78,21 +78,6 @@ TTkWidgetProperties = {
'init': {'name':'maxHeight', 'type':int } ,
'get': { 'cb':TTkWidget.maximumHeight, 'type':int } ,
'set': { 'cb':TTkWidget.setMaximumHeight,'type':int } },
'Padding': {
'get': { 'cb':TTkWidget.getPadding, 'type': [
{ 'name': 'top', 'type':int } ,
{ 'name': 'bottom', 'type':int } ,
{ 'name': 'left', 'type':int } ,
{ 'name': 'right', 'type':int } ] },
'set': { 'cb':TTkWidget.setPadding, 'type': [
{ 'name': 'top', 'type':int } ,
{ 'name': 'bottom', 'type':int } ,
{ 'name': 'left', 'type':int } ,
{ 'name': 'right', 'type':int } ] } },
'Layout' : {
'init': {'name':'layout', 'type':TTkLayout} ,
'get': { 'cb':TTkWidget.layout, 'type':TTkLayout} ,
'set': { 'cb':TTkWidget.setLayout, 'type':TTkLayout} },
'Visible' : {
'init': {'name':'visible', 'type':bool } ,
'get': { 'cb':TTkWidget.isVisible, 'type':bool } ,

1
TermTk/TTkUiTools/uiproperties.py

@ -28,6 +28,7 @@ TTkUiProperties = {
# Widgets
TTkButton.__name__: TTkButtonProperties,
TTkCheckbox.__name__: TTkCheckboxProperties,
TTkContainer.__name__: TTkContainerProperties,
TTkComboBox.__name__: TTkComboBoxProperties,
TTkFrame.__name__: TTkFrameProperties,
TTkLabel.__name__: TTkLabelProperties,

2
TermTk/TTkWidgets/TTkModelView/treewidget.py

@ -1,5 +1,3 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>

11
TermTk/TTkWidgets/__init__.py

@ -1,9 +1,16 @@
# Base widhgets
from .widget import TTkWidget
from .container import TTkContainer
# Containerised widgets
from .frame import TTkFrame
from .resizableframe import TTkResizableFrame
from .button import TTkButton
from .window import TTkWindow
from .splitter import TTkSplitter
# Everything else
from .about import TTkAbout
from .button import TTkButton
from .checkbox import TTkCheckbox
from .combobox import TTkComboBox
from .Fancy import *
@ -21,10 +28,8 @@ from .scrollarea import TTkScrollArea
from .scrollbar import TTkScrollBar
from .spacer import TTkSpacer
from .spinbox import TTkSpinBox
from .splitter import TTkSplitter
from .tabwidget import TTkTabWidget, TTkTabButton, TTkTabBar
from .kodetab import TTkKodeTab
from .texedit import TTkTextEdit, TTkTextEditView
from .TTkModelView import *
from .TTkPickers import *
from .window import TTkWindow

423
TermTk/TTkWidgets/container.py

@ -0,0 +1,423 @@
# MIT License
#
# Copyright (c) 2023 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.cfg import TTkCfg, TTkGlbl
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkTemplates.lookandfeel import TTkLookAndFeel
from TermTk.TTkTemplates.dragevents import TDragEvents
from TermTk.TTkTemplates.mouseevents import TMouseEvents
from TermTk.TTkTemplates.keyevents import TKeyEvents
from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
from TermTk.TTkWidgets.widget import TTkWidget
class TTkContainer(TTkWidget):
''' Widget Layout sizes:
::
Terminal area (i.e. XTerm)
TTkWidget width
(x,y)
padt (Top Padding)
height
padl Layout/child padr
padb (Bottom Pad.)
The TTkWidget class is the base class of all user interface objects
:param name: the name of the widget, defaults to ""
:type name: str, optional
:param parent: the parent widget, defaults to None
:type parent: :class:`TTkWidget`, optional
:param int x: the x position, defaults to 0
:param int y: the y position, defaults to 0
:param [int,int] pos: the [x,y] position (override the previously defined x, y), optional, default=[0,0]
:param int width: the width of the widget, defaults to 0
:param int height: the height of the widget, defaults to 0
:param [int,int] size: the size [width, height] of the widget (override the previously defined sizes), optional, default=[0,0]
:param int padding: the padding (top, bottom, left, right) of the widget, defaults to 0
:param int paddingTop: the Top padding, override Top padding if already defined, optional, default=padding
:param int paddingBottom: the Bottom padding, override Bottom padding if already defined, optional, default=padding
:param int paddingLeft: the Left padding, override Left padding if already defined, optional, default=padding
:param int paddingRight: the Right padding, override Right padding if already defined, optional, default=padding
:param int maxWidth: the maxWidth of the widget, optional, defaults to 0x10000
:param int maxHeight: the maxHeight of the widget, optional, defaults to 0x10000
:param [int,int] maxSize: the max [width,height] of the widget, optional
:param int minWidth: the minWidth of the widget, defaults to 0
:param int minHeight: the minHeight of the widget, defaults to 0
:param [int,int] minSize: the minSize [width,height] of the widget, optional
:param toolTip: This property holds the widget's tooltip
:type toolTip: :class:`~TermTk.TTkCore.string.TTkString`
:param lookAndFeel: the style helper to be used for any customization
:type lookAndFeel: :class:`~TermTk.TTkTemplates.lookandfeel.TTkTTkLookAndFeel`
:param bool,optional visible: the visibility, optional, defaults to True
:param bool,optional enabled: the ability to handle input events, optional, defaults to True
:param layout: the layout of this widget, optional, defaults to :class:`~TermTk.TTkLayouts.layout.TTkLayout`
:type layout: :mod:`TermTk.TTkLayouts`
'''
__slots__ = (
'_padt', '_padb', '_padl', '_padr',
'_layout')
def __init__(self, *args, **kwargs):
padding = kwargs.get('padding', 0 )
self._padt = kwargs.get('paddingTop', padding )
self._padb = kwargs.get('paddingBottom', padding )
self._padl = kwargs.get('paddingLeft', padding )
self._padr = kwargs.get('paddingRight', padding )
self._layout = TTkLayout() # root layout
self._layout.addItem(kwargs.get('layout',TTkLayout())) # main layout
super().__init__(**kwargs)
self._layout.setParent(self)
def addWidget(self, widget):
'''
.. warning::
Method Deprecated,
use :class:`TTkWidget` -> :class:`~TermTk.TTkWidgets.widget.TTkWidget.layout` -> :class:`~TermTk.TTkLayouts.layout.TTkLayout.addWidget`
i.e.
.. code:: python
parentWidget.layout().addWidget(childWidget)
'''
TTkLog.error("<TTkWidget>.addWidget(...) is deprecated, use <TTkWidget>.layout().addWidget(...)")
if self.layout(): self.layout().addWidget(widget)
def removeWidget(self, widget):
'''
.. warning::
Method Deprecated,
use :class:`TTkWidget` -> :class:`~TermTk.TTkWidgets.widget.TTkWidget.layout` -> :class:`~TermTk.TTkLayouts.layout.TTkLayout.removeWidget`
i.e.
.. code:: python
parentWidget.layout().removeWidget(childWidget)
'''
TTkLog.error("<TTkWidget>.removeWidget(...) is deprecated, use <TTkWidget>.layout().removeWidget(...)")
if self.layout(): self.layout().removeWidget(widget)
@staticmethod
def _paintChildCanvas(canvas, item, geometry, offset):
''' .. caution:: Don't touch this! '''
lx,ly,lw,lh = geometry
ox, oy = offset
if item.layoutItemType() == TTkK.WidgetItem and not item.isEmpty():
child = item.widget()
cx,cy,cw,ch = child.geometry()
canvas.paintCanvas(
child.getCanvas(),
(cx+ox, cy+oy, cw, ch), # geometry
( 0, 0, cw, ch), # slice
( lx, ly, lw, lh)) # bound
else:
for child in item.zSortedItems:
# The Parent Layout Geometry (lx,ly,lw,lh) include the padding of the layout
igx, igy, igw, igh = item.geometry()
iox, ioy = item.offset()
# Moved Layout to the new geometry (ix,iy,iw,ih)
ix = igx+ox # + iox
iy = igy+oy # + ioy
iw = igw # -iox
ih = igh # -ioy
# return if Child outside the bound
if ix+iw < lx and ix > lx+lw and iy+ih < ly and iy > ly+lh: continue
# Crop the Layout based on the Parent Layout Geometry
bx = max(ix,lx)
by = max(iy,ly)
bw = min(ix+iw,lx+lw)-bx
bh = min(iy+ih,ly+lh)-by
TTkContainer._paintChildCanvas(canvas, child, (bx,by,bw,bh), (ix+iox,iy+ioy))
def paintChildCanvas(self):
''' .. caution:: Don't touch this! '''
TTkContainer._paintChildCanvas(self._canvas, self.rootLayout(), self.rootLayout().geometry(), self.rootLayout().offset())
def getPadding(self) -> (int, int, int, int):
''' Retrieve the widget padding sizes
:return: list[top, bottom, left, right]: the 4 padding sizes
'''
return self._padt, self._padb, self._padl, self._padr
def setPadding(self, top: int, bottom: int, left: int, right: int):
''' Set the padding of the widget
:param int top: top padding
:param int bottom: bottom padding
:param int left: left padding
:param int right: right padding
'''
if self._padt == top and self._padb == bottom and \
self._padl == left and self._padr == right: return
self._padt = top
self._padb = bottom
self._padl = left
self._padr = right
self.update(repaint=True, updateLayout=True)
@staticmethod
def _mouseEventLayoutHandle(evt, layout):
''' .. caution:: Don't touch this! '''
x, y = evt.x, evt.y
lx,ly,lw,lh =layout.geometry()
lox, loy = layout.offset()
lx,ly,lw,lh = lx+lox, ly+loy, lw-lox, lh-loy
# opt of bounds
if x<lx or x>=lx+lw or y<ly or y>=lh+ly:
return False
x-=lx
y-=ly
for item in reversed(layout.zSortedItems):
# for item in layout.zSortedItems:
if item.layoutItemType() == TTkK.WidgetItem and not item.isEmpty():
widget = item.widget()
if not widget._visible: continue
wx,wy,ww,wh = widget.geometry()
# Skip the mouse event if outside this widget
if not (wx <= x < wx+ww and wy <= y < wy+wh): continue
wevt = evt.clone(pos=(x-wx, y-wy))
if widget.mouseEvent(wevt):
return True
elif item.layoutItemType() == TTkK.LayoutItem:
levt = evt.clone(pos=(x, y))
if TTkContainer._mouseEventLayoutHandle(levt, item):
return True
return False
_mouseOver = None
_mouseOverTmp = None
_mouseOverProcessed = False
def mouseEvent(self, evt):
''' .. caution:: Don't touch this! '''
if not self._enabled: return False
# Saving self in this global variable
# So that after the "_mouseEventLayoutHandle"
# this tmp value will hold the last widget below the mouse
TTkWidget._mouseOverTmp = self
# Mouse Drag has priority because it
# should be handled by the focused widget and
# not pushed to the unfocused childs
# unless there is a Drag and Drop event ongoing
if evt.evt == TTkK.Drag and not TTkHelper.isDnD():
if self.mouseDragEvent(evt):
return True
if self.rootLayout() is not None:
if TTkContainer._mouseEventLayoutHandle(evt, self.rootLayout()):
return True
# If there is an overlay and it is modal,
# return False if this widget is not part of any
# of the widgets above the modal
if not TTkHelper.checkModalOverlay(self):
return False
# Handle Drag and Drop Events
if TTkHelper.isDnD():
ret = False
if evt.evt == TTkK.Drag:
dndw = TTkHelper.dndWidget()
if dndw == self:
if self.dragMoveEvent(TTkHelper.dndGetDrag().getDragMoveEvent(evt)):
return True
else:
if self.dragEnterEvent(TTkHelper.dndGetDrag().getDragEnterEvent(evt)):
if dndw:
ret = dndw.dragLeaveEvent(TTkHelper.dndGetDrag().getDragLeaveEvent(evt))
TTkHelper.dndEnter(self)
return True
if evt.evt == TTkK.Release:
if self.dropEvent(TTkHelper.dndGetDrag().getDropEvent(evt)):
return True
return ret
# handle Enter/Leave Events
# _mouseOverTmp hold the top widget under the mouse
# if different than self it means that it is a child
if evt.evt == TTkK.Move:
if not TTkWidget._mouseOverProcessed:
if TTkWidget._mouseOver != TTkWidget._mouseOverTmp == self:
if TTkWidget._mouseOver:
# TTkLog.debug(f"Leave: {TTkWidget._mouseOver._name}")
TTkWidget._mouseOver.leaveEvent(evt)
TTkWidget._mouseOver = self
# TTkLog.debug(f"Enter: {TTkWidget._mouseOver._name}")
TTkHelper.toolTipClose()
if self._toolTip and self._toolTip != '':
TTkHelper.toolTipTrigger(self._toolTip)
# TTkHelper.triggerToolTip(self._name)
TTkWidget._mouseOver.enterEvent(evt)
TTkWidget._mouseOverProcessed = True
if self.mouseMoveEvent(evt):
return True
else:
TTkHelper.toolTipClose()
if evt.evt == TTkK.Release:
self._pendingMouseRelease = False
self._processStyleEvent(TTkWidget._S_NONE)
if self.mouseReleaseEvent(evt):
return True
if evt.evt == TTkK.Press:
# in case of parent focus, check the parent that can accept the focus
w = self
while w._parent and (w.focusPolicy() & TTkK.ParentFocus) == TTkK.ParentFocus:
w = w._parent
if w.focusPolicy() & TTkK.ClickFocus == TTkK.ClickFocus:
w.setFocus()
w.raiseWidget()
self._processStyleEvent(TTkWidget._S_PRESSED)
if evt.tap == 2 and self.mouseDoubleClickEvent(evt):
#self._pendingMouseRelease = True
return True
if evt.tap > 1 and self.mouseTapEvent(evt):
return True
if evt.tap == 1 and self.mousePressEvent(evt):
# TTkLog.debug(f"Click {self._name}")
self._pendingMouseRelease = True
return True
if evt.key == TTkK.Wheel:
if self.wheelEvent(evt):
return True
return False
def setLayout(self, layout):
self._layout.replaceItem(layout, 0)
#self.layout().setParent(self)
self.update(repaint=True, updateLayout=True)
def layout(self):
''' Get the layout
:return: The layout used
:rtype: :class:`TTkLayout` or derived
'''
return self._layout.itemAt(0)
def rootLayout(self): return self._layout
def maximumHeight(self):
wMaxH = self._maxh
if self.layout() is not None:
lMaxH = self.layout().maximumHeight() + self._padt + self._padb
if lMaxH < wMaxH:
return lMaxH
return wMaxH
def maximumWidth(self):
wMaxW = self._maxw
if self.layout() is not None:
lMaxW = self.layout().maximumWidth() + self._padl + self._padr
if lMaxW < wMaxW:
return lMaxW
return wMaxW
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
def minDimension(self, orientation) -> int:
if orientation == TTkK.HORIZONTAL:
return self.minimumWidth()
else:
return self.minimumHeight()
def minimumHeight(self):
wMinH = self._minh
if self.layout() is not None:
lMinH = self.layout().minimumHeight() + self._padt + self._padb
if lMinH > wMinH:
return lMinH
return wMinH
def minimumWidth(self):
wMinW = self._minw
if self.layout() is not None:
lMinW = self.layout().minimumWidth() + self._padl + self._padr
if lMinW > wMinW:
return lMinW
return wMinW
@pyTTkSlot()
def show(self):
'''show'''
if self._visible: return
self._visible = True
self._canvas.show()
self.update(updateLayout=True, updateParent=True)
for w in self.rootLayout().iterWidgets(onlyVisible=True):
w.update()
@pyTTkSlot()
def hide(self):
'''hide'''
if not self._visible: return
self._visible = False
self._canvas.hide()
self.update(repaint=False, updateParent=True)
def update(self, repaint: bool =True, updateLayout: bool =False, updateParent: bool =False):
super().update(repaint=repaint, updateLayout=updateLayout, updateParent=updateParent)
if updateLayout and self.rootLayout() is not None:
self.rootLayout().setGeometry(0,0,self._width,self._height)
self.layout().setGeometry(
self._padl, self._padt,
self._width - self._padl - self._padr,
self._height - self._padt - self._padb)
self.rootLayout().update()
def getWidgetByName(self, name: str):
if name == self._name:
return self
for w in self.rootLayout().iterWidgets(onlyVisible=False, recurse=True):
if w._name == name:
return w
return None

22
TermTk/TTkWidgets/frame.py

@ -24,9 +24,9 @@
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.string import TTkString
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
class TTkFrame(TTkWidget):
class TTkFrame(TTkContainer):
'''
::
@ -62,10 +62,26 @@ class TTkFrame(TTkWidget):
self._menubarBottomPosition = 0
self._menubarTop = None
self._menubarBottom = None
TTkWidget.__init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self.setBorder(self._border)
def newMenubarTop(self):
'''newMenubarTop
.. warning::
Method Deprecated,
use :class:`~TermTk.TTkWidgets.frame.setMenuBar` instead
i.e.
.. code:: python
menuBar = TTkMenuBarLayout()
frame.setMenuBar(menuBar)
menuBar.addMenu("File")
'''
if not self._menubarTop:
from TermTk.TTkWidgets.menubar import TTkMenuBarLayout
self._menubarTop = TTkMenuBarLayout(borderColor=self._borderColor)

6
TermTk/TTkWidgets/spinbox.py

@ -27,11 +27,11 @@ from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkLayouts import TTkGridLayout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.lineedit import TTkLineEdit
class TTkSpinBox(TTkWidget):
class TTkSpinBox(TTkContainer):
'''TTkSpinBox'''
__slots__= (
'_lineEdit', '_value', '_maximum', '_minimum',
@ -41,7 +41,7 @@ class TTkSpinBox(TTkWidget):
def __init__(self, *args, **kwargs):
# Signals
self.valueChanged=pyTTkSignal(int)
TTkWidget.__init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self._value = kwargs.get("value",0)
self._maximum = kwargs.get("maximum",99)
self._minimum = kwargs.get("minimum",0)

4
TermTk/TTkWidgets/splitter.py

@ -27,9 +27,9 @@ from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.string import TTkString
from TermTk.TTkLayouts.layout import TTkLayout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkWidgets.container import TTkContainer
class TTkSplitter(TTkWidget):
class TTkSplitter(TTkContainer):
'''TTkSplitter'''
__slots__ = (
'_orientation', '_separators', '_refSizes',

5
TermTk/TTkWidgets/tabwidget.py

@ -31,6 +31,7 @@ from TermTk.TTkCore.string import TTkString
from TermTk.TTkGui.drag import TTkDrag
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.spacer import TTkSpacer
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkWidgets.button import TTkButton
@ -214,7 +215,7 @@ _labels= │◀│La│Label1║Label2║Label3│Label4│▶│
leftscroller rightScroller
'''
class TTkTabBar(TTkWidget):
class TTkTabBar(TTkContainer):
'''TTkTabBar'''
__slots__ = (
'_tabButtons', '_tabData', '_tabMovable', '_small',
@ -241,7 +242,7 @@ class TTkTabBar(TTkWidget):
self._leftScroller.clicked.connect( self._moveToTheLeft)
self._rightScroller.clicked.connect(self._andMoveToTheRight)
TTkWidget.__init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self.setFocusPolicy(TTkK.ClickFocus + TTkK.TabFocus)
self.focusChanged.connect(self._focusChanged)

199
TermTk/TTkWidgets/widget.py

@ -105,10 +105,9 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
__slots__ = (
'_name', '_parent',
'_x', '_y', '_width', '_height',
'_padt', '_padb', '_padl', '_padr',
'_maxw', '_maxh', '_minw', '_minh',
'_focus','_focus_policy',
'_layout', '_canvas', '_widgetItem',
'_canvas', '_widgetItem',
'_visible', '_transparent',
'_pendingMouseRelease',
'_enabled',
@ -144,12 +143,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._height = kwargs.get('height', 0 )
self._width, self._height = kwargs.get('size', (self._width, self._height))
padding = kwargs.get('padding', 0 )
self._padt = kwargs.get('paddingTop', padding )
self._padb = kwargs.get('paddingBottom', padding )
self._padl = kwargs.get('paddingLeft', padding )
self._padr = kwargs.get('paddingRight', padding )
self._maxw = kwargs.get('maxWidth', 0x10000)
self._maxh = kwargs.get('maxHeight', 0x10000)
self._maxw, self._maxh = kwargs.get('maxSize', (self._maxw, self._maxh))
@ -169,17 +162,14 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._widgetItem = TTkWidgetItem(widget=self)
self._layout = TTkLayout() # root layout
self._layout.setParent(self)
self._layout.addItem(kwargs.get('layout',TTkLayout())) # main layout
self._canvas = TTkCanvas(
widget = self,
width = self._width ,
height = self._height )
if self._parent and self._parent.layout():
# TODO: Check this,
# The parent should always have a layout
if hasattr(self._parent,'layout') and self._parent.layout():
self._parent.layout().addWidget(self)
self._parent.update(repaint=True, updateLayout=True)
@ -194,7 +184,7 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
# att = self.__getattribute__(an)
# # TODO: TBD, I need to find the time to do this
if self._parent and self._parent.layout():
if hasattr(self._parent,'layout') and self._parent.layout():
self._parent.layout().removeWidget(self)
self._parent = None
@ -206,41 +196,8 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
'''setName'''
self._name = name
def widgetItem(self): return self._widgetItem
def addWidget(self, widget):
'''
.. warning::
Method Deprecated,
use :class:`TTkWidget` -> :class:`~TermTk.TTkWidgets.widget.TTkWidget.layout` -> :class:`~TermTk.TTkLayouts.layout.TTkLayout.addWidget`
i.e.
.. code:: python
parentWidget.layout().addWidget(childWidget)
'''
TTkLog.error("<TTkWidget>.addWidget(...) is deprecated, use <TTkWidget>.layout().addWidget(...)")
if self.layout(): self.layout().addWidget(widget)
def removeWidget(self, widget):
'''
.. warning::
Method Deprecated,
use :class:`TTkWidget` -> :class:`~TermTk.TTkWidgets.widget.TTkWidget.layout` -> :class:`~TermTk.TTkLayouts.layout.TTkLayout.removeWidget`
i.e.
.. code:: python
parentWidget.layout().removeWidget(childWidget)
'''
TTkLog.error("<TTkWidget>.removeWidget(...) is deprecated, use <TTkWidget>.layout().removeWidget(...)")
if self.layout(): self.layout().removeWidget(widget)
def paintEvent(self, canvas:TTkCanvas):
'''
Paint Event callback,
@ -255,39 +212,10 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
@staticmethod
def _paintChildCanvas(canvas, item, geometry, offset):
''' .. caution:: Don't touch this! '''
lx,ly,lw,lh = geometry
ox, oy = offset
if item.layoutItemType() == TTkK.WidgetItem and not item.isEmpty():
child = item.widget()
cx,cy,cw,ch = child.geometry()
canvas.paintCanvas(
child.getCanvas(),
(cx+ox, cy+oy, cw, ch), # geometry
( 0, 0, cw, ch), # slice
( lx, ly, lw, lh)) # bound
else:
for child in item.zSortedItems:
# The Parent Layout Geometry (lx,ly,lw,lh) include the padding of the layout
igx, igy, igw, igh = item.geometry()
iox, ioy = item.offset()
# Moved Layout to the new geometry (ix,iy,iw,ih)
ix = igx+ox # + iox
iy = igy+oy # + ioy
iw = igw # -iox
ih = igh # -ioy
# return if Child outside the bound
if ix+iw < lx and ix > lx+lw and iy+ih < ly and iy > ly+lh: continue
# Crop the Layout based on the Parent Layout Geometry
bx = max(ix,lx)
by = max(iy,ly)
bw = min(ix+iw,lx+lw)-bx
bh = min(iy+ih,ly+lh)-by
TTkWidget._paintChildCanvas(canvas, child, (bx,by,bw,bh), (ix+iox,iy+ioy))
pass
def paintChildCanvas(self):
''' .. caution:: Don't touch this! '''
TTkWidget._paintChildCanvas(self._canvas, self.rootLayout(), self.rootLayout().geometry(), self.rootLayout().offset())
pass
def moveEvent(self, x: int, y: int):
''' Event Callback triggered after a successful move'''
@ -343,58 +271,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self.resize(w, h)
self.move(x, y)
def getPadding(self) -> (int, int, int, int):
''' Retrieve the widget padding sizes
:return: list[top, bottom, left, right]: the 4 padding sizes
'''
return self._padt, self._padb, self._padl, self._padr
def setPadding(self, top: int, bottom: int, left: int, right: int):
''' Set the padding of the widget
:param int top: top padding
:param int bottom: bottom padding
:param int left: left padding
:param int right: right padding
'''
if self._padt == top and self._padb == bottom and \
self._padl == left and self._padr == right: return
self._padt = top
self._padb = bottom
self._padl = left
self._padr = right
self.update(repaint=True, updateLayout=True)
@staticmethod
def _mouseEventLayoutHandle(evt, layout):
''' .. caution:: Don't touch this! '''
x, y = evt.x, evt.y
lx,ly,lw,lh =layout.geometry()
lox, loy = layout.offset()
lx,ly,lw,lh = lx+lox, ly+loy, lw-lox, lh-loy
# opt of bounds
if x<lx or x>=lx+lw or y<ly or y>=lh+ly:
return False
x-=lx
y-=ly
for item in reversed(layout.zSortedItems):
# for item in layout.zSortedItems:
if item.layoutItemType() == TTkK.WidgetItem and not item.isEmpty():
widget = item.widget()
if not widget._visible: continue
wx,wy,ww,wh = widget.geometry()
# Skip the mouse event if outside this widget
if not (wx <= x < wx+ww and wy <= y < wy+wh): continue
wevt = evt.clone(pos=(x-wx, y-wy))
if widget.mouseEvent(wevt):
return True
elif item.layoutItemType() == TTkK.LayoutItem:
levt = evt.clone(pos=(x, y))
if TTkWidget._mouseEventLayoutHandle(levt, item):
return True
return False
def pasteEvent(self, txt:str):
return False
@ -418,9 +294,9 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
if self.mouseDragEvent(evt):
return True
if self.rootLayout() is not None:
if TTkWidget._mouseEventLayoutHandle(evt, self.rootLayout()):
return True
# if self.rootLayout() is not None:
# if TTkWidget._mouseEventLayoutHandle(evt, self.rootLayout()):
# return True
# If there is an overlay and it is modal,
# return False if this widget is not part of any
@ -500,20 +376,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
return False
def setLayout(self, layout):
self._layout.replaceItem(layout, 0)
#self.layout().setParent(self)
self.update(repaint=True, updateLayout=True)
def layout(self):
''' Get the layout
:return: The layout used
:rtype: :class:`TTkLayout` or derived
'''
return self._layout.itemAt(0)
def rootLayout(self): return self._layout
def setParent(self, parent):
self._parent = parent
def parentWidget(self):
@ -536,19 +398,9 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
else:
return self.maximumHeight()
def maximumHeight(self):
wMaxH = self._maxh
if self.layout() is not None:
lMaxH = self.layout().maximumHeight() + self._padt + self._padb
if lMaxH < wMaxH:
return lMaxH
return wMaxH
return self._maxh
def maximumWidth(self):
wMaxW = self._maxw
if self.layout() is not None:
lMaxW = self.layout().maximumWidth() + self._padl + self._padr
if lMaxW < wMaxW:
return lMaxW
return wMaxW
return self._maxw
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
@ -558,19 +410,9 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
else:
return self.minimumHeight()
def minimumHeight(self):
wMinH = self._minh
if self.layout() is not None:
lMinH = self.layout().minimumHeight() + self._padt + self._padb
if lMinH > wMinH:
return lMinH
return wMinH
return self._minh
def minimumWidth(self):
wMinW = self._minw
if self.layout() is not None:
lMinW = self.layout().minimumWidth() + self._padl + self._padr
if lMinW > wMinW:
return lMinW
return wMinW
return self._minw
def setMaximumSize(self, maxw: int, maxh: int):
self.setMaximumWidth(maxw)
@ -603,8 +445,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
self._visible = True
self._canvas.show()
self.update(updateLayout=True, updateParent=True)
for w in self.rootLayout().iterWidgets(onlyVisible=True):
w.update()
@pyTTkSlot()
def hide(self):
@ -659,16 +499,8 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
if repaint:
TTkHelper.addUpdateBuffer(self)
TTkHelper.addUpdateWidget(self)
if updateLayout and self.rootLayout() is not None:
self.rootLayout().setGeometry(0,0,self._width,self._height)
self.layout().setGeometry(
self._padl, self._padt,
self._width - self._padl - self._padr,
self._height - self._padt - self._padb)
if updateParent and self._parent is not None:
self._parent.update(updateLayout=True)
if updateLayout and self.rootLayout() is not None:
self.rootLayout().update()
@pyTTkSlot()
def setFocus(self):
@ -749,9 +581,6 @@ class TTkWidget(TMouseEvents,TKeyEvents, TDragEvents):
def getWidgetByName(self, name: str):
if name == self._name:
return self
for w in self.rootLayout().iterWidgets(onlyVisible=False, recurse=True):
if w._name == name:
return w
return None
_BASE_STYLE = {'default' : {'color': TTkColor.RST}}

8
demo/demo.py

@ -105,9 +105,9 @@ def demoShowcase(root=None, border=True):
logInput = ttk.TTkKeyPressView(visible=False, maxHeight=3, minHeight=3)
root.layout().addWidget(logInput, 1, 0)
domTree = ttk.TTkFrame(title="Tom Inspector", border=True, visible=False, layout=ttk.TTkGridLayout())
ttk.TTkTomInspector(parent=domTree)
root.layout().addWidget(domTree, 0, 1)
# domTree = ttk.TTkFrame(title="Tom Inspector", border=True, visible=False, layout=ttk.TTkGridLayout())
# ttk.TTkTomInspector(parent=domTree)
# root.layout().addWidget(domTree, 0, 1)
leftFrame = ttk.TTkFrame(parent=splitter, layout=ttk.TTkGridLayout(), border=False)
@ -116,7 +116,7 @@ def demoShowcase(root=None, border=True):
logInputToggler = ttk.TTkCheckbox(text='ShowInput')
logInputToggler.stateChanged.connect(lambda x: logInput.setVisible(x==ttk.TTkK.Checked))
tomTreeToggler = ttk.TTkCheckbox(text='Tom View', enabled=False)
tomTreeToggler.stateChanged.connect(lambda x: domTree.setVisible(x==ttk.TTkK.Checked))
# tomTreeToggler.stateChanged.connect(lambda x: domTree.setVisible(x==ttk.TTkK.Checked))
mouseToggler = ttk.TTkCheckbox(text='Mouse 🐀', checked=True)
mouseToggler.stateChanged.connect(lambda x: ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON if x==ttk.TTkK.Checked else ttk.TTkTerm.Mouse.OFF))
quitButton = ttk.TTkButton(text="Quit", border=True, maxHeight=3)

Loading…
Cancel
Save