# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""A few useful widgets."""

# XXX To do: documentation; generalization

import tkinter as Tkinter
from tkinter import X, Y, BOTH, LEFT, RIGHT, TOP, BOTTOM, END, N, S, W, E
from tkinter import FLAT, GROOVE, RAISED, RIDGE, SOLID, SUNKEN
from tkinter import DISABLED, NORMAL, ACTIVE, EXTENDED

class StructuredWidget(object):

    def __init__(self, master):
        self.master = master
        self.frame = Tkinter.Frame(master)
        self.create_structure()

    def create_structure(self):
        self.create_widget()

    def create_widget(self):
        # Abstract method
        raise NotImplementedError

class ScrolledWidget(StructuredWidget):

    def create_structure(self):
        self.vbar = Tkinter.Scrollbar(self.frame, takefocus=False)
        self.vbar.pack(side=RIGHT, fill=BOTH, expand=False)
        self.create_widget()
        self.widget.pack(fill=BOTH, expand=True)
        self.widget.config(yscrollcommand=self.vbar.set)
        self.vbar.config(command=self.widget.yview)

class ScrolledCanvas(ScrolledWidget):

    def create_widget(self):
        self.widget = Tkinter.Canvas(self.frame, relief=SUNKEN, borderwidth=2)

class ScrolledText(ScrolledWidget):

    def create_widget(self):
        self.widget = Tkinter.Text(self.frame, state=DISABLED, takefocus=False,
                                   wrap="word", height=9)

    def reset(self, text):
        self.widget.config(state=NORMAL)
        self.widget.delete("1.0", END)
        self.widget.insert(END, text)
        self.widget.config(state=DISABLED)

class ScrolledList(ScrolledWidget):

    def create_widget(self):
        self.widget = Tkinter.Listbox(self.frame)
        self.widget.bind("<1>", self.on_click)

    def reset(self, values, objects):
        self.widget.delete(0, END)
        self.widget.insert(END, *values)
        self.objects = objects

    def selection(self):
        return [self.objects[int(i)]
                for i in self.widget.curselection()
                if self.objects[int(i)] is not None]

    def select(self, target):
        for i, obj in enumerate(self.objects):
            if obj is target:
                self.widget.selection_set(i)
                self.widget.activate(i)
                self.widget.see(i)
                self.widget.focus_set()
                break

    def on_click(self, event=None):
        self.widget.focus_set()

class LabeledScrolledWidget(ScrolledWidget):

    def __init__(self, master, labeltext):
        ScrolledWidget.__init__(self, master)
        self.label.config(text=labeltext)

    def create_structure(self):
        self.label = Tkinter.Label(self.frame, anchor=W)
        self.label.pack(side=TOP, fill=BOTH, expand=False)
        ScrolledWidget.create_structure(self)

class LabeledScrolledText(LabeledScrolledWidget, ScrolledText):
    pass

class LabeledScrolledList(LabeledScrolledWidget, ScrolledList):
    pass

class LabeledScrolledCanvas(LabeledScrolledWidget, ScrolledCanvas):
    pass
