Updated emoji loading to be faster; added auto fill option
This commit is contained in:
parent
c3c85a3040
commit
e688416244
@ -5,6 +5,7 @@ An onscreen keyboard for the mouse.
|
||||
* PyGObject
|
||||
* python-xlib
|
||||
* pyautogui
|
||||
* fast-autocomplete[levenshtein]
|
||||
|
||||
# TODO
|
||||
<li>Get save and execute of custom commands working.</li>
|
||||
|
@ -85,8 +85,9 @@ _USR_PATH = f"/usr/share/{app_name.lower()}"
|
||||
_CONFIG_PATH = f"{_USER_HOME}/.config/{app_name.lower()}"
|
||||
_ICON_FILE = f"{_CONFIG_PATH}/icons/{app_name.lower()}.png"
|
||||
_CSS_FILE = f"{_CONFIG_PATH}/stylesheet.css"
|
||||
_DICT_FILE = f"{_CONFIG_PATH}/edmt_dictionary.json"
|
||||
_EMOJI_FILE = f"{_CONFIG_PATH}/emoji.json"
|
||||
_LOG_FILE = f"{_CONFIG_PATH}/application.log"
|
||||
_LOG_PATH = f"{_CONFIG_PATH}"
|
||||
ch_log_lvl: int = 10
|
||||
fh_log_lvl: int = 20
|
||||
|
||||
@ -110,10 +111,11 @@ if not os.path.exists(_EMOJI_FILE):
|
||||
builtins.CONFIG_PATH = _CONFIG_PATH
|
||||
builtins.ICON_FILE = _ICON_FILE
|
||||
builtins.CSS_FILE = _CSS_FILE
|
||||
builtins.DICT_FILE = _DICT_FILE
|
||||
builtins.EMOJI_FILE = _EMOJI_FILE
|
||||
|
||||
|
||||
builtins.logger = Logger(_LOG_FILE, ch_log_lvl, fh_log_lvl).get_logger()
|
||||
builtins.logger = Logger(_LOG_PATH, ch_log_lvl, fh_log_lvl).get_logger()
|
||||
builtins.endpoint_registry = EndpointRegistry()
|
||||
builtins.event_system = EventSystem()
|
||||
builtins.typwriter = Pyautogui_Controller()
|
@ -1,10 +1,19 @@
|
||||
# Python imports
|
||||
import json
|
||||
import time
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
try:
|
||||
from fast_autocomplete import AutoComplete
|
||||
auto_completion = True
|
||||
except Exception as e:
|
||||
print( repr(e) )
|
||||
auto_completion = False
|
||||
|
||||
# Application imports
|
||||
from .columns import Left_Column
|
||||
from .columns import Keys_Column
|
||||
@ -20,16 +29,34 @@ class Auto_Type(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(Auto_Type, self).__init__()
|
||||
|
||||
pad1 = Gtk.Label()
|
||||
pad2 = Gtk.Label()
|
||||
self._auto_typer = Gtk.SearchEntry()
|
||||
self._type_btn = Gtk.Button(label = "Type")
|
||||
self._processing_dictionary = False
|
||||
pad1 = Gtk.Label()
|
||||
pad2 = Gtk.Label()
|
||||
self._res_popover = Gtk.Popover()
|
||||
self._auto_typer = Gtk.SearchEntry()
|
||||
self._type_btn = Gtk.Button(label = "Type")
|
||||
|
||||
self._word_list = Gtk.Box()
|
||||
scrolled_win = Gtk.ScrolledWindow()
|
||||
viewport = Gtk.Viewport()
|
||||
|
||||
viewport.add(self._word_list)
|
||||
scrolled_win.add(viewport)
|
||||
scrolled_win.show_all()
|
||||
|
||||
self._res_popover.set_size_request(200, 400)
|
||||
self._res_popover.set_relative_to(self._auto_typer)
|
||||
self._res_popover.set_modal(False)
|
||||
self._res_popover.add(scrolled_win)
|
||||
self._res_popover.set_default_widget(scrolled_win)
|
||||
|
||||
self._auto_typer.set_placeholder_text("Autotype Field...")
|
||||
self._auto_typer.set_icon_from_stock(0, "gtk-go-forward") # PRIMARY = 0, SECONDARY = 1
|
||||
self._auto_typer.set_can_focus(True)
|
||||
self._auto_typer.set_hexpand(True)
|
||||
|
||||
self._word_list.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
pad1.set_hexpand(True)
|
||||
pad2.set_hexpand(True)
|
||||
|
||||
@ -38,15 +65,49 @@ class Auto_Type(Gtk.Box):
|
||||
self.add(self._type_btn)
|
||||
self.add(pad2)
|
||||
|
||||
self.setup_styling()
|
||||
if auto_completion:
|
||||
self.setup_dictionary()
|
||||
|
||||
self.setup_styling()
|
||||
self.setup_signals()
|
||||
self.show_all()
|
||||
|
||||
@daemon_threaded
|
||||
def setup_dictionary(self):
|
||||
self._processing_dictionary = True
|
||||
|
||||
_words = set()
|
||||
words = {}
|
||||
with open(DICT_FILE, 'r') as f:
|
||||
dict_data = json.load(f)
|
||||
self._auto_typer.set_progress_fraction(0.25)
|
||||
|
||||
for field in dict_data:
|
||||
_words.add( field["word"] )
|
||||
_words.add( field["word"].lower() )
|
||||
|
||||
self._auto_typer.set_progress_fraction(0.5)
|
||||
del dict_data
|
||||
for word in _words:
|
||||
words[word] = {}
|
||||
|
||||
self._auto_typer.set_progress_fraction(0.75)
|
||||
self.autocomplete = AutoComplete(words=words)
|
||||
del _words
|
||||
del words
|
||||
|
||||
self._auto_typer.set_progress_fraction(1.0)
|
||||
time.sleep(1)
|
||||
self._auto_typer.set_progress_fraction(0.0)
|
||||
self._processing_dictionary = False
|
||||
|
||||
def setup_styling(self):
|
||||
self.set_margin_bottom(5)
|
||||
|
||||
def setup_signals(self):
|
||||
if auto_completion:
|
||||
self._auto_typer.connect("search-changed", self.search_changed)
|
||||
|
||||
self._auto_typer.connect("enter-notify-event", self.focus_entry)
|
||||
self._auto_typer.connect("leave-notify-event", self.unfocus_entry)
|
||||
self._type_btn.connect("released", self.type_out)
|
||||
@ -61,8 +122,39 @@ class Auto_Type(Gtk.Box):
|
||||
widget.grab_remove()
|
||||
event_system.emit("unset_focusable")
|
||||
|
||||
def search_changed(self, widget = None, eve = None):
|
||||
if self._processing_dictionary: return
|
||||
|
||||
text = widget.get_text()
|
||||
if not text:
|
||||
self._res_popover.hide()
|
||||
return
|
||||
|
||||
words = self.autocomplete.search(word=text, max_cost=3, size=100)
|
||||
if not words:
|
||||
self._res_popover.hide()
|
||||
return
|
||||
|
||||
self._clear_children(self._word_list)
|
||||
for word in words:
|
||||
button = Gtk.Button(label=word[0])
|
||||
button.connect("clicked", self.type_out)
|
||||
self._word_list.add(button)
|
||||
|
||||
self._word_list.show_all()
|
||||
self._res_popover.show()
|
||||
|
||||
def _clear_children(self, widget):
|
||||
for child in widget.get_children():
|
||||
widget.remove(child)
|
||||
|
||||
def type_out(self, widget = None, eve = None):
|
||||
text = self._auto_typer.get_text()
|
||||
|
||||
if isinstance(widget, Gtk.Button):
|
||||
if not widget.get_label().lower() == "type":
|
||||
text = widget.get_label()
|
||||
|
||||
typwriter.type_string(text)
|
||||
|
||||
|
||||
@ -110,4 +202,4 @@ class Container(Gtk.Box):
|
||||
|
||||
def add_content(self):
|
||||
self.add(Auto_Type())
|
||||
self.add(Main_Container())
|
||||
self.add(Main_Container())
|
@ -1,11 +1,13 @@
|
||||
# Python imports
|
||||
from collections import defaultdict
|
||||
import json
|
||||
import asyncio
|
||||
from collections import defaultdict
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from .key import Key
|
||||
@ -19,7 +21,7 @@ class Emoji_Notebook(Gtk.Notebook):
|
||||
def __init__(self):
|
||||
super(Emoji_Notebook, self).__init__()
|
||||
|
||||
self.load_ui( self.get_data(EMOJI_FILE) )
|
||||
self.load_ui()
|
||||
|
||||
self.setup_styling()
|
||||
self.show_all()
|
||||
@ -29,26 +31,52 @@ class Emoji_Notebook(Gtk.Notebook):
|
||||
self.set_current_page(0)
|
||||
self.set_scrollable(True)
|
||||
|
||||
def get_data(self, file):
|
||||
emoji_grouping = defaultdict(list)
|
||||
|
||||
with open(file, 'r') as f:
|
||||
@daemon_threaded
|
||||
def load_ui(self):
|
||||
emoji_data = None
|
||||
with open(EMOJI_FILE, 'r') as f:
|
||||
emoji_data = json.load(f)
|
||||
for emoji in emoji_data:
|
||||
category = emoji['category']
|
||||
del emoji['category']
|
||||
del emoji['unicode_version']
|
||||
del emoji['ios_version']
|
||||
emoji_grouping[category].append(emoji)
|
||||
|
||||
if not emoji_data:
|
||||
print("No emoji data found in file...")
|
||||
return
|
||||
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
loop = None
|
||||
|
||||
if loop and loop.is_running():
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task( self._async_load_ui(emoji_data) )
|
||||
else:
|
||||
asyncio.run( self._async_load_ui(emoji_data) )
|
||||
|
||||
async def _async_load_ui(self, emoji_data):
|
||||
emoji_grouping = await self._get_emoji_grouping(emoji_data)
|
||||
GLib.idle_add(self._populate_ui, emoji_grouping)
|
||||
|
||||
async def _get_emoji_grouping(self, emoji_data):
|
||||
emoji_grouping = defaultdict(list)
|
||||
async def add_to_group(emoji):
|
||||
category = emoji['category']
|
||||
key = Key( emoji["emoji"], emoji["emoji"] )
|
||||
key._is_emoji = True
|
||||
|
||||
emoji_grouping[category].append(key)
|
||||
|
||||
tasks = [ add_to_group(emoji) for emoji in emoji_data]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
return emoji_grouping
|
||||
|
||||
def load_ui(self, emoji_grouping):
|
||||
def _populate_ui(self, emoji_grouping):
|
||||
width = 1
|
||||
height = 1
|
||||
for group in emoji_grouping:
|
||||
tab_widget = Gtk.Label(label=group)
|
||||
scroll, grid = self.create_scroll_and_grid()
|
||||
|
||||
self.append_page(scroll, tab_widget)
|
||||
self.set_tab_reorderable(scroll, False)
|
||||
self.set_tab_detachable(scroll, False)
|
||||
@ -56,16 +84,15 @@ class Emoji_Notebook(Gtk.Notebook):
|
||||
top = 0
|
||||
left = 0
|
||||
for emoji in emoji_grouping[group]:
|
||||
key = Key(emoji["emoji"], emoji["emoji"])
|
||||
key._is_emoji = True
|
||||
key.show()
|
||||
grid.attach(key, left, top, width, height)
|
||||
grid.attach(emoji, left, top, width, height)
|
||||
|
||||
left += 1
|
||||
if left > 8:
|
||||
left = 0
|
||||
top += 1
|
||||
|
||||
self.show_all()
|
||||
del emoji_grouping
|
||||
|
||||
def create_scroll_and_grid(self):
|
||||
scroll = Gtk.ScrolledWindow()
|
||||
@ -114,4 +141,4 @@ class Emoji_Popover(Gtk.Popover):
|
||||
self.popup()
|
||||
|
||||
def hide_emoji_view(self):
|
||||
self.popdown()
|
||||
self.popdown()
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user