glimmer-dsl-libui 0.2.11 → 0.2.15

Sign up to get free protection for your applications and to get access to all the features.
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