You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

450 lines
16 KiB

#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.constant import *
import TermTk.libbpytop as lbt
from TermTk.TTkCore.canvas import *
from TermTk.TTkCore.signal import *
from TermTk.TTkLayouts.layout import TTkLayout, TTkWidgetItem
class TTkWidget:
'''
Terminal
┌─────────────────────────────────────────┐
│ │
│ TTkWidget width │
│ (x,y)┌─────────────────────────┐ │
│ │ padt │ │
│ │ ┌───────────────┐ │ height │
│ │padl│ Layout/childs │padr│ │
│ │ └───────────────┘ │ │
│ │ padl │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────┘
'''
__slots__ = (
'_name', '_parent',
'_x', '_y', '_width', '_height',
'_padt', '_padb', '_padl', '_padr',
'_maxw', '_maxh', '_minw', '_minh',
'_focus','_focus_policy',
'_layout', '_canvas', '_visible')
def __init__(self, *args, **kwargs):
self._name = kwargs.get('name', 'TTkWidget' )
self._parent = kwargs.get('parent', None )
self._x = kwargs.get('x', 0 )
self._y = kwargs.get('y', 0 )
self._x, self._y = kwargs.get('pos', (self._x, self._y))
self._width = kwargs.get('width' , 0 )
self._height = kwargs.get('height', 0 )
self._width, self._height = kwargs.get('size', (self._width, self._height))
padding = kwargs.get('padding', 0 )
self._padt = kwargs.get('paddingTop', padding )
self._padb = kwargs.get('paddingBottom', padding )
self._padl = kwargs.get('paddingLeft', padding )
self._padr = kwargs.get('paddingRight', padding )
self._maxw = kwargs.get('maxWidth', 0x10000)
self._maxh = kwargs.get('maxHeight', 0x10000)
self._maxw, self._maxh = kwargs.get('maxSize', (self._maxw, self._maxh))
self._minw = kwargs.get('minWidth', 0x00000)
self._minh = kwargs.get('minHeight', 0x00000)
self._minw, self._minh = kwargs.get('minSize', (self._minw, self._minh))
self._visible = kwargs.get('visible', True)
self._focus = False
self._focus_policy = TTkK.NoFocus
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)
self.update(repaint=True, updateLayout=True)
def addWidget(self, widget):
widget._parent = self
if self._layout is not None:
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):
# paint over child canvas
lx,ly,lw,lh = self._layout.geometry()
for item in self._layout.zSortedItems:
if isinstance(item, TTkWidgetItem) and not item.isEmpty():
child = item.widget()
cx,cy,cw,ch = child.geometry()
self._canvas.paintCanvas(
child.getCanvas(),
(cx, cy, cw, ch),
(0,0,cw,ch),
(lx, ly, lw, lh))
def paintNotifyParent(self):
parent = self._parent
while parent is not None:
parent._canvas.clean()
parent.paintEvent()
parent.paintChildCanvas()
parent = parent._parent
def moveEvent(self, x, y): pass
def resizeEvent(self, w, h): pass
def move(self, x, y):
if x==self._x and y==self._y: return
self._x = x
self._y = y
self.update(repaint=False, updateLayout=False)
self.moveEvent(x,y)
def resize(self, w, h):
if w==self._width and h==self._height: return
self._width = w
self._height = h
self._canvas.resize(self._width, self._height)
self.update(repaint=True, updateLayout=True)
self.resizeEvent(w,h)
def setGeometry(self, x, y, w, h):
self.resize(w, h)
self.move(x, y)
def getPadding(self):
return self._padt, self._padb, self._padl, self._padr
def setPadding(self, top, bottom, left, right):
if self._padt == top and self._padb == bottom and \
self._padl == left and self._padr == right: return
self._padt = top
self._padb = bottom
self._padl = left
self._padr = right
self.update(repaint=True, updateLayout=True)
def mouseDoubleClickEvent(self, evt): return False
def mouseMoveEvent(self, evt): return False
def mouseDragEvent(self, evt): return False
def mousePressEvent(self, evt): return False
def mouseReleaseEvent(self, evt): return False
def wheelEvent(self, evt): return False
def enterEvent(self, evt): return False
def leaveEvent(self, evt): return False
def keyPressEvent(self, evt): return False
def keyReleaseEvent(self, evt): return False
@staticmethod
def _mouseEventLayoutHandle(evt, layout):
x, y = evt.x, evt.y
lx,ly,lw,lh =layout.geometry()
# opt of bounds
if x<lx or x>lx+lw or y<ly or y>lh+ly:
return True
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
wevt = None
mouseEvent = False
if isinstance(evt, lbt.MouseEvent):
mouseEvent = True
wx,wy,ww,wh = widget.geometry()
# Skip the mouse event if outside this widget
if x >= wx and x<wx+ww and y>=wy and y<wy+wh:
wevt = evt.clone(pos=(x-wx, y-wy))
if mouseEvent:
if wevt is not None:
#if not widget._data['mouse']['underMouse']:
# widget._data['mouse']['underMouse'] = True
# widget.enterEvent(wevt)
if widget.mouseEvent(wevt):
return True
#else:
# if widget._data['mouse']['underMouse']:
# widget._data['mouse']['underMouse'] = False
# widget.leaveEvent(evt)
# if widget._data['layout'] is not None:
# CuWidget._broadcastLeaveEvent(evt, widget._data['layout'])
continue
#if widget.event(evt):
# return True
elif isinstance(item, TTkLayout):
levt = evt.clone(pos=(x, y))
if TTkWidget._mouseEventLayoutHandle(levt, item):
return True
return False
def mouseEvent(self, evt):
# handle own events
if evt.evt == lbt.MouseEvent.Move:
if self.mouseMoveEvent(evt):
return True
if evt.evt == lbt.MouseEvent.Drag:
if self.mouseDragEvent(evt):
return True
elif evt.evt == lbt.MouseEvent.Release:
#if self.hasFocus():
# self.clearFocus()
if self.mouseReleaseEvent(evt):
return True
elif evt.evt == lbt.MouseEvent.Press:
if self.focusPolicy() & TTkK.ClickFocus == TTkK.ClickFocus:
self.setFocus()
self.raiseWidget()
if self.mousePressEvent(evt):
# TTkLog.debug(f"Click {self._name}")
return True
elif evt.key == lbt.MouseEvent.Wheel:
if self.wheelEvent(evt):
return True
#if self.focusPolicy() & CuT.WheelFocus == CuT.WheelFocus:
# self.setFocus()
#elif evt.type() == CuEvent.KeyPress:
# self.keyPressEvent(evt)
#elif evt.type() == CuEvent.KeyRelease:
# self.keyReleaseEvent(evt)
# Trigger this event to the childs
if self._layout is not None:
return TTkWidget._mouseEventLayoutHandle(evt, self._layout)
def keyEvent(self, evt):
pass
#def event(self, evt):
# pass
# # handle own events
# if evt.type() == CuEvent.MouseMove:
# if evt.button() == CuT.NoButton:
# self.mouseMoveEvent(evt)
# elif evt.type() == CuEvent.MouseButtonRelease:
# self.mouseReleaseEvent(evt)
# elif evt.type() == CuEvent.MouseButtonPress:
# self.mousePressEvent(evt)
# if self.focusPolicy() & CuT.ClickFocus == CuT.ClickFocus:
# self.setFocus()
# elif evt.type() == CuEvent.Wheel:
# self.wheelEvent(evt)
# if self.focusPolicy() & CuT.WheelFocus == CuT.WheelFocus:
# self.setFocus()
# elif evt.type() == CuEvent.KeyPress:
# self.keyPressEvent(evt)
# elif evt.type() == CuEvent.KeyRelease:
# self.keyReleaseEvent(evt)
# # Trigger this event to the childs
# if self._layout is not None:
# return CuWidget._eventLayoutHandle(evt, self._layout)
def setLayout(self, layout):
self._layout = layout
self._layout.setParent(self)
self.update(repaint=True, updateLayout=True)
def layout(self): return self._layout
def setParent(self, parent):
self._parent = parent
def parentWidget(self):
return self._parent
def x(self): return self._x
def y(self): return self._y
def width(self): return self._width
def height(self): return self._height
def pos(self): return self._x, self._y
def size(self): return self._width, self._height
def geometry(self): return self._x, self._y, self._width, self._height
def maximumSize(self):
return self.maximumWidth(), self.maximumHeight()
def maximumHeight(self):
wMaxH = self._maxh
if self._layout is not None:
lMaxH = self._layout.maximumHeight() + self._padt + self._padb
if lMaxH < wMaxH:
return lMaxH
return wMaxH
def maximumWidth(self):
wMaxW = self._maxw
if self._layout is not None:
lMaxW = self._layout.maximumWidth() + self._padl + self._padr
if lMaxW < wMaxW:
return lMaxW
return wMaxW
def minimumSize(self):
return self.minimumWidth(), self.minimumHeight()
def minimumHeight(self):
wMinH = self._minh
if self._layout is not None:
lMinH = self._layout.minimumHeight() + self._padt + self._padb
if lMinH > wMinH:
return lMinH
return wMinH
def minimumWidth(self):
wMinW = self._minw
if self._layout is not None:
lMinW = self._layout.minimumWidth() + self._padl + self._padr
if lMinW > wMinW:
return lMinW
return wMinW
def setMaximumSize(self, maxw, maxh):
self.setMaximumWidth(maxw)
self.setMaximumHeight(maxh)
def setMaximumHeight(self, maxh):
self._maxh = maxh
self.update(updateLayout=True, updateParent=True)
def setMaximumWidth(self, maxw):
self._maxw = maxw
self.update(updateLayout=True, updateParent=True)
def setMinimumSize(self, minw, minh):
self.setMinimumWidth(minw)
self.setMinimumHeight(minh)
def setMinimumHeight(self, minh):
self._minh = minh
self.update(updateLayout=True, updateParent=True)
def setMinimumWidth(self, minw):
self._minw = minw
self.update(updateLayout=True, updateParent=True)
#@staticmethod
#def _showHandle(layout):
# for i in range(layout.count()):
# item = layout.itemAt(i)
# if isinstance(item, CuWidgetItem) and not item.isEmpty():
# item.widget().show()
# elif isinstance(item, CuLayout):
# CuWidget._showHandle(item)
@pyTTkSlot()
def show(self):
self._canvas.show()
self._visible = True
self.update(updateLayout=True, updateParent=True)
#@staticmethod
#def _hideHandle(layout):
# for i in range(layout.count()):
# item = layout.itemAt(i)
# if isinstance(item, CuWidgetItem) and not item.isEmpty():
# item.widget().hide()
# elif isinstance(item, CuLayout):
# CuWidget._hideHandle(item)
@pyTTkSlot()
def hide(self):
self._canvas.hide()
self._visible = False
self.update(repaint=False, updateParent=True)
def raiseWidget(self):
if self._parent is not None and \
self._parent._layout is not None:
self._parent.raiseWidget()
self._parent._layout.raiseWidget(self)
def lowerWidget(self):
if self._parent is not None and \
self._parent._layout is not None:
self._parent.lowerWidget()
self._parent._layout.lowerWidget(self)
def close(self): pass
def isVisible(self):
return self._visible
# Event to be sent
# TODO: Remove This
def layoutUpdated(self): pass
def update(self, repaint=True, updateLayout=False, updateParent=False):
if repaint:
TTkHelper.addUpdateBuffer(self)
TTkHelper.addUpdateWidget(self)
if updateLayout and self._layout is not None:
self._layout.setGeometry(
self._padl, self._padt,
self._width - self._padl - self._padr,
self._height - self._padt - self._padb)
if updateParent and self._parent is not None:
self._parent.update(updateLayout=True)
if updateLayout and self._layout is not None:
if self._layout.update():
self.layoutUpdated()
def setFocus(self):
tmp = TTkHelper.getFocus()
if tmp is not None:
tmp.clearFocus()
tmp.focusOutEvent()
tmp.update(repaint=True, updateLayout=False)
#tmp = TTkHelper.getOverlay()
if not TTkHelper.isOverlay(self):
TTkHelper.removeOverlay()
TTkHelper.setFocus(self)
self._focus = True
self.focusInEvent()
def clearFocus(self):
TTkHelper.clearFocus()
self._focus = False
self.focusOutEvent()
def hasFocus(self):
return self._focus
def getCanvas(self):
return self._canvas
def focusPolicy(self):
return self._focus_policy
def setFocusPolicy(self, policy):
self._focus_policy = policy
def focusInEvent(self): pass
def focusOutEvent(self): pass