diff --git a/src/core/controller.py b/src/core/controller.py index a632026..9024c7f 100644 --- a/src/core/controller.py +++ b/src/core/controller.py @@ -9,38 +9,32 @@ from gi.repository import Gdk from gi.repository import GLib # Application imports -from .mixins.dummy_mixin import DummyMixin from .controller_data import ControllerData from .core_widget import CoreWidget +from .mixins.signals_mixins import SignalsMixins - -class Controller(DummyMixin, ControllerData): +class Controller(SignalsMixins, ControllerData): def __init__(self, args, unknownargs): + self.setup_controller_data() + self._setup_styling() self._setup_signals() self._subscribe_to_events() - self.setup_controller_data() - self.print_hello_world() # A mixin method from the DummyMixin file - - logger.info(f"Made it past {self.__class__} loading...") - def _setup_styling(self): ... def _setup_signals(self): - ... - + self.window.connect("focus-out-event", self.unset_keys_and_data) + self.window.connect("key-press-event", self.on_global_key_press_controller) + self.window.connect("key-release-event", self.on_global_key_release_controller) def _subscribe_to_events(self): event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc) - 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()) @@ -53,24 +47,3 @@ class Controller(DummyMixin, ControllerData): 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() - if keyname.replace("_l", "").replace("_r", "") in ["control", "alt", "shift"]: - if "control" in keyname: - self.ctrl_down = False - if "shift" in keyname: - self.shift_down = False - if "alt" in keyname: - self.alt_down = False - - - mapping = keybindings.lookup(event) - if mapping: - getattr(self, mapping)() - return True - else: - print(f"on_global_key_release_controller > key > {keyname}") - print(f"Add logic or remove this from: {self.__class__}") diff --git a/src/core/controller_data.py b/src/core/controller_data.py index 2e59e1a..4068f12 100644 --- a/src/core/controller_data.py +++ b/src/core/controller_data.py @@ -14,12 +14,15 @@ 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.window = settings.get_main_window() - self.builder = None - self.core_widget = None + self.window = settings.get_main_window() + self.builder = None + self.core_widget = None + self.ctrl_down = False + self.shift_down = False + self.alt_down = False self.load_glade_file() - self.plugins = PluginsController() + self.plugins = PluginsController() def clear_console(self) -> None: diff --git a/src/core/mixins/__init__.py b/src/core/mixins/__init__.py index 4589fc7..636992f 100644 --- a/src/core/mixins/__init__.py +++ b/src/core/mixins/__init__.py @@ -1,3 +1,3 @@ """ - Generic Mixins Module + Mixins module """ diff --git a/src/core/mixins/dummy_mixin.py b/src/core/mixins/dummy_mixin.py deleted file mode 100644 index 675bb81..0000000 --- a/src/core/mixins/dummy_mixin.py +++ /dev/null @@ -1,14 +0,0 @@ -# Python imports - -# Lib imports - -# Application imports - - - - -class DummyMixin: - """ DummyMixin is an example of how mixins are used and structured in a project. """ - - def print_hello_world(self) -> None: - print("Hello, World!") diff --git a/src/core/mixins/signals/__init__.py b/src/core/mixins/signals/__init__.py new file mode 100644 index 0000000..03c3ec2 --- /dev/null +++ b/src/core/mixins/signals/__init__.py @@ -0,0 +1,3 @@ +""" + Signals module +""" diff --git a/src/core/mixins/signals/ipc_signals_mixin.py b/src/core/mixins/signals/ipc_signals_mixin.py new file mode 100644 index 0000000..34c6555 --- /dev/null +++ b/src/core/mixins/signals/ipc_signals_mixin.py @@ -0,0 +1,17 @@ +# Python imports + +# Lib imports + +# Application imports + + + + +class IPCSignalsMixin: + """ IPCSignalsMixin handle messages from another starting solarfm process. """ + + def print_to_console(self, message=None): + print(message) + + def handle_file_from_ipc(self, path: str) -> None: + print(f"Path From IPC: {path}") diff --git a/src/core/mixins/signals/keyboard_signals_mixin.py b/src/core/mixins/signals/keyboard_signals_mixin.py new file mode 100644 index 0000000..3b3a4a7 --- /dev/null +++ b/src/core/mixins/signals/keyboard_signals_mixin.py @@ -0,0 +1,74 @@ +# Python imports +import re + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk +from gi.repository import Gdk + +# Application imports + + + +valid_keyvalue_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]") + + + +class KeyboardSignalsMixin: + """ KeyboardSignalsMixin keyboard hooks controller. """ + + # TODO: Need to set methods that use this to somehow check the keybindings state instead. + def unset_keys_and_data(self, widget=None, eve=None): + self.ctrl_down = False + self.shift_down = False + self.alt_down = False + + def on_global_key_press_controller(self, eve, user_data): + keyname = Gdk.keyval_name(user_data.keyval).lower() + if keyname.replace("_l", "").replace("_r", "") in ["control", "alt", "shift"]: + if "control" in keyname: + self.ctrl_down = True + if "shift" in keyname: + self.shift_down = True + if "alt" in keyname: + self.alt_down = True + + def on_global_key_release_controller(self, widget, event): + """ Handler for keyboard events """ + keyname = Gdk.keyval_name(event.keyval).lower() + if keyname.replace("_l", "").replace("_r", "") in ["control", "alt", "shift"]: + if "control" in keyname: + self.ctrl_down = False + if "shift" in keyname: + self.shift_down = False + if "alt" in keyname: + self.alt_down = False + + mapping = keybindings.lookup(event) + if mapping: + # See if in controller scope + try: + getattr(self, mapping)() + return True + except Exception: + # Must be plugins scope, event call, OR we forgot to add method to controller scope + if "||" in mapping: + sender, eve_type = mapping.split("||") + else: + sender = "" + eve_type = mapping + + self.handle_key_event_system(sender, eve_type) + else: + logger.debug(f"on_global_key_release_controller > key > {keyname}") + + if self.ctrl_down: + if not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]: + self.handle_key_event_system(None, mapping) + else: + ... + + def handle_key_event_system(self, sender, eve_type): + event_system.emit(eve_type) diff --git a/src/core/mixins/signals_mixins.py b/src/core/mixins/signals_mixins.py new file mode 100644 index 0000000..76515f6 --- /dev/null +++ b/src/core/mixins/signals_mixins.py @@ -0,0 +1,13 @@ +# Python imports + +# Lib imports +from .signals.ipc_signals_mixin import IPCSignalsMixin +from .signals.keyboard_signals_mixin import KeyboardSignalsMixin + +# Application imports + + + + +class SignalsMixins(KeyboardSignalsMixin, IPCSignalsMixin): + ... diff --git a/src/core/widgets/base/editer_notebook.py b/src/core/widgets/base/editer_notebook.py index 9c8572c..5bd3501 100644 --- a/src/core/widgets/base/editer_notebook.py +++ b/src/core/widgets/base/editer_notebook.py @@ -37,10 +37,15 @@ class EditorNotebook(Gtk.Notebook): event_system.subscribe("set_buffer_style", self.action_controller) event_system.subscribe("set_buffer_language", self.action_controller) event_system.subscribe("set_buffer_style", self.action_controller) + event_system.subscribe("open_files", self._open_files) event_system.subscribe("toggle_highlight_line", self.action_controller) - event_system.subscribe("scale_up_text", self.action_controller) - event_system.subscribe("scale_down_text", self.action_controller) + event_system.subscribe("keyboard_scale_up_text", self._keyboard_scale_up_text) + event_system.subscribe("keyboard_scale_down_text", self._keyboard_scale_down_text) + event_system.subscribe("keyboard_create_tab", self.create_view) + event_system.subscribe("keyboard_close_tab", self._keyboard_close_tab) + def _open_files(self): + print("Open file stub...") def _add_action_widgets(self): start_box = Gtk.Box() @@ -85,18 +90,25 @@ class EditorNotebook(Gtk.Notebook): self.show_all() self.set_current_page(index) - def close_tab(self, button, scroll_view, source_view, eve = None): + def close_tab(self, button, container, source_view, eve = None): if self.get_n_pages() == 1: return - page_num = self.page_num(scroll_view) + page_num = self.page_num(container) watcher = source_view.get_file_watcher() if watcher: watcher.cancel() self.remove_page(page_num) + def _keyboard_close_tab(self): + self.action_controller("close_tab") + def _keyboard_scale_up_text(self): + self.action_controller("scale_up_text") + + def _keyboard_scale_down_text(self): + self.action_controller("scale_down_text") def _text_search(self, widget = None, eve = None): self.action_controller("do_text_search", widget.get_text()) @@ -118,6 +130,8 @@ class EditorNotebook(Gtk.Notebook): self.scale_up_text(source_view) if action == "scale_down_text": self.scale_down_text(source_view) + if action == "close_tab": + self.close_tab(None, container, source_view) def do_text_search(self, query = ""): source_view.scale_down_text() diff --git a/src/utils/keybindings.py b/src/utils/keybindings.py index 790c963..84d4d52 100644 --- a/src/utils/keybindings.py +++ b/src/utils/keybindings.py @@ -12,16 +12,15 @@ from gi.repository import Gdk def err(log = ""): - """Print an error message""" print(log) class KeymapError(Exception): - """Custom exception for errors in keybinding configurations""" + """ Custom exception for errors in keybinding configurations """ MODIFIER = re.compile('<([^<]+)>') class Keybindings: - """Class to handle loading and lookup of Terminator keybindings""" + """ Class to handle loading and lookup of Terminator keybindings """ modifiers = { 'ctrl': Gdk.ModifierType.CONTROL_MASK, @@ -44,12 +43,12 @@ class Keybindings: self.configure({}) def configure(self, bindings): - """Accept new bindings and reconfigure with them""" + """ Accept new bindings and reconfigure with them """ self.keys = bindings self.reload() def reload(self): - """Parse bindings and mangle into an appropriate form""" + """ Parse bindings and mangle into an appropriate form """ self._lookup = {} self._masks = 0 @@ -66,10 +65,10 @@ class Keybindings: try: keyval, mask = self._parsebinding(binding) - # Does much the same, but with poorer error handling. - #keyval, mask = Gtk.accelerator_parse(binding) + # Does much the same, but with worse error handling. + # keyval, mask = Gtk.accelerator_parse(binding) except KeymapError as e: - err ("keybinding reload failed to parse binding '%s': %s" % (binding, e)) + err(f"Keybinding reload failed to parse binding '{binding}': {e}") else: if mask & Gdk.ModifierType.SHIFT_MASK: if keyval == Gdk.KEY_Tab: @@ -88,7 +87,7 @@ class Keybindings: self._masks |= mask def _parsebinding(self, binding): - """Parse an individual binding using Gtk's binding function""" + """ Parse an individual binding using Gtk's binding function """ mask = 0 modifiers = re.findall(MODIFIER, binding) @@ -103,25 +102,25 @@ class Keybindings: keyval = Gdk.keyval_from_name(key) if keyval == 0: - raise KeymapError("Key '%s' is unrecognised..." % key) + raise KeymapError(f"Key '{key}' is unrecognised...") return (keyval, mask) def _lookup_modifier(self, modifier): - """Map modifier names to gtk values""" + """ Map modifier names to gtk values """ try: return self.modifiers[modifier.lower()] except KeyError: - raise KeymapError("Unhandled modifier '<%s>'" % modifier) + raise KeymapError(f"Unhandled modifier '<{modifier}>'") def lookup(self, event): - """Translate a keyboard event into a mapped key""" + """ Translate a keyboard event into a mapped key """ try: _found, keyval, _egp, _lvl, consumed = self.keymap.translate_keyboard_state( event.hardware_keycode, Gdk.ModifierType(event.get_state() & ~Gdk.ModifierType.LOCK_MASK), event.group) except TypeError: - err ("Keybinding lookup failed to translate keyboard event: %s" % dir(event)) + err(f"Keybinding lookup failed to translate keyboard event: {dir(event)}") return None mask = (event.get_state() & ~consumed) & self._masks diff --git a/src/utils/settings/settings.py b/src/utils/settings/settings.py index c3ee5f3..d81a9d4 100644 --- a/src/utils/settings/settings.py +++ b/src/utils/settings/settings.py @@ -66,6 +66,7 @@ class Settings(StartCheckMixin): with open(self._KEY_BINDINGS_FILE) as file: + print(self._KEY_BINDINGS_FILE) bindings = json.load(file)["keybindings"] keybindings.configure(bindings) diff --git a/user_config/usr/share/newton_editor/key-bindings.json b/user_config/usr/share/newton_editor/key-bindings.json index 487bc02..e95106a 100644 --- a/user_config/usr/share/newton_editor/key-bindings.json +++ b/user_config/usr/share/newton_editor/key-bindings.json @@ -1,23 +1,14 @@ { "keybindings": { "help" : "F1", - "rename_files" : ["F2", "e"], "open_terminal" : "F4", - "refresh_tab" : ["F5", "r"], - "delete_files" : "Delete", - "tggl_top_main_menubar" : "", - "trash_files" : "t", + "tggl_top_main_menubar" : "h", "tear_down" : "q", - "go_up" : "Up", - "go_home" : "slash", - "grab_focus_path_entry" : "l", + "toggle_highlight_line" : "h", "open_files" : "o", - "show_hide_hidden_files" : "h", "keyboard_create_tab" : "t", "keyboard_close_tab" : "w", - "keyboard_copy_files" : "c", - "keyboard_cut_files" : "x", - "paste_files" : "v", - "show_new_file_menu" : "n" + "keyboard_scale_up_text" : "equal", + "keyboard_scale_down_text" : "minus" } }