This repository has been archived by the owner on Jun 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
42 changed files
with
1,224 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from tkinter import Toplevel, ttk, StringVar, PhotoImage | ||
from typing import Callable | ||
|
||
|
||
class ComboBox(ttk.Frame): | ||
def __init__(self: object, parent: object, values: list, default_value: int = 0, image: PhotoImage = None, command: Callable = None) -> None: | ||
super().__init__(parent) | ||
self.parent: object = parent | ||
self.values: list = values | ||
self.command: Callable = command | ||
self.value: StringVar = StringVar(value=values[default_value]) | ||
ttk.Button(self, image=image, textvariable=self.value, style='third.TButton', | ||
compound='right', command=self.toggle_panel).pack(anchor='c') | ||
self.init_window() | ||
|
||
def init_window(self: object): | ||
self.window: Toplevel = Toplevel(self.parent) | ||
self.window.withdraw() | ||
self.window.overrideredirect(True) | ||
self.window.bind('<FocusOut>', lambda _: self.hide()) | ||
self.window.protocol('WM_DELETE_WINDOW', lambda _: self.hide()) | ||
for option in self.values: | ||
self.add_option(option) | ||
|
||
def add_option(self: object, option: str) -> None: | ||
ttk.Button(self.window, text=option, command=lambda: self.select_option( | ||
option), style='third.TButton').pack(anchor='c', fill='x') | ||
|
||
def toggle_panel(self: object) -> None: | ||
self.window.deiconify() | ||
# get mouse position | ||
mouse_pos: tuple = self.parent.winfo_pointerxy() | ||
# get button class | ||
button: ttk.Button = self.parent.winfo_containing( | ||
mouse_pos[0], mouse_pos[1]) | ||
if button: | ||
button_position: tuple = ( | ||
button.winfo_rootx(), button.winfo_rooty()) | ||
self.window.geometry( | ||
f'{button.winfo_width()}x{len(self.values) * 38}+{button_position[0]}+{button_position[1] + 38}') | ||
else: | ||
self.window.geometry('') | ||
self.window.geometry(f'+{mouse_pos[0]}+{mouse_pos[1]}') | ||
self.window.focus_set() | ||
|
||
def select_option(self: object, option: str) -> None: | ||
self.value.set(option) | ||
self.window.withdraw() | ||
self.command(option) | ||
|
||
def hide(self: object) -> None: | ||
self.window.after(10, self.window.withdraw) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
from tkinter import Event | ||
from typing import Callable | ||
|
||
|
||
class Inspector: | ||
def __init__(self: object, parent: object) -> object: | ||
# variables | ||
self.parent: object = parent | ||
self.widget: object = None | ||
self.update_speed: int = 500 | ||
self.run: bool = True | ||
self.highlighted_widget: list = [] | ||
self.ignore_widgets = ('TProgressbar', 'Progressbar') | ||
# events | ||
self.bindings: dict = {'start': [], | ||
'end': [], 'change': [], 'pointing': [], } | ||
|
||
parent.after(1000, lambda: self.monitor_widget(parent)) | ||
|
||
def start_inspecting(self: object) -> None: | ||
self.__notify('start') | ||
self.parent.bind('<Motion>', self.__while_inspecting) | ||
self.parent.bind('<Button-1>', self.__finish_inspecting) | ||
|
||
def stop_inspecting(self: object) -> None: | ||
self.parent.unbind('<Motion>') | ||
self.parent.unbind('<Button-1>') | ||
|
||
def get_widget(self: object) -> object: | ||
return self.widget | ||
|
||
def set_widget(self: object, widget: object) -> None: | ||
self.widget = widget | ||
self.__notify('change') | ||
|
||
def __while_inspecting(self: object, _: Event) -> None: | ||
position: tuple = self.parent.winfo_pointerxy() | ||
widget: object = self.parent.winfo_containing(position[0], position[1]) | ||
if widget is not self.widget: | ||
self.__unhighlight_widget(self.widget) | ||
self.widget = widget | ||
self.__highlight_widget(widget) | ||
self.__notify('pointing') | ||
|
||
def __finish_inspecting(self: object, _: Event) -> None: | ||
self.__notify('end') | ||
self.parent.unbind('<Motion>') | ||
self.parent.unbind('<Button-1>') | ||
self.__unhighlight_all() | ||
|
||
def get_children(self: object, widget: object) -> list: | ||
children_list = widget.winfo_children() | ||
for widget in children_list: | ||
if widget.winfo_children(): | ||
children_list.extend(widget.winfo_children()) | ||
return children_list | ||
|
||
def bind(self: object, bind_type: str, methode: Callable) -> None: | ||
self.bindings[bind_type].append(methode) | ||
|
||
def unbind(self: object, methode: Callable) -> None: | ||
for key in self.bindings: | ||
if methode in self.bindings[key]: | ||
self.bindings[key].remove(methode) | ||
|
||
def __notify(self: object, notify_type: str) -> None: | ||
for methode in self.bindings[notify_type]: | ||
methode() | ||
|
||
def monitor_widget(self: object, widget: object) -> None: | ||
widget.bind('<Configure>', lambda _: self.__notify('change'), add='+') | ||
self.parent.after(1000, self.__update) | ||
|
||
def __update(self: object) -> None: | ||
if self.run: | ||
self.__notify('change') | ||
self.parent.after(self.update_speed, self.__update) | ||
|
||
def unbind_all(self: object) -> None: | ||
self.run = False | ||
self.parent.unbind('<Button-1>') | ||
self.parent.unbind('<Configure>') | ||
|
||
def __highlight_widget(self: object, widget: object) -> None: | ||
widget_class: str = widget.winfo_class() | ||
if widget_class not in self.highlighted_widget: | ||
widget_config: dict = widget.config() | ||
if 'state' in widget_config: | ||
self.highlighted_widget.append(widget) | ||
if widget_class[0] == 'T': | ||
widget.state(['disabled']) | ||
else: | ||
widget['state'] = 'disabled' | ||
|
||
def __unhighlight_widget(self: object, widget: object) -> None: | ||
widget_class: str = widget.winfo_class() | ||
if widget in self.highlighted_widget: | ||
widget_config: dict = widget.config() | ||
if 'state' in widget_config: | ||
self.highlighted_widget.remove(widget) | ||
if widget_class[0] == 'T': | ||
widget.state(['!disabled']) | ||
else: | ||
widget['state'] = 'normal' | ||
|
||
def __unhighlight_all(self: object) -> None: | ||
for widget in self.highlighted_widget: | ||
self.__unhighlight_widget(widget) | ||
|
||
def delete_current_widget(self: object, _: Event = None) -> None: | ||
if self.widget and self.widget.winfo_class() not in ('Tk', 'Toplevel'): | ||
widget_parent: object = self.parent._nametowidget( | ||
self.widget.winfo_parent()) | ||
parent_childrens: list = widget_parent.winfo_children() | ||
child_index: int = parent_childrens.index(self.widget) | ||
# delete widget | ||
parent_childrens.remove(self.widget) | ||
self.widget.destroy() | ||
if parent_childrens: | ||
# select next widget | ||
self.widget = parent_childrens[child_index - 1] | ||
else: | ||
# select parent widget | ||
self.widget = widget_parent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
class Matcher: | ||
def __init__(self: object) -> object: | ||
self.properties: dict = { | ||
'Tk': {'Class': '', 'Name': '', 'Manager': '', 'Geometry': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': ''}, | ||
'Toplevel': {'Class': '', 'Name': '', 'Manager': '', 'Geometry': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': ''}, | ||
'TLabel': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Text': '', 'WrapLength': 'Infinite', 'Justify': 'Default', 'Image': 'Not specified', 'Compound': 'None', 'Style': 'Default'}, | ||
'TButton': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Text': '', 'Image': 'Not specified', 'Compound': 'None', 'Style': 'Default'}, | ||
'TFrame': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Childrens': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Style': 'Default'}, | ||
'TRadiobutton': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Text': '', 'Image': 'Not specified', 'Compound': 'None', 'Style': 'Default'}, | ||
'TScale': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Value': '', 'Style': 'Default'}, | ||
'TEntry': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Value': '', 'Style': 'Default'}, | ||
'TProgressbar': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Progress': ''}, | ||
'TCheckbutton': {'Class': '', 'Name': '', 'Manager': '', 'Manager Config': '', 'Parent': '', 'Position': '', 'Dimentions': '', 'Binds': '', 'State': '', 'Visible': '', 'Text': '', 'WrapLength': 'Infinite', 'Image': 'Not specified', 'Compound': 'None', 'Style': 'Default'} | ||
|
||
} | ||
|
||
def get_properties(self: object, widget: object) -> dict: | ||
properties: dict = { | ||
'Class': widget.winfo_class(), | ||
'Name': f'{widget}', | ||
'Manager': widget.winfo_manager(), | ||
'Geometry': widget.winfo_geometry(), | ||
'Parent': widget.winfo_parent(), | ||
'Text': widget['text'] if widget.winfo_class() in ('TLabel', 'Label', 'TButton', 'Button', 'TRadiobutton') else '', | ||
'WrapLength': widget['wraplength'] if widget.winfo_class() in ('TLabel', 'Label') else '', | ||
'Position': f'X: {widget.winfo_x()} Y: {widget.winfo_y()}', | ||
'Dimentions': f'Width: {widget.winfo_width()} Height: {widget.winfo_height()}', | ||
'Binds': widget.bind(), | ||
'Manager Config': self.__get_manager_config(widget), | ||
'Value': widget.get() if widget.winfo_class() in ('TScale', 'TEntry') else '', | ||
'State': widget.state() if widget.winfo_class()[0] == 'T' else '', | ||
'Progress': widget['value'] if widget.winfo_class() in ('TProgressbar') else '', | ||
'Image': widget['image'] if widget.winfo_class() in ('TButton', 'TLabel', 'TRadiobutton') else '', | ||
'Visible': bool(widget.winfo_ismapped()), | ||
'Compound': f'{widget["compound"]}'.capitalize() if widget.winfo_class() in ('TLabel', 'TButton', 'TRadiobutton') else '', | ||
'Justify': widget['justify'] if widget.winfo_class() in ('TLabel') else '', | ||
'Style': widget['style'] if widget.winfo_class() not in ('Tk', 'Toplevel') and widget.winfo_class()[0] == 'T' else '', | ||
'Childrens': len(widget.winfo_children()), | ||
} | ||
return properties | ||
|
||
def match(self: object, widget: object) -> dict: | ||
properties: dict = self.get_properties(widget) | ||
widget_class: str = widget.winfo_class() | ||
available_properties: dict = {} | ||
if widget_class in self.properties: | ||
for key in self.properties[widget_class]: | ||
propertie: str = properties[key] | ||
available_properties[key] = propertie if propertie else self.properties[widget_class][key] | ||
return available_properties | ||
else: | ||
available_properties['WARNING'] = f' THIS IS A LEGACY OR UNKNOWN WIDGET' | ||
available_properties[''] = ' PROPS BELOW =>' | ||
|
||
for key in widget.keys(): | ||
available_properties[key.capitalize()] = f' {widget[key]}' | ||
return available_properties | ||
|
||
def __get_manager_config(self: object, widget: object) -> str: | ||
manager: str = widget.winfo_manager() | ||
widget_config: dict = {} | ||
if manager == 'pack': | ||
widget_config = widget.pack_info() | ||
elif manager == 'grid': | ||
widget_config = widget.grid_info() | ||
elif manager == 'place': | ||
widget_config = widget.place_info() | ||
config: str = '' | ||
for key in widget_config: | ||
if key == 'in' or not widget_config[key] or widget_config[key] in ('None', 'none', 0): | ||
continue | ||
config += f'{key}: {widget_config[key]} ' | ||
if config: | ||
return config | ||
return 'Unknown' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from darkdetect import theme | ||
|
||
|
||
def get_theme() -> str: | ||
return theme() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from tkinter import Tk, ttk, PhotoImage | ||
from typing import Callable | ||
from ..Components.SystemTheme import get_theme | ||
from os.path import join | ||
|
||
|
||
class Layout: | ||
def __init__(self: object, parent: Tk, absolute_path: str) -> object: | ||
# pass parent object | ||
self.parent = parent | ||
# init theme object | ||
self.parent.layout = ttk.Style(self.parent) | ||
# abs path | ||
self.abs_path = absolute_path | ||
|
||
self.parent.layout.layout('debugger.TButton', [('Button.padding', { | ||
'sticky': 'nswe', 'children': [('Button.label', {'sticky': 'nswe'})]})]) | ||
# treeview | ||
self.parent.layout.configure('debugger.Treeview', indent=25, rowheight=25, font=( | ||
'Catamaran', 10, 'bold')) | ||
self.parent.layout.layout('debugger.Treeview', [('Treeview.treearea', { | ||
'sticky': 'nswe'})]) # Remove the borders | ||
self.tree_open = PhotoImage( | ||
file=join(self.abs_path, r'Resources\\plus.png')) | ||
self.tree_close = PhotoImage( | ||
file=join(self.abs_path, r'Resources\\minus.png')) | ||
self.tree_empty = PhotoImage( | ||
file=join(self.abs_path, r'Resources\\empty.png')) | ||
self.parent.layout.element_create('Treeitem.indicator', | ||
'image', self.tree_open, ('user1', '!user2', | ||
self.tree_close), ('user2', self.tree_empty), | ||
sticky='w', width=20) | ||
self.parent.layout.layout('Treeview.Item', | ||
[('Treeitem.padding', | ||
{'sticky': 'nswe', | ||
'children': [('Treeitem.indicator', {'side': 'left', 'sticky': ''}), | ||
('Treeitem.image', { | ||
'side': 'left', 'sticky': ''}), | ||
('Treeitem.text', { | ||
'side': 'left', 'sticky': ''}) | ||
]})] | ||
) | ||
|
||
# scrollbar | ||
self.parent.layout.element_create( | ||
'debugger.Vertical.Scrollbar.trough', 'from', 'clam') | ||
self.parent.layout.element_create( | ||
'debugger.Vertical.Scrollbar.thumb', | ||
'from', 'clam') | ||
self.parent.layout.layout('debugger.Vertical.TScrollbar', [('debugger.Vertical.Scrollbar.trough', {'children': [ | ||
('debugger.Vertical.Scrollbar.thumb', {'expand': '1', 'sticky': 'nswe'})], 'sticky': 'ns'})]) | ||
|
||
|
||
class Theme: | ||
def __init__(self: object, parent: Tk) -> None: | ||
# pass parent object | ||
self.parent = parent | ||
self.colors: dict = {'Dark': ['#111', '#212121', '#333', '#fff'], 'Light': [ | ||
'#fff', '#ecf0f1', '#ecf0f1', '#000']} | ||
# get system theme | ||
self.system_theme: str = get_theme() | ||
self.colors['System'] = self.colors[self.system_theme] | ||
# set default applied theme | ||
self.applied_theme: str = 'Light' | ||
# bindings | ||
self.bindings: dict = {'changed': []} | ||
|
||
def apply(self: object, theme: str) -> None: | ||
self.applied_theme = theme | ||
# pass parent object | ||
self.parent.configure(background=self.colors[theme][1]) | ||
# frames | ||
self.parent.layout.configure( | ||
'debugger.TFrame', background=self.colors[theme][0]) | ||
self.parent.layout.configure( | ||
'debugger.dark.TFrame', background=self.colors[theme][1]) | ||
# label | ||
self.parent.layout.configure('debugger.TLabel', background=self.colors[theme][0], font=( | ||
'catamaran 12 bold'), foreground=self.colors[theme][3]) | ||
# button | ||
self.parent.layout.configure('debugger.TButton', background=self.colors[theme][0], font=( | ||
'catamaran 12 bold'), foreground=self.colors[theme][3], anchor='w', padding=4) | ||
|
||
self.parent.layout.map('debugger.TButton', background=[('pressed', '!disabled', self.colors[theme][1]), ( | ||
'active', self.colors[theme][1]), ('selected', self.colors[theme][1])]) | ||
|
||
# treewiev | ||
self.parent.layout.map('debugger.Treeview', background=[ | ||
('selected', self.colors[theme][1])], foreground=[('selected', self.colors[theme][3])]) | ||
|
||
# scrollbar | ||
self.parent.layout.configure('debugger.Vertical.TScrollbar', gripcount=0, background=self.colors[theme][2], darkcolor=self.colors[ | ||
theme][0], lightcolor=self.colors[theme][0], troughcolor=self.colors[theme][0], bordercolor=self.colors[theme][0]) | ||
|
||
self.parent.layout.map('debugger.Vertical.TScrollbar', background=[('pressed', '!disabled', self.colors[theme][2]), ( | ||
'disabled', self.colors[theme][0]), ('active', self.colors[theme][2]), ('!active', self.colors[theme][2])]) | ||
|
||
# notify event | ||
self.__notify('changed') | ||
|
||
def get_theme(self: object) -> str: | ||
if self.applied_theme == 'System': | ||
return self.system_theme | ||
return self.applied_theme | ||
|
||
def get_internal_theme(self: object) -> str: | ||
return self.applied_theme | ||
|
||
def get_colors(self: object, theme: str) -> list: | ||
return self.colors[theme] | ||
|
||
def bind(self: object, bind_type: str, methode: Callable) -> None: | ||
self.bindings[bind_type].append(methode) | ||
|
||
def unbind(self: object, methode: Callable) -> None: | ||
for key in self.bindings: | ||
if methode in self.bindings[key]: | ||
self.bindings[key].remove(methode) | ||
|
||
def __notify(self: object, notify_type: str) -> None: | ||
for methode in self.bindings[notify_type]: | ||
methode() |
Oops, something went wrong.