Skip to content

Commit

Permalink
UI: improve tab options displaying used environment variables and usi…
Browse files Browse the repository at this point in the history
…ng collapsible frames (#330)
  • Loading branch information
Guts authored Jul 23, 2024
2 parents d982f06 + f6dbe16 commit 6bc0a3f
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 36 deletions.
117 changes: 117 additions & 0 deletions dicogis/ui/collapsible_frame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#! python3 # noqa: E265


"""
Name: Custom collapsible frame
Purpose: Allow toggle a frame in pure Python Tkinter.
Author: Julien Moura (@geojulien)
Sources:
- ttkwidgets (GPL 3)
- Onlyjus (https://stackoverflow.com/a/13169685/2556577)
"""

# ##############################################################################
# ########## Libraries #############
# ##################################

# Standard library
import logging
from tkinter import BooleanVar
from tkinter.ttk import Button, Frame, Label, Widget

# ##############################################################################
# ############ Globals ############
# #################################

logger = logging.getLogger(__name__)


# ##############################################################################
# ########## Classes ###############
# ##################################


class ToggledFrame(Frame):
"""A frame that can be toggled to open and close."""

def __init__(
self,
parent: Widget = None,
in_text: str = "",
toggle_width: int = 2,
start_opened: bool = True,
**kwargs,
):
"""Initializes UI tab for end-user options.
Args:
parent: tkinter parent object
in_text: text to display next to the toggle arrow. Defaults to empty string.
toggle_width: width of the tgogle button(in characters). Defaults to 2.
kwargs: keyword arguments passed on to the :class:`ttk.Frame` initializer
"""
super().__init__(parent, **kwargs)

# variables
self.is_open_var = BooleanVar(value=start_opened)

# frame containing tool button and label
self.title_frame = Frame(self)
self.lbl_frame = Label(self.title_frame, text=in_text)
self.btn_toggle = Button(
self.title_frame,
command=self.toggle,
style="Toolbutton",
text="-" if start_opened is True else "+",
width=toggle_width,
)

self.sub_frame = Frame(self)

self._grid_widgets()
self.toggle()

def _grid_widgets(self):
"""Grid frame widgets."""
self.title_frame.grid(sticky="WE")
self.title_frame.grid_columnconfigure(0, weight=1)
self.lbl_frame.grid(row=0, column=0, sticky="W", padx=15)
self.btn_toggle.grid(row=0, column=1, sticky="E")

def toggle(self):
"""Toggle opened or closed."""
if self.is_open_var.get():
self._open = False
self.sub_frame.grid(row=1, sticky="nswe")
self.btn_toggle.configure(text="-")
else:
self._open = True
self.sub_frame.grid_forget()

self.btn_toggle.configure(text="+")

self.is_open_var.set(not self.is_open_var.get())


if __name__ == "__main__":
from tkinter import Tk
from tkinter.ttk import Button

root = Tk()

collapsible_frame = ToggledFrame(
parent=root,
in_text="Rotate",
start_opened=True,
borderwidth=2,
relief="raised",
)
collapsible_frame.pack()
button = Button(
collapsible_frame.sub_frame, text="Close window", command=root.destroy
)
button.grid()
collapsible_frame.toggle()
root.mainloop()
25 changes: 16 additions & 9 deletions dicogis/ui/main_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,20 +171,27 @@ def __init__(self, theme: str = "radiance"):
self.global_ignored = 0 # files ignored by an user filter
self.global_dico_fields = {}

# fillfulling text
self.localized_strings = self.txt_manager.load_texts(
language_code=self.def_lang
)

# Notebook
self.nb = Notebook(self)
# tabs
self.tab_files = TabFiles(self.nb, self.localized_strings) # tab_id = 0
self.tab_sgbd = TabDatabaseServer(self.nb) # tab_id = 1
self.tab_files = TabFiles(
parent=self.nb, localized_strings=self.localized_strings
) # tab_id = 0
self.tab_sgbd = TabDatabaseServer(
parent=self.nb, localized_strings=self.localized_strings, init_widgets=True
) # tab_id = 1
self.tab_options = TabSettings(
self.nb, self.localized_strings, utils_global.ui_switch
parent=self.nb,
localized_strings=self.localized_strings,
init_widgets=True,
switcher=utils_global.ui_switch,
) # tab_id = 2
self.tab_credits = TabCredits(self.nb) # tab_id = 3

# fillfulling text
self.localized_strings = self.txt_manager.load_texts(
language_code=self.def_lang
)
self.tab_credits = TabCredits(parent=self.nb) # tab_id = 3

# =================================================================================
# ## TAB 1: FILES ##
Expand Down
81 changes: 81 additions & 0 deletions dicogis/ui/scrollable_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from tkinter import Event
from tkinter.ttk import Frame, Scrollbar, Treeview, Widget

from dicogis.utils.texts import TextsManager


class ScrollableTable(Frame):
"""
A scrollable table with two columns in read-only mode.
Attributes:
tree (ttk.Treeview): The Treeview widget for displaying the table.
vsb (ttk.Scrollbar): The vertical scrollbar for the Treeview.
"""

def __init__(
self,
parent: Widget,
localized_strings: dict | None = None,
init_widgets: bool = True,
):
"""Initialize the ScrollableTable frame.
Args:
parent (tk.Widget): The parent widget.
init_widgets: option to create widgets during init or not. Defaults to True.
"""
super().__init__(parent)

# handle empty localized strings
self.localized_strings = localized_strings
if self.localized_strings is None:
self.localized_strings = TextsManager().load_texts()

if init_widgets:
self.create_widgets()

def create_widgets(self) -> None:
"""Create and layout the widgets for the frame."""
# Create Treeview with 2 columns
self.tree = Treeview(
self,
columns=("column1", "column2"),
show="headings",
height=3,
selectmode="browse",
)
self.tree.heading("column1", text=self.localized_strings.get("key", "Key"))
self.tree.heading("column2", text=self.localized_strings.get("value", "Value"))

# Make the columns read-only
# self.tree.bind("<1>", self.disable_event)

# Add a vertical scrollbar
self.vsb = Scrollbar(
self,
orient="vertical",
name="env_var_table_vert_scroll",
command=self.tree.yview,
)
self.tree.configure(yscrollcommand=self.vsb.set)

# Layout the Treeview and Scrollbar
self.tree.grid(row=0, column=0, sticky="NSEW")
self.vsb.grid(row=0, column=1, sticky="NS")

# Make the frame expandable
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)

def disable_event(self, event: Event) -> str:
"""
Disable the event to make the Treeview read-only.
Args:
event (Event): The event object.
Returns:
str: "break" to indicate that the event should be ignored.
"""
return "break"
Loading

0 comments on commit 6bc0a3f

Please sign in to comment.