glimmer-dsl-libui 0.2.22 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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.22
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.1
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)
@@ -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
  }
@@ -219,7 +219,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
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
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): Ruby-GNOME 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)
223
223
  - [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
224
224
  - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS
225
225
 
@@ -238,6 +238,14 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
238
238
  - [Extra Operations](#extra-operations)
239
239
  - [Table API](#table-api)
240
240
  - [Area API](#area-api)
241
+ - [Area Path Shapes](#area-path-shapes)
242
+ - [Area Text](#area-text)
243
+ - [Area Image](#area-image)
244
+ - [Colors](#colors)
245
+ - [Area Draw Params](#area-draw-params)
246
+ - [Area Listeners](#area-listeners)
247
+ - [Area Methods/Attributes](#area-methods-attributes)
248
+ - [Area Transform Matrix](#area-transform-matrix)
241
249
  - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
242
250
  - [Custom Keywords](#custom-keywords)
243
251
  - [API Gotchas](#api-gotchas)
@@ -270,6 +278,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
270
278
  - [Basic Area](#basic-area)
271
279
  - [Dynamic Area](#dynamic-area)
272
280
  - [Area Gallery](#area-gallery)
281
+ - [Basic Image](#basic-image)
273
282
  - [Histogram](#histogram)
274
283
  - [Basic Transform](#basic-transform)
275
284
  - [Login](#login)
@@ -373,7 +382,7 @@ gem install glimmer-dsl-libui
373
382
  Or install via Bundler `Gemfile`:
374
383
 
375
384
  ```ruby
376
- gem 'glimmer-dsl-libui', '~> 0.2.22'
385
+ gem 'glimmer-dsl-libui', '~> 0.3.1'
377
386
  ```
378
387
 
379
388
  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.
@@ -444,8 +453,6 @@ w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0
444
453
 
445
454
  ### Supported Keywords
446
455
 
447
- 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)
448
-
449
456
  Keyword(Args) | Properties | Listeners
450
457
  ------------- | ---------- | ---------
451
458
  `about_menu_item` | None | `on_clicked`
@@ -473,7 +480,7 @@ Keyword(Args) | Properties | Listeners
473
480
  `group(text as String)` | `margined` (Boolean), `title` (`String`) | None
474
481
  `horizontal_box` | `padded` (Boolean) | None
475
482
  `horizontal_separator` | None | None
476
- `image(width as Numeric, height as Numeric)` | None | None
483
+ `image(file as String = nil, width as Numeric = nil, height as Numeric = nil)` | None | None
477
484
  `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
478
485
  `image_column(name as String)` | None | None
479
486
  `image_text_column(name as String)` | None | None
@@ -552,8 +559,8 @@ There are additional useful `Glimmer::LibUI` operations that are not found in `L
552
559
  - `Glimmer::LibUI::integer_to_boolean(int, allow_nil: true)`
553
560
  - `Glimmer::LibUI::boolean_to_integer(int, allow_nil: true)`
554
561
  - `Glimmer::LibUI::degrees_to_radians(degrees)`
555
- - `Glimmer::LibUI::interpret_color(value)`: interprets a color in any form like `String`, `Symbol`, or hex into an rgb `Hash`
556
- - `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash`
562
+ - `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)
563
+ - `Glimmer::LibUI::hex_to_rgb(value)`: converts a hex color to an rgb `Hash` (including `0x1f3b5d`, `'0x1f3b5d'`, `'#1f3b5d'`, and 3-char hex-shorthand variations)
557
564
  - `Glimmer::LibUI::enum_names`: provides all possible enum names to use with `Glimmer::LibUI::enum_symbols(enum_name)`
558
565
  - `Glimmer::LibUI::enum_symbols(enum_name)`: returns all possible values for an enum. `enum_name` can be:
559
566
  - `:draw_brush_type`: `[:solid, :linear_gradient, :radial_gradient, :image]`
@@ -717,6 +724,8 @@ The `area` control is a canvas-like control for drawing paths that can be used i
717
724
  - 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).
718
725
  - 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.
719
726
 
727
+ Note that 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.
728
+
720
729
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
721
730
 
722
731
  ```ruby
@@ -739,8 +748,18 @@ window('Basic Area', 400, 400) {
739
748
  }.show
740
749
  ```
741
750
 
751
+ Mac
752
+
742
753
  ![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
743
754
 
755
+ Windows
756
+
757
+ ![glimmer-dsl-libui-windows-basic-area.png](images/glimmer-dsl-libui-windows-basic-area.png)
758
+
759
+ Linux
760
+
761
+ ![glimmer-dsl-libui-linux-basic-area.png](images/glimmer-dsl-libui-linux-basic-area.png)
762
+
744
763
  Here is the same example using a semi-declarative `area` with `on_draw` listener that receives a `area_draw_params` argument and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
745
764
 
746
765
  ```ruby
@@ -767,6 +786,8 @@ window('Basic Area', 400, 400) {
767
786
 
768
787
  Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
769
788
 
789
+ #### Area Path Shapes
790
+
770
791
  `path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
771
792
 
772
793
  Available nested `path` shapes:
@@ -782,6 +803,270 @@ Available nested `path` shapes:
782
803
 
783
804
  Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
784
805
 
806
+ Mac
807
+
808
+ ![glimmer-dsl-libui-mac-area-gallery.png](images/glimmer-dsl-libui-mac-area-gallery.png)
809
+
810
+ Windows
811
+
812
+ ![glimmer-dsl-libui-windows-area-gallery.png](images/glimmer-dsl-libui-windows-area-gallery.png)
813
+
814
+ Linux
815
+
816
+ ![glimmer-dsl-libui-linux-area-gallery.png](images/glimmer-dsl-libui-linux-area-gallery.png)
817
+
818
+ #### Area Text
819
+
820
+ To draw `text` in an `area`, you simply nest a `text(x, y, width)` control directly under `area` or inside a `on_draw` listener, and then nest attributed `string {[attributes]; string_value}` controls underneath it returning an actual `String` (think of them as the `<span>` or `<p>` element in html, which contains a string of text). Alternatively, you can nest attributed `string(string_value) {[attributes]}` if `string_value` is a short single-line string. An attributed `string` value can be changed dynamically via its `string` property.
821
+
822
+ `text` has the following properties:
823
+ - `default_font`:
824
+ - `align`: `:left` (default), `:center`, or `:right` (`align` currently seems not to work on the Mac)
825
+ - `x`: x coordinate in relation to parent `area` top-left corner
826
+ - `y`: y coordinate in relation to parent `area` top-left corner
827
+ - `width` (default: area width - x*2): width of text to display
828
+
829
+ `string` has the following properties:
830
+ - `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
831
+ - `color`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
832
+ - `background`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
833
+ - `underline`: one of `:none`, `:single`, `:double`, `:suggestion`, `:color_custom`, `:color_spelling`, `:color_grammar`, `:color_auxiliary`
834
+ - `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
835
+ - `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.
836
+ - `string`: string value (`String`)
837
+
838
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
839
+
840
+ ```ruby
841
+ window('area text drawing') {
842
+ area {
843
+ text {
844
+ default_font family: 'Helvetica', size: 12, weight: :normal, italic: :normal, stretch: :normal
845
+
846
+ string {
847
+ font family: 'Georgia', size: 13, weight: :medium, italic: :normal, stretch: :normal
848
+ color r: 230, g: 100, b: 50, a: 0.5
849
+ background r: 230, g: 200, b: 250, a: 0.8
850
+ underline :single
851
+ underline_color :spelling
852
+ open_type_features {
853
+ open_type_tag 'l', 'i', 'g', 'a', 0
854
+ open_type_tag 'l', 'i', 'g', 'a', 1
855
+ }
856
+
857
+ "This is a demonstration\n" \
858
+ "of a very long\n" \
859
+ "attributed string\n" \
860
+ "spanning multiple lines\n\n"
861
+ }
862
+
863
+ string('This is a short unattributed string')
864
+ }
865
+ }
866
+ }.show
867
+ ```
868
+
869
+ You may checkout [examples/basic_draw_text.rb](#basic-draw-text) and [examples/custom_draw_text.rb](#custom-draw-text) for examples of using `text` inside `area`.
870
+
871
+ Mac
872
+
873
+ ![glimmer-dsl-libui-mac-custom-draw-text-changed.png](images/glimmer-dsl-libui-mac-custom-draw-text-changed.png)
874
+
875
+ Windows
876
+
877
+ ![glimmer-dsl-libui-windows-custom-draw-text-changed.png](images/glimmer-dsl-libui-windows-custom-draw-text-changed.png)
878
+
879
+ Linux
880
+
881
+ ![glimmer-dsl-libui-linux-custom-draw-text-changed.png](images/glimmer-dsl-libui-linux-custom-draw-text-changed.png)
882
+
883
+ #### Area Image
884
+
885
+ **(ALPHA FEATURE)**
886
+
887
+ [libui](https://github.com/andlabs/libui) does not support `image` rendering outside of `table` yet.
888
+ 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).
889
+
890
+ Given that it is very new and not a [libui](https://github.com/andlabs/libui)-native control, please keep these notes in mind:
891
+ - It only supports the `.png` file format.
892
+ - [libui](https://github.com/andlabs/libui) pixel-by-pixel rendering performance is slow.
893
+ - Including an `image` inside an `area` `on_draw` listener improves performance due to not retaining pixel/line data in memory.
894
+ - Supplying `width` and `height` (2nd and 3rd arguments) greatly improves performance when shrinking image.
895
+
896
+ Currently, it is recommended to use `image` with very small `width` and `height` values only.
897
+
898
+ Setting a `transform` `matrix` is supported under `image` just like it is under `path` and `text` inside `area`.
899
+
900
+ Example of using `image` declaratively (you may copy/paste in [`girb`](#girb-glimmer-irb)):
901
+
902
+ Mac
903
+
904
+ ![glimmer-dsl-libui-mac-basic-image.png](images/glimmer-dsl-libui-mac-basic-image.png)
905
+
906
+ Windows
907
+
908
+ ![glimmer-dsl-libui-windows-basic-image.png](images/glimmer-dsl-libui-windows-basic-image.png)
909
+
910
+ ```ruby
911
+ require 'glimmer-dsl-libui'
912
+
913
+ include Glimmer
914
+
915
+ window('Basic Image', 96, 96) {
916
+ area {
917
+ image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
918
+ }
919
+ }.show
920
+ ```
921
+
922
+ Example of better performance via `on_draw` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
923
+
924
+ ```ruby
925
+ require 'glimmer-dsl-libui'
926
+
927
+ include Glimmer
928
+
929
+ window('Basic Image', 96, 96) {
930
+ area {
931
+ on_draw do |area_draw_params|
932
+ image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
933
+ end
934
+ }
935
+ }.show
936
+ ```
937
+
938
+ Example of using `image` declaratively with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
939
+
940
+ ```ruby
941
+ require 'glimmer-dsl-libui'
942
+
943
+ include Glimmer
944
+
945
+ window('Basic Image', 96, 96) {
946
+ area {
947
+ image {
948
+ file File.expand_path('icons/glimmer.png', __dir__)
949
+ width 96
950
+ height 96
951
+ }
952
+ }
953
+ }.show
954
+ ```
955
+
956
+ Example of better performance via `on_draw` with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
957
+
958
+ ```ruby
959
+ require 'glimmer-dsl-libui'
960
+
961
+ include Glimmer
962
+
963
+ window('Basic Image', 96, 96) {
964
+ area {
965
+ on_draw do |area_draw_params|
966
+ image {
967
+ file File.expand_path('icons/glimmer.png', __dir__)
968
+ width 96
969
+ height 96
970
+ }
971
+ end
972
+ }
973
+ }.show
974
+ ```
975
+
976
+ 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:
977
+
978
+ ```ruby
979
+ # This is the manual way of rendering an image unto an area control.
980
+ # It could come in handy in special situations.
981
+ # Otherwise, it is recommended to simply utilize the `image` control that
982
+ # can be nested under area or area on_draw listener to automate all this work.
983
+
984
+ require 'glimmer-dsl-libui'
985
+ require 'chunky_png'
986
+
987
+ include Glimmer
988
+
989
+ puts 'Parsing image...'; $stdout.flush
990
+
991
+ f = File.open(File.expand_path('icons/glimmer.png', __dir__))
992
+ canvas = ChunkyPNG::Canvas.from_io(f)
993
+ f.close
994
+ canvas.resample_nearest_neighbor!(96, 96)
995
+ data = canvas.to_rgba_stream
996
+ width = canvas.width
997
+ height = canvas.height
998
+ puts "Image width: #{width}"
999
+ puts "Image height: #{height}"
1000
+
1001
+ puts 'Parsing colors...'; $stdout.flush
1002
+
1003
+ color_maps = height.times.map do |y|
1004
+ width.times.map do |x|
1005
+ r = data[(y*width + x)*4].ord
1006
+ g = data[(y*width + x)*4 + 1].ord
1007
+ b = data[(y*width + x)*4 + 2].ord
1008
+ a = data[(y*width + x)*4 + 3].ord
1009
+ {x: x, y: y, color: {r: r, g: g, b: b, a: a}}
1010
+ end
1011
+ end.flatten
1012
+ puts "#{color_maps.size} pixels to render..."; $stdout.flush
1013
+
1014
+ puts 'Parsing shapes...'; $stdout.flush
1015
+
1016
+ shape_maps = []
1017
+ original_color_maps = color_maps.dup
1018
+ indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
1019
+ color_maps.each do |color_map|
1020
+ index = indexed_original_color_maps[color_map]
1021
+ @rectangle_start_x ||= color_map[:x]
1022
+ @rectangle_width ||= 1
1023
+ if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
1024
+ @rectangle_width += 1
1025
+ else
1026
+ if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
1027
+ shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
1028
+ else
1029
+ shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
1030
+ end
1031
+ @rectangle_width = 1
1032
+ @rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
1033
+ end
1034
+ end
1035
+ puts "#{shape_maps.size} shapes to render..."; $stdout.flush
1036
+
1037
+ puts 'Rendering image...'; $stdout.flush
1038
+
1039
+ window('Basic Image', 96, 96) {
1040
+ area {
1041
+ on_draw do |area_draw_params|
1042
+ shape_maps.each do |shape_map|
1043
+ path {
1044
+ rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
1045
+
1046
+ fill shape_map[:color]
1047
+ }
1048
+ end
1049
+ end
1050
+ }
1051
+ }.show
1052
+ ```
1053
+
1054
+ One final note is that in Linux, table images grow and shrink with the image size unlike on the Mac where table row heights are constant regardless of image sizes. As such, you may be able to repurpose a table with a single image column and a single row as an image control with more native libui rendering if you are only targeting Linux with your app.
1055
+
1056
+ Check out [examples/basic_image.rb](#basic-image) (all versions) for examples of using `image` Glimmer custom control.
1057
+
1058
+ #### Colors
1059
+
1060
+ `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)
1061
+
1062
+ Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
1063
+
1064
+ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
1065
+
1066
+ Check [Histogram](#histogram) example for use of hex colors.
1067
+
1068
+ #### Area Draw Params
1069
+
785
1070
  The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
786
1071
  - `:context`: the drawing context object
787
1072
  - `:area_width`: area width
@@ -793,7 +1078,9 @@ The `area_draw_params` argument for `on_draw` block is a hash consisting of the
793
1078
 
794
1079
  In general, it is recommended to use declarative stable paths whenever feasible since they require less code and simpler maintenance. But, in more advanced cases, semi-declarative dynamic paths could be used instead, especially if there are thousands of dynamic paths that need maximum performance and low memory footprint.
795
1080
 
796
- `area` supported mouse listeners are:
1081
+ #### Area Listeners
1082
+
1083
+ `area` supported listeners are:
797
1084
  - `on_key_event {|area_key_event| ...}`: general catch-all key event (recommend using fine-grained key events below instead)
798
1085
  - `on_key_down {|area_key_event| ...}`
799
1086
  - `on_key_up {|area_key_event| ...}`
@@ -821,14 +1108,14 @@ The `area_mouse_event` `Hash` argument for mouse events that receive it (e.g. `o
821
1108
 
822
1109
  The `area_key_event` `Hash` argument for keyboard events that receive it (e.g. `on_key_up`, `on_key_down`) consist of the following hash keys:
823
1110
  - `:key`: key character (`String`)
824
- - `:key_value`: key value (`Integer`). Useful in rare cases for numeric processing of keys instead of dealing with as `:key` character `String`
1111
+ - `:key_value` (alias: `:key_code`): key code value (`Integer`). Useful in rare cases for numeric processing of keys instead of dealing with as `:key` character `String`
825
1112
  - `:ext_key`: non-character extra key (`Symbol`) from `Glimmer::LibUI.enum_symbols(:ext_key)` such as `:left`, `:right`, `:escape`, `:insert`
826
1113
  - `:ext_key_value`: non-character extra key value (`Integer`). Useful in rare cases for numeric processing of extra keys instead of dealing with as `:ext_key` `Symbol`
827
1114
  - `:modifier`: modifier key pressed alone (e.g. `:shift` or `:control`)
828
1115
  - `:modifiers`: modifier keys pressed simultaneously with `:key`, `:ext_key`, or `:modifier`
829
1116
  - `:up`: indicates if key has been released or not (Boolean)
830
1117
 
831
- Note that 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.
1118
+ #### Area Methods/Attributes
832
1119
 
833
1120
  To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
834
1121
 
@@ -838,6 +1125,8 @@ To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#re
838
1125
  - `resume_auto_redraw`: resume auto redraw upon changes to nested stable `path` or shapes
839
1126
  - `auto_redraw_enabled`/`auto_redraw_enabled?`/`auto_redraw_enabled=`: an attribute to disable/enable auto redraw on an `area` upon changes to nested stable `path` or shapes
840
1127
 
1128
+ #### Area Transform Matrix
1129
+
841
1130
  A transform `matrix` can be set on a path by building a `matrix(m11 = nil, m12 = nil, m21 = nil, m22 = nil, m31 = nil, m32 = nil) {operations}` proxy object and then setting via `transform` property, or alternatively by building and setting the matrix in one call to `transform(m11 = nil, m12 = nil, m21 = nil, m22 = nil, m31 = nil, m32 = nil) {operations}` passing it the matrix arguments and/or content operations.
842
1131
 
843
1132
  When instantiating a `matrix` object, it always starts with identity matrix.
@@ -901,64 +1190,9 @@ transform m1
901
1190
  # and then reuse m1 elsewhere too
902
1191
  ```
903
1192
 
904
- 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.
905
-
906
- `fill` and `stroke` accept [X11](https://en.wikipedia.org/wiki/X11_color_names) color `Symbol`s/`String`s like `:skyblue` and `'sandybrown'` or 6-number hex or 3-number hex-shorthand (as `Integer` or `String` with or without `0x` prefix)
907
-
908
- Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
909
-
910
- Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
911
-
912
- Check [Histogram](#histogram) example for use of hex colors.
913
-
914
- To draw `text` in an `area`, you simply nest a `text(x, y, width)` control directly under `area` or inside a `on_draw` listener, and then nest attributed `string {[attributes]; string_value}` controls underneath it returning an actual `String` (think of them as the `<span>` or `<p>` element in html, which contains a string of text). Alternatively, you can nest attributed `string(string_value) {[attributes]}` if `string_value` is a short single-line string. An attributed `string` value can be changed dynamically via its `string` property.
915
-
916
- `text` has the following properties:
917
- - `default_font`:
918
- - `align`: `:left` (default), `:center`, or `:right` (`align` currently seems not to work on the Mac)
919
- - `x`: x coordinate in relation to parent `area` top-left corner
920
- - `y`: y coordinate in relation to parent `area` top-left corner
921
- - `width` (default: area width - x*2): width of text to display
922
-
923
- `string` has the following properties:
924
- - `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
925
- - `color`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
926
- - `background`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
927
- - `underline`: one of `:none`, `:single`, `:double`, `:suggestion`, `:color_custom`, `:color_spelling`, `:color_grammar`, `:color_auxiliary`
928
- - `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
929
- - `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.
930
- - `string`: string value (`String`)
931
-
932
- Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
1193
+ You can set a `matrix`/`transform` on `area` directly to conveniently apply to all nested `path`s too.
933
1194
 
934
- ```ruby
935
- window('area text drawing') {
936
- area {
937
- text {
938
- default_font family: 'Helvetica', size: 12, weight: :normal, italic: :normal, stretch: :normal
939
-
940
- string {
941
- font family: 'Georgia', size: 13, weight: :medium, italic: :normal, stretch: :normal
942
- color r: 230, g: 100, b: 50, a: 0.5
943
- background r: 230, g: 200, b: 250, a: 0.8
944
- underline :single
945
- underline_color :spelling
946
- open_type_features {
947
- open_type_tag 'l', 'i', 'g', 'a', 0
948
- open_type_tag 'l', 'i', 'g', 'a', 1
949
- }
950
-
951
- "This is a demonstration\n" \
952
- "of a very long\n" \
953
- "attributed string\n" \
954
- "spanning multiple lines\n\n"
955
- }
956
-
957
- string('This is a short unattributed string')
958
- }
959
- }
960
- }.show
961
- ```
1195
+ 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.
962
1196
 
963
1197
  ### Smart Defaults and Conventions
964
1198
 
@@ -982,7 +1216,7 @@ window('area text drawing') {
982
1216
  - When destroying a control nested under a `form`, it is automatically deleted from the form's children
983
1217
  - When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
984
1218
  - 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`
985
- - Smart defaults for `grid` child attributes are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`:fill`), `vexpand` (`false`), and `valign` (`:fill`)
1219
+ - Smart defaults for `grid` child properties are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`:fill`), `vexpand` (`false`), and `valign` (`:fill`)
986
1220
  - 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`)
987
1221
  - Table model instances are automatically freed from memory after `window` is destroyed.
988
1222
  - 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.
@@ -996,7 +1230,7 @@ window('area text drawing') {
996
1230
  - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
997
1231
  - All resources are freed automatically once no longer needed or left to garbage collection.
998
1232
  - 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.
999
- - 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)
1233
+ - 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)
1000
1234
  - Color alpha value defaults to `1.0` when not specified.
1001
1235
 
1002
1236
  ### Custom Keywords
@@ -1110,7 +1344,8 @@ window('Method-Based Custom Keyword') {
1110
1344
  ### API Gotchas
1111
1345
 
1112
1346
  - 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`).
1113
- - `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).
1347
+ - `table` `checkbox_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).
1348
+ - `table` `checkbox_text_column` checkbox editing only works on Linux (not Mac or Windows) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
1114
1349
  - `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)
1115
1350
  - `text` `string` `background` does not work on Windows due to an [issue in libui](https://github.com/andlabs/libui/issues/347).
1116
1351
  - `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.
@@ -1760,11 +1995,11 @@ class TinyMidiPlayer
1760
1995
 
1761
1996
  UI.new_horizontal_box.tap do |hbox|
1762
1997
  UI.new_vertical_box.tap do |vbox|
1763
- UI.new_button('').tap do |button1|
1998
+ UI.new_button('â–¶').tap do |button1|
1764
1999
  UI.button_on_clicked(button1) { play_midi }
1765
2000
  UI.box_append(vbox, button1, 1)
1766
2001
  end
1767
- UI.new_button('').tap do |button2|
2002
+ UI.new_button('â– ').tap do |button2|
1768
2003
  UI.button_on_clicked(button2) { stop_midi }
1769
2004
  UI.box_append(vbox, button2, 1)
1770
2005
  end
@@ -1858,12 +2093,12 @@ class TinyMidiPlayer
1858
2093
  vertical_box {
1859
2094
  stretchy false
1860
2095
 
1861
- button('') {
2096
+ button('â–¶') {
1862
2097
  on_clicked do
1863
2098
  play_midi
1864
2099
  end
1865
2100
  }
1866
- button('') {
2101
+ button('â– ') {
1867
2102
  on_clicked do
1868
2103
  stop_midi
1869
2104
  end
@@ -2994,13 +3229,7 @@ window('Editable column animal sounds', 400, 200) {
2994
3229
 
2995
3230
  ### Basic Table Image
2996
3231
 
2997
- This example requires pre-installing `chunky_png` Ruby gem:
2998
-
2999
- ```
3000
- gem install chunky_png -v1.4.0
3001
- ```
3002
-
3003
- Also, note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3232
+ Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3004
3233
 
3005
3234
  [examples/basic_table_image.rb](examples/basic_table_image.rb)
3006
3235
 
@@ -3114,6 +3343,41 @@ UI.quit
3114
3343
  # NOTE:
3115
3344
  # This example displays images that can be freely downloaded from the Studio Ghibli website.
3116
3345
 
3346
+ require 'glimmer-dsl-libui'
3347
+
3348
+ include Glimmer
3349
+
3350
+ IMAGE_ROWS = []
3351
+
3352
+ 50.times do |i|
3353
+ url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
3354
+ puts "Processing Image: #{url}"; $stdout.flush # for Windows
3355
+ IMAGE_ROWS << [image(url)] # array of one column cell
3356
+ rescue StandardError => e
3357
+ warn url, e.message
3358
+ end
3359
+
3360
+ window('The Red Turtle', 310, 350, false) {
3361
+ horizontal_box {
3362
+ table {
3363
+ image_column('www.ghibli.jp/works/red-turtle')
3364
+
3365
+ cell_rows IMAGE_ROWS
3366
+ }
3367
+ }
3368
+
3369
+ on_closing do
3370
+ puts 'Bye Bye'
3371
+ end
3372
+ }.show
3373
+ ```
3374
+
3375
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (manual construction of `image` from `image_part`):
3376
+
3377
+ ```ruby
3378
+ # NOTE:
3379
+ # This example displays images that can be freely downloaded from the Studio Ghibli website.
3380
+
3117
3381
  require 'glimmer-dsl-libui'
3118
3382
  require 'chunky_png'
3119
3383
  require 'open-uri'
@@ -3156,13 +3420,7 @@ window('The Red Turtle', 310, 350, false) {
3156
3420
 
3157
3421
  ### Basic Table Image Text
3158
3422
 
3159
- This example has a prerequisite of installing `chunky_png` Ruby gem:
3160
-
3161
- ```
3162
- gem install chunky_png -v1.4.0
3163
- ```
3164
-
3165
- Also, note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3423
+ Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3166
3424
 
3167
3425
  [examples/basic_table_image_text.rb](examples/basic_table_image_text.rb)
3168
3426
 
@@ -3196,6 +3454,42 @@ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
3196
3454
  # NOTE:
3197
3455
  # This example displays images that can be freely downloaded from the Studio Ghibli website.
3198
3456
 
3457
+ require 'glimmer-dsl-libui'
3458
+
3459
+ include Glimmer
3460
+
3461
+ IMAGE_ROWS = []
3462
+
3463
+ 5.times do |i|
3464
+ url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
3465
+ puts "Processing Image: #{url}"; $stdout.flush # for Windows
3466
+ text = url.sub('https://www.ghibli.jp/gallery/thumb-redturtle', '').sub('.png', '')
3467
+ img = image(url)
3468
+ IMAGE_ROWS << [[img, text], [img, text]] # cell values are dual-element arrays
3469
+ rescue StandardError => e
3470
+ warn url, e.message
3471
+ end
3472
+
3473
+ window('The Red Turtle', 670, 350) {
3474
+ horizontal_box {
3475
+ table {
3476
+ image_text_column('image/number')
3477
+ image_text_column('image/number (editable)') {
3478
+ editable true
3479
+ }
3480
+
3481
+ cell_rows IMAGE_ROWS
3482
+ }
3483
+ }
3484
+ }.show
3485
+ ```
3486
+
3487
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (manual construction of `image` from `image_part`):
3488
+
3489
+ ```ruby
3490
+ # NOTE:
3491
+ # This example displays images that can be freely downloaded from the Studio Ghibli website.
3492
+
3199
3493
  require 'glimmer-dsl-libui'
3200
3494
  require 'chunky_png'
3201
3495
  require 'open-uri'
@@ -3482,12 +3776,6 @@ window('Task Progress', 300, 200) {
3482
3776
 
3483
3777
  ### Basic Table Color
3484
3778
 
3485
- This example requires pre-installing `chunky_png` Ruby gem:
3486
-
3487
- ```
3488
- gem install chunky_png -v1.4.0
3489
- ```
3490
-
3491
3779
  [examples/basic_table_color.rb](examples/basic_table_color.rb)
3492
3780
 
3493
3781
  Run with this command from the root of the project if you cloned the project:
@@ -3516,6 +3804,40 @@ Linux
3516
3804
 
3517
3805
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3518
3806
 
3807
+ ```ruby
3808
+ # frozen_string_literal: true
3809
+
3810
+ require 'glimmer-dsl-libui'
3811
+
3812
+ include Glimmer
3813
+
3814
+ img = image(File.expand_path('../icons/glimmer.png', __dir__), 24, 24)
3815
+
3816
+ data = [
3817
+ [['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
3818
+ [['dog', :yellow] , ['woof', {r: 240, g: 32, b: 32}] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], :skyblue],
3819
+ [['chicken', :beige], ['cock-a-doodle-doo', :blue] , [false, 'mammal', :red] , [img, 'Glimmer', :beige], {r: 5, g: 120, b: 110}],
3820
+ [['horse', :purple] , ['neigh', {r: 240, g: 32, b: 32}], [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], '13a1fb'],
3821
+ [['cow', :gray] , ['moo', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :brown], 0x12ff02]
3822
+ ]
3823
+
3824
+ window('Animals', 500, 200) {
3825
+ horizontal_box {
3826
+ table {
3827
+ text_color_column('Animal')
3828
+ text_color_column('Sound')
3829
+ checkbox_text_color_column('Description')
3830
+ image_text_color_column('GUI')
3831
+ background_color_column('Mammal')
3832
+
3833
+ cell_rows data
3834
+ }
3835
+ }
3836
+ }.show
3837
+ ```
3838
+
3839
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (manual construction of [libui](https://github.com/andlabs/libui) `image` from `image_part`):
3840
+
3519
3841
  ```ruby
3520
3842
  require 'glimmer-dsl-libui'
3521
3843
  require 'chunky_png'
@@ -4129,7 +4451,7 @@ window('Area Gallery', 400, 400) {
4129
4451
  }
4130
4452
  text(161, 40, 100) { # x, y, width
4131
4453
  string('Area Gallery') {
4132
- font family: 'Arial', size: 14
4454
+ font family: 'Arial', size: (OS.mac? ? 14 : 11)
4133
4455
  color :black
4134
4456
  }
4135
4457
  }
@@ -4339,7 +4661,7 @@ window('Area Gallery', 400, 400) {
4339
4661
  width 100
4340
4662
 
4341
4663
  string {
4342
- font family: 'Arial', size: 14
4664
+ font family: 'Arial', size: (OS.mac? ? 14 : 11)
4343
4665
  color :black
4344
4666
 
4345
4667
  'Area Gallery'
@@ -4452,7 +4774,7 @@ window('Area Gallery', 400, 400) {
4452
4774
  }
4453
4775
  text(161, 40, 100) { # x, y, width
4454
4776
  string('Area Gallery') {
4455
- font family: 'Arial', size: 14
4777
+ font family: 'Arial', size: (OS.mac? ? 14 : 11)
4456
4778
  color :black
4457
4779
  }
4458
4780
  }
@@ -4664,7 +4986,7 @@ window('Area Gallery', 400, 400) {
4664
4986
  width 100
4665
4987
 
4666
4988
  string {
4667
- font family: 'Arial', size: 14
4989
+ font family: 'Arial', size: (OS.mac? ? 14 : 11)
4668
4990
  color :black
4669
4991
 
4670
4992
  'Area Gallery'
@@ -4723,6 +5045,200 @@ window('Area Gallery', 400, 400) {
4723
5045
  }.show
4724
5046
  ```
4725
5047
 
5048
+ ### Basic Image
5049
+
5050
+ [examples/basic_image.rb](examples/basic_image.rb)
5051
+
5052
+ Run with this command from the root of the project if you cloned the project:
5053
+
5054
+ ```
5055
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_image.rb
5056
+ ```
5057
+
5058
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
5059
+
5060
+ ```
5061
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_image'"
5062
+ ```
5063
+
5064
+ Mac
5065
+
5066
+ ![glimmer-dsl-libui-mac-basic-image.png](images/glimmer-dsl-libui-mac-basic-image.png)
5067
+
5068
+ Windows
5069
+
5070
+ ![glimmer-dsl-libui-windows-basic-image.png](images/glimmer-dsl-libui-windows-basic-image.png)
5071
+
5072
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
5073
+
5074
+ ```ruby
5075
+ require 'glimmer-dsl-libui'
5076
+
5077
+ include Glimmer
5078
+
5079
+ window('Basic Image', 96, 96) {
5080
+ area {
5081
+ # image is not a real LibUI control. It is built in Glimmer as a custom control that renders
5082
+ # tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
5083
+ # be used in exceptional circumstances where an image control is really needed.
5084
+ #
5085
+ # Furthermore, adding image directly under area is even slower due to taking up more memory for every
5086
+ # image pixel rendered. Check basic_image2.rb for a faster alternative using on_draw manually.
5087
+ #
5088
+ # It is recommended to pass width/height args to shrink image and achieve faster performance.
5089
+ image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
5090
+ }
5091
+ }.show
5092
+ ```
5093
+
5094
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (better performance via `on_draw`):
5095
+
5096
+ ```ruby
5097
+ # frozen_string_literal: true
5098
+
5099
+ require 'glimmer-dsl-libui'
5100
+
5101
+ include Glimmer
5102
+
5103
+ window('Basic Image', 96, 96) {
5104
+ area {
5105
+ on_draw do |area_draw_params|
5106
+ image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
5107
+ end
5108
+ }
5109
+ }.show
5110
+ ```
5111
+
5112
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (explicit properties):
5113
+
5114
+ ```ruby
5115
+ # frozen_string_literal: true
5116
+
5117
+ require 'glimmer-dsl-libui'
5118
+
5119
+ include Glimmer
5120
+
5121
+ window('Basic Image', 96, 96) {
5122
+ area {
5123
+ # image is not a real LibUI control. It is built in Glimmer as a custom control that renders
5124
+ # tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
5125
+ # be used in exceptional circumstances where an image control is really needed.
5126
+ #
5127
+ # Furthermore, adding image directly under area is even slower due to taking up more memory for every
5128
+ # image pixel rendered. Check basic_image4.rb for a faster alternative using on_draw manually.
5129
+ #
5130
+ # It is recommended to pass width/height args to shrink image and achieve faster performance.
5131
+ image {
5132
+ file File.expand_path('../icons/glimmer.png', __dir__)
5133
+ width 96
5134
+ height 96
5135
+ }
5136
+ }
5137
+ }.show
5138
+ ```
5139
+
5140
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (better performance with `on_draw` when setting explicit properties):
5141
+
5142
+ ```ruby
5143
+ # frozen_string_literal: true
5144
+
5145
+ require 'glimmer-dsl-libui'
5146
+
5147
+ include Glimmer
5148
+
5149
+ window('Basic Image', 96, 96) {
5150
+ area {
5151
+ on_draw do |area_draw_params|
5152
+ image {
5153
+ file File.expand_path('../icons/glimmer.png', __dir__)
5154
+ width 96
5155
+ height 96
5156
+ }
5157
+ end
5158
+ }
5159
+ }.show
5160
+ ```
5161
+
5162
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 5 (fully manual pixel-by-pixel rendering):
5163
+
5164
+ ```ruby
5165
+ # frozen_string_literal: true
5166
+
5167
+ # This is the manual way of rendering an image unto an area control.
5168
+ # It could come in handy in special situations.
5169
+ # Otherwise, it is recommended to simply utilize the `image` control that
5170
+ # can be nested under area or area on_draw listener to automate all this work.
5171
+
5172
+ require 'glimmer-dsl-libui'
5173
+ require 'chunky_png'
5174
+
5175
+ include Glimmer
5176
+
5177
+ puts 'Parsing image...'; $stdout.flush
5178
+
5179
+ f = File.open(File.expand_path('../icons/glimmer.png', __dir__))
5180
+ canvas = ChunkyPNG::Canvas.from_io(f)
5181
+ f.close
5182
+ canvas.resample_nearest_neighbor!(96, 96)
5183
+ data = canvas.to_rgba_stream
5184
+ width = canvas.width
5185
+ height = canvas.height
5186
+ puts "Image width: #{width}"
5187
+ puts "Image height: #{height}"
5188
+
5189
+ puts 'Parsing colors...'; $stdout.flush
5190
+
5191
+ color_maps = height.times.map do |y|
5192
+ width.times.map do |x|
5193
+ r = data[(y*width + x)*4].ord
5194
+ g = data[(y*width + x)*4 + 1].ord
5195
+ b = data[(y*width + x)*4 + 2].ord
5196
+ a = data[(y*width + x)*4 + 3].ord
5197
+ {x: x, y: y, color: {r: r, g: g, b: b, a: a}}
5198
+ end
5199
+ end.flatten
5200
+ puts "#{color_maps.size} pixels to render..."; $stdout.flush
5201
+
5202
+ puts 'Parsing shapes...'; $stdout.flush
5203
+
5204
+ shape_maps = []
5205
+ original_color_maps = color_maps.dup
5206
+ indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
5207
+ color_maps.each do |color_map|
5208
+ index = indexed_original_color_maps[color_map]
5209
+ @rectangle_start_x ||= color_map[:x]
5210
+ @rectangle_width ||= 1
5211
+ if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
5212
+ @rectangle_width += 1
5213
+ else
5214
+ if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
5215
+ shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
5216
+ else
5217
+ shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
5218
+ end
5219
+ @rectangle_width = 1
5220
+ @rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
5221
+ end
5222
+ end
5223
+ puts "#{shape_maps.size} shapes to render..."; $stdout.flush
5224
+
5225
+ puts 'Rendering image...'; $stdout.flush
5226
+
5227
+ window('Basic Image', 96, 96) {
5228
+ area {
5229
+ on_draw do |area_draw_params|
5230
+ shape_maps.each do |shape_map|
5231
+ path {
5232
+ rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
5233
+
5234
+ fill shape_map[:color]
5235
+ }
5236
+ end
5237
+ end
5238
+ }
5239
+ }.show
5240
+ ```
5241
+
4726
5242
  ### Histogram
4727
5243
 
4728
5244
  [examples/histogram.rb](examples/histogram.rb)
@@ -6292,6 +6808,22 @@ Mac
6292
6808
 
6293
6809
  ![glimmer-dsl-libui-mac-tetris-high-scores.png](images/glimmer-dsl-libui-mac-tetris-high-scores.png)
6294
6810
 
6811
+ Windows
6812
+
6813
+ ![glimmer-dsl-libui-windows-tetris.png](images/glimmer-dsl-libui-windows-tetris.png)
6814
+
6815
+ ![glimmer-dsl-libui-windows-tetris-game-over.png](images/glimmer-dsl-libui-windows-tetris-game-over.png)
6816
+
6817
+ ![glimmer-dsl-libui-windows-tetris-high-scores.png](images/glimmer-dsl-libui-windows-tetris-high-scores.png)
6818
+
6819
+ Linux
6820
+
6821
+ ![glimmer-dsl-libui-linux-tetris.png](images/glimmer-dsl-libui-linux-tetris.png)
6822
+
6823
+ ![glimmer-dsl-libui-linux-tetris-game-over.png](images/glimmer-dsl-libui-linux-tetris-game-over.png)
6824
+
6825
+ ![glimmer-dsl-libui-linux-tetris-high-scores.png](images/glimmer-dsl-libui-linux-tetris-high-scores.png)
6826
+
6295
6827
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
6296
6828
 
6297
6829
  ```ruby
@@ -6532,7 +7064,19 @@ class Tetris
6532
7064
  on_key_down do |key_event|
6533
7065
  case key_event
6534
7066
  in ext_key: :down
6535
- @game.down!
7067
+ if OS.windows?
7068
+ # rate limit downs in Windows as they go too fast when key is held
7069
+ @queued_downs ||= 0
7070
+ if @queued_downs < 2
7071
+ @queued_downs += 1
7072
+ Glimmer::LibUI.timer(0.01, repeat: false) do
7073
+ @game.down! if @queued_downs < 2
7074
+ @queued_downs -= 1
7075
+ end
7076
+ end
7077
+ else
7078
+ @game.down!
7079
+ end
6536
7080
  in key: ' '
6537
7081
  @game.down!(instant: true)
6538
7082
  in ext_key: :up
@@ -6616,8 +7160,11 @@ class Tetris
6616
7160
  end
6617
7161
 
6618
7162
  def start_moving_tetrominos_down
6619
- Glimmer::LibUI.timer(@game.delay) do
6620
- @game.down! if !@game.game_over? && !@game.paused?
7163
+ unless @tetrominos_start_moving_down
7164
+ @tetrominos_start_moving_down = true
7165
+ Glimmer::LibUI.timer(@game.delay) do
7166
+ @game.down! if !@game.game_over? && !@game.paused?
7167
+ end
6621
7168
  end
6622
7169
  end
6623
7170
 
@@ -6630,6 +7177,8 @@ class Tetris
6630
7177
 
6631
7178
  def show_high_scores
6632
7179
  Glimmer::LibUI.queue_main do
7180
+ game_paused = !!@game.paused
7181
+ @game.paused = true
6633
7182
  if @game.high_scores.empty?
6634
7183
  high_scores_string = "No games have been scored yet."
6635
7184
  else
@@ -6638,6 +7187,7 @@ class Tetris
6638
7187
  end.join("\n")
6639
7188
  end
6640
7189
  msg_box('High Scores', high_scores_string)
7190
+ @game.paused = game_paused
6641
7191
  end
6642
7192
  end
6643
7193
 
@@ -6677,6 +7227,26 @@ Mac
6677
7227
 
6678
7228
  ![glimmer-dsl-libui-mac-tic-tac-toe-draw.png](images/glimmer-dsl-libui-mac-tic-tac-toe-draw.png)
6679
7229
 
7230
+ Windows
7231
+
7232
+ ![glimmer-dsl-libui-windows-tic-tac-toe.png](images/glimmer-dsl-libui-windows-tic-tac-toe.png)
7233
+
7234
+ ![glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-o-wins.png)
7235
+
7236
+ ![glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-windows-tic-tac-toe-player-x-wins.png)
7237
+
7238
+ ![glimmer-dsl-libui-windows-tic-tac-toe-draw.png](images/glimmer-dsl-libui-windows-tic-tac-toe-draw.png)
7239
+
7240
+ Linux
7241
+
7242
+ ![glimmer-dsl-libui-linux-tic-tac-toe.png](images/glimmer-dsl-libui-linux-tic-tac-toe.png)
7243
+
7244
+ ![glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-o-wins.png)
7245
+
7246
+ ![glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png](images/glimmer-dsl-libui-linux-tic-tac-toe-player-x-wins.png)
7247
+
7248
+ ![glimmer-dsl-libui-linux-tic-tac-toe-draw.png](images/glimmer-dsl-libui-linux-tic-tac-toe-draw.png)
7249
+
6680
7250
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
6681
7251
 
6682
7252
  ```ruby
@@ -6791,6 +7361,18 @@ Mac
6791
7361
 
6792
7362
  ![glimmer-dsl-libui-mac-snake-game-over.png](images/glimmer-dsl-libui-mac-snake-game-over.png)
6793
7363
 
7364
+ Windows
7365
+
7366
+ ![glimmer-dsl-libui-windows-snake.png](images/glimmer-dsl-libui-windows-snake.png)
7367
+
7368
+ ![glimmer-dsl-libui-windows-snake-game-over.png](images/glimmer-dsl-libui-windows-snake-game-over.png)
7369
+
7370
+ Linux
7371
+
7372
+ ![glimmer-dsl-libui-linux-snake.png](images/glimmer-dsl-libui-linux-snake.png)
7373
+
7374
+ ![glimmer-dsl-libui-linux-snake-game-over.png](images/glimmer-dsl-libui-linux-snake-game-over.png)
7375
+
6794
7376
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
6795
7377
 
6796
7378
  ```ruby