#! /usr/bin/env python3
#  -*- coding: utf-8 -*-
# ======================================================
#     PAGE80Demo_support.py
#  ------------------------------------------------------
# Created for PAGE and PAGE users.
# Written by G.D. Walters
# Copyright © 2023, 2025 by G.D. Walters
# This source code is released under the MIT License (see license.txt)
# ======================================================
# Credit for the 'cubby owl' graphic goes to 'bocian' on
#   openclipart.org.  It was uploaded on March 17, 2012
#   https://openclipart.org/detail/168873/owl-with-ebook-reader
# ======================================================
# Still to do (12/23/2023)
# ------------------------------------------------------
# P - Animate routine - needs code cleanup
# * - Code cleanup and documentation
# ======================================================
# Support module generated by PAGE version 8.0Q
#  in conjunction with Tcl version 8.6
#    Dec 23, 2023 03:24:05 PM CST  platform: Linux
#    Dec 23, 2023 06:10:42 PM CST  platform: Linux
#    Dec 23, 2023 07:23:33 PM CST  platform: Linux

import sys
import os.path
import platform
import glob

# =================================
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *

# ===========================================
#       Additional tkinter imports
# ===========================================
from tkinter import font
import tkinter.messagebox as messagebox
from tkinter import simpledialog
from tkinter import colorchooser
from tkinter.filedialog import (
    askdirectory,
    askopenfilename,
    asksaveasfile,
    asksaveasfilename,
)
from tkinter.simpledialog import askfloat, askinteger, askstring

import PAGE80Demo

# ======================================================
_debug = False  # False to eliminate debug printing from callback functions.
_debug2 = False  # Theme related debugging
_debug3 = False  # Listbox related debugging
# -----------------------------------
location = PAGE80Demo._location
programName = "PAGE 8.0Q Demo"
version = "0.1.1"


# ===================================
def main(*args):
    """Main entry point for the application."""
    global root
    root = tk.Tk()
    root.protocol("WM_DELETE_WINDOW", root.destroy)
    # Creates a toplevel widget.
    global _top1, _w1
    _top1 = root
    _w1 = PAGE80Demo.Toplevel1(_top1)
    startup()
    root.mainloop()


def startup():
    global originalBackground, originalForeground, speed
    sty = ttk.Style()
    defaultTheme = sty.theme_use()
    originalBackground = sty.lookup(".", "background")
    originalForeground = sty.lookup(".", "foreground")
    setup_treeview(_w1.Scrolledtreeview1)
    load_scrolledtext()
    setup_listbox()
    themelist = load_tcl_themes(location, _debug2)
    setup_combobox(themelist)
    _w1.TComboThemes.set(defaultTheme)
    setup_Progressbars()
    setup_spinbox()
    _w1.TNotebook1.tab(0, text="Treeview")
    _w1.TNotebook1.tab(1, text="General")
    _w1.TNotebook1.tab(2, text="Textbox")
    _w1.TNotebook1.tab(3, text="About")
    # =================================================
    # Fill Message widget...
    _w1.Message1.configure(
        text="""\n\n\nThis program was written by Gregory Walters.

Copyright © 2023, 2025 by Gregory Walters

This program is licensed under the MIT license (see license.txt)"""
    )
    # =================================================
    _w1.TNotebook1.bind("<<NotebookTabChanged>>", on_TabChange)
    centre_screen(1002, 750, True)
    set_icon()
    _top1.title(f"{programName} - version {version}")
    show_environ_info()


def setup_spinbox():
    global speed
    speed = 30
    _w1.TSpinbox1.configure(from_=10, to=80)
    _w1.SpinData.set(speed)


def on_TabChange(*args):
    if _debug:
        print(args)
    currenttab = _w1.TNotebook1.index("current")
    print(f"Current tab: {currenttab}")


def on_btnExit(*args):
    if _debug:
        print("test2_support.on_btnExit")
        for arg in args:
            print("    another arg:", arg)
        sys.stdout.flush()
    sys.exit()


