CRESS-Surrey / eXtraWidgets

An extension for creating additional interface tabs in the NetLogo GUI and putting custom widgets on them.
MIT License
13 stars 4 forks source link

Find a way of setting properties when adding a widget #45

Closed nicolaspayette closed 10 years ago

nicolaspayette commented 10 years ago

My first idea was that we could have a variadic version of xw:add to add properties:

(xw:add widget-kind widget-key property-key1 property-value1 ...)

nicolaspayette commented 10 years ago

An alternative to the variadic version would be one that may take a list of key/value pairs.

Uglier syntax is a downside:

(xw:add "slider" "s1" [["label" "My Slider"] ["x" 10] ["y" 10]])

instead of

(xw:add "slider" "s1" "label" "My Slider" "x" 10 "y" 10)

But allows stuff like:

let props [["label" "My Slider"] ["x" 10] ["y" 10]]
xw:add "slider" "s1" props
xw:add "slider" "s2" props

And, perhaps more importantly:

(xw:add "slider" s2 xw:properties "s1")

which may make xw:copy (#35) unnecessary.

nicolaspayette commented 10 years ago

If we go with the list, should it still be variadic? There will almost always be only one list; accepting multiple lists would not be especially useful. And how often will we need to use add without properties? In those cases, you could just say xw:add "kind" "key" [].

I'm also wondering if we should drop the kind argument and expect it through the list:

xw:add "s1" ["kind" "slider"]

Maybe we should validate at runtime that kind is always there?

The predefined widget types would not need that:

xw:add-slider "s1"

(We could even find a way for custom widgets to dynamically provide add- primitives...)

A nice benefit would be to allow copying from one type of widget to another:

xw:add-input "i1" [["x" 10] ["y" 10] ["width 50"] ["height" 20]]
xw:add-slider xw:properties "i1"

...with xw:add-slider overriding the kind property of xw:properties "i1".

nicolaspayette commented 10 years ago

Finally settled for:

xw:add-<kind> widget-key (xw:add-<kind> widget-key property-list1 ...)

It allows not to bother with empty property lists when doing simple stuff like xw:add-tab "t1", but preserves the possibility of copying properties and other fancy stuff. If multiple lists are given, they are concatenated.

nicolaspayette commented 10 years ago

Re-opening this, as I wasn't satisfied with the syntax and got a new idea for it: have xw:ask and xw:of.

You'd create a new widget like this:

xw:create-slider "s1" [
  xw:set-x 10
  xw:set-y 10
  xw:set-color blue
  xw:set-maximum 200
]

Instead of:

xw:create-slider "s1"
xw:set-x "s1" 10
xw:set-y "s1" 10
xw:set-color "s1" blue
xw:set-maximum "s1" 200

And later modify it like this:

xw:ask "s1" [
  xw:set-x 10
  xw:set-y 10
  xw:set-color yellow
  xw:set-maximum 500
]

Instead of:

xw:set-x "s1" 10
xw:set-y "s1" 10
xw:set-color "s1" yellow
xw:set-maximum "s1" 500

You need to set more than three properties to actually save keystrokes (and setting one or two is actually more costly) but the main gain is in being less error prone (and arguably more readable). I got burned a few times by copying blocks of setters and forgetting to change the widget key.

For xw:of, we'd have:

[xw:color] xw:of "s1"

Instead of:

xw:get-color "s1"

I'm less sure about this one, because it is longer. But the symmetry is compelling. And there is this other thing that I have in mind:

xw:ask xw:all-sliders [ xw:set-color one-of base-colors ]

And conversely:

[ xw:color ] xw:of xw:all-sliders

The same could be achieved, however, with:

map [ xw:get-color ? ] xw:all-sliders

(xw:all-sliders would just return a list of widget keys; you could also use a list directly with xw:ask and xw:of).

Need to think about this a bit more. In any case, having xw:of doesn't preclude keeping xw:get-<property> around.

nicolaspayette commented 10 years ago

About saving keystrokes: my examples assume very short widget keys (e.g., "t1"). Longer keys, which I suspect people might use, would mean more extensive savings (at least for xw:ask).

nicolaspayette commented 10 years ago

Another possibility: have each widget declare which of their properties is its "value" and have something like xw:get return that automatically. That actually might be a good idea in any case.

nicolaspayette commented 10 years ago

Other use for having getters work within context:

xw:ask "s1" [
  if xw:value > 10 [ xw:set-color red ]
  xw:set-width xw:height * 3
]
nicolaspayette commented 10 years ago

Left to do: