glimmer-dsl-libui 0.2.6 → 0.2.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +530 -92
- data/VERSION +1 -1
- data/examples/area_gallery.rb +18 -8
- data/examples/area_gallery2.rb +26 -12
- data/examples/area_gallery3.rb +16 -6
- data/examples/area_gallery4.rb +26 -12
- data/examples/basic_table_button.rb +4 -0
- data/examples/basic_table_color.rb +39 -0
- data/examples/basic_table_progress_bar.rb +1 -1
- data/examples/color_button.rb +2 -0
- data/examples/custom_draw_text.rb +1 -1
- data/examples/custom_draw_text2.rb +1 -1
- data/examples/editable_table.rb +8 -0
- data/examples/form.rb +12 -2
- data/examples/form_table.rb +4 -0
- data/examples/meta_example.rb +27 -17
- data/examples/method_based_custom_keyword.rb +87 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/icons/glimmer.png +0 -0
- data/lib/glimmer/libui/control_proxy/column/background_color_column_proxy.rb +38 -0
- data/lib/glimmer/libui/control_proxy/column/checkbox_text_color_column_proxy.rb +82 -0
- data/lib/glimmer/libui/control_proxy/column/image_text_color_column_proxy.rb +50 -0
- data/lib/glimmer/libui/control_proxy/column/text_color_column_proxy.rb +50 -0
- data/lib/glimmer/libui/control_proxy/editable_column.rb +1 -0
- data/lib/glimmer/libui/control_proxy/path_proxy.rb +31 -6
- data/lib/glimmer/libui/control_proxy/table_proxy.rb +53 -14
- data/lib/glimmer/libui/control_proxy/text_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy/triple_column.rb +45 -0
- data/lib/glimmer/libui.rb +1 -1
- metadata +12 -4
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.10
|
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
|
[![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
|
@@ -14,10 +14,10 @@ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/gl
|
|
14
14
|
- Declarative DSL syntax that visually maps to the GUI control hierarchy
|
15
15
|
- Convention over configuration via smart defaults and automation of low-level details
|
16
16
|
- Requiring the least amount of syntax possible to build GUI
|
17
|
-
- Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
|
18
17
|
- Custom Control support
|
19
|
-
-
|
20
|
-
-
|
18
|
+
- [Far Future Plan] Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
|
19
|
+
- [Far Future Plan] Scaffolding for new custom controls, apps, and gems
|
20
|
+
- [Far Future Plan] Native-Executable packaging on Mac, Windows, and Linux.
|
21
21
|
|
22
22
|
Hello, World!
|
23
23
|
|
@@ -61,7 +61,7 @@ window('Task Progress', 300, 200) {
|
|
61
61
|
|
62
62
|
on_clicked do
|
63
63
|
data.each_with_index do |row_data, row|
|
64
|
-
data[row] =
|
64
|
+
data[row][1] = 100 # automatically updates table due to implicit data-binding
|
65
65
|
end
|
66
66
|
end
|
67
67
|
}
|
@@ -84,14 +84,15 @@ window('Area Gallery', 400, 400) {
|
|
84
84
|
path { # declarative stable path
|
85
85
|
square(0, 0, 100)
|
86
86
|
square(100, 100, 400)
|
87
|
-
|
87
|
+
|
88
88
|
fill r: 102, g: 102, b: 204
|
89
89
|
}
|
90
90
|
path { # declarative stable path
|
91
91
|
rectangle(0, 100, 100, 400)
|
92
92
|
rectangle(100, 0, 400, 100)
|
93
|
-
|
94
|
-
|
93
|
+
|
94
|
+
# linear gradient (has x0, y0, x1, y1, and stops)
|
95
|
+
fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
|
95
96
|
}
|
96
97
|
path { # declarative stable path
|
97
98
|
figure(100, 100) {
|
@@ -117,17 +118,26 @@ window('Area Gallery', 400, 400) {
|
|
117
118
|
fill r: 202, g: 102, b: 204, a: 0.5
|
118
119
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
119
120
|
}
|
121
|
+
path { # declarative stable path
|
122
|
+
arc(400, 220, 180, 90, 90, false)
|
123
|
+
|
124
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
125
|
+
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}]
|
126
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
127
|
+
}
|
120
128
|
path { # declarative stable path
|
121
129
|
circle(200, 200, 90)
|
122
130
|
|
123
131
|
fill r: 202, g: 102, b: 204, a: 0.5
|
124
132
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
125
133
|
}
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
134
|
+
text(160, 40, 100) { # x, y, width
|
135
|
+
string {
|
136
|
+
font family: 'Times', size: 14
|
137
|
+
color :black
|
138
|
+
|
139
|
+
'Area Gallery'
|
140
|
+
}
|
131
141
|
}
|
132
142
|
|
133
143
|
on_mouse_event do |area_mouse_event|
|
@@ -186,7 +196,7 @@ window('Area Gallery', 400, 400) {
|
|
186
196
|
|
187
197
|
[Check Out Many More Examples Over Here!](#examples)
|
188
198
|
|
189
|
-
NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is in
|
199
|
+
NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is feature-complete and in beta mode (though the C [libui](https://github.com/andlabs/libui) is still mid-alpha). Please help make better by contributing, adopting for small or low risk projects, and providing feedback. The more feedback and issues you report the better.
|
190
200
|
|
191
201
|
Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
|
192
202
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
|
@@ -197,7 +207,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
197
207
|
|
198
208
|
## Table of Contents
|
199
209
|
|
200
|
-
- [Glimmer DSL for LibUI 0.2.
|
210
|
+
- [Glimmer DSL for LibUI 0.2.10](#-glimmer-dsl-for-libui-0210)
|
201
211
|
- [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
|
202
212
|
- [Usage](#usage)
|
203
213
|
- [Girb (Glimmer IRB)](#girb-glimmer-irb)
|
@@ -211,8 +221,10 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
211
221
|
- [Table API](#table-api)
|
212
222
|
- [Area API](#area-api)
|
213
223
|
- [Smart Defaults and Conventions](#smart-defaults-and-conventions)
|
224
|
+
- [Custom Keywords](#custom-keywords)
|
214
225
|
- [API Gotchas](#api-gotchas)
|
215
226
|
- [Original API](#original-api)
|
227
|
+
- [Packaging](#packaging)
|
216
228
|
- [Glimmer Style Guide](#glimmer-style-guide)
|
217
229
|
- [Examples](#examples)
|
218
230
|
- [Basic Window](#basic-window)
|
@@ -235,6 +247,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
235
247
|
- [Basic Table Checkbox](#basic-table-checkbox)
|
236
248
|
- [Basic Table Checkbox Text](#basic-table-checkbox-text)
|
237
249
|
- [Basic Table Progress Bar](#basic-table-progress-bar)
|
250
|
+
- [Basic Table Color](#basic-table-color)
|
238
251
|
- [Form Table](#form-table)
|
239
252
|
- [Basic Area](#basic-area)
|
240
253
|
- [Dynamic Area](#dynamic-area)
|
@@ -246,6 +259,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
246
259
|
- [Color The Circles](#color-the-circles)
|
247
260
|
- [Basic Draw Text](#basic-draw-text)
|
248
261
|
- [Custom Draw Text](#custom-draw-text)
|
262
|
+
- [Method-Based Custom Keyword](#method-based-custom-keyword)
|
249
263
|
- [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
|
250
264
|
- [Help](#help)
|
251
265
|
- [Issues](#issues)
|
@@ -333,7 +347,7 @@ gem install glimmer-dsl-libui
|
|
333
347
|
Or install via Bundler `Gemfile`:
|
334
348
|
|
335
349
|
```ruby
|
336
|
-
gem 'glimmer-dsl-libui', '~> 0.2.
|
350
|
+
gem 'glimmer-dsl-libui', '~> 0.2.10'
|
337
351
|
```
|
338
352
|
|
339
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.
|
@@ -409,12 +423,14 @@ Control(Args) | Properties | Listeners
|
|
409
423
|
`about_menu_item` | None | `on_clicked`
|
410
424
|
`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)`
|
411
425
|
`arc(x_center as Numeric, y_center as Numeric, radius as Numeric, start_angle as Numeric, sweep as Numeric, is_negative as Boolean)` | `x_center` (`Numeric`), `y_center` (`Numeric`), `radius` (`Numeric`), `start_angle` (`Numeric`), `sweep` (`Numeric`), `is_negative` (Boolean) | None
|
426
|
+
`background_color_column(name as String)` | None | None
|
412
427
|
`bezier(c1_x as Numeric, c1_y as Numeric, c2_x as Numeric, c2_y as Numeric, end_x as Numeric, end_y as Numeric)` | `c1_x` (`Numeric`), `c1_y` (`Numeric`), `c2_x` (`Numeric`), `c2_y` (`Numeric`), `end_x` (`Numeric`), `end_y` (`Numeric`) | None
|
413
428
|
`button(text as String)` | `text` (`String`) | `on_clicked`
|
414
429
|
`button_column(name as String)` | `enabled` (Boolean) | None
|
415
430
|
`checkbox(text as String)` | `checked` (Boolean), `text` (`String`) | `on_toggled`
|
416
431
|
`checkbox_column(name as String)` | `editable` (Boolean) | None
|
417
432
|
`checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
433
|
+
`checkbox_text_color_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
418
434
|
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
|
419
435
|
`color_button` | `color` (Array of `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float`), `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float` | `on_changed`
|
420
436
|
`date_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
|
@@ -432,6 +448,7 @@ Control(Args) | Properties | Listeners
|
|
432
448
|
`image_part(pixels as String [encoded image rgba byte array], width as Numeric, height as Numeric, byte_stride as Numeric [usually width*4])` | None | None
|
433
449
|
`image_column(name as String)` | None | None
|
434
450
|
`image_text_column(name as String)` | None | None
|
451
|
+
`image_text_color_column(name as String)` | None | None
|
435
452
|
`label(text as String)` | `text` (`String`) | None
|
436
453
|
`line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
|
437
454
|
`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
|
@@ -442,7 +459,7 @@ Control(Args) | Properties | Listeners
|
|
442
459
|
`msg_box_error(window = main_window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
443
460
|
`non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
444
461
|
`password_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
445
|
-
`path(draw_fill_mode = :winding)` | `fill` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0
|
462
|
+
`path(draw_fill_mode = :winding)` | `fill` (`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), `stroke` (`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), `:cap` as (`:round`, `:square`, `:flat`), `:join` as (`:miter`, `:round`, `:bevel`), `:thickness` as `Numeric`, `:miter_limit` as `Numeric`, `:dashes` as `Array` of `Numeric` ) | None
|
446
463
|
`preferences_menu_item` | None | `on_clicked`
|
447
464
|
`progress_bar` | `value` (`Numeric`) | None
|
448
465
|
`progress_bar_column(name as String)` | None | None
|
@@ -453,10 +470,13 @@ Control(Args) | Properties | Listeners
|
|
453
470
|
`slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
454
471
|
`spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
455
472
|
`square(x as Numeric, y as Numeric, length as Numeric)` | `x` (`Numeric`), `y` (`Numeric`), `length` (`Numeric`) | None
|
473
|
+
`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
|
456
474
|
`tab` | `margined` (Boolean), `num_pages` (`Integer`) | None
|
457
475
|
`tab_item(name as String)` | `index` [read-only] (`Integer`), `margined` (Boolean), `name` [read-only] (`String`) | None
|
458
|
-
`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 |
|
476
|
+
`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| ...}`
|
477
|
+
`text(x = 0 as Numeric, y = 0 as Numeric, width = area_width as Numeric)` | `align`, `default_font` | None
|
459
478
|
`text_column(name as String)` | `editable` (Boolean) | None
|
479
|
+
`text_color_column(name as String)` | `editable` (Boolean) | None
|
460
480
|
`time_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`) | `on_changed`
|
461
481
|
`vertical_box` | `padded` (Boolean) | None
|
462
482
|
`vertical_separator` | None | None
|
@@ -510,12 +530,16 @@ All operations that could normally be called on `LibUI` can also be called on `G
|
|
510
530
|
### Table API
|
511
531
|
|
512
532
|
The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Controls](#supported-controls)):
|
533
|
+
- `background_color_column`: expects color cell values
|
513
534
|
- `button_column`: expects `String` cell values
|
514
535
|
- `checkbox_column`: expects Boolean cell values
|
515
536
|
- `checkbox_text_column`: expects dual-element `Array` of Boolean and `String` cell values
|
537
|
+
- `checkbox_text_color_column`: expects triple-element `Array` of Boolean, `String`, and color cell values
|
516
538
|
- `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported Controls](#supported-controls))
|
517
539
|
- `image_text_column`: expects dual-element `Array` of `image` and `String` cell values
|
540
|
+
- `image_text_color_column`: expects triple-element `Array` of `image`, `String`, and color cell values
|
518
541
|
- `text_column`: expects `String` cell values
|
542
|
+
- `text_color_column`: expects dual-element `Array` of `String` and color cell values
|
519
543
|
- `progress_bar_column`: expects `Integer` cell values
|
520
544
|
|
521
545
|
Afterwards, it must declare its `cell_rows` array (`Array` of `Array`s of column cell values) and whether it is `editable` (Boolean) for all its columns.
|
@@ -798,11 +822,11 @@ To draw `text` in an `area`, you simply nest a `text(x, y, width)` control direc
|
|
798
822
|
|
799
823
|
`string` can have the following properties:
|
800
824
|
- `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
|
801
|
-
- `color`: rgba, hex, or
|
802
|
-
- `background`: rgba, hex, or
|
825
|
+
- `color`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
|
826
|
+
- `background`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
|
803
827
|
- `underline`: one of `:none`, `:single`, `:double`, `:suggestion`, `:color_custom`, `:color_spelling`, `:color_grammar`, `:color_auxiliary`
|
804
|
-
- `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or
|
805
|
-
- `open_type_features`:
|
828
|
+
- `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
|
829
|
+
- `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.
|
806
830
|
|
807
831
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
808
832
|
|
@@ -871,16 +895,126 @@ window('area text drawing') {
|
|
871
895
|
- Colors may be passed in as a hash of `:r`, `:g`, `:b`, `:a`, or `:red`, `:green`, `:blue`, `:alpha`, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color like `:skyblue`, or 6-number hex or 3-number hex (as `Integer` or `String` with or without `0x` prefix)
|
872
896
|
- Color alpha value defaults to `1.0` when not specified.
|
873
897
|
|
898
|
+
### Custom Keywords
|
899
|
+
|
900
|
+
To define custom keywords, simply define a method representing the custom control you want. To make reusable, you can define in modules and simply include the modules in the view classes that need them.
|
901
|
+
|
902
|
+
Example that defines `field`, `address_form`, `label_pair`, and `address` keywords (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
903
|
+
|
904
|
+
```ruby
|
905
|
+
require 'glimmer-dsl-libui'
|
906
|
+
require 'facets'
|
907
|
+
|
908
|
+
include Glimmer
|
909
|
+
|
910
|
+
Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
|
911
|
+
|
912
|
+
def field(model, property)
|
913
|
+
property = property.to_s
|
914
|
+
entry { |e|
|
915
|
+
label property.underscore.split('_').map(&:capitalize).join(' ')
|
916
|
+
text model.send(property).to_s
|
917
|
+
|
918
|
+
on_changed do
|
919
|
+
model.send("#{property}=", e.text)
|
920
|
+
end
|
921
|
+
}
|
922
|
+
end
|
923
|
+
|
924
|
+
def address_form(address)
|
925
|
+
form {
|
926
|
+
field(address, :street)
|
927
|
+
field(address, :p_o_box)
|
928
|
+
field(address, :city)
|
929
|
+
field(address, :state)
|
930
|
+
field(address, :zip_code)
|
931
|
+
}
|
932
|
+
end
|
933
|
+
|
934
|
+
def label_pair(model, attribute, value)
|
935
|
+
name_label = nil
|
936
|
+
value_label = nil
|
937
|
+
horizontal_box {
|
938
|
+
name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
|
939
|
+
value_label = label(value.to_s)
|
940
|
+
}
|
941
|
+
Glimmer::DataBinding::Observer.proc do
|
942
|
+
value_label.text = model.send(attribute)
|
943
|
+
end.observe(model, attribute)
|
944
|
+
end
|
945
|
+
|
946
|
+
def address(address)
|
947
|
+
vertical_box {
|
948
|
+
address.each_pair do |attribute, value|
|
949
|
+
label_pair(address, attribute, value)
|
950
|
+
end
|
951
|
+
}
|
952
|
+
end
|
953
|
+
|
954
|
+
address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
|
955
|
+
address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
|
956
|
+
|
957
|
+
window('Method-Based Custom Keyword') {
|
958
|
+
margined true
|
959
|
+
|
960
|
+
horizontal_box {
|
961
|
+
vertical_box {
|
962
|
+
label('Address 1') {
|
963
|
+
stretchy false
|
964
|
+
}
|
965
|
+
address_form(address1)
|
966
|
+
horizontal_separator {
|
967
|
+
stretchy false
|
968
|
+
}
|
969
|
+
label('Address 1 (Saved)') {
|
970
|
+
stretchy false
|
971
|
+
}
|
972
|
+
address(address1)
|
973
|
+
}
|
974
|
+
vertical_separator {
|
975
|
+
stretchy false
|
976
|
+
}
|
977
|
+
vertical_box {
|
978
|
+
label('Address 2') {
|
979
|
+
stretchy false
|
980
|
+
}
|
981
|
+
address_form(address2)
|
982
|
+
horizontal_separator {
|
983
|
+
stretchy false
|
984
|
+
}
|
985
|
+
label('Address 2 (Saved)') {
|
986
|
+
stretchy false
|
987
|
+
}
|
988
|
+
address(address2)
|
989
|
+
}
|
990
|
+
}
|
991
|
+
}.show
|
992
|
+
```
|
993
|
+
|
994
|
+
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
|
995
|
+
|
874
996
|
### API Gotchas
|
875
997
|
|
876
998
|
- 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`).
|
877
999
|
- `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).
|
878
|
-
-
|
1000
|
+
- `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)
|
879
1001
|
|
880
1002
|
### Original API
|
881
1003
|
|
882
|
-
To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed through [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
883
|
-
|
1004
|
+
To learn more about the [LibUI](https://github.com/kojix2/LibUI) API exposed through [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui):
|
1005
|
+
- Check out [LibUI ffi.rb](https://github.com/kojix2/LibUI/blob/main/lib/libui/ffi.rb)
|
1006
|
+
- Check out the [libui C headers](https://github.com/andlabs/libui/blob/master/ui.h)
|
1007
|
+
- Check out the [Go UI (Golang LibUI) documentation](https://pkg.go.dev/github.com/andlabs/ui) for an alternative well-documented [libui](https://github.com/andlabs/libui) reference.
|
1008
|
+
|
1009
|
+
## Packaging
|
1010
|
+
|
1011
|
+
I am documenting options for packaging, which I have not tried myself, but figured they would still be useful to add to the README.md until I can expand further effort into supporting packaging.
|
1012
|
+
|
1013
|
+
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.
|
1014
|
+
|
1015
|
+
For Mac, consider [Platybus](https://github.com/sveinbjornt/Platypus) (builds a native Mac app from a Ruby script)
|
1016
|
+
|
1017
|
+
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/).
|
884
1018
|
|
885
1019
|
## Glimmer Style Guide
|
886
1020
|
|
@@ -897,8 +1031,6 @@ The following examples include reimplementions of the examples in the [LibUI](ht
|
|
897
1031
|
|
898
1032
|
To browse all examples, simply launch the [Meta-Example](examples/meta_example.rb), which lists all examples and displays each example's code when selected. It also enables code editing to facilitate experimentation and learning.
|
899
1033
|
|
900
|
-
(note that for examples that emit output to terminal/command-line via `p` or `puts`, you must run them directly to see output)
|
901
|
-
|
902
1034
|
[examples/meta_example.rb](examples/meta_example.rb)
|
903
1035
|
|
904
1036
|
Run with this command from the root of the project if you cloned the project:
|
@@ -924,65 +1056,118 @@ Linux
|
|
924
1056
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
925
1057
|
|
926
1058
|
```ruby
|
1059
|
+
# frozen_string_literal: true
|
1060
|
+
|
927
1061
|
require 'glimmer-dsl-libui'
|
928
1062
|
require 'facets'
|
929
1063
|
|
930
1064
|
class MetaExample
|
931
1065
|
include Glimmer
|
932
1066
|
|
1067
|
+
def initialize
|
1068
|
+
@selected_example_index = 0
|
1069
|
+
end
|
1070
|
+
|
933
1071
|
def examples
|
934
1072
|
if @examples.nil?
|
935
1073
|
example_files = Dir.glob(File.join(File.expand_path('.', __dir__), '**', '*.rb'))
|
936
1074
|
example_file_names = example_files.map { |f| File.basename(f, '.rb') }
|
937
|
-
example_file_names = example_file_names.reject { |f| f == 'meta_example' }
|
1075
|
+
example_file_names = example_file_names.reject { |f| f == 'meta_example' || f.match(/\d$/) }
|
938
1076
|
@examples = example_file_names.map { |f| f.underscore.titlecase }
|
939
1077
|
end
|
940
1078
|
@examples
|
941
1079
|
end
|
942
1080
|
|
1081
|
+
def examples_with_versions
|
1082
|
+
examples.map do |example|
|
1083
|
+
version_count_for(example) > 1 ? "#{example} (#{version_count_for(example)} versions)" : example
|
1084
|
+
end
|
1085
|
+
end
|
1086
|
+
|
943
1087
|
def file_path_for(example)
|
944
1088
|
File.join(File.expand_path('.', __dir__), "#{example.underscore}.rb")
|
945
1089
|
end
|
946
1090
|
|
1091
|
+
def version_count_for(example)
|
1092
|
+
Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/\d\.rb$/)}.count + 1
|
1093
|
+
end
|
1094
|
+
|
947
1095
|
def glimmer_dsl_libui_file
|
948
1096
|
File.expand_path('../lib/glimmer-dsl-libui', __dir__)
|
949
1097
|
end
|
950
1098
|
|
1099
|
+
def selected_example
|
1100
|
+
examples[@selected_example_index]
|
1101
|
+
end
|
1102
|
+
|
951
1103
|
def launch
|
952
1104
|
window('Meta-Example', 700, 500) {
|
953
1105
|
margined true
|
954
1106
|
|
955
1107
|
horizontal_box {
|
956
1108
|
vertical_box {
|
957
|
-
|
1109
|
+
stretchy false
|
1110
|
+
|
1111
|
+
@example_radio_buttons = radio_buttons {
|
958
1112
|
stretchy false
|
959
|
-
items
|
960
|
-
selected
|
1113
|
+
items examples_with_versions
|
1114
|
+
selected @selected_example_index
|
961
1115
|
|
962
1116
|
on_selected do
|
963
|
-
@
|
1117
|
+
@selected_example_index = @example_radio_buttons.selected
|
1118
|
+
example = selected_example
|
1119
|
+
@code_entry.text = File.read(file_path_for(example))
|
1120
|
+
@version_spinbox.value = 1
|
964
1121
|
end
|
965
1122
|
}
|
966
|
-
|
1123
|
+
|
1124
|
+
horizontal_box {
|
1125
|
+
label('Version') {
|
1126
|
+
stretchy false
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
@version_spinbox = spinbox(1, 100) {
|
1130
|
+
value 1
|
1131
|
+
|
1132
|
+
on_changed do
|
1133
|
+
example = selected_example
|
1134
|
+
if @version_spinbox.value > version_count_for(example)
|
1135
|
+
@version_spinbox.value -= 1
|
1136
|
+
else
|
1137
|
+
version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
|
1138
|
+
example = "#{selected_example}#{version_number}"
|
1139
|
+
@code_entry.text = File.read(file_path_for(example))
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
}
|
1143
|
+
}
|
1144
|
+
|
1145
|
+
horizontal_box {
|
967
1146
|
stretchy false
|
968
1147
|
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
1148
|
+
button('Launch') {
|
1149
|
+
on_clicked do
|
1150
|
+
begin
|
1151
|
+
meta_example_file = File.join(Dir.home, '.meta_example.rb')
|
1152
|
+
File.write(meta_example_file, @code_entry.text)
|
1153
|
+
result = `ruby -r #{glimmer_dsl_libui_file} #{meta_example_file} 2>&1`
|
1154
|
+
msg_box('Error Running Example', result) if result.include?('error')
|
1155
|
+
rescue => e
|
1156
|
+
puts 'Unable to write code changes! Running original example...'
|
1157
|
+
system "ruby -r #{glimmer_dsl_libui_file} #{file_path_for(selected_example)}"
|
1158
|
+
end
|
978
1159
|
end
|
979
|
-
|
1160
|
+
}
|
1161
|
+
button('Reset') {
|
1162
|
+
on_clicked do
|
1163
|
+
@code_entry.text = File.read(file_path_for(selected_example))
|
1164
|
+
end
|
1165
|
+
}
|
980
1166
|
}
|
981
1167
|
}
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
}
|
1168
|
+
|
1169
|
+
@code_entry = non_wrapping_multiline_entry {
|
1170
|
+
text File.read(file_path_for(selected_example))
|
986
1171
|
}
|
987
1172
|
}
|
988
1173
|
}.show
|
@@ -2049,6 +2234,8 @@ include Glimmer
|
|
2049
2234
|
|
2050
2235
|
window('color button', 230) {
|
2051
2236
|
color_button { |cb|
|
2237
|
+
color :blue
|
2238
|
+
|
2052
2239
|
on_changed do
|
2053
2240
|
rgba = cb.color
|
2054
2241
|
p rgba
|
@@ -2513,6 +2700,14 @@ window('Editable animal sounds', 300, 200) {
|
|
2513
2700
|
|
2514
2701
|
cell_rows data
|
2515
2702
|
editable true
|
2703
|
+
|
2704
|
+
on_changed do |row, type, row_data| # fires on all changes (even ones happening through data array)
|
2705
|
+
puts "Row #{row} #{type}: #{row_data}"
|
2706
|
+
end
|
2707
|
+
|
2708
|
+
on_edited do |row, row_data| # only fires on direct table editing
|
2709
|
+
puts "Row #{row} edited: #{row_data}"
|
2710
|
+
end
|
2516
2711
|
}
|
2517
2712
|
}
|
2518
2713
|
|
@@ -2584,7 +2779,7 @@ window('Editable column animal sounds', 400, 200) {
|
|
2584
2779
|
|
2585
2780
|
### Basic Table Image
|
2586
2781
|
|
2587
|
-
This example
|
2782
|
+
This example requires pre-installing `chunky_png` Ruby gem:
|
2588
2783
|
|
2589
2784
|
```
|
2590
2785
|
gem install chunky_png -v1.4.0
|
@@ -2871,6 +3066,10 @@ window('Animal sounds', 300, 200) {
|
|
2871
3066
|
}
|
2872
3067
|
|
2873
3068
|
cell_rows data # implicit data-binding
|
3069
|
+
|
3070
|
+
on_changed do |row, type, row_data|
|
3071
|
+
puts "Row #{row} #{type}: #{row_data}"
|
3072
|
+
end
|
2874
3073
|
}
|
2875
3074
|
}
|
2876
3075
|
}.show
|
@@ -3033,7 +3232,7 @@ window('Task Progress', 300, 200) {
|
|
3033
3232
|
|
3034
3233
|
on_clicked do
|
3035
3234
|
data.each_with_index do |row_data, row|
|
3036
|
-
data[row] =
|
3235
|
+
data[row][1] = 100 # automatically updates table due to implicit data-binding
|
3037
3236
|
end
|
3038
3237
|
end
|
3039
3238
|
}
|
@@ -3041,6 +3240,78 @@ window('Task Progress', 300, 200) {
|
|
3041
3240
|
}.show
|
3042
3241
|
```
|
3043
3242
|
|
3243
|
+
### Basic Table Color
|
3244
|
+
|
3245
|
+
This example requires pre-installing `chunky_png` Ruby gem:
|
3246
|
+
|
3247
|
+
```
|
3248
|
+
gem install chunky_png -v1.4.0
|
3249
|
+
```
|
3250
|
+
|
3251
|
+
[examples/basic_table_color.rb](examples/basic_table_color.rb)
|
3252
|
+
|
3253
|
+
Run with this command from the root of the project if you cloned the project:
|
3254
|
+
|
3255
|
+
```
|
3256
|
+
ruby -r './lib/glimmer-dsl-libui' examples/basic_table_color.rb
|
3257
|
+
```
|
3258
|
+
|
3259
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
3260
|
+
|
3261
|
+
```
|
3262
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/basic_table_color'"
|
3263
|
+
```
|
3264
|
+
|
3265
|
+
Mac
|
3266
|
+
|
3267
|
+
![glimmer-dsl-libui-mac-basic-table-color.png](images/glimmer-dsl-libui-mac-basic-table-color.png)
|
3268
|
+
|
3269
|
+
Linux
|
3270
|
+
|
3271
|
+
![glimmer-dsl-libui-linux-basic-table-color.png](images/glimmer-dsl-libui-linux-basic-table-color.png)
|
3272
|
+
|
3273
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
3274
|
+
|
3275
|
+
```ruby
|
3276
|
+
require 'glimmer-dsl-libui'
|
3277
|
+
require 'chunky_png'
|
3278
|
+
|
3279
|
+
include Glimmer
|
3280
|
+
|
3281
|
+
f = File.open(File.expand_path('../icons/glimmer.png', __dir__))
|
3282
|
+
canvas = ChunkyPNG::Canvas.from_io(f)
|
3283
|
+
f.close
|
3284
|
+
canvas.resample_nearest_neighbor!(24, 24)
|
3285
|
+
data = canvas.to_rgba_stream
|
3286
|
+
width = canvas.width
|
3287
|
+
height = canvas.height
|
3288
|
+
img = image {
|
3289
|
+
image_part(data, width, height, width * 4)
|
3290
|
+
}
|
3291
|
+
|
3292
|
+
data = [
|
3293
|
+
[['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
|
3294
|
+
[['dog', :yellow] , ['woof', {r: 240, g: 32, b: 32}] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], :skyblue],
|
3295
|
+
[['chicken', :beige], ['cock-a-doodle-doo', :blue] , [false, 'mammal', :red] , [img, 'Glimmer', :beige], {r: 5, g: 120, b: 110}],
|
3296
|
+
[['horse', :purple] , ['neigh', {r: 240, g: 32, b: 32}], [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], '13a1fb'],
|
3297
|
+
[['cow', :gray] , ['moo', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :brown], 0x12ff02]
|
3298
|
+
]
|
3299
|
+
|
3300
|
+
window('Animals', 500, 200) {
|
3301
|
+
horizontal_box {
|
3302
|
+
table {
|
3303
|
+
text_color_column('Animal')
|
3304
|
+
text_color_column('Sound')
|
3305
|
+
checkbox_text_color_column('Description')
|
3306
|
+
image_text_color_column('GUI')
|
3307
|
+
background_color_column('Mammal')
|
3308
|
+
|
3309
|
+
cell_rows data
|
3310
|
+
}
|
3311
|
+
}
|
3312
|
+
}.show
|
3313
|
+
```
|
3314
|
+
|
3044
3315
|
### Form Table
|
3045
3316
|
|
3046
3317
|
[examples/form_table.rb](examples/form_table.rb)
|
@@ -3156,6 +3427,10 @@ window('Contacts', 600, 600) { |w|
|
|
3156
3427
|
text_column('State')
|
3157
3428
|
|
3158
3429
|
cell_rows data # implicit data-binding
|
3430
|
+
|
3431
|
+
on_changed do |row, type, row_data|
|
3432
|
+
puts "Row #{row} #{type}: #{row_data}"
|
3433
|
+
end
|
3159
3434
|
}
|
3160
3435
|
}
|
3161
3436
|
}.show
|
@@ -3551,14 +3826,15 @@ window('Area Gallery', 400, 400) {
|
|
3551
3826
|
path { # declarative stable path
|
3552
3827
|
square(0, 0, 100)
|
3553
3828
|
square(100, 100, 400)
|
3554
|
-
|
3829
|
+
|
3555
3830
|
fill r: 102, g: 102, b: 204
|
3556
3831
|
}
|
3557
3832
|
path { # declarative stable path
|
3558
3833
|
rectangle(0, 100, 100, 400)
|
3559
3834
|
rectangle(100, 0, 400, 100)
|
3560
|
-
|
3561
|
-
|
3835
|
+
|
3836
|
+
# linear gradient (has x0, y0, x1, y1, and stops)
|
3837
|
+
fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
|
3562
3838
|
}
|
3563
3839
|
path { # declarative stable path
|
3564
3840
|
figure(100, 100) {
|
@@ -3584,17 +3860,26 @@ window('Area Gallery', 400, 400) {
|
|
3584
3860
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3585
3861
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3586
3862
|
}
|
3863
|
+
path { # declarative stable path
|
3864
|
+
arc(400, 220, 180, 90, 90, false)
|
3865
|
+
|
3866
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
3867
|
+
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}]
|
3868
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3869
|
+
}
|
3587
3870
|
path { # declarative stable path
|
3588
3871
|
circle(200, 200, 90)
|
3589
3872
|
|
3590
3873
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3591
3874
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3592
3875
|
}
|
3593
|
-
|
3594
|
-
|
3595
|
-
|
3596
|
-
|
3597
|
-
|
3876
|
+
text(160, 40, 100) { # x, y, width
|
3877
|
+
string {
|
3878
|
+
font family: 'Times', size: 14
|
3879
|
+
color :black
|
3880
|
+
|
3881
|
+
'Area Gallery'
|
3882
|
+
}
|
3598
3883
|
}
|
3599
3884
|
|
3600
3885
|
on_mouse_event do |area_mouse_event|
|
@@ -3685,7 +3970,8 @@ window('Area Gallery', 400, 400) {
|
|
3685
3970
|
height 100
|
3686
3971
|
}
|
3687
3972
|
|
3688
|
-
|
3973
|
+
# linear gradient (has x0, y0, x1, y1, and stops)
|
3974
|
+
fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
|
3689
3975
|
}
|
3690
3976
|
path { # declarative stable path
|
3691
3977
|
figure {
|
@@ -3747,16 +4033,6 @@ window('Area Gallery', 400, 400) {
|
|
3747
4033
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3748
4034
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3749
4035
|
}
|
3750
|
-
path { # declarative stable path
|
3751
|
-
circle {
|
3752
|
-
x_center 200
|
3753
|
-
y_center 200
|
3754
|
-
radius 90
|
3755
|
-
}
|
3756
|
-
|
3757
|
-
fill r: 202, g: 102, b: 204, a: 0.5
|
3758
|
-
stroke r: 0, g: 0, b: 0, thickness: 2
|
3759
|
-
}
|
3760
4036
|
path { # declarative stable path
|
3761
4037
|
arc {
|
3762
4038
|
x_center 400
|
@@ -3767,9 +4043,32 @@ window('Area Gallery', 400, 400) {
|
|
3767
4043
|
is_negative false
|
3768
4044
|
}
|
3769
4045
|
|
3770
|
-
|
4046
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4047
|
+
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}]
|
3771
4048
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3772
4049
|
}
|
4050
|
+
path { # declarative stable path
|
4051
|
+
circle {
|
4052
|
+
x_center 200
|
4053
|
+
y_center 200
|
4054
|
+
radius 90
|
4055
|
+
}
|
4056
|
+
|
4057
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
4058
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4059
|
+
}
|
4060
|
+
text {
|
4061
|
+
x 160
|
4062
|
+
y 40
|
4063
|
+
width 100
|
4064
|
+
|
4065
|
+
string {
|
4066
|
+
font family: 'Times', size: 14
|
4067
|
+
color :black
|
4068
|
+
|
4069
|
+
'Area Gallery'
|
4070
|
+
}
|
4071
|
+
}
|
3773
4072
|
|
3774
4073
|
on_mouse_event do |area_mouse_event|
|
3775
4074
|
p area_mouse_event
|
@@ -3842,7 +4141,8 @@ window('Area Gallery', 400, 400) {
|
|
3842
4141
|
rectangle(0, 100, 100, 400)
|
3843
4142
|
rectangle(100, 0, 400, 100)
|
3844
4143
|
|
3845
|
-
|
4144
|
+
# linear gradient (has x0, y0, x1, y1, and stops)
|
4145
|
+
fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
|
3846
4146
|
}
|
3847
4147
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3848
4148
|
figure(100, 100) {
|
@@ -3868,17 +4168,26 @@ window('Area Gallery', 400, 400) {
|
|
3868
4168
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3869
4169
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
3870
4170
|
}
|
4171
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4172
|
+
arc(400, 220, 180, 90, 90, false)
|
4173
|
+
|
4174
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4175
|
+
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}]
|
4176
|
+
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4177
|
+
}
|
3871
4178
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3872
4179
|
circle(200, 200, 90)
|
3873
4180
|
|
3874
4181
|
fill r: 202, g: 102, b: 204, a: 0.5
|
3875
4182
|
stroke r: 0, g: 0, b: 0, thickness: 2
|
3876
4183
|
}
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
3881
|
-
|
4184
|
+
text(160, 40, 100) { # x, y, width
|
4185
|
+
string {
|
4186
|
+
font family: 'Times', size: 14
|
4187
|
+
color :black
|
4188
|
+
|
4189
|
+
'Area Gallery'
|
4190
|
+
}
|
3882
4191
|
}
|
3883
4192
|
end
|
3884
4193
|
|
@@ -3971,7 +4280,8 @@ window('Area Gallery', 400, 400) {
|
|
3971
4280
|
height 100
|
3972
4281
|
}
|
3973
4282
|
|
3974
|
-
|
4283
|
+
# linear gradient (has x0, y0, x1, y1, and stops)
|
4284
|
+
fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
|
3975
4285
|
}
|
3976
4286
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
3977
4287
|
figure {
|
@@ -4033,16 +4343,6 @@ window('Area Gallery', 400, 400) {
|
|
4033
4343
|
fill r: 202, g: 102, b: 204, a: 0.5
|
4034
4344
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4035
4345
|
}
|
4036
|
-
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4037
|
-
circle {
|
4038
|
-
x_center 200
|
4039
|
-
y_center 200
|
4040
|
-
radius 90
|
4041
|
-
}
|
4042
|
-
|
4043
|
-
fill r: 202, g: 102, b: 204, a: 0.5
|
4044
|
-
stroke r: 0, g: 0, b: 0, thickness: 2
|
4045
|
-
}
|
4046
4346
|
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4047
4347
|
arc {
|
4048
4348
|
x_center 400
|
@@ -4053,9 +4353,32 @@ window('Area Gallery', 400, 400) {
|
|
4053
4353
|
is_negative false
|
4054
4354
|
}
|
4055
4355
|
|
4056
|
-
|
4356
|
+
# radial gradient (has an outer_radius in addition to x0, y0, x1, y1, and stops)
|
4357
|
+
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}]
|
4057
4358
|
stroke r: 0, g: 0, b: 0, thickness: 2, dashes: [50, 10, 10, 10], dash_phase: -50.0
|
4058
4359
|
}
|
4360
|
+
path { # a dynamic path is added semi-declaratively inside on_draw block
|
4361
|
+
circle {
|
4362
|
+
x_center 200
|
4363
|
+
y_center 200
|
4364
|
+
radius 90
|
4365
|
+
}
|
4366
|
+
|
4367
|
+
fill r: 202, g: 102, b: 204, a: 0.5
|
4368
|
+
stroke r: 0, g: 0, b: 0, thickness: 2
|
4369
|
+
}
|
4370
|
+
text {
|
4371
|
+
x 160
|
4372
|
+
y 40
|
4373
|
+
width 100
|
4374
|
+
|
4375
|
+
string {
|
4376
|
+
font family: 'Times', size: 14
|
4377
|
+
color :black
|
4378
|
+
|
4379
|
+
'Area Gallery'
|
4380
|
+
}
|
4381
|
+
}
|
4059
4382
|
end
|
4060
4383
|
|
4061
4384
|
on_mouse_event do |area_mouse_event|
|
@@ -5441,11 +5764,11 @@ class CustomDrawText
|
|
5441
5764
|
text { # default arguments for x, y, and width are (0, 0, area_draw_params[:area_width])
|
5442
5765
|
# align :left # default alignment
|
5443
5766
|
|
5444
|
-
|
5445
|
-
font @font
|
5446
|
-
color @color
|
5447
|
-
background @background
|
5448
|
-
underline @underline
|
5767
|
+
string {
|
5768
|
+
font @font
|
5769
|
+
color @color
|
5770
|
+
background @background
|
5771
|
+
underline @underline
|
5449
5772
|
|
5450
5773
|
' At last Ygramul sensed that something was coming toward ' \
|
5451
5774
|
'her. With the speed of lightning, she turned about, confronting ' \
|
@@ -5479,7 +5802,122 @@ class CustomDrawText
|
|
5479
5802
|
end
|
5480
5803
|
|
5481
5804
|
CustomDrawText.new.launch
|
5805
|
+
```
|
5806
|
+
|
5807
|
+
### Method-Based Custom Keyword
|
5808
|
+
|
5809
|
+
[examples/method_based_custom_keyword.rb](examples/method_based_custom_keyword.rb)
|
5810
|
+
|
5811
|
+
Run with this command from the root of the project if you cloned the project:
|
5812
|
+
|
5813
|
+
```
|
5814
|
+
ruby -r './lib/glimmer-dsl-libui' examples/method_based_custom_keyword.rb
|
5815
|
+
```
|
5816
|
+
|
5817
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
5818
|
+
|
5819
|
+
```
|
5820
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/method_based_custom_keyword'"
|
5821
|
+
```
|
5822
|
+
|
5823
|
+
Mac
|
5824
|
+
|
5825
|
+
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
|
5826
|
+
|
5827
|
+
Linux
|
5828
|
+
|
5829
|
+
![glimmer-dsl-libui-linux-method-based-custom-keyword.png](images/glimmer-dsl-libui-linux-method-based-custom-keyword.png)
|
5830
|
+
|
5831
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
5482
5832
|
|
5833
|
+
```ruby
|
5834
|
+
require 'glimmer-dsl-libui'
|
5835
|
+
require 'facets'
|
5836
|
+
|
5837
|
+
include Glimmer
|
5838
|
+
|
5839
|
+
Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
|
5840
|
+
|
5841
|
+
def field(model, property)
|
5842
|
+
property = property.to_s
|
5843
|
+
entry { |e|
|
5844
|
+
label property.underscore.split('_').map(&:capitalize).join(' ')
|
5845
|
+
text model.send(property).to_s
|
5846
|
+
|
5847
|
+
on_changed do
|
5848
|
+
model.send("#{property}=", e.text)
|
5849
|
+
end
|
5850
|
+
}
|
5851
|
+
end
|
5852
|
+
|
5853
|
+
def address_form(address)
|
5854
|
+
form {
|
5855
|
+
field(address, :street)
|
5856
|
+
field(address, :p_o_box)
|
5857
|
+
field(address, :city)
|
5858
|
+
field(address, :state)
|
5859
|
+
field(address, :zip_code)
|
5860
|
+
}
|
5861
|
+
end
|
5862
|
+
|
5863
|
+
def label_pair(model, attribute, value)
|
5864
|
+
name_label = nil
|
5865
|
+
value_label = nil
|
5866
|
+
horizontal_box {
|
5867
|
+
name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
|
5868
|
+
value_label = label(value.to_s)
|
5869
|
+
}
|
5870
|
+
Glimmer::DataBinding::Observer.proc do
|
5871
|
+
value_label.text = model.send(attribute)
|
5872
|
+
end.observe(model, attribute)
|
5873
|
+
end
|
5874
|
+
|
5875
|
+
def address(address)
|
5876
|
+
vertical_box {
|
5877
|
+
address.each_pair do |attribute, value|
|
5878
|
+
label_pair(address, attribute, value)
|
5879
|
+
end
|
5880
|
+
}
|
5881
|
+
end
|
5882
|
+
|
5883
|
+
address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
|
5884
|
+
address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
|
5885
|
+
|
5886
|
+
window('Method-Based Custom Keyword') {
|
5887
|
+
margined true
|
5888
|
+
|
5889
|
+
horizontal_box {
|
5890
|
+
vertical_box {
|
5891
|
+
label('Address 1') {
|
5892
|
+
stretchy false
|
5893
|
+
}
|
5894
|
+
address_form(address1)
|
5895
|
+
horizontal_separator {
|
5896
|
+
stretchy false
|
5897
|
+
}
|
5898
|
+
label('Address 1 (Saved)') {
|
5899
|
+
stretchy false
|
5900
|
+
}
|
5901
|
+
address(address1)
|
5902
|
+
}
|
5903
|
+
vertical_separator {
|
5904
|
+
stretchy false
|
5905
|
+
}
|
5906
|
+
vertical_box {
|
5907
|
+
label('Address 2') {
|
5908
|
+
stretchy false
|
5909
|
+
}
|
5910
|
+
address_form(address2)
|
5911
|
+
horizontal_separator {
|
5912
|
+
stretchy false
|
5913
|
+
}
|
5914
|
+
label('Address 2 (Saved)') {
|
5915
|
+
stretchy false
|
5916
|
+
}
|
5917
|
+
address(address2)
|
5918
|
+
}
|
5919
|
+
}
|
5920
|
+
}.show
|
5483
5921
|
```
|
5484
5922
|
|
5485
5923
|
## Contributing to glimmer-dsl-libui
|