2323__all__ = ['TTkAbstractScrollArea' ]
2424
2525from dataclasses import dataclass
26- from typing import List ,Any ,Type
26+ from typing import List ,Any ,Type , Optional
2727
2828from TermTk .TTkCore .constant import TTkK
2929# from TermTk.TTkCore.log import TTkLog
3030from TermTk .TTkCore .signal import pyTTkSlot
3131from TermTk .TTkWidgets .widget import TTkWidget
3232from TermTk .TTkWidgets .container import TTkContainer
3333from TermTk .TTkWidgets .scrollbar import TTkScrollBar
34+ from TermTk .TTkLayouts .layout import TTkLayout
3435from TermTk .TTkLayouts .gridlayout import TTkGridLayout
3536from TermTk .TTkAbstract .abstractscrollview import TTkAbstractScrollViewInterface
3637
@@ -42,12 +43,25 @@ class _ForwardData():
4243 methods : List [str ]
4344
4445class TTkAbstractScrollArea (TTkContainer ):
46+ '''
47+ The :py:class:`TTkAbstractScrollArea` provides a scrolling area with on-demand scroll bars.
48+
49+ This abstract class manages vertical and horizontal scroll bars that appear automatically
50+ based on the viewport size and content.
51+ '''
4552 __slots__ = (
4653 '_processing' , # this flag is required to avoid unnecessary loop on edge cases
4754 '_viewport' ,
4855 '_verticalScrollBar' , '_verticalScrollBarPolicy' ,
4956 '_horizontalScrollBar' , '_horizontalScrollBarPolicy' ,)
5057
58+ _processing :bool
59+ _viewport :Optional [TTkAbstractScrollViewInterface ]
60+ _verticalScrollBar :TTkScrollBar
61+ _horizontalScrollBar :TTkScrollBar
62+ _verticalScrollBarPolicy :TTkK .ScrollBarPolicy
63+ _horizontalScrollBarPolicy :TTkK .ScrollBarPolicy
64+
5165 def __init__ (self , * ,
5266 verticalScrollBarPolicy :TTkK .ScrollBarPolicy = TTkK .ScrollBarPolicy .ScrollBarAsNeeded ,
5367 horizontalScrollBarPolicy :TTkK .ScrollBarPolicy = TTkK .ScrollBarPolicy .ScrollBarAsNeeded ,
@@ -63,8 +77,10 @@ def __init__(self, *,
6377 self .layout ().addWidget (self ._verticalScrollBar )
6478 self .layout ().addWidget (self ._horizontalScrollBar )
6579
66- def _resizeEvent (self ):
67- if self ._processing : return
80+ def _resizeEvent (self ) -> None :
81+ ''' Internal method to handle resize events and reposition scroll bars '''
82+ if self ._processing :
83+ return
6884 self ._processing = True
6985 w ,h = self .size ()
7086 vert = 1 if self ._verticalScrollBar .isVisible () else 0
@@ -73,16 +89,24 @@ def _resizeEvent(self):
7389 self ._verticalScrollBar .setGeometry (w - 1 ,0 ,1 ,h - hori )
7490 if hori :
7591 self ._horizontalScrollBar .setGeometry (0 ,h - 1 ,w - vert ,1 )
76- if self ._viewport :
92+ if isinstance ( self ._viewport , ( TTkWidget , TTkLayout )) :
7793 self ._viewport .setGeometry (0 ,0 ,w - vert ,h - hori )
7894 self ._processing = False
7995
80- def resizeEvent (self , w : int , h : int ):
96+ def resizeEvent (self , w : int , h : int ) -> None :
97+ ''' Handle resize events
98+
99+ :param w: the new width
100+ :type w: int
101+ :param h: the new height
102+ :type h: int
103+ '''
81104 self ._resizeEvent ()
82105
83106 @pyTTkSlot ()
84- def _viewportChanged (self ):
85- if not self .isVisible (): return
107+ def _viewportChanged (self ) -> None :
108+ ''' Internal slot to handle viewport changes and update scroll bar ranges and visibility '''
109+ if not self ._viewport or not self .isVisible (): return
86110 w ,h = self .size ()
87111 fw , fh = self ._viewport .viewFullAreaSize ()
88112 dw , dh = self ._viewport .viewDisplayedSize ()
@@ -125,16 +149,37 @@ def _viewportChanged(self):
125149 self ._resizeEvent ()
126150
127151 @pyTTkSlot (int )
128- def _vscrollMoved (self , val ):
152+ def _vscrollMoved (self , val : int ) -> None :
153+ ''' Internal slot to handle vertical scroll bar movement
154+
155+ :param val: the new vertical scroll position
156+ :type val: int
157+ '''
158+ if not self ._viewport :
159+ return
129160 ox , _ = self ._viewport .getViewOffsets ()
130161 self ._viewport .viewMoveTo (ox , val )
131162
132163 @pyTTkSlot (int )
133- def _hscrollMoved (self , val ):
164+ def _hscrollMoved (self , val : int ) -> None :
165+ ''' Internal slot to handle horizontal scroll bar movement
166+
167+ :param val: the new horizontal scroll position
168+ :type val: int
169+ '''
170+ if not self ._viewport :
171+ return
134172 _ , oy = self ._viewport .getViewOffsets ()
135173 self ._viewport .viewMoveTo (val , oy )
136174
137- def setViewport (self , viewport ):
175+ def setViewport (self , viewport : TTkAbstractScrollViewInterface ) -> None :
176+ ''' Set the viewport widget
177+
178+ :param viewport: the viewport widget implementing TTkAbstractScrollViewInterface
179+ :type viewport: :py:class:`TTkAbstractScrollViewInterface`
180+
181+ :raises TypeError: if viewport does not implement TTkAbstractScrollViewInterface
182+ '''
138183 if not isinstance (viewport , TTkAbstractScrollViewInterface ):
139184 raise TypeError ("TTkAbstractScrollViewInterface is required in TTkAbstractScrollArea.setVewport(viewport)" )
140185 if self ._viewport :
@@ -157,20 +202,44 @@ def setViewport(self, viewport):
157202 self .layout ().addItem (viewport )
158203 self ._resizeEvent ()
159204
160- def setVerticalScrollBarPolicy (self , policy ):
205+ def setVerticalScrollBarPolicy (self , policy : TTkK .ScrollBarPolicy ) -> None :
206+ ''' Set the vertical scroll bar policy
207+
208+ :param policy: the scroll bar policy (ScrollBarAsNeeded, ScrollBarAlwaysOn, ScrollBarAlwaysOff)
209+ :type policy: :py:class:`TTkK.ScrollBarPolicy`
210+ '''
161211 if policy != self ._verticalScrollBarPolicy :
162212 self ._verticalScrollBarPolicy = policy
163213 self ._viewportChanged ()
164214
165- def setHorizontalScrollBarPolicy (self , policy ):
215+ def setHorizontalScrollBarPolicy (self , policy : TTkK .ScrollBarPolicy ) -> None :
216+ ''' Set the horizontal scroll bar policy
217+
218+ :param policy: the scroll bar policy (ScrollBarAsNeeded, ScrollBarAlwaysOn, ScrollBarAlwaysOff)
219+ :type policy: :py:class:`TTkK.ScrollBarPolicy`
220+ '''
166221 if policy != self ._horizontalScrollBarPolicy :
167222 self ._horizontalScrollBarPolicy = policy
168223 self ._viewportChanged ()
169224
170- def viewport (self ) -> TTkAbstractScrollViewInterface :
225+ def viewport (self ) -> Optional [TTkAbstractScrollViewInterface ]:
226+ ''' Return the current viewport
227+
228+ :return: the viewport widget or None
229+ :rtype: :py:class:`TTkAbstractScrollViewInterface`, optional
230+ '''
171231 return self ._viewport
172232
173- def update (self , repaint = True , updateLayout = False , updateParent = False ):
174- if self ._viewport :
233+ def update (self , repaint : bool = True , updateLayout : bool = False , updateParent : bool = False ) -> None :
234+ ''' Update the scroll area and viewport
235+
236+ :param repaint: trigger a repaint, defaults to True
237+ :type repaint: bool, optional
238+ :param updateLayout: trigger a layout update, defaults to False
239+ :type updateLayout: bool, optional
240+ :param updateParent: trigger a parent update, defaults to False
241+ :type updateParent: bool, optional
242+ '''
243+ if isinstance (self ._viewport , (TTkWidget , TTkLayout )):
175244 self ._viewport .update (repaint , updateLayout , updateParent = False )
176245 return super ().update (repaint , updateLayout , updateParent )
0 commit comments