generated from itdominator/Python-With-Gtk-Template
Implimented different settings structure
This commit is contained in:
parent
28c6acc345
commit
e95e37b1bd
@ -9,7 +9,11 @@ from utils.event_system import EventSystem
|
|||||||
from utils.endpoint_registry import EndpointRegistry
|
from utils.endpoint_registry import EndpointRegistry
|
||||||
from utils.keybindings import Keybindings
|
from utils.keybindings import Keybindings
|
||||||
from utils.logger import Logger
|
from utils.logger import Logger
|
||||||
from utils.settings import Settings
|
from utils.settings_manager.manager import SettingsManager
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltinsException(Exception):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -33,10 +37,14 @@ builtins.app_name = "Newton"
|
|||||||
builtins.keybindings = Keybindings()
|
builtins.keybindings = Keybindings()
|
||||||
builtins.event_system = EventSystem()
|
builtins.event_system = EventSystem()
|
||||||
builtins.endpoint_registry = EndpointRegistry()
|
builtins.endpoint_registry = EndpointRegistry()
|
||||||
builtins.settings = Settings()
|
builtins.settings_manager = SettingsManager()
|
||||||
builtins.logger = Logger(settings.get_home_config_path(), \
|
|
||||||
_ch_log_lvl=settings.get_ch_log_lvl(), \
|
settings_manager.load_settings()
|
||||||
_fh_log_lvl=settings.get_fh_log_lvl()).get_logger()
|
|
||||||
|
builtins.settings = settings_manager.settings
|
||||||
|
builtins.logger = Logger(settings_manager.get_home_config_path(), \
|
||||||
|
_ch_log_lvl=settings.debugging.ch_log_lvl, \
|
||||||
|
_fh_log_lvl=settings.debugging.fh_log_lvl).get_logger()
|
||||||
|
|
||||||
builtins.threaded = threaded_wrapper
|
builtins.threaded = threaded_wrapper
|
||||||
builtins.daemon_threaded = daemon_threaded_wrapper
|
builtins.daemon_threaded = daemon_threaded_wrapper
|
||||||
|
@ -40,12 +40,12 @@ if __name__ == "__main__":
|
|||||||
args, unknownargs = parser.parse_known_args()
|
args, unknownargs = parser.parse_known_args()
|
||||||
|
|
||||||
if args.debug == "true":
|
if args.debug == "true":
|
||||||
settings.set_debug(True)
|
settings_manager.set_debug(True)
|
||||||
|
|
||||||
if args.trace_debug == "true":
|
if args.trace_debug == "true":
|
||||||
settings.set_trace_debug(True)
|
settings_manager.set_trace_debug(True)
|
||||||
|
|
||||||
settings.do_dirty_start_check()
|
settings_manager.do_dirty_start_check()
|
||||||
Application(args, unknownargs)
|
Application(args, unknownargs)
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -18,7 +18,7 @@ class Application(IPCServer):
|
|||||||
|
|
||||||
def __init__(self, args, unknownargs):
|
def __init__(self, args, unknownargs):
|
||||||
super(Application, self).__init__()
|
super(Application, self).__init__()
|
||||||
if not settings.is_trace_debug():
|
if not settings_manager.is_trace_debug():
|
||||||
try:
|
try:
|
||||||
self.create_ipc_listener()
|
self.create_ipc_listener()
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -32,4 +32,4 @@ class Application(IPCServer):
|
|||||||
|
|
||||||
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
|
raise AppLaunchException(f"{app_name} IPC Server Exists: Will send path(s) to it and close...")
|
||||||
|
|
||||||
Window(args, unknownargs)
|
Window(args, unknownargs)
|
||||||
|
@ -25,7 +25,7 @@ class Controller(SignalsMixins, ControllerData):
|
|||||||
messages.append(f"FILE|{arg.replace('file://', '')}")
|
messages.append(f"FILE|{arg.replace('file://', '')}")
|
||||||
|
|
||||||
if len(messages) > 0:
|
if len(messages) > 0:
|
||||||
settings.set_is_starting_with_file(True)
|
settings_manager.set_is_starting_with_file(True)
|
||||||
|
|
||||||
self.setup_controller_data()
|
self.setup_controller_data()
|
||||||
|
|
||||||
@ -53,13 +53,13 @@ class Controller(SignalsMixins, ControllerData):
|
|||||||
|
|
||||||
def load_glade_file(self):
|
def load_glade_file(self):
|
||||||
self.builder = Gtk.Builder()
|
self.builder = Gtk.Builder()
|
||||||
self.builder.add_from_file(settings.get_glade_file())
|
self.builder.add_from_file(settings_manager.get_glade_file())
|
||||||
self.builder.expose_object("main_window", self.window)
|
self.builder.expose_object("main_window", self.window)
|
||||||
|
|
||||||
settings.set_builder(self.builder)
|
settings_manager.set_builder(self.builder)
|
||||||
self.core_widget = CoreWidget()
|
self.core_widget = CoreWidget()
|
||||||
|
|
||||||
settings.register_signals_to_builder([self, self.core_widget])
|
settings_manager.register_signals_to_builder([self, self.core_widget])
|
||||||
|
|
||||||
def get_core_widget(self):
|
def get_core_widget(self):
|
||||||
return self.core_widget
|
return self.core_widget
|
||||||
|
@ -14,7 +14,7 @@ class ControllerData:
|
|||||||
''' ControllerData contains most of the state of the app at ay given time. It also has some support methods. '''
|
''' 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:
|
def setup_controller_data(self) -> None:
|
||||||
self.window = settings.get_main_window()
|
self.window = settings_manager.get_main_window()
|
||||||
self.builder = None
|
self.builder = None
|
||||||
self.core_widget = None
|
self.core_widget = None
|
||||||
self.was_midified_key = False
|
self.was_midified_key = False
|
||||||
|
@ -16,7 +16,7 @@ class CoreWidget(Gtk.Box):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CoreWidget, self).__init__()
|
super(CoreWidget, self).__init__()
|
||||||
|
|
||||||
builder = settings.get_builder()
|
builder = settings_manager.get_builder()
|
||||||
builder.expose_object("core_widget", self)
|
builder.expose_object("core_widget", self)
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
|
@ -18,7 +18,7 @@ class GeneralInfoWidget:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(GeneralInfoWidget, self).__init__()
|
super(GeneralInfoWidget, self).__init__()
|
||||||
|
|
||||||
_GLADE_FILE = f"{settings.get_ui_widgets_path()}/general_info_ui.glade"
|
_GLADE_FILE = f"{settings_manager.get_ui_widgets_path()}/general_info_ui.glade"
|
||||||
self._builder = Gtk.Builder()
|
self._builder = Gtk.Builder()
|
||||||
self._builder.add_from_file(_GLADE_FILE)
|
self._builder.add_from_file(_GLADE_FILE)
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class GeneralInfoWidget:
|
|||||||
|
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
builder = settings.get_builder()
|
builder = settings_manager.get_builder()
|
||||||
|
|
||||||
self.bottom_status_info = self._builder.get_object("general_info")
|
self.bottom_status_info = self._builder.get_object("general_info")
|
||||||
self.bottom_path_label = self._builder.get_object("path_label")
|
self.bottom_path_label = self._builder.get_object("path_label")
|
||||||
|
@ -29,7 +29,7 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
|
|||||||
super(EditorNotebook, self).__init__()
|
super(EditorNotebook, self).__init__()
|
||||||
|
|
||||||
self.NAME = f"notebook_{self.ccount}"
|
self.NAME = f"notebook_{self.ccount}"
|
||||||
self.builder = settings.get_builder()
|
self.builder = settings_manager.get_builder()
|
||||||
self.is_editor_focused = False
|
self.is_editor_focused = False
|
||||||
|
|
||||||
self.set_group_name("editor_widget")
|
self.set_group_name("editor_widget")
|
||||||
@ -108,7 +108,7 @@ class EditorNotebook(EditorEventsMixin, EditorControllerMixin, Gtk.Notebook):
|
|||||||
self.set_action_widget(end_box, 1)
|
self.set_action_widget(end_box, 1)
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
if self.NAME == "notebook_1" and not settings.is_starting_with_file():
|
if self.NAME == "notebook_1" and not settings_manager.is_starting_with_file():
|
||||||
self.create_view()
|
self.create_view()
|
||||||
|
|
||||||
def _dbl_click_create_view(self, notebook, eve):
|
def _dbl_click_create_view(self, notebook, eve):
|
||||||
|
@ -44,8 +44,7 @@ class SourceView(SourceViewEventsMixin, GtkSource.View):
|
|||||||
self._file_filter_text = Gtk.FileFilter()
|
self._file_filter_text = Gtk.FileFilter()
|
||||||
self._file_filter_text.set_name("Text Files")
|
self._file_filter_text.set_name("Text Files")
|
||||||
# TODO: Need to externalize to settings file...
|
# TODO: Need to externalize to settings file...
|
||||||
pattern = ["*.txt", "*.py", "*.c", "*.h", "*.cpp", "*.csv", "*.m3*", "*.lua", "*.js", "*.toml", "*.xml", "*.pom", "*.htm", "*.md" "*.vala", "*.tsv", "*.css", "*.html", ".json", "*.java", "*.go", "*.php", "*.ts", "*.rs"]
|
for p in settings.filters.code:
|
||||||
for p in pattern:
|
|
||||||
self._file_filter_text.add_pattern(p)
|
self._file_filter_text.add_pattern(p)
|
||||||
|
|
||||||
self._file_filter_all = Gtk.FileFilter()
|
self._file_filter_all = Gtk.FileFilter()
|
||||||
|
@ -34,17 +34,17 @@ class Window(Gtk.ApplicationWindow):
|
|||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
|
|
||||||
settings.set_main_window(self)
|
settings_manager.set_main_window(self)
|
||||||
self._load_widgets(args, unknownargs)
|
self._load_widgets(args, unknownargs)
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_default_size(settings.get_main_window_width(),
|
self.set_default_size(settings.config.main_window_width,
|
||||||
settings.get_main_window_height())
|
settings.config.main_window_height)
|
||||||
self.set_title(f"{app_name}")
|
self.set_title(f"{app_name}")
|
||||||
self.set_icon_from_file( settings.get_window_icon() )
|
self.set_icon_from_file( settings_manager.get_window_icon() )
|
||||||
self.set_gravity(5) # 5 = CENTER
|
self.set_gravity(5) # 5 = CENTER
|
||||||
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ class Window(Gtk.ApplicationWindow):
|
|||||||
event_system.subscribe("tear_down", self._tear_down)
|
event_system.subscribe("tear_down", self._tear_down)
|
||||||
|
|
||||||
def _load_widgets(self, args, unknownargs):
|
def _load_widgets(self, args, unknownargs):
|
||||||
if settings.is_debug():
|
if settings_manager.is_debug():
|
||||||
self.set_interactive_debugging(True)
|
self.set_interactive_debugging(True)
|
||||||
|
|
||||||
self._controller = Controller(args, unknownargs)
|
self._controller = Controller(args, unknownargs)
|
||||||
@ -76,19 +76,19 @@ class Window(Gtk.ApplicationWindow):
|
|||||||
|
|
||||||
# bind css file
|
# bind css file
|
||||||
cssProvider = Gtk.CssProvider()
|
cssProvider = Gtk.CssProvider()
|
||||||
cssProvider.load_from_path( settings.get_css_file() )
|
cssProvider.load_from_path( settings_manager.get_css_file() )
|
||||||
screen = Gdk.Screen.get_default()
|
screen = Gdk.Screen.get_default()
|
||||||
styleContext = Gtk.StyleContext()
|
styleContext = Gtk.StyleContext()
|
||||||
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||||
|
|
||||||
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
||||||
cr.set_source_rgba( *settings.get_paint_bg_color() )
|
cr.set_source_rgba( *settings_manager.get_paint_bg_color() )
|
||||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||||
cr.paint()
|
cr.paint()
|
||||||
cr.set_operator(cairo.OPERATOR_OVER)
|
cr.set_operator(cairo.OPERATOR_OVER)
|
||||||
|
|
||||||
|
|
||||||
def _tear_down(self, widget=None, eve=None):
|
def _tear_down(self, widget=None, eve=None):
|
||||||
settings.clear_pid()
|
settings_manager.clear_pid()
|
||||||
time.sleep(event_sleep_time)
|
time.sleep(event_sleep_time)
|
||||||
Gtk.main_quit()
|
Gtk.main_quit()
|
||||||
|
@ -30,8 +30,8 @@ class PluginsController:
|
|||||||
path = os.path.dirname(os.path.realpath(__file__))
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
||||||
|
|
||||||
self._builder = settings.get_builder()
|
self._builder = settings_manager.get_builder()
|
||||||
self._plugins_path = settings.get_plugins_path()
|
self._plugins_path = settings_manager.get_plugins_path()
|
||||||
|
|
||||||
self._plugins_dir_watcher = None
|
self._plugins_dir_watcher = None
|
||||||
self._plugin_collection = []
|
self._plugin_collection = []
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
"""
|
|
||||||
Settings module
|
|
||||||
"""
|
|
||||||
from .settings import Settings
|
|
4
src/utils/settings_manager/__init__.py
Normal file
4
src/utils/settings_manager/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
"""
|
||||||
|
Settings module
|
||||||
|
"""
|
||||||
|
from .manager import SettingsManager
|
@ -1,12 +1,20 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
import os
|
import signal
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
import inspect
|
import inspect
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
from os import mkdir
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
from ..singleton import Singleton
|
||||||
from .start_check_mixin import StartCheckMixin
|
from .start_check_mixin import StartCheckMixin
|
||||||
|
from .options.settings import Settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MissingConfigError(Exception):
|
class MissingConfigError(Exception):
|
||||||
@ -14,14 +22,14 @@ class MissingConfigError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Settings(StartCheckMixin):
|
class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._SCRIPT_PTH = os.path.dirname(os.path.realpath(__file__))
|
self._SCRIPT_PTH = path.dirname(path.realpath(__file__))
|
||||||
self._USER_HOME = os.path.expanduser('~')
|
self._USER_HOME = path.expanduser('~')
|
||||||
self._USR_PATH = f"/usr/share/{app_name.lower()}"
|
|
||||||
|
|
||||||
self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
|
||||||
self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}"
|
self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}"
|
||||||
|
self._USR_PATH = f"/usr/share/{app_name.lower()}"
|
||||||
|
self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
||||||
|
|
||||||
self._PLUGINS_PATH = f"{self._HOME_CONFIG_PATH}/plugins"
|
self._PLUGINS_PATH = f"{self._HOME_CONFIG_PATH}/plugins"
|
||||||
self._DEFAULT_ICONS = f"{self._HOME_CONFIG_PATH}/icons"
|
self._DEFAULT_ICONS = f"{self._HOME_CONFIG_PATH}/icons"
|
||||||
self._CONFIG_FILE = f"{self._HOME_CONFIG_PATH}/settings.json"
|
self._CONFIG_FILE = f"{self._HOME_CONFIG_PATH}/settings.json"
|
||||||
@ -33,42 +41,35 @@ class Settings(StartCheckMixin):
|
|||||||
self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json"
|
self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json"
|
||||||
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png"
|
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png"
|
||||||
|
|
||||||
if not os.path.exists(self._HOME_CONFIG_PATH):
|
if not path.exists(self._HOME_CONFIG_PATH):
|
||||||
os.mkdir(self._HOME_CONFIG_PATH)
|
mkdir(self._HOME_CONFIG_PATH)
|
||||||
if not os.path.exists(self._PLUGINS_PATH):
|
if not path.exists(self._PLUGINS_PATH):
|
||||||
os.mkdir(self._PLUGINS_PATH)
|
mkdir(self._PLUGINS_PATH)
|
||||||
|
|
||||||
if not os.path.exists(self._CONFIG_FILE):
|
if not path.exists(self._DEFAULT_ICONS):
|
||||||
import shutil
|
|
||||||
try:
|
|
||||||
shutil.copyfile(self._USR_CONFIG_FILE, self._CONFIG_FILE)
|
|
||||||
except Exception as e:
|
|
||||||
raise
|
|
||||||
|
|
||||||
if not os.path.exists(self._DEFAULT_ICONS):
|
|
||||||
self._DEFAULT_ICONS = f"{self._USR_PATH}/icons"
|
self._DEFAULT_ICONS = f"{self._USR_PATH}/icons"
|
||||||
if not os.path.exists(self._DEFAULT_ICONS):
|
if not path.exists(self._DEFAULT_ICONS):
|
||||||
raise MissingConfigError("Unable to find the application icons directory.")
|
raise MissingConfigError("Unable to find the application icons directory.")
|
||||||
if not os.path.exists(self._GLADE_FILE):
|
if not path.exists(self._GLADE_FILE):
|
||||||
self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade"
|
self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade"
|
||||||
if not os.path.exists(self._GLADE_FILE):
|
if not path.exists(self._GLADE_FILE):
|
||||||
raise MissingConfigError("Unable to find the application Glade file.")
|
raise MissingConfigError("Unable to find the application Glade file.")
|
||||||
if not os.path.exists(self._KEY_BINDINGS_FILE):
|
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||||
self._KEY_BINDINGS_FILE = f"{self._USR_PATH}/key-bindings.json"
|
self._KEY_BINDINGS_FILE = f"{self._USR_PATH}/key-bindings.json"
|
||||||
if not os.path.exists(self._KEY_BINDINGS_FILE):
|
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||||
raise MissingConfigError("Unable to find the application Keybindings file.")
|
raise MissingConfigError("Unable to find the application Keybindings file.")
|
||||||
if not os.path.exists(self._CSS_FILE):
|
if not path.exists(self._CSS_FILE):
|
||||||
self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css"
|
self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css"
|
||||||
if not os.path.exists(self._CSS_FILE):
|
if not path.exists(self._CSS_FILE):
|
||||||
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
||||||
if not os.path.exists(self._WINDOW_ICON):
|
if not path.exists(self._WINDOW_ICON):
|
||||||
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{app_name.lower()}.png"
|
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{app_name.lower()}.png"
|
||||||
if not os.path.exists(self._WINDOW_ICON):
|
if not path.exists(self._WINDOW_ICON):
|
||||||
raise MissingConfigError("Unable to find the application icon.")
|
raise MissingConfigError("Unable to find the application icon.")
|
||||||
if not os.path.exists(self._UI_WIDEGTS_PATH):
|
if not path.exists(self._UI_WIDEGTS_PATH):
|
||||||
self._UI_WIDEGTS_PATH = f"{self._USR_PATH}/ui_widgets"
|
self._UI_WIDEGTS_PATH = f"{self._USR_PATH}/ui_widgets"
|
||||||
if not os.path.exists(self._CONTEXT_MENU):
|
if not path.exists(self._CONTEXT_MENU):
|
||||||
self._CONTEXT_MENU = f"{self._USR_PATH}/contexct_menu.json"
|
self._CONTEXT_MENU = f"{self._USR_PATH}/contexct_menu.json"
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -85,18 +86,15 @@ class Settings(StartCheckMixin):
|
|||||||
print( f"Settings: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
print( f"Settings: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
||||||
|
|
||||||
|
|
||||||
self._main_window = None
|
self.settings: Settings = None
|
||||||
self._main_window_w = 800
|
self._main_window = None
|
||||||
self._main_window_h = 600
|
self._builder = None
|
||||||
self._builder = None
|
self.PAINT_BG_COLOR = (0, 0, 0, 0.0)
|
||||||
self.PAINT_BG_COLOR = (0, 0, 0, 0.54)
|
|
||||||
|
|
||||||
self._trace_debug = False
|
self._trace_debug = False
|
||||||
self._debug = False
|
self._debug = False
|
||||||
self._dirty_start = False
|
self._dirty_start = False
|
||||||
self._passed_in_file = False
|
self._passed_in_file = False
|
||||||
|
|
||||||
self.load_settings()
|
|
||||||
|
|
||||||
|
|
||||||
def register_signals_to_builder(self, classes=None):
|
def register_signals_to_builder(self, classes=None):
|
||||||
@ -126,13 +124,11 @@ class Settings(StartCheckMixin):
|
|||||||
return monitors
|
return monitors
|
||||||
|
|
||||||
def get_main_window(self) -> any: return self._main_window
|
def get_main_window(self) -> any: return self._main_window
|
||||||
def get_main_window_width(self) -> any: return self._main_window_w
|
def get_builder(self) -> any: return self._builder
|
||||||
def get_main_window_height(self) -> any: return self._main_window_h
|
def get_paint_bg_color(self) -> any: return self.PAINT_BG_COLOR
|
||||||
def get_builder(self) -> any: return self._builder
|
def get_glade_file(self) -> str: return self._GLADE_FILE
|
||||||
def get_paint_bg_color(self) -> any: return self.PAINT_BG_COLOR
|
def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH
|
||||||
def get_glade_file(self) -> str: return self._GLADE_FILE
|
def get_context_menu_data(self) -> str: return self._context_menu_data
|
||||||
def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH
|
|
||||||
|
|
||||||
|
|
||||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||||
def get_icon_theme(self) -> str: return self._ICON_THEME
|
def get_icon_theme(self) -> str: return self._ICON_THEME
|
||||||
@ -141,24 +137,21 @@ class Settings(StartCheckMixin):
|
|||||||
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
||||||
def get_home_path(self) -> str: return self._USER_HOME
|
def get_home_path(self) -> str: return self._USER_HOME
|
||||||
|
|
||||||
# Filter returns
|
|
||||||
def get_office_filter(self) -> tuple: return tuple(self._settings["filters"]["office"])
|
|
||||||
def get_vids_filter(self) -> tuple: return tuple(self._settings["filters"]["videos"])
|
|
||||||
def get_text_filter(self) -> tuple: return tuple(self._settings["filters"]["text"])
|
|
||||||
def get_music_filter(self) -> tuple: return tuple(self._settings["filters"]["music"])
|
|
||||||
def get_images_filter(self) -> tuple: return tuple(self._settings["filters"]["images"])
|
|
||||||
def get_pdf_filter(self) -> tuple: return tuple(self._settings["filters"]["pdf"])
|
|
||||||
|
|
||||||
def get_success_color(self) -> str: return self._theming["success_color"]
|
|
||||||
def get_warning_color(self) -> str: return self._theming["warning_color"]
|
|
||||||
def get_error_color(self) -> str: return self._theming["error_color"]
|
|
||||||
|
|
||||||
def is_trace_debug(self) -> str: return self._trace_debug
|
def is_trace_debug(self) -> str: return self._trace_debug
|
||||||
def is_debug(self) -> str: return self._debug
|
def is_debug(self) -> str: return self._debug
|
||||||
def is_starting_with_file(self) -> bool: return self._passed_in_file
|
def is_starting_with_file(self) -> bool: return self._passed_in_file
|
||||||
|
|
||||||
def get_ch_log_lvl(self) -> str: return self._settings["debugging"]["ch_log_lvl"]
|
def call_method(self, target_class = None, _method_name = None, data = None):
|
||||||
def get_fh_log_lvl(self) -> str: return self._settings["debugging"]["fh_log_lvl"]
|
method_name = str(_method_name)
|
||||||
|
method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}")
|
||||||
|
return method(data) if data else method()
|
||||||
|
|
||||||
|
def set_main_window_x(self, x = 0): self.settings.config.window_x = x
|
||||||
|
def set_main_window_y(self, y = 0): self.settings.config.window_y = y
|
||||||
|
def set_main_window_width(self, width = 800): self.settings.config.window_width = width
|
||||||
|
def set_main_window_height(self, height = 600): self.settings.config.window_height = height
|
||||||
|
def set_main_window_min_width(self, width = 720): self.settings.config.window_min_width = width
|
||||||
|
def set_main_window_min_height(self, height = 480): self.settings.config.window_min_height = height
|
||||||
|
|
||||||
def set_trace_debug(self, trace_debug):
|
def set_trace_debug(self, trace_debug):
|
||||||
self._trace_debug = trace_debug
|
self._trace_debug = trace_debug
|
||||||
@ -171,11 +164,15 @@ class Settings(StartCheckMixin):
|
|||||||
|
|
||||||
|
|
||||||
def load_settings(self):
|
def load_settings(self):
|
||||||
with open(self._CONFIG_FILE) as f:
|
if not path.exists(self._CONFIG_FILE):
|
||||||
self._settings = json.load(f)
|
self.settings = Settings()
|
||||||
self._config = self._settings["config"]
|
return
|
||||||
self._theming = self._settings["theming"]
|
|
||||||
|
with open(self._CONFIG_FILE) as file:
|
||||||
|
data = json.load(file)
|
||||||
|
data["load_defaults"] = False
|
||||||
|
self.settings = Settings(**data)
|
||||||
|
|
||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
with open(self._CONFIG_FILE, 'w') as outfile:
|
with open(self._CONFIG_FILE, 'w') as outfile:
|
||||||
json.dump(self._settings, outfile, separators=(',', ':'), indent=4)
|
json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4)
|
8
src/utils/settings_manager/options/__init__.py
Normal file
8
src/utils/settings_manager/options/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Options module
|
||||||
|
"""
|
||||||
|
from .settings import Settings
|
||||||
|
from .config import Config
|
||||||
|
from .filters import Filters
|
||||||
|
from .theming import Theming
|
||||||
|
from .debugging import Debugging
|
35
src/utils/settings_manager/options/config.py
Normal file
35
src/utils/settings_manager/options/config.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Config:
|
||||||
|
base_of_home: str = ""
|
||||||
|
hide_hidden_files: str = "true"
|
||||||
|
thumbnailer_path: str = "ffmpegthumbnailer"
|
||||||
|
blender_thumbnailer_path: str = ""
|
||||||
|
go_past_home: str = "true"
|
||||||
|
lock_folder: str = "false"
|
||||||
|
locked_folders: list = field(default_factory=lambda: [ "venv", "flasks" ])
|
||||||
|
mplayer_options: str = "-quiet -really-quiet -xy 1600 -geometry 50%:50%",
|
||||||
|
music_app: str = "/opt/deadbeef/bin/deadbeef"
|
||||||
|
media_app: str = "mpv"
|
||||||
|
image_app: str = "mirage"
|
||||||
|
office_app: str = "libreoffice"
|
||||||
|
pdf_app: str = "evince"
|
||||||
|
code_app: str = "atom"
|
||||||
|
text_app: str = "leafpad"
|
||||||
|
file_manager_app: str = "solarfm"
|
||||||
|
terminal_app: str = "terminator"
|
||||||
|
remux_folder_max_disk_usage: str = "8589934592"
|
||||||
|
make_transparent: int = 0
|
||||||
|
main_window_x: int = 721
|
||||||
|
main_window_y: int = 465
|
||||||
|
main_window_min_width: int = 720
|
||||||
|
main_window_min_height: int = 480
|
||||||
|
main_window_width: int = 800
|
||||||
|
main_window_height: int = 600
|
12
src/utils/settings_manager/options/debugging.py
Normal file
12
src/utils/settings_manager/options/debugging.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Debugging:
|
||||||
|
ch_log_lvl: int = 10
|
||||||
|
fh_log_lvl: int = 20
|
90
src/utils/settings_manager/options/filters.py
Normal file
90
src/utils/settings_manager/options/filters.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Filters:
|
||||||
|
meshs: list = field(default_factory=lambda: [
|
||||||
|
".blend",
|
||||||
|
".dae",
|
||||||
|
".fbx",
|
||||||
|
".gltf",
|
||||||
|
".obj",
|
||||||
|
".stl"
|
||||||
|
])
|
||||||
|
code: list = field(default_factory=lambda: [
|
||||||
|
".txt",
|
||||||
|
".py",
|
||||||
|
".c",
|
||||||
|
".h",
|
||||||
|
".cpp",
|
||||||
|
".csv",
|
||||||
|
".m3*",
|
||||||
|
".lua",
|
||||||
|
".js",
|
||||||
|
".toml",
|
||||||
|
".xml",
|
||||||
|
".pom",
|
||||||
|
".htm",
|
||||||
|
".md",
|
||||||
|
".vala",
|
||||||
|
".tsv",
|
||||||
|
".css",
|
||||||
|
".html",
|
||||||
|
".json",
|
||||||
|
".java",
|
||||||
|
".go",
|
||||||
|
".php",
|
||||||
|
".ts",
|
||||||
|
".rs"
|
||||||
|
])
|
||||||
|
videos: list = field(default_factory=lambda:[
|
||||||
|
".mkv",
|
||||||
|
".mp4",
|
||||||
|
".webm",
|
||||||
|
".avi",
|
||||||
|
".mov",
|
||||||
|
".m4v",
|
||||||
|
".mpg",
|
||||||
|
".mpeg",
|
||||||
|
".wmv",
|
||||||
|
".flv"
|
||||||
|
])
|
||||||
|
office: list = field(default_factory=lambda: [
|
||||||
|
".doc",
|
||||||
|
".docx",
|
||||||
|
".xls",
|
||||||
|
".xlsx",
|
||||||
|
".xlt",
|
||||||
|
".xltx",
|
||||||
|
".xlm",
|
||||||
|
".ppt",
|
||||||
|
".pptx",
|
||||||
|
".pps",
|
||||||
|
".ppsx",
|
||||||
|
".odt",
|
||||||
|
".rtf"
|
||||||
|
])
|
||||||
|
images: list = field(default_factory=lambda: [
|
||||||
|
".png",
|
||||||
|
".jpg",
|
||||||
|
".jpeg",
|
||||||
|
".gif",
|
||||||
|
".ico",
|
||||||
|
".tga",
|
||||||
|
".webp"
|
||||||
|
])
|
||||||
|
music: list = field(default_factory=lambda: [
|
||||||
|
".psf",
|
||||||
|
".mp3",
|
||||||
|
".ogg",
|
||||||
|
".flac",
|
||||||
|
".m4a"
|
||||||
|
])
|
||||||
|
pdf: list = field(default_factory=lambda: [
|
||||||
|
".pdf"
|
||||||
|
])
|
31
src/utils/settings_manager/options/settings.py
Normal file
31
src/utils/settings_manager/options/settings.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from dataclasses import asdict
|
||||||
|
|
||||||
|
# Gtk imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .config import Config
|
||||||
|
from .filters import Filters
|
||||||
|
from .theming import Theming
|
||||||
|
from .debugging import Debugging
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Settings:
|
||||||
|
load_defaults: bool = True
|
||||||
|
config: Config = field(default_factory=lambda: Config())
|
||||||
|
filters: Filters = field(default_factory=lambda: Filters())
|
||||||
|
theming: Theming = field(default_factory=lambda: Theming())
|
||||||
|
debugging: Debugging = field(default_factory=lambda: Debugging())
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
if not self.load_defaults:
|
||||||
|
self.load_defaults = False
|
||||||
|
self.config = Config(**self.config)
|
||||||
|
self.filters = Filters(**self.filters)
|
||||||
|
self.theming = Theming(**self.theming)
|
||||||
|
self.debugging = Debugging(**self.debugging)
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
return asdict(self)
|
13
src/utils/settings_manager/options/theming.py
Normal file
13
src/utils/settings_manager/options/theming.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Theming:
|
||||||
|
success_color: str = "#88cc27"
|
||||||
|
warning_color: str = "#ffa800"
|
||||||
|
error_color: str = "#ff0000"
|
@ -41,6 +41,7 @@ class StartCheckMixin:
|
|||||||
def _write_new_pid(self):
|
def _write_new_pid(self):
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
self._write_pid(pid)
|
self._write_pid(pid)
|
||||||
|
print(f"{app_name} PID: {pid}")
|
||||||
|
|
||||||
def _clean_pid(self):
|
def _clean_pid(self):
|
||||||
os.unlink(self._PID_FILE)
|
os.unlink(self._PID_FILE)
|
@ -1,40 +1,121 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"load_defaults":false,
|
||||||
"base_of_home": "",
|
"config":{
|
||||||
"hide_hidden_files": "true",
|
"base_of_home":"",
|
||||||
"thumbnailer_path": "ffmpegthumbnailer",
|
"hide_hidden_files":"true",
|
||||||
"go_past_home": "true",
|
"thumbnailer_path":"ffmpegthumbnailer",
|
||||||
"lock_folder": "false",
|
"blender_thumbnailer_path":"",
|
||||||
"locked_folders": "venv::::flasks",
|
"go_past_home":"true",
|
||||||
"mplayer_options": "-quiet -really-quiet -xy 1600 -geometry 50%:50%",
|
"lock_folder":"false",
|
||||||
"music_app": "/opt/deadbeef/bin/deadbeef",
|
"locked_folders":"venv::::flasks",
|
||||||
"media_app": "mpv",
|
"mplayer_options":"-quiet -really-quiet -xy 1600 -geometry 50%:50%",
|
||||||
"image_app": "mirage",
|
"music_app":"/opt/deadbeef/bin/deadbeef",
|
||||||
"office_app": "libreoffice",
|
"media_app":"mpv",
|
||||||
"pdf_app": "evince",
|
"image_app":"mirage",
|
||||||
"text_app": "leafpad",
|
"office_app":"libreoffice",
|
||||||
"file_manager_app": "solarfm",
|
"pdf_app":"evince",
|
||||||
"terminal_app": "terminator",
|
"code_app":"atom",
|
||||||
"remux_folder_max_disk_usage": "8589934592"
|
"text_app":"leafpad",
|
||||||
|
"file_manager_app":"solarfm",
|
||||||
|
"terminal_app":"terminator",
|
||||||
|
"remux_folder_max_disk_usage":"8589934592",
|
||||||
|
"make_transparent":0,
|
||||||
|
"main_window_x":721,
|
||||||
|
"main_window_y":465,
|
||||||
|
"main_window_min_width":720,
|
||||||
|
"main_window_min_height":480,
|
||||||
|
"main_window_width":800,
|
||||||
|
"main_window_height":600
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters":{
|
||||||
"meshs": [".blend", ".dae", ".fbx", ".gltf", ".obj", ".stl"],
|
"meshs":[
|
||||||
"code": [".cpp", ".css", ".c", ".go", ".html", ".htm", ".java", ".js", ".json", ".lua", ".md", ".py", ".rs", ".toml", ".xml", ".pom"],
|
".blend",
|
||||||
"videos": [".mkv", ".mp4", ".webm", ".avi", ".mov", ".m4v", ".mpg", ".mpeg", ".wmv", ".flv"],
|
".dae",
|
||||||
"office": [".doc", ".docx", ".xls", ".xlsx", ".xlt", ".xltx", ".xlm", ".ppt", ".pptx", ".pps", ".ppsx", ".odt", ".rtf"],
|
".fbx",
|
||||||
"images": [".png", ".jpg", ".jpeg", ".gif", ".ico", ".tga", ".webp"],
|
".gltf",
|
||||||
"text": [".txt", ".text", ".sh", ".cfg", ".conf", ".log"],
|
".obj",
|
||||||
"music": [".psf", ".mp3", ".ogg", ".flac", ".m4a"],
|
".stl"
|
||||||
"pdf": [".pdf"]
|
],
|
||||||
|
"code":[
|
||||||
},
|
".txt",
|
||||||
"theming":{
|
".py",
|
||||||
"success_color":"#88cc27",
|
".c",
|
||||||
"warning_color":"#ffa800",
|
".h",
|
||||||
"error_color":"#ff0000"
|
".cpp",
|
||||||
},
|
".csv",
|
||||||
"debugging": {
|
".m3*",
|
||||||
"ch_log_lvl": 10,
|
".lua",
|
||||||
"fh_log_lvl": 20
|
".js",
|
||||||
}
|
".toml",
|
||||||
|
".xml",
|
||||||
|
".pom",
|
||||||
|
".htm",
|
||||||
|
".md",
|
||||||
|
".vala",
|
||||||
|
".tsv",
|
||||||
|
".css",
|
||||||
|
".html",
|
||||||
|
".json",
|
||||||
|
".java",
|
||||||
|
".go",
|
||||||
|
".php",
|
||||||
|
".ts",
|
||||||
|
".rs"
|
||||||
|
],
|
||||||
|
"videos":[
|
||||||
|
".mkv",
|
||||||
|
".mp4",
|
||||||
|
".webm",
|
||||||
|
".avi",
|
||||||
|
".mov",
|
||||||
|
".m4v",
|
||||||
|
".mpg",
|
||||||
|
".mpeg",
|
||||||
|
".wmv",
|
||||||
|
".flv"
|
||||||
|
],
|
||||||
|
"office":[
|
||||||
|
".doc",
|
||||||
|
".docx",
|
||||||
|
".xls",
|
||||||
|
".xlsx",
|
||||||
|
".xlt",
|
||||||
|
".xltx",
|
||||||
|
".xlm",
|
||||||
|
".ppt",
|
||||||
|
".pptx",
|
||||||
|
".pps",
|
||||||
|
".ppsx",
|
||||||
|
".odt",
|
||||||
|
".rtf"
|
||||||
|
],
|
||||||
|
"images":[
|
||||||
|
".png",
|
||||||
|
".jpg",
|
||||||
|
".jpeg",
|
||||||
|
".gif",
|
||||||
|
".ico",
|
||||||
|
".tga",
|
||||||
|
".webp"
|
||||||
|
],
|
||||||
|
"music":[
|
||||||
|
".psf",
|
||||||
|
".mp3",
|
||||||
|
".ogg",
|
||||||
|
".flac",
|
||||||
|
".m4a"
|
||||||
|
],
|
||||||
|
"pdf":[
|
||||||
|
".pdf"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"theming":{
|
||||||
|
"success_color":"#88cc27",
|
||||||
|
"warning_color":"#ffa800",
|
||||||
|
"error_color":"#ff0000"
|
||||||
|
},
|
||||||
|
"debugging":{
|
||||||
|
"ch_log_lvl":10,
|
||||||
|
"fh_log_lvl":20
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,89 +1,5 @@
|
|||||||
/* Set fm to have transparent window */
|
/* Set fm to have transparent window */
|
||||||
box,
|
* {
|
||||||
iconview,
|
background: rgba(39, 43, 52, 0.24);
|
||||||
notebook,
|
|
||||||
paned,
|
|
||||||
stack,
|
|
||||||
scrolledwindow,
|
|
||||||
treeview.view,
|
|
||||||
.content-view,
|
|
||||||
.view {
|
|
||||||
background: rgba(19, 21, 25, 0.14);
|
|
||||||
color: rgba(255, 255, 255, 1);
|
color: rgba(255, 255, 255, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
notebook > header > tabs > tab:checked {
|
|
||||||
/* Neon Blue 00e8ff */
|
|
||||||
background-color: rgba(0, 232, 255, 0.2);
|
|
||||||
/* Dark Bergundy */
|
|
||||||
/* background-color: rgba(116, 0, 0, 0.25); */
|
|
||||||
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#message_view {
|
|
||||||
font: 16px "Monospace";
|
|
||||||
}
|
|
||||||
|
|
||||||
.view:selected,
|
|
||||||
.view:selected:hover {
|
|
||||||
box-shadow: inset 0 0 0 9999px rgba(21, 158, 167, 0.34);
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-border {
|
|
||||||
border: 2px solid rgba(116, 0, 0, 0.64);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-border {
|
|
||||||
border: 2px solid rgba(136, 204, 39, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.notebook-selected-focus {
|
|
||||||
/* Neon Blue 00e8ff border */
|
|
||||||
border: 2px solid rgba(0, 232, 255, 0.34);
|
|
||||||
/* Dark Bergundy */
|
|
||||||
/* border: 2px solid rgba(116, 0, 0, 0.64); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.notebook-unselected-focus {
|
|
||||||
/* Neon Blue 00e8ff border */
|
|
||||||
/* border: 2px solid rgba(0, 232, 255, 0.25); */
|
|
||||||
/* Dark Bergundy */
|
|
||||||
/* border: 2px solid rgba(116, 0, 0, 0.64); */
|
|
||||||
/* Snow White */
|
|
||||||
border: 2px solid rgba(255, 255, 255, 0.24);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.sourceview > * {
|
|
||||||
background-color: rgba(0, 0, 0, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* * {
|
|
||||||
background: rgba(0, 0, 0, 0.14);
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* * selection {
|
|
||||||
background-color: rgba(116, 0, 0, 0.65);
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* Rubberband coloring */
|
|
||||||
/* .rubberband,
|
|
||||||
rubberband,
|
|
||||||
flowbox rubberband,
|
|
||||||
treeview.view rubberband,
|
|
||||||
.content-view rubberband,
|
|
||||||
.content-view .rubberband,
|
|
||||||
XfdesktopIconView.view .rubberband {
|
|
||||||
border: 1px solid #6c6c6c;
|
|
||||||
background-color: rgba(21, 158, 167, 0.57);
|
|
||||||
}
|
|
||||||
|
|
||||||
XfdesktopIconView.view:active {
|
|
||||||
background-color: rgba(172, 102, 21, 1);
|
|
||||||
} */
|
|
Loading…
Reference in New Issue
Block a user