Skip to content

Commit

Permalink
Scrolled stack (#49)
Browse files Browse the repository at this point in the history
* Initial implementation of ScrolledFrame

* Fixes to ScrolledFrame
  • Loading branch information
RhetTbull authored Nov 13, 2023
1 parent 759510c commit 1494092
Show file tree
Hide file tree
Showing 5 changed files with 514 additions and 11 deletions.
45 changes: 45 additions & 0 deletions examples/scrolled_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Demo grid container with scrollbars"""

from guitk import *


class Grid(Window):
def config(self):
self.title = "Grid Demo"
with VLayout():
with HGrid(
4,
vspacing=0,
hspacing=(0, 20),
vscrollbar=True,
autohide_scrollbars=True,
) as self.vgrid:
for i in range(25):
Button(f"HGrid {i}")
HSeparator()
with HStack(expand=False):
Button("Add")
Button("Remove")
HSeparator()
Label("", key="status")

@on("Add")
def on_add(self):
"""Add a widget"""
button_count = len(self.vgrid)
self.vgrid.append(Button(f"HGrid {button_count}"))

@on("Remove")
def on_remove(self):
"""Remove a widget"""
if len(self.vgrid):
self.vgrid.pop()

@on(event_type=EventType.ButtonPress)
def on_button_press(self, event):
"""Update status label"""
self.get("status").value = f"Button {event.widget.value} pressed"


if __name__ == "__main__":
Grid().run()
8 changes: 7 additions & 1 deletion guitk/_debug.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Debug utilities"""
"""Debug utilities; set GUITK_DEBUG=1 to enable debugging or use set_debug()"""

from __future__ import annotations

import datetime
import inspect
import os
import sys
import time
from functools import wraps
Expand Down Expand Up @@ -82,3 +83,8 @@ def wrapper(*args, **kwargs):
return rv

return wrapper


if os.getenv("GUITK_DEBUG") == "1":
set_debug(True)
debug("debugging enabled")
43 changes: 41 additions & 2 deletions guitk/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def __init__(
distribute: bool = False,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
):
"""Base container container that stacks widgets when added to a Layout.
Expand All @@ -57,6 +60,7 @@ def __init__(
distribute (bool, optional): Whether the Stack should distribute widgets evenly.
vspacing (PadType, optional): Vertical spacing between widgets. Defaults to None.
hspacing (PadType, optional): Horizontal spacing between widgets. Defaults to None.
vscrollbar (bool): Whether to include a vertical scrollbar. Defaults to False.
Note:
If width or height is specified, the Stack will not expand to fill the available space and the
Expand Down Expand Up @@ -84,6 +88,9 @@ def __init__(
halign=halign,
vspacing=vspacing,
hspacing=hspacing,
vscrollbar=vscrollbar,
# hscrollbar=hscrollbar,
autohide_scrollbars=autohide_scrollbars,
)
self.expand = expand if (width is None or height is None) else False
self.distribute = distribute
Expand Down Expand Up @@ -179,7 +186,6 @@ def pop(self, index: int = -1):
widget = self._layout_list.pop(index)
widget.widget.grid_forget()
self.redraw()
print(f"popped {widget.key} {widget.widget}")
return widget

@debug_watch
Expand Down Expand Up @@ -263,6 +269,7 @@ def __init__(
self,
key: Hashable | None = None,
width: int | None = None,
# height: int | None = None,
padding: PaddingType | None = None,
disabled: bool | None = False,
sticky: str | None = "nsew",
Expand All @@ -272,6 +279,9 @@ def __init__(
distribute: bool = False,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
):
"""Base container container that stacks widgets vertically when added to a Layout
Expand All @@ -290,15 +300,17 @@ def __init__(
distribute (bool, optional): Whether the VStack should distribute widgets evenly.
vspacing (PadType, optional): Vertical spacing between widgets. Defaults to None.
hspacing (PadType, optional): Horizontal spacing between widgets. Defaults to None.
vscrollbar (bool): Whether to include a vertical scrollbar. Defaults to False.
autohide_scrollbars (bool): Whether to hide scrollbars when not needed. Defaults to True.
Note:
If width is specified, the VStack will not expand to fill the available space and the
expand parameter will be ignored.
"""
super().__init__(
key=key,
height=None,
width=width,
height=None,
padding=padding,
disabled=disabled,
sticky=sticky,
Expand All @@ -308,6 +320,9 @@ def __init__(
distribute=distribute,
vspacing=vspacing,
hspacing=hspacing,
vscrollbar=vscrollbar,
# hscrollbar=hscrollbar,
autohide_scrollbars=autohide_scrollbars,
)
self.expand = expand if width is None else False

Expand All @@ -328,6 +343,9 @@ def __init__(
distribute: bool = False,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
):
"""A container that stacks widgets horizontally when added to a Layout
Expand All @@ -346,6 +364,8 @@ def __init__(
distribute (bool, optional): Whether the HStack should distribute widgets evenly.
vspacing (PadType, optional): Vertical spacing between widgets. Defaults to None.
hspacing (PadType, optional): Horizontal spacing between widgets. Defaults to None.
vscrollbar (bool): Whether to include a vertical scrollbar. Defaults to False.
autohide_scrollbars (bool): Whether to hide scrollbars when not needed. Defaults to True.
Note:
If height is specified, the HStack will not expand to fill the available space and the
Expand All @@ -364,6 +384,9 @@ def __init__(
distribute=distribute,
vspacing=vspacing,
hspacing=hspacing,
vscrollbar=vscrollbar,
# hscrollbar=hscrollbar,
autohide_scrollbars=autohide_scrollbars,
)
self.expand = expand if height is None else False

Expand Down Expand Up @@ -421,6 +444,9 @@ def __init__(
expand: bool = True,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
):
"""Container that stacks widgets in a vertical grid when added to a Layout
Expand All @@ -440,6 +466,8 @@ def __init__(
Defaults to True.
vspacing (PadType, optional): Vertical spacing between widgets. Defaults to None.
hspacing (PadType, optional): Horizontal spacing between widgets. Defaults to None.
vscrollbar (bool): Whether to include a vertical scrollbar. Defaults to False.
autohide_scrollbars (bool): Whether to hide scrollbars when not needed. Defaults to True.
Note:
If width is specified, the VStack will not expand to fill the available space and the
Expand All @@ -458,6 +486,9 @@ def __init__(
distribute=False,
vspacing=vspacing,
hspacing=hspacing,
vscrollbar=vscrollbar,
# hscrollbar=hscrollbar,
autohide_scrollbars=autohide_scrollbars,
)
self.expand = expand if width is None else False
self.rows = rows
Expand Down Expand Up @@ -524,6 +555,9 @@ def __init__(
expand: bool = True,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
):
"""Container that stacks widgets in a horizontal grid when added to a Layout
Expand All @@ -543,6 +577,8 @@ def __init__(
Defaults to True.
vspacing (PadType, optional): Vertical spacing between widgets. Defaults to None.
hspacing (PadType, optional): Horizontal spacing between widgets. Defaults to None.
vscrollbar (bool): Whether to include a vertical scrollbar. Defaults to False.
autohide_scrollbars (bool): Whether to hide scrollbars when not needed. Defaults to True.
Note:
If width is specified, the VStack will not expand to fill the available space and the
Expand All @@ -561,6 +597,9 @@ def __init__(
distribute=False,
vspacing=vspacing,
hspacing=hspacing,
vscrollbar=vscrollbar,
# hscrollbar=hscrollbar,
autohide_scrollbars=autohide_scrollbars,
)
self.expand = expand if width is None else False
self.cols = cols
Expand Down
37 changes: 29 additions & 8 deletions guitk/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from ._debug import debug, debug_borderwidth, debug_relief, debug_watch
from .basewidget import BaseWidget
from .layout import HLayout, VLayout, pop_parent, push_parent
from .scrolledframe import ScrolledFrame
from .spacer import HSpacer, VSpacer
from .tooltips import Hovertip
from .ttk_label import Label
Expand Down Expand Up @@ -320,6 +321,9 @@ def __init__(
halign: HAlign | None = None,
vspacing: PadType | None = None,
hspacing: PadType | None = None,
vscrollbar: bool = False,
# hscrollbar: bool = False,
autohide_scrollbars: bool = True,
**kwargs,
):
# padx and pady passed to Widget not Frame
Expand Down Expand Up @@ -366,6 +370,9 @@ def __init__(
self.halign = halign.lower() if halign else None
self.vspacing = vspacing
self.hspacing = hspacing
self.vscrollbar = vscrollbar
# self.hscrollbar = hscrollbar
self.autohide = autohide_scrollbars

def remove(self, key_or_widget: Hashable | BaseWidget):
""" "Remove widget from layout and destroy it.
Expand Down Expand Up @@ -397,14 +404,28 @@ def _create_widget(self, parent, window: Window, row, col):
kwargs["style"] = self._style

if self.frametype == GUITK.ELEMENT_FRAME:
self.widget = ttk.Frame(
parent,
width=self.width,
height=self.height,
borderwidth=self.borderwidth,
relief=self.relief,
**kwargs,
)
# if self.vscrollbar or self.hscrollbar:
if self.vscrollbar:
self.widget = ScrolledFrame(
parent,
vscrollbar=self.vscrollbar,
# hscrollbar=self.hscrollbar,
autohide=self.autohide,
width=self.width,
height=self.height,
borderwidth=self.borderwidth,
relief=self.relief,
**kwargs,
)
else:
self.widget = ttk.Frame(
parent,
width=self.width,
height=self.height,
borderwidth=self.borderwidth,
relief=self.relief,
**kwargs,
)
elif self.frametype == GUITK.ELEMENT_TK_FRAME:
self.widget = tk.Frame(
parent,
Expand Down
Loading

0 comments on commit 1494092

Please sign in to comment.