Glimmer DSL for LibUI 0.0.5

Prerequisite-Free Ruby Desktop Development GUI Library

Gem Version Maintainability Join the chat at https://gitter.im/AndyObtiva/glimmer

Glimmer DSL for LibUI is a prerequisite-free Ruby desktop development GUI library. No need to pre-install any prerequisites. Just install the gem and have platform-independent GUI that just works!

LibUI is a thin Ruby wrapper around libui, a relatively new C GUI library that renders native widgets on every platform (similar to SWT, but without the heavy weight of the Java Virtual Machine).

The main trade-off in using Glimmer DSL for LibUI as opposed to Glimmer DSL for SWT or Glimmer DSL for Tk is the fact that SWT and Tk are more mature than mid-alpha libui as GUI toolkits. Still, if there is only a need to build a small simple application, Glimmer DSL for LibUI could be a good convenient choice due to having zero prerequisites beyond the dependencies included in the Ruby gem. Also, just like Glimmer DSL for Tk, its apps start instantly and have a small memory footprint. LibUI is a promising new GUI toolkit that might prove quite worthy in the future.

Glimmer DSL for LibUI aims to provide a DSL similar to the Glimmer DSL for SWT to enable more productive desktop development in Ruby with:

  • Declarative DSL syntax that visually maps to the GUI widget hierarchy
  • Convention over configuration via smart defaults and automation of low-level details
  • Requiring the least amount of syntax possible to build GUI
  • Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
  • Custom Widget support
  • Scaffolding for new custom widgets, apps, and gems
  • Native-Executable packaging on Mac, Windows, and Linux

Example:

require 'glimmer-dsl-libui'

include Glimmer

window('hello world', 300, 200, 1).show

glimmer-dsl-libui-mac-basic-window.png glimmer-dsl-libui-linux-basic-window.png

NOTE: Glimmer DSL for LibUI is in early alpha mode (only supports included examples). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. It is still an early alpha, so the more feedback and issues you report the better.

Other Glimmer DSL gems you might be interested in:

Glimmer GUI DSL Concepts

The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for LibUI that:

  • Supports smart defaults (e.g. automatic on_closing listener that quits window)
  • Automates wiring of widgets (e.g. button is automatically set as child of window)
  • Hides lower-level details (e.g. LibUI.main loop is started automatically when triggering show on window)
  • Nests widgets according to their visual hierarchy
  • Requires the minimum amount of syntax needed to describe an app's GUI

The Glimmer GUI DSL follows these simple concepts in mapping from LibUI syntax:

  • Control: LibUI controls may be declared by lower-case underscored name (aka keyword) (e.g. window or button). Behind the scenes, they are represented by keyword methods that map to corresponding LibUI.new_keyword methods receiving args (e.g. window('hello world', 300, 200, 1)).
  • Content/Properties/Listeners Block: Any keyword may be optionally followed by a Ruby curly-brace multi-line-block containing nested controls (content) and/or properties (attributes) (e.g. window('hello world', 300, 200, 1) {button('greet')}). It optionally recives one arg representing the control (e.g. button('greet') {|b| on_clicked { puts b.text}})
  • Property: Control properties may be declared inside keyword blocks with lower-case underscored name followed by property value args (e.g. title "hello world" inside group). Behind the scenes, properties correspond to control_set_property methods.
  • Listener: Control listeners may be declared inside keyword blocks with listener lower-case underscored name beginning with on_ and receiving required block handler (e.g. on_clicked {puts 'clicked'} inside button). Behind the scenes, listeners correspond to control_on_event methods.

Example of an app written in LibUI's procedural imperative syntax:

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('hello world', 300, 200, 1)

button = UI.new_button('Button')

UI.button_on_clicked(button) do
  UI.msg_box(main_window, 'Information', 'You clicked the button')
end

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

UI.window_set_child(main_window, button)
UI.control_show(main_window)

UI.main
UI.quit

Example of the same app written in Glimmer object-oriented declarative hierarchical syntax:

require 'glimmer-dsl-libui'

include Glimmer