def centre_screen(wid, hei, testing=False):
    # ===================================================
    # This will centre the Toplevel form in the monitor.
    #     If used in a dual monitor situation, this would
    #     mean that the Toplevel form will centre within a
    #     screen width of (primaryMonitor) + (secondaryMonitor)
    # ---------------------------------------------------
    # Written by G.D. Walters 20 November, 2023
    # ===================================================
    # version 0.9
    # ===================================================
    # Parameters:
    #    Inputs:
    #        wid: integer - Toplevel width
    #        hei: integer - Toplevel height
    #        testing: boolean - Overrides the system width and height.
    #             change the values to the width/height of your primary
    #             monitor.
    #    Returns:
    #        Nothing
    #    Example:
    #        centre_screen(880, 629, 1)
    # ===================================================
    if testing == False:
        ws = root.winfo_screenwidth()
        hs = root.winfo_screenheight()
    else:
        # Override python tkinter winfo_screenwidth/winfo_screenheight
        # set to the values of your monitor to test.  This could be either
        # the primar or secondary monitor screen width and height
        ws = 2560
        hs = 1440
    x = (ws / 2) - (wid / 2)
    y = (hs / 2) - (hei / 2)
    root.geometry("%dx%d+%d+%d" % (wid, hei, x, y))


# ===================================================
#   Start of Treeview Support Functions
# ===================================================


def setup_treeview(tree):
    _w1.Scrolledtreeview1.bind("<<TreeviewSelect>>", lambda e: update_tree(e))
    _w1.Scrolledtreeview1.bind("<<TreeviewOpen>>", lambda e: tree_open(e))
    _w1.Scrolledtreeview1.bind("<<TreeviewClose>>", lambda e: tree_close(e))
    _w1.Scrolledtreeview1.bind("<Button-1>", lambda e: on_TV_Click(e))
    init_tree(_w1.Scrolledtreeview1)


def update_tree(e):
    pass


def tree_open(e):
    pass


def tree_close(e):
    pass


def on_TV_Click(e):
    pass


def init_tree(tree):
    global folderimage
    tree_columns = ("country", "capital", "currency")
    tree["columns"] = tree_columns
    tree.column("#0", width=40, stretch=NO)
    tree.column("country", width=185, stretch=NO)
    tree.column("capital", width=190, stretch=NO)
    tree.column("currency", width=160, stretch=NO)
    tree.heading("#0", text="", anchor=W)
    tree.heading("country", text="Country", anchor=W)
    tree.heading("capital", text="Capital", anchor=W)
    tree.heading("currency", text="Currency", anchor=W)
    node = tree.insert("", 1, text="")  # , image=folderimage)
    populate_tree(tree, node)


def populate_tree(tree, node):
    global first
    tree_data = [
        ("Argentina", "Buenos Aires", "ARS"),
        ("Australia", "Canberra", "AUD"),
        ("Brazil", "Brazilia", "BRL"),
        ("Canada", "Ottawa", "CAD"),
        ("China", "Beijing", "CNY"),
        ("France", "Paris", "EUR"),
        ("Germany", "Berlin", "EUR"),
        ("India", "New Delhi", "INR"),
        ("Italy", "Rome", "EUR"),
        ("Japan", "Tokyo", "JPY"),
        ("Mexico", "Mexico City", "MXN"),
        ("Russia", "Moscow", "RUB"),
        ("South Africa", "Pretoria", "ZAR"),
        ("United Kingdom", "London", "GBP"),
        ("United States", "Washington, D.C.", "USD"),
    ]
    cntr = 0
    for t in tree_data:
        id = tree.insert(node, 2, values=(t[0], t[1], t[2]))
        if cntr == 0:
            first = id
        cntr += 1
    tree.item(node, open=True)
    tree.focus(first)
    tree.selection_set(first)
    CurrentID = tree.set(first, 1)


# ===================================================
#    END Treeview support functions
# ===================================================


