Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) version 0.12.0 ships with an exciting new feature called Custom Control Component Slots!!! Component Slots are containers that could accept content in different parts of a Custom Control component (e.g. an address_form Custom Control can have a header slot and a footer slot to display extra information about the address being entered, which consumers could fill in with any GUI controls). A new example has been implemented to demonstrate this feature: Class-Based Custom Control Slots.
Of course, Glimmer implements Component Slots with the simplest most declarative DSL syntax possible (as with all features of Glimmer), which does not require redundant declarations of slots in advance or a distinction between singular and plural slots, yet all slots are treated uniformly in the simplest way possible. In the past, if you opened a block in front of a Custom Control keyword and shoved content in it (e.g. `address_form { label('some text') }`), it got added to the bottom inside the Custom Control's top-level control (though there was a bug in that feature that was fixed in version 0.11.10). That was a good smart default as it allowed contributing Custom Control content by consumers without having to explicitly/manually specify where to insert `children` in the Custom Control. Glimmer just knew what to do by default. That said, it did not address all needs, like wanting to insert content in arbitrary places deep in a Custom Control's body hierarchy. Now, Software Engineers could allow consumers of Custom Controls to contribute content everywhere inside a Custom Control, not just inside the top-level control, with a very minimalistic declarative DSL syntax that greatly facilitates building highly customizable Custom Controls.
I leave you with the Custom Control Component Slots feature documentation below.
Glimmer on!!!
P.S. In other news, somebody built Go in Ruby using Glimmer DSL for LibUI.
Component can have Component Slots inside layout container controls: vertical_box
, horizontal_box
, form
, and grid
.
Simply designate a layout container control as a Component Slot inside a Custom Control class body block by passing it a slot: slot_name
option (in the example below, we have a :header
slot and a :footer
slot):
body {
vertical_box {
vertical_box(slot: :header) {
stretchy false
}
form {
form_field(model: address, attribute: :street)
form_field(model: address, attribute: :p_o_box)
form_field(model: address, attribute: :city)
form_field(model: address, attribute: :state)
form_field(model: address, attribute: :zip_code)
}
vertical_box(slot: :footer) {
stretchy false
}
}
}
Next, in the Custom Control consuming code, open a block matching the name of the Component Slot (e.g. header {}
and footer {}
):
address_form(address: @address) {
header {
label('Billing Address') {
stretchy false
}
}
footer {
label('Billing address is used for online payments') {
stretchy false
}
}
}
Note that the slotted labels can include properties that apply to their Component Slot container like stretchy false
.
Example (Class-Based Custom Control Slots):
require 'glimmer-dsl-libui'
require 'facets'
Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
class FormField
include Glimmer::LibUI::CustomControl
options :model, :attribute
body {
entry { |e|
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
text <=> [model, attribute]
}
}
end
class AddressForm
include Glimmer::LibUI::CustomControl
option :address
body {
vertical_box {
vertical_box(slot: :header) {
stretchy false
}
form {
form_field(model: address, attribute: :street)
form_field(model: address, attribute: :p_o_box)
form_field(model: address, attribute: :city)
form_field(model: address, attribute: :state)
form_field(model: address, attribute: :zip_code)
}
vertical_box(slot: :footer) {
stretchy false
}
}
}
end
class LabelPair
include Glimmer::LibUI::CustomControl
options :model, :attribute, :value
body {
horizontal_box {
label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
label(value.to_s) {
text <= [model, attribute]
}
}
}
end
class AddressView
include Glimmer::LibUI::CustomControl
options :address
body {
vertical_box {
vertical_box(slot: :header) {
stretchy false
}
address.each_pair do |attribute, value|
label_pair(model: address, attribute: attribute, value: value)
end
}
}
end
class ClassBasedCustomControlSlots
include Glimmer::LibUI::Application # alias: Glimmer::LibUI::CustomWindow
before_body do
@address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
@address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
end
body {
window('Class-Based Custom Control Slots') {
margined true
horizontal_box {
vertical_box {
address_form(address: @address1) {
header {
label('Shipping Address') {
stretchy false
}
}
footer {
label('Shipping address is used for mailing purchases') {
stretchy false
}
}
}
horizontal_separator {
stretchy false
}
address_view(address: @address1) {
header {
label('Shipping Address (Saved)') {
stretchy false
}
}
}
}
vertical_separator {
stretchy false
}
vertical_box {
address_form(address: @address2) {
header {
label('Billing Address') {
stretchy false
}
}
footer {
label('Billing address is used for online payments') {
stretchy false
}
}
}
horizontal_separator {
stretchy false
}
address_view(address: @address2) {
header {
label('Billing Address (Saved)') {
stretchy false
}
}
}
}
}
}
}
end
ClassBasedCustomControlSlots.launch
No comments:
Post a Comment