Browse Source

Add Color Gradient mod, Grid Layout, moved const in TTkK

pull/3/head
Eugenio Parodi 5 years ago
parent
commit
d25d93759d
  1. 4
      TermTk/TTkCore/canvas.py
  2. 115
      TermTk/TTkCore/color.py
  3. 8
      TermTk/TTkCore/constant.py
  4. 32
      TermTk/TTkCore/ttk.py
  5. 3
      TermTk/TTkLayouts/__init__.py
  6. 214
      TermTk/TTkLayouts/boxlayout.py
  7. 283
      TermTk/TTkLayouts/gridlayout.py
  8. 544
      TermTk/TTkLayouts/layout.py
  9. 1
      TermTk/TTkWidgets/__init__.py
  10. 9
      TermTk/TTkWidgets/button.py
  11. 347
      TermTk/TTkWidgets/layout.py
  12. 1
      TermTk/TTkWidgets/scrollbar.py
  13. 4
      TermTk/TTkWidgets/splitter.py
  14. 123
      TermTk/TTkWidgets/table.py
  15. 21
      TermTk/TTkWidgets/widget.py
  16. 1
      TermTk/__init__.py
  17. 5
      docs/BUGS.md
  18. 15
      docs/TODO.md
  19. 32
      tests/test.showcase.001.py
  20. 19
      tests/test.ui.003.layout.py
  21. 15
      tests/test.ui.005.labels.py
  22. 32
      tests/test.ui.006.scroll.py
  23. 81
      tests/test.ui.008.table.py

4
TermTk/TTkCore/canvas.py

@ -99,7 +99,7 @@ class TTkCanvas:
_x < self._width and \
_x >= 0 and _y >=0 :
self._data[_y][_x] = _ch
self._colors[_y][_x] = _col
self._colors[_y][_x] = _col.mod(_x,_y)
def drawText(self, pos, text, color=TTkColor.RST):
if not self._visible: return
@ -208,7 +208,7 @@ class TTkCanvas:
def pushToTerminal(self, x, y, w, h):
# TTkLog.debug("pushToTerminal")
lastcolor = None
lastcolor = TTkColor.RST
for y in range(0, self._height):
ansi = lbt.Mv.t(y+1,1)
for x in range(0, self._width):

115
TermTk/TTkCore/color.py

@ -62,12 +62,13 @@ from TermTk.TTkCore.helper import *
# [49m 2.53 set background color to default (black)
class _TTkColor:
__slots__ = ('_fg','_bg','_mod')
__slots__ = ('_fg','_bg','_mod', '_colorMod')
_fg: str; _bg: str; _mod: str
def __init__(self, fg:str="", bg:str="", mod:str=""):
def __init__(self, fg:str="", bg:str="", mod:str="", colorMod=None):
self._fg = fg
self._bg = bg
self._mod = mod
self._colorMod = colorMod
def __str__(self):
return self._fg+self._bg+self._mod
@ -86,8 +87,9 @@ class _TTkColor:
else:
fg: str = self._fg if other._fg == "" else other._fg
bg: str = self._bg if other._bg == "" else other._bg
mod: str = self._mod if other._mod == "" else other._mod
return TTkColor(fg,bg,mod)
mod: str = self._mod + other._mod
colorMod = self._colorMod if other._colorMod == None else other._colorMod
return TTkColor(fg,bg,mod,colorMod)
def __radd__(self, other):
# TTkLog.debug("__radd__")
@ -96,23 +98,116 @@ class _TTkColor:
else:
fg: str = self._fg if other._fg == "" else other._fg
bg: str = self._bg if other._bg == "" else other._bg
mod: str = self._mod if other._mod == "" else other._mod
return TTkColor(fg,bg,mod)
mod: self._mod + other._mod
colorMod = self._colorMod if other._colorMod == None else other._colorMod
return TTkColor(fg,bg,mod,colorMod)
def __sub__(self, other):
# TTkLog.debug("__sub__")
if other is None: return str(self)
# if other is None: return str(self)
if "" == self._bg != other._bg or \
"" == self._fg != other._fg or \
"" == self._mod != other._mod :
return '\033[0m'+self
return str(self)
def modParam(self, *args, **kwargs):
if self._colorMod is None: return self
ret = self.copy()
ret._colorMod.setParam(*args, **kwargs)
return ret
def mod(self, x , y):
if self._colorMod is None: return self
return self._colorMod.exec(x,y,self)
def copy(self, modifier=True):
ret = _TTkColor()
ret._fg = self._fg
ret._bg = self._bg
ret._mod = self._mod
if modifier:
ret._colorMod = self._colorMod.copy()
return ret
class _TTkColorModifier():
def __init__(self, *args, **kwargs): pass
def setParam(self, *args, **kwargs): pass
def copy(self): return self
class TTkColorGradient(_TTkColorModifier):
__slots__ = ('_increment', '_val', '_buffer')
_increment: int; _val: int
def __init__(self, *args, **kwargs):
_TTkColorModifier.__init__(self, *args, **kwargs)
self._increment = kwargs.get("increment",0)
self._val = 0
self._buffer = {}
def setParam(self, *args, **kwargs):
self._val = kwargs.get("val",0)
def exec(self, x, y, color):
def _applyGradient(c):
if c == "": return c
multiplier = abs(self._val + y)
cc = c.split(';')
#TTkLog.debug("Eugenio "+c.replace('\033','<ESC>'))
r = int(cc[2]) + self._increment * multiplier
g = int(cc[3]) + self._increment * multiplier
b = int(cc[4][:-1])+ self._increment * multiplier
if r>255: r=255
if g>255: g=255
if b>255: b=255
if r<0: r=0
if g<0: g=0
if b<0: b=0
return f"{cc[0]};{cc[1]};{r};{g};{b}m"
bname = str(color)
# I made a buffer to keep all the gradient values to speed up the paint process
if bname not in self._buffer:
self._buffer[bname] = [None]*(256*2)
id = self._val + y - 256
if self._buffer[bname][id] is not None:
return self._buffer[bname][id]
copy = color.copy(modifier=False)
copy._fg = _applyGradient(color._fg)
copy._bg = _applyGradient(color._bg)
self._buffer[bname][id] = copy
return self._buffer[bname][id]
def copy(self):
return self
#ret = TTkColorGradient()
#ret._increment = self._increment
#ret._val = self._val
#return ret
class TTkColor(_TTkColor):
RST = _TTkColor('\033[0m')
RST = _TTkColor(fg='\033[0m')
# Modifiers:
BOLD = _TTkColor(mod='\033[1m')
ITALIC = _TTkColor(mod='\033[3m')
UNDERLINE = _TTkColor(mod='\033[4m')
STRIKETROUGH = _TTkColor(mod='\033[9m')
@staticmethod
def fg(*args, **kwargs):
return _TTkColor(fg=TTkHelper.Color.fg(*args, **kwargs))
mod = kwargs.get('modifier', None )
if len(args) > 0:
color = args[0]
else:
color = kwargs.get('color', "" )
return _TTkColor(fg=TTkHelper.Color.fg(color), colorMod=mod)
@staticmethod
def bg(*args, **kwargs):
return _TTkColor(bg=TTkHelper.Color.bg(*args, **kwargs))
mod = kwargs.get('modifier', None )
if len(args) > 0:
color = args[0]
else:
color = kwargs.get('color', "" )
return _TTkColor(bg=TTkHelper.Color.bg(color), colorMod=mod)

8
TermTk/TTkCore/constant.py

@ -50,5 +50,13 @@ class TTkConstant:
WHEEL_Up = 0x00100000 # Wheel Up
WHEEL_Down = 0x00200000 # Wheel Down
# Alignment
NONE = 0x0000
LEFT_ALIGN = 0x0001
RIGHT_ALIGN = 0x0002
CENTER_ALIGN = 0x0003
JUSTIFY = 0x0004
# Alias to TTkConstant
class TTkK(TTkConstant): pass

32
TermTk/TTkCore/ttk.py