def load_scrolledtext():
    txtdata = f"""
def setup_treeview(tree):
    # global tree_columns, tree_data
    _w1.Scrolledtreeview1.bind("<<TreeviewSelect>>", lambda e: update_tree(e))
    _w1.Scrolledtreeview1.bind("<<TreeviewOpen>>", lambda e: tree_open(e))
    _w1.Scrolledtreeview1.bind("<<TreeviewClose>>", lambda e: tree_close(e))
    _w1.Scrolledtreeview1.bind("<Button-1>", lambda e: on_TV_Click(e))
    init_tree(_w1.Scrolledtreeview1)

def init_tree(tree):
    global folderimage
    tree_columns = ("country", "capital", "currency")
    tree["columns"] = tree_columns
    tree.column("#0", width=40, stretch=NO)
    tree.column("country", width=140, stretch=NO)
    tree.column("capital", width=140, stretch=NO)
    tree.column("currency", width=140, stretch=NO)
    tree.heading("#0", text="", anchor=W)
    tree.heading("country", text="Country", anchor=W)
    tree.heading("capital", text="Capital", anchor=W)
    tree.heading("currency", text="Currency", anchor=W)
    node = tree.insert("", 1, text="")  # , image=folderimage)
    populate_tree(tree, node)

def populate_tree(tree, node):
    global first
    tree_data = [
        ("Argentina", "Buenos Aires", "ARS"),
        ("Australia", "Canberra", "AUD"),
        ("Brazil", "Brazilia", "BRL"),
        ("Canada", "Ottawa", "CAD"),
        ("China", "Beijing", "CNY"),
        ("France", "Paris", "EUR"),
        ("Germany", "Berlin", "EUR"),
        ("India", "New Delhi", "INR"),
        ("Italy", "Rome", "EUR"),
        ("Japan", "Tokyo", "JPY"),
        ("Mexico", "Mexico City", "MXN"),
        ("Russia", "Moscow", "RUB"),
        ("South Africa", "Pretoria", "ZAR"),
        ("United Kingdom", "London", "GBP"),
        ("United States", "Washington, D.C.", "USD"),
    ]
    cntr = 0
    for t in tree_data:
        id = tree.insert(node, 2, values=(t[0], t[1], t[2]))
        if cntr == 0:
            first = id
        cntr += 1
    tree.item(node, open=True)
    tree.focus(first)
    tree.selection_set(first)
    CurrentID = tree.set(first, 1)
"""
    _w1.Scrolledtext1.insert(1.0, txtdata)


def on_WrapSettings(*args):
    if _debug:
        print("test2_support.on_WrapSettings")
        for arg in args:
            print("    another arg:", arg)
        sys.stdout.flush()
    which = _w1.WrapOption.get()
    if which == 1:
        _w1.Scrolledtext1.configure(wrap=NONE)
    elif which == 2:
        _w1.Scrolledtext1.configure(wrap=CHAR)
    elif which == 3:
        _w1.Scrolledtext1.configure(wrap=WORD)


def set_icon():
    # ======================================================
    # Sets the application icon...
    # ======================================================
    global progImagesPath
    img = os.path.join(location, "graphics", "ChubbyOwl.png")
    p1 = tk.PhotoImage(file=img)
    root.tk.call("wm", "iconphoto", root._w, p1)


