glimmer-dsl-libui 0.2.13 → 0.2.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +205 -167
- data/VERSION +1 -1
- data/examples/area_gallery.rb +13 -15
- data/examples/area_gallery2.rb +22 -24
- data/examples/area_gallery3.rb +13 -15
- data/examples/area_gallery4.rb +22 -24
- data/examples/{color_the_shapes.rb → color_the_circles.rb} +37 -38
- data/examples/meta_example.rb +12 -8
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/control_expression.rb +2 -0
- data/lib/glimmer/libui/control_proxy/area_proxy.rb +37 -4
- data/lib/glimmer/libui/control_proxy.rb +17 -2
- data/lib/glimmer/libui/shape/arc.rb +5 -1
- data/lib/glimmer/libui/shape/circle.rb +5 -1
- metadata +6 -6
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
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.
|
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.14
|
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
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)
|
@@ -9,13 +9,11 @@
|
|
9
9
|
|
10
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.
|
11
11
|
|
12
|
-
**(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. Issue reporting for Windows is appreciated in the meantime.)**
|
13
|
-
|
14
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:
|
15
13
|
- Declarative DSL syntax that visually maps to the GUI control hierarchy
|
16
14
|
- Convention over configuration via smart defaults and automation of low-level details
|
17
15
|
- Requiring the least amount of syntax possible to build GUI
|
18
|
-
- Custom
|
16
|
+
- Custom Keyword support
|
19
17
|
- [Far Future Plan] Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
|
20
18
|
- [Far Future Plan] Scaffolding for new custom controls, apps, and gems
|
21
19
|
- [Far Future Plan] Native-Executable packaging on Mac, Windows, and Linux.
|
@@ -119,21 +117,19 @@ window('Area Gallery', 400, 400) {
|
|
119
117
|
fill r: 202, g: 102, b: 204, a: 0.5
|
120
118
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
121
119
|
}
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
}
|
136
|
-
end
|
120
|
+
path { # declarative stable path
|
121
|
+
arc(400, 220, 180, 90, 90, false)
|
122
|
+
|
123
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
124
|
+
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
125
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
126
|
+
}
|
127
|
+
path { # declarative stable path
|
128
|
+
circle(200, 200, 90)
|
129
|
+
|
130
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
131
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
132
|
+
}
|
137
133
|
text(160, 40, 100) { # x, y, width
|
138
134
|
string('Area Gallery') {
|
139
135
|
font family: 'Times', size: 14
|
@@ -213,7 +209,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
213
209
|
- [Usage](#usage)
|
214
210
|
- [Girb (Glimmer IRB)](#girb-glimmer-irb)
|
215
211
|
- [API](#api)
|
216
|
-
- [Supported
|
212
|
+
- [Supported Keywords](#supported-keywords)
|
217
213
|
- [Common Control Properties](#common-control-properties)
|
218
214
|
- [Common Control Operations](#common-control-operations)
|
219
215
|
- [LibUI Operations](#libui-operations)
|
@@ -257,10 +253,13 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
257
253
|
- [Basic Transform](#basic-transform)
|
258
254
|
- [Login](#login)
|
259
255
|
- [Timer](#timer)
|
260
|
-
- [Color The
|
256
|
+
- [Color The Circles](#color-the-circles)
|
261
257
|
- [Basic Draw Text](#basic-draw-text)
|
262
258
|
- [Custom Draw Text](#custom-draw-text)
|
263
259
|
- [Method-Based Custom Keyword](#method-based-custom-keyword)
|
260
|
+
- [Applications](#applications)
|
261
|
+
- [Manga2PDF](#manga2pdf)
|
262
|
+
- [Befunge98 GUI](#befunge98-gui)
|
264
263
|
- [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
|
265
264
|
- [Help](#help)
|
266
265
|
- [Issues](#issues)
|
@@ -281,10 +280,10 @@ The Glimmer GUI DSL provides object-oriented declarative hierarchical syntax for
|
|
281
280
|
- Requires the minimum amount of syntax needed to describe an app's GUI
|
282
281
|
|
283
282
|
The Glimmer GUI DSL follows these simple concepts in mapping from [LibUI](https://github.com/kojix2/LibUI) syntax:
|
284
|
-
- **
|
285
|
-
- **Content
|
286
|
-
- **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.
|
287
|
-
- **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.
|
283
|
+
- **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)`).
|
284
|
+
- **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}}`)
|
285
|
+
- **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.
|
286
|
+
- **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.
|
288
287
|
|
289
288
|
Example of an app written in [LibUI](https://github.com/kojix2/LibUI)'s procedural imperative syntax:
|
290
289
|
|
@@ -348,7 +347,7 @@ gem install glimmer-dsl-libui
|
|
348
347
|
Or install via Bundler `Gemfile`:
|
349
348
|
|
350
349
|
```ruby
|
351
|
-
gem 'glimmer-dsl-libui', '~> 0.2.
|
350
|
+
gem 'glimmer-dsl-libui', '~> 0.2.14'
|
352
351
|
```
|
353
352
|
|
354
353
|
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.
|
@@ -408,7 +407,7 @@ w.set_title 'aloha'
|
|
408
407
|
puts w.title # => aloha
|
409
408
|
```
|
410
409
|
|
411
|
-
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.
|
410
|
+
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.
|
412
411
|
|
413
412
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
414
413
|
|
@@ -417,9 +416,11 @@ w = window('hello world') # => #<Glimmer::LibUI::WindowProxy:0x00007fde4ea39fb0
|
|
417
416
|
w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0 free=0x0000000000000000>
|
418
417
|
```
|
419
418
|
|
420
|
-
### Supported
|
419
|
+
### Supported Keywords
|
420
|
+
|
421
|
+
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)
|
421
422
|
|
422
|
-
|
423
|
+
Keyword(Args) | Properties | Listeners
|
423
424
|
------------- | ---------- | ---------
|
424
425
|
`about_menu_item` | None | `on_clicked`
|
425
426
|
`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)`
|
@@ -455,6 +456,8 @@ Control(Args) | Properties | Listeners
|
|
455
456
|
`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
|
456
457
|
`menu(text as String)` | None | None
|
457
458
|
`menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
|
459
|
+
`message_box` (alias for `msg_box`; see for arguments) | None | None
|
460
|
+
`message_box_error` (alias for `msg_box_error`; see for arguments) | None | None
|
458
461
|
`multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
459
462
|
`msg_box(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
460
463
|
`msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
@@ -516,8 +519,8 @@ All operations that could normally be called on `LibUI` can also be called on `G
|
|
516
519
|
|
517
520
|
### Extra Dialogs
|
518
521
|
|
519
|
-
- `open_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
|
520
|
-
- `save_file(window as Glimmer::LibUI::WindowProxy)`: returns selected file (`String`) or `nil` if cancelled
|
522
|
+
- `open_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
|
523
|
+
- `save_file(window as Glimmer::LibUI::WindowProxy = ControlProxy::main_window_proxy)`: returns selected file (`String`) or `nil` if cancelled
|
521
524
|
|
522
525
|
### Extra Operations
|
523
526
|
|
@@ -530,13 +533,13 @@ All operations that could normally be called on `LibUI` can also be called on `G
|
|
530
533
|
|
531
534
|
### Table API
|
532
535
|
|
533
|
-
The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported
|
536
|
+
The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Keywords](#supported-keywords)):
|
534
537
|
- `background_color_column`: expects color cell values
|
535
538
|
- `button_column`: expects `String` cell values
|
536
539
|
- `checkbox_column`: expects Boolean cell values
|
537
540
|
- `checkbox_text_column`: expects dual-element `Array` of Boolean and `String` cell values
|
538
541
|
- `checkbox_text_color_column`: expects triple-element `Array` of Boolean, `String`, and color cell values
|
539
|
-
- `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported
|
542
|
+
- `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported Keywords](#supported-keywords))
|
540
543
|
- `image_text_column`: expects dual-element `Array` of `image` and `String` cell values
|
541
544
|
- `image_text_color_column`: expects triple-element `Array` of `image`, `String`, and color cell values
|
542
545
|
- `text_column`: expects `String` cell values
|
@@ -598,6 +601,7 @@ window('Contacts', 600, 600) { |w|
|
|
598
601
|
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
599
602
|
else
|
600
603
|
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
604
|
+
@unfiltered_data = data.dup
|
601
605
|
@name_entry.text = ''
|
602
606
|
@email_entry.text = ''
|
603
607
|
@phone_entry.text = ''
|
@@ -607,6 +611,25 @@ window('Contacts', 600, 600) { |w|
|
|
607
611
|
end
|
608
612
|
}
|
609
613
|
|
614
|
+
search_entry { |se|
|
615
|
+
stretchy false
|
616
|
+
|
617
|
+
on_changed do
|
618
|
+
filter_value = se.text
|
619
|
+
@unfiltered_data ||= data.dup
|
620
|
+
# Unfilter first to remove any previous filters
|
621
|
+
data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
|
622
|
+
# Now, apply filter if entered
|
623
|
+
unless filter_value.empty?
|
624
|
+
data.filter! do |row_data| # affects table indirectly through implicit data-binding
|
625
|
+
row_data.any? do |cell|
|
626
|
+
cell.to_s.downcase.include?(filter_value.downcase)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
}
|
632
|
+
|
610
633
|
table {
|
611
634
|
text_column('Name')
|
612
635
|
text_column('Email')
|
@@ -615,6 +638,10 @@ window('Contacts', 600, 600) { |w|
|
|
615
638
|
text_column('State')
|
616
639
|
|
617
640
|
cell_rows data # implicit data-binding
|
641
|
+
|
642
|
+
on_changed do |row, type, row_data|
|
643
|
+
puts "Row #{row} #{type}: #{row_data}"
|
644
|
+
end
|
618
645
|
}
|
619
646
|
}
|
620
647
|
}.show
|
@@ -627,8 +654,8 @@ Learn more by checking out [examples](#examples).
|
|
627
654
|
### Area API
|
628
655
|
|
629
656
|
The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
|
630
|
-
- 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).
|
631
|
-
- 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.
|
657
|
+
- 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).
|
658
|
+
- 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.
|
632
659
|
|
633
660
|
Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
634
661
|
|
@@ -892,6 +919,7 @@ window('area text drawing') {
|
|
892
919
|
- 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.
|
893
920
|
- `image` instances are automatically freed from memory after `window` is destroyed.
|
894
921
|
- `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`
|
922
|
+
- Automatically provide shifted `:key` characters in `area_key_event` provided in `area` key listeners `on_key_event`, `on_key_down`, and `on_key_up`
|
895
923
|
- `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
|
896
924
|
- Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
|
897
925
|
- Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
|
@@ -1013,12 +1041,13 @@ window('Method-Based Custom Keyword') {
|
|
1013
1041
|
### API Gotchas
|
1014
1042
|
|
1015
1043
|
- 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`).
|
1016
|
-
- `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on
|
1044
|
+
- `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).
|
1017
1045
|
- `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)
|
1018
|
-
- `text` `string` `background` does not work on Windows due to an issue in
|
1019
|
-
- `arc` shape does not work on Windows due to
|
1046
|
+
- `text` `string` `background` does not work on Windows due to an [issue in libui](https://github.com/andlabs/libui/issues/347).
|
1047
|
+
- `arc` shape does not work on Windows unless a figure is started due to implementation of [libui](https://github.com/andlabs/libui).
|
1020
1048
|
- `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.
|
1021
1049
|
- `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.
|
1050
|
+
- 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.
|
1022
1051
|
|
1023
1052
|
### Original API
|
1024
1053
|
|
@@ -1033,7 +1062,7 @@ I am documenting options for packaging, which I have not tried myself, but figur
|
|
1033
1062
|
|
1034
1063
|
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.
|
1035
1064
|
|
1036
|
-
For Mac, consider [
|
1065
|
+
For Mac, consider [Platypus](https://github.com/sveinbjornt/Platypus) (builds a native Mac app from a Ruby script)
|
1037
1066
|
|
1038
1067
|
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/).
|
1039
1068
|
|
@@ -3384,8 +3413,6 @@ Linux
|
|
3384
3413
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3385
3414
|
|
3386
3415
|
```ruby
|
3387
|
-
# frozen_string_literal: true
|
3388
|
-
|
3389
3416
|
require 'glimmer-dsl-libui'
|
3390
3417
|
|
3391
3418
|
include Glimmer
|
@@ -3901,21 +3928,19 @@ window('Area Gallery', 400, 400) {
|
|
3901
3928
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3902
3929
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3903
3930
|
}
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
3909
|
-
|
3910
|
-
|
3911
|
-
|
3912
|
-
|
3913
|
-
|
3914
|
-
|
3915
|
-
|
3916
|
-
|
3917
|
-
}
|
3918
|
-
end
|
3931
|
+
path { # declarative stable path
|
3932
|
+
arc(400, 220, 180, 90, 90, false)
|
3933
|
+
|
3934
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
3935
|
+
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
3936
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3937
|
+
}
|
3938
|
+
path { # declarative stable path
|
3939
|
+
circle(200, 200, 90)
|
3940
|
+
|
3941
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
3942
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
3943
|
+
}
|
3919
3944
|
text(160, 40, 100) { # x, y, width
|
3920
3945
|
string('Area Gallery') {
|
3921
3946
|
font family: 'Times', size: 14
|
@@ -4074,32 +4099,30 @@ window('Area Gallery', 400, 400) {
|
|
4074
4099
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4075
4100
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4076
4101
|
}
|
4077
|
-
|
4078
|
-
|
4079
|
-
|
4080
|
-
|
4081
|
-
|
4082
|
-
|
4083
|
-
|
4084
|
-
|
4085
|
-
is_negative false
|
4086
|
-
}
|
4087
|
-
|
4088
|
-
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4089
|
-
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
4090
|
-
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4102
|
+
path { # declarative stable path
|
4103
|
+
arc {
|
4104
|
+
x_center 400
|
4105
|
+
y_center 220
|
4106
|
+
radius 180
|
4107
|
+
start_angle 90
|
4108
|
+
sweep 90
|
4109
|
+
is_negative false
|
4091
4110
|
}
|
4092
|
-
|
4093
|
-
|
4094
|
-
|
4095
|
-
|
4096
|
-
|
4097
|
-
|
4098
|
-
|
4099
|
-
|
4100
|
-
|
4111
|
+
|
4112
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4113
|
+
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
4114
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4115
|
+
}
|
4116
|
+
path { # declarative stable path
|
4117
|
+
circle {
|
4118
|
+
x_center 200
|
4119
|
+
y_center 200
|
4120
|
+
radius 90
|
4101
4121
|
}
|
4102
|
-
|
4122
|
+
|
4123
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
4124
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4125
|
+
}
|
4103
4126
|
text {
|
4104
4127
|
x 160
|
4105
4128
|
y 40
|
@@ -4211,21 +4234,19 @@ window('Area Gallery', 400, 400) {
|
|
4211
4234
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4212
4235
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4213
4236
|
}
|
4214
|
-
|
4215
|
-
|
4216
|
-
|
4217
|
-
|
4218
|
-
|
4219
|
-
|
4220
|
-
|
4221
|
-
|
4222
|
-
|
4223
|
-
|
4224
|
-
|
4225
|
-
|
4226
|
-
|
4227
|
-
}
|
4228
|
-
end
|
4237
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4238
|
+
arc(400, 220, 180, 90, 90, false)
|
4239
|
+
|
4240
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4241
|
+
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
4242
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4243
|
+
}
|
4244
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4245
|
+
circle(200, 200, 90)
|
4246
|
+
|
4247
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
4248
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4249
|
+
}
|
4229
4250
|
text(160, 40, 100) { # x, y, width
|
4230
4251
|
string('Area Gallery') {
|
4231
4252
|
font family: 'Times', size: 14
|
@@ -4386,32 +4407,30 @@ window('Area Gallery', 400, 400) {
|
|
4386
4407
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4387
4408
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4388
4409
|
}
|
4389
|
-
|
4390
|
-
|
4391
|
-
|
4392
|
-
|
4393
|
-
|
4394
|
-
|
4395
|
-
|
4396
|
-
|
4397
|
-
is_negative false
|
4398
|
-
}
|
4399
|
-
|
4400
|
-
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4401
|
-
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
4402
|
-
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4410
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4411
|
+
arc {
|
4412
|
+
x_center 400
|
4413
|
+
y_center 220
|
4414
|
+
radius 180
|
4415
|
+
start_angle 90
|
4416
|
+
sweep 90
|
4417
|
+
is_negative false
|
4403
4418
|
}
|
4404
|
-
|
4405
|
-
|
4406
|
-
|
4407
|
-
|
4408
|
-
|
4409
|
-
|
4410
|
-
|
4411
|
-
|
4412
|
-
|
4419
|
+
|
4420
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4421
|
+
fill outer_radius: 90, x0: 0, y0: 0, x1: 500, y1: 500, stops: [{pos: 0.25, r: 102, g: 102, b: 204, a: 0.5}, {pos: 0.75, r: 204, g: 102, b: 204}]
|
4422
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4423
|
+
}
|
4424
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4425
|
+
circle {
|
4426
|
+
x_center 200
|
4427
|
+
y_center 200
|
4428
|
+
radius 90
|
4413
4429
|
}
|
4414
|
-
|
4430
|
+
|
4431
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
4432
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4433
|
+
}
|
4415
4434
|
text {
|
4416
4435
|
x 160
|
4417
4436
|
y 40
|
@@ -5114,63 +5133,62 @@ end
|
|
5114
5133
|
Timer.new
|
5115
5134
|
```
|
5116
5135
|
|
5117
|
-
### Color The
|
5136
|
+
### Color The Circles
|
5118
5137
|
|
5119
|
-
[examples/
|
5138
|
+
[examples/color_the_circles.rb](examples/color_the_circles.rb)
|
5120
5139
|
|
5121
5140
|
Run with this command from the root of the project if you cloned the project:
|
5122
5141
|
|
5123
5142
|
```
|
5124
|
-
ruby -r './lib/glimmer-dsl-libui' examples/
|
5143
|
+
ruby -r './lib/glimmer-dsl-libui' examples/color_the_circles.rb
|
5125
5144
|
```
|
5126
5145
|
|
5127
5146
|
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
5128
5147
|
|
5129
5148
|
```
|
5130
|
-
ruby -r glimmer-dsl-libui -e "require 'examples/
|
5149
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/color_the_circles'"
|
5131
5150
|
```
|
5132
5151
|
|
5133
5152
|
Mac
|
5134
5153
|
|
5135
|
-
![glimmer-dsl-libui-mac-color-the-
|
5136
|
-
![glimmer-dsl-libui-mac-color-the-
|
5137
|
-
![glimmer-dsl-libui-mac-color-the-
|
5154
|
+
![glimmer-dsl-libui-mac-color-the-circles.png](images/glimmer-dsl-libui-mac-color-the-circles.png)
|
5155
|
+
![glimmer-dsl-libui-mac-color-the-circles-lost.png](images/glimmer-dsl-libui-mac-color-the-circles-lost.png)
|
5156
|
+
![glimmer-dsl-libui-mac-color-the-circles-won.png](images/glimmer-dsl-libui-mac-color-the-circles-won.png)
|
5138
5157
|
|
5139
5158
|
Linux
|
5140
5159
|
|
5141
|
-
![glimmer-dsl-libui-linux-color-the-
|
5142
|
-
![glimmer-dsl-libui-linux-color-the-
|
5143
|
-
![glimmer-dsl-libui-linux-color-the-
|
5160
|
+
![glimmer-dsl-libui-linux-color-the-circles.png](images/glimmer-dsl-libui-linux-color-the-circles.png)
|
5161
|
+
![glimmer-dsl-libui-linux-color-the-circles-lost.png](images/glimmer-dsl-libui-linux-color-the-circles-lost.png)
|
5162
|
+
![glimmer-dsl-libui-linux-color-the-circles-won.png](images/glimmer-dsl-libui-linux-color-the-circles-won.png)
|
5144
5163
|
|
5145
5164
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5146
5165
|
|
5147
5166
|
```ruby
|
5148
5167
|
require 'glimmer-dsl-libui'
|
5149
5168
|
|
5150
|
-
class
|
5169
|
+
class ColorTheCircles
|
5151
5170
|
include Glimmer
|
5152
5171
|
|
5153
5172
|
WINDOW_WIDTH = 800
|
5154
5173
|
WINDOW_HEIGHT = 600
|
5155
5174
|
SHAPE_MIN_SIZE = 15
|
5156
|
-
SHAPE_MAX_SIZE =
|
5175
|
+
SHAPE_MAX_SIZE = 75
|
5157
5176
|
MARGIN_WIDTH = 55
|
5158
5177
|
MARGIN_HEIGHT = 155
|
5159
5178
|
TIME_MAX_EASY = 4
|
5160
5179
|
TIME_MAX_MEDIUM = 3
|
5161
5180
|
TIME_MAX_HARD = 2
|
5162
5181
|
TIME_MAX_INSANE = 1
|
5163
|
-
SHAPES = ['square'] + (OS.windows? ? [] : ['circle'])
|
5164
5182
|
|
5165
5183
|
attr_accessor :score
|
5166
5184
|
|
5167
5185
|
def initialize
|
5168
|
-
@
|
5186
|
+
@circles_data = []
|
5169
5187
|
@score = 0
|
5170
5188
|
@time_max = TIME_MAX_HARD
|
5171
5189
|
@game_over = false
|
5172
5190
|
register_observers
|
5173
|
-
|
5191
|
+
setup_circle_factory
|
5174
5192
|
end
|
5175
5193
|
|
5176
5194
|
def register_observers
|
@@ -5189,14 +5207,14 @@ class ColorTheShapes
|
|
5189
5207
|
observer.observe(self, :score) # automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer on score attribute changes
|
5190
5208
|
end
|
5191
5209
|
|
5192
|
-
def
|
5210
|
+
def setup_circle_factory
|
5193
5211
|
consumer = Proc.new do
|
5194
5212
|
unless @game_over
|
5195
|
-
if @
|
5196
|
-
# start with 3
|
5197
|
-
|
5213
|
+
if @circles_data.empty?
|
5214
|
+
# start with 3 circles to make more challenging
|
5215
|
+
add_circle until @circles_data.size > 3
|
5198
5216
|
else
|
5199
|
-
|
5217
|
+
add_circle
|
5200
5218
|
end
|
5201
5219
|
end
|
5202
5220
|
delay = rand * @time_max
|
@@ -5205,13 +5223,13 @@ class ColorTheShapes
|
|
5205
5223
|
Glimmer::LibUI.queue_main(&consumer)
|
5206
5224
|
end
|
5207
5225
|
|
5208
|
-
def
|
5209
|
-
|
5210
|
-
|
5211
|
-
|
5226
|
+
def add_circle
|
5227
|
+
circle_x = rand * (WINDOW_WIDTH - MARGIN_WIDTH - SHAPE_MAX_SIZE) + SHAPE_MAX_SIZE
|
5228
|
+
circle_y = rand * (WINDOW_HEIGHT - MARGIN_HEIGHT - SHAPE_MAX_SIZE) + SHAPE_MAX_SIZE
|
5229
|
+
circle_size = rand * (SHAPE_MAX_SIZE - SHAPE_MIN_SIZE) + SHAPE_MIN_SIZE
|
5212
5230
|
stroke_color = Glimmer::LibUI.x11_colors.sample
|
5213
|
-
@
|
5214
|
-
args: [
|
5231
|
+
@circles_data << {
|
5232
|
+
args: [circle_x, circle_y, circle_size],
|
5215
5233
|
fill: nil,
|
5216
5234
|
stroke: stroke_color
|
5217
5235
|
}
|
@@ -5221,27 +5239,27 @@ class ColorTheShapes
|
|
5221
5239
|
|
5222
5240
|
def restart_game
|
5223
5241
|
@score = 0 # update variable directly to avoid notifying observers
|
5224
|
-
@
|
5242
|
+
@circles_data.clear
|
5225
5243
|
@game_over = false
|
5226
5244
|
end
|
5227
5245
|
|
5228
|
-
def
|
5229
|
-
|
5230
|
-
|
5246
|
+
def color_circle(x, y)
|
5247
|
+
clicked_circle_data = @circles_data.find do |circle_data|
|
5248
|
+
circle_data[:fill].nil? && circle_data[:circle]&.include?(x, y)
|
5231
5249
|
end
|
5232
|
-
if
|
5233
|
-
|
5234
|
-
|
5250
|
+
if clicked_circle_data
|
5251
|
+
clicked_circle_data[:fill] = clicked_circle_data[:stroke]
|
5252
|
+
push_colored_circle_behind_uncolored_circles(clicked_circle_data)
|
5235
5253
|
@area.queue_redraw_all
|
5236
5254
|
self.score += 1 # notifies score observers automatically of change
|
5237
5255
|
end
|
5238
5256
|
end
|
5239
5257
|
|
5240
|
-
def
|
5241
|
-
|
5242
|
-
|
5243
|
-
|
5244
|
-
@
|
5258
|
+
def push_colored_circle_behind_uncolored_circles(colored_circle_data)
|
5259
|
+
removed_colored_circle_data = @circles_data.delete(colored_circle_data)
|
5260
|
+
last_colored_circle_data = @circles_data.select {|cd| cd[:fill]}.last
|
5261
|
+
last_colored_circle_data_index = @circles_data.index(last_colored_circle_data) || -1
|
5262
|
+
@circles_data.insert(last_colored_circle_data_index + 1, removed_colored_circle_data)
|
5245
5263
|
end
|
5246
5264
|
|
5247
5265
|
def launch
|
@@ -5286,12 +5304,12 @@ class ColorTheShapes
|
|
5286
5304
|
menu('Help') {
|
5287
5305
|
menu_item('Instructions') {
|
5288
5306
|
on_clicked do
|
5289
|
-
msg_box('Instructions', "Score goes down as
|
5307
|
+
msg_box('Instructions', "Score goes down as circles are added.\nIf it reaches -20, you lose!\n\nClick circles to color and score!\nOnce score reaches 0, you win!\n\nBeware of concealed light-colored circles!\nThey are revealed once darker circles intersect them.\n\nThere are four levels of difficulty.\nChange via difficulty menu if the game gets too tough.")
|
5290
5308
|
end
|
5291
5309
|
}
|
5292
5310
|
}
|
5293
5311
|
|
5294
|
-
window('Color The
|
5312
|
+
window('Color The Circles', WINDOW_WIDTH, WINDOW_HEIGHT) {
|
5295
5313
|
margined true
|
5296
5314
|
|
5297
5315
|
grid {
|
@@ -5305,13 +5323,13 @@ class ColorTheShapes
|
|
5305
5323
|
end
|
5306
5324
|
}
|
5307
5325
|
|
5308
|
-
label('Score goes down as
|
5326
|
+
label('Score goes down as circles are added. If it reaches -20, you lose!') {
|
5309
5327
|
left 0
|
5310
5328
|
top 1
|
5311
5329
|
halign :center
|
5312
5330
|
}
|
5313
5331
|
|
5314
|
-
label('Click
|
5332
|
+
label('Click circles to color and score! Once score reaches 0, you win!') {
|
5315
5333
|
left 0
|
5316
5334
|
top 2
|
5317
5335
|
halign :center
|
@@ -5346,18 +5364,18 @@ class ColorTheShapes
|
|
5346
5364
|
fill :white
|
5347
5365
|
}
|
5348
5366
|
|
5349
|
-
@
|
5367
|
+
@circles_data.each do |circle_data|
|
5350
5368
|
path {
|
5351
|
-
|
5369
|
+
circle_data[:circle] = circle(*circle_data[:args])
|
5352
5370
|
|
5353
|
-
fill
|
5354
|
-
stroke
|
5371
|
+
fill circle_data[:fill]
|
5372
|
+
stroke circle_data[:stroke]
|
5355
5373
|
}
|
5356
5374
|
end
|
5357
5375
|
end
|
5358
5376
|
|
5359
5377
|
on_mouse_down do |area_mouse_event|
|
5360
|
-
|
5378
|
+
color_circle(area_mouse_event[:x], area_mouse_event[:y])
|
5361
5379
|
end
|
5362
5380
|
}
|
5363
5381
|
}
|
@@ -5365,7 +5383,7 @@ class ColorTheShapes
|
|
5365
5383
|
end
|
5366
5384
|
end
|
5367
5385
|
|
5368
|
-
|
5386
|
+
ColorTheCircles.new.launch
|
5369
5387
|
```
|
5370
5388
|
|
5371
5389
|
### Basic Draw Text
|
@@ -5991,6 +6009,26 @@ window('Method-Based Custom Keyword') {
|
|
5991
6009
|
}.show
|
5992
6010
|
```
|
5993
6011
|
|
6012
|
+
## Applications
|
6013
|
+
|
6014
|
+
Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
6015
|
+
|
6016
|
+
### Manga2PDF
|
6017
|
+
|
6018
|
+
Download and merge manga images into a single pdf file.
|
6019
|
+
|
6020
|
+
https://github.com/PinGunter/manga2pdf
|
6021
|
+
|
6022
|
+
![manga2pdf screenshot](https://raw.githubusercontent.com/PinGunter/manga2pdf/master/screenshots/manga2pdf-gui.png)
|
6023
|
+
|
6024
|
+
### Befunge98 GUI
|
6025
|
+
|
6026
|
+
Ruby implementation of the Befunge-98 programmming language.
|
6027
|
+
|
6028
|
+
https://github.com/AndyObtiva/befunge98/tree/gui
|
6029
|
+
|
6030
|
+
![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)
|
6031
|
+
|
5994
6032
|
## Contributing to glimmer-dsl-libui
|
5995
6033
|
|
5996
6034
|
- Check out the latest master to make sure the feature hasn't been
|