@ -31,7 +31,7 @@ from TermTk.TTkCore.constant import TTkConstant, TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.canvas import *
from TermTk.TTkWidgets.layout import *
from TermTk.TTkLayouts.layout import TTkLayout
from TermTk.TTkWidgets.widget import *
class TTkTimer(threading.Thread):
@ -59,21 +59,13 @@ class TTk(TTkWidget):
mouse_events = None
screen_events = None
MOUSE_EVENT = TTkK.MOUSE_EVENT
KEY_EVENT = TTkK.KEY_EVENT
SCREEN_EVENT = TTkK.SCREEN_EVENT
QUIT_EVENT = TTkK.QUIT_EVENT
TIME_EVENT = TTkK.TIME_EVENT
HORIZONTAL = TTkConstant.HORIZONTAL
VERTICAL = TTkConstant.VERTICAL
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
self.events = queue.Queue()
self.key_events = queue.Queue()
self.mouse_events = queue.Queue()
self.screen_events = queue.Queue()
self.setFocusPolicy(TTkWidget.ClickFocus)
TTkHelper.registerRootCanvas(self._canvas)
def mainloop(self):
@ -101,7 +93,7 @@ class TTk(TTkWidget):
while self.running:
# Main Loop
evt = self.events.get()
if evt is TTk.MOUSE_EVENT:
if evt is TTkK.MOUSE_EVENT:
mevt = self.mouse_events.get()
focusWidget = TTkHelper.getFocus()
if focusWidget is not None and mevt.evt != TTkK.Press:
@ -110,19 +102,19 @@ class TTk(TTkWidget):
focusWidget.mouseEvent(nmevt)
else:
self.mouseEvent(mevt)
elif evt is TTk.KEY_EVENT:
elif evt is TTkK.KEY_EVENT:
kevt = self.key_events.get()
self.keyEvent(kevt)
# TTkLog.info(f"Key Event: {kevt}")
pass
elif evt is TTk.TIME_EVENT:
elif evt is TTkK.TIME_EVENT:
TTkHelper.paintAll()
self._timerEvent.set()
pass
elif evt is TTk.SCREEN_EVENT:
elif evt is TTkK.SCREEN_EVENT:
self.setGeometry(0,0,TTkGlbl.term_w,TTkGlbl.term_h)
TTkLog.info(f"Resize: w:{TTkGlbl.term_w}, h:{TTkGlbl.term_h}")
elif evt is TTk.QUIT_EVENT:
elif evt is TTkK.QUIT_EVENT:
TTkLog.debug(f"Quit.")
break
else:
@ -133,21 +125,21 @@ class TTk(TTkWidget):
pass
def _time_event(self):
self.events.put(TTk.TIME_EVENT)
self.events.put(TTkK.TIME_EVENT)
def _win_resize_cb(self, width, height):
TTkGlbl.term_w = int(width)
TTkGlbl.term_h = int(height)
self.events.put(TTk.SCREEN_EVENT)
self.events.put(TTkK.SCREEN_EVENT)
def _input_thread(self):
def _inputCallback(kevt=None, mevt=None):
if kevt is not None:
self.key_events.put(kevt)
self.events.put(TTk.KEY_EVENT)
self.events.put(TTkK.KEY_EVENT)
if mevt is not None:
self.mouse_events.put(mevt)
self.events.put(TTk.MOUSE_EVENT)
self.events.put(TTkK.MOUSE_EVENT)
return self.running
# Start input key loop
lbt.Input.get_key(_inputCallback)
@ -156,7 +148,7 @@ class TTk(TTkWidget):
pass
def quit(self):
self.events.put(TTk.QUIT_EVENT)
self.events.put(TTkK.QUIT_EVENT)
self._timer.quit()
self.running = False

3
TermTk/TTkLayouts/__init__.py

@ -0,0 +1,3 @@
from .layout import *
from .gridlayout import *
from .boxlayout import *

214
TermTk/TTkLayouts/boxlayout.py

@ -0,0 +1,214 @@
#!/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.
'''
Layout System
'''
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
class TTkHBoxLayout(TTkGridLayout): pass
# class TTkHBoxLayout(TTkLayout):
# def __init__(self):
# TTkLayout.__init__(self)
#
# def minimumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# minw = 0
# for item in self.children():
# w1 = item.minimumWidth()
# minw += w1
# return minw
#
# def minimumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# minh = TTkLayout.minimumHeight(self)
# for item in self.children():
# h1 = item.minimumHeight()
# if h1 > minh : minh = h1
# return minh
#
# def maximumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# maxw = 0
# for item in self.children():
# w1 = item.maximumWidth()
# maxw += w1
# return maxw
#
# def maximumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# maxh = TTkLayout.maximumHeight(self)
# for item in self.children():
# h1 = item.maximumHeight()
# if h1 < maxh : maxh = h1
# return maxh
#
# def update(self):
# x, y, w, h = self.geometry()
# numWidgets = self.count()
# leftWidgets = numWidgets
# freeWidth = w
# newx, newy = x, y
# # Loop to check the resizable space
# for item in self.children():
# item._sMax = False
# item._sMin = False
# iterate = True
#
# # Copy and Sort list of items based on the minsize
# sortedItems = sorted(self.children(), key=lambda item: item.minimumWidth())
#
# while iterate and leftWidgets > 0:
# iterate = False
# for item in sortedItems:
# if item._sMax or item._sMin: continue
# sliceSize = freeWidth//leftWidgets
# maxs = item.maximumWidth()
# mins = item.minimumWidth()
# if sliceSize >= maxs:
# freeWidth -= maxs
# iterate = True
# item._sMax = True
# item._sMaxVal = maxs
# leftWidgets -= 1
# elif sliceSize < mins:
# freeWidth -= mins
# leftWidgets -= 1
# iterate = True
# item._sMin = True
# item._sMinVal = mins
#
# # loop and set the geometry of any item
# for item in self.children():
# if item._sMax:
# item.setGeometry(newx, newy, item._sMaxVal, h)
# newx += item._sMaxVal
# elif item._sMin:
# item.setGeometry(newx, newy, item._sMinVal, h)
# newx += item._sMinVal
# else:
# sliceSize = freeWidth//leftWidgets
# item.setGeometry(newx, newy, sliceSize, h)
# newx += sliceSize
# freeWidth -= sliceSize
# leftWidgets -= 1
# if isinstance(item, TTkWidgetItem) and not item.isEmpty():
# item.widget().update()
# elif isinstance(item, TTkLayout):
# item.update()
class TTkVBoxLayout(TTkLayout):
def __init__(self):
TTkLayout.__init__(self)
def minimumWidth(self) -> int:
''' process the widgets and get the min size '''
minw = TTkLayout.minimumWidth(self)
for item in self.children():
w1 = item.minimumWidth()
if w1 > minw : minw = w1
return minw
def minimumHeight(self) -> int:
''' process the widgets and get the min size '''
minh = 0
for item in self.children():
h1 = item.minimumHeight()
minh += h1
return minh
def maximumWidth(self) -> int:
''' process the widgets and get the min size '''
maxw = TTkLayout.maximumWidth(self)
for item in self.children():
w1 = item.maximumWidth()
if w1 < maxw : maxw = w1
return maxw
def maximumHeight(self) -> int:
''' process the widgets and get the min size '''
maxh = 0
for item in self.children():
h1 = item.maximumHeight()
maxh += h1
return maxh
def update(self):
x, y, w, h = self.geometry()
numWidgets = self.count()
leftWidgets = numWidgets
freeHeight = h
newx, newy = x, y
# Loop to check the resizable space
for item in self.children():
item._sMax = False
item._sMin = False
iterate = True
# Copy and Sort list of items based on the minsize
sortedItems = sorted(self.children(), key=lambda item: item.minimumHeight())
while iterate and leftWidgets > 0:
iterate = False
for item in sortedItems:
if item._sMax or item._sMin: continue
sliceSize = freeHeight//leftWidgets
maxs = item.maximumHeight()
mins = item.minimumHeight()
if sliceSize >= maxs:
freeHeight -= maxs
iterate = True
item._sMax = True
item._sMaxVal = maxs
leftWidgets -= 1
elif sliceSize < mins:
freeHeight -= mins
leftWidgets -= 1
iterate = True
item._sMin = True
item._sMinVal = mins
# loop and set the geometry of any item
for item in self.children():
if item._sMax:
item.setGeometry(newx, newy, w, item._sMaxVal)
newy += item._sMaxVal
elif item._sMin:
item.setGeometry(newx, newy, w, item._sMinVal)
newy += item._sMinVal
else:
sliceSize = freeHeight//leftWidgets
item.setGeometry(newx, newy, w, sliceSize)
newy += sliceSize
freeHeight -= sliceSize
leftWidgets -= 1
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
item.widget().update()
elif isinstance(item, TTkLayout):
item.update()

283
TermTk/TTkLayouts/gridlayout.py