window('hello world', 300, 200, 1) { |w|
  button('Button') {
    on_clicked do
      msg_box(w, 'Information', 'You clicked the button')
    end
  }

  on_closing do
    puts 'Bye Bye'
  end
}.show

Usage

Install glimmer-dsl-libui gem directly:

gem install glimmer-dsl-libui

Or install via Bundler Gemfile:

gem 'glimmer-dsl-libui', '~> 0.0.5'

Add require 'glimmer-dsl-libui' at the top, and then include Glimmer into the top-level main object for testing or into an actual class for serious usage.

Example (you may copy/paste in girb):

require 'glimmer-dsl-libui'

class Application
  include Glimmer

  def launch
    window('hello world', 300, 200, 1) {
      button('Button') {
        on_clicked do
          puts 'Button Clicked'
        end
      }
    }.show
  end
end

Application.new.launch

API

Any control returned by a Glimmer GUI DSL keyword declaration can be introspected for its properties and updated via object-oriented attributes (standard Ruby attr/attr= or set_attr).

Example (you may copy/paste in girb):

w = window('hello world', 300, 200, 1)
puts w.title # => hello world
w.title = 'howdy'
puts w.title # => howdy
w.set_title 'aloha'
puts w.title # => aloha

Controls are wrapped as Ruby proxy objects, having a #libui method to obtain the wrapped Fiddle pointer object. Ruby proxy objects rely on composition (via Proxy Design Pattern) instead of inheritance to shield consumers from having to deal with lower-level details unless absolutely needed.

Example (you may copy/paste in girb):

w = window('hello world', 300, 200, 1) # => #<Glimmer::LibUI::WindowProxy:0x00007fde4ea39fb0
w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0 free=0x0000000000000000>

Supported Controls and their Properties / Listeners:

  • button: text (String) / on_clicked
  • combobox: items (Array of String), selected (1 or 0) / on_selected
  • color_button: color (r Numeric, g Numeric, b Numeric, a Numeric), selected (1 or 0) / on_selected
  • date_picker: None / None
  • date_time_picker: time (UI::FFI::TM) / on_changed
  • editable_combobox: items (Array of String), text (String) / on_changed
  • entry: read_only (1 or 0), text (String) / on_changed
  • font_button: font (UI::FFI::FontDescriptor) / on_changed
  • group: margined (1 or 0), title (String) / None
  • horizontal_box: padded (1 or 0) / None
  • horizontal_separator: None / None
  • label: text (String) / None
  • menu: None / None
  • menu_item: checked (1 or 0) / on_clicked
  • multiline_entry: read_only (1 or 0), text (String) / None
  • msg_box: None / None
  • non_wrapping_multiline_entry: None / None
  • progress_bar: value (Numeric) / None
  • radio_buttons: selected (1 or 0) / on_selected
  • slider: value (Numeric) / on_changed
  • spinbox: value (Numeric) / on_changed
  • tab: margined (1 or 0), num_pages (Integer) / None
  • tab_item: index read-only, margined (1 or 0), name read-only / None
  • time_picker: None / None
  • vertical_box: padded (1 or 0) / None
  • window: borderless (1 or 0), content_size (width Numeric, height Numeric), fullscreen (1 or 0), margined (1 or 0), title (String) / on_closing, on_content_size_changed

Common Control Properties:

  • enabled (1 or 0)
  • libui (Fiddle::Pointer): returns wrapped LibUI object
  • parent_proxy (Glimmer::LibUI::ControlProxy or subclass)
  • parent (Fiddle::Pointer)
  • toplevel read-only
  • visible (1 or 0)
  • stretchy dsl-only: available in Glimmer GUI DSL when nested under horizontal_box or vertical_box

Common Control Operations:

  • destroy
  • disable
  • enable
  • hide
  • show

To learn more about the LibUI API exposed through Glimmer DSL for LibUI, check out the libui C headers

Girb (Glimmer IRB)

You can run the girb command (bin/girb if you cloned the project locally):

girb

This gives you irb with the glimmer-dsl-libui gem loaded and the Glimmer module mixed into the main object for easy experimentation with GUI.

Gotcha: On the Mac, when you close a window opened in girb, it remains open until you enter exit or open another GUI window.

Examples

These examples reimplement the ones in the LibUI project utilizing the Glimmer GUI DSL.

Basic Window

examples/basic_window.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/basic_window.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/basic_window'"

Mac

glimmer-dsl-libui-mac-basic-window.png

Linux

glimmer-dsl-libui-linux-basic-window.png

LibUI Original Version:

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('hello world', 300, 200, 1)

UI.control_show(main_window)

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

UI.main
UI.quit

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

include Glimmer

window('hello world', 300, 200, 1) {
  on_closing do
    puts 'Bye Bye'
  end
}.show

Basic Button

examples/basic_button.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/basic_button.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/basic_button'"

Mac

glimmer-dsl-libui-mac-basic-button.png glimmer-dsl-libui-mac-basic-button-msg-box.png

Linux

glimmer-dsl-libui-linux-basic-button.png glimmer-dsl-libui-linux-basic-button-msg-box.png

LibUI Original Version:

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('hello world', 300, 200, 1)

button = UI.new_button('Button')

UI.button_on_clicked(button) do
  UI.msg_box(main_window, 'Information', 'You clicked the button')
end

UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

UI.window_set_child(main_window, button)
UI.control_show(main_window)

UI.main
UI.quit

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

include Glimmer

window('hello world', 300, 200, 1) { |w|
  button('Button') {
    on_clicked do
      msg_box(w, 'Information', 'You clicked the button')
    end
  }

  on_closing do
    puts 'Bye Bye'
  end
}.show

Basic Entry

examples/basic_entry.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/basic_entry.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/basic_entry'"

Mac

glimmer-dsl-libui-mac-basic-entry.png glimmer-dsl-libui-mac-basic-entry-msg-box.png

Linux

glimmer-dsl-libui-linux-basic-entry.png glimmer-dsl-libui-linux-basic-entry-msg-box.png

LibUI Original Version:

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('Basic Entry', 300, 50, 1)
UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

hbox = UI.new_horizontal_box
UI.window_set_child(main_window, hbox)

entry = UI.new_entry
UI.entry_on_changed(entry) do
  puts UI.entry_text(entry).to_s
  $stdout.flush # For Windows
end
UI.box_append(hbox, entry, 1)

button = UI.new_button('Button')
UI.button_on_clicked(button) do
  text = UI.entry_text(entry).to_s
  UI.msg_box(main_window, 'You entered', text)
  0
end

UI.box_append(hbox, button, 0)

UI.control_show(main_window)
UI.main
UI.quit

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

include Glimmer

window('Basic Entry', 300, 50, 1) { |w|
  horizontal_box {
    e = entry {
      # stretchy 1 # Smart default option for appending to horizontal_box

      on_changed do
        puts e.text
        $stdout.flush # For Windows
      end
    }

    button('Button') {
      stretchy 0

      on_clicked do
        text = e.text
        msg_box(w, 'You entered', text)
      end
    }
  }

  on_closing do
    puts 'Bye Bye'
  end
}.show

Simple Notepad

examples/simple_notepad.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/simple_notepad.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/simple_notepad'"

Mac

glimmer-dsl-libui-mac-simple-notepad.png

Linux

glimmer-dsl-libui-linux-simple-notepad.png

LibUI Original Version:

require 'libui'

UI = LibUI

UI.init

main_window = UI.new_window('Notepad', 500, 300, 1)
UI.window_on_closing(main_window) do
  puts 'Bye Bye'
  UI.control_destroy(main_window)
  UI.quit
  0
end

vbox = UI.new_vertical_box
UI.window_set_child(main_window, vbox)

entry = UI.new_non_wrapping_multiline_entry
UI.box_append(vbox, entry, 1)

UI.control_show(main_window)
UI.main
UI.quit

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

include Glimmer

