48
loading...
This website collects cookies to deliver better user experience
Object
becomes Glimmer::DataBinding::ObservableModel
, which supports observing specified Object
model attributes.Hash
becomes Glimmer::DataBinding::ObservableHash
, which supports observing all Hash
keys or a specific Hash
keyArray
becomes Glimmer::DataBinding::ObservableArray
, which supports observing Array
changes like those done with push
, <<
, delete
, and map!
methods (all mutation methods).observe(person, :name) do |new_name|
@name_label.text = new_name
end
label
text
property accordingly.observe
keyword at Color The Circles, Method-Based Custom Keyword, Snake, and Tetris.checkbox
: checked
check_menu_item
: checked
color_button
: color
combobox
: selected
, selected_item
date_picker
: time
date_time_picker
: time
editable_combobox
: text
entry
: text
font_button
: font
multiline_entry
: text
non_wrapping_multiline_entry
: text
radio_buttons
: selected
radio_menu_item
: checked
search_entry
: text
slider
: value
spinbox
: value
table
: cell_rows
(explicit data-binding by using <=>
and implicit data-binding by assigning value directly)time_picker
: time
entry {
text <=> [contract, :legal_text]
}
entry
text
property.entry {
text <=> [self, :entered_text, after_write: ->(text) {puts text}]
}
entered_text
attribute on self
to entry
text
property and printing text after write to the model.square(0, 0, CELL_SIZE) {
fill <= [@grid.cells[row][column], :color]
}
square
shape's fill
property. That means if the color
attribute of the grid cell is updated, the fill
property of the square
shape is automatically updated accordingly.window {
title <= [@game, :score, on_read: -> (score) {"Glimmer Snake (Score: #{@game.score})"}]
}
window
title
property to the score
attribute of a @game
, but converting on read from the Model to a String
.view_property <=> [model, attribute, *read_or_write_options]
: Bidirectional (two-way) data-binding to Model attribute accessorview_property <= [model, attribute, *read_only_options]
: Unidirectional (one-way) data-binding to Model attribute readerSymbol
representing attribute reader/writer (e.g. [person, :name
])String
representing nested attribute path (e.g. [company, 'address.street']
). That results in "nested data-binding"String
containing array attribute index (e.g. [customer, 'addresses[0].street']
). That results in "indexed data-binding"before_read {|value| ...}
: performs an operation before reading data from Model to update the View.on_read {|value| ...}
: converts value read from Model to update the View.after_read {|converted_value| ...}
: performs an operation after read from Model and updating the View.before_write {|value| ...}
: performs an operation before writing data to Model from View.on_write {|value| ...}
: converts value read from View to update the Model.after_write {|converted_value| ...}
: performs an operation after writing to Model from View.computed_by attribute
or computed_by [attribute1, attribute2, ...]
: indicates model attribute is computed from specified attribute(s), thus updated when they are updated (see in Login example version 2). That is known as "computed data-binding".on_read
and on_write
converters, you could pass a Symbol
representing the name of a method on the value object to invoke.entry {
text <=> [product, :price, on_read: :to_s, on_write: :to_i]
}
entry
text
property to self
text
attribute) as it would conflict with it. Instead, data-bind view property to an attribute with a different name on the view object or with the same name, but on a presenter or model object (e.g. data-bind entry
text
to self
legal_text
attribute or to contract
model text
attribute)on_changed
for entry
text
), so you cannot hook into the listener directly anymore as that would negate data-binding. Instead, you can add an after_write: ->(val) {}
option to perform something on trigger of the control listener instead.ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
Mac | Windows | Linux |
---|---|---|
![]() |
![]() |
![]() |
require 'glimmer-dsl-libui'
class FormTable
Contact = Struct.new(:name, :email, :phone, :city, :state)
include Glimmer
attr_accessor :contacts, :name, :email, :phone, :city, :state, :filter_value
def initialize
@contacts = [
Contact.new('Lisa Sky', '[email protected]', '720-523-4329', 'Denver', 'CO'),
Contact.new('Jordan Biggins', '[email protected]', '617-528-5399', 'Boston', 'MA'),
Contact.new('Mary Glass', '[email protected]', '847-589-8788', 'Elk Grove Village', 'IL'),
Contact.new('Darren McGrath', '[email protected]', '206-539-9283', 'Seattle', 'WA'),
Contact.new('Melody Hanheimer', '[email protected]', '213-493-8274', 'Los Angeles', 'CA'),
]
end
def launch
window('Contacts', 600, 600) { |w|
margined true
vertical_box {
form {
stretchy false
entry {
label 'Name'
text <=> [self, :name] # bidirectional data-binding between entry text and self.name
}
entry {
label 'Email'
text <=> [self, :email]
}
entry {
label 'Phone'
text <=> [self, :phone]
}
entry {
label 'City'
text <=> [self, :city]
}
entry {
label 'State'
text <=> [self, :state]
}
}
button('Save Contact') {
stretchy false
on_clicked do
new_row = [name, email, phone, city, state]
if new_row.include?('')
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
else
@contacts << Contact.new(*new_row) # automatically inserts a row into the table due to explicit data-binding
@unfiltered_contacts = @contacts.dup
self.name = '' # automatically clears name entry through explicit data-binding
self.email = ''
self.phone = ''
self.city = ''
self.state = ''
end
end
}
search_entry {
stretchy false
# bidirectional data-binding of text to self.filter_value with after_write option
text <=> [self, :filter_value,
after_write: ->(filter_value) { # execute after write to self.filter_value
@unfiltered_contacts ||= @contacts.dup
# Unfilter first to remove any previous filters
self.contacts = @unfiltered_contacts.dup # affects table indirectly through explicit data-binding
# Now, apply filter if entered
unless filter_value.empty?
self.contacts = @contacts.filter do |contact| # affects table indirectly through explicit data-binding
contact.members.any? do |attribute|
contact[attribute].to_s.downcase.include?(filter_value.downcase)
end
end
end
}
]
}
table {
text_column('Name')
text_column('Email')
text_column('Phone')
text_column('City')
text_column('State')
editable true
# explicit data-binding to Model Array (expects model attribute names to be underscored column names by convention [e.g. :state for State], can be customized with :column_attributes option [e.g. {'State/Province' => :state})
cell_rows <=> [self, :contacts]
on_changed do |row, type, row_data|
puts "Row #{row} #{type}: #{row_data}"
end
}
}
}.show
end
end
FormTable.new.launch