diff --git a/TermTk/TTkCore/canvas.py b/TermTk/TTkCore/canvas.py index 46af4c99..1be980a8 100644 --- a/TermTk/TTkCore/canvas.py +++ b/TermTk/TTkCore/canvas.py @@ -186,7 +186,7 @@ class TTkCanvas: for i in range(0, len(arr)): self._set(y, x+i, arr[i], color) - def drawBoxTitle(self, pos, size, text, color=TTkColor.RST, colorText=TTkColor.RST, grid=0): + def drawBoxTitle(self, pos, size, text, align=TTkK.CENTER_ALIGN, color=TTkColor.RST, colorText=TTkColor.RST, grid=0): if not self._visible: return x,y = pos w,h = size @@ -195,7 +195,12 @@ class TTkCanvas: if len(text) > w-4: text = text[:w-4] - l = (w-2-len(text))//2 + if align == TTkK.CENTER_ALIGN: + l = (w-2-len(text))//2 + elif align == TTkK.LEFT_ALIGN: + l=1 + else: + l = w-2-len(text) r = l+len(text)+1 self._set(y,l, gg[7], color) @@ -415,6 +420,25 @@ class TTkCanvas: # TTkLog.debug(f"z:{zl1,zl2},t:{t1,t2},i:{i} {t1-i*4} {t2-i*4} o:{o1,o2}, {hex(braille)}") self._set(y-i-1,x, gb[braille], color) + def drawMenuBarBg(self, pos, size, color=TTkColor.RST ): + mb = TTkCfg.theme.menuBar + self.drawText(pos, text=f"{mb[3]}{mb[1]*(size-2)}{mb[4]}", color=color) + + def drawMenuBarButton(self, pos, width, text, border=True, submenu=False, shortcuts=[], color=TTkColor.RST, borderColor=TTkColor.RST, shortcutColor=TTkColor.UNDERLINE ): + mb = TTkCfg.theme.menuBar + x,y = pos + if border: + self.drawText(pos=(x,y), color=borderColor ,text=mb[2]) + self.drawText(pos=(x+1+len(text),y), color=borderColor ,text=mb[0]) + self.drawText(pos=(x+1,y), color=color ,text=text) + off = 1 + else: + self.drawText(pos=(x,y), color=color ,text=text) + if submenu: + self._set(y,x+width-1, mb[5], color) + off = 0 + for i in shortcuts: + self._set(y,x+i+off, text[i], shortcutColor) def execPaint(self, winw, winh): pass @@ -438,22 +462,34 @@ class TTkCanvas: # out of bound if not self._visible: return if not canvas._visible: return + if canvas._width==0 or canvas._height==0: return if x+w < bx or y+h=self._width: x=self._width-1 - if y>=self._height: y=self._height-1 - if w>=self._width-x: w=self._width-x - if h>=self._height-y: h=self._height-y + + x = min(x,self._width-1) + y = min(y,self._height-1) + w = min(w,self._width-x) + h = min(h,self._height-y) + + # if x>=self._width: x=self._width-1 + # if y>=self._height: y=self._height-1 + # if w>=self._width-x: w=self._width-x + # if h>=self._height-y: h=self._height-y xoffset = 0 if x>=bx else bx-x yoffset = 0 if y>=by else by-y wslice = w if x+w < bx+bw else bx+bw-x hslice = h if y+h < by+bh else by+bh-y + for iy in range(yoffset,hslice): for ix in range(xoffset,wslice): #TTkLog.debug(f"PaintCanvas:{(ix,iy)}") - self._data[y+iy][x+ix] = canvas._data[iy][ix] + if iy > len(canvas._data)-1: + TTkLog.debug(f"{canvas._width, canvas._height} - {(yoffset,hslice)}, {(xoffset,wslice)}, {slice}") + b = canvas._data[iy] + a = b[ix] + self._data[y+iy][x+ix] = a # canvas._data[iy][ix] self._colors[y+iy][x+ix] = canvas._colors[iy][ix] def pushToTerminal(self, x, y, w, h): diff --git a/TermTk/TTkCore/helper.py b/TermTk/TTkCore/helper.py index b8a3cacd..6dee0ce1 100644 --- a/TermTk/TTkCore/helper.py +++ b/TermTk/TTkCore/helper.py @@ -42,7 +42,33 @@ class TTkHelper: self._widget = widget widget.move(x,y) - _overlay = None + _overlay = [] + + class _Shortcut(): + __slots__ = ('_letter','_widget') + def __init__(self, letter, widget): + self._letter = letter.lower() + self._widget = widget + _shortcut = [] + + @staticmethod + def addShortcut(widget, letter): + TTkHelper._shortcut.append(TTkHelper._Shortcut(letter, widget)) + + @staticmethod + def isParent(parent, widget): + if parent==widget: return True + if widget.parentWidget() is None: return False + return TTkHelper.isParent(parent,widget.parentWidget()) + + @staticmethod + def execShortcut(letter, widget=None): + if not isinstance(letter, str): return + for sc in TTkHelper._shortcut: + if sc._letter == letter.lower() and sc._widget.isVisible(): + if not widget or TTkHelper.isParent(widget, sc._widget): + sc._widget.shortcutEvent() + return @staticmethod def addUpdateWidget(widget): @@ -66,10 +92,11 @@ class TTkHelper: def isOverlay(widget): if widget is None: return False - if TTkHelper._overlay is None: + if not TTkHelper._overlay: return False + overlayWidgets = [o._widget for o in TTkHelper._overlay] while widget is not None: - if widget == TTkHelper._overlay._widget: + if widget in overlayWidgets: return True widget = widget.parentWidget() return False @@ -77,19 +104,17 @@ class TTkHelper: @staticmethod def overlay(caller, widget, x, y): wx, wy = TTkHelper.absPos(caller) - TTkHelper._overlay = TTkHelper._Overlay(wx+x,wy+y,widget) - # widget.setFocus() + TTkHelper._overlay.append(TTkHelper._Overlay(wx+x,wy+y,widget)) @staticmethod def getOverlay(): - if TTkHelper._overlay is not None: - return TTkHelper._overlay._widget + if TTkHelper._overlay: + return TTkHelper._overlay[-1]._widget return None @staticmethod def removeOverlay(): - if TTkHelper._overlay is not None: - TTkHelper._overlay = None + TTkHelper._overlay = [] @staticmethod def paintAll(): @@ -137,17 +162,18 @@ class TTkHelper: pushToTerminal = True widget.paintChildCanvas() - if TTkHelper._overlay is not None: + if TTkHelper._overlay: TTkHelper._rootCanvas.clean() TTkHelper._rootCanvas.getWidget().paintChildCanvas() lx,ly,lw,lh = (0, 0, TTkGlbl.term_w, TTkGlbl.term_h) - child =TTkHelper._overlay._widget - cx,cy,cw,ch = child.geometry() - TTkHelper._rootCanvas.paintCanvas( - child.getCanvas(), - (cx, cy, cw, ch), - (0,0,cw,ch), - (lx, ly, lw, lh)) + for o in TTkHelper._overlay: + child =o._widget + cx,cy,cw,ch = child.geometry() + TTkHelper._rootCanvas.paintCanvas( + child.getCanvas(), + (cx, cy, cw, ch), + (0,0,cw,ch), + (lx, ly, lw, lh)) if pushToTerminal: if TTkHelper._cursor: diff --git a/TermTk/TTkCore/signal.py b/TermTk/TTkCore/signal.py index e666aeaa..d2c2a0c7 100644 --- a/TermTk/TTkCore/signal.py +++ b/TermTk/TTkCore/signal.py @@ -78,7 +78,8 @@ class pyTTkSignal_obj(): if hasattr(slot, '_TTkslot_attr') and slot._TTkslot_attr != self._types: error = "Decorated slot has no signature compatible: "+slot.__name__+str(slot._TTkslot_attr)+" != signal"+str(self._types) raise TypeError(error) - self._connected_slots.append(slot) + if slot not in self._connected_slots: + self._connected_slots.append(slot) def disconnect(self, *args, **kwargs): for slot in args: diff --git a/TermTk/TTkCore/ttk.py b/TermTk/TTkCore/ttk.py index f24f78f5..f116651c 100644 --- a/TermTk/TTkCore/ttk.py +++ b/TermTk/TTkCore/ttk.py @@ -115,10 +115,15 @@ class TTk(TTkWidget): kevt = self.key_events.get() focusWidget = TTkHelper.getFocus() overlayWidget = TTkHelper.getOverlay() + TTkLog.debug(f"{focusWidget}") if focusWidget is not None: + TTkHelper.execShortcut(kevt.key,focusWidget) focusWidget.keyEvent(kevt) elif overlayWidget is not None: + TTkHelper.execShortcut(kevt.key,overlayWidget) overlayWidget.keyEvent(kevt) + else: + TTkHelper.execShortcut(kevt.key) pass elif evt is TTkK.TIME_EVENT: TTkHelper.paintAll() diff --git a/TermTk/TTkGui/theme.py b/TermTk/TTkGui/theme.py index ccf083db..48dd3766 100644 --- a/TermTk/TTkGui/theme.py +++ b/TermTk/TTkGui/theme.py @@ -120,6 +120,9 @@ class TTkTheme(): hscroll = ('◀','┄','▓','▶') vscroll = ('▲','┊','▓','▼') + # 0 1 2 3 4 5 + menuBar = ('├','─','┤','┄','┄','▶') + ''' ┌──────╔══════╗──────┬──────┐ ┌─┌──────╔══════╗──────┬──────┐─┐ │Label1║Label2║Label3│Label4│ │◀│Label1║Label2║Label3│Label4│▶│ @@ -197,6 +200,12 @@ class TTkTheme(): buttonTextColorFocus = buttonTextColor + TTkColor.BOLD buttonBorderColorFocus = buttonBorderColor + TTkColor.BOLD + menuButtonShortcutColor = TTkColor.fg("#dddddd") + TTkColor.UNDERLINE + menuButtonColor = TTkColor.BOLD + menuButtonBorderColor = frameBorderColor + menuButtonColorClicked = TTkColor.fg("#ffff88") + menuButtonBorderColorClicked = frameBorderColor + listColor = TTkColor.RST listColorSelected = TTkColor.fg("#ffffdd")+TTkColor.bg("#000044") + TTkColor.BOLD diff --git a/TermTk/TTkLayouts/layout.py b/TermTk/TTkLayouts/layout.py index 28b494d5..97f661f9 100644 --- a/TermTk/TTkLayouts/layout.py +++ b/TermTk/TTkLayouts/layout.py @@ -30,13 +30,20 @@ from TermTk.TTkCore.log import TTkLog from TermTk.TTkCore.constant import TTkK class TTkLayoutItem: - __slots__ = ('_x', '_y', '_z', '_w', '_h', '_row','_col', '_sMax', '_sMaxVal', '_sMin', '_sMinVal', '_layoutItemType') + __slots__ = ( + '_x', '_y', '_z', '_w', '_h', + '_row','_col', + '_sMax', '_sMaxVal', + '_sMin', '_sMinVal', + '_alignment', + '_layoutItemType') def __init__(self, *args, **kwargs): self._x, self._y = 0, 0 self._z = kwargs.get('z',0) self._row = kwargs.get('row', 0) self._col = kwargs.get('col', 0) self._layoutItemType = kwargs.get('layoutItemType', TTkK.NONE) + self._alignment = kwargs.get('alignment', TTkK.NONE) self._w, self._h = 0, 0 self._sMax, self._sMin = False, False self._sMaxVal, self._sMinVal = 0, 0 @@ -120,6 +127,13 @@ class TTkLayout(TTkLayoutItem): def replaceItem(self, item, index): self._items[index] = item self._zSortItems() + self.update() + if item.layoutItemType == TTkK.LayoutItem: + item.setParent(self) + else: + item.widget().setParent(self.parentWidget()) + if self.parentWidget(): + self.parentWidget().update(repaint=True, updateLayout=True) def addItem(self, item): self._items.append(item) diff --git a/TermTk/TTkWidgets/__init__.py b/TermTk/TTkWidgets/__init__.py index 661972e8..f611648b 100644 --- a/TermTk/TTkWidgets/__init__.py +++ b/TermTk/TTkWidgets/__init__.py @@ -22,3 +22,4 @@ from .tree import * from .treeview import * from .treewidget import * from .graph import * +from .menubar import * diff --git a/TermTk/TTkWidgets/frame.py b/TermTk/TTkWidgets/frame.py index c5c8a986..e0ebe721 100644 --- a/TermTk/TTkWidgets/frame.py +++ b/TermTk/TTkWidgets/frame.py @@ -23,29 +23,42 @@ # SOFTWARE. from TermTk.TTkCore.cfg import * +from TermTk.TTkCore.helper import TTkHelper from TermTk.TTkCore.log import TTkLog from TermTk.TTkWidgets.widget import TTkWidget - - -class _TTkMenuBar(): - __slots__ = ('_itemsLeft', '_itemsCenter', '_itemsRight') - def __init__(self, *args, **kwargs): - pass - - def addMenu(self): - pass +from TermTk.TTkWidgets.menubar import TTkMenuLayout class TTkFrame(TTkWidget): - __slots__ = ('_border','_title', '_titleColor', '_borderColor', '_menubarTop', '_menubarBottom') + __slots__ = ( + '_border','_title', '_titleColor', '_titleAlign','_borderColor', + '_menubarTop', '_menubarTopPosition', '_menubarBottom') def __init__(self, *args, **kwargs): - TTkWidget.__init__(self, *args, **kwargs) - self._name = kwargs.get('name' , 'TTkFrame' ) self._borderColor = kwargs.get('borderColor', TTkCfg.theme.frameBorderColor ) self._titleColor = kwargs.get('titleColor', TTkCfg.theme.frameTitleColor ) + self._titleAlign = kwargs.get('titleAlign' , TTkK.CENTER_ALIGN ) self._title = kwargs.get('title' , '' ) self._border = kwargs.get('border', True ) + self._menubarTopPosition = 0 + self._menubarTop = None + self._menubarBottom = None + TTkWidget.__init__(self, *args, **kwargs) + self._name = kwargs.get('name' , 'TTkFrame' ) self.setBorder(self._border) + + def menubarTop(self): + if not self._menubarTop: + self._menubarTop = TTkMenuLayout(borderColor=self._borderColor) + self.rootLayout().addItem(self._menubarTop) + self._menubarTop.setGeometry(1,self._menubarTopPosition,self.width()-2,1) + if not self._border and self._padt == 0: + self.setPadding(1,0,0,0) + return self._menubarTop + + def resizeEvent(self, w, h): + if self._menubarTop: + self._menubarTop.setGeometry(1,self._menubarTopPosition,w-2,1) + def setBorder(self, border): self._border = border if border: self.setPadding(1,1,1,1) @@ -62,6 +75,9 @@ class TTkFrame(TTkWidget): pos=(0,0), size=(self._width,self._height), text=self._title, + align=self._titleAlign, color=self._borderColor, colorText=self._titleColor) + elif self._menubarTop: + self._canvas.drawMenuBarBg(pos=(0,0),size=self.width(),color=self._borderColor) diff --git a/TermTk/TTkWidgets/listwidget.py b/TermTk/TTkWidgets/listwidget.py index 464bbbfd..3d3f038a 100644 --- a/TermTk/TTkWidgets/listwidget.py +++ b/TermTk/TTkWidgets/listwidget.py @@ -29,7 +29,6 @@ from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal from TermTk.TTkCore.color import TTkColor from TermTk.TTkWidgets.widget import TTkWidget from TermTk.TTkWidgets.label import TTkLabel -from TermTk.TTkTestWidgets.testwidgetsizes import TTkTestWidgetSizes from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView class _TTkListWidgetText(TTkLabel): @@ -121,6 +120,5 @@ class TTkListWidget(TTkAbstractScrollView): w = self.width() for item in self.layout().children(): x,y,_,h = item.geometry() - minw = item.minimumWidth() item.setGeometry(x,y,max(w-1,fw),h) self.viewChanged.emit() \ No newline at end of file diff --git a/TermTk/TTkWidgets/menubar.py b/TermTk/TTkWidgets/menubar.py new file mode 100644 index 00000000..3461ac31 --- /dev/null +++ b/TermTk/TTkWidgets/menubar.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# 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 * +from TermTk.TTkCore.helper import TTkHelper +from TermTk.TTkCore.log import TTkLog +from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot +from TermTk.TTkWidgets.widget import TTkWidget +from TermTk.TTkWidgets.button import TTkButton +from TermTk.TTkLayouts.layout import TTkLayout +from TermTk.TTkLayouts.boxlayout import TTkHBoxLayout + +class _TTkMenuSpacer(TTkWidget): + __slots__ = ('clicked') + def __init__(self, *args, **kwargs): + TTkWidget.__init__(self, *args, **kwargs) + self._name = kwargs.get('name' , '_TTkMenuSpacer' ) + # Define Signals + self.clicked = pyTTkSignal() + self.resize(1,1) + #self.setMinimumHeight(1) + + def paintEvent(self): + TTkLog.debug("pippo") + self._canvas.drawText(pos=(0,0), text="-"*self.width()) + +class _TTkMenuButton(TTkButton): + __slot__ = ('_color', '_borderColor', '_shortcut', '_menu', 'menuButtonClicked') + def __init__(self, *args, **kwargs): + TTkButton.__init__(self, *args, **kwargs) + self._name = kwargs.get('name' , '_TTkMenuButton' ) + # signals + self.menuButtonClicked = pyTTkSignal(TTkButton) + self._color = kwargs.get('color', TTkCfg.theme.menuButtonColor ) + self._borderColor = kwargs.get('borderColor', TTkCfg.theme.menuButtonBorderColor ) + self._shortcut = [] + self._menu = [] + while self._text.find('&') != -1: + index = self._text.find('&') + shortcut = self._text[index+1] + TTkHelper.addShortcut(self, shortcut) + self._shortcut.append(index) + self._text = self._text[:index]+self._text[index+1:] + txtlen = len(self._text) + self.resize(txtlen,1) + self.setMinimumSize(txtlen+2,1) + self.setMaximumSize(txtlen+2,1) + self.clicked.connect(self.menuButtonEvent) + + def addMenu(self, text): + button = _TTkMenuButton(text=text, borderColor=self._borderColor, border=False) + button.menuButtonClicked.connect(self._menuCallback) + self._menu.append(button) + return button + + def addSpacer(self): + self._menu.append(_TTkMenuSpacer()) + + def setColor(self, color): + self._color = color + self.update() + + def setBorderColor(self, color): + self._borderColor = color + self.update() + + def shortcutEvent(self): + self.menuButtonEvent() + + @pyTTkSlot(TTkButton) + def _menuCallback(self, button): + #self._id = self._list.index(label) + TTkLog.debug(f"Bind Clicked {button._text}") + self.menuButtonClicked.emit(button) + self.setFocus() + self.update() + + @pyTTkSlot() + def menuButtonEvent(self): + if not self._menu: + self.menuButtonClicked.emit(self) + return + # Import here to avoid circular import + from TermTk.TTkWidgets.list import TTkList + from TermTk.TTkWidgets.resizableframe import TTkResizableFrame + + # Stupid way to find out if I am a submenu + isSubmenu = not self._border + frameHeight = len(self._menu) + 2 + frameWidth = self.width() + if frameHeight > 15: frameHeight = 15 + if frameWidth < 15: frameWidth = 15 + if isSubmenu: + frame = TTkResizableFrame(layout=TTkHBoxLayout(), size=(frameWidth,frameHeight)) + pos = (self.width(), -1) + else: + frame = TTkResizableFrame(layout=TTkHBoxLayout(), size=(frameWidth,frameHeight), title=self._text, titleAlign=TTkK.LEFT_ALIGN) + pos = (-1, 0) + listw = TTkList(parent=frame) + # listw.textClicked.connect(self._menuCallback) + # listw.textClicked.connect(self._menuCallback) + TTkLog.debug(f"{self._menu}") + for item in self._menu: + listw.addItem(item) + TTkHelper.overlay(self, frame, pos[0], pos[1]) + self.update() + + def paintEvent(self): + if self._pressed: + borderColor = self._borderColor + textColor = TTkCfg.theme.menuButtonColorClicked + scColor = TTkCfg.theme.menuButtonShortcutColor + else: + borderColor = self._borderColor + textColor = self._color + scColor = TTkCfg.theme.menuButtonShortcutColor + self._canvas.drawMenuBarButton( + pos=(0,0),text=self._text, + width=self.width(), + shortcuts=self._shortcut, + border=self._border, + submenu=len(self._menu)>0, + color=textColor, + borderColor=borderColor, + shortcutColor=scColor ) + +class TTkMenuLayout(TTkHBoxLayout): + __slots__ = ('_itemsLeft', '_itemsCenter', '_itemsRight', '_buttons') + def __init__(self, *args, **kwargs): + self._buttons = [] + TTkHBoxLayout.__init__(self, *args, **kwargs) + self._borderColor = kwargs.get('borderColor', TTkCfg.theme.frameBorderColor ) + self._itemsLeft = TTkHBoxLayout() + self._itemsCenter = TTkHBoxLayout() + self._itemsRight = TTkHBoxLayout() + self.addItem(self._itemsLeft) + self.addItem(TTkLayout()) + self.addItem(self._itemsCenter) + self.addItem(TTkLayout()) + self.addItem(self._itemsRight) + + def setBorderColor(self, color): + self._borderColor = color + for b in self._buttons: + b.setBorderColor(color) + self.update() + + def addMenu(self, text, alignment=TTkK.LEFT_ALIGN): + button = _TTkMenuButton(text=text, borderColor=self._borderColor, border=True) + if alignment == TTkK.LEFT_ALIGN: + self._itemsLeft.addWidget(button) + elif alignment == TTkK.CENTER_ALIGN: + self._itemsCenter.addWidget(button) + elif alignment == TTkK.RIGHT_ALIGN: + self._itemsRight.addWidget(button) + self._buttons.append(button) + return button diff --git a/TermTk/TTkWidgets/widget.py b/TermTk/TTkWidgets/widget.py index 62d51f00..d0d20d73 100644 --- a/TermTk/TTkWidgets/widget.py +++ b/TermTk/TTkWidgets/widget.py @@ -53,14 +53,12 @@ class TTkWidget: '_padt', '_padb', '_padl', '_padr', '_maxw', '_maxh', '_minw', '_minh', '_focus','_focus_policy', - '_layout', '_canvas', '_visible') + '_layout', '_canvas', '_visible', '_transparent') def __init__(self, *args, **kwargs): self._name = kwargs.get('name', 'TTkWidget' ) self._parent = kwargs.get('parent', None ) - self._layout = TTkLayout() # root layout - self._layout.addItem(TTkLayout()) # main layout self._x = kwargs.get('x', 0 ) self._y = kwargs.get('y', 0 ) self._x, self._y = kwargs.get('pos', (self._x, self._y)) @@ -86,11 +84,15 @@ class TTkWidget: self._focus = False self._focus_policy = TTkK.NoFocus + 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 ) - self.setLayout(kwargs.get('layout',TTkLayout())) + if self._parent is not None: self._parent.addWidget(self) self._parent.update(repaint=True, updateLayout=True) @@ -141,7 +143,7 @@ class TTkWidget: TTkWidget._paintChildCanvas(canvas, child, (bx,by,bw,bh)) def paintChildCanvas(self): - TTkWidget._paintChildCanvas(self._canvas, self.layout(), self.layout().geometry()) + TTkWidget._paintChildCanvas(self._canvas, self.rootLayout(), self.rootLayout().geometry()) def paintNotifyParent(self): parent = self._parent @@ -310,7 +312,7 @@ class TTkWidget: def setLayout(self, layout): self._layout.replaceItem(layout, 0) - self.layout().setParent(self) + #self.layout().setParent(self) self.update(repaint=True, updateLayout=True) def layout(self): return self._layout.itemAt(0) @@ -473,7 +475,7 @@ class TTkWidget: if repaint: TTkHelper.addUpdateBuffer(self) TTkHelper.addUpdateWidget(self) - if updateLayout and self.layout() is not None: + if updateLayout and self.rootLayout() is not None: self.rootLayout().setGeometry(0,0,self._width,self._height) self.layout().setGeometry( self._padl, self._padt, @@ -481,8 +483,8 @@ class TTkWidget: self._height - self._padt - self._padb) if updateParent and self._parent is not None: self._parent.update(updateLayout=True) - if updateLayout and self.layout() is not None: - if self.layout().update(): + if updateLayout and self.rootLayout() is not None: + if self.rootLayout().update(): self.layoutUpdated() def setFocus(self): diff --git a/TermTk/TTkWidgets/window.py b/TermTk/TTkWidgets/window.py index 213f2605..26651ebf 100644 --- a/TermTk/TTkWidgets/window.py +++ b/TermTk/TTkWidgets/window.py @@ -40,6 +40,7 @@ class TTkWindow(TTkResizableFrame): self._mouseDelta = (0,0) self.setFocusPolicy(TTkK.ClickFocus) self._draggable = False + self._menubarTopPosition = 2 def paintEvent(self): if self.hasFocus(): @@ -73,7 +74,11 @@ class TTkWindow(TTkResizableFrame): return TTkResizableFrame.mouseDragEvent(self, evt) def focusInEvent(self): + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.fg("#ffff55")) self.update() def focusOutEvent(self): + if self._menubarTop: + self._menubarTop.setBorderColor(TTkColor.RST) self.update() \ No newline at end of file diff --git a/tests/showcase/menubar.py b/tests/showcase/menubar.py new file mode 100755 index 00000000..d927fb3c --- /dev/null +++ b/tests/showcase/menubar.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2021 Eugenio Parodi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys, os, argparse + +sys.path.append(os.path.join(sys.path[0],'../..')) +import TermTk as ttk + + +def demoMenuBar(root=None): + frame = ttk.TTkFrame(parent=root, border=False, layout=ttk.TTkVBoxLayout()) + frameTop = ttk.TTkFrame(parent=frame, border=False) + frameBottom = ttk.TTkFrame(parent=frame, border=True,layout=ttk.TTkVBoxLayout()) + + fileMenu = frameTop.menubarTop().addMenu("&File") + fileMenu.addMenu("Open") + fileMenu.addMenu("Close") + fileMenu.addMenu("Exit") + + frameTop.menubarTop().addMenu("&Edit") + frameTop.menubarTop().addMenu("&Selection") + + frameTop.menubarTop().addMenu("&Center 1", alignment=ttk.TTkK.CENTER_ALIGN) + frameTop.menubarTop().addMenu("Cen&te&r 2", alignment=ttk.TTkK.CENTER_ALIGN) + + frameTop.menubarTop().addMenu("_", alignment=ttk.TTkK.RIGHT_ALIGN) + frameTop.menubarTop().addMenu("^", alignment=ttk.TTkK.RIGHT_ALIGN) + frameTop.menubarTop().addMenu("X", alignment=ttk.TTkK.RIGHT_ALIGN) + + window = ttk.TTkWindow(title="Test MenuBar", parent=frameTop,pos=(1,1), size=(60,10), border=True) + fileMenu2 = window.menubarTop().addMenu("&File") + fileMenu2.addMenu("New File") + fileMenu2.addMenu("Old File") + fileMenu2.addSpacer() + fileMenu2.addMenu("Open") + fileMenu2.addMenu("Save") + fileMenu2.addMenu("Save as") + fileMenu2.addSpacer() + exportFileMenu2 = fileMenu2.addMenu("Export") + txtExportFileMenu2 = exportFileMenu2.addMenu("t&xt") + txtExportFileMenu2.addMenu("ASCII") + txtExportFileMenu2.addMenu("URF-8") + txtExportFileMenu2.addMenu("PETSCII") + exportFileMenu2.addMenu("&json") + exportFileMenu2.addMenu("&yaml") + fileMenu2.addSpacer() + fileMenu2.addMenu("Close") + fileMenu2.addSpacer() + fileMenu2.addMenu("Exit") + + editMenu2 = window.menubarTop().addMenu("&Edit") + editMenu2.addMenu("Undo") + editMenu2.addMenu("Redo") + editMenu2.addMenu("Cut") + editMenu2.addMenu("Copy") + editMenu2.addMenu("Paste") + editMenu2.addMenu("Find") + editMenu2.addMenu("Replace") + + window.menubarTop().addMenu("&Selection") + + window.menubarTop().addMenu("&Center 3", alignment=ttk.TTkK.CENTER_ALIGN) + + window.menubarTop().addMenu("X", alignment=ttk.TTkK.RIGHT_ALIGN) + + + fileMenu3 = frameBottom.menubarTop().addMenu("&File 2") + fileMenu3.addMenu("Open") + fileMenu3.addMenu("Close") + fileMenu3.addMenu("Exit") + + frameBottom.menubarTop().addMenu("&Edit 2") + frameBottom.menubarTop().addMenu("&Selection 2") + + ttk.TTkLogViewer(parent=frameBottom) + + return frame + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-f', help='Full Screen', action='store_true') + args = parser.parse_args() + + ttk.TTkLog.use_default_file_logging() + + root = ttk.TTk() + if args.f: + rootLayout = root + root.setLayout(ttk.TTkGridLayout()) + else: + rootLayout = ttk.TTkWindow(title="Test MenuBar", parent=root,pos=(1,1), size=(100,40), border=True, layout=ttk.TTkGridLayout()) + demoMenuBar(rootLayout) + root.mainloop() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tests/test.showcase.001.py b/tests/test.showcase.001.py index 7cd43894..cdcaace9 100755 --- a/tests/test.showcase.001.py +++ b/tests/test.showcase.001.py @@ -39,6 +39,7 @@ from showcase.windows import demoWindows from showcase.formwidgets import demoFormWidgets from showcase.scrollarea import demoScrollArea from showcase.list import demoList +from showcase.menubar import demoMenuBar def demoShowcase(root= None, border=True): tabWidget1 = ttk.TTkTabWidget(parent=root, border=border) @@ -46,6 +47,7 @@ def demoShowcase(root= None, border=True): tabWidget1.addTab(ttk.TTkTestWidget(border=True, title="Frame1.2"), " Label Test 1.2 ") tabWidget1.addTab(demoLayout(), " Layout Test ") tabWidget1.addTab(demoLayoutNested()," Nested Layout Test ") + tabWidget1.addTab(demoMenuBar(), " MenuBar Test ") tabWidget1.addTab(demoFormWidgets(), " Form Test ") tabWidget1.addTab(demoList(), " List Test ") tabWidget1.addTab(demoGraph(), " Graph Test ")