window('Notepad', 500, 300, 1) {
  on_closing do
    puts 'Bye Bye'
  end

  vertical_box {
    non_wrapping_multiline_entry
  }
}.show

Midi Player

This example has prerequisites:

  • Install TiMidity and ensure timidity command is in PATH (can be installed via Homebrew on Mac or apt-get on Linux).
  • Add *.mid files to ~/Music directory (you may copy the ones included in sounds directory)

examples/midi_player.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/midi_player.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/midi_player'"

Mac

glimmer-dsl-libui-mac-midi-player.png glimmer-dsl-libui-mac-midi-player-version-msg-box.png

Linux

glimmer-dsl-libui-linux-midi-player.png glimmer-dsl-libui-linux-midi-player-version-msg-box.png

LibUI Original Version:

require 'libui'
UI = LibUI

class TinyMidiPlayer
  VERSION = '0.0.1'

  def initialize
    UI.init
    @pid = nil
    @music_directory = File.expand_path(ARGV[0] || '~/Music/')
    @midi_files      = Dir.glob(File.join(@music_directory, '**/*.mid'))
                          .sort_by { |path| File.basename(path) }
    at_exit { stop_midi }
    create_gui
  end

  def stop_midi
    if @pid
      if @th.alive?
        Process.kill(:SIGKILL, @pid)
        @pid = nil
      else
        @pid = nil
      end
    end
  end

  def play_midi
    stop_midi
    if @pid.nil? && @selected_file
      begin
        @pid = spawn "timidity #{@selected_file}"
        @th = Process.detach @pid
      rescue Errno::ENOENT
        warn 'Timidty++ not found. Please install Timidity++.'
        warn 'https://sourceforge.net/projects/timidity/'
      end
    end
  end

  def show_version(main_window)
    UI.msg_box(main_window,
               'Tiny Midi Player',
               "Written in Ruby\n" \
               "https://github.com/kojix2/libui\n" \
               "Version #{VERSION}")
  end

  def create_gui
    help_menu = UI.new_menu('Help')
    version_item = UI.menu_append_item(help_menu, 'Version')

    UI.new_window('Tiny Midi Player', 200, 50, 1).tap do |main_window|
      UI.menu_item_on_clicked(version_item) { show_version(main_window) }

      UI.window_on_closing(main_window) do
        UI.control_destroy(main_window)
        UI.quit
        0
      end

      UI.new_horizontal_box.tap do |hbox|
        UI.new_vertical_box.tap do |vbox|
          UI.new_button('▶').tap do |button1|
            UI.button_on_clicked(button1) { play_midi }
            UI.box_append(vbox, button1, 1)
          end
          UI.new_button('■').tap do |button2|
            UI.button_on_clicked(button2) { stop_midi }
            UI.box_append(vbox, button2, 1)
          end
          UI.box_append(hbox, vbox, 0)
        end
        UI.window_set_child(main_window, hbox)

        UI.new_combobox.tap do |cbox|
          @midi_files.each do |path|
            name = File.basename(path)
            UI.combobox_append(cbox, name)
          end
          UI.combobox_on_selected(cbox) do |ptr|
            @selected_file = @midi_files[UI.combobox_selected(ptr)]
            play_midi if @th&.alive?
            0
          end
          UI.box_append(hbox, cbox, 1)
        end
      end
      UI.control_show(main_window)
    end
    UI.main
    UI.quit
  end
end

TinyMidiPlayer.new

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

