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', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO'), Contact.new('Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA'), Contact.new('Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL'), Contact.new('Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA'), Contact.new('Melody Hanheimer', 'melody@hanheimer.com', '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 cell_rows <=> [self, :contacts] # explicit data-binding to Model Array on_changed do |row, type, row_data| puts "Row #{row} #{type}: #{row_data}" end } } }.show end end FormTable.new.launch