glimmer-dsl-libui 0.2.11 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.2.11
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.2.15
2
2
  ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
- [![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
5
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
5
 
7
6
  [Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [LibUI](https://github.com/kojix2/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 native GUI that just works!
@@ -10,13 +9,11 @@
10
9
 
11
10
  The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) as opposed to [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) or [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) is the fact that [SWT](https://www.eclipse.org/swt/) and [Tk](https://www.tcl.tk/) are more mature than mid-alpha [libui](https://github.com/andlabs/libui) as GUI toolkits. Still, if there is only a need to build a small simple application, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) could be a good convenient choice due to having zero prerequisites beyond the dependencies included in the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui). Also, just like [Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk), its apps start instantly and have a small memory footprint. [LibUI](https://github.com/kojix2/LibUI) is a promising new GUI toolkit that might prove quite worthy in the future.
12
11
 
13
- **(Note: although LibUI works on Windows, this project has not been tested on Windows yet. It has only been verified on Mac x64 and Linux x64)**
14
-
15
12
  [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
16
13
  - Declarative DSL syntax that visually maps to the GUI control hierarchy
17
14
  - Convention over configuration via smart defaults and automation of low-level details
18
15
  - Requiring the least amount of syntax possible to build GUI
19
- - Custom Control support
16
+ - Custom Keyword support
20
17
  - [Far Future Plan] Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
21
18
  - [Far Future Plan] Scaffolding for new custom controls, apps, and gems
22
19
  - [Far Future Plan] Native-Executable packaging on Mac, Windows, and Linux.
@@ -134,11 +131,9 @@ window('Area Gallery', 400, 400) {
134
131
  stroke r: 0, g: 0, b: 0, thickness: 2
135
132
  }
136
133
  text(160, 40, 100) { # x, y, width
137
- string {
134
+ string('Area Gallery') {
138
135
  font family: 'Times', size: 14
139
136
  color :black
140
-
141
- 'Area Gallery'
142
137
  }
143
138
  }
144
139
 
@@ -214,7 +209,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
214
209
  - [Usage](#usage)
215
210
  - [Girb (Glimmer IRB)](#girb-glimmer-irb)
216
211
  - [API](#api)
217
- - [Supported Controls](#supported-controls)
212
+ - [Supported Keywords](#supported-keywords)
218
213
  - [Common Control Properties](#common-control-properties)
219
214
  - [Common Control Operations](#common-control-operations)
220
215
  - [LibUI Operations](#libui-operations)
@@ -262,13 +257,18 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
262
257
  - [Basic Draw Text](#basic-draw-text)
263
258
  - [Custom Draw Text](#custom-draw-text)
264
259
  - [Method-Based Custom Keyword](#method-based-custom-keyword)
265
- - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
260
+ - [Applications](#applications)
261
+ - [Manga2PDF](#manga2pdf)
262
+ - [Befunge98 GUI](#befunge98-gui)
263
+ - [i3off Gtk Ruby](#i3off-gtk-ruby)
264
+ - [Process](#process)
265
+ - [Resources](#resources)
266
266
  - [Help](#help)
267
267
  - [Issues](#issues)
268
268
  - [Chat](#chat)
269
- - [Process](#process)
270
269
  - [Planned Features and Feature Suggestions](#planned-features-and-feature-suggestions)
271
270
  - [Change Log](#change-log)
271
+ - [Contributing](#contributing)
272
272
  - [Contributors](#contributors)
273
273
  - [License](#license)
274
274
 
@@ -282,10 +282,10 @@ The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for
282
282
  - Requires the minimum amount of syntax needed to describe an app's GUI
283
283
 
284
284
  The Glimmer GUI DSL follows these simple concepts in mapping from [LibUI](https://github.com/kojix2/LibUI) syntax:
285
- - **Control**: [LibUI](https://github.com/kojix2/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, true)`).
286
- - **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, true) {button('greet')}`). It optionally receives one arg representing the control (e.g. `button('greet') {|b| on_clicked { puts b.text}}`)
287
- - **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.
288
- - **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.
285
+ - **Keyword(args)**: [LibUI](https://github.com/kojix2/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, true)`).
286
+ - **Content Block** (Properties/Listeners/Controls): Any keyword may be optionally followed by a Ruby curly-brace multi-line content block containing properties (attributes), listeners, and/or nested controls (e.g. `window {title 'hello world'; on_closing {puts 'Bye'}; button('greet')}`). Content block optionally receives one arg representing the control (e.g. `button('greet') {|b| on_clicked { puts b.text}}`)
287
+ - **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 `LibUI.control_set_property` methods.
288
+ - **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`). Optionally, the listener block can receive an arg representing the control (e.g. `on_clicked {|btn| puts btn.text}`). Behind the scenes, listeners correspond to `LibUI.control_on_event` methods.
289
289
 
290
290
  Example of an app written in [LibUI](https://github.com/kojix2/LibUI)'s procedural imperative syntax:
291
291
 
@@ -349,7 +349,7 @@ gem install glimmer-dsl-libui
349
349
  Or install via Bundler `Gemfile`:
350
350
 
351
351
  ```ruby
352
- gem 'glimmer-dsl-libui', '~> 0.2.11'
352
+ gem 'glimmer-dsl-libui', '~> 0.2.15'
353
353
  ```
354
354
 
355
355
  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.
@@ -409,7 +409,7 @@ w.set_title 'aloha'
409
409
  puts w.title # => aloha
410
410
  ```
411
411
 
412
- 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](https://en.wikipedia.org/wiki/Proxy_pattern)) instead of inheritance to shield consumers from having to deal with lower-level details unless absolutely needed.
412
+ Controls are wrapped as Ruby proxy objects, having a `#libui` method to obtain the wrapped [LibUI](https://github.com/kojix2/LibUI) Fiddle pointer object. Ruby proxy objects rely on composition (via [Proxy Design Pattern](https://en.wikipedia.org/wiki/Proxy_pattern)) instead of inheritance to shield consumers from having to deal with lower-level details unless absolutely needed.
413
413
 
414
414
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
415
415
 
@@ -418,9 +418,11 @@ w = window('hello world') # => #<Glimmer::LibUI::WindowProxy:0x00007fde4ea39fb0
418
418
  w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0 free=0x0000000000000000>
419
419
  ```
420
420
 
421
- ### Supported Controls
421
+ ### Supported Keywords
422
422
 
423
- Control(Args) | Properties | Listeners
423
+ These are all the supported keywords. Note that some keywords do not represent controls, but produce objects that are used as the property values of controls (e.g. `image` builds objects to use in `cell_rows` for a `table` with an image column)
424
+
425
+ Keyword(Args) | Properties | Listeners
424
426
  ------------- | ---------- | ---------
425
427
  `about_menu_item` | None | `on_clicked`
426
428
  `area` | None | `on_draw(area_draw_params)`, `on_mouse_event(area_mouse_event)`, `on_mouse_down(area_mouse_event)`, `on_mouse_up(area_mouse_event)`, `on_mouse_drag_started(area_mouse_event)`, `on_mouse_dragged(area_mouse_event)`, `on_mouse_dropped(area_mouse_event)`, `on_mouse_entered`, `on_mouse_exited`, `on_key_event(area_key_event)`, `on_key_down(area_key_event)`, `on_key_up(area_key_event)`
@@ -456,6 +458,8 @@ Control(Args) | Properties | Listeners
456
458
  `matrix(m11 = nil as Numeric, m12 = nil as Numeric, m21 = nil as Numeric, m22 = nil as Numeric, m31 = nil as Numeric, m32 = nil as Numeric)` | `m11` (`Numeric`), `m12` (`Numeric`), `m21` (`Numeric`), `m22` (`Numeric`), `m31` (`Numeric`), `m32` (`Numeric`) | None
457
459
  `menu(text as String)` | None | None
458
460
  `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
461
+ `message_box` (alias for `msg_box`; see for arguments) | None | None
462
+ `message_box_error` (alias for `msg_box_error`; see for arguments) | None | None
459
463
  `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
460
464
  `msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
461
465
  `msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
@@ -472,7 +476,7 @@ Control(Args) | Properties | Listeners
472
476
  `slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
473
477
  `spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
474
478
  `square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
475
- `string` | `font`, `color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `background` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `underline`, `underline_color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `open_type_features` | None
479
+ `string(string = '')` | `font`, `color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `background` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `underline`, `underline_color` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color), `open_type_features`, `string` (`String`) | None
476
480
  `tab` | `margined` (Boolean), `num_pages` (`Integer`) | None
477
481
  `tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
478
482
  `table` | `cell_rows` (`Array` (rows) of `Arrays` (row columns) of cell values (e.g. `String` values for `text_column` cells or `Array` of `image`/`String` for `image_text_column`)), `editable` as Boolean | `on_changed {|row, type, row_data| ...}`, `on_edited {|row, row_data| ...}`
@@ -517,8 +521,8 @@ All operations that could normally be called on `LibUI` can also be called on `G
517
521
 
518
522
  ### Extra Dialogs
519
523
 
520
- - `open_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
521
- - `save_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
524
+ - `open_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
525
+ - `save_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
522
526
 
523
527
  ### Extra Operations
524
528
 
@@ -531,13 +535,13 @@ All operations that could normally be called on `LibUI` can also be called on `G
531
535
 
532
536
  ### Table API
533
537
 
534
- The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Controls](#supported-controls)):
538
+ The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Keywords](#supported-keywords)):
535
539
  - `background_color_column`: expects color cell values
536
540
  - `button_column`: expects `String` cell values
537
541
  - `checkbox_column`: expects Boolean cell values
538
542
  - `checkbox_text_column`: expects dual-element `Array` of Boolean and `String` cell values
539
543
  - `checkbox_text_color_column`: expects triple-element `Array` of Boolean, `String`, and color cell values
540
- - `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported Controls](#supported-controls))
544
+ - `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported Keywords](#supported-keywords))
541
545
  - `image_text_column`: expects dual-element `Array` of `image` and `String` cell values
542
546
  - `image_text_color_column`: expects triple-element `Array` of `image`, `String`, and color cell values
543
547
  - `text_column`: expects `String` cell values
@@ -599,6 +603,7 @@ window('Contacts', 600, 600) { |w|
599
603
  msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
600
604
  else
601
605
  data << new_row # automatically inserts a row into the table due to implicit data-binding
606
+ @unfiltered_data = data.dup
602
607
  @name_entry.text = ''
603
608
  @email_entry.text = ''
604
609
  @phone_entry.text = ''
@@ -608,6 +613,25 @@ window('Contacts', 600, 600) { |w|
608
613
  end
609
614
  }
610
615
 
616
+ search_entry { |se|
617
+ stretchy false
618
+
619
+ on_changed do
620
+ filter_value = se.text
621
+ @unfiltered_data ||= data.dup
622
+ # Unfilter first to remove any previous filters
623
+ data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
624
+ # Now, apply filter if entered
625
+ unless filter_value.empty?
626
+ data.filter! do |row_data| # affects table indirectly through implicit data-binding
627
+ row_data.any? do |cell|
628
+ cell.to_s.downcase.include?(filter_value.downcase)
629
+ end
630
+ end
631
+ end
632
+ end
633
+ }
634
+
611
635
  table {
612
636
  text_column('Name')
613
637
  text_column('Email')
@@ -616,6 +640,10 @@ window('Contacts', 600, 600) { |w|
616
640
  text_column('State')
617
641
 
618
642
  cell_rows data # implicit data-binding
643
+
644
+ on_changed do |row, type, row_data|
645
+ puts "Row #{row} #{type}: #{row_data}"
646
+ end
619
647
  }
620
648
  }
621
649
  }.show
@@ -628,8 +656,8 @@ Learn more by checking out [examples](#examples).
628
656
  ### Area API
629
657
 
630
658
  The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
631
- - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be few stable paths (mostly for decorative reasons).
632
- - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block that receives a `area_draw_params` argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
659
+ - Declaratively via stable paths: useful for stable paths that will not change often later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be relatively few stable paths (mostly for decorative reasons).
660
+ - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change very often. Open an `on_draw` listener block that receives a `area_draw_params` argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
633
661
 
634
662
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
635
663
 
@@ -816,19 +844,23 @@ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wi
816
844
 
817
845
  Check [Histogram](#histogram) example for use of hex colors.
818
846
 
819
- To draw `text` in an `area`, you simply nest a `text(x, y, width)` control directly under `area` or inside a `on_draw` listener, and then nest attributed `string {string_value}` controls underneath it returning an actual `String` (think of them as the `<span>` element in html, which contains a string of text).
847
+ To draw `text` in an `area`, you simply nest a `text(x, y, width)` control directly under `area` or inside a `on_draw` listener, and then nest attributed `string {[attributes]; string_value}` controls underneath it returning an actual `String` (think of them as the `<span>` or `<p>` element in html, which contains a string of text). Alternatively, you can nest attributed `string(string_value) {[attributes]}` if `string_value` is a short single-line string. An attributed `string` value can be changed dynamically via its `string` property.
820
848
 
821
- `text` control can have the following properties:
849
+ `text` has the following properties:
822
850
  - `default_font`:
823
851
  - `align`: `:left` (default), `:center`, or `:right` (`align` currently seems not to work on the Mac)
852
+ - `x`: x coordinate in relation to parent `area` top-left corner
853
+ - `y`: y coordinate in relation to parent `area` top-left corner
854
+ - `width` (default: area width - x*2): width of text to display
824
855
 
825
- `string` can have the following properties:
856
+ `string` has the following properties:
826
857
  - `font`: font descriptor hash consisting of `:family`, `:size`, `:weight` (`[:minimum, :thin, :ultra_light, :light, :book, :normal, :medium, :semi_bold, :bold, :ultra_bold, :heavy, :ultra_heavy, :maximum]`), `:italic` (`[:normal, :oblique, :italic]`), and `:stretch` (`[:ultra_condensed, :extra_condensed, :condensed, :semi_condensed, :normal, :semi_expanded, :expanded, :extra_expanded, :ultra_expanded]`) key values
827
858
  - `color`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
828
859
  - `background`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
829
860
  - `underline`: one of `:none`, `:single`, `:double`, `:suggestion`, `:color_custom`, `:color_spelling`, `:color_grammar`, `:color_auxiliary`
830
861
  - `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
831
862
  - `open_type_features`: Open Type Features (https://www.microsoft.com/typography/otspec/featuretags.htm) consist of `open_type_tag`s nested in content block, which accept (`a`, `b`, `c`, `d`, `Integer`) arguments.
863
+ - `string`: string value (`String`)
832
864
 
833
865
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
834
866
 
@@ -849,12 +881,13 @@ window('area text drawing') {
849
881
  open_type_tag 'l', 'i', 'g', 'a', 1
850
882
  }
851
883
 
852
- "This is a test\n\n"
884
+ "This is a demonstration\n" \
885
+ "of a very long\n" \
886
+ "attributed string\n" \
887
+ "spanning multiple lines\n\n"
853
888
  }
854
889
 
855
- string {
856
- 'This is another test'
857
- }
890
+ string('This is a short unattributed string')
858
891
  }
859
892
  }
860
893
  }.show
@@ -888,9 +921,11 @@ window('area text drawing') {
888
921
  - Table `cell_rows` data has implicit data-binding to table cell values for deletion, insertion, and change (done by diffing `cell_rows` value before and after change and auto-informing `table` of deletions [`LibUI.table_model_row_deleted`], insertions [`LibUI.table_model_row_deleted`], and changes [`LibUI.table_model_row_changed`]). When deleting data rows from `cell_rows` array, then actual rows from the `table` are automatically deleted. When inserting data rows into `cell_rows` array, then actual `table` rows are automatically inserted. When updating data rows in `cell_rows` array, then actual `table` rows are automatically updated.
889
922
  - `image` instances are automatically freed from memory after `window` is destroyed.
890
923
  - `image` `width` and `height` can be left off if it has one `image_part` only as they default to the same `width` and `height` of the `image_part`
924
+ - Automatically provide shifted `:key` characters in `area_key_event` provided in `area` key listeners `on_key_event`, `on_key_down`, and `on_key_up`
891
925
  - `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
892
926
  - Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
893
927
  - Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
928
+ - Observe `text` and `string` properties for changes and automatically redraw containing area accordingly
894
929
  - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
895
930
  - All resources are freed automatically once no longer needed or left to garbage collection.
896
931
  - When nesting an `area` directly underneath `window` (without a layout control like `vertical_box`), it is automatically reparented with `vertical_box` in between the `window` and `area` since it would not show up on Linux otherwise.
@@ -1008,8 +1043,13 @@ window('Method-Based Custom Keyword') {
1008
1043
  ### API Gotchas
1009
1044
 
1010
1045
  - There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`).
1011
- - `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on Windows and Linux (not Mac) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
1046
+ - `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on Linux and Windows (not Mac) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
1012
1047
  - `text` `align` property seems not to work on the Mac ([libui](https://github.com/andlabs/libui) has an [issue](https://github.com/andlabs/libui/pull/407) about it)
1048
+ - `text` `string` `background` does not work on Windows due to an [issue in libui](https://github.com/andlabs/libui/issues/347).
1049
+ - `arc` shape does not work on Windows unless a figure is started due to implementation of [libui](https://github.com/andlabs/libui).
1050
+ - `table` controls on Windows intentionally get an extra empty row at the end because if any row were to be deleted for the first time, double-deletion happens due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
1051
+ - `table` `progress_bar` column on Windows cannot be updated with a positive value if it started initially with `-1` (it ignores update to avoid crashing due to an issue in [libui](https://github.com/andlabs/libui) on Windows.
1052
+ - It seems that [libui](https://github.com/andlabs/libui) does not support nesting multiple `area` controls under a `grid` as only the first one shows up in that scenario. To workaround that limitation, use a `vertical_box` with nested `horizontal_box`s instead to include multiple `area`s in a GUI.
1013
1053
 
1014
1054
  ### Original API
1015
1055
 
@@ -1024,7 +1064,7 @@ I am documenting options for packaging, which I have not tried myself, but figur
1024
1064
 
1025
1065
  For Windows, the [LibUI](https://github.com/kojix2/LibUI) project recommends [OCRA](https://github.com/larsch/ocra) (One-Click Ruby Application), which builds Windows executables from Ruby source.
1026
1066
 
1027
- For Mac, consider [Platybus](https://github.com/sveinbjornt/Platypus) (builds a native Mac app from a Ruby script)
1067
+ For Mac, consider [Platypus](https://github.com/sveinbjornt/Platypus) (builds a native Mac app from a Ruby script)
1028
1068
 
1029
1069
  For Linux, simply package your app as a [Ruby Gem](https://guides.rubygems.org/what-is-a-gem/) and [build rpm package from Ruby Gem](https://www.redpill-linpro.com/sysadvent/2015/12/07/building-rpms-from-gems.html) or [build deb package from Ruby Gem](https://openpreservation.org/blogs/building-debian-package-ruby-program/).
1030
1070
 
@@ -1111,15 +1151,20 @@ class MetaExample
1111
1151
  end
1112
1152
 
1113
1153
  def run_example(example)
1114
- command = "ruby -r #{glimmer_dsl_libui_file} #{example} 2>&1"
1115
- result = ''
1116
- IO.popen(command) do |f|
1117
- f.each_line do |line|
1118
- result << line
1119
- puts line
1154
+ Thread.new do
1155
+ command = "ruby -r #{glimmer_dsl_libui_file} #{example} 2>&1"
1156
+ result = ''
1157
+ IO.popen(command) do |f|
1158
+ sleep(0.0001) # yield to main thread
1159
+ f.each_line do |line|
1160
+ result << line
1161
+ puts line
1162
+ $stdout.flush # for Windows
1163
+ sleep(0.0001) # yield to main thread
1164
+ end
1120
1165
  end
1166
+ Glimmer::LibUI.queue_main { msg_box('Error Running Example', result) } if result.downcase.include?('error')
1121
1167
  end
1122
- msg_box('Error Running Example', result) if result.downcase.include?('error')
1123
1168
  end
1124
1169
 
1125
1170
  def launch
@@ -3375,8 +3420,6 @@ Linux
3375
3420
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3376
3421
 
3377
3422
  ```ruby
3378
- # frozen_string_literal: true
3379
-
3380
3423
  require 'glimmer-dsl-libui'
3381
3424
 
3382
3425
  include Glimmer
@@ -3906,11 +3949,9 @@ window('Area Gallery', 400, 400) {
3906
3949
  stroke r: 0, g: 0, b: 0, thickness: 2
3907
3950
  }
3908
3951
  text(160, 40, 100) { # x, y, width
3909
- string {
3952
+ string('Area Gallery') {
3910
3953
  font family: 'Times', size: 14
3911
3954
  color :black
3912
-
3913
- 'Area Gallery'
3914
3955
  }
3915
3956
  }
3916
3957
 
@@ -4214,11 +4255,9 @@ window('Area Gallery', 400, 400) {
4214
4255
  stroke r: 0, g: 0, b: 0, thickness: 2
4215
4256
  }
4216
4257
  text(160, 40, 100) { # x, y, width
4217
- string {
4258
+ string('Area Gallery') {
4218
4259
  font family: 'Times', size: 14
4219
4260
  color :black
4220
-
4221
- 'Area Gallery'
4222
4261
  }
4223
4262
  }
4224
4263
  end
@@ -5139,8 +5178,8 @@ class ColorTheCircles
5139
5178
 
5140
5179
  WINDOW_WIDTH = 800
5141
5180
  WINDOW_HEIGHT = 600
5142
- CIRCLE_MIN_RADIUS = 15
5143
- CIRCLE_MAX_RADIUS = 50
5181
+ SHAPE_MIN_SIZE = 15
5182
+ SHAPE_MAX_SIZE = 75
5144
5183
  MARGIN_WIDTH = 55
5145
5184
  MARGIN_HEIGHT = 155
5146
5185
  TIME_MAX_EASY = 4
@@ -5154,6 +5193,7 @@ class ColorTheCircles
5154
5193
  @circles_data = []
5155
5194
  @score = 0
5156
5195
  @time_max = TIME_MAX_HARD
5196
+ @game_over = false
5157
5197
  register_observers
5158
5198
  setup_circle_factory
5159
5199
  end
@@ -5162,9 +5202,11 @@ class ColorTheCircles
5162
5202
  observer = Glimmer::DataBinding::Observer.proc do |new_score|
5163
5203
  @score_label.text = new_score.to_s
5164
5204
  if new_score == -20
5205
+ @game_over = true
5165
5206
  msg_box('You Lost!', 'Sorry! Your score reached -20')
5166
5207
  restart_game
5167
5208
  elsif new_score == 0
5209
+ @game_over = true
5168
5210
  msg_box('You Won!', 'Congratulations! Your score reached 0')
5169
5211
  restart_game
5170
5212
  end
@@ -5174,11 +5216,13 @@ class ColorTheCircles
5174
5216
 
5175
5217
  def setup_circle_factory
5176
5218
  consumer = Proc.new do
5177
- if @circles_data.empty?
5178
- # start with 3 circles to make more challenging
5179
- add_circle until @circles_data.size > 3
5180
- else
5181
- add_circle
5219
+ unless @game_over
5220
+ if @circles_data.empty?
5221
+ # start with 3 circles to make more challenging
5222
+ add_circle until @circles_data.size > 3
5223
+ else
5224
+ add_circle
5225
+ end
5182
5226
  end
5183
5227
  delay = rand * @time_max
5184
5228
  Glimmer::LibUI.timer(delay, repeat: false, &consumer)
@@ -5187,12 +5231,12 @@ class ColorTheCircles
5187
5231
  end
5188
5232
 
5189
5233
  def add_circle
5190
- circle_x_center = rand * (WINDOW_WIDTH - MARGIN_WIDTH - CIRCLE_MAX_RADIUS) + CIRCLE_MAX_RADIUS
5191
- circle_y_center = rand * (WINDOW_HEIGHT - MARGIN_HEIGHT - CIRCLE_MAX_RADIUS) + CIRCLE_MAX_RADIUS
5192
- circle_radius = rand * (CIRCLE_MAX_RADIUS - CIRCLE_MIN_RADIUS) + CIRCLE_MIN_RADIUS
5234
+ circle_x = rand * (WINDOW_WIDTH - MARGIN_WIDTH - SHAPE_MAX_SIZE) + SHAPE_MAX_SIZE
5235
+ circle_y = rand * (WINDOW_HEIGHT - MARGIN_HEIGHT - SHAPE_MAX_SIZE) + SHAPE_MAX_SIZE
5236
+ circle_size = rand * (SHAPE_MAX_SIZE - SHAPE_MIN_SIZE) + SHAPE_MIN_SIZE
5193
5237
  stroke_color = Glimmer::LibUI.x11_colors.sample
5194
5238
  @circles_data << {
5195
- args: [circle_x_center, circle_y_center, circle_radius],
5239
+ args: [circle_x, circle_y, circle_size],
5196
5240
  fill: nil,
5197
5241
  stroke: stroke_color
5198
5242
  }
@@ -5203,8 +5247,28 @@ class ColorTheCircles
5203
5247
  def restart_game
5204
5248
  @score = 0 # update variable directly to avoid notifying observers
5205
5249
  @circles_data.clear
5250
+ @game_over = false
5206
5251
  end
5207
5252
 
5253
+ def color_circle(x, y)
5254
+ clicked_circle_data = @circles_data.find do |circle_data|
5255
+ circle_data[:fill].nil? && circle_data[:circle]&.include?(x, y)
5256
+ end
5257
+ if clicked_circle_data
5258
+ clicked_circle_data[:fill] = clicked_circle_data[:stroke]
5259
+ push_colored_circle_behind_uncolored_circles(clicked_circle_data)
5260
+ @area.queue_redraw_all
5261
+ self.score += 1 # notifies score observers automatically of change
5262
+ end
5263
+ end
5264
+
5265
+ def push_colored_circle_behind_uncolored_circles(colored_circle_data)
5266
+ removed_colored_circle_data = @circles_data.delete(colored_circle_data)
5267
+ last_colored_circle_data = @circles_data.select {|cd| cd[:fill]}.last
5268
+ last_colored_circle_data_index = @circles_data.index(last_colored_circle_data) || -1
5269
+ @circles_data.insert(last_colored_circle_data_index + 1, removed_colored_circle_data)
5270
+ end
5271
+
5208
5272
  def launch
5209
5273
  menu('Actions') {
5210
5274
  menu_item('Restart') {
@@ -5292,45 +5356,35 @@ class ColorTheCircles
5292
5356
  }
5293
5357
  }
5294
5358
 
5295
- vertical_box {
5359
+ @area = area {
5296
5360
  left 0
5297
5361
  top 4
5298
5362
  hexpand true
5299
5363
  vexpand true
5300
5364
  halign :fill
5301
5365
  valign :fill
5302
-
5303
- @area = area {
5304
- on_draw do |area_draw_params|
5366
+
5367
+ on_draw do |area_draw_params|
5368
+ path {
5369
+ rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
5370
+
5371
+ fill :white
5372
+ }
5373
+
5374
+ @circles_data.each do |circle_data|
5305
5375
  path {
5306
- rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT)
5307
-
5308
- fill :white
5376
+ circle_data[:circle] = circle(*circle_data[:args])
5377
+
5378
+ fill circle_data[:fill]
5379
+ stroke circle_data[:stroke]
5309
5380
  }
5310
-
5311
- @circles_data.each do |circle_data|
5312
- path {
5313
- circle_data[:circle] = circle(*circle_data[:args])
5314
-
5315
- fill circle_data[:fill]
5316
- stroke circle_data[:stroke]
5317
- }
5318
- end
5319
- end
5320
-
5321
- on_mouse_down do |area_mouse_event|
5322
- clicked_circle_data = @circles_data.find do |circle_data|
5323
- circle_data[:fill].nil? && circle_data[:circle].include?(area_mouse_event[:x], area_mouse_event[:y])
5324
- end
5325
- if clicked_circle_data
5326
- clicked_circle_data[:fill] = clicked_circle_data[:stroke]
5327
- @area.queue_redraw_all
5328
- self.score += 1 # notifies score observers automatically of change
5329
- end
5330
5381
  end
5331
- }
5382
+ end
5383
+
5384
+ on_mouse_down do |area_mouse_event|
5385
+ color_circle(area_mouse_event[:x], area_mouse_event[:y])
5386
+ end
5332
5387
  }
5333
-
5334
5388
  }
5335
5389
  }.show
5336
5390
  end
@@ -5962,38 +6016,50 @@ window('Method-Based Custom Keyword') {
5962
6016
  }.show
5963
6017
  ```
5964
6018
 
5965
- ## Contributing to glimmer-dsl-libui
6019
+ ## Applications
5966
6020
 
5967
- - Check out the latest master to make sure the feature hasn't been
5968
- implemented or the bug hasn't been fixed yet.
5969
- - Check out the issue tracker to make sure someone already hasn't
5970
- requested it and/or contributed it.
5971
- - Fork the project.
5972
- - Start a feature/bugfix branch.
5973
- - Commit and push until you are happy with your contribution.
5974
- - Make sure to add tests for it. This is important so I don't break it
5975
- in a future version unintentionally.
5976
- - Please try not to mess with the Rakefile, version, or history. If
5977
- you want to have your own version, or is otherwise necessary, that
5978
- is fine, but please isolate to its own commit so I can cherry-pick
5979
- around it.
6021
+ Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
5980
6022
 
5981
- ## Help
6023
+ ### Manga2PDF
5982
6024
 
5983
- ### Issues
6025
+ Download and merge manga images into a single pdf file.
5984
6026
 
5985
- You may submit [issues](https://github.com/AndyObtiva/glimmer/issues) on [GitHub](https://github.com/AndyObtiva/glimmer/issues).
6027
+ https://github.com/PinGunter/manga2pdf
5986
6028
 
5987
- [Click here to submit an issue.](https://github.com/AndyObtiva/glimmer/issues)
6029
+ ![manga2pdf screenshot](https://raw.githubusercontent.com/PinGunter/manga2pdf/master/screenshots/manga2pdf-gui.png)
5988
6030
 
5989
- ### Chat
6031
+ ### Befunge98 GUI
5990
6032
 
5991
- If you need live help, try to [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6033
+ Ruby implementation of the Befunge-98 programmming language.
6034
+
6035
+ https://github.com/AndyObtiva/befunge98/tree/gui
6036
+
6037
+ ![befunge98 gui screenshot](https://raw.githubusercontent.com/AndyObtiva/befunge98/master/gui/glimmer-dsl-libui/befunge98_gui_glimmer_dsl_libui/screenshots/befunge98_gui_glimmer_dsl_libui_example.png)
6038
+
6039
+ ### i3off Gtk Ruby
6040
+
6041
+ https://github.com/iraamaro/i3off-gtk-ruby
5992
6042
 
5993
6043
  ## Process
5994
6044
 
5995
6045
  [Glimmer Process](https://github.com/AndyObtiva/glimmer/blob/master/PROCESS.md)
5996
6046
 
6047
+ ## Resources
6048
+
6049
+ - [libui C Library](https://github.com/andlabs/libui)
6050
+ - [LibUI Ruby Bindings](https://github.com/kojix2/LibUI)
6051
+ - [Code Master Blog](https://andymaleh.blogspot.com/search/label/LibUI)
6052
+
6053
+ ## Help
6054
+
6055
+ ### Issues
6056
+
6057
+ If you encounter [issues](https://github.com/AndyObtiva/glimmer-dsl-libui/issues) that are not reported, discover missing features that are not mentioned in [TODO.md](TODO.md), or think up better ways to use [libui](https://github.com/andlabs/libui) than what is possible with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), you may submit an [issue](https://github.com/AndyObtiva/glimmer-dsl-libui/issues/new) or [pull request](https://github.com/AndyObtiva/glimmer-dsl-libui/compare) on [GitHub](https://github.com).
6058
+
6059
+ ### Chat
6060
+
6061
+ If you need live help, try to [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6062
+
5997
6063
  ## Planned Features and Feature Suggestions
5998
6064
 
5999
6065
  These features have been planned or suggested. You might see them in a future version of [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui). You are welcome to contribute more feature suggestions.
@@ -6004,6 +6070,22 @@ These features have been planned or suggested. You might see them in a future ve
6004
6070
 
6005
6071
  [CHANGELOG.md](CHANGELOG.md)
6006
6072
 
6073
+ ## Contributing
6074
+
6075
+ - Check out the latest master to make sure the feature hasn't been
6076
+ implemented or the bug hasn't been fixed yet.
6077
+ - Check out the issue tracker to make sure someone already hasn't
6078
+ requested it and/or contributed it.
6079
+ - Fork the project.
6080
+ - Start a feature/bugfix branch.
6081
+ - Commit and push until you are happy with your contribution.
6082
+ - Make sure to add tests for it. This is important so I don't break it
6083
+ in a future version unintentionally.
6084
+ - Please try not to mess with the Rakefile, version, or history. If
6085
+ you want to have your own version, or is otherwise necessary, that
6086
+ is fine, but please isolate to its own commit so I can cherry-pick
6087
+ around it.
6088
+
6007
6089
  ## Contributors
6008
6090
 
6009
6091
  * [Andy Maleh](https://github.com/AndyObtiva) (Founder)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.11
1
+ 0.2.15
data/bin/girb CHANGED
File without changes
data/bin/girb_runner.rb CHANGED
@@ -27,7 +27,7 @@ require_relative '../lib/glimmer-dsl-libui'
27
27
 
28
28
  include Glimmer
29
29
 
30
- GIRB_RUNNER_EXIT_FILE = "#{Etc.getpwuid.dir}/.girb_runner_exit"
30
+ GIRB_RUNNER_EXIT_FILE = "#{Dir.home}/.girb_runner_exit"
31
31
  FileUtils.rm_rf GIRB_RUNNER_EXIT_FILE
32
32
 
33
33
  @exit_method = method(:exit)
@@ -55,11 +55,9 @@ window('Area Gallery', 400, 400) {
55
55
  stroke r: 0, g: 0, b: 0, thickness: 2
56
56
  }
57
57
  text(160, 40, 100) { # x, y, width
58
- string {
58
+ string('Area Gallery') {
59
59
  font family: 'Times', size: 14
60
60
  color :black
61
-
62
- 'Area Gallery'
63
61
  }
64
62
  }
65
63