def load_tcl_themes(folder, silent):
    # ===================================================
    # This will load the various tcl Themes.
    # ---------------------------------------------------
    # This function is now Windows 10+ compliant and supports
    # the page-legacy theme.
    # ---------------------------------------------------
    # Written by G.D. Walters 3 March, 2024
    # ===================================================
    # version 0.20
    # ===================================================
    # Parameters:
    #    Inputs:
    #        folder: string - The current working directory.
    #                   This allows the parent program to be
    #                   run from any folder, if the program name
    #                   is in '~/.bashrc' or '~/.bash_aliases'
    #        silent: boolean - if False: surpress debugging
    #                   output
    #    Returns:
    #        list containing all ttk themes found in folder
    # Example:
    #     theme_list = load_tcl_themes(curdir, 1)
    # ===================================================
    # version 0.20
    # ---------------------------------------------------
    #   Added a fix just in case someone accidentally copies
    #     the themes_list.tcl into the themes folder
    # ---------------------------------------------------

    if silent:
        print(sys.platform)
    sty = ttk.Style()
    localThemes = sty.theme_names()
    currentTheme = sty.theme_use()

    if silent:
        print(f"{currentTheme=}")
    if sys.platform == "win32":
        cthemename = f"\\{currentTheme}.tcl"
    else:
        cthemename = f"/{currentTheme}.tcl"
    filedef = os.path.join(folder, "themes", "*.tcl")
    if silent:
        print(filedef)
    themelist1 = glob.glob(filedef)
    themelist = []
    if silent:
        print(f"{localThemes=}")
        print(f"{themelist1=}")
    for theme in localThemes:
        themelist.append(theme)
    for theme in themelist1:
        _top1.option_clear()
        if silent:
            print(f"{theme=}")
        if theme.endswith(cthemename):
            pass
        elif theme.endswith("themes_list.tcl"):
            pass
        elif theme.endswith("page-legacy.tcl"):
            if silent:
                print(f"{theme=}")
            root.tk.eval("set ::xframe #d9d9d9")
            root.tk.eval("set ::xfore #000000")
            root.tk.eval("set ::ana2color beige")
            root.tk.eval("set ::_tabfg1 black")
            root.tk.eval("set ::_tabfg2 black")
            root.tk.eval("set ::_tabbg1 #d9d9d9")
            root.tk.eval("set ::_tabbg2 #afb5cc")
            root.tk.eval("set ::_bgmode light")
            try:
                if sys.platform == "win32":
                    rs = theme.rsplit("\\", 1)[1]
                    nameend = rs.rfind(".tcl")
                    themename = rs[:nameend]
                else:
                    rs = theme.rsplit("/", 1)[1]
                    nameend = rs.rfind(".tcl")
                    themename = rs[:nameend]
                _top1.tk.call("source", theme)
                themelist.append(themename)
            except:
                pass
        else:
            if sys.platform == "win32":
                if silent:
                    print(f"{theme=}")
                rs = theme.rsplit("\\", 1)[1]
                nameend = rs.rfind(".tcl")
                themename = rs[:nameend]
            else:
                rs = theme.rsplit("/", 1)[1]
                nameend = rs.rfind(".tcl")
                themename = rs[:nameend]
            if silent:
                print(f"{themename=}")
            themelist.append(themename)
            _top1.tk.call("source", theme)
    themelist.sort()
    if silent:
        print(f"{themelist=}")
    return themelist


# Shows information at the beginning of the program that could be helpful for troubleshooting
def show_environ_info():
    osVersion = platform.system()
    release = platform.release()
    platformversion = platform.version()
    pv = platform.python_version()
    print("=" * 35)
    print(f"Program name: {programName} {version}")
    print(f"System running {osVersion} {release}")
    print(f"Running under Python {pv}")
    print(f"Program path: {location}")
    print("=" * 35)


def setup_listbox():
    global demolist
    demolist = [
        "One",
        "Two",
        "Three",
        "Four",
        "Five",
        "Six",
        "Seven",
        "Eight",
        "Nine",
        "Ten",
    ]
    for itm in demolist:
        _w1.Scrolledlistbox1.insert("end", itm)
    _w1.Scrolledlistbox1.bind("<<ListboxSelect>>", on_listboxSelect)


def on_listboxSelect(e):
    indx = _w1.Scrolledlistbox1.curselection()
    itm = _w1.Scrolledlistbox1.get(indx[0])

    if _debug3:
        print(f"Selected Item: {indx[0]} - {itm}")


def setup_combobox(themeList):
    _w1.TComboThemes["values"] = themeList
    _w1.TComboThemes.bind("<<ComboboxSelected>>", lambda e: on_ComboSelect(e))


def on_ComboSelect(e):
    sty = ttk.Style()
    selected = _w1.comboThemes.get()
    if _debug2:
        print(f"Combobox Select: {selected}")
    sty.theme_use(selected)
    bg1 = sty.lookup(".", "background")
    _top1.configure(background=bg1)
    on_ChkApplyBkgnd()


