Handling completion keyboard movement

This commit is contained in:
itdominator 2024-09-26 00:22:10 -05:00
parent 3d37a2335a
commit 096841e98a
4 changed files with 116 additions and 28 deletions

View File

@ -5,6 +5,7 @@ import gi
gi.require_version('Gtk', '3.0')
gi.require_version('GtkSource', '4')
from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GtkSource
# Application imports
@ -68,6 +69,7 @@ class EditorControllerMixin(KeyInputController, EditorEventsMixin):
source_view.completion_view.add_completion_item(ci)
source_view.completion_view.show_all()
GLib.idle_add( source_view.completion_view.select_first_row )
# completion = source_view.get_completion()

View File

@ -31,9 +31,9 @@ class KeyInputController:
return True
if keyname in [ "slash", "Up", "Down", "m", "z", "y" ]:
if keyname == "Up":
if keyname == "Up" and not self.completion_view.get_parent():
self.keyboard_move_lines_up()
if keyname == "Down":
if keyname == "Down" and not self.completion_view.get_parent():
self.keyboard_move_lines_down()
if keyname == "z":
@ -47,10 +47,22 @@ class KeyInputController:
if keyname in [ "Up", "Down", "Left", "Right" ]:
return True
if keyname in [ "Return", "Enter", "Up", "Down" ]:
if keyname in [ "Left", "Right" ]:
if self.completion_view.get_parent() and self.completion_view.is_visible():
# Needed to escape our completion widget and get back ibeam
if keyname == "Left":
self.remove( self.completion_view )
GLib.idle_add(self.grab_focus)
if keyname == "Right":
self.remove( self.completion_view )
GLib.idle_add(self.grab_focus)
# ^ Needed to escape our completion widget and get back ibeam
return True
if keyname in [ "Return", "Enter" ]:
if self.completion_view.get_parent() and self.completion_view.is_visible():
return True
if len(self._multi_insert_marks) > 0:
if keyname == "BackSpace":
@ -129,23 +141,12 @@ class KeyInputController:
self.keyboard_clear_marks()
if keyname in [ "Return", "Enter", "Up", "Down", "Left", "Right" ]:
if keyname in [ "Return", "Enter" ]:
if self.completion_view.get_parent() and self.completion_view.is_visible():
if keyname in {"Return", "Enter"}:
self.completion_view.activate_completion()
if keyname == "UP":
self.completion_view.move_selection_up()
if keyname == "Down":
self.completion_view.move_selection_down()
if keyname == "Left":
self.remove( self.completion_view )
if keyname == "Right":
self.remove( self.completion_view )
self.completion_view.activate_completion()
return True
if keyname in {"Return", "Enter"}:
if len(self._multi_insert_marks) > 0:
self.begin_user_action(buffer)
with buffer.freeze_notify():

View File

@ -9,7 +9,7 @@ from gi.repository import Gtk
class CompletionItem(Gtk.Button):
class CompletionItem(Gtk.Label):
def __init__(self):
super(CompletionItem, self).__init__()
@ -27,7 +27,7 @@ class CompletionItem(Gtk.Button):
ctx.add_class("completion-item")
def _setup_signals(self):
self.connect("clicked", self._do_completion)
...
def populate_completion_item(self, item):
@ -39,6 +39,3 @@ class CompletionItem(Gtk.Button):
if "additionalTextEdits" in keys:
self.additionalTextEdits = item["additionalTextEdits"]
def _do_completion(self, button):
...

View File

@ -3,7 +3,10 @@
# 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
from gi.repository import GLib
# Application imports
from .completion_item import CompletionItem
@ -26,21 +29,58 @@ class CompletionView(Gtk.ScrolledWindow):
def _setup_styling(self):
ctx = self.get_style_context()
ctx.add_class("completion-view")
self.set_size_request(320, 320)
self.set_margin_top(10)
self.set_margin_bottom(10)
self.set_margin_start(10)
self.set_margin_end(10)
self.set_size_request(320, -1)
self.set_min_content_height(120)
self.set_max_content_height(480)
self.set_overlay_scrolling(False)
self.set_policy( Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC ) # hbar, vbar
def _setup_signals(self):
...
def _load_widgets(self):
viewport = Gtk.Viewport()
self.button_box = Gtk.Box()
self.button_box = Gtk.ListBox()
self.button_box.set_orientation( Gtk.Orientation.VERTICAL )
self.button_box.set_hexpand( True )
self.button_box.set_placeholder( Gtk.Label(label = "No completion data...") )
self.button_box.set_selection_mode( Gtk.SelectionMode.BROWSE )
self.button_box.connect("key-press-event", self._key_press_event)
viewport.add(self.button_box)
self.add(viewport)
# This is depressing but only way I can get to scroll with items getting selected.
# Cannot figure out how to just manually scroll widget into view with code.
def _key_press_event(self, widget, eve):
keyname = Gdk.keyval_name(eve.keyval)
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
if is_control:
return True
if keyname in [ "Up" ]:
self.move_selection_up()
return True
if keyname in [ "Down" ]:
self.move_selection_down()
return True
if keyname in [ "Enter", "Return" ]:
self.activate_completion()
return True
def add_completion_item(self, item: CompletionItem):
self.button_box.add(item)
@ -49,11 +89,59 @@ class CompletionView(Gtk.ScrolledWindow):
self.button_box.remove(child)
def activate_completion(self):
...
row = self.button_box.get_selected_row()
def move_selection_up(self):
...
index = -1
srow = self.button_box.get_selected_row()
if not srow:
self.select_last_row()
return
for i, child in enumerate( self.button_box.get_children() ):
if child == srow:
index = i - 1
break
if index == -1:
index = len( self.button_box.get_children() ) - 1
row = self.button_box.get_row_at_index(index)
self.select_and_scroll_to_view(row)
def move_selection_down(self):
...
index = -1
srow = self.button_box.get_selected_row()
if not srow:
self.select_first_row()
return
for i, child in enumerate( self.button_box.get_children() ):
if child == srow:
index = i + 1
break
if index > (len( self.button_box.get_children() ) - 1):
index = 0
row = self.button_box.get_row_at_index(index)
self.select_and_scroll_to_view(row)
def select_first_row(self):
row = self.button_box.get_row_at_y(0)
if not row: return
self.select_and_scroll_to_view(row)
def select_last_row(self):
row = self.button_box.get_row_at_y( len( self.button_box.get_children() ) - 1)
if not row: return
self.select_and_scroll_to_view(row)
def select_and_scroll_to_view(self, row):
self.button_box.select_row(row)
GLib.idle_add( row.grab_focus )
# row.set_focus(True)
# GLib.idle_add( row.set_focus, True )