class TinyMidiPlayer
  include Glimmer

  VERSION = '0.0.1'

  def initialize
    @pid = nil
    @music_directory = File.expand_path(ARGV[0] || '~/Music/')
    @midi_files      = Dir.glob(File.join(@music_directory, '**/*.mid'))
                          .sort_by { |path| File.basename(path) }
    at_exit { stop_midi }
    create_gui
  end

  def stop_midi
    if @pid
      if @th.alive?
        Process.kill(:SIGKILL, @pid)
        @pid = nil
      else
        @pid = nil
      end
    end
  end

  def play_midi
    stop_midi
    if @pid.nil? && @selected_file
      begin
        @pid = spawn "timidity #{@selected_file}"
        @th = Process.detach @pid
      rescue Errno::ENOENT
        warn 'Timidty++ not found. Please install Timidity++.'
        warn 'https://sourceforge.net/projects/timidity/'
      end
    end
  end

  def show_version(main_window)
    msg_box(main_window,
               'Tiny Midi Player',
               "Written in Ruby\n" \
               "https://github.com/kojix2/libui\n" \
               "Version #{VERSION}")
  end

  def create_gui
    menu('Help') { |m|
      menu_item('Version') {
        on_clicked do
          show_version(@main_window)
        end
      }
    }
    @main_window = window('Tiny Midi Player', 200, 50, 1) {
      horizontal_box {
        vertical_box {
          stretchy 0

          button('▶') {
            on_clicked do
              play_midi
            end
          }
          button('■') {
            on_clicked do
              stop_midi
            end
          }
        }

        combobox { |c|
          items @midi_files.map { |path| File.basename(path) }

          on_selected do
            @selected_file = @midi_files[c.selected]
            play_midi if @th&.alive?
          end
        }
      }
    }
    @main_window.show
  end
end

TinyMidiPlayer.new

examples/control_gallery.rb

Run with this command from the root of the project if you cloned the project:

ruby -r './lib/glimmer-dsl-libui' examples/control_gallery.rb

Run with this command if you installed the Ruby gem:

ruby -r glimmer-dsl-libui -e "require 'examples/control_gallery'"

Mac

glimmer-dsl-libui-mac-control-gallery.png

Linux

glimmer-dsl-libui-linux-control-gallery.png

LibUI Original Version:

require 'libui'
UI = LibUI

UI.init

should_quit = proc do
  puts 'Bye Bye'
  UI.control_destroy(MAIN_WINDOW)
  UI.quit
  0
end

# File menu
menu = UI.new_menu('File')
open_menu_item = UI.menu_append_item(menu, 'Open')
UI.menu_item_on_clicked(open_menu_item) do
  pt = UI.open_file(MAIN_WINDOW)
  puts pt unless pt.null?
end
save_menu_item = UI.menu_append_item(menu, 'Save')
UI.menu_item_on_clicked(save_menu_item) do
  pt = UI.save_file(MAIN_WINDOW)
  puts pt unless pt.null?
end

UI.menu_append_quit_item(menu)
UI.on_should_quit(should_quit)

# Edit menu
edit_menu = UI.new_menu('Edit')
UI.menu_append_check_item(edit_menu, 'Checkable Item_')
UI.menu_append_separator(edit_menu)
disabled_item = UI.menu_append_item(edit_menu, 'Disabled Item_')
UI.menu_item_disable(disabled_item)

preferences = UI.menu_append_preferences_item(menu)

# Help menu
help_menu = UI.new_menu('Help')
UI.menu_append_item(help_menu, 'Help')
UI.menu_append_about_item(help_menu)

# Main Window
MAIN_WINDOW = UI.new_window('Control Gallery', 600, 500, 1)
UI.window_set_margined(MAIN_WINDOW, 1)
UI.window_on_closing(MAIN_WINDOW, should_quit)

vbox = UI.new_vertical_box
UI.window_set_child(MAIN_WINDOW, vbox)
hbox = UI.new_horizontal_box
UI.box_set_padded(vbox, 1)
UI.box_set_padded(hbox, 1)

UI.box_append(vbox, hbox, 1)

# Group - Basic Controls
group = UI.new_group('Basic Controls')
UI.group_set_margined(group, 1)
UI.box_append(hbox, group, 1) # OSX bug?

inner = UI.new_vertical_box
UI.box_set_padded(inner, 1)
UI.group_set_child(group, inner)

# Button
button = UI.new_button('Button')
UI.button_on_clicked(button) do
  UI.msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
end
UI.box_append(inner, button, 0)

