diff --git a/plugins/template/plugin.py b/plugins/template/plugin.py index 21a5d5b..5535f4d 100644 --- a/plugins/template/plugin.py +++ b/plugins/template/plugin.py @@ -7,6 +7,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports +from plugins.plugin_base import PluginBase # NOTE: Threads WILL NOT die with parent's destruction. @@ -24,53 +25,22 @@ def daemon_threaded(fn): -class Plugin: +class Plugin(PluginBase): def __init__(self): + super().__init__() + self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus # where self.name should not be needed for message comms - self._event_system = None - self._event_sleep_time = .5 - self._event_message = None - def get_ui_element(self): + def generate_reference_ui_element(self): button = Gtk.Button(label=self.name) button.connect("button-release-event", self.send_message) return button - def set_fm_event_system(self, fm_event_system): - self._event_system = fm_event_system - def run(self): - self._module_event_observer() - + ... def send_message(self, widget=None, eve=None): message = "Hello, World!" - self._event_system.push_gui_event([self.name, "display_message", ("warning", message, None)]) - - - def wait_for_fm_message(self): - while not self._event_message: - pass - - @daemon_threaded - def _module_event_observer(self): - while True: - time.sleep(self._event_sleep_time) - event = self._event_system.read_module_event() - if event: - try: - if event[0] == self.name: - target_id, method_target, data = self._event_system.consume_module_event() - - if not method_target: - self._event_message = data - else: - method = getattr(self.__class__, f"{method_target}") - if data: - data = method(*(self, *data)) - else: - method(*(self,)) - except Exception as e: - print(repr(e)) + event_system.emit("display_message", ("warning", message, None)) diff --git a/src/__builtins__.py b/src/__builtins__.py index 1416b06..d676771 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -8,7 +8,8 @@ import builtins # Application imports from utils.event_system import EventSystem from utils.endpoint_registry import EndpointRegistry - +from utils.keybindings import Keybindings +from utils.settings import Settings @@ -30,10 +31,12 @@ def daemon_threaded_wrapper(fn): # NOTE: Just reminding myself we can add to builtins two different ways... # __builtins__.update({"event_system": Builtins()}) builtins.app_name = "" +builtins.keybindings = Keybindings() builtins.event_system = EventSystem() builtins.endpoint_registry = EndpointRegistry() +builtins.settings = Settings() +builtins.logger = settings.get_logger() + builtins.threaded = threaded_wrapper builtins.daemon_threaded = daemon_threaded_wrapper builtins.event_sleep_time = 0.05 -builtins.trace_debug = False -builtins.debug = False diff --git a/src/__main__.py b/src/__main__.py index ed40606..5f08a75 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -1,7 +1,9 @@ #!/usr/bin/python3 # Python imports -import argparse, faulthandler, traceback +import argparse +import faulthandler +import traceback from setproctitle import setproctitle import tracemalloc @@ -14,6 +16,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports +from __builtins__ import * from app import Application @@ -21,13 +24,13 @@ if __name__ == "__main__": ''' Set process title, get arguments, and create GTK main thread. ''' try: - # import web_pdb - # web_pdb.set_trace() - setproctitle('') faulthandler.enable() # For better debug info + parser = argparse.ArgumentParser() # Add long and short arguments + parser.add_argument("--debug", "-d", default="false", help="Do extra console messaging.") + parser.add_argument("--trace-debug", "-td", default="false", help="Disable saves, ignore IPC lock, do extra console messaging.") parser.add_argument("--file", "-f", default="default", help="JUST SOME FILE ARG.") # Read arguments (If any...) diff --git a/src/app.py b/src/app.py index 54144a3..2470aaf 100644 --- a/src/app.py +++ b/src/app.py @@ -1,19 +1,20 @@ # Python imports -import os, inspect, time +import os +import time # Lib imports # Application imports -from __builtins__ import * from utils.ipc_server import IPCServer from utils.settings import Settings -from context.controller import Controller +from core.window import Window -class App_Launch_Exception(Exception): + +class AppLaunchException(Exception): ... -class Controller_Start_Exceptio(Exception): +class ControllerStartExceptiom(Exception): ... @@ -22,8 +23,13 @@ class Application(IPCServer): def __init__(self, args, unknownargs): super(Application, self).__init__() + if args.debug == "true": + settings.set_debug(True) - if not trace_debug: + if args.trace_debug == "true": + settings.set_trace_debug(True) + + if not settings.is_trace_debug(): self.create_ipc_listener() time.sleep(0.05) @@ -34,26 +40,6 @@ class Application(IPCServer): message = f"FILE|{arg}" self.send_ipc_message(message) - raise App_Launch_Exception(f"IPC Server Exists: Will send path(s) to it and close...\nNote: If no fm exists, remove /tmp/{app_name}-ipc.sock") + raise AppLaunchException(f"IPC Server Exists: Will send path(s) to it and close...\nNote: If no fm exists, remove /tmp/{app_name}-ipc.sock") - - settings = Settings() - settings.create_window() - - controller = Controller(settings, args, unknownargs) - if not controller: - raise Controller_Start_Exceptio("Controller exited and doesn't exist...") - - # Gets the methods from the classes and sets to handler. - # Then, builder from settings will connect to any signals it needs. - classes = [controller] - handlers = {} - for c in classes: - methods = None - try: - methods = inspect.getmembers(c, predicate=inspect.ismethod) - handlers.update(methods) - except Exception as e: - print(repr(e)) - - settings.get_builder().connect_signals(handlers) + Window(args, unknownargs) diff --git a/src/context/controller_data.py b/src/context/controller_data.py deleted file mode 100644 index 0de8776..0000000 --- a/src/context/controller_data.py +++ /dev/null @@ -1,61 +0,0 @@ -# Python imports -import os, signal - -# Lib imports -from gi.repository import GLib - -# Application imports -from plugins.plugins import Plugins - - -class Controller_Data: - ''' Controller_Data contains most of the state of the app at ay given time. It also has some support methods. ''' - - def setup_controller_data(self, _settings: type) -> None: - self.plugins = Plugins(_settings) - - self.settings = _settings - self.builder = self.settings.get_builder() - self.window = self.settings.get_main_window() - self.logger = self.settings.get_logger() - self.keybindings = self.settings.get_keybindings() - - - self.home_path = self.settings.get_home_path() - self.success_color = self.settings.get_success_color() - self.warning_color = self.settings.get_warning_color() - self.error_color = self.settings.get_error_color() - - self.window.connect("delete-event", self.tear_down) - GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down) - - - def clear_console(self) -> None: - ''' Clears the terminal screen. ''' - os.system('cls' if os.name == 'nt' else 'clear') - - def call_method(self, _method_name: str, data: type) -> type: - ''' - Calls a method from scope of class. - - Parameters: - a (obj): self - b (str): method name to be called - c (*): Data (if any) to be passed to the method. - Note: It must be structured according to the given methods requirements. - - Returns: - Return data is that which the calling method gives. - ''' - method_name = str(_method_name) - method = getattr(self, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") - return method(data) if data else method() - - def has_method(self, obj: type, name: type) -> type: - ''' Checks if a given method exists. ''' - return callable(getattr(obj, name, None)) - - def clear_children(self, widget: type) -> None: - ''' Clear children of a gtk widget. ''' - for child in widget.get_children(): - widget.remove(child) diff --git a/src/context/__init__.py b/src/core/__init__.py similarity index 100% rename from src/context/__init__.py rename to src/core/__init__.py diff --git a/src/context/controller.py b/src/core/controller.py similarity index 66% rename from src/context/controller.py rename to src/core/controller.py index c869717..c31979f 100644 --- a/src/context/controller.py +++ b/src/core/controller.py @@ -1,39 +1,58 @@ # Python imports -import subprocess, time - +import subprocess # Gtk imports import gi + gi.require_version('Gtk', '3.0') gi.require_version('Gdk', '3.0') -from gi.repository import Gtk, Gdk, GLib + +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GLib # Application imports from .mixins.dummy_mixin import DummyMixin -from .controller_data import Controller_Data +from .controller_data import ControllerData +from .core_widget import CoreWidget +class Controller(DummyMixin, ControllerData): + def __init__(self, args, unknownargs): + self._setup_styling() + self._setup_signals() + self._subscribe_to_events() -class Controller(DummyMixin, Controller_Data): - def __init__(self, _settings, args, unknownargs): - self.setup_controller_data(_settings) - self.window.show() + self.setup_controller_data() self.print_hello_world() # A mixin method from the DummyMixin file - self._subscribe_to_events() + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + def _subscribe_to_events(self): event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) - - def tear_down(self, widget=None, eve=None): - time.sleep(event_sleep_time) - Gtk.main_quit() - def handle_file_from_ipc(self, path: str) -> None: print(f"Path From IPC: {path}") + def load_glade_file(self): + self.builder = Gtk.Builder() + self.builder.add_from_file(settings.get_glade_file()) + settings.set_builder(self.builder) + self.core_widget = CoreWidget() + + settings.register_signals_to_builder([self, self.core_widget]) + + def get_core_widget(self): + return self.core_widget + + def on_global_key_release_controller(self, widget: type, event: type) -> None: """Handler for keyboard events""" keyname = Gdk.keyval_name(event.keyval).lower() @@ -46,7 +65,7 @@ class Controller(DummyMixin, Controller_Data): self.alt_down = False - mapping = self.keybindings.lookup(event) + mapping = keybindings.lookup(event) if mapping: getattr(self, mapping)() return True @@ -55,7 +74,6 @@ class Controller(DummyMixin, Controller_Data): print(f"Add logic or remove this from: {self.__class__}") - def get_clipboard_data(self) -> str: proc = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE) retcode = proc.wait() diff --git a/src/core/controller_data.py b/src/core/controller_data.py new file mode 100644 index 0000000..400bf42 --- /dev/null +++ b/src/core/controller_data.py @@ -0,0 +1,51 @@ +# Python imports +import os + +# Lib imports + +# Application imports +from plugins.plugins_controller import PluginsController + + + +class ControllerData: + ''' ControllerData contains most of the state of the app at ay given time. It also has some support methods. ''' + + def setup_controller_data(self) -> None: + self.logger = settings.get_logger() + self.builder = None + self.core_widget = None + + self.load_glade_file() + self.plugins = PluginsController() + + + def clear_console(self) -> None: + ''' Clears the terminal screen. ''' + os.system('cls' if os.name == 'nt' else 'clear') + + def call_method(self, _method_name: str, data: type) -> type: + ''' + Calls a method from scope of class. + + Parameters: + a (obj): self + b (str): method name to be called + c (*): Data (if any) to be passed to the method. + Note: It must be structured according to the given methods requirements. + + Returns: + Return data is that which the calling method gives. + ''' + method_name = str(_method_name) + method = getattr(self, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}") + return method(*data) if data else method() + + def has_method(self, obj: type, method: type) -> type: + ''' Checks if a given method exists. ''' + return callable(getattr(obj, method, None)) + + def clear_children(self, widget: type) -> None: + ''' Clear children of a gtk widget. ''' + for child in widget.get_children(): + widget.remove(child) diff --git a/src/core/core_widget.py b/src/core/core_widget.py new file mode 100644 index 0000000..ac99adf --- /dev/null +++ b/src/core/core_widget.py @@ -0,0 +1,37 @@ +# Python imports + +# Gtk imports +import gi + +gi.require_version('Gtk', '3.0') + +from gi.repository import Gtk + +# Application imports + + +class CoreWidget(Gtk.Box): + def __init__(self): + super(CoreWidget, self).__init__() + + self._setup_styling() + self._setup_signals() + self._load_widgets() + + self.show_all() + + + def _setup_styling(self): + self.set_orientation(1) + + def _setup_signals(self): + ... + + def _load_widgets(self): + button = Gtk.Button(label="Click Me!") + button.connect("clicked", self._hello_world) + + self.add(button) + + def _hello_world(self, widget=None, eve=None): + print("Hello, World!") diff --git a/src/context/mixins/__init__.py b/src/core/mixins/__init__.py similarity index 100% rename from src/context/mixins/__init__.py rename to src/core/mixins/__init__.py diff --git a/src/context/mixins/dummy_mixin.py b/src/core/mixins/dummy_mixin.py similarity index 100% rename from src/context/mixins/dummy_mixin.py rename to src/core/mixins/dummy_mixin.py diff --git a/src/core/window.py b/src/core/window.py new file mode 100644 index 0000000..572841c --- /dev/null +++ b/src/core/window.py @@ -0,0 +1,76 @@ +# Python imports +import time +import signal + +# Lib imports +import gi +import cairo + +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') + +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GLib + +# Application imports +from core.controller import Controller + + + + +class Window(Gtk.ApplicationWindow): + """docstring for Window.""" + + def __init__(self, args, unknownargs): + super(Window, self).__init__() + + self._set_window_data() + self._setup_styling() + self._setup_signals() + self._load_widgets(args, unknownargs) + + self.show_all() + + + def _setup_styling(self): + self.set_default_size(1670, 830) + self.set_title(f"{app_name}") + self.set_icon_from_file( settings.get_window_icon() ) + self.set_gravity(5) # 5 = CENTER + self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS + + def _setup_signals(self): + self.connect("delete-event", self._tear_down) + GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down) + + def _load_widgets(self, args, unknownargs): + controller = Controller(args, unknownargs) + self.add( controller.get_core_widget() ) + + def _set_window_data(self) -> None: + screen = self.get_screen() + visual = screen.get_rgba_visual() + + if visual != None and screen.is_composited(): + self.set_visual(visual) + self.set_app_paintable(True) + self.connect("draw", self._area_draw) + + # bind css file + cssProvider = Gtk.CssProvider() + cssProvider.load_from_path( settings.get_css_file() ) + screen = Gdk.Screen.get_default() + styleContext = Gtk.StyleContext() + styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER) + + def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None: + cr.set_source_rgba(0, 0, 0, 0.54) + cr.set_operator(cairo.OPERATOR_SOURCE) + cr.paint() + cr.set_operator(cairo.OPERATOR_OVER) + + + def _tear_down(self, widget=None, eve=None): + time.sleep(event_sleep_time) + Gtk.main_quit() diff --git a/src/plugins/manifest.py b/src/plugins/manifest.py index 363e4b9..1865fa3 100644 --- a/src/plugins/manifest.py +++ b/src/plugins/manifest.py @@ -52,9 +52,9 @@ class ManifestProcessor: requests = self._plugin.requests keys = requests.keys() - if "pass_fm_events" in keys: - if requests["pass_fm_events"] in ["true"]: - loading_data["pass_fm_events"] = True + if "pass_events" in keys: + if requests["pass_events"] in ["true"]: + loading_data["pass_events"] = True if "bind_keys" in keys: if isinstance(requests["bind_keys"], list): diff --git a/src/plugins/plugin_base.py b/src/plugins/plugin_base.py new file mode 100644 index 0000000..974583a --- /dev/null +++ b/src/plugins/plugin_base.py @@ -0,0 +1,60 @@ +# Python imports +import os, time + +# Lib imports + +# Application imports + + +class PluginBaseException(Exception): + ... + + +class PluginBase: + def __init__(self): + self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus + # where self.name should not be needed for message comms + + self._builder = None + self._ui_objects = None + self._event_system = None + + + def run(self): + """ + Must define regardless if needed and can 'pass' if plugin doesn't need it. + Is intended to be used to setup internal signals or custom Gtk Builders/UI logic. + """ + raise PluginBaseException("Method hasn't been overriden...") + + def generate_reference_ui_element(self): + """ + Requests Key: 'ui_target': "plugin_control_list", + Must define regardless if needed and can 'pass' if plugin doesn't use it. + Must return a widget if "ui_target" is set. + """ + raise PluginBaseException("Method hasn't been overriden...") + + def set_event_system(self, event_system): + """ + Requests Key: 'pass_events': "true" + Must define in plugin if "pass_events" is set to "true" string. + """ + self._event_system = event_system + + def set_ui_object_collection(self, ui_objects): + """ + Requests Key: "pass_ui_objects": [""] + Request reference to a UI component. Will be passed back as array to plugin. + Must define in plugin if set and an array of valid glade UI IDs is given. + """ + self._ui_objects = ui_objects + + def subscribe_to_events(self): + ... + + + def clear_children(self, widget: type) -> None: + """ Clear children of a gtk widget. """ + for child in widget.get_children(): + widget.remove(child) diff --git a/src/plugins/plugins.py b/src/plugins/plugins_controller.py similarity index 74% rename from src/plugins/plugins.py rename to src/plugins/plugins_controller.py index 86d08ea..3c41dd3 100644 --- a/src/plugins/plugins.py +++ b/src/plugins/plugins_controller.py @@ -17,17 +17,15 @@ class InvalidPluginException(Exception): ... -class Plugins: - """Plugins controller""" +class PluginsController: + """PluginsController controller""" - def __init__(self, settings: type): + def __init__(self): path = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, path) # NOTE: I think I'm not using this correctly... - self._settings = settings - self._builder = self._settings.get_builder() - self._plugins_path = self._settings.get_plugins_path() - self._keybindings = self._settings.get_keybindings() + self._builder = settings.get_builder() + self._plugins_path = settings.get_plugins_path() self._plugins_dir_watcher = None self._plugin_collection = [] @@ -72,23 +70,41 @@ class Plugins: def load_plugin_module(self, path, folder, target): os.chdir(path) - spec = importlib.util.spec_from_file_location(folder, target, submodule_search_locations=path) + + locations = [] + self.collect_search_locations(path, locations) + + spec = importlib.util.spec_from_file_location(folder, target, submodule_search_locations = locations) module = importlib.util.module_from_spec(spec) sys.modules[folder] = module spec.loader.exec_module(module) return module + def collect_search_locations(self, path, locations): + locations.append(path) + for file in os.listdir(path): + _path = os.path.join(path, file) + if os.path.isdir(_path): + self.collect_search_locations(_path, locations) def execute_plugin(self, module: type, plugin: Plugin, loading_data: []): plugin.reference = module.Plugin() keys = loading_data.keys() - if "pass_fm_events" in keys: + if "ui_target" in keys: + loading_data["ui_target"].add( plugin.reference.generate_reference_ui_element() ) + loading_data["ui_target"].show_all() + + if "pass_ui_objects" in keys: + plugin.reference.set_ui_object_collection( loading_data["pass_ui_objects"] ) + + if "pass_events" in keys: plugin.reference.set_fm_event_system(event_system) + plugin.reference.subscribe_to_events() if "bind_keys" in keys: - self._keybindings.append_bindings( loading_data["bind_keys"] ) + keybindings.append_bindings( loading_data["bind_keys"] ) plugin.reference.run() self._plugin_collection.append(plugin) diff --git a/src/utils/settings.py b/src/utils/settings.py index b7418c1..ba65b42 100644 --- a/src/utils/settings.py +++ b/src/utils/settings.py @@ -1,18 +1,13 @@ # Python imports -import os, json +import os +import json +import inspect # Gtk imports -import gi, cairo -gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') - -from gi.repository import Gtk -from gi.repository import Gdk - # Application imports from .logger import Logger -from .keybindings import Keybindings + @@ -23,7 +18,7 @@ class Settings: self._CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}" self._PLUGINS_PATH = f"{self._CONFIG_PATH}/plugins" self._GLADE_FILE = f"{self._CONFIG_PATH}/Main_Window.glade" - self._KEY_BINDINGS = f"{self._CONFIG_PATH}/key-bindings.json" + self._KEY_BINDINGS_FILE = f"{self._CONFIG_PATH}/key-bindings.json" self._CSS_FILE = f"{self._CONFIG_PATH}/stylesheet.css" self._DEFAULT_ICONS = f"{self._CONFIG_PATH}/icons" self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png" @@ -36,8 +31,8 @@ class Settings: if not os.path.exists(self._GLADE_FILE): self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade" - if not os.path.exists(self._KEY_BINDINGS): - self._KEY_BINDINGS = f"{self._USR_SOLARFM}/key-bindings.json" + if not os.path.exists(self._KEY_BINDINGS_FILE): + self._KEY_BINDINGS_FILE = f"{self._USR_PATH}/key-bindings.json" if not os.path.exists(self._CSS_FILE): self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css" if not os.path.exists(self._WINDOW_ICON): @@ -57,62 +52,39 @@ class Settings: self._warning_color = "#ffa800" self._error_color = "#ff0000" - self._keybindings = Keybindings() - with open(self._KEY_BINDINGS) as file: - keybindings = json.load(file)["keybindings"] - self._keybindings.configure(keybindings) + with open(self._KEY_BINDINGS_FILE) as file: + bindings = json.load(file)["keybindings"] + keybindings.configure(bindings) - self._main_window = None + self._builder = None self._logger = Logger(self._CONFIG_PATH).get_logger() - self._builder = Gtk.Builder() - self._builder.add_from_file(self._GLADE_FILE) + + self._trace_debug = False + self._debug = False + def get_builder(self) -> any: return self._builder + def set_builder(self, builder) -> any: self._builder = builder + def get_glade_file(self) -> str: return self._GLADE_FILE - def create_window(self) -> None: - # Get window and connect signals - self._main_window = self._builder.get_object("Main_Window") - self.set_window_data() + def register_signals_to_builder(self, classes=None): + handlers = {} - def set_window_data(self) -> None: - self._main_window.set_icon_from_file(self._WINDOW_ICON) - screen = self._main_window.get_screen() - visual = screen.get_rgba_visual() + for c in classes: + methods = None + try: + methods = inspect.getmembers(c, predicate=inspect.ismethod) + handlers.update(methods) + except Exception as e: + print(repr(e)) - if visual != None and screen.is_composited(): - self._main_window.set_visual(visual) - self._main_window.set_app_paintable(True) - self._main_window.connect("draw", self.draw_area) + self._builder.connect_signals(handlers) - # bind css file - cssProvider = Gtk.CssProvider() - cssProvider.load_from_path(self._CSS_FILE) - screen = Gdk.Screen.get_default() - styleContext = Gtk.StyleContext() - styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER) - - def get_monitor_data(self) -> list: - screen = self._builder.get_object("Main_Window").get_screen() - monitors = [] - for m in range(screen.get_n_monitors()): - monitors.append(screen.get_monitor_geometry(m)) - print("{}x{}|{}+{}".format(monitor.width, monitor.height, monitor.x, monitor.y)) - - return monitors - - def draw_area(self, widget, cr): - cr.set_source_rgba(0, 0, 0, 0.54) - cr.set_operator(cairo.OPERATOR_SOURCE) - cr.paint() - cr.set_operator(cairo.OPERATOR_OVER) - - - - def get_main_window(self) -> Gtk.ApplicationWindow: return self._main_window - def get_builder(self) -> Gtk.Builder: return self._builder def get_logger(self) -> Logger: return self._logger - def get_keybindings(self) -> Keybindings: return self._keybindings def get_plugins_path(self) -> str: return self._PLUGINS_PATH + def get_icon_theme(self) -> str: return self._ICON_THEME + def get_css_file(self) -> str: return self._CSS_FILE + def get_window_icon(self) -> str: return self._WINDOW_ICON def get_home_path(self) -> str: return self._USER_HOME # Filter returns @@ -126,3 +98,13 @@ class Settings: def get_success_color(self) -> str: return self._success_color def get_warning_color(self) -> str: return self._warning_color def get_error_color(self) -> str: return self._error_color + + def is_trace_debug(self) -> str: return self._trace_debug + def is_debug(self) -> str: return self._debug + + + def set_trace_debug(self, trace_debug): + self._trace_debug = trace_debug + + def set_debug(self, debug): + self._debug = debug