Browse Source

Improving the menubar in the apptemplate

pull/243/head
Eugenio Parodi 2 years ago
parent
commit
9275c60a20
  1. 164
      TermTk/TTkWidgets/apptemplate.py
  2. 19
      demo/showcase/apptemplate.py

164
TermTk/TTkWidgets/apptemplate.py

@ -27,8 +27,10 @@ from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.string import TTkString
from TermTk.TTkLayouts import TTkLayout, TTkGridLayout
from TermTk.TTkWidgets.container import TTkWidget, TTkContainer
from TermTk.TTkWidgets.menubar import TTkMenuBarLayout
class TTkAppTemplate(TTkContainer):
''' TTkAppTemplate Layout:
@ -65,11 +67,13 @@ class TTkAppTemplate(TTkContainer):
@dataclass(frozen=False)
class _Panel:
# It's either item or widget
item: TTkLayout = None
widget: TTkWidget = None
size = 0
border = True
fixed = False
item: TTkLayout = None
widget: TTkWidget = None
title: TTkString = None
menubar: TTkMenuBarLayout = None
size: int = 0
border: bool = True
fixed: bool = False
def setGeometry(self,x,y,w,h):
if it := self.item:
@ -127,9 +131,9 @@ class TTkAppTemplate(TTkContainer):
__slots__ = ('_panels', '_splitters', '_selected'
#Signals
)
def __init__(self, **kwargs):
def __init__(self, border=False, **kwargs):
self._panels = {
TTkAppTemplate.MAIN : TTkAppTemplate._Panel(item=TTkLayout()) ,
TTkAppTemplate.MAIN : TTkAppTemplate._Panel(item=TTkLayout(), border=border) ,
TTkAppTemplate.TOP : None ,
TTkAppTemplate.BOTTOM : None ,
TTkAppTemplate.LEFT : None ,
@ -150,39 +154,67 @@ class TTkAppTemplate(TTkContainer):
self._updateGeometries()
self.setFocusPolicy(TTkK.ClickFocus)
def setWidget(self, widget, location):
if not self._panels[location]:
self._panels[location] = TTkAppTemplate._Panel()
self._panels[location].widget = widget
if it:=self._panels[location].item:
def setWidget(self, widget, poosition=MAIN, size=None, title=""):
if not self._panels[poosition]:
self._panels[poosition] = TTkAppTemplate._Panel()
if wid:=self._panels[poosition].widget:
self.layout().removeWidget(wid)
self._panels[poosition].widget = None
if it:=self._panels[poosition].item:
self.layout().removeItem(it)
self._panels[location].item = None
self._panels[poosition].item = None
if widget:
self._panels[poosition].widget = widget
self.layout().addWidget(widget)
self._panels[location].size = widget.minimumWidth() if location in (TTkAppTemplate.LEFT,TTkAppTemplate.RIGHT) else widget.maximumWidth()
self._panels[poosition].title = TTkString(title)
self._panels[poosition].size = ( size if size is not None else
widget.minimumWidth() if poosition in (TTkAppTemplate.LEFT,TTkAppTemplate.RIGHT) else
widget.minimumHeight() )
self._updateGeometries()
def setItem(self, item, location):
if not self._panels[location]:
self._panels[location] = TTkAppTemplate._Panel()
self._panels[location].item = item
if wid:=self._panels[location].widget:
self.layout().removeWdget(wid)
self._panels[location].widget = None
def setItem(self, item, poosition=MAIN, size=None, title=""):
if not self._panels[poosition]:
self._panels[poosition] = TTkAppTemplate._Panel()
if wid:=self._panels[poosition].widget:
self.layout().removeWidget(wid)
self._panels[poosition].widget = None
if it:=self._panels[poosition].item:
self.layout().removeItem(it)
self._panels[poosition].item = None
if item:
self._panels[poosition].item = item
self.layout().addItem(item)
self._panels[poosition].title = TTkString(title)
self._panels[poosition].size = ( size if size is not None else
item.minimumWidth() if poosition in (TTkAppTemplate.LEFT,TTkAppTemplate.RIGHT) else
item.minimumHeight() )
self._updateGeometries()
def menuBar(self, position=MAIN):
return None if not self._panels[position] else self._panels[position].menubar
def setMenuBar(self, menuBar, position=MAIN):
if not self._panels[position]:
self._panels[position] = TTkAppTemplate._Panel()
p = self._panels[position]
if p.menubar:
self.rootLayout().removeItem(p.menubar)
# TODO: Dispose the menubar
p.menubar = menuBar
if menuBar:
self.rootLayout().addItem(p.menubar)
self._updateGeometries()
def setBorder(self, border=True, location=MAIN):
if not self._panels[location]:
self._panels[location] = TTkAppTemplate._Panel()
self._panels[location].border = border
def setBorder(self, border=True, poosition=MAIN):
if not self._panels[poosition]:
self._panels[poosition] = TTkAppTemplate._Panel()
self._panels[poosition].border = border
self._updateGeometries()
def setFixed(self, fixed=False, location=MAIN):
if not self._panels[location]:
self._panels[location] = TTkAppTemplate._Panel()
self._panels[location].fixed = fixed
def setFixed(self, fixed=False, poosition=MAIN):
if not self._panels[poosition]:
self._panels[poosition] = TTkAppTemplate._Panel()
self._panels[poosition].fixed = fixed
self._updateGeometries()
def resizeEvent(self, w, h):
@ -318,21 +350,30 @@ class TTkAppTemplate(TTkContainer):
def _updateGeometries(self):
w,h = self.size()
if w<=0 or h<=0 or not self.isVisibleAndParent(): return
pns = self._panels
spl = self._splitters
sl=sr=st=sb=sh=sf=0
bm=bl=br=bt=bb=bh=bf=0
# A,B,C,D HSplitters
pt=pb=ph=pf=None
if ( (p:=pns[TTkAppTemplate.TOP ]) and p.isVisible() ): pt=p ; ptmin=p.minimumHeight() ; ptmax=p.maximumHeight() ; st=min(max(p.size,ptmin),ptmax) ; ft=p.fixed ; bt=1 if p.border else 0
if ( (p:=pns[TTkAppTemplate.BOTTOM]) and p.isVisible() ): pb=p ; pbmin=p.minimumHeight() ; pbmax=p.maximumHeight() ; sb=min(max(p.size,pbmin),pbmax) ; fb=p.fixed ; bb=1 if p.border else 0
if ( (p:=pns[TTkAppTemplate.HEADER]) and p.isVisible() ): ph=p ; phmin=p.minimumHeight() ; phmax=p.maximumHeight() ; sh=min(max(p.size,phmin),phmax) ; fh=p.fixed ; bh=1 if p.border else 0
if ( (p:=pns[TTkAppTemplate.FOOTER]) and p.isVisible() ): pf=p ; pfmin=p.minimumHeight() ; pfmax=p.maximumHeight() ; sf=min(max(p.size,pfmin),pfmax) ; ff=p.fixed ; bf=1 if p.border else 0
# E,F VSplitters
pl=pr=None
if ( (p:=pns[TTkAppTemplate.LEFT ]) and p.isVisible() ): pl=p ; plmin=p.minimumWidth() ; plmax=p.maximumWidth() ; sl=min(max(p.size,plmin),plmax) ; fl=p.fixed ; bl=1 if p.border else 0
if ( (p:=pns[TTkAppTemplate.RIGHT ]) and p.isVisible() ): pr=p ; prmin=p.minimumWidth() ; prmax=p.maximumWidth() ; sr=min(max(p.size,prmin),prmax) ; fr=p.fixed ; br=1 if p.border else 0
# Retrieve all the panels parameters and hide the menubar if required
def _processPanel(_loc):
_p = pns[_loc]
_menu = _p.menubar
if not (_p and _p.isVisible()):
if _menu: _menu.setGeometry(-1,-1,0,0)
return None, 0, 0x1000, 0, True, 0, None
_min = _p.minimumHeight()
_max = _p.maximumHeight()
_size = min(max(_p.size,_min),_max)
_fixed = _p.fixed
_border = 1 if _p.border else 0
return _p, _min, _max, _size, _fixed, _border, _menu
pt,ptmin,ptmax,st,ft,bt,mt = _processPanel(TTkAppTemplate.TOP)
pb,pbmin,pbmax,sb,fb,bb,mb = _processPanel(TTkAppTemplate.BOTTOM)
ph,phmin,phmax,sh,fh,bh,mh = _processPanel(TTkAppTemplate.HEADER)
pf,pfmin,pfmax,sf,ff,bf,mf = _processPanel(TTkAppTemplate.FOOTER)
pl,plmin,plmax,sl,fl,bl,ml = _processPanel(TTkAppTemplate.LEFT)
pr,prmin,prmax,sr,fr,br,mr = _processPanel(TTkAppTemplate.RIGHT)
# Main Boundaries
pm=pns[TTkAppTemplate.MAIN]
@ -347,7 +388,7 @@ class TTkAppTemplate(TTkContainer):
# check horizontal sizes
if not (mminw <= (newszw:=(w-sl-sr)) <= mmaxw):
# the main width does not fit
# we need to move the (E,F) splitters
# we need to move the (R,L) splitters
# * to avoid extra complexity,
# Let's resize the right panel first
# and adjust the left one to allows the
@ -376,30 +417,37 @@ class TTkAppTemplate(TTkContainer):
# Resize any panel to the proper dimension
w+=bl+br
h+=bt+bb+bh+bf
pm.setGeometry( bm+sl+bl , bm+sh+bh+st+bt , newszw , newszh )
def _setGeometries(_p, _x,_y,_w,_h,_bbar):
off = 0
if _mb:=_p.menubar:
off = 0 if _bbar else 1
_mb.setGeometry(_x,_y-1+off,_w,1)
_p.setGeometry(_x,_y+off,_w,_h-off)
_setGeometries( pm, bm+sl+bl , bm+sh+bh+st+bt , newszw , newszh , bt | ( bh and pt==None ) | ( bm and ph==pt==None))
if pl: pl.setGeometry( bm , bm+sh+bh , sl , h-sh-bh-sf-bf )
if pr: pr.setGeometry( bm+sl+bl+newszw+br , bm+sh+bh , sr , h-sh-bh-sf-bf )
if pl: _setGeometries(pl, bm , bm+sh+bh , sl , h-sh-bh-sf-bf , bh | ( bm and ph==None))
if pr: _setGeometries(pr, bm+sl+bl+newszw+br , bm+sh+bh , sr , h-sh-bh-sf-bf , bh | ( bm and ph==None))
if ph: ph.setGeometry( bm , bm , w , sh )
if pt: pt.setGeometry( bm+sl+bl , bm+sh+bh , newszw , st )
if pb: pb.setGeometry( bm+sl+bl , bm+sh+bh+st+bt+newszh+bb , newszw , sb )
if pf: pf.setGeometry( bm , bm+sh+bh+st+bt+newszh+bb+sb+bf , w , sf )
if ph: _setGeometries(ph, bm , bm , w , sh , bm)
if pt: _setGeometries(pt, bm+sl+bl , bm+sh+bh , newszw , st , bh | ( bm and ph==None))
if pb: _setGeometries(pb, bm+sl+bl , bm+sh+bh+st+bt+newszh+bb , newszw , sb , bb)
if pf: _setGeometries(pf, bm , bm+sh+bh+st+bt+newszh+bb+sb+bf , w , sf , bf)
# Define Splitter geometries
w,h = self.size()
spl[TTkAppTemplate.HEADER] = None if not bh else {'pos':(0 , bm+sh ) ,'size':w , 'fixed':fh }
spl[TTkAppTemplate.FOOTER] = None if not bf else {'pos':(0 , bm+sh+bh+st+bt+newszh+bb+sb) ,'size':w , 'fixed':ff }
spl[TTkAppTemplate.HEADER] = None if not bh else {'pos':(0 , bm+sh ) ,'size':w , 'fixed':fh , 'panel': ph }
spl[TTkAppTemplate.FOOTER] = None if not bf else {'pos':(0 , bm+sh+bh+st+bt+newszh+bb+sb) ,'size':w , 'fixed':ff , 'panel': pf }
ca = sh + (bm if ph else 0 )
cb = bm+sh+bh+st+bt+newszh+bb+sb + (bf if pf else bm)
spl[TTkAppTemplate.LEFT] = None if not bl else {'pos':(bm+sl , ca ) ,'size':cb-ca , 'fixed':fl }
spl[TTkAppTemplate.RIGHT] = None if not br else {'pos':(bm+sl+bl+newszw , ca ) ,'size':cb-ca , 'fixed':fr }
spl[TTkAppTemplate.LEFT] = None if not bl else {'pos':(bm+sl , ca ) ,'size':cb-ca , 'fixed':fl , 'panel': pl }
spl[TTkAppTemplate.RIGHT] = None if not br else {'pos':(bm+sl+bl+newszw , ca ) ,'size':cb-ca , 'fixed':fr , 'panel': pr }
ca = sl + (bm if pl else 0 )
cb = bm+sl+bl+newszw + (br if pr else bm)
spl[TTkAppTemplate.TOP] = None if not bt else {'pos':(ca , bm+sh+bh+st ) ,'size':cb-ca , 'fixed':ft }
spl[TTkAppTemplate.BOTTOM] = None if not bb else {'pos':(ca , bm+sh+bh+st+bt+newszh) ,'size':cb-ca , 'fixed':fb }
spl[TTkAppTemplate.TOP] = None if not bt else {'pos':(ca , bm+sh+bh+st ) ,'size':cb-ca , 'fixed':ft , 'panel': pt }
spl[TTkAppTemplate.BOTTOM] = None if not bb else {'pos':(ca , bm+sh+bh+st+bt+newszh) ,'size':cb-ca , 'fixed':fb , 'panel': pb }
self.update()
@ -441,6 +489,12 @@ class TTkAppTemplate(TTkContainer):
canvas.fill(pos=(_x,_y), size=(_w,_h), color=color, char=chs[0] )
canvas.drawChar(pos=(_x,_y), color=color, char=chs[1]if b and _x==0 else chs[3])
canvas.drawChar(pos=(_x+_w-1,_y), color=color, char=chs[2]if b and _x+_w==w else chs[4])
if _title:=sp['panel'].title:
_l = min(w-2,_title.termWidth())
_tx = (_w-_l)//2
canvas.drawChar(pos=(_x+_tx,_y), color=color, char=chs[2])
canvas.drawChar(pos=(_x+_tx+_l+1,_y),color=color, char=chs[1])
canvas.drawTTkString(pos=(_x+_tx+1,_y),text=_title,width=_l)
# Draw the 4 splittters
if (sp:=spl[TTkAppTemplate.HEADER]) : drawHLine(sp, color=selectColor if self._selected and TTkAppTemplate.HEADER in self._selected else TTkColor.RST)

19
demo/showcase/apptemplate.py

@ -57,7 +57,7 @@ class AppTestWidget(ttk.TTkContainer):
cbf.clicked.connect(lambda b,loc=wids[wn]['loc']: at.setFixed(b,loc))
def demoAppTemplate(root=None):
at = ttk.TTkAppTemplate(parent=root)
at = ttk.TTkAppTemplate(parent=root, border=True)
twl = ttk.TTkTestWidgetSizes(border=False, name="Left", minSize=( 15, 5), maxSize=( 50, 0x1000))
twr = ttk.TTkTestWidgetSizes(border=False, name="Right", minSize=( 15, 5), maxSize=( 50, 0x1000))
@ -85,6 +85,23 @@ def demoAppTemplate(root=None):
at.setWidget(twb, at.BOTTOM)
at.setWidget(twf, at.FOOTER)
def _createMenuBar(position, text):
_mb = ttk.TTkMenuBarLayout()
at.setMenuBar(_mb, position)
_fileMenu = _mb.addMenu(text)
_fileMenu.addMenu("Open")
_fileMenu.addMenu("Close")
_fileMenu.addMenu("Exit")
_helpMenu = _mb.addMenu("&Help", alignment=ttk.TTkK.RIGHT_ALIGN)
_helpMenu.addMenu("About...")
_createMenuBar(at.MAIN, "&File")
_createMenuBar(at.TOP , "F&ile")
_createMenuBar(at.BOTTOM, "Fi&le")
_createMenuBar(at.LEFT, "Fil&e")
return at

Loading…
Cancel
Save