make keyboard completions work
1. When adding a button to flowbox, the flowbox widget interposes a flowboxchild between the two, which can receive events and so becomes part of the tab order. this is why our buttons weren't getting activated - they weren't focused even though they looked focused. So, use labels instead of buttons for completions 2. For some reason I don't understand, flowboxchild widgets receive :activate *only* on keyboard activation. So instead of using it, we connect to :child-activated on the flowbox. 3. Setting widget:on_foo *adds* a handler to the widget instead of replacing what was previously there. There is no nice way to remove handlers from a widget either. Because we need a new on_child_activated handler every time the completions change, the only way I can see to achieve this is to create the flowbox afresh on each keystroke instead of creating it once when the frame is createdmain
parent
d76769752b
commit
a5a65006ca
39
command.fnl
39
command.fnl
|
@ -20,7 +20,7 @@
|
||||||
(fn completion [{: widget : text : value }]
|
(fn completion [{: widget : text : value }]
|
||||||
(let [value (or value (assert text "must have text"))]
|
(let [value (or value (assert text "must have text"))]
|
||||||
{
|
{
|
||||||
:widget (or widget (Gtk.Button { :label text }))
|
:widget (or widget (Gtk.Label { :label text }))
|
||||||
: text
|
: text
|
||||||
: value
|
: value
|
||||||
}))
|
}))
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
(icollect [v (_G.history:find-distinct term)]
|
(icollect [v (_G.history:find-distinct term)]
|
||||||
(let [label (.. v.url " " (or v.title ""))]
|
(let [label (.. v.url " " (or v.title ""))]
|
||||||
(completion { :text v.url
|
(completion { :text v.url
|
||||||
:widget (Gtk.Button { : label })
|
:widget (Gtk.Label { : label })
|
||||||
:value v.url
|
:value v.url
|
||||||
})))
|
})))
|
||||||
[])]
|
[])]
|
||||||
|
@ -147,6 +147,8 @@
|
||||||
(if (not result.active)
|
(if (not result.active)
|
||||||
(completions-widget:hide))
|
(completions-widget:hide))
|
||||||
(set entry.text (or result.default result.error ""))
|
(set entry.text (or result.default result.error ""))
|
||||||
|
(if result.active (entry:grab_focus))
|
||||||
|
|
||||||
(when widget.parent
|
(when widget.parent
|
||||||
(widget.parent:set_visible_child_name
|
(widget.parent:set_visible_child_name
|
||||||
(if result.active "commander" "echo-area"))))
|
(if result.active "commander" "echo-area"))))
|
||||||
|
@ -155,14 +157,29 @@
|
||||||
(let [parent self.completions-widget
|
(let [parent self.completions-widget
|
||||||
set-completions
|
set-completions
|
||||||
(fn [completions]
|
(fn [completions]
|
||||||
(parent:foreach #(parent:remove $1))
|
(let [flowbox (Gtk.FlowBox {
|
||||||
(each [_ c (pairs completions)]
|
:activate_on_single_click true
|
||||||
(parent:add
|
:selection_mode Gtk.SelectionMode.SINGLE
|
||||||
(doto c.widget
|
})
|
||||||
(tset :on_clicked
|
;; I don't know why, but the flowboxchild activate signal
|
||||||
#(update-widget-state
|
;; is working only for keyboard activation not for
|
||||||
self
|
;; clicking. So instead of using it we connect to
|
||||||
(self:on-input-finished c.text))))))
|
;; child_activated, and use kids-map to find out which
|
||||||
|
;; child it was
|
||||||
|
kids-map {}]
|
||||||
|
(parent:foreach #(parent:remove $1)) ; expect only 1 direct child
|
||||||
|
(each [_ c (pairs completions)]
|
||||||
|
(let [fbc (Gtk.FlowBoxChild)]
|
||||||
|
(tset kids-map fbc c.text)
|
||||||
|
(fbc:add c.widget)
|
||||||
|
(flowbox:add fbc)))
|
||||||
|
(tset flowbox :on_child_activated
|
||||||
|
(fn [_self child]
|
||||||
|
(match (. kids-map child)
|
||||||
|
text (update-widget-state
|
||||||
|
self
|
||||||
|
(self:on-input-finished text)))))
|
||||||
|
(parent:add flowbox))
|
||||||
(parent:show_all))]
|
(parent:show_all))]
|
||||||
(match self.state
|
(match self.state
|
||||||
{:command c :this-param param-name}
|
{:command c :this-param param-name}
|
||||||
|
@ -210,7 +227,7 @@
|
||||||
prompt (Gtk.Label { :label ""})
|
prompt (Gtk.Label { :label ""})
|
||||||
box (Gtk.Box { :orientation Gtk.Orientation.VERTICAL })
|
box (Gtk.Box { :orientation Gtk.Orientation.VERTICAL })
|
||||||
hbox (Gtk.Box { :orientation Gtk.Orientation.HORIZONTAL })
|
hbox (Gtk.Box { :orientation Gtk.Orientation.HORIZONTAL })
|
||||||
completions (Gtk.FlowBox)
|
completions (Gtk.Box { :orientation Gtk.Orientation.VERTICAL })
|
||||||
self {
|
self {
|
||||||
:state default-state
|
:state default-state
|
||||||
: activate
|
: activate
|
||||||
|
|
|
@ -66,18 +66,20 @@ focus from entry to step through the completions then RET activates
|
||||||
* [done] back binding
|
* [done] back binding
|
||||||
* [done] save url history, use it in completions
|
* [done] save url history, use it in completions
|
||||||
* [done] autocomplete command name
|
* [done] autocomplete command name
|
||||||
|
* [done] keyboard navigation of completions
|
||||||
|
|
||||||
* custom rendering for completions (e.g. buffer thumbnails)
|
* custom rendering for completions (e.g. buffer thumbnails)
|
||||||
* less ugly default completions rendering
|
* less ugly default completions rendering
|
||||||
* buffer name is often going to be useless. find buffers by url/title
|
* buffer name is often going to be useless. find buffers by url/title
|
||||||
still need some 1:1 mapping between the buffer object and
|
still need some 1:1 mapping between the buffer object and
|
||||||
a text-representable form of same
|
a text-representable form of same
|
||||||
* bind event to echo-area click, ideally dependent on what's being shown
|
* bind event to echo-area click, ideally dependent on what's being shown in there
|
||||||
in there
|
|
||||||
* in general, can we bind commands to widget events?
|
* in general, can we bind commands to widget events?
|
||||||
* command to create new buffer
|
* command to create new buffer
|
||||||
* keyboard navigation of completions
|
|
||||||
|
|
||||||
* suppress "Return is undefined" message after a command executes
|
* suppress "Return is undefined" message after a command executes
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
can we increase the testability? e.g. for command processing,
|
||||||
|
define a command, feed in some keystrokes,
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
(completion {
|
(completion {
|
||||||
:text keyword
|
:text keyword
|
||||||
:value keyword
|
:value keyword
|
||||||
:widget (Gtk.Button { :label name })
|
:widget (Gtk.Label { :label name })
|
||||||
}))))
|
}))))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue