Skip to content

Instantly share code, notes, and snippets.

@daveray
Created October 4, 2011 03:31
Show Gist options
  • Save daveray/1260843 to your computer and use it in GitHub Desktop.
Save daveray/1260843 to your computer and use it in GitHub Desktop.
Seesaw Keybinding Design Notes

Thoughts:

  • Should make specifying keybindings externally easy, through resources.
  • Should be easy like (listen)
  • Should be consistent with rest of event system.

A function to set up one key binding

Arguments:

  • Target widget

  • This is where the binding is installed using input map and action map. It could be omitted when the action is a widget and the scope is global (see below).

  • The keystroke(s). (:key)

  • Allow resources

  • Required? If not, what's the default?

  • Action to execute (:to)

  • A function (generate Action object)

  • A widget. Use the widget's action, or programmatically invoke, i.e. (.doClick)

  • An action

  • :none suppresses actions?

  • Required? If not, what's the default value?

  • Scope of the binding (:scope)

  • Only when the widget is focused (:local)

  • When the widget or any descendant has focus (default) (:descendants)

  • When current frame has focus (:global)

If :global is the default scope that gives the highest probability it will actually work, but could lead to weird behavior. For example, when there are tabs, global bindings are active in all tabs. hmmm.

Returns:

Same as (listen), a function that removes the binding and restores the previous one.

Possible Names:

  • listen-key
  • bind-key
  • on-key
  • with-key
  • bind-keypress

Notional Examples

; Map keys to calculator buttons
(let [b1 (button :text "1" ... handlers ...)
      ...
      b9 (button :text "2" ... handlers ...)
      grid (grid-panel :columns 3 [b1 ... b9])]
  (bind-key grid :key "1" :to b1 :scope :global)
  (bind-key grid :key "2" :to b2 :scope :global)
  ...)
  • The choice of where to attach the binding is confusing. On the button? On the container with :scope :descendants?
  • Decision depends a lot on focus

another notional example with fewer keyword args:

; Map keys to calculator buttons
(let [b1 (button :text "1" ... handlers ...)
      ...
      b9 (button :text "2" ... handlers ...)
      grid (grid-panel :columns 3 [b1 ... b9])]
  (bind-key grid "1" b1 :scope :global)
  (bind-key grid "2" b2 :scope :global)
  ...)

Here, we assume the key and action are always required and make them positional. :scope is optional, so it remains a keyword arg.

Links

http://download.oracle.com/javase/tutorial/uiswing/misc/keybinding.html

@gw666
Copy link

gw666 commented Dec 30, 2011

Dave, many thanks for seesaw! Without it, I wouldn't be able to do any kind of GUI-based Clojure project (see my project at gw666/infwb/snapshots). I'm struggling to understand Clojure + seesaw + Piccolo2D (the Java graphics library I'm using), so I can't speak to the tradeoffs you're talking about in the text above.

However, I can say that, under Notational Examples, I like the first version better, the one that uses ":key '1' :to b1". I find Clojure code to be too terse in general. Programming is hard enough--it only makes sense to write it in a way that gives your future self some hints on what the code means!

@daveray
Copy link
Author

daveray commented Dec 31, 2011

Greg. Thanks! I'm glad you find it useful. Have seesaw and piccolo been getting along pretty well for you? Is there anything that could be changed or added in Seesaw to make that easier? Just checking.

On the key binding stuff, I ended up going with the more terse version. See https://github.com/daveray/seesaw/blob/develop/src/seesaw/keymap.clj#L46. I don't know if I chose correctly or not. Deciding between positional and keyword arguments is an ongoing struggle for me :)

@gw666
Copy link

gw666 commented Jan 2, 2012

Dave: So far, so good! Piccolo does all its work in a PCanvas, which I just declare to be the :content of a seesaw frame! I'm taking baby steps here, and this one thing has been sufficient so far. Re: key bindings, I'm sure I'll be fine with whatever you implement! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment