From 9c2b52009a770eb4cc471a39e71d14e2c1ff355d Mon Sep 17 00:00:00 2001 From: alfrix Date: Mon, 18 Jul 2022 20:19:39 -0300 Subject: [PATCH] built-in keyboard --- ks_includes/widgets/keyboard.py | 110 +++++++++++++++++++++++++++++++ panels/bed_mesh.py | 7 +- panels/console.py | 5 +- panels/network.py | 5 +- screen.py | 68 +++++++++++-------- styles/base.css | 10 +++ styles/colorized/style.css | 4 ++ styles/material-dark/style.css | 6 +- styles/material-darker/style.css | 5 ++ styles/material-light/style.css | 7 +- styles/z-bolt/style.css | 4 ++ 11 files changed, 197 insertions(+), 34 deletions(-) create mode 100644 ks_includes/widgets/keyboard.py diff --git a/ks_includes/widgets/keyboard.py b/ks_includes/widgets/keyboard.py new file mode 100644 index 00000000..3b172fa0 --- /dev/null +++ b/ks_includes/widgets/keyboard.py @@ -0,0 +1,110 @@ +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GLib + + +class Keyboard(Gtk.Box): + def __init__(self, screen, close_cb, entry=None): + super().__init__(orientation=Gtk.Orientation.VERTICAL) + _ = screen.lang.gettext + self._gtk = screen.gtk + self.close_cb = close_cb + self.keyboard = Gtk.Grid() + self.keyboard.set_direction(Gtk.TextDirection.LTR) + self.timeout = self.clear_timeout = None + self.entry = entry + + self.keys = [ + [["q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "⌫"], + ["a", "s", "d", "f", "g", "h", "j", "k", "l", "'"], + ["ABC", "z", "x", "c", "v", "b", "n", "m", ",", ".", "?123"], + ["✕", " ", "✔"] + ], + [["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "⌫"], + ["A", "S", "D", "F", "G", "H", "J", "K", "L", "'"], + ["?123", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "abc"], + ["✕", " ", "✔"] + ], + [["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "⌫"], + ["=", "-", "+", "*", "/", "\\", ":", ";", "'", "\""], + ["abc", "(", ")", "#", "$", "!", "?", "@", "_", ",", "ABC"], + ["✕", " ", "✔"] + ] + ] + + self.labels = self.keys.copy() + for p, pallet in enumerate(self.keys): + for r, row in enumerate(pallet): + for k, key in enumerate(row): + self.labels[p][r][k] = self._gtk.Button(key) + self.labels[p][r][k].set_hexpand(True) + self.labels[p][r][k].set_vexpand(True) + self.labels[p][r][k].connect('button-press-event', self.repeat, key) + self.labels[p][r][k].connect('button-release-event', self.release) + self.labels[p][r][k].get_style_context().add_class("keyboard_pad") + + self.pallet_nr = 0 + self.set_pallet(self.pallet_nr) + self.add(self.keyboard) + + def set_pallet(self, p): + pallet = self.keys[p] + span = 2 + for r, row in enumerate(pallet[:-1]): + for k, key in enumerate(row): + x = k * 2 + 1 if r == 1 else k * 2 + old = self.keyboard.get_child_at(x, r) + if old: + self.keyboard.remove(old) + self.keyboard.attach(self.labels[p][r][k], x, r, span, 1) + if not self.keyboard.get_child_at(0, 4): + self.keyboard.attach(self.labels[p][3][0], 0, 4, 3, 1) + self.keyboard.attach(self.labels[p][3][1], 3, 4, 16, 1) + self.keyboard.attach(self.labels[p][3][2], 19, 4, 3, 1) + self.show_all() + + def repeat(self, widget, event, key): + # Button-press + self.update_entry(widget, key) + if self.timeout is None and key == "⌫": + # Hold for repeat, hold longer to clear the field + self.clear_timeout = GLib.timeout_add_seconds(3, self.clear, widget) + # This can be used to repeat all the keys, + # but I don't find it useful on the console + self.timeout = GLib.timeout_add(400, self.repeat, widget, None, key) + return True + + def release(self, widget, event): + # Button-release + if self.timeout is not None: + GLib.source_remove(self.timeout) + self.timeout = None + if self.clear_timeout is not None: + GLib.source_remove(self.clear_timeout) + self.clear_timeout = None + + def clear(self, widget=None): + self.entry.set_text("") + if self.clear_timeout is not None: + GLib.source_remove(self.clear_timeout) + self.clear_timeout = None + + def update_entry(self, widget, key): + if key == "⌫": + Gtk.Entry.do_backspace(self.entry) + elif key == "✔": + self.close_cb() + return + elif key == "✕": + self.clear() + self.close_cb() + return + elif key == "abc": + self.set_pallet(0) + elif key == "ABC": + self.set_pallet(1) + elif key == "?123": + self.set_pallet(2) + else: + Gtk.Entry.do_insert_at_cursor(self.entry, key) diff --git a/panels/bed_mesh.py b/panels/bed_mesh.py index ed16cb3c..c0054a6d 100644 --- a/panels/bed_mesh.py +++ b/panels/bed_mesh.py @@ -227,7 +227,7 @@ class BedMeshPanel(ScreenPanel): self.labels['profile_name'].set_text('') self.labels['profile_name'].set_hexpand(True) self.labels['profile_name'].connect("activate", self.create_profile) - self.labels['profile_name'].connect("focus-in-event", self._screen.show_keyboard) + self.labels['profile_name'].connect("focus-in-event", self._show_keyboard) self.labels['profile_name'].grab_focus_without_selecting() save = self._gtk.ButtonImage("complete", _("Save"), "color3") @@ -246,9 +246,12 @@ class BedMeshPanel(ScreenPanel): self.labels['create_profile'].pack_start(box, True, True, 5) self.content.add(self.labels['create_profile']) - self._screen.show_keyboard() + self._show_keyboard() self.show_create = True + def _show_keyboard(self, widget=None, event=None): + self._screen.show_keyboard(entry=self.labels['profile_name']) + def show_mesh(self, widget, profile): bm = self._printer.get_config_section(f"bed_mesh {profile}") diff --git a/panels/console.py b/panels/console.py index 6bc5f406..81a6aacc 100644 --- a/panels/console.py +++ b/panels/console.py @@ -80,7 +80,7 @@ class ConsolePanel(ScreenPanel): entry = Gtk.Entry() entry.set_hexpand(True) entry.set_vexpand(False) - entry.connect("button-press-event", self._screen.show_keyboard) + entry.connect("button-press-event", self._show_keyboard) entry.connect("focus-in-event", self._screen.show_keyboard) entry.connect("activate", self._send_command) entry.grab_focus_without_selecting() @@ -105,6 +105,9 @@ class ConsolePanel(ScreenPanel): content_box.pack_end(ebox, False, False, 0) self.content.add(content_box) + def _show_keyboard(self, widget=None, event=None): + self._screen.show_keyboard(entry=self.labels['entry']) + def clear(self, widget): self.labels['tb'].set_text("") diff --git a/panels/network.py b/panels/network.py index c34cf069..bc0df12c 100644 --- a/panels/network.py +++ b/panels/network.py @@ -351,7 +351,7 @@ class NetworkPanel(ScreenPanel): self.labels['network_psk'].set_text('') self.labels['network_psk'].set_hexpand(True) self.labels['network_psk'].connect("activate", self.add_new_network, ssid, True) - self.labels['network_psk'].connect("focus-in-event", self._screen.show_keyboard) + self.labels['network_psk'].connect("focus-in-event", self._show_keyboard) self.labels['network_psk'].grab_focus_without_selecting() save = self._gtk.ButtonImage("sd", _("Save"), "color3") @@ -374,6 +374,9 @@ class NetworkPanel(ScreenPanel): self.content.show_all() self.show_add = True + def _show_keyboard(self, widget=None, event=None): + self._screen.show_keyboard(entry=self.labels['network_psk']) + def update_all_networks(self): for network in list(self.networks): self.update_network_info(network) diff --git a/screen.py b/screen.py index 396f6f72..edba2382 100644 --- a/screen.py +++ b/screen.py @@ -23,7 +23,7 @@ from ks_includes.KlippyRest import KlippyRest from ks_includes.files import KlippyFiles from ks_includes.KlippyGtk import KlippyGtk from ks_includes.printer import Printer - +from ks_includes.widgets.keyboard import Keyboard from ks_includes.config import KlipperScreenConfig from panels.base_panel import BasePanel @@ -1020,47 +1020,59 @@ class KlipperScreen(Gtk.Window): self.show_panel('job_status', "job_status", "Print Status", 2) self.base_panel.show_heaters(True) - def show_keyboard(self, widget=None, event=None): + def show_keyboard(self, widget=None, event=None, entry=None): if self.keyboard is not None: return - env = os.environ.copy() - usrkbd = "/home/pi/.matchbox/keyboard.xml" - if os.path.isfile(usrkbd): - env["MB_KBD_CONFIG"] = usrkbd - else: - env["MB_KBD_CONFIG"] = "ks_includes/locales/keyboard.xml" - p = subprocess.Popen(["matchbox-keyboard", "--xid"], stdout=subprocess.PIPE, - stderr=subprocess.PIPE, env=env) - - xid = int(p.stdout.readline()) - logging.debug(f"XID {xid}") - logging.debug(f"PID {p.pid}") - keyboard = Gtk.Socket() - box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) box.set_size_request(self.gtk.get_content_width(), self.gtk.get_keyboard_height()) + + if self._config.get_main_config().getboolean("use-matchbox-keyboard", False): + env = os.environ.copy() + usrkbd = os.path.expanduser("~/.matchbox/keyboard.xml") + if os.path.isfile(usrkbd): + env["MB_KBD_CONFIG"] = usrkbd + else: + env["MB_KBD_CONFIG"] = "ks_includes/locales/keyboard.xml" + p = subprocess.Popen(["matchbox-keyboard", "--xid"], stdout=subprocess.PIPE, + stderr=subprocess.PIPE, env=env) + xid = int(p.stdout.readline()) + logging.debug(f"XID {xid}") + logging.debug(f"PID {p.pid}") + + keyboard = Gtk.Socket() + box.get_style_context().add_class("keyboard_matchbox") + box.pack_start(keyboard, True, True, 0) + self.base_panel.get_content().pack_end(box, False, False, 0) + + self.show_all() + keyboard.add_id(xid) + + self.keyboard = { + "box": box, + "process": p, + "socket": keyboard + } + return + if entry is None: + logging.debug("Error: no entry provided for keyboard") + return box.get_style_context().add_class("keyboard_box") - box.pack_start(keyboard, True, True, 0) - - self.base_panel.get_content().pack_end(box, False, False, 0) - - self.show_all() - keyboard.add_id(xid) - + box.add(Keyboard(self, self.remove_keyboard, entry=entry)) self.keyboard = { - "box": box, - # "panel": cur_panel.get(), - "process": p, - "socket": keyboard + "entry": entry, + "box": box } + self.base_panel.get_content().pack_end(box, False, False, 0) + self.base_panel.get_content().show_all() def remove_keyboard(self, widget=None, event=None): if self.keyboard is None: return + if 'process' in self.keyboard: + os.kill(self.keyboard['process'].pid, signal.SIGTERM) self.base_panel.get_content().remove(self.keyboard['box']) - os.kill(self.keyboard['process'].pid, signal.SIGTERM) self.keyboard = None def change_cursor(self, cursortype=None): diff --git a/styles/base.css b/styles/base.css index 082eb164..2362d058 100644 --- a/styles/base.css +++ b/styles/base.css @@ -267,9 +267,19 @@ trough { } .keyboard_box { + margin-top: 35px; +} + +.keyboard_matchbox { margin-top: 42px; } +.keyboard_pad { + margin: 0.05em; + padding: 0.0em; + border-radius: 0.7em; +} + .message_popup { border-bottom: .1em solid white; } diff --git a/styles/colorized/style.css b/styles/colorized/style.css index 28caa471..cfb46789 100644 --- a/styles/colorized/style.css +++ b/styles/colorized/style.css @@ -235,3 +235,7 @@ textview .time { .error { background-color: #dc322f; /*solarized-red*/ } + +.keyboard_pad { + background-color: #073642; /*base02*/ +} diff --git a/styles/material-dark/style.css b/styles/material-dark/style.css index 65535219..0b25d2b3 100644 --- a/styles/material-dark/style.css +++ b/styles/material-dark/style.css @@ -19,8 +19,8 @@ button:active { .button_active { background-color: #000000; border-color: #d81549; - border-width: .15em; border-style: dashed; + border-width: .25em; border-radius: 1em; } @@ -227,3 +227,7 @@ textview .time { .error { background-color: #B71C1C; } + +.keyboard_pad { + background-color: #090909; /*base02*/ +} diff --git a/styles/material-darker/style.css b/styles/material-darker/style.css index 386029e9..cfdac74a 100644 --- a/styles/material-darker/style.css +++ b/styles/material-darker/style.css @@ -24,6 +24,7 @@ button:active { .button_active { border-color: #282828; border-style: solid; + border-width: .25em; background-color: #282828; border-radius: 1em; } @@ -209,3 +210,7 @@ textview .time { .error { background-color: #CF6679; } + +.keyboard_pad { + background-color: #090909; /*base02*/ +} diff --git a/styles/material-light/style.css b/styles/material-light/style.css index b71f38b1..fed6cf9d 100644 --- a/styles/material-light/style.css +++ b/styles/material-light/style.css @@ -23,8 +23,9 @@ button:active { .button_active { border-color: #BDBDBD; border-style: solid; + border-width: .25em; background-color: white; - box-shadow: .15em .15em #BDBDBD; + box-shadow: .1em .1em #BDBDBD; border-radius: 1em; } @@ -257,3 +258,7 @@ textview .time { .error { background-color: #EF9A9A; } + +.keyboard_pad { + background-color: #BDBDBD; +} diff --git a/styles/z-bolt/style.css b/styles/z-bolt/style.css index 87b1a2df..85f88875 100644 --- a/styles/z-bolt/style.css +++ b/styles/z-bolt/style.css @@ -206,3 +206,7 @@ textview .time { .error { background-color: rgba(204, 30, 30, 0.7); } + +.keyboard_pad { + background-color: #13181C; +}