@ -0,0 +1,283 @@
#!/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.
'''
Layout System
'''
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem
class TTkGridWidgetItem(TTkWidgetItem):
__slots__ = ('_row','_col')
def __init__(self, *args, **kwargs):
TTkWidgetItem.__init__(self, args[0])
self._row = kwargs.get('row')
self._col = kwargs.get('col')
class TTkGridLayout(TTkLayout):
__slots__ = ('_gridItems','_columnMinWidth','_columnMinHeight')
def __init__(self, *args, **kwargs):
TTkLayout.__init__(self, args, kwargs)
self._gridItems = [[]]
self._columnMinWidth = kwargs.get('columnMinWidth',0)
self._columnMinHeight = kwargs.get('columnMinHeight',0)
def _gridUsedsize(self):
rows = 1
cols = 0
for gridRow in range(len(self._gridItems)):
if rows < gridRow:
rows = gridRow
for gridCol in range(len(self._gridItems[0])):
if self._gridItems[gridRow][gridCol] is not None:
if cols < gridCol:
cols = gridCol
return (rows+1, cols+1)
def _reshapeGrid(self, size):
rows = size[0]
cols = size[1]
# remove extra rows
if rows < len(self._gridItems):
self._gridItems = self._gridItems[:rows]
elif rows > len(self._gridItems):
self._gridItems += [None]*(rows-len(self._gridItems))
# remove extra cols
for gridRow in range(len(self._gridItems)):
if self._gridItems[gridRow] is None:
self._gridItems[gridRow] = [None]*(cols+1)
continue
sizeRow = len(self._gridItems[gridRow])
if cols < sizeRow:
self._gridItems[gridRow] = self._gridItems[gridRow][:cols]
elif cols > sizeRow:
self._gridItems[gridRow] += [None]*(cols-sizeRow)
# addWidget(self, widget, row, col)
def addWidget(self, *args, **kwargs):
widget = args[0]
if len(args) == 3:
row = args[1]
col = args[2]
else:
# Append The widget at the end
row = 0
col = len(self._gridItems[0])
#retrieve the max col/rows to reshape the grid
maxrow = row
maxcol = col
for item in self.children():
if maxrow < item._row: maxrow = item._row
if maxcol < item._col: maxcol = item._col
# reshape the gridItems
maxrow += 1
maxcol += 1
self._reshapeGrid(size=(maxrow,maxcol))
if self._gridItems[row][col] is not None:
# TODO: Handle the LayoutItem
self.removeWidget(self._gridItems[row][col])
item = TTkGridWidgetItem(widget, row=row, col=col)
self._gridItems[row][col] = item
self.addItem(item)
def removeWidget(self, widget):
TTkLayout.removeWidget(self, widget)
for gridRow in range(len(self._gridItems)):
for gridCol in range(len(self._gridItems[0])):
if self._gridItems[gridRow][gridCol] is not None and \
self._gridItems[gridRow][gridCol].widget() == widget:
self._gridItems[gridRow][gridCol] = None
self._reshapeGrid(self._gridUsedsize())
def itemAtPosition(self, row: int, col: int):
if row >= len(self._gridItems) or \
col >= len(self._gridItems[0]):
return None
return self._gridItems[row][col]
def minimumColWidth(self, gridCol: int) -> int:
colw = 0
anyItem = False
for gridRow in range(len(self._gridItems)):
item = self._gridItems[gridRow][gridCol]
if item is not None:
anyItem = True
w = item.minimumWidth()
if colw < w:
colw = w
if not anyItem:
return self._columnMinWidth
return colw
def minimumRowHeight(self, gridRow: int):
rowh = 0
anyItem = False
for item in self._gridItems[gridRow]:
if item is not None:
anyItem = True
h = item.minimumHeight()
if rowh < h:
rowh = h
if not anyItem:
return self._columnMinHeight
return rowh
def maximumColWidth(self, gridCol: int) -> int:
colw = 0x10000
anyItem = False
for gridRow in range(len(self._gridItems)):
item = self._gridItems[gridRow][gridCol]
if item is not None:
anyItem = True
w = item.maximumWidth()
if colw > w:
colw = w
if not anyItem:
return self._columnMinWidth
return colw
def maximumRowHeight(self, gridRow: int):
rowh = 0x10000
anyItem = False
for item in self._gridItems[gridRow]:
if item is not None:
anyItem = True
h = item.maximumHeight()
if rowh > h:
rowh = h
if not anyItem:
return self._columnMinHeight
return rowh
def minimumWidth(self) -> int:
''' process the widgets and get the min size '''
minw = 0
for gridCol in range(len(self._gridItems[0])):
minw += self.minimumColWidth(gridCol)
return minw
def minimumHeight(self) -> int:
''' process the widgets and get the min size '''
minh = 0
for gridRow in range(len(self._gridItems)):
minh += self.minimumRowHeight(gridRow)
return minh
def maximumWidth(self) -> int:
''' process the widgets and get the min size '''
maxw = 0
for gridCol in range(len(self._gridItems[0])):
maxw += self.maximumColWidth(gridCol)
return maxw
def maximumHeight(self) -> int:
''' process the widgets and get the min size '''
maxh = 0
for gridRow in range(len(self._gridItems)):
maxh += self.maximumRowHeight(gridRow)
return maxh
def update(self):
x, y, w, h = self.geometry()
newx, newy = x, y
# Sorted List of minimum heights
# min max val
# content IDs 0 1 2 3
sortedHeights = [ [i, self.minimumRowHeight(i), self.maximumRowHeight(i), -1] for i in range(len(self._gridItems)) ]
sortedWidths = [ [i, self.minimumColWidth(i), self.maximumColWidth(i), -1] for i in range(len(self._gridItems[0])) ]
sortedHeights = sorted(sortedHeights, key=lambda h: h[1])
sortedWidths = sorted(sortedWidths, key=lambda w: w[1])
minWidth = 0
minHeight = 0
for i in sortedWidths: minWidth += i[1]
for i in sortedHeights: minHeight += i[1]
if h < minHeight: h = minHeight
if w < minWidth: w = minWidth
# TTkLog.debug(f"w,h:({w,h}) mh:{minHeight} sh:{sortedHeights}")
# TTkLog.debug(f"w,h:({w,h}) mw:{minWidth} sw:{sortedWidths}")
def parseSizes(sizes, space, out):
iterate = True
freeSpace = space
leftSlots = len(sizes)
while iterate and leftSlots > 0:
iterate = False
for item in sizes:
if item[3] != -1: continue
if freeSpace < 0: freeSpace=0
sliceSize = freeSpace//leftSlots
mins = item[1]
maxs = item[2]
if sliceSize >= maxs:
iterate = True
freeSpace -= maxs
leftSlots -= 1
item[3] = maxs
elif sliceSize < mins:
iterate = True
freeSpace -= mins
leftSlots -= 1
item[3] = mins
# Push the sizes
for item in sizes:
out[item[0]] = [0,item[3]]
if item[3] == -1:
sliceSize = freeSpace//leftSlots
out[item[0]] = [0,sliceSize]
freeSpace -= sliceSize
leftSlots -= 1
vertSizes = [None]*len(sortedHeights)
horSizes = [None]*len(sortedWidths)
parseSizes(sortedHeights,h, vertSizes)
parseSizes(sortedWidths, w, horSizes)
for i in horSizes:
i[0] = newx
newx += i[1]
for i in vertSizes:
i[0] = newy
newy += i[1]
# loop and set the geometry of any item
for item in self.children():
col = item._col
row = item._row
item.setGeometry(
horSizes[col][0], vertSizes[row][0] ,
horSizes[col][1], vertSizes[row][1] )
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
item.widget().update()
elif isinstance(item, TTkLayout):
item.update()

544
TermTk/TTkLayouts/layout.py

