Setters
Setters are a convenience mechanism for creating widgets. During creation, setters act like any other field on the widget, in the sense that they can be assigned to. When a setter is assigned to, it is executed and can decide how the assigned value should be handled.
One example is the Button.icon
setter.
When assigning to it, the setter creates an Icon
widget with the given name and adds it to the Button
.
Another usecase is converting the type assigned to a field before storing it.
For example, the BaseWidget.margin
setter has overloads for both the Margin
object and int
.
When you assign an int
to the margin
setter, it first converts it to a Margin
object with the same margin on all sides.
When you assign a Margin
object, it gets stored directly.
To create a setter you need:
- a
setter <SetterName>
declaration with the type that the setter receives, e.g.setter margins: int
defines a setter that will receive an int from a parent-widget - a
has<SetterName>=
proc, forwarding booleans that would enable/disable the "field" represented by the setter to the actual field onWidgetState
- a
val<SetterName>=
proc, converting the value received by the setter as needed and assigning it to the actual field onWidgetState
Note: You only need 1 has<SetterName>
proc, even if you define multiple setters.
Lets take a look at a code example:
## The custom widget
import owlkettle, sequtils
viewable LabelList:
labelTexts {.private.}: seq[string]
setter texts: openArray[string]
setter texts: openArray[int]
proc `hasTexts=`*(widget: LabelList, has: bool) =
widget.hasLabelTexts = has
proc `valTexts=`*(widget: LabelList, texts: openArray[string]) =
widget.valLabelTexts = @texts
proc `valTexts=`*(widget: LabelList, slice: openArray[int]) =
widget.valLabelTexts = mapIt(slice, $it)
method view(state: LabelListState): Widget =
result = gui:
Box(orient = OrientY):
for text in state.labelTexts:
Label(text = text)
## The App
viewable App:
discard
method view(app: AppState): Widget =
result = gui:
Window:
Box(orient = OrientX):
LabelList(texts = ["Hello", "World"])
LabelList(texts = [1, 2, 3])
when not defined(owlkettleNimiDocs):
brew(gui(App()))
This defines a LabelList
that has a setter called texts
.
When texts
gets assigned to, it triggers the valTexts=
procs.
This will convert the received value into the type of labelTexts
and assign to it via valLabelTexts
.
Thus, via the setter the widget can now accept an openArray[string]
and an openArray[int]
for the "texts" field!