Browse Source

Added abstract for scroll area and scroll view

pull/3/head
Eugenio Parodi 5 years ago
parent
commit
9e1a9e9e1d
  1. 1
      TermTk/TTkAbstract/__init__.py
  2. 92
      TermTk/TTkAbstract/abstractscrollarea.py
  3. 91
      TermTk/TTkAbstract/abstractscrollview.py
  4. 6
      TermTk/TTkCore/constant.py
  5. 1
      TermTk/TTkWidgets/__init__.py
  6. 9
      TermTk/TTkWidgets/scrollbar.py
  7. 272
      TermTk/TTkWidgets/table.py
  8. 258
      TermTk/TTkWidgets/tableview.py
  9. 52
      TermTk/TTkWidgets/texedit.py
  10. 22
      TermTk/TTkWidgets/widget.py
  11. 1
      TermTk/__init__.py
  12. 1
      docs/BUGS.md
  13. 5
      docs/TODO.md

1
TermTk/TTkAbstract/__init__.py

@ -0,0 +1 @@
from .abstractscrollarea import *

92
TermTk/TTkAbstract/abstractscrollarea.py

@ -0,0 +1,92 @@
#!/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.constant import TTkConstant, TTkK
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
class TTkAbstractScrollArea(TTkWidget):
__slots__ = (
'_viewport',
'_verticalScrollBar', '_verticalScrollBarPolicy',
'_horizontalScrollBar', '_horizontalScrollBarPolicy',)
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkAbstractScrollArea')
self.setLayout(TTkGridLayout())
self._verticalScrollBar = TTkScrollBar(orientation=TTkK.VERTICAL)
self._horizontalScrollBar = TTkScrollBar(orientation=TTkK.HORIZONTAL)
self._verticalScrollBarPolicy = TTkK.ScrollBarAsNeeded
self._horizontalScrollBarPolicy = TTkK.ScrollBarAsNeeded
@pyTTkSlot()
def _viewportChanged(self):
fw, fh = self._viewport.viewFullAreaSize()
dw, dh = self._viewport.viewDisplayedSize()
ox, oy = self._viewport.getViewOffsets()
hpage = dw
vpage = dh
hrange = fw - dw
vrange = fh - dh
self._verticalScrollBar.setPageStep(vpage)
self._verticalScrollBar.setRange(0, vrange)
self._verticalScrollBar.setValue(oy)
self._horizontalScrollBar.setPageStep(hpage)
self._horizontalScrollBar.setRange(0, hrange)
self._horizontalScrollBar.setValue(ox)
@pyTTkSlot(int)
def _vscrollMoved(self, val):
ox, _ = self._viewport.getViewOffsets()
self._viewport.viewMoveTo(ox, val)
@pyTTkSlot(int)
def _hscrollMoved(self, val):
_, oy = self._viewport.getViewOffsets()
self._viewport.viewMoveTo(val, oy)
def setViewport(self, viewport):
if not isinstance(viewport, TTkAbstractScrollView):
raise TypeError("TTkAbstractScrollView is required in TTkAbstractScrollArea.setVewport(viewport)")
self._viewport = viewport
self._viewport.viewChanged.connect(self._viewportChanged)
self._verticalScrollBar.sliderMoved.connect(self._vscrollMoved)
self._horizontalScrollBar.sliderMoved.connect(self._hscrollMoved)
self.layout().addWidget(viewport,0,0)
self.layout().addWidget(self._verticalScrollBar,0,1)
self.layout().addWidget(self._horizontalScrollBar,1,0)
def setVerticalScrollBarPolicy(self, policy):
self._verticalScrollBarPolicy = policy
def setHorizontalScrollBarPolicy(self, policy):
self._horizontalScrollBarPolicy = policy

91
TermTk/TTkAbstract/abstractscrollview.py