@ -0,0 +1,544 @@
#!/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.
'''
Layout System
'''
from TermTk.TTkCore.log import TTkLog
class TTkLayoutItem:
__slots__ = ('_x', '_y', '_w', '_h', '_sMax', '_sMaxVal', '_sMin', '_sMinVal')
def __init__(self, *args, **kwargs):
self._x, self._y = 0, 0
self._w, self._h = 0, 0
self._sMax, self._sMin = False, False
self._sMaxVal, self._sMinVal = 0, 0
pass
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
def minimumHeight(self) -> int: return 0
def minimumWidth(self) -> int: return 0
def maximumSize(self):
return self.maximumWidth(), self.maximumHeight()
def maximumHeight(self) -> int: return 0x80000000
def maximumWidth(self) -> int: return 0x80000000
def geometry(self):
return self._x, self._y, self._w, self._h
def setGeometry(self, x, y, w, h):
self._x = x
self._y = y
self._w = w
self._h = h
class TTkLayout(TTkLayoutItem):
__slots__ = ('_items', '_zSortedItems', '_parent')
def __init__(self, *args, **kwargs):
TTkLayoutItem.__init__(self, args, kwargs)
self._items = []
self._zSortedItems = []
self._parent = None
pass
def children(self):
return self._items
def count(self):
return len(self._items)
def itemAt(self, index):
if index < len(self._items):
return self._items[index]
return 0
def setParent(self, parent):
self._parent = parent
def parentWidget(self):
return self._parent
def _zSortItems(self):
self._zSortedItems = sorted(self._items, key=lambda item: item.z)
@property
def zSortedItems(self): return self._zSortedItems
def addItem(self, item):
self._items.append(item)
self._zSortItems()
def addWidget(self, widget):
if widget.parentWidget() is not None:
widget.parentWidget().removeWidget(self)
self.addItem(TTkWidgetItem(widget))
def removeWidget(self, widget):
for i in self._items:
if i.widget() == widget:
self._items.remove(i)
return
self._zSortItems()
def raiseWidget(self, widget):
maxz = 0
item = None
for i in self._items:
if i.widget() == widget:
item = i
elif i.z >= maxz:
maxz=i.z+1
item.z = maxz
self._zSortItems()
def lowerWidget(self, widget):
minz = 0
item = None
for i in self._items:
if i.widget() == widget:
item = i
elif i.z <= minz:
minz=i.z-1
item.z = minz
self._zSortItems()
def update(self):
for i in self.children():
if isinstance(i, TTkWidgetItem) and not i.isEmpty():
i.widget().update()
# TODO: Have a look at this:
# i.getCanvas().top()
elif isinstance(i, TTkLayout):
i.update()
class TTkWidgetItem(TTkLayoutItem):
slots = ('_widget','_z')
def __init__(self, widget, z=0):
TTkLayoutItem.__init__(self)
self._widget = widget
self.z = z
def widget(self):
return self._widget
def isEmpty(self): return self._widget is None
def minimumSize(self) -> int: return self._widget.minimumSize()
def minimumHeight(self)-> int: return self._widget.minimumHeight()
def minimumWidth(self) -> int: return self._widget.minimumWidth()
def maximumSize(self) -> int: return self._widget.maximumSize()
def maximumHeight(self)-> int: return self._widget.maximumHeight()
def maximumWidth(self) -> int: return self._widget.maximumWidth()
def geometry(self): return self._widget.geometry()
def setGeometry(self, x, y, w, h):
self._widget.setGeometry(x, y, w, h)
@property
def z(self): return self._z
@z.setter
def z(self, z): self._z = z
#class TTkHBoxLayout(TTkLayout):
# def __init__(self):
# TTkLayout.__init__(self)
#
# def minimumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# minw = 0
# for item in self.children():
# w1 = item.minimumWidth()
# minw += w1
# return minw
#
# def minimumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# minh = TTkLayout.minimumHeight(self)
# for item in self.children():
# h1 = item.minimumHeight()
# if h1 > minh : minh = h1
# return minh
#
# def maximumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# maxw = 0
# for item in self.children():
# w1 = item.maximumWidth()
# maxw += w1
# return maxw
#
# def maximumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# maxh = TTkLayout.maximumHeight(self)
# for item in self.children():
# h1 = item.maximumHeight()
# if h1 < maxh : maxh = h1
# return maxh
#
# def update(self):
# x, y, w, h = self.geometry()
# numWidgets = self.count()
# leftWidgets = numWidgets
# freeWidth = w
# newx, newy = x, y
# # Loop to check the resizable space
# for item in self.children():
# item._sMax = False
# item._sMin = False
# iterate = True
#
# # Copy and Sort list of items based on the minsize
# sortedItems = sorted(self.children(), key=lambda item: item.minimumWidth())
#
# while iterate and leftWidgets > 0:
# iterate = False
# for item in sortedItems:
# if item._sMax or item._sMin: continue
# sliceSize = freeWidth//leftWidgets
# maxs = item.maximumWidth()
# mins = item.minimumWidth()
# if sliceSize >= maxs:
# freeWidth -= maxs
# iterate = True
# item._sMax = True
# item._sMaxVal = maxs
# leftWidgets -= 1
# elif sliceSize < mins:
# freeWidth -= mins
# leftWidgets -= 1
# iterate = True
# item._sMin = True
# item._sMinVal = mins
#
# # loop and set the geometry of any item
# for item in self.children():
# if item._sMax:
# item.setGeometry(newx, newy, item._sMaxVal, h)
# newx += item._sMaxVal
# elif item._sMin:
# item.setGeometry(newx, newy, item._sMinVal, h)
# newx += item._sMinVal
# else:
# sliceSize = freeWidth//leftWidgets
# item.setGeometry(newx, newy, sliceSize, h)
# newx += sliceSize
# freeWidth -= sliceSize
# leftWidgets -= 1
# if isinstance(item, TTkWidgetItem) and not item.isEmpty():
# item.widget().update()
# elif isinstance(item, TTkLayout):
# item.update()
#
#
#class TTkVBoxLayout(TTkLayout):
# def __init__(self):
# TTkLayout.__init__(self)
#
# def minimumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# minw = TTkLayout.minimumWidth(self)
# for item in self.children():
# w1 = item.minimumWidth()
# if w1 > minw : minw = w1
# return minw
#
# def minimumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# minh = 0
# for item in self.children():
# h1 = item.minimumHeight()
# minh += h1
# return minh
#
# def maximumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# maxw = TTkLayout.maximumWidth(self)
# for item in self.children():
# w1 = item.maximumWidth()
# if w1 < maxw : maxw = w1
# return maxw
#
# def maximumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# maxh = 0
# for item in self.children():
# h1 = item.maximumHeight()
# maxh += h1
# return maxh
#
# def update(self):
# x, y, w, h = self.geometry()
# numWidgets = self.count()
# leftWidgets = numWidgets
# freeHeight = h
# newx, newy = x, y
# # Loop to check the resizable space
# for item in self.children():
# item._sMax = False
# item._sMin = False
# iterate = True
#
# # Copy and Sort list of items based on the minsize
# sortedItems = sorted(self.children(), key=lambda item: item.minimumHeight())
#
# while iterate and leftWidgets > 0:
# iterate = False
# for item in sortedItems:
# if item._sMax or item._sMin: continue
# sliceSize = freeHeight//leftWidgets
# maxs = item.maximumHeight()
# mins = item.minimumHeight()
# if sliceSize >= maxs:
# freeHeight -= maxs
# iterate = True
# item._sMax = True
# item._sMaxVal = maxs
# leftWidgets -= 1
# elif sliceSize < mins:
# freeHeight -= mins
# leftWidgets -= 1
# iterate = True
# item._sMin = True
# item._sMinVal = mins
#
# # loop and set the geometry of any item
# for item in self.children():
# if item._sMax:
# item.setGeometry(newx, newy, w, item._sMaxVal)
# newy += item._sMaxVal
# elif item._sMin:
# item.setGeometry(newx, newy, w, item._sMinVal)
# newy += item._sMinVal
# else:
# sliceSize = freeHeight//leftWidgets
# item.setGeometry(newx, newy, w, sliceSize)
# newy += sliceSize
# freeHeight -= sliceSize
# leftWidgets -= 1
# if isinstance(item, TTkWidgetItem) and not item.isEmpty():
# item.widget().update()
# elif isinstance(item, TTkLayout):
# item.update()
#
#class TTkGridWidgetItem(TTkWidgetItem):
# __slots__ = ('_row','_col')
# def __init__(self, *args, **kwargs):
# TTkWidgetItem.__init__(self, args[0])
# self._row = kwargs.get('row')
# self._col = kwargs.get('col')
#
#class TTkGridLayout(TTkLayout):
# __slots__ = ('_gridItems')
# def __init__(self):
# TTkLayout.__init__(self)
# self._gridItems = [[]]
#
# # addWidget(self, widget, row, col)
# def addWidget(self, *args, **kwargs):
# if len(args) == 3:
# row = args[1]
# col = args[2]
# else:
# # Append The widget at the end
# row = 0
# col = len(self._gridItems[0])
# #retrieve the max col/rows to reshape the grid
# maxrow = row + 1
# maxcol = col + 1
# for item in self.children():
# if maxrow < item._row: maxrow = item._row + 1
# if maxcol < item._col: maxcol = item._col + 1
# # reshape the gridItems
# if len(self._gridItems) > maxrow:
# self._gridItems = self._gridItems[:maxrow]
# if len(self._gridItems) < maxrow:
# self._gridItems += [[]]*(maxrow-len(self._gridItems))
# for gridRow in range(len(self._gridItems)):
# if len(self._gridItems[gridRow]) > maxcol:
# self._gridItems[gridRow] = self._gridItems[gridRow][:maxcol]
# if len(self._gridItems[gridRow]) < maxcol:
# self._gridItems[gridRow] += [None]*(maxcol-len(self._gridItems[gridRow]))
# if self._gridItems[row][col] is not None:
# # TODO: Handle the LayoutItem
# self.removeWidget(self._gridItems[row][col])
#
# item = TTkGridWidgetItem(args[0], row=row, col=col)
# self._gridItems[row][col] = item
# self.addItem(item)
#
# def itemAtPosition(self, row: int, col: int):
# if row >= len(self._gridItems) or \
# col >= len(self._gridItems[0]):
# return None
# return self._gridItems[row][col]
#
# def minimumColWidth(self, gridCol: int) -> int:
# colw = 0
# for gridRow in range(len(self._gridItems)):
# item = self._gridItems[gridRow][gridCol]
# if item is not None:
# w = item.minimumWidth()
# if colw < w:
# colw = w
# return colw
#
# def minimumRowHeight(self, gridRow: int):
# rowh = 0
# for item in self._gridItems[gridRow]:
# if item is not None:
# h = item.minimumHeight()
# if rowh < h:
# rowh = h
# return rowh
#
# def maximumColWidth(self, gridCol: int) -> int:
# colw = 0x10000
# for gridRow in range(len(self._gridItems)):
# item = self._gridItems[gridRow][gridCol]
# if item is not None:
# w = item.maximumWidth()
# if colw > w:
# colw = w
# return colw
#
# def maximumRowHeight(self, gridRow: int):
# rowh = 0x10000
# for item in self._gridItems[gridRow]:
# if item is not None:
# h = item.maximumHeight()
# if rowh > h:
# rowh = h
# return rowh
#
# def minimumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# minw = 0
# for gridCol in range(len(self._gridItems[0])):
# minw += self.minimumColWidth(gridCol)
# return minw
#
# def minimumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# minh = 0
# for gridRow in range(len(self._gridItems)):
# minh += self.minimumRowHeight(gridRow)
# return minh
#
# def maximumWidth(self) -> int:
# ''' process the widgets and get the min size '''
# maxw = 0
# for gridCol in range(len(self._gridItems[0])):
# maxw += self.maximumColWidth(gridCol)
# return maxw
#
# def maximumHeight(self) -> int:
# ''' process the widgets and get the min size '''
# maxh = 0
# for gridRow in range(len(self._gridItems)):
# maxh += self.maximumRowHeight(gridRow)
# return maxh
#
#
# def update(self):
# x, y, w, h = self.geometry()
# newx, newy = x, y
# TTkLog.debug(f"1) x:{x} y:{y} w:{w} h:{h}")
#
# # Sorted List of minimum heights
# # 0 1 2 3
# sortedHeights = [ [i,self.minimumRowHeight(i),self.maximumRowHeight(i),-1] for i in range(len(self._gridItems)) ]
# sortedWidths = [ [i,self.minimumColWidth(i), self.maximumColWidth(i), -1] for i in range(len(self._gridItems[0])) ]
# sortedHeights = sorted(sortedHeights, key=lambda h: h[1])
# sortedWidths = sorted(sortedWidths, key=lambda w: w[1])
#
# minWidth = 0
# minHeight = 0
# for i in sortedWidths: minWidth += i[1]
# for i in sortedHeights: minHeight += i[1]
#
# if h < minHeight: h = minHeight
# if w < minWidth: w = minWidth
# TTkLog.debug(f"2) x:{x} y:{y} w:{w} h:{h} - {self._gridItems}")
#
# def parseSizes(sizes, space, out):
# iterate = True
# freeSpace = space
# leftSlots = len(sizes)+1
# while iterate and leftSlots > 0:
# iterate = False
# for item in sizes:
# if item[3] != -1: continue
# if freeSpace < 0: freeSpace=0
# sliceSize = freeSpace//leftSlots
# mins = item[1]
# maxs = item[2]
# if sliceSize >= maxs:
# iterate = True
# freeSpace -= maxs
# leftSlots -= 1
# item[3] = maxs
# elif sliceSize < mins:
# iterate = True
# freeSpace -= mins
# leftSlots -= 1
# item[3] = mins
# # Push the sizes
# TTkLog.debug(f"2) sizes:{sizes}, space:{space}, fs:{freeSpace}, ls:{leftSlots}")
# for item in sizes:
# out[item[0]] = [0,item[3]]
# if item[3] != -1:
# sliceSize = freeSpace//leftSlots
# out[item[0]] = [0,sliceSize]
# freeSpace -= sliceSize
# leftSlots -= 1
#
# vertSizes = [None]*len(sortedHeights)
# horSizes = [None]*len(sortedWidths)
# parseSizes(sortedHeights,h, vertSizes)
# parseSizes(sortedWidths, w, horSizes)
#
# for i in horSizes:
# i[0] = newx
# newx += i[1]
# for i in vertSizes:
# i[0] = newy
# newy += i[1]
#
# # loop and set the geometry of any item
# for item in self.children():
# col = item._col
# row = item._row
# item.setGeometry(horSizes[col][0], vertSizes[row][0], 10, 3)
# if isinstance(item, TTkWidgetItem) and not item.isEmpty():
# item.widget().update()
# elif isinstance(item, TTkLayout):
# item.update()
#