# Checkbox
checkbox = UI.new_checkbox('Checkbox')
UI.checkbox_on_toggled(checkbox) do |ptr|
  checked = UI.checkbox_checked(ptr) == 1
  UI.window_set_title(MAIN_WINDOW, "Checkbox is #{checked}")
  UI.checkbox_set_text(ptr, "I am the checkbox (#{checked})")
end
UI.box_append(inner, checkbox, 0)

# Label
UI.box_append(inner, UI.new_label('Label'), 0)

# Separator
UI.box_append(inner, UI.new_horizontal_separator, 0)

# Date Picker
UI.box_append(inner, UI.new_date_picker, 0)

# Time Picker
UI.box_append(inner, UI.new_time_picker, 0)

# Date Time Picker
UI.box_append(inner, UI.new_date_time_picker, 0)

# Font Button
UI.box_append(inner, UI.new_font_button, 0)

# Color Button
UI.box_append(inner, UI.new_color_button, 0)

inner2 = UI.new_vertical_box
UI.box_set_padded(inner2, 1)
UI.box_append(hbox, inner2, 1)

# Group - Numbers
group = UI.new_group('Numbers')
UI.group_set_margined(group, 1)
UI.box_append(inner2, group, 0)

inner = UI.new_vertical_box
UI.box_set_padded(inner, 1)
UI.group_set_child(group, inner)

# Spinbox
spinbox = UI.new_spinbox(0, 100)
UI.spinbox_set_value(spinbox, 42)
UI.spinbox_on_changed(spinbox) do |ptr|
  puts "New Spinbox value: #{UI.spinbox_value(ptr)}"
end
UI.box_append(inner, spinbox, 0)

# Slider
slider = UI.new_slider(0, 100)
UI.box_append(inner, slider, 0)

# Progressbar
progressbar = UI.new_progress_bar
UI.box_append(inner, progressbar, 0)

UI.slider_on_changed(slider) do |ptr|
  v = UI.slider_value(ptr)
  puts "New Slider value: #{v}"
  UI.progress_bar_set_value(progressbar, v)
end

# Group - Lists
group = UI.new_group('Lists')
UI.group_set_margined(group, 1)
UI.box_append(inner2, group, 0)

inner = UI.new_vertical_box
UI.box_set_padded(inner, 1)
UI.group_set_child(group, inner)

# Combobox
cbox = UI.new_combobox
UI.combobox_append(cbox, 'combobox Item 1')
UI.combobox_append(cbox, 'combobox Item 2')
UI.combobox_append(cbox, 'combobox Item 3')
UI.box_append(inner, cbox, 0)
UI.combobox_on_selected(cbox) do |ptr|
  puts "New combobox selection: #{UI.combobox_selected(ptr)}"
end

# Editable Combobox
ebox = UI.new_editable_combobox
UI.editable_combobox_append(ebox, 'Editable Item 1')
UI.editable_combobox_append(ebox, 'Editable Item 2')
UI.editable_combobox_append(ebox, 'Editable Item 3')
UI.box_append(inner, ebox, 0)

# Radio Buttons
rb = UI.new_radio_buttons
UI.radio_buttons_append(rb, 'Radio Button 1')
UI.radio_buttons_append(rb, 'Radio Button 2')
UI.radio_buttons_append(rb, 'Radio Button 3')
UI.box_append(inner, rb, 1)

# Tab
tab = UI.new_tab
hbox1 = UI.new_horizontal_box
hbox2 = UI.new_horizontal_box
UI.tab_append(tab, 'Page 1', hbox1)
UI.tab_append(tab, 'Page 2', hbox2)
UI.tab_append(tab, 'Page 3', UI.new_horizontal_box)
UI.box_append(inner2, tab, 1)

# Text Entry
text_entry = UI.new_entry
UI.entry_set_text text_entry, 'Please enter your feelings'
UI.entry_on_changed(text_entry) do |ptr|
  puts "Current textbox data: '#{UI.entry_text(ptr)}'"
end
UI.box_append(hbox1, text_entry, 1)

UI.control_show(MAIN_WINDOW)

UI.main
UI.quit

Glimmer DSL for LibUI Version:

require 'glimmer-dsl-libui'

