-
Notifications
You must be signed in to change notification settings - Fork 4
Widget contexts
The semantics of widget manipulation in the eXtraWidgets extension are very much inspired by the semantics of agent manipulation in NetLogo.
Just like you can ask
turtles, patches and links to run commands, you can xw:ask
widgets to run commands. Just like you can use of
to extract information from an agent or agentset, you can use xw:of
to do the same with widgets. Finally, just like with
can be used to filter an agentset, xw:with
can be used to filter a list of widget keys.
All three primitives use code blocks: a command block for xw:ask
and reporter blocks for xw:of
and xw:with
. The important thing to understand is that each of these code blocks introduce a new "widget context" and that the behavior of some other primitives is affected by the current context: they operate on the current widget. Other primitives that introduce a new widget context are widget constructors (xw:create-<kind>).
The primitives affected by the widget context are the property getters (xw:<property>) and setters (xw:set-<property>).
Suppose that you create a tab with three sliders on it:
to startup
xw:clear-all
xw:create-tab "t1"
foreach ["alpha" "beta" "gamma"] [
xw:create-slider ? [
xw:set-color one-of base-colors
xw:set-label xw:key
]
]
end
Here, we are using NetLogo's foreach
command to avoid repeating ourselves three times. Inside the foreach
block, the ?
character stands, in turn, for each member of the list ["alpha" "beta" "gamma"]
, so we create a new slider for each of these three keys. The xw:create-slider
statement is followed by a command block that introduces a new widget context, where getters and setters will operate on the widget that is being created. The xw:set-color one-of base-colors
statement will thus set the color of that particular widget to a random color amongst NetLogo's base colors. The xw:set-label xw:key
statement uses both a setter (xw:set-label
) and a getter (xw:key
) to set the label of that widget to the key of that widget.
Widget contexts can also be nested. You may have noticed that the startup
procedure shown above creates all three sliders on top of one another. You could, of course, remedy to this by setting the y
property of "beta"
and "gamma"
to an appropriate absolute value, but it may be wiser to position them relative to the widget above them. Here is how to do it for "beta"
:
xw:ask "beta" [ xw:set-y [ xw:y + xw:height + 10 ] xw:of "alpha" ]
Notice the two nested code blocks. The first one is introduced by xw:ask
and puts us in the context of "beta"
, so xw:set-y
will set the y
property of "beta"
. The inner code block, introduced with xw:of
, puts us in the context of "alpha"
instead, so the xw:y + xw:height + 10
expression reports a y
coordinate that is 10 points below the bottom of "alpha"
(and this is where we place the top of "beta"
, using xw:set-y
).
You would do the same thing for "gamma"
, setting its y
property relative to the bottom of "beta"
:
xw:ask "gamma" [ xw:set-y [ xw:y + xw:height + 10 ] xw:of "beta" ]
By the way, if you had many different sliders (or other widgets) that you wanted to lay out this way, you could generalize this pattern to something like:
(foreach (but-last xw:sliders) (but-first xw:sliders) [
xw:ask ?2 [ xw:set-y [ xw:y + xw:height + 10 ] xw:of ?1 ]
])
(Note that we've used the xw:sliders
reporter to list all our sliders. It worked for us because xw:<kinds> reporters like xw:sliders
always list widgets in alphabetical order and that happened to be the order we wanted. In a real-life model, though, it is unlikely to be the case, so you may have to create a list where you explicitly place your widgets in the order you want them.)