1
TermTk/TTkWidgets/__init__.py

@ -1,5 +1,4 @@
from .widget import *
from .layout import *
from .spacer import *
from .frame import *
from .button import *

9
TermTk/TTkWidgets/button.py

@ -46,10 +46,13 @@ class TTkButton(TTkWidget):
def paintEvent(self):
if self._pressed:
borderColor = TTkColor.fg("#00ffff")
textColor = TTkColor.fg("#0000ff")
# borderColor = TTkColor.fg("#00ffff")
# textColor = TTkColor.fg("#0000ff")
borderColor = TTkColor.fg("#ffff88")+TTkColor.BOLD
textColor = TTkColor.fg("#00ff00")+TTkColor.BOLD
else:
borderColor = TTkColor.fg("#ffff00")
# borderColor = TTkColor.fg("#ffff00")
borderColor = TTkColor.RST
textColor = TTkColor.fg("#00ff00")
self._canvas.drawText(pos=(1,1), color=textColor ,text=self.text)
if self._border:

347
TermTk/TTkWidgets/layout.py

@ -1,347 +0,0 @@
#!/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.
'''
Layout System
'''
from TermTk.TTkCore.log import TTkLog
class TTkLayoutItem:
__slots__ = ('_x', '_y', '_w', '_h', '_sMax', '_sMaxVal', '_sMin', '_sMinVal')
def __init__(self):
self._x, self._y = 0, 0
self._w, self._h = 0, 0
self._sMax, self._sMin = False, False
self._sMaxVal, self._sMinVal = 0, 0
pass
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
def minimumHeight(self): return 0
def minimumWidth(self): return 0
def maximumSize(self):
return self.maximumWidth(), self.maximumHeight()
def maximumHeight(self): return 0x80000000
def maximumWidth(self): return 0x80000000
def geometry(self):
return self._x, self._y, self._w, self._h
def setGeometry(self, x, y, w, h):
self._x = x
self._y = y
self._w = w
self._h = h
class TTkLayout(TTkLayoutItem):
__slots__ = ('_items', '_zSortedItems', '_parent')
def __init__(self):
TTkLayoutItem.__init__(self)
self._items = []
self._zSortedItems = []
self._parent = None
pass
def children(self):
return self._items
def count(self):
return len(self._items)
def itemAt(self, index):
if index < len(self._items):
return self._items[index]
return 0
def setParent(self, parent):
self._parent = parent
def parentWidget(self):
return self._parent
def _zSortItems(self):
self._zSortedItems = sorted(self._items, key=lambda item: item.z)
@property
def zSortedItems(self): return self._zSortedItems
def addItem(self, item):
self._items.append(item)
self._zSortItems()
def addWidget(self, widget):
self.addItem(TTkWidgetItem(widget))
def removeWidget(self, widget):
for i in self._items:
if i.widget() == widget:
self._items.remove(i)
return
self._zSortItems()
def raiseWidget(self, widget):
maxz = 0
item = None
for i in self._items:
if i.widget() == widget:
item = i
elif i.z >= maxz:
maxz=i.z+1
item.z = maxz
self._zSortItems()
def lowerWidget(self, widget):
minz = 0
item = None
for i in self._items:
if i.widget() == widget:
item = i
elif i.z <= minz:
minz=i.z-1
item.z = minz
self._zSortItems()
def update(self):
for i in self.children():
if isinstance(i, TTkWidgetItem) and not i.isEmpty():
i.widget().update()
# TODO: Have a look at this:
# i.getCanvas().top()
elif isinstance(i, TTkLayout):
i.update()
class TTkWidgetItem(TTkLayoutItem):
slots = ('_widget','_z')
def __init__(self, widget, z=0):
TTkLayoutItem.__init__(self)
self._widget = widget
self.z = z
def widget(self):
return self._widget
def isEmpty(self): return self._widget is None
def minimumSize(self): return self._widget.minimumSize()
def minimumHeight(self): return self._widget.minimumHeight()
def minimumWidth(self): return self._widget.minimumWidth()
def maximumSize(self): return self._widget.maximumSize()
def maximumHeight(self): return self._widget.maximumHeight()
def maximumWidth(self): return self._widget.maximumWidth()
def geometry(self): return self._widget.geometry()
def setGeometry(self, x, y, w, h):
self._widget.setGeometry(x, y, w, h)
@property
def z(self): return self._z
@z.setter
def z(self, z): self._z = z
class TTkHBoxLayout(TTkLayout):
def __init__(self):
TTkLayout.__init__(self)
def minimumWidth(self):
''' process the widgets and get the min size '''
minw = 0
for item in self.children():
w1 = item.minimumWidth()
minw += w1
return minw
def minimumHeight(self):
''' process the widgets and get the min size '''
minh = TTkLayout.minimumHeight(self)
for item in self.children():
h1 = item.minimumHeight()
if h1 > minh : minh = h1
return minh
def maximumWidth(self):
''' process the widgets and get the min size '''
maxw = 0
for item in self.children():
w1 = item.maximumWidth()
maxw += w1
return maxw
def maximumHeight(self):
''' process the widgets and get the min size '''
maxh = TTkLayout.maximumHeight(self)
for item in self.children():
h1 = item.maximumHeight()
if h1 < maxh : maxh = h1
return maxh
def update(self):
x, y, w, h = self.geometry()
numWidgets = self.count()
leftWidgets = numWidgets
freeWidth = w
newx, newy = x, y
# Loop to check the resizable space
for item in self.children():
item._sMax = False
item._sMin = False
iterate = True
# Copy and Sort list of items based on the minsize
sortedItems = sorted(self.children(), key=lambda item: item.minimumWidth())
while iterate and leftWidgets > 0:
iterate = False
for item in sortedItems:
if item._sMax or item._sMin: continue
sliceSize = freeWidth//leftWidgets
maxs = item.maximumWidth()
mins = item.minimumWidth()
if sliceSize >= maxs:
freeWidth -= maxs
iterate = True
item._sMax = True
item._sMaxVal = maxs
leftWidgets -= 1
elif sliceSize < mins:
freeWidth -= mins
leftWidgets -= 1
iterate = True
item._sMin = True
item._sMinVal = mins
# loop and set the geometry of any item
for item in self.children():
if item._sMax:
item.setGeometry(newx, newy, item._sMaxVal, h)
newx += item._sMaxVal
elif item._sMin:
item.setGeometry(newx, newy, item._sMinVal, h)
newx += item._sMinVal
else:
sliceSize = freeWidth//leftWidgets
item.setGeometry(newx, newy, sliceSize, h)
newx += sliceSize
freeWidth -= sliceSize
leftWidgets -= 1
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
item.widget().update()
elif isinstance(item, TTkLayout):
item.update()
class TTkVBoxLayout(TTkLayout):
def __init__(self):
TTkLayout.__init__(self)
def minimumWidth(self):
''' process the widgets and get the min size '''
minw = TTkLayout.minimumWidth(self)
for item in self.children():
w1 = item.minimumWidth()
if w1 > minw : minw = w1
return minw
def minimumHeight(self):
''' process the widgets and get the min size '''
minh = 0
for item in self.children():
h1 = item.minimumHeight()
minh += h1
return minh
def maximumWidth(self):
''' process the widgets and get the min size '''
maxw = TTkLayout.maximumWidth(self)
for item in self.children():
w1 = item.maximumWidth()
if w1 < maxw : maxw = w1
return maxw
def maximumHeight(self):
''' process the widgets and get the min size '''
maxh = 0
for item in self.children():
h1 = item.maximumHeight()
maxh += h1
return maxh
def update(self):
x, y, w, h = self.geometry()
numWidgets = self.count()
leftWidgets = numWidgets
freeHeight = h
newx, newy = x, y
# Loop to check the resizable space
for item in self.children():
item._sMax = False
item._sMin = False
iterate = True
# Copy and Sort list of items based on the minsize
sortedItems = sorted(self.children(), key=lambda item: item.minimumHeight())
while iterate and leftWidgets > 0:
iterate = False
for item in sortedItems:
if item._sMax or item._sMin: continue
sliceSize = freeHeight//leftWidgets
maxs = item.maximumHeight()
mins = item.minimumHeight()
if sliceSize >= maxs:
freeHeight -= maxs
iterate = True
item._sMax = True
item._sMaxVal = maxs
leftWidgets -= 1
elif sliceSize < mins:
freeHeight -= mins
leftWidgets -= 1
iterate = True
item._sMin = True
item._sMinVal = mins
# loop and set the geometry of any item
for item in self.children():
if item._sMax:
item.setGeometry(newx, newy, w, item._sMaxVal)
newy += item._sMaxVal
elif item._sMin:
item.setGeometry(newx, newy, w, item._sMinVal)
newy += item._sMinVal
else:
sliceSize = freeHeight//leftWidgets
item.setGeometry(newx, newy, w, sliceSize)
newy += sliceSize
freeHeight -= sliceSize
leftWidgets -= 1
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
item.widget().update()
elif isinstance(item, TTkLayout):
item.update()