include Glimmer

menu('File') {
  menu_item('Open') {
    on_clicked do
      file = open_file(MAIN_WINDOW)
      puts file unless file.nil?
    end
  }

  menu_item('Save') {
    on_clicked do
      file = save_file(MAIN_WINDOW)
      puts file unless file.nil?
    end
  }

  quit_menu_item {
    on_clicked do
      puts 'Bye Bye'
    end
  }

  preferences_menu_item # Can optionally contain an on_clicked listener
}

menu('Edit') {
  check_menu_item('Checkable Item_')
  separator_menu_item
  menu_item('Disabled Item_') { |mi|
    enabled 0
  }
}

menu('Help') {
  menu_item('Help')

  about_menu_item # Can optionally contain an on_clicked listener
}

MAIN_WINDOW = window('Control Gallery', 600, 500, 1) {
  margined 1

  on_closing do
    puts 'Bye Bye'
  end

  vertical_box { |vb|
    padded 1

    horizontal_box {
      padded 1

      group('Basic Controls') {
        margined 1

        vertical_box {
          padded 1

          button('Button') {
            stretchy 0

            on_clicked do
              msg_box(MAIN_WINDOW, 'Information', 'You clicked the button')
            end
          }

          checkbox('Checkbox') { |c|
            stretchy 0

            on_toggled do
              checked = c.checked == 1
              MAIN_WINDOW.title = "Checkbox is #{checked}"
              c.text = "I am the checkbox (#{checked})"
            end
          }

          label('Label') { stretchy 0 }

          horizontal_separator { stretchy 0 }

          date_picker { stretchy 0 }

          time_picker { stretchy 0 }

          date_time_picker { stretchy 0 }

          font_button { stretchy 0 }

          color_button { stretchy 0 }
        }
      }

      vertical_box {
        padded 1

        group('Numbers') {
          stretchy 0
          margined 1

          vertical_box {
            padded 1

            spinbox(0, 100) { |s|
              stretchy 0
              value 42

              on_changed do
                puts "New Spinbox value: #{s.value}"
              end
            }

            slider(0, 100) { |s|
              stretchy 0

              on_changed do
                v = s.value
                puts "New Slider value: #{v}"
                @progress_bar.value = v
              end
            }

            @progress_bar = progress_bar { stretchy 0 }
          }
        }

        group('Lists') {
          stretchy 0
          margined 1

          vertical_box {
            padded 1

            combobox { |c|
              stretchy 0
              items ['combobox Item 1', 'combobox Item 2', 'combobox Item 3']

              on_selected do
                puts "New combobox selection: #{c.selected}"
              end
            }

            editable_combobox {
              stretchy 0
              items ['Editable Item 1', 'Editable Item 2', 'Editable Item 3']
            }

            radio_buttons {
              items ['Radio Button 1', 'Radio Button 2', 'Radio Button 3']
            }
          }
        }

        tab {
          tab_item('Page 1') {
            horizontal_box {
              entry { |e|
                text 'Please enter your feelings'

                on_changed do
                  puts "Current textbox data: '#{e.text}'"
                end
              }
            }
          }

          tab_item('Page 2') {
            horizontal_box
          }

          tab_item('Page 3') {
            horizontal_box
          }
        }
      }
    }
  }
}

MAIN_WINDOW.show

Contributing to glimmer-dsl-libui

  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
  • Fork the project.
  • Start a feature/bugfix branch.
  • Commit and push until you are happy with your contribution.
  • Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Help

Issues

You may submit issues on GitHub.

Click here to submit an issue.

Chat

If you need live help, try to Join the chat at https://gitter.im/AndyObtiva/glimmer

Process

Glimmer Process

Planned Features and Feature Suggestions

These features have been planned or suggested. You might see them in a future version of Glimmer DSL for LibUI. You are welcome to contribute more feature suggestions.

TODO.md

Change Log

CHANGELOG.md

Contributors

Click here to view contributor commits.

License

MIT

Copyright (c) 2021 Andy Maleh

--

Built for Glimmer (DSL Framework).