def on_ChkApplyBkgnd(*args):
    if _debug:
        print("PAGE80Demo_support.on_ChkApplyBkgnd")
        for arg in args:
            print("    another arg:", arg)
        sys.stdout.flush()
    global originalBackground, originalForeground
    sty = ttk.Style()
    curTheme = sty.theme_use()
    bg1 = sty.lookup(".", "background")
    fg1 = sty.lookup(".", "foreground")
    if fg1 == "":
        fg1 = "black"
    which = _w1.tch47.get()
    if which == 1:
        _w1.TNotebook1_t1.configure(background=bg1)
        _w1.TNotebook1_t2.configure(background=bg1)
        _w1.TNotebook1_t3.configure(background=bg1)
        _w1.TNotebook1_t4.configure(background=bg1)
        _w1.Message1.configure(background=bg1, foreground=fg1)
    else:
        _w1.TNotebook1_t1.configure(background=originalBackground)
        _w1.TNotebook1_t2.configure(background=originalBackground)
        _w1.TNotebook1_t3.configure(background=originalBackground)
        _w1.TNotebook1_t4.configure(background=originalBackground)
        _w1.Message1.configure(
            background=originalBackground, foreground=originalForeground
        )


# ===================================================
# Annimation functions
# ===================================================


class count_it:
    # ===================================================
    # A quick (and sloppy class) to provide an up/down counter.
    # ===================================================
    def __init__(
        self,
        direction="up",
        min_value=0,
        max_value=100,
        start_value=0,
        step=1,
        verbose=False,
    ) -> None:
        self.direction = direction
        self.min_value = min_value
        self.max_value = max_value
        self.start_value = start_value
        self.step = step
        self.current_counter = self.start_value
        self.verbose = verbose

    def do_it(self):
        if self.direction == "up":
            if self.current_counter > (self.max_value - 1):
                self.direction = "down"
                if self.verbose:
                    print(f"Changing direction to {self.direction}")
        else:
            if self.current_counter < (self.min_value + 1):
                self.direction = "up"
                if self.verbose:
                    print(f"Changing direction to {self.direction}")
        if self.direction == "down":
            self.current_counter -= self.step
        else:
            self.current_counter += self.step
        return self.current_counter


def on_animate_time_update():
    # ======================================================
    # Callback function for the TProgressbar determinate mode
    # Timer function.  It uses the 'counter1' class to provide
    # the up and down counts for the TProgressbar values.
    # ======================================================
    global timer_id, pbValue, speed
    pbValue = counter1.do_it()
    _w1.VProg.set(pbValue)
    _w1.HProg.set(pbValue)
    _w1.VScale.set(pbValue)
    _w1.HScale.set(pbValue)
    timer_id = root.after(speed, on_animate_time_update)


def setup_Progressbars():
    # ===================================================
    # This function will set up the TProgress Bars for Demo
    # I purposly did as little work in the designer to show
    # how easy it is to do in code.
    # ===================================================
    global freerun, pbValue, pbmode, isrunning
    freerun = False
    isrunning = False
    pbmode = "determinate"
    pbValue = 0
    global counter1
    counter1 = count_it("up", 0, 100, 0, 2)
    global timer_id


def on_Spin(*args):
    if _debug:
        print("PAGE80Demo_support.on_Spin")
        for arg in args:
            print("    another arg:", arg)
        sys.stdout.flush()
    global speed
    tempspeed = _w1.SpinData.get()
    speed = int(tempspeed)


def on_btnAnimate(*args):
    if _debug:
        print("test2_support.on_btnAnimate")
        for arg in args:
            print("    another arg:", arg)
        sys.stdout.flush()
    global freerun, pbValue, pbmode, isrunning
    global timer_id
    if freerun == True:
        freerun = False
        root.after_cancel(timer_id)
        _w1.btnAnimate.configure(text="Start Animation")

    else:
        freerun = True
        timer_id = root.after(0, on_animate_time_update)
        _w1.btnAnimate.configure(text="Stop Animation")


# ===================================================
# END of Annimation functions
# ===================================================

if __name__ == "__main__":
    PAGE80Demo.start_up()