@ -0,0 +1,91 @@
#!/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.constant import TTkConstant, TTkK
from TermTk.TTkCore.cfg import *
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkWidgets.widget import TTkWidget
class TTkAbstractScrollView(TTkWidget):
__slots__ = (
'_viewOffsetX', '_viewOffsetY',
# Signals
'viewMovedTo', 'viewSizeChanged', 'viewChanged')
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkAbstractScrollView')
# Signals
self.viewMovedTo = pyTTkSignal(int, int) # x, y
self.viewSizeChanged = pyTTkSignal(int, int) # w, h
self.viewChanged = pyTTkSignal()
self._viewOffsetX = 0
self._viewOffsetY = 0
# Override this function
def viewFullAreaSize(self) -> (int, int):
raise NotImplementedError()
# Override this function
def viewDisplayedSize(self) -> (int, int):
raise NotImplementedError()
@pyTTkSlot(int, int)
def viewMoveTo(self, x, y):
fw, fh = self.viewFullAreaSize()
dw, dh = self.viewDisplayedSize()
rangex = fw - dw
rangey = fh - dh
# TTkLog.debug(f"x:{x},y:{y}, full:{fw,fh}, display:{dw,dh}, range:{rangex,rangey}")
if x>rangex: x = rangex
if y>rangey: y = rangey
if x<0 : x = 0
if y<0 : y = 0
# TTkLog.debug(f"x:{x},y:{y}, wo:{self._viewOffsetX,self._viewOffsetY}")
if self._viewOffsetX == x and \
self._viewOffsetY == y: # Nothong to do
return
self._viewOffsetX = x
self._viewOffsetY = y
self.viewMovedTo.emit(x,y)
self.viewChanged.emit()
self.update()
def wheelEvent(self, evt):
delta = TTkCfg.scrollDelta
offx, offy = self.getViewOffsets()
if evt.evt == TTkK.WHEEL_Up:
delta = -delta
self.viewMoveTo(offx, offy + delta)
return True
def resizeEvent(self, w, h):
self.viewSizeChanged.emit(w,h)
self.viewChanged.emit()
def getViewOffsets(self):
return self._viewOffsetX, self._viewOffsetY

6
TermTk/TTkCore/constant.py

@ -46,6 +46,12 @@ class TTkConstant:
HORIZONTAL = 0x01
VERTICAL = 0x02
# Scroll Bar Policy
ScrollBarAsNeeded = 0x00
ScrollBarAlwaysOff = 0x01
ScrollBarAlwaysOn = 0x02
# Keys
NoButton = 0x00000000 # The button state does not refer to any button (see QMouseEvent::button()).
AllButtons = 0x07ffffff # This value corresponds to a mask of all possible mouse buttons. Use to set the 'acceptedButtons' property of a MouseArea to accept ALL mouse buttons.

1
TermTk/TTkWidgets/__init__.py

@ -13,4 +13,5 @@ from .texedit import *
from .scrollbar import *
from .window import *
from .table import *
from .tableview import *
from .logviewer import *

9
TermTk/TTkWidgets/scrollbar.py

@ -196,6 +196,9 @@ class TTkScrollBar(TTkWidget):
@pyTTkSlot(int, int)
def setRange(self, min, max):
if self._minimum == min and \
self._maximum == max :
return
self.minimum = min
self.maximum = max
self.rangeChanged.emit(min, max)
@ -208,6 +211,8 @@ class TTkScrollBar(TTkWidget):
def minimum(self): return self._minimum
@minimum.setter
def minimum(self, v):
if v == self._minimum:
return
if v > self._maximum:
v = self._maximum
self._minimum = v
@ -217,6 +222,8 @@ class TTkScrollBar(TTkWidget):
def maximum(self): return self._maximum
@minimum.setter
def maximum(self, v):
if v == self._maximum:
return
if v < self._minimum:
v = self._minimum
self._maximum = v
@ -236,6 +243,8 @@ class TTkScrollBar(TTkWidget):
def value(self): return self._value
@value.setter
def value(self, v):
if self._value == v:
return
if v > self._maximum: v = self._maximum
if v < self._minimum: v = self._minimum
if self._value == v: return

272
TermTk/TTkWidgets/table.py