1
TermTk/TTkWidgets/scrollbar.py

@ -229,6 +229,7 @@ class TTkScrollBar(TTkWidget):
def value(self, v):
if v > self._maximum: v = self._maximum
if v < self._minimum: v = self._minimum
if self._value == v: return
self._value = v
self.valueChanged.emit(v)
self.update()

4
TermTk/TTkWidgets/splitter.py

@ -36,7 +36,7 @@ class TTkSplitter(TTkFrame):
self._name = kwargs.get('name' , 'TTkSplitter' )
self._widgets = []
self._splitters = []
self._orientation = kwargs.get('orientation' , TTk.HORIZONTAL )
self._orientation = kwargs.get('orientation' , TTkK.HORIZONTAL )
def addWidget(self, widget):
# NOTE: Check with the max/min size if the new widget can fit
@ -46,7 +46,7 @@ class TTkSplitter(TTkFrame):
def _rearrange(self):
w, h = self.size()
if self._orientation == TTk.HORIZONTAL:
if self._orientation == TTkK.HORIZONTAL:
pass
else:
pass

123
TermTk/TTkWidgets/table.py

@ -26,8 +26,8 @@ from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkLayouts.boxlayout import TTkHBoxLayout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.layout import *
from TermTk.TTkWidgets.spacer import TTkSpacer
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
@ -36,30 +36,59 @@ from TermTk.TTkWidgets.scrollbar import TTkScrollBar
'''
class TTkTable(TTkWidget):
__slots__ = ('_hlayout','_vscroller','_columns','_tableData', '_moveTo')
__slots__ = ('_hlayout','_vscroller', '_header', '_alignments', '_headerColor', '_columns', '_columnColors', '_selectColor', '_tableData', '_moveTo', '_selected')
def __init__(self, *args, **kwargs):
self._vscroller = None # This is required to avoid crash int he vScroller Tuning
self._moveTo = 0
self._tableData = []
TTkWidget.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkTable' )
self._columns = kwargs.get('columns' , 'TTkTable' )
self._columns = kwargs.get('columns' , [] )
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
self._columnColors = kwargs.get('columnColors' , [TTkColor.RST]*len(self._columns) )
self._selectColor = kwargs.get('selectColor' , TTkColor.BOLD )
self._headerColor = kwargs.get('headerColor' , TTkColor.BOLD )
self._hlayout = TTkHBoxLayout()
self.setLayout(self._hlayout)
self._selected = -1
TTkSpacer(parent=self)
self._vscroller = TTkScrollBar(parent=self)
self._vscroller.valueChanged.connect(self.scrollTo)
self.setFocusPolicy(TTkWidget.ClickFocus)
def setAlignment(self, alignments):
if len(alignments) != len(self._columns):
return
self._alignments = alignments
def setHeader(self, header):
if len(header) != len(self._columns):
return
self._header = header
def setColumnSize(self, columns):
self._columns = columns
self._columnColors = [TTkColor.RST]*len(self._columns)
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
def setColumnColors(self, colors):
if len(colors) != len(self._columns):
return
self._columnColors = colors
def appendItem(self, item):
if len(item) != len(self._columns):
return
self._tableData.append(item)
self._tuneTheScroller()
def resizeEvent(self, w, h):
if self._moveTo > len(self._tableData)-h:
self._moveTo = len(self._tableData)-h
if self._moveTo > len(self._tableData)-h-1:
self._moveTo = len(self._tableData)-h-1
if self._moveTo < 0:
self._moveTo = 0
self._tuneTheScroller()
def _tuneTheScroller(self):
@ -68,6 +97,15 @@ class TTkTable(TTkWidget):
self._vscroller.setRange(0, scrollTo)
self._vscroller.pagestep = self.height()
def mousePressEvent(self, evt):
x,y = evt.x, evt.y
if x == self.width() - 1:
return False
if y > 0:
self._selected = self._moveTo + y - 1
self.update()
return True
def wheelEvent(self, evt):
# delta = self.height()
delta = 5
@ -86,7 +124,6 @@ class TTkTable(TTkWidget):
self.update()
def paintEvent(self):
y = 0
w,h = self.size()
total = 0
variableCols = 0
@ -98,34 +135,64 @@ class TTkTable(TTkWidget):
variableCols += 1
if variableCols > 0:
slicesize = int((w-total)/variableCols)
TTkLog.debug(f"ss:{slicesize}, w:{w}")
# TTkLog.debug(f"ss:{slicesize}, w:{w}")
maxItems = len(self._tableData)
itemFrom = self._moveTo
itemFrom = self._moveTo -1
if itemFrom > maxItems-h: itemFrom = maxItems-h
if itemFrom < 0 : itemFrom = 0
itemTo = itemFrom + h
if itemFrom > maxItems: itemFrom = maxItems
if itemTo > maxItems: itemTo = maxItems
for i in range(itemFrom, itemTo):
item= self._tableData[i]
line = ""
for i in range(0,len(item)):
txt = item[i]
width = self._columns[i]
if width < 0:
width = slicesize
if width > 0:
lentxt = len(txt)
if lentxt > width:
line += txt[0:width]
# TTkLog.debug(f"moveto:{self._moveTo}, maxItems:{maxItems}, f:{itemFrom}, t{itemTo}, h:{h}, sel:{self._selected}")
def _lineDraw(_y, _val, _item, _inColor=None):
_x = 0
for i in range(0,len(_item)):
_txt = _item[i]
_width = self._columns[i]
_color = self._columnColors[i]
_align = self._alignments[i]
if _inColor is not None:
_color = _inColor
if _width < 0:
_width = slicesize
if _width > 0:
_line = ""
_lentxt = len(_txt)
if _lentxt > _width:
_line += _txt[0:_width]
else:
line += txt + " "*(width-lentxt)
line += " "
lentxt = len(line)
if lentxt > w-2:
line = line[0:w-2]
_pad = _width-_lentxt
if _align == TTkK.NONE or _align == TTkK.LEFT_ALIGN:
_line += _txt + " "*_pad
elif _align == TTkK.RIGHT_ALIGN:
_line += " "*_pad + _txt
elif _align == TTkK.CENTER_ALIGN:
_p1 = _pad//2
_p2 = _pad-_p1
_line += " "*_p1 + _txt+" "*_p2
elif _align == TTkK.JUSTIFY:
# TODO: Text Justification
_line += _txt + " "*_pad
self._canvas.drawText(pos=(_x,_y), text=_line, color=_color.modParam(val=-_val))
_line += " "
_x += _width + 1
_lineDraw(0,0,self._header,self._headerColor)
y = 1
for it in range(itemFrom, itemTo):
item = self._tableData[it]
if self._selected > 0:
val = self._selected - itemFrom
else:
val = h//2
if val < 0 : val = 0
if val > h : val = h
if it == self._selected:
_lineDraw(y,val,item,self._selectColor)
else:
line = line + " "*(w-2-lentxt)
self._canvas.drawText(pos=(0,y), text=line)
_lineDraw(y,val,item)
y+=1

21
TermTk/TTkWidgets/widget.py

@ -26,7 +26,7 @@ import TermTk.libbpytop as lbt
from TermTk.TTkCore.canvas import *
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.signal import *
from TermTk.TTkWidgets.layout import *
from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem
class TTkWidget:
@ -110,6 +110,11 @@ class TTkWidget:
self._layout.addWidget(widget)
self.update(repaint=True, updateLayout=True)
def removeWidget(self, widget):
if self._layout is not None:
self._layout.removeWidget(widget)
self.update(repaint=True, updateLayout=True)
def paintEvent(self): pass
def paintChildCanvas(self):
@ -190,7 +195,8 @@ class TTkWidget:
# opt of bounds
if x<lx or x>lx+lw or y<ly or y>lh+ly:
return True
for item in layout.zSortedItems:# reversed(layout.zSortedItems):
for item in reversed(layout.zSortedItems):
# for item in layout.zSortedItems:
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
widget = item.widget()
if not widget._visible: continue
@ -229,24 +235,25 @@ class TTkWidget:
# handle own events
if evt.evt == lbt.MouseEvent.Move:
if self.mouseMoveEvent(evt):
return
return True
if evt.evt == lbt.MouseEvent.Drag:
if self.mouseDragEvent(evt):
return
return True
elif evt.evt == lbt.MouseEvent.Release:
#if self.hasFocus():
# self.clearFocus()
if self.mouseReleaseEvent(evt):
return
return True
elif evt.evt == lbt.MouseEvent.Press:
if self.focusPolicy() & TTkWidget.ClickFocus == TTkWidget.ClickFocus:
self.setFocus()
self.raiseWidget()
if self.mousePressEvent(evt):
return
TTkLog.debug(f"Click {self._name}")
return True
elif evt.key == lbt.MouseEvent.Wheel:
if self.wheelEvent(evt):
return
return True
#if self.focusPolicy() & CuT.WheelFocus == CuT.WheelFocus:
# self.setFocus()
#elif evt.type() == CuEvent.KeyPress:

1
TermTk/__init__.py

@ -1,3 +1,4 @@
from .TTkCore import *
from .TTkGui import *
from .TTkLayouts import *
from .TTkWidgets import *

5
docs/BUGS.md

@ -0,0 +1,5 @@
# BUGS 😈
## Events
- [Minor] ~~Overlapping widget click (below window receive the click event)~~
- [Minor] Background color still propagate between widgets

15
docs/TODO.md

@ -1,7 +1,10 @@
# TODO
- [ ] Follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) coding style
- [ ] Use @property/@setter when possible
- [ ] Move the Global Constants outside TTk object
- [ ] Add Typing (good luck) https://docs.python.org/3/library/typing.html
- [ ] Remove Duplicate functionalities (i.e. Widget)
- [ ] Use @property/@setter when possible
- [ ] Uniform the setter/getter/signal/slots
## Terminal Helper
- [ ] Events
@ -21,12 +24,12 @@
## Colors
- [ ] Allow dynamic depth change
- [ ] Define a gradient feature
- [x] Define a gradient feature
## Canvas Class
- [ ] Have a look to the Unicode chartable: https://www.utf8-chartable.de/unicode-utf8-table.pl
## Signal/Slots
- [ ] Implement Signal/Slots
- [x] Implement Signal/Slots
## Logs
- [x] Log Class
@ -39,6 +42,8 @@
## Widgets
- [ ] Add Size Policy (fixed minimum maximum expanding)
- [ ] Add Show/Hide
- [x] Add Show/Hide
### Layout
- [ ] Add Weight in V and H Layout
- [ ] Add Weight in V and H Layout
- [ ] Add addLayout method
- [x] Add Grid Layout

32
tests/test.showcase.001.py

@ -84,26 +84,26 @@ btn3.clicked.connect(win_scroller.show)
btn4.clicked.connect(win_scroller.hide)
win_scroller.setLayout(ttk.TTkVBoxLayout())
top = ttk.TTkFrame(parent=win_scroller, layout=ttk.TTkHBoxLayout())
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTk.HORIZONTAL, value=0, color=ttk.TTkColor.bg('#990044')+ttk.TTkColor.fg('#ffff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTk.HORIZONTAL, value=10, color=ttk.TTkColor.bg('#770044')+ttk.TTkColor.fg('#ccff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTk.HORIZONTAL, value=50, color=ttk.TTkColor.bg('#660044')+ttk.TTkColor.fg('#88ff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTk.HORIZONTAL, value=80, color=ttk.TTkColor.bg('#550044')+ttk.TTkColor.fg('#55ff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTk.HORIZONTAL, value=99, color=ttk.TTkColor.bg('#330044')+ttk.TTkColor.fg('#33ff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTkK.HORIZONTAL, value=0, color=ttk.TTkColor.bg('#990044')+ttk.TTkColor.fg('#ffff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTkK.HORIZONTAL, value=10, color=ttk.TTkColor.bg('#770044')+ttk.TTkColor.fg('#ccff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTkK.HORIZONTAL, value=50, color=ttk.TTkColor.bg('#660044')+ttk.TTkColor.fg('#88ff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTkK.HORIZONTAL, value=80, color=ttk.TTkColor.bg('#550044')+ttk.TTkColor.fg('#55ff00'))
ttk.TTkScrollBar(parent=win_scroller, orientation=ttk.TTkK.HORIZONTAL, value=99, color=ttk.TTkColor.bg('#330044')+ttk.TTkColor.fg('#33ff00'))
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=0)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=10)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=40)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=0)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=10)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=40)
ttk.TTkSpacer(parent=top)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=40, pagestep=3)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=50, pagestep=5)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=60, pagestep=20)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=70, pagestep=30)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=80, pagestep=60)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=40, pagestep=3)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=50, pagestep=5)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=60, pagestep=20)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=70, pagestep=30)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=80, pagestep=60)
ttk.TTkSpacer(parent=top)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=80)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=90)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=99)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=80)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=90)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=99)
# Table window from test.ui.008.table.py

19
tests/test.ui.003.layout.py

@ -32,11 +32,26 @@ ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
root.setLayout(ttk.TTkHBoxLayout())
ttk.TTkTestWidget(parent=root,border=True)
ttk.TTkTestWidget(parent=root,border=True, maxWidth=52)
rightframe = ttk.TTkFrame(parent=root)
rightframe.setLayout(ttk.TTkVBoxLayout())
ttk.TTkFrame(parent=rightframe, border=True)
gridFrame = ttk.TTkFrame(parent=rightframe, border=False)
gridFrame.setLayout(ttk.TTkGridLayout())
ttk.TTkButton(parent=gridFrame, text="Button1")
ttk.TTkButton(parent=gridFrame, text="Button2")
gridFrame.layout().addWidget(ttk.TTkButton(text="Button (1,0)"),1,0)
ttk.TTkButton(parent=gridFrame, text="Button4")
gridFrame.layout().addWidget(ttk.TTkButton(text="Button (1,2)"),1,2)
# Test (add a widget to the same parent with a different layout params than the default)
gridFrame.layout().addWidget(ttk.TTkButton(parent=gridFrame, text="Button (2,1)"),2,1)
gridFrame.layout().addWidget(ttk.TTkButton(text="Button (5,5)"),5,5)
gridFrame.layout().addWidget(ttk.TTkFrame(border=True),0,5)
gridFrame.layout().addWidget(ttk.TTkFrame(border=True),2,3)
gridFrame.layout().addWidget(ttk.TTkFrame(border=True),5,3)
gridFrame.layout().addWidget(ttk.TTkFrame(border=True),5,1)
centerrightframe=ttk.TTkFrame(parent=rightframe, border=True)
centerrightframe.setLayout(ttk.TTkHBoxLayout())
ttk.TTkTestWidget(parent=rightframe, border=True)

15
tests/test.ui.005.labels.py

@ -35,17 +35,18 @@ win1 = ttk.TTkWindow(parent=root,pos = (1,1), size=(100,50), title="Test Window
win1.setLayout(ttk.TTkVBoxLayout())
ttk.TTkButton(parent=win1, text="BUTTON")
ttk.TTkLabel(parent=win1, text="Test Label 1")
ttk.TTkLabel(parent=win1, text="Test Label 2")
ttk.TTkLabel(parent=win1, text="Test Label 3")
ttk.TTkLabel(parent=win1, text="Test Label 4")
ttk.TTkLabel(parent=win1, text="Test Label 5")
ttk.TTkLabel(parent=win1, text="Test Label 6")
ttk.TTkLabel(parent=win1, text="Test Very Long Label 7 - abcdefghihjlmno")
ttk.TTkLabel(parent=win1, text="Test Label 8")
ttk.TTkLabel(parent=win1, text="Test Label 2 Bold", color=ttk.TTkColor.BOLD)
ttk.TTkLabel(parent=win1, text="Test Label 3 Italic", color=ttk.TTkColor.ITALIC)
ttk.TTkLabel(parent=win1, text="Test Label 4 Underline", color=ttk.TTkColor.UNDERLINE)
ttk.TTkLabel(parent=win1, text="Test Label 5 StrikeTrough", color=ttk.TTkColor.STRIKETROUGH)
ttk.TTkLabel(parent=win1, text="Test Label 6 Mix", color=ttk.TTkColor.BOLD+ttk.TTkColor.ITALIC+ttk.TTkColor.UNDERLINE)
ttk.TTkLabel(parent=win1, text="Test Label 7")
ttk.TTkLabel(parent=win1, text="Test Very Long Label 8 - abcdefghihjlmno")
ttk.TTkLabel(parent=win1, text="Test Label 9")
ttk.TTkLabel(parent=win1, text="Test Label 10")
ttk.TTkLabel(parent=win1, text="Test Label 11")
ttk.TTkLabel(parent=win1, text="Test Label 12")
ttk.TTkLabel(parent=win1, text="Test Label 13")
root.mainloop()

32
tests/test.ui.006.scroll.py

@ -34,26 +34,26 @@ root = ttk.TTk()
win1 = ttk.TTkWindow(parent=root,pos = (1,1), size=(30,40), title="Test Window 1", border=True)
win1.setLayout(ttk.TTkVBoxLayout())
top = ttk.TTkFrame(parent=win1, layout=ttk.TTkHBoxLayout())
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTk.HORIZONTAL, value=0, color=ttk.TTkColor.bg('#990044')+ttk.TTkColor.fg('#ffff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTk.HORIZONTAL, value=10, color=ttk.TTkColor.bg('#770044')+ttk.TTkColor.fg('#ccff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTk.HORIZONTAL, value=50, color=ttk.TTkColor.bg('#660044')+ttk.TTkColor.fg('#88ff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTk.HORIZONTAL, value=80, color=ttk.TTkColor.bg('#550044')+ttk.TTkColor.fg('#55ff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTk.HORIZONTAL, value=99, color=ttk.TTkColor.bg('#330044')+ttk.TTkColor.fg('#33ff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTkK.HORIZONTAL, value=0, color=ttk.TTkColor.bg('#990044')+ttk.TTkColor.fg('#ffff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTkK.HORIZONTAL, value=10, color=ttk.TTkColor.bg('#770044')+ttk.TTkColor.fg('#ccff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTkK.HORIZONTAL, value=50, color=ttk.TTkColor.bg('#660044')+ttk.TTkColor.fg('#88ff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTkK.HORIZONTAL, value=80, color=ttk.TTkColor.bg('#550044')+ttk.TTkColor.fg('#55ff00'))
ttk.TTkScrollBar(parent=win1, orientation=ttk.TTkK.HORIZONTAL, value=99, color=ttk.TTkColor.bg('#330044')+ttk.TTkColor.fg('#33ff00'))
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=0)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=10)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=40)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=0)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=10)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=40)
ttk.TTkSpacer(parent=top)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=40, pagestep=3)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=50, pagestep=5)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=60, pagestep=20)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=70, pagestep=30)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=80, pagestep=60)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=40, pagestep=3)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=50, pagestep=5)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=60, pagestep=20)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=70, pagestep=30)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=80, pagestep=60)
ttk.TTkSpacer(parent=top)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=80)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=90)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTk.VERTICAL, value=99)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=80)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=90)
ttk.TTkScrollBar(parent=top, orientation=ttk.TTkK.VERTICAL, value=99)
root.mainloop()

81
tests/test.ui.008.table.py

@ -38,16 +38,83 @@ def getSentence():
ttk.TTkLog.use_default_file_logging()
root = ttk.TTk()
win1 = ttk.TTkWindow(parent=root,pos = (3,3), size=(40,20), title="Test Table 1", layout=ttk.TTkHBoxLayout(), border=True)
table = ttk.TTkTable(parent=win1)
btn1 = ttk.TTkButton(parent=root, pos=(0,0), size=(5,3), text='Add')
btn2 = ttk.TTkButton(parent=root, pos=(5,0), size=(10,3), text='Add Many')
table.setColumnSize((20,-1,10,15))
table.appendItem(("","You see it's all clear, You were meant to be here, From the beginning","",""))
for i in range(0, 100):
table.appendItem((str(i)+" - "+getWord(), getSentence(), getWord(), getWord()))
table.appendItem(("This is the end", "Beautiful friend, This is the end My only friend", "the end", "..."))
win_table1 = ttk.TTkWindow(parent=root,pos = (3,3), size=(150,40), title="Test Table 1", layout=ttk.TTkHBoxLayout(), border=True)
table1 = ttk.TTkTable(parent=win_table1, selectColor=ttk.TTkColor.bg('#882200'))
win_table2 = ttk.TTkWindow(parent=root,pos = (15,5), size=(100,30), title="Test Table 2 Default", layout=ttk.TTkHBoxLayout(), border=True)
table2 = ttk.TTkTable(parent=win_table2)
win_table3 = ttk.TTkWindow(parent=root,pos = (15,5), size=(130,40), title="Test Table 2 Default", layout=ttk.TTkHBoxLayout(), border=True)
table3 = ttk.TTkTable(parent=win_table3)
table1.setColumnSize((5,10,-1,10,20))
table1.setAlignment((
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.RIGHT_ALIGN,
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.CENTER_ALIGN
))
table1.setHeader(("id","Name","Sentence","Word","center"))
table1.setColumnColors((
ttk.TTkColor.fg('#888800', modifier=ttk.TTkColorGradient(increment=6)),
ttk.TTkColor.RST,
ttk.TTkColor.fg('#00dddd', modifier=ttk.TTkColorGradient(increment=-4)),
ttk.TTkColor.RST,
ttk.TTkColor.fg('#cccccc', modifier=ttk.TTkColorGradient(increment=-2))
))
table2.setColumnSize((5,10,-1,10,20))
table2.setHeader(("id","Name","Sentence","Word",""))
table3.setColumnSize((5,10,-1,10,20))
table3.setAlignment((
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.RIGHT_ALIGN,
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.LEFT_ALIGN,
ttk.TTkK.CENTER_ALIGN
))
table3.setHeader(("id","Name","Sentence","Word","center"))
table3.setColumnColors((
ttk.TTkColor.fg('#ffff00', modifier=ttk.TTkColorGradient(increment=6)),
ttk.TTkColor.fg('#ff0000', modifier=ttk.TTkColorGradient(increment=6)),
ttk.TTkColor.fg('#00ffff', modifier=ttk.TTkColorGradient(increment=-8)),
ttk.TTkColor.fg('#00ff00', modifier=ttk.TTkColorGradient(increment=-4)),
ttk.TTkColor.fg('#cccccc', modifier=ttk.TTkColorGradient(increment=-2))
))
table3.appendItem((" - ","","You see it's all clear, You were meant to be here, From the beginning","",""))
for i in range(0, 5):
table1.appendItem((str(i), getWord(), getSentence(), getWord(), getWord()))
for i in range(0, 5):
table2.appendItem((str(i), getWord(), getSentence(), getWord(), getWord()))
for i in range(0, 35):
table3.appendItem((str(i), getWord(), getSentence(), getWord(), getWord()))
table3.appendItem((" - ","This is the end", "Beautiful friend, This is the end My only friend", "the end", "..."))
# Attach the add Event
ii = 1000
def add():
global ii
ii+=1
table1.appendItem((str(ii), getWord(), getSentence(), getWord(), getWord()))
table2.appendItem((str(ii), getWord(), getSentence(), getWord(), getWord()))
btn1.clicked.connect(add)
def addMany():
global ii
for i in range(0, 500):
ii+=1
table1.appendItem((str(ii), getWord(), getSentence(), getWord(), getWord()))
btn2.clicked.connect(addMany)
root.mainloop()
Loading…
Cancel
Save