glimmer-dsl-libui 0.2.21 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +571 -42
- data/VERSION +1 -1
- data/examples/area_gallery.rb +1 -1
- data/examples/area_gallery2.rb +1 -1
- data/examples/area_gallery3.rb +1 -1
- data/examples/area_gallery4.rb +1 -1
- data/examples/basic_image.rb +19 -0
- data/examples/basic_image2.rb +13 -0
- data/examples/basic_image3.rb +23 -0
- data/examples/basic_image4.rb +17 -0
- data/examples/basic_image5.rb +75 -0
- data/examples/meta_example.rb +1 -1
- data/examples/snake/model/apple.rb +33 -0
- data/examples/snake/model/game.rb +51 -0
- data/examples/snake/model/snake.rb +95 -0
- data/examples/snake/model/vertebra.rb +22 -0
- data/examples/snake/presenter/cell.rb +27 -0
- data/examples/snake/presenter/grid.rb +47 -0
- data/examples/snake.rb +90 -0
- data/examples/tetris/model/game.rb +1 -1
- data/examples/tetris.rb +23 -3
- data/examples/tic_tac_toe.rb +1 -1
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/control_expression.rb +1 -1
- data/lib/glimmer/libui/control_proxy/image_part_proxy.rb +0 -1
- data/lib/glimmer/libui/control_proxy/image_proxy.rb +152 -12
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +1 -1
- data/lib/glimmer/libui/control_proxy.rb +7 -7
- data/lib/glimmer/libui/image_path_renderer.rb +30 -0
- data/lib/glimmer/libui.rb +6 -5
- metadata +31 -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.
|
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.3.0
|
2
2
|
## Prerequisite-Free Ruby Desktop Development GUI Library
|
3
3
|
[](http://badge.fury.io/rb/glimmer-dsl-libui)
|
4
4
|
[](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
@@ -143,7 +143,7 @@ window('Area Gallery', 400, 400) {
|
|
143
143
|
}
|
144
144
|
text(161, 40, 100) { # x, y, width
|
145
145
|
string('Area Gallery') {
|
146
|
-
font family: 'Arial', size: 14
|
146
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
147
147
|
color :black
|
148
148
|
}
|
149
149
|
}
|
@@ -218,9 +218,10 @@ NOTE: [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) is fe
|
|
218
218
|
Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interested in:
|
219
219
|
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop Development GUI Framework)
|
220
220
|
- [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps)
|
221
|
+
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
222
|
+
- [glimmer-dsl-gtk](https://github.com/AndyObtiva/glimmer-dsl-gtk): Glimmer DSL for GTK (Ruby-GNOME Desktop Development GUI Library)
|
221
223
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
222
224
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
|
223
|
-
- [glimmer-dsl-tk](https://github.com/AndyObtiva/glimmer-dsl-tk): Glimmer DSL for Tk (MRI Ruby Desktop Development GUI Library)
|
224
225
|
|
225
226
|
## Table of Contents
|
226
227
|
|
@@ -237,6 +238,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
237
238
|
- [Extra Operations](#extra-operations)
|
238
239
|
- [Table API](#table-api)
|
239
240
|
- [Area API](#area-api)
|
241
|
+
- [Image Glimmer Custom Control](#image-glimmer-custom-control)
|
240
242
|
- [Smart Defaults and Conventions](#smart-defaults-and-conventions)
|
241
243
|
- [Custom Keywords](#custom-keywords)
|
242
244
|
- [API Gotchas](#api-gotchas)
|
@@ -269,6 +271,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
269
271
|
- [Basic Area](#basic-area)
|
270
272
|
- [Dynamic Area](#dynamic-area)
|
271
273
|
- [Area Gallery](#area-gallery)
|
274
|
+
- [Basic Image](#basic-image)
|
272
275
|
- [Histogram](#histogram)
|
273
276
|
- [Basic Transform](#basic-transform)
|
274
277
|
- [Login](#login)
|
@@ -279,6 +282,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
279
282
|
- [Method-Based Custom Keyword](#method-based-custom-keyword)
|
280
283
|
- [Tetris](#tetris)
|
281
284
|
- [Tic Tac Toe](#tic-tac-toe)
|
285
|
+
- [Snake](#snake)
|
282
286
|
- [Applications](#applications)
|
283
287
|
- [Manga2PDF](#manga2pdf)
|
284
288
|
- [Befunge98 GUI](#befunge98-gui)
|
@@ -371,7 +375,7 @@ gem install glimmer-dsl-libui
|
|
371
375
|
Or install via Bundler `Gemfile`:
|
372
376
|
|
373
377
|
```ruby
|
374
|
-
gem 'glimmer-dsl-libui', '~> 0.
|
378
|
+
gem 'glimmer-dsl-libui', '~> 0.3.0'
|
375
379
|
```
|
376
380
|
|
377
381
|
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.
|
@@ -471,7 +475,7 @@ Keyword(Args) | Properties | Listeners
|
|
471
475
|
`group(text as String)` | `margined` (Boolean), `title` (`String`) | None
|
472
476
|
`horizontal_box` | `padded` (Boolean) | None
|
473
477
|
`horizontal_separator` | None | None
|
474
|
-
`image(width as Numeric, height as Numeric)` | None | None
|
478
|
+
`image(file as String = nil, width as Numeric = nil, height as Numeric = nil)` | None | None
|
475
479
|
`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
|
476
480
|
`image_column(name as String)` | None | None
|
477
481
|
`image_text_column(name as String)` | None | None
|
@@ -550,8 +554,8 @@ There are additional useful `Glimmer::LibUI` operations that are not found in `L
|
|
550
554
|
- `Glimmer::LibUI::integer_to_boolean(int, allow_nil: true)`
|
551
555
|
- `Glimmer::LibUI::boolean_to_integer(int, allow_nil: true)`
|
552
556
|
- `Glimmer::LibUI::degrees_to_radians(degrees)`
|
553
|
-
- `Glimmer::LibUI::interpret_color(value)`: interprets a color in any form like `String`, `Symbol`, or hex into an rgb `Hash`
|
554
|
-
- `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash`
|
557
|
+
- `Glimmer::LibUI::interpret_color(value)`: interprets a color in any form like `String`, `Symbol`, or hex into an rgb `Hash` (including `0x1f3b5d`, `'0x1f3b5d'`, `'#1f3b5d'`, and 3-char hex-shorthand variations)
|
558
|
+
- `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash` (including `0x1f3b5d`, `'0x1f3b5d'`, `'#1f3b5d'`, and 3-char hex-shorthand variations)
|
555
559
|
- `Glimmer::LibUI::enum_names`: provides all possible enum names to use with `Glimmer::LibUI::enum_symbols(enum_name)`
|
556
560
|
- `Glimmer::LibUI::enum_symbols(enum_name)`: returns all possible values for an enum. `enum_name` can be:
|
557
561
|
- `:draw_brush_type`: `[:solid, :linear_gradient, :radial_gradient, :image]`
|
@@ -899,9 +903,11 @@ transform m1
|
|
899
903
|
# and then reuse m1 elsewhere too
|
900
904
|
```
|
901
905
|
|
906
|
+
You can set a `matrix`/`transform` on `area` directly to conveniently apply to all nested `path`s too.
|
907
|
+
|
902
908
|
Note that `area`, `path`, and nested shapes are all truly declarative, meaning they do not care about the ordering of calls to `fill`, `stroke`, and `transform`. Furthermore, any transform that is applied is reversed at the end of the block, so you never have to worry about the ordering of `transform` calls among different paths. You simply set a transform on the `path`s that need it and it is guaranteed to be called before all its content is drawn, and then undone afterwards to avoid affecting later paths. Matrix `transform` can be set on an entire `area` too, applying to all nested `path`s.
|
903
909
|
|
904
|
-
`fill` and `stroke` accept [X11](https://en.wikipedia.org/wiki/X11_color_names) color `Symbol`s/`String`s like `:skyblue` and `'sandybrown'` or 6-
|
910
|
+
`fill` and `stroke` accept [X11](https://en.wikipedia.org/wiki/X11_color_names) color `Symbol`s/`String`s like `:skyblue` and `'sandybrown'` or 6-char hex or 3-char hex-shorthand (as `Integer` or `String` with or without `0x` prefix)
|
905
911
|
|
906
912
|
Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
|
907
913
|
|
@@ -958,6 +964,172 @@ window('area text drawing') {
|
|
958
964
|
}.show
|
959
965
|
```
|
960
966
|
|
967
|
+
#### Image Glimmer Custom Control
|
968
|
+
|
969
|
+
**(ALPHA FEATURE)**
|
970
|
+
|
971
|
+
[libui](https://github.com/andlabs/libui) does not support `image` rendering outside of `table` yet.
|
972
|
+
However, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) adds a special `image` custom control that renders an image unto an `area` pixel by pixel (and when possible to optimize, line by line).
|
973
|
+
|
974
|
+
Given that it is not a [libui](https://github.com/andlabs/libui)-native control, please keep these notes in mind:
|
975
|
+
- [libui](https://github.com/andlabs/libui) pixel-by-pixel rendering performance is slow
|
976
|
+
- Including an `image` inside an `area` `on_draw` listener improves performance due to not retaining pixel/line data in memory.
|
977
|
+
- Supplying `width` and `height` (2nd and 3rd arguments) greatly improves performance when shrinking image
|
978
|
+
|
979
|
+
Currently, it is recommended to use `image` with very small `width` and `height` values only.
|
980
|
+
|
981
|
+
Setting a `transform` `matrix` is supported under `image` just like it is under `path` and `text` inside `area`.
|
982
|
+
|
983
|
+
Example of using `image` declaratively (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
984
|
+
|
985
|
+

|
986
|
+
|
987
|
+
```ruby
|
988
|
+
require 'glimmer-dsl-libui'
|
989
|
+
|
990
|
+
include Glimmer
|
991
|
+
|
992
|
+
window('Basic Image', 96, 96) {
|
993
|
+
area {
|
994
|
+
image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
|
995
|
+
}
|
996
|
+
}.show
|
997
|
+
```
|
998
|
+
|
999
|
+
Example of better performance via `on_draw` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1000
|
+
|
1001
|
+
```ruby
|
1002
|
+
require 'glimmer-dsl-libui'
|
1003
|
+
|
1004
|
+
include Glimmer
|
1005
|
+
|
1006
|
+
window('Basic Image', 96, 96) {
|
1007
|
+
area {
|
1008
|
+
on_draw do |area_draw_params|
|
1009
|
+
image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
|
1010
|
+
end
|
1011
|
+
}
|
1012
|
+
}.show
|
1013
|
+
```
|
1014
|
+
|
1015
|
+
Example of using `image` declaratively with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1016
|
+
|
1017
|
+
```ruby
|
1018
|
+
require 'glimmer-dsl-libui'
|
1019
|
+
|
1020
|
+
include Glimmer
|
1021
|
+
|
1022
|
+
window('Basic Image', 96, 96) {
|
1023
|
+
area {
|
1024
|
+
image {
|
1025
|
+
file File.expand_path('icons/glimmer.png', __dir__)
|
1026
|
+
width 96
|
1027
|
+
height 96
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
}.show
|
1031
|
+
```
|
1032
|
+
|
1033
|
+
Example of better performance via `on_draw` with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
require 'glimmer-dsl-libui'
|
1037
|
+
|
1038
|
+
include Glimmer
|
1039
|
+
|
1040
|
+
window('Basic Image', 96, 96) {
|
1041
|
+
area {
|
1042
|
+
on_draw do |area_draw_params|
|
1043
|
+
image {
|
1044
|
+
file File.expand_path('icons/glimmer.png', __dir__)
|
1045
|
+
width 96
|
1046
|
+
height 96
|
1047
|
+
}
|
1048
|
+
end
|
1049
|
+
}
|
1050
|
+
}.show
|
1051
|
+
```
|
1052
|
+
|
1053
|
+
If you need to render an image pixel by pixel (e.g. to support a format other than `.png`) for very exceptional scenarios, you may use this example as a guide, including a line-merge optimization for neighboring horizontal pixels with the same color:
|
1054
|
+
|
1055
|
+
```ruby
|
1056
|
+
# This is the manual way of rendering an image unto an area control.
|
1057
|
+
# It could come in handy in special situations.
|
1058
|
+
# Otherwise, it is recommended to simply utilize the `image` control that
|
1059
|
+
# can be nested under area or area on_draw listener to automate all this work.
|
1060
|
+
|
1061
|
+
require 'glimmer-dsl-libui'
|
1062
|
+
require 'chunky_png'
|
1063
|
+
|
1064
|
+
include Glimmer
|
1065
|
+
|
1066
|
+
puts 'Parsing image...'; $stdout.flush
|
1067
|
+
|
1068
|
+
f = File.open(File.expand_path('icons/glimmer.png', __dir__))
|
1069
|
+
canvas = ChunkyPNG::Canvas.from_io(f)
|
1070
|
+
f.close
|
1071
|
+
canvas.resample_nearest_neighbor!(96, 96)
|
1072
|
+
data = canvas.to_rgba_stream
|
1073
|
+
width = canvas.width
|
1074
|
+
height = canvas.height
|
1075
|
+
puts "Image width: #{width}"
|
1076
|
+
puts "Image height: #{height}"
|
1077
|
+
|
1078
|
+
puts 'Parsing colors...'; $stdout.flush
|
1079
|
+
|
1080
|
+
color_maps = height.times.map do |y|
|
1081
|
+
width.times.map do |x|
|
1082
|
+
r = data[(y*width + x)*4].ord
|
1083
|
+
g = data[(y*width + x)*4 + 1].ord
|
1084
|
+
b = data[(y*width + x)*4 + 2].ord
|
1085
|
+
a = data[(y*width + x)*4 + 3].ord
|
1086
|
+
{x: x, y: y, color: {r: r, g: g, b: b, a: a}}
|
1087
|
+
end
|
1088
|
+
end.flatten
|
1089
|
+
puts "#{color_maps.size} pixels to render..."; $stdout.flush
|
1090
|
+
|
1091
|
+
puts 'Parsing shapes...'; $stdout.flush
|
1092
|
+
|
1093
|
+
shape_maps = []
|
1094
|
+
original_color_maps = color_maps.dup
|
1095
|
+
indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
|
1096
|
+
color_maps.each do |color_map|
|
1097
|
+
index = indexed_original_color_maps[color_map]
|
1098
|
+
@rectangle_start_x ||= color_map[:x]
|
1099
|
+
@rectangle_width ||= 1
|
1100
|
+
if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
|
1101
|
+
@rectangle_width += 1
|
1102
|
+
else
|
1103
|
+
if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
|
1104
|
+
shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
|
1105
|
+
else
|
1106
|
+
shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
|
1107
|
+
end
|
1108
|
+
@rectangle_width = 1
|
1109
|
+
@rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
puts "#{shape_maps.size} shapes to render..."; $stdout.flush
|
1113
|
+
|
1114
|
+
puts 'Rendering image...'; $stdout.flush
|
1115
|
+
|
1116
|
+
window('Basic Image', 96, 96) {
|
1117
|
+
area {
|
1118
|
+
on_draw do |area_draw_params|
|
1119
|
+
shape_maps.each do |shape_map|
|
1120
|
+
path {
|
1121
|
+
rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
|
1122
|
+
|
1123
|
+
fill shape_map[:color]
|
1124
|
+
}
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
}
|
1128
|
+
}.show
|
1129
|
+
```
|
1130
|
+
|
1131
|
+
Check out [examples/basic_image.rb](#basic-image) (all versions) for examples of using `image` Glimmer custom control.
|
1132
|
+
|
961
1133
|
### Smart Defaults and Conventions
|
962
1134
|
|
963
1135
|
- `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
|
@@ -980,7 +1152,7 @@ window('area text drawing') {
|
|
980
1152
|
- When destroying a control nested under a `form`, it is automatically deleted from the form's children
|
981
1153
|
- When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
|
982
1154
|
- For `date_time_picker`, `date_picker`, and `time_picker`, make sure `time` hash values for `mon`, `wday`, and `yday` are 1-based instead of [libui](https://github.com/andlabs/libui) original 0-based values, and return `dst` as Boolean instead of `isdst` as `1`/`0`
|
983
|
-
- Smart defaults for `grid` child
|
1155
|
+
- Smart defaults for `grid` child properties are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`:fill`), `vexpand` (`false`), and `valign` (`:fill`)
|
984
1156
|
- The `table` control automatically constructs required `TableModelHandler`, `TableModel`, and `TableParams`, calculating all their arguments from `cell_rows` and `editable` properties (e.g. `NumRows`) as well as nested columns (e.g. `text_column`)
|
985
1157
|
- Table model instances are automatically freed from memory after `window` is destroyed.
|
986
1158
|
- 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.
|
@@ -994,7 +1166,7 @@ window('area text drawing') {
|
|
994
1166
|
- All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
|
995
1167
|
- All resources are freed automatically once no longer needed or left to garbage collection.
|
996
1168
|
- 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.
|
997
|
-
- 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-
|
1169
|
+
- 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-char hex or 3-char hex (as `Integer` or `String` with or without `0x` prefix)
|
998
1170
|
- Color alpha value defaults to `1.0` when not specified.
|
999
1171
|
|
1000
1172
|
### Custom Keywords
|
@@ -1221,7 +1393,7 @@ class MetaExample
|
|
1221
1393
|
|
1222
1394
|
def run_example(example)
|
1223
1395
|
Thread.new do
|
1224
|
-
command = "ruby -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
1396
|
+
command = "#{RbConfig.ruby} -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
1225
1397
|
result = ''
|
1226
1398
|
IO.popen(command) do |f|
|
1227
1399
|
sleep(0.0001) # yield to main thread
|
@@ -1758,11 +1930,11 @@ class TinyMidiPlayer
|
|
1758
1930
|
|
1759
1931
|
UI.new_horizontal_box.tap do |hbox|
|
1760
1932
|
UI.new_vertical_box.tap do |vbox|
|
1761
|
-
UI.new_button('
|
1933
|
+
UI.new_button('â–¶').tap do |button1|
|
1762
1934
|
UI.button_on_clicked(button1) { play_midi }
|
1763
1935
|
UI.box_append(vbox, button1, 1)
|
1764
1936
|
end
|
1765
|
-
UI.new_button('
|
1937
|
+
UI.new_button('â– ').tap do |button2|
|
1766
1938
|
UI.button_on_clicked(button2) { stop_midi }
|
1767
1939
|
UI.box_append(vbox, button2, 1)
|
1768
1940
|
end
|
@@ -1856,12 +2028,12 @@ class TinyMidiPlayer
|
|
1856
2028
|
vertical_box {
|
1857
2029
|
stretchy false
|
1858
2030
|
|
1859
|
-
button('
|
2031
|
+
button('â–¶') {
|
1860
2032
|
on_clicked do
|
1861
2033
|
play_midi
|
1862
2034
|
end
|
1863
2035
|
}
|
1864
|
-
button('
|
2036
|
+
button('â– ') {
|
1865
2037
|
on_clicked do
|
1866
2038
|
stop_midi
|
1867
2039
|
end
|
@@ -2992,13 +3164,7 @@ window('Editable column animal sounds', 400, 200) {
|
|
2992
3164
|
|
2993
3165
|
### Basic Table Image
|
2994
3166
|
|
2995
|
-
|
2996
|
-
|
2997
|
-
```
|
2998
|
-
gem install chunky_png -v1.4.0
|
2999
|
-
```
|
3000
|
-
|
3001
|
-
Also, note that behavior varies per platform (i.e. how `table` chooses to size images by default).
|
3167
|
+
Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
|
3002
3168
|
|
3003
3169
|
[examples/basic_table_image.rb](examples/basic_table_image.rb)
|
3004
3170
|
|
@@ -3154,13 +3320,7 @@ window('The Red Turtle', 310, 350, false) {
|
|
3154
3320
|
|
3155
3321
|
### Basic Table Image Text
|
3156
3322
|
|
3157
|
-
|
3158
|
-
|
3159
|
-
```
|
3160
|
-
gem install chunky_png -v1.4.0
|
3161
|
-
```
|
3162
|
-
|
3163
|
-
Also, note that behavior varies per platform (i.e. how `table` chooses to size images by default).
|
3323
|
+
Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
|
3164
3324
|
|
3165
3325
|
[examples/basic_table_image_text.rb](examples/basic_table_image_text.rb)
|
3166
3326
|
|
@@ -3480,12 +3640,6 @@ window('Task Progress', 300, 200) {
|
|
3480
3640
|
|
3481
3641
|
### Basic Table Color
|
3482
3642
|
|
3483
|
-
This example requires pre-installing `chunky_png` Ruby gem:
|
3484
|
-
|
3485
|
-
```
|
3486
|
-
gem install chunky_png -v1.4.0
|
3487
|
-
```
|
3488
|
-
|
3489
3643
|
[examples/basic_table_color.rb](examples/basic_table_color.rb)
|
3490
3644
|
|
3491
3645
|
Run with this command from the root of the project if you cloned the project:
|
@@ -4127,7 +4281,7 @@ window('Area Gallery', 400, 400) {
|
|
4127
4281
|
}
|
4128
4282
|
text(161, 40, 100) { # x, y, width
|
4129
4283
|
string('Area Gallery') {
|
4130
|
-
font family: 'Arial', size: 14
|
4284
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4131
4285
|
color :black
|
4132
4286
|
}
|
4133
4287
|
}
|
@@ -4337,7 +4491,7 @@ window('Area Gallery', 400, 400) {
|
|
4337
4491
|
width 100
|
4338
4492
|
|
4339
4493
|
string {
|
4340
|
-
font family: 'Arial', size: 14
|
4494
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4341
4495
|
color :black
|
4342
4496
|
|
4343
4497
|
'Area Gallery'
|
@@ -4450,7 +4604,7 @@ window('Area Gallery', 400, 400) {
|
|
4450
4604
|
}
|
4451
4605
|
text(161, 40, 100) { # x, y, width
|
4452
4606
|
string('Area Gallery') {
|
4453
|
-
font family: 'Arial', size: 14
|
4607
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4454
4608
|
color :black
|
4455
4609
|
}
|
4456
4610
|
}
|
@@ -4662,7 +4816,7 @@ window('Area Gallery', 400, 400) {
|
|
4662
4816
|
width 100
|
4663
4817
|
|
4664
4818
|
string {
|
4665
|
-
font family: 'Arial', size: 14
|
4819
|
+
font family: 'Arial', size: (OS.mac? ? 14 : 11)
|
4666
4820
|
color :black
|
4667
4821
|
|
4668
4822
|
'Area Gallery'
|
@@ -4721,6 +4875,196 @@ window('Area Gallery', 400, 400) {
|
|
4721
4875
|
}.show
|
4722
4876
|
```
|
4723
4877
|
|
4878
|
+
### Basic Image
|
4879
|
+
|
4880
|
+
[examples/basic_image.rb](examples/basic_image.rb)
|
4881
|
+
|
4882
|
+
Run with this command from the root of the project if you cloned the project:
|
4883
|
+
|
4884
|
+
```
|
4885
|
+
ruby -r './lib/glimmer-dsl-libui' examples/basic_image.rb
|
4886
|
+
```
|
4887
|
+
|
4888
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
4889
|
+
|
4890
|
+
```
|
4891
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/basic_image'"
|
4892
|
+
```
|
4893
|
+
|
4894
|
+
Mac
|
4895
|
+
|
4896
|
+

|
4897
|
+
|
4898
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
4899
|
+
|
4900
|
+
```ruby
|
4901
|
+
require 'glimmer-dsl-libui'
|
4902
|
+
|
4903
|
+
include Glimmer
|
4904
|
+
|
4905
|
+
window('Basic Image', 96, 96) {
|
4906
|
+
area {
|
4907
|
+
# image is not a real LibUI control. It is built in Glimmer as a custom control that renders
|
4908
|
+
# tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
|
4909
|
+
# be used in exceptional circumstances where an image control is really needed.
|
4910
|
+
#
|
4911
|
+
# Furthermore, adding image directly under area is even slower due to taking up more memory for every
|
4912
|
+
# image pixel rendered. Check basic_image2.rb for a faster alternative using on_draw manually.
|
4913
|
+
#
|
4914
|
+
# It is recommended to pass width/height args to shrink image and achieve faster performance.
|
4915
|
+
image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
|
4916
|
+
}
|
4917
|
+
}.show
|
4918
|
+
```
|
4919
|
+
|
4920
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (better performance via `on_draw`):
|
4921
|
+
|
4922
|
+
```ruby
|
4923
|
+
# frozen_string_literal: true
|
4924
|
+
|
4925
|
+
require 'glimmer-dsl-libui'
|
4926
|
+
|
4927
|
+
include Glimmer
|
4928
|
+
|
4929
|
+
window('Basic Image', 96, 96) {
|
4930
|
+
area {
|
4931
|
+
on_draw do |area_draw_params|
|
4932
|
+
image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
|
4933
|
+
end
|
4934
|
+
}
|
4935
|
+
}.show
|
4936
|
+
```
|
4937
|
+
|
4938
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (explicit properties):
|
4939
|
+
|
4940
|
+
```ruby
|
4941
|
+
# frozen_string_literal: true
|
4942
|
+
|
4943
|
+
require 'glimmer-dsl-libui'
|
4944
|
+
|
4945
|
+
include Glimmer
|
4946
|
+
|
4947
|
+
window('Basic Image', 96, 96) {
|
4948
|
+
area {
|
4949
|
+
# image is not a real LibUI control. It is built in Glimmer as a custom control that renders
|
4950
|
+
# tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
|
4951
|
+
# be used in exceptional circumstances where an image control is really needed.
|
4952
|
+
#
|
4953
|
+
# Furthermore, adding image directly under area is even slower due to taking up more memory for every
|
4954
|
+
# image pixel rendered. Check basic_image4.rb for a faster alternative using on_draw manually.
|
4955
|
+
#
|
4956
|
+
# It is recommended to pass width/height args to shrink image and achieve faster performance.
|
4957
|
+
image {
|
4958
|
+
file File.expand_path('../icons/glimmer.png', __dir__)
|
4959
|
+
width 96
|
4960
|
+
height 96
|
4961
|
+
}
|
4962
|
+
}
|
4963
|
+
}.show
|
4964
|
+
```
|
4965
|
+
|
4966
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (better performance with `on_draw` when setting explicit properties):
|
4967
|
+
|
4968
|
+
```ruby
|
4969
|
+
# frozen_string_literal: true
|
4970
|
+
|
4971
|
+
require 'glimmer-dsl-libui'
|
4972
|
+
|
4973
|
+
include Glimmer
|
4974
|
+
|
4975
|
+
window('Basic Image', 96, 96) {
|
4976
|
+
area {
|
4977
|
+
on_draw do |area_draw_params|
|
4978
|
+
image {
|
4979
|
+
file File.expand_path('../icons/glimmer.png', __dir__)
|
4980
|
+
width 96
|
4981
|
+
height 96
|
4982
|
+
}
|
4983
|
+
end
|
4984
|
+
}
|
4985
|
+
}.show
|
4986
|
+
```
|
4987
|
+
|
4988
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 5 (fully manual pixel-by-pixel rendering):
|
4989
|
+
|
4990
|
+
```ruby
|
4991
|
+
# frozen_string_literal: true
|
4992
|
+
|
4993
|
+
# This is the manual way of rendering an image unto an area control.
|
4994
|
+
# It could come in handy in special situations.
|
4995
|
+
# Otherwise, it is recommended to simply utilize the `image` control that
|
4996
|
+
# can be nested under area or area on_draw listener to automate all this work.
|
4997
|
+
|
4998
|
+
require 'glimmer-dsl-libui'
|
4999
|
+
require 'chunky_png'
|
5000
|
+
|
5001
|
+
include Glimmer
|
5002
|
+
|
5003
|
+
puts 'Parsing image...'; $stdout.flush
|
5004
|
+
|
5005
|
+
f = File.open(File.expand_path('../icons/glimmer.png', __dir__))
|
5006
|
+
canvas = ChunkyPNG::Canvas.from_io(f)
|
5007
|
+
f.close
|
5008
|
+
canvas.resample_nearest_neighbor!(96, 96)
|
5009
|
+
data = canvas.to_rgba_stream
|
5010
|
+
width = canvas.width
|
5011
|
+
height = canvas.height
|
5012
|
+
puts "Image width: #{width}"
|
5013
|
+
puts "Image height: #{height}"
|
5014
|
+
|
5015
|
+
puts 'Parsing colors...'; $stdout.flush
|
5016
|
+
|
5017
|
+
color_maps = height.times.map do |y|
|
5018
|
+
width.times.map do |x|
|
5019
|
+
r = data[(y*width + x)*4].ord
|
5020
|
+
g = data[(y*width + x)*4 + 1].ord
|
5021
|
+
b = data[(y*width + x)*4 + 2].ord
|
5022
|
+
a = data[(y*width + x)*4 + 3].ord
|
5023
|
+
{x: x, y: y, color: {r: r, g: g, b: b, a: a}}
|
5024
|
+
end
|
5025
|
+
end.flatten
|
5026
|
+
puts "#{color_maps.size} pixels to render..."; $stdout.flush
|
5027
|
+
|
5028
|
+
puts 'Parsing shapes...'; $stdout.flush
|
5029
|
+
|
5030
|
+
shape_maps = []
|
5031
|
+
original_color_maps = color_maps.dup
|
5032
|
+
indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
|
5033
|
+
color_maps.each do |color_map|
|
5034
|
+
index = indexed_original_color_maps[color_map]
|
5035
|
+
@rectangle_start_x ||= color_map[:x]
|
5036
|
+
@rectangle_width ||= 1
|
5037
|
+
if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
|
5038
|
+
@rectangle_width += 1
|
5039
|
+
else
|
5040
|
+
if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
|
5041
|
+
shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
|
5042
|
+
else
|
5043
|
+
shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
|
5044
|
+
end
|
5045
|
+
@rectangle_width = 1
|
5046
|
+
@rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
|
5047
|
+
end
|
5048
|
+
end
|
5049
|
+
puts "#{shape_maps.size} shapes to render..."; $stdout.flush
|
5050
|
+
|
5051
|
+
puts 'Rendering image...'; $stdout.flush
|
5052
|
+
|
5053
|
+
window('Basic Image', 96, 96) {
|
5054
|
+
area {
|
5055
|
+
on_draw do |area_draw_params|
|
5056
|
+
shape_maps.each do |shape_map|
|
5057
|
+
path {
|
5058
|
+
rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
|
5059
|
+
|
5060
|
+
fill shape_map[:color]
|
5061
|
+
}
|
5062
|
+
end
|
5063
|
+
end
|
5064
|
+
}
|
5065
|
+
}.show
|
5066
|
+
```
|
5067
|
+
|
4724
5068
|
### Histogram
|
4725
5069
|
|
4726
5070
|
[examples/histogram.rb](examples/histogram.rb)
|
@@ -6290,6 +6634,22 @@ Mac
|
|
6290
6634
|
|
6291
6635
|

|
6292
6636
|
|
6637
|
+
Windows
|
6638
|
+
|
6639
|
+

|
6640
|
+
|
6641
|
+

|
6642
|
+
|
6643
|
+

|
6644
|
+
|
6645
|
+
Linux
|
6646
|
+
|
6647
|
+

|
6648
|
+
|
6649
|
+

|
6650
|
+
|
6651
|
+

|
6652
|
+
|
6293
6653
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6294
6654
|
|
6295
6655
|
```ruby
|
@@ -6530,7 +6890,19 @@ class Tetris
|
|
6530
6890
|
on_key_down do |key_event|
|
6531
6891
|
case key_event
|
6532
6892
|
in ext_key: :down
|
6533
|
-
|
6893
|
+
if OS.windows?
|
6894
|
+
# rate limit downs in Windows as they go too fast when key is held
|
6895
|
+
@queued_downs ||= 0
|
6896
|
+
if @queued_downs < 2
|
6897
|
+
@queued_downs += 1
|
6898
|
+
Glimmer::LibUI.timer(0.01, repeat: false) do
|
6899
|
+
@game.down! if @queued_downs < 2
|
6900
|
+
@queued_downs -= 1
|
6901
|
+
end
|
6902
|
+
end
|
6903
|
+
else
|
6904
|
+
@game.down!
|
6905
|
+
end
|
6534
6906
|
in key: ' '
|
6535
6907
|
@game.down!(instant: true)
|
6536
6908
|
in ext_key: :up
|
@@ -6614,8 +6986,11 @@ class Tetris
|
|
6614
6986
|
end
|
6615
6987
|
|
6616
6988
|
def start_moving_tetrominos_down
|
6617
|
-
|
6618
|
-
@
|
6989
|
+
unless @tetrominos_start_moving_down
|
6990
|
+
@tetrominos_start_moving_down = true
|
6991
|
+
Glimmer::LibUI.timer(@game.delay) do
|
6992
|
+
@game.down! if !@game.game_over? && !@game.paused?
|
6993
|
+
end
|
6619
6994
|
end
|
6620
6995
|
end
|
6621
6996
|
|
@@ -6628,6 +7003,8 @@ class Tetris
|
|
6628
7003
|
|
6629
7004
|
def show_high_scores
|
6630
7005
|
Glimmer::LibUI.queue_main do
|
7006
|
+
game_paused = !!@game.paused
|
7007
|
+
@game.paused = true
|
6631
7008
|
if @game.high_scores.empty?
|
6632
7009
|
high_scores_string = "No games have been scored yet."
|
6633
7010
|
else
|
@@ -6636,6 +7013,7 @@ class Tetris
|
|
6636
7013
|
end.join("\n")
|
6637
7014
|
end
|
6638
7015
|
msg_box('High Scores', high_scores_string)
|
7016
|
+
@game.paused = game_paused
|
6639
7017
|
end
|
6640
7018
|
end
|
6641
7019
|
|
@@ -6675,6 +7053,26 @@ Mac
|
|
6675
7053
|
|
6676
7054
|

|
6677
7055
|
|
7056
|
+
Windows
|
7057
|
+
|
7058
|
+

|
7059
|
+
|
7060
|
+

|
7061
|
+
|
7062
|
+

|
7063
|
+
|
7064
|
+

|
7065
|
+
|
7066
|
+
Linux
|
7067
|
+
|
7068
|
+

|
7069
|
+
|
7070
|
+

|
7071
|
+
|
7072
|
+

|
7073
|
+
|
7074
|
+

|
7075
|
+
|
6678
7076
|
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
6679
7077
|
|
6680
7078
|
```ruby
|
@@ -6765,6 +7163,137 @@ end
|
|
6765
7163
|
TicTacToe.new.launch
|
6766
7164
|
```
|
6767
7165
|
|
7166
|
+
### Snake
|
7167
|
+
|
7168
|
+
Snake provides an example of building a desktop application [test-first](/spec/examples/snake/model/game_spec.rb) following the MVP ([Model](/examples/snake/model/game.rb) / [View](/examples/snake.rb) / [Presenter](/examples/snake/presenter/grid.rb)) architectural pattern.
|
7169
|
+
|
7170
|
+
[examples/snake.rb](examples/snake.rb)
|
7171
|
+
|
7172
|
+
Run with this command from the root of the project if you cloned the project:
|
7173
|
+
|
7174
|
+
```
|
7175
|
+
ruby -r './lib/glimmer-dsl-libui' examples/snake.rb
|
7176
|
+
```
|
7177
|
+
|
7178
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
7179
|
+
|
7180
|
+
```
|
7181
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/snake'"
|
7182
|
+
```
|
7183
|
+
|
7184
|
+
Mac
|
7185
|
+
|
7186
|
+

|
7187
|
+
|
7188
|
+

|
7189
|
+
|
7190
|
+
Windows
|
7191
|
+
|
7192
|
+

|
7193
|
+
|
7194
|
+

|
7195
|
+
|
7196
|
+
Linux
|
7197
|
+
|
7198
|
+

|
7199
|
+
|
7200
|
+

|
7201
|
+
|
7202
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
7203
|
+
|
7204
|
+
```ruby
|
7205
|
+
require 'glimmer-dsl-libui'
|
7206
|
+
require 'glimmer/data_binding/observer'
|
7207
|
+
|
7208
|
+
require_relative 'snake/presenter/grid'
|
7209
|
+
|
7210
|
+
class Snake
|
7211
|
+
CELL_SIZE = 15
|
7212
|
+
SNAKE_MOVE_DELAY = 0.1
|
7213
|
+
include Glimmer
|
7214
|
+
|
7215
|
+
def initialize
|
7216
|
+
@game = Model::Game.new
|
7217
|
+
@grid = Presenter::Grid.new(@game)
|
7218
|
+
@game.start
|
7219
|
+
create_gui
|
7220
|
+
register_observers
|
7221
|
+
end
|
7222
|
+
|
7223
|
+
def launch
|
7224
|
+
@main_window.show
|
7225
|
+
end
|
7226
|
+
|
7227
|
+
def register_observers
|
7228
|
+
@game.height.times do |row|
|
7229
|
+
@game.width.times do |column|
|
7230
|
+
Glimmer::DataBinding::Observer.proc do |new_color|
|
7231
|
+
@cell_grid[row][column].fill = new_color
|
7232
|
+
end.observe(@grid.cells[row][column], :color)
|
7233
|
+
end
|
7234
|
+
end
|
7235
|
+
|
7236
|
+
Glimmer::DataBinding::Observer.proc do |game_over|
|
7237
|
+
Glimmer::LibUI.queue_main do
|
7238
|
+
if game_over
|
7239
|
+
msg_box('Game Over!', "Score: #{@game.score}")
|
7240
|
+
@game.start
|
7241
|
+
end
|
7242
|
+
end
|
7243
|
+
end.observe(@game, :over)
|
7244
|
+
|
7245
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
7246
|
+
unless @game.over?
|
7247
|
+
@game.snake.move
|
7248
|
+
@main_window.title = "Glimmer Snake (Score: #{@game.score})"
|
7249
|
+
end
|
7250
|
+
end
|
7251
|
+
end
|
7252
|
+
|
7253
|
+
def create_gui
|
7254
|
+
@cell_grid = []
|
7255
|
+
@main_window = window('Glimmer Snake', @game.width * CELL_SIZE, @game.height * CELL_SIZE) {
|
7256
|
+
resizable false
|
7257
|
+
|
7258
|
+
vertical_box {
|
7259
|
+
padded false
|
7260
|
+
|
7261
|
+
@game.height.times do |row|
|
7262
|
+
@cell_grid << []
|
7263
|
+
horizontal_box {
|
7264
|
+
padded false
|
7265
|
+
|
7266
|
+
@game.width.times do |column|
|
7267
|
+
area {
|
7268
|
+
@cell_grid.last << path {
|
7269
|
+
square(0, 0, CELL_SIZE)
|
7270
|
+
|
7271
|
+
fill Presenter::Cell::COLOR_CLEAR
|
7272
|
+
}
|
7273
|
+
|
7274
|
+
on_key_up do |area_key_event|
|
7275
|
+
orientation_and_key = [@game.snake.head.orientation, area_key_event[:ext_key]]
|
7276
|
+
case orientation_and_key
|
7277
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
7278
|
+
@game.snake.turn_right
|
7279
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
7280
|
+
@game.snake.turn_left
|
7281
|
+
else
|
7282
|
+
# No Op
|
7283
|
+
end
|
7284
|
+
end
|
7285
|
+
}
|
7286
|
+
end
|
7287
|
+
}
|
7288
|
+
end
|
7289
|
+
}
|
7290
|
+
}
|
7291
|
+
end
|
7292
|
+
end
|
7293
|
+
|
7294
|
+
Snake.new.launch
|
7295
|
+
```
|
7296
|
+
|
6768
7297
|
## Applications
|
6769
7298
|
|
6770
7299
|
Here are some applications built with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|