@ -27,288 +27,34 @@ 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.TTkWidgets.tableview import TTkTableView
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.frame import TTkFrame
from TermTk.TTkWidgets.spacer import TTkSpacer
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea
class _TTkTableViewHeader(TTkWidget):
__slots__ = (
'_header', '_showHeader',
'_alignments', '_headerColor',
'_columns')
class TTkTable(TTkAbstractScrollArea):
__slots__ = ('_tableView', 'activated')
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTableViewHeader' )
self._columns = kwargs.get('columns' , [-1] )
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
self._headerColor = kwargs.get('headerColor' , TTkColor.BOLD )
self.setMaximumHeight(1)
self.setMinimumHeight(1)
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 setHeader(self, header):
if len(header) != len(self._columns):
return
self._header = header
def setColumnSize(self, columns):
self._columns = columns
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
def paintEvent(self):
w,h = self.size()
total = 0
variableCols = 0
# Retrieve the free size
for width in self._columns:
if width > 0:
total += width
else:
variableCols += 1
# Define the list of cols sizes
sizes = []
for width in self._columns:
if width > 0:
sizes.append(width)
else:
sizes.append((w-total)//variableCols)
variableCols -= 1
colors = [self._headerColor]*len(self._header)
self._canvas.drawTableLine(pos=(0,0), items=self._header, sizes=sizes, colors=colors, alignments=self._alignments)
class _TTkTableViewData(TTkWidget):
__slots__ = (
'_alignments',
'_columns', '_columnColors',
'_tableData',
'_selectColor', '_moveTo', '_selected')
def __init__(self, *args, **kwargs):
self._moveTo = 0
self._tableData = []
TTkWidget.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTableViewData' )
self._columns = kwargs.get('columns' , [-1] )
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._selected = -1
self.setFocusPolicy(TTkK.ClickFocus)
class _TTkTableView(TTkWidget):
__slots__ = (
'_header', '_showHeader',
'_alignments', '_headerColor',
'_columns', '_columnColors',
'_tableData',
'_selectColor', '_moveTo', '_selected',
# Signals
'activated', 'tableMoved', 'displayedMaxRowsChanged', 'tablePropertiesChanged')
def __init__(self, *args, **kwargs):
self._moveTo = 0
self._tableData = []
TTkWidget.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTableView' )
# define signals
self.activated = pyTTkSignal(int) # Value
self.tableMoved = pyTTkSignal(int) # Value
self.displayedMaxRowsChanged = pyTTkSignal(int) # Value
self.tablePropertiesChanged = pyTTkSignal(int, int, int, int) # selected, numItems, displayed lines, offsetView
self._columns = kwargs.get('columns' , [-1] )
self._header = [""]*len(self._columns)
self._showHeader = False
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._selected = -1
self.setFocusPolicy(TTkK.ClickFocus)
def _initSignals(self):
# self.cellActivated(int row, int column)
# self.cellChanged(int row, int column)
# self.cellClicked(int row, int column)
# self.cellDoubleClicked(int row, int column)
# self.cellEntered(int row, int column)
# self.cellPressed(int row, int column)
# self.currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
# self.currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
# self.itemActivated(QTableWidgetItem *item)
# self.itemChanged(QTableWidgetItem *item)
# self.itemClicked(QTableWidgetItem *item)
# self.itemDoubleClicked(QTableWidgetItem *item)
# self.itemEntered(QTableWidgetItem *item)
# self.itemPressed(QTableWidgetItem *item)
# self.itemSelectionChanged()
pass
def items(self): return self._tableData
def setAlignment(self, alignments):
if len(alignments) != len(self._columns):
return
self._alignments = alignments
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.tablePropertiesChanged.emit(self._selected, len(self._tableData), self.height(), self._moveTo)
self.update()
def mousePressEvent(self, evt):
x,y = evt.x, evt.y
if y >= 0:
selected = self._moveTo + y
if selected >= len(self._tableData):
selected = -1
self._selected = selected
self.update()
self.activated.emit(self._selected)
return True
def wheelEvent(self, evt):
delta = TTkCfg.scrollDelta
if evt.evt == TTkK.WHEEL_Up:
delta = -delta
self.scrollTo(self._moveTo + delta)
self.update()
return True
def resizeEvent(self, w, h):
if self._moveTo > len(self._tableData)-h-1:
self._moveTo = len(self._tableData)-h-1
if self._moveTo < 0:
self._moveTo = 0
self.displayedMaxRowsChanged.emit(h)
self.tablePropertiesChanged.emit(self._selected, len(self._tableData), self.height(), self._moveTo)
@pyTTkSlot(int)
def scrollTo(self, to):
# TTkLog.debug(f"to:{to},h{self._height},size:{len(self._tableData)}")
max = len(self._tableData) - self.height()
if to>max: to=max
if to<0: to=0
self._moveTo = to
self.tableMoved.emit(to)
self.tablePropertiesChanged.emit(self._selected, len(self._tableData), self.height(), self._moveTo)
self.update()
def paintEvent(self):
w,h = self.size()
total = 0
variableCols = 0
# Retrieve the free size
for width in self._columns:
if width > 0:
total += width
else:
variableCols += 1
# Define the list of cols sizes
sizes = []
for width in self._columns:
if width > 0:
sizes.append(width)
else:
sizes.append((w-total)//variableCols)
variableCols -= 1
maxItems = len(self._tableData)
itemFrom = self._moveTo
if itemFrom > maxItems-h: itemFrom = maxItems-h
if itemFrom < 0 : itemFrom = 0
itemTo = itemFrom + h
if itemTo > maxItems: itemTo = maxItems
# TTkLog.debug(f"moveto:{self._moveTo}, maxItems:{maxItems}, f:{itemFrom}, t{itemTo}, h:{h}, sel:{self._selected}")
y = 0
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:
colors = [self._selectColor]*len(self._columnColors)
self._canvas.drawTableLine(pos=(0,y), items=item, sizes=sizes, colors=colors, alignments=self._alignments)
else:
colors = [c.modParam(val=-val) for c in self._columnColors]
self._canvas.drawTableLine(pos=(0,y), items=item, sizes=sizes, colors=colors, alignments=self._alignments)
y+=1
class TTkTable(TTkWidget):
__slots__ = ('_vscroller', '_hscroller', '_tableView', '_headerView', '_showHeader', 'activated')
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
TTkAbstractScrollArea.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkTable' )
if 'parent' in kwargs:
kwargs.pop('parent')
self._tableView = _TTkTableView(*args, **kwargs)
self._headerView = _TTkTableViewHeader(*args, **kwargs)
if 'parent' in kwargs: kwargs.pop('parent')
self._tableView = TTkTableView(*args, **kwargs)
# Forward the signal
self.activated = self._tableView.activated
self._showHeader = kwargs.get('showHeader',True)
self._vscroller = TTkScrollBar(orientation=TTkK.VERTICAL)
self._hscroller = TTkScrollBar(orientation=TTkK.HORIZONTAL)
self.setLayout(TTkGridLayout())
self._vscroller.sliderMoved.connect(self._tableView.scrollTo)
self._tableView.tablePropertiesChanged.connect(self.handleTableProperties)
self.layout().addWidget(self._headerView,0,0)
self.layout().addWidget(self._tableView,1,0)
# self.layout().addWidget(TTkTestWidget(border=True),0,0)
self.layout().addWidget(self._vscroller,1,1)
# self.layout().addWidget(self._hscroller,1,0)
if not self._showHeader:
self._headerView.hide()
self.setFocusPolicy(TTkK.ClickFocus)
self.setViewport(self._tableView)
def setAlignment(self, *args, **kwargs) :
self._tableView.setAlignment(*args, **kwargs)
self._headerView.setAlignment(*args, **kwargs)
def setHeader(self, *args, **kwargs) :
self._headerView.setHeader(*args, **kwargs)
self._tableView.setHeader(*args, **kwargs)
def setColumnSize(self, *args, **kwargs) :
self._tableView.setColumnSize(*args, **kwargs)
self._headerView.setColumnSize(*args, **kwargs)
def setColumnColors(self, *args, **kwargs):
self._tableView.setColumnColors(*args, **kwargs)
def appendItem(self, *args, **kwargs) :
self._vscroller.setRangeTo(len(self._tableView.items()))
self._tableView.appendItem(*args, **kwargs)
@pyTTkSlot(int, int, int, int)
def handleTableProperties(self, selected, items, height, offset):
self._vscroller.setRange(0, items-height)
self._vscroller.setValue(offset)

258
TermTk/TTkWidgets/tableview.py

@ -22,62 +22,121 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from TermTk.TTkCore.cfg import TTkCfg
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.spacer import TTkSpacer
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
'''
class _TTkTableViewHeader(TTkWidget):
__slots__ = ('_header', '_alignments', '_headerColor', '_columns')
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTableViewHeader' )
self._columns = kwargs.get('columns' , [-1] )
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
self._headerColor = kwargs.get('headerColor' , TTkColor.BOLD )
self.setMaximumHeight(1)
self.setMinimumHeight(1)
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
'''
class _______TTkTable(TTkWidget):
def setColumnSize(self, columns):
self._columns = columns
self._header = [""]*len(self._columns)
self._alignments = [TTkK.NONE]*len(self._columns)
def paintEvent(self):
w,h = self.size()
total = 0
variableCols = 0
# Retrieve the free size
for width in self._columns:
if width > 0:
total += width
else:
variableCols += 1
# Define the list of cols sizes
sizes = []
for width in self._columns:
if width > 0:
sizes.append(width)
else:
sizes.append((w-total)//variableCols)
variableCols -= 1
colors = [self._headerColor]*len(self._header)
self._canvas.drawTableLine(pos=(0,0), items=self._header, sizes=sizes, colors=colors, alignments=self._alignments)
class _TTkTableView(TTkAbstractScrollView):
__slots__ = (
'_hlayout','_vscroller',
'_header', '_showHeader',
'_alignments', '_headerColor',
'_columns', '_columnColors',
'_tableData',
'_selectColor', '_moveTo', '_selected')
'_selectColor', '_selected',
# Signals
'activated')
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' )
TTkAbstractScrollView.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTableView' )
# define signals
self.activated = pyTTkSignal(int) # Value
self._columns = kwargs.get('columns' , [-1] )
self._header = [""]*len(self._columns)
self._showHeader = False
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(TTkK.ClickFocus)
def _initSignals(self):
# self.cellActivated(int row, int column)
# self.cellChanged(int row, int column)
# self.cellClicked(int row, int column)
# self.cellDoubleClicked(int row, int column)
# self.cellEntered(int row, int column)
# self.cellPressed(int row, int column)
# self.currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
# self.currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
# self.itemActivated(QTableWidgetItem *item)
# self.itemChanged(QTableWidgetItem *item)
# self.itemClicked(QTableWidgetItem *item)
# self.itemDoubleClicked(QTableWidgetItem *item)
# self.itemEntered(QTableWidgetItem *item)
# self.itemPressed(QTableWidgetItem *item)
# self.itemSelectionChanged()
pass
def viewFullAreaSize(self) -> (int, int):
return self.width(), len(self._tableData)
def viewDisplayedSize(self) -> (int, int):
return self.size()
def items(self): return self._tableData
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):
@ -89,105 +148,50 @@ class _______TTkTable(TTkWidget):
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-1:
self._moveTo = len(self._tableData)-h-1
if self._moveTo < 0:
self._moveTo = 0
self._tuneTheScroller()
def _tuneTheScroller(self):
if self._vscroller is None: return
scrollTo = len(self._tableData) - self.height()
self._vscroller.setRange(0, scrollTo)
self._vscroller.pagestep = self.height()
self.viewChanged.emit()
self.update()
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
_,y = evt.x, evt.y
_, oy = self.getViewOffsets()
if y >= 0:
selected = oy + y
if selected >= len(self._tableData):
selected = -1
self._selected = selected
self.update()
self.activated.emit(self._selected)
return True
def wheelEvent(self, evt):
# delta = self.height()
delta = 5
if evt.evt == TTkK.WHEEL_Up:
delta = -delta
# self.scrollTo(self._moveTo + delta)
self._vscroller.value = self._moveTo + delta
return True
@pyTTkSlot(int)
def scrollTo(self, to):
max = len(self._tableData) - self.height()
if to>max: to=max
if to<0: to=0
self._moveTo = to
self.update()
def paintEvent(self):
w,h = self.size()
_, oy = self.getViewOffsets()
total = 0
variableCols = 0
slicesize = 0
# Retrieve the free size
for width in self._columns:
if width > 0:
total += width
else:
variableCols += 1
if variableCols > 0:
slicesize = int((w-total)/variableCols)
# TTkLog.debug(f"ss:{slicesize}, w:{w}")
# Define the list of cols sizes
sizes = []
for width in self._columns:
if width > 0:
sizes.append(width)
else:
sizes.append((w-total)//variableCols)
variableCols -= 1
maxItems = len(self._tableData)
itemFrom = self._moveTo -1
itemFrom = oy
if itemFrom > maxItems-h: itemFrom = maxItems-h
if itemFrom < 0 : itemFrom = 0
itemTo = itemFrom + h
if itemTo > maxItems: itemTo = maxItems
# 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:
_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
y = 0
for it in range(itemFrom, itemTo):
item = self._tableData[it]
if self._selected > 0:
@ -197,12 +201,56 @@ class _______TTkTable(TTkWidget):
if val < 0 : val = 0
if val > h : val = h
if it == self._selected:
_lineDraw(y,val,item,self._selectColor)
colors = [self._selectColor]*len(self._columnColors)
self._canvas.drawTableLine(pos=(0,y), items=item, sizes=sizes, colors=colors, alignments=self._alignments)
else:
_lineDraw(y,val,item)
colors = [c.modParam(val=-val) for c in self._columnColors]
self._canvas.drawTableLine(pos=(0,y), items=item, sizes=sizes, colors=colors, alignments=self._alignments)
y+=1
class TTkTableView(TTkAbstractScrollView):
__slots__ = ( '_header', '_tableView', '_showHeader', 'activated')
def __init__(self, *args, **kwargs):
TTkAbstractScrollView.__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkTableView' )
if 'parent' in kwargs: kwargs.pop('parent')
self._showHeader = kwargs.get('showHeader', True)
self.setLayout(TTkGridLayout())
self._tableView = _TTkTableView(*args, **kwargs)
self._header = _TTkTableViewHeader(*args, **kwargs)
self.layout().addWidget(self._header,0,0)
self.layout().addWidget(self._tableView,1,0)
# Forward the tableSignals
self.viewMovedTo = self._tableView.viewMovedTo
self.viewSizeChanged = self._tableView.viewSizeChanged
self.activated = self._tableView.activated
self.viewChanged = self._tableView.viewChanged
if not self._showHeader:
self._header.hide()
@pyTTkSlot(int, int)
def viewMoveTo(self, x, y):
self._tableView.viewMoveTo(x, y)
def getViewOffsets(self):
return self._tableView.getViewOffsets()
def viewFullAreaSize(self) -> (int, int):
return self._tableView.viewFullAreaSize()
def viewDisplayedSize(self) -> (int, int):
return self._tableView.viewDisplayedSize()
def setAlignment(self, *args, **kwargs) :
self._tableView.setAlignment(*args, **kwargs)
self._header.setAlignment(*args, **kwargs)
def setHeader(self, *args, **kwargs) :
self._header.setHeader(*args, **kwargs)
def setColumnSize(self, *args, **kwargs) :
self._tableView.setColumnSize(*args, **kwargs)
self._header.setColumnSize(*args, **kwargs)
def setColumnColors(self, *args, **kwargs):
self._tableView.setColumnColors(*args, **kwargs)
def appendItem(self, *args, **kwargs) :
self._tableView.appendItem(*args, **kwargs)

52
TermTk/TTkWidgets/texedit.py

@ -27,56 +27,44 @@ from TermTk.TTkCore.log import TTkLog
from TermTk.TTkWidgets.widget import *
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkWidgets.scrollbar import TTkScrollBar
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
class _TTkTextEditView(TTkWidget):
__slots__ = ('_lines','_moveTo')
class _TTkTextEditView(TTkAbstractScrollView):
__slots__ = ('_lines')
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
super().__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , '_TTkTextEditView' )
self._lines = []
self._moveTo = 0
@pyTTkSlot(str)
def setText(self, text):
self._lines = text.split('\n')
self.update()
def viewFullAreaSize(self) -> (int, int):
return self.width(), len(self._lines)
def viewDisplayedSize(self) -> (int, int):
return self.size()
def paintEvent(self):
_, oy = self.getViewOffsets()
y = 0
for t in self._lines[self._moveTo:]:
for t in self._lines[oy:]:
self._canvas.drawText(pos=(0,y), text=t)
y+=1
def wheelEvent(self, evt):
delta = TTkCfg.scrollDelta
if evt.evt == TTkK.WHEEL_Up:
delta = -delta
self.scrollTo(self._moveTo + delta)
self.update()
return True
@pyTTkSlot(int)
def scrollTo(self, to):
# TTkLog.debug(f"to:{to},h{self._height},size:{len(self._tableData)}")
max = len(self._lines) - self.height()
if to>max: to=max
if to<0: to=0
self._moveTo = to
self.update()
class TTkTextEdit(TTkWidget):
__slots__ = ('_textEdit', '_vscroller', '_hscroller')
class TTkTextEdit(TTkAbstractScrollArea):
__slots__ = ('_textEditView')
def __init__(self, *args, **kwargs):
TTkWidget.__init__(self, *args, **kwargs)
super().__init__(self, *args, **kwargs)
self._name = kwargs.get('name' , 'TTkTextEdit' )
self._textEdit = _TTkTextEditView()
self._vscroller = TTkScrollBar(orientation=TTkK.VERTICAL)
self._hscroller = TTkScrollBar(orientation=TTkK.HORIZONTAL)
self.setLayout(TTkGridLayout())
self.layout().addWidget(self._textEdit,0,0)
self.layout().addWidget(self._vscroller,0,1)
self._textEditView = _TTkTextEditView()
self.setViewport(self._textEditView)
@pyTTkSlot(str)
def setText(self, text):
self._textEdit.setText(text)
self._textEditView.setText(text)

22
TermTk/TTkWidgets/widget.py

@ -149,7 +149,7 @@ class TTkWidget:
self.resize(w, h)
self.move(x, y)
def getPadding(self):
def getPadding(self) -> (int, int, int, int) :
return self._padt, self._padb, self._padl, self._padr
def setPadding(self, top, bottom, left, right):
@ -161,16 +161,16 @@ class TTkWidget:
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
def mouseDoubleClickEvent(self, evt) -> bool : return False
def mouseMoveEvent(self, evt) -> bool : return False
def mouseDragEvent(self, evt) -> bool : return False
def mousePressEvent(self, evt) -> bool : return False
def mouseReleaseEvent(self, evt) -> bool : return False
def wheelEvent(self, evt) -> bool : return False
def enterEvent(self, evt) -> bool : return False
def leaveEvent(self, evt) -> bool : return False
def keyPressEvent(self, evt) -> bool : return False
def keyReleaseEvent(self, evt) -> bool : return False
@staticmethod
def _mouseEventLayoutHandle(evt, layout):

1
TermTk/__init__.py

@ -3,3 +3,4 @@ from .TTkGui import *
from .TTkLayouts import *
from .TTkWidgets import *
from .TTkTestWidgets import *
from .TTkAbstract import *

1
docs/BUGS.md

@ -6,3 +6,4 @@
- [Minor] Window does not reshape to the max/min layout during initialization
- [Minor] test.ui.009.py - Starting layout size is wrong
- [Major] ~~[Canvas Paint] The Top Left corner start with the bottom right corner color~~
- [Minor] DrawText, handle "tabs"

5
docs/TODO.md

@ -49,6 +49,11 @@
- [ ] Add addLayout method - Nested layouts
- [x] Add Grid Layout
### AbstractScrollArea
- [ ] Implement something that mimic the QAbstactScrollArea
https://doc.qt.io/qt-5/qabstractscrollarea.html
https://doc.qt.io/qt-5/qscrollarea.html
### Overlay widget
- [ ] Rewrite the Handling (ttk.py)
It would be nice to have it as child outside the layour

Loading…
Cancel
Save