glimmer-dsl-libui 0.2.23 → 0.3.2

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.23
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.2
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)
@@ -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.23'
385
+ gem 'glimmer-dsl-libui', '~> 0.3.2'
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,7 +453,7 @@ 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)
456
+ 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` can be used as a control under `area` or alternatively build objects to use in `cell_rows` for a `table` with an `image_column`)
448
457
 
449
458
  Keyword(Args) | Properties | Listeners
450
459
  ------------- | ---------- | ---------
@@ -473,7 +482,7 @@ Keyword(Args) | Properties | Listeners
473
482
  `group(text as String)` | `margined` (Boolean), `title` (`String`) | None
474
483
  `horizontal_box` | `padded` (Boolean) | None
475
484
  `horizontal_separator` | None | None
476
- `image(width as Numeric, height as Numeric)` | None | None
485
+ `image(file as String = nil, width as Numeric = nil, height as Numeric = nil)` | `file` (`String` path or URL), `width`, `height` | None
477
486
  `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
487
  `image_column(name as String)` | None | None
479
488
  `image_text_column(name as String)` | None | None
@@ -552,8 +561,8 @@ There are additional useful `Glimmer::LibUI` operations that are not found in `L
552
561
  - `Glimmer::LibUI::integer_to_boolean(int, allow_nil: true)`
553
562
  - `Glimmer::LibUI::boolean_to_integer(int, allow_nil: true)`
554
563
  - `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`
564
+ - `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)
565
+ - `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
566
  - `Glimmer::LibUI::enum_names`: provides all possible enum names to use with `Glimmer::LibUI::enum_symbols(enum_name)`
558
567
  - `Glimmer::LibUI::enum_symbols(enum_name)`: returns all possible values for an enum. `enum_name` can be:
559
568
  - `:draw_brush_type`: `[:solid, :linear_gradient, :radial_gradient, :image]`
@@ -717,6 +726,8 @@ The `area` control is a canvas-like control for drawing paths that can be used i
717
726
  - 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
727
  - 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
728
 
729
+ 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.
730
+
720
731
  Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
721
732
 
722
733
  ```ruby
@@ -739,8 +750,18 @@ window('Basic Area', 400, 400) {
739
750
  }.show
740
751
  ```
741
752
 
753
+ Mac
754
+
742
755
  ![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
743
756
 
757
+ Windows
758
+
759
+ ![glimmer-dsl-libui-windows-basic-area.png](images/glimmer-dsl-libui-windows-basic-area.png)
760
+
761
+ Linux
762
+
763
+ ![glimmer-dsl-libui-linux-basic-area.png](images/glimmer-dsl-libui-linux-basic-area.png)
764
+
744
765
  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
766
 
746
767
  ```ruby
@@ -767,6 +788,8 @@ window('Basic Area', 400, 400) {
767
788
 
768
789
  Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
769
790
 
791
+ #### Area Path Shapes
792
+
770
793
  `path` can receive a `draw_fill_mode` argument that can accept values `:winding` or `:alternate` and defaults to `:winding`.
771
794
 
772
795
  Available nested `path` shapes:
@@ -782,6 +805,270 @@ Available nested `path` shapes:
782
805
 
783
806
  Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
784
807
 
808
+ Mac
809
+
810
+ ![glimmer-dsl-libui-mac-area-gallery.png](images/glimmer-dsl-libui-mac-area-gallery.png)
811
+
812
+ Windows
813
+
814
+ ![glimmer-dsl-libui-windows-area-gallery.png](images/glimmer-dsl-libui-windows-area-gallery.png)
815
+
816
+ Linux
817
+
818
+ ![glimmer-dsl-libui-linux-area-gallery.png](images/glimmer-dsl-libui-linux-area-gallery.png)
819
+
820
+ #### Area Text
821
+
822
+ 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.
823
+
824
+ `text` has the following properties:
825
+ - `default_font`:
826
+ - `align`: `:left` (default), `:center`, or `:right` (`align` currently seems not to work on the Mac)
827
+ - `x`: x coordinate in relation to parent `area` top-left corner
828
+ - `y`: y coordinate in relation to parent `area` top-left corner
829
+ - `width` (default: area width - x*2): width of text to display
830
+
831
+ `string` has the following properties:
832
+ - `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
833
+ - `color`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
834
+ - `background`: rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
835
+ - `underline`: one of `:none`, `:single`, `:double`, `:suggestion`, `:color_custom`, `:color_spelling`, `:color_grammar`, `:color_auxiliary`
836
+ - `underline_color`: one of `:spelling`, `:grammar`, `:auxiliary`, rgba, hex, or [X11](https://en.wikipedia.org/wiki/X11_color_names) color
837
+ - `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.
838
+ - `string`: string value (`String`)
839
+
840
+ Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
841
+
842
+ ```ruby
843
+ window('area text drawing') {
844
+ area {
845
+ text {
846
+ default_font family: 'Helvetica', size: 12, weight: :normal, italic: :normal, stretch: :normal
847
+
848
+ string {
849
+ font family: 'Georgia', size: 13, weight: :medium, italic: :normal, stretch: :normal
850
+ color r: 230, g: 100, b: 50, a: 0.5
851
+ background r: 230, g: 200, b: 250, a: 0.8
852
+ underline :single
853
+ underline_color :spelling
854
+ open_type_features {
855
+ open_type_tag 'l', 'i', 'g', 'a', 0
856
+ open_type_tag 'l', 'i', 'g', 'a', 1
857
+ }
858
+
859
+ "This is a demonstration\n" \
860
+ "of a very long\n" \
861
+ "attributed string\n" \
862
+ "spanning multiple lines\n\n"
863
+ }
864
+
865
+ string('This is a short unattributed string')
866
+ }
867
+ }
868
+ }.show
869
+ ```
870
+
871
+ 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`.
872
+
873
+ Mac
874
+
875
+ ![glimmer-dsl-libui-mac-custom-draw-text-changed.png](images/glimmer-dsl-libui-mac-custom-draw-text-changed.png)
876
+
877
+ Windows
878
+
879
+ ![glimmer-dsl-libui-windows-custom-draw-text-changed.png](images/glimmer-dsl-libui-windows-custom-draw-text-changed.png)
880
+
881
+ Linux
882
+
883
+ ![glimmer-dsl-libui-linux-custom-draw-text-changed.png](images/glimmer-dsl-libui-linux-custom-draw-text-changed.png)
884
+
885
+ #### Area Image
886
+
887
+ **(ALPHA FEATURE)**
888
+
889
+ [libui](https://github.com/andlabs/libui) does not support `image` rendering outside of `table` yet.
890
+ However, [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) adds a special `image(file as String path or web URL, width as Numeric, height as Numeric)` custom control that renders an image unto an `area` pixel by pixel (and when possible to optimize, line by line).
891
+
892
+ Given that it is very new and is not a [libui](https://github.com/andlabs/libui)-native control, please keep these notes in mind:
893
+ - It only supports the `.png` file format.
894
+ - [libui](https://github.com/andlabs/libui) pixel-by-pixel rendering performance is slow.
895
+ - Including an `image` inside an `area` `on_draw` listener improves performance due to not retaining pixel/line data in memory.
896
+ - Supplying `width` and `height` (2nd and 3rd arguments) greatly improves performance when shrinking image.
897
+
898
+ Currently, it is recommended to use `image` with very small `width` and `height` values only.
899
+
900
+ Setting a `transform` `matrix` is supported under `image` just like it is under `path` and `text` inside `area`.
901
+
902
+ Example of using `image` declaratively (you may copy/paste in [`girb`](#girb-glimmer-irb)):
903
+
904
+ Mac
905
+
906
+ ![glimmer-dsl-libui-mac-basic-image.png](images/glimmer-dsl-libui-mac-basic-image.png)
907
+
908
+ Windows
909
+
910
+ ![glimmer-dsl-libui-windows-basic-image.png](images/glimmer-dsl-libui-windows-basic-image.png)
911
+
912
+ ```ruby
913
+ require 'glimmer-dsl-libui'
914
+
915
+ include Glimmer
916
+
917
+ window('Basic Image', 96, 96) {
918
+ area {
919
+ image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
920
+ }
921
+ }.show
922
+ ```
923
+
924
+ Example of better performance via `on_draw` (you may copy/paste in [`girb`](#girb-glimmer-irb)):
925
+
926
+ ```ruby
927
+ require 'glimmer-dsl-libui'
928
+
929
+ include Glimmer
930
+
931
+ window('Basic Image', 96, 96) {
932
+ area {
933
+ on_draw do |area_draw_params|
934
+ image(File.expand_path('icons/glimmer.png', __dir__), 96, 96)
935
+ end
936
+ }
937
+ }.show
938
+ ```
939
+
940
+ Example of using `image` declaratively with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
941
+
942
+ ```ruby
943
+ require 'glimmer-dsl-libui'
944
+
945
+ include Glimmer
946
+
947
+ window('Basic Image', 96, 96) {
948
+ area {
949
+ image {
950
+ file File.expand_path('icons/glimmer.png', __dir__)
951
+ width 96
952
+ height 96
953
+ }
954
+ }
955
+ }.show
956
+ ```
957
+
958
+ Example of better performance via `on_draw` with explicit properties (you may copy/paste in [`girb`](#girb-glimmer-irb)):
959
+
960
+ ```ruby
961
+ require 'glimmer-dsl-libui'
962
+
963
+ include Glimmer
964
+
965
+ window('Basic Image', 96, 96) {
966
+ area {
967
+ on_draw do |area_draw_params|
968
+ image {
969
+ file File.expand_path('icons/glimmer.png', __dir__)
970
+ width 96
971
+ height 96
972
+ }
973
+ end
974
+ }
975
+ }.show
976
+ ```
977
+
978
+ 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:
979
+
980
+ ```ruby
981
+ # This is the manual way of rendering an image unto an area control.
982
+ # It could come in handy in special situations.
983
+ # Otherwise, it is recommended to simply utilize the `image` control that
984
+ # can be nested under area or area on_draw listener to automate all this work.
985
+
986
+ require 'glimmer-dsl-libui'
987
+ require 'chunky_png'
988
+
989
+ include Glimmer
990
+
991
+ puts 'Parsing image...'; $stdout.flush
992
+
993
+ f = File.open(File.expand_path('icons/glimmer.png', __dir__))
994
+ canvas = ChunkyPNG::Canvas.from_io(f)
995
+ f.close
996
+ canvas.resample_nearest_neighbor!(96, 96)
997
+ data = canvas.to_rgba_stream
998
+ width = canvas.width
999
+ height = canvas.height
1000
+ puts "Image width: #{width}"
1001
+ puts "Image height: #{height}"
1002
+
1003
+ puts 'Parsing colors...'; $stdout.flush
1004
+
1005
+ color_maps = height.times.map do |y|
1006
+ width.times.map do |x|
1007
+ r = data[(y*width + x)*4].ord
1008
+ g = data[(y*width + x)*4 + 1].ord
1009
+ b = data[(y*width + x)*4 + 2].ord
1010
+ a = data[(y*width + x)*4 + 3].ord
1011
+ {x: x, y: y, color: {r: r, g: g, b: b, a: a}}
1012
+ end
1013
+ end.flatten
1014
+ puts "#{color_maps.size} pixels to render..."; $stdout.flush
1015
+
1016
+ puts 'Parsing shapes...'; $stdout.flush
1017
+
1018
+ shape_maps = []
1019
+ original_color_maps = color_maps.dup
1020
+ indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
1021
+ color_maps.each do |color_map|
1022
+ index = indexed_original_color_maps[color_map]
1023
+ @rectangle_start_x ||= color_map[:x]
1024
+ @rectangle_width ||= 1
1025
+ if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
1026
+ @rectangle_width += 1
1027
+ else
1028
+ if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
1029
+ shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
1030
+ else
1031
+ shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
1032
+ end
1033
+ @rectangle_width = 1
1034
+ @rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
1035
+ end
1036
+ end
1037
+ puts "#{shape_maps.size} shapes to render..."; $stdout.flush
1038
+
1039
+ puts 'Rendering image...'; $stdout.flush
1040
+
1041
+ window('Basic Image', 96, 96) {
1042
+ area {
1043
+ on_draw do |area_draw_params|
1044
+ shape_maps.each do |shape_map|
1045
+ path {
1046
+ rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
1047
+
1048
+ fill shape_map[:color]
1049
+ }
1050
+ end
1051
+ end
1052
+ }
1053
+ }.show
1054
+ ```
1055
+
1056
+ 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.
1057
+
1058
+ Check out [examples/basic_image.rb](#basic-image) (all versions) for examples of using `image` Glimmer custom control.
1059
+
1060
+ #### Colors
1061
+
1062
+ `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)
1063
+
1064
+ Available [X11 colors](https://en.wikipedia.org/wiki/X11_color_names) can be obtained through `Glimmer::LibUI.x11_colors` method.
1065
+
1066
+ Check [Basic Transform](#basic-transform) example for use of [X11](https://en.wikipedia.org/wiki/X11_color_names) colors.
1067
+
1068
+ Check [Histogram](#histogram) example for use of hex colors.
1069
+
1070
+ #### Area Draw Params
1071
+
785
1072
  The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
786
1073
  - `:context`: the drawing context object
787
1074
  - `:area_width`: area width
@@ -793,7 +1080,9 @@ The `area_draw_params` argument for `on_draw` block is a hash consisting of the
793
1080
 
794
1081
  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
1082
 
796
- `area` supported mouse listeners are:
1083
+ #### Area Listeners
1084
+
1085
+ `area` supported listeners are:
797
1086
  - `on_key_event {|area_key_event| ...}`: general catch-all key event (recommend using fine-grained key events below instead)
798
1087
  - `on_key_down {|area_key_event| ...}`
799
1088
  - `on_key_up {|area_key_event| ...}`
@@ -821,14 +1110,14 @@ The `area_mouse_event` `Hash` argument for mouse events that receive it (e.g. `o
821
1110
 
822
1111
  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
1112
  - `: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`
1113
+ - `: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
1114
  - `:ext_key`: non-character extra key (`Symbol`) from `Glimmer::LibUI.enum_symbols(:ext_key)` such as `:left`, `:right`, `:escape`, `:insert`
826
1115
  - `: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
1116
  - `:modifier`: modifier key pressed alone (e.g. `:shift` or `:control`)
828
1117
  - `:modifiers`: modifier keys pressed simultaneously with `:key`, `:ext_key`, or `:modifier`
829
1118
  - `:up`: indicates if key has been released or not (Boolean)
830
1119
 
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.
1120
+ #### Area Methods/Attributes
832
1121
 
833
1122
  To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
834
1123
 
@@ -838,6 +1127,8 @@ To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#re
838
1127
  - `resume_auto_redraw`: resume auto redraw upon changes to nested stable `path` or shapes
839
1128
  - `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
1129
 
1130
+ #### Area Transform Matrix
1131
+
841
1132
  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
1133
 
843
1134
  When instantiating a `matrix` object, it always starts with identity matrix.
@@ -901,64 +1192,9 @@ transform m1
901
1192
  # and then reuse m1 elsewhere too
902
1193
  ```
903
1194
 
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.
1195
+ You can set a `matrix`/`transform` on `area` directly to conveniently apply to all nested `path`s too.
915
1196
 
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)):
933
-
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
- ```
1197
+ 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
1198
 
963
1199
  ### Smart Defaults and Conventions
964
1200
 
@@ -982,7 +1218,7 @@ window('area text drawing') {
982
1218
  - When destroying a control nested under a `form`, it is automatically deleted from the form's children
983
1219
  - When destroying a control nested under a `window` or `group`, it is automatically unset as their child to allow successful destruction
984
1220
  - 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`)
1221
+ - 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
1222
  - 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
1223
  - Table model instances are automatically freed from memory after `window` is destroyed.
988
1224
  - 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 +1232,7 @@ window('area text drawing') {
996
1232
  - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
997
1233
  - All resources are freed automatically once no longer needed or left to garbage collection.
998
1234
  - 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)
1235
+ - 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
1236
  - Color alpha value defaults to `1.0` when not specified.
1001
1237
 
1002
1238
  ### Custom Keywords
@@ -1110,7 +1346,8 @@ window('Method-Based Custom Keyword') {
1110
1346
  ### API Gotchas
1111
1347
 
1112
1348
  - 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).
1349
+ - `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).
1350
+ - `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
1351
  - `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
1352
  - `text` `string` `background` does not work on Windows due to an [issue in libui](https://github.com/andlabs/libui/issues/347).
1116
1353
  - `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 +1997,11 @@ class TinyMidiPlayer
1760
1997
 
1761
1998
  UI.new_horizontal_box.tap do |hbox|
1762
1999
  UI.new_vertical_box.tap do |vbox|
1763
- UI.new_button('â–¶').tap do |button1|
2000
+ UI.new_button('â–¶').tap do |button1|
1764
2001
  UI.button_on_clicked(button1) { play_midi }
1765
2002
  UI.box_append(vbox, button1, 1)
1766
2003
  end
1767
- UI.new_button('â– ').tap do |button2|
2004
+ UI.new_button('â– ').tap do |button2|
1768
2005
  UI.button_on_clicked(button2) { stop_midi }
1769
2006
  UI.box_append(vbox, button2, 1)
1770
2007
  end
@@ -1858,12 +2095,12 @@ class TinyMidiPlayer
1858
2095
  vertical_box {
1859
2096
  stretchy false
1860
2097
 
1861
- button('â–¶') {
2098
+ button('â–¶') {
1862
2099
  on_clicked do
1863
2100
  play_midi
1864
2101
  end
1865
2102
  }
1866
- button('â– ') {
2103
+ button('â– ') {
1867
2104
  on_clicked do
1868
2105
  stop_midi
1869
2106
  end
@@ -2994,13 +3231,7 @@ window('Editable column animal sounds', 400, 200) {
2994
3231
 
2995
3232
  ### Basic Table Image
2996
3233
 
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).
3234
+ Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3004
3235
 
3005
3236
  [examples/basic_table_image.rb](examples/basic_table_image.rb)
3006
3237
 
@@ -3114,6 +3345,41 @@ UI.quit
3114
3345
  # NOTE:
3115
3346
  # This example displays images that can be freely downloaded from the Studio Ghibli website.
3116
3347
 
3348
+ require 'glimmer-dsl-libui'
3349
+
3350
+ include Glimmer
3351
+
3352
+ IMAGE_ROWS = []
3353
+
3354
+ 50.times do |i|
3355
+ url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
3356
+ puts "Processing Image: #{url}"; $stdout.flush # for Windows
3357
+ IMAGE_ROWS << [image(url)] # array of one column cell
3358
+ rescue StandardError => e
3359
+ warn url, e.message
3360
+ end
3361
+
3362
+ window('The Red Turtle', 310, 350, false) {
3363
+ horizontal_box {
3364
+ table {
3365
+ image_column('www.ghibli.jp/works/red-turtle')
3366
+
3367
+ cell_rows IMAGE_ROWS
3368
+ }
3369
+ }
3370
+
3371
+ on_closing do
3372
+ puts 'Bye Bye'
3373
+ end
3374
+ }.show
3375
+ ```
3376
+
3377
+ [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (manual construction of `image` from `image_part`):
3378
+
3379
+ ```ruby
3380
+ # NOTE:
3381
+ # This example displays images that can be freely downloaded from the Studio Ghibli website.
3382
+
3117
3383
  require 'glimmer-dsl-libui'
3118
3384
  require 'chunky_png'
3119
3385
  require 'open-uri'
@@ -3156,13 +3422,7 @@ window('The Red Turtle', 310, 350, false) {
3156
3422
 
3157
3423
  ### Basic Table Image Text
3158
3424
 
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).
3425
+ Note that behavior varies per platform (i.e. how `table` chooses to size images by default).
3166
3426
 
3167
3427
  [examples/basic_table_image_text.rb](examples/basic_table_image_text.rb)
3168
3428
 
@@ -3196,6 +3456,42 @@ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version
3196
3456
  # NOTE:
3197
3457
  # This example displays images that can be freely downloaded from the Studio Ghibli website.
3198
3458
 
3459
+ require 'glimmer-dsl-libui'
3460
+
3461
+ include Glimmer
3462
+
3463
+ IMAGE_ROWS = []
3464
+
3465
+ 5.times do |i|
3466
+ url = format('https://www.ghibli.jp/gallery/thumb-redturtle%03d.png', (i + 1))
3467
+ puts "Processing Image: #{url}"; $stdout.flush # for Windows
3468
+ text = url.sub('https://www.ghibli.jp/gallery/thumb-redturtle', '').sub('.png', '')
3469
+ img = image(url)
3470
+ IMAGE_ROWS << [[img, text], [img, text]] # cell values are dual-element arrays
3471
+ rescue StandardError => e
3472
+ warn url, e.message
3473
+ end
3474
+
3475
+ window('The Red Turtle', 670, 350) {
3476
+ horizontal_box {
3477
+ table {
3478
+ image_text_column('image/number')
3479
+ image_text_column('image/number (editable)') {
3480
+ editable true
3481
+ }
3482
+
3483
+ cell_rows IMAGE_ROWS
3484
+ }
3485
+ }
3486
+ }.show
3487
+ ```
3488
+
3489
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (manual construction of `image` from `image_part`):
3490
+
3491
+ ```ruby
3492
+ # NOTE:
3493
+ # This example displays images that can be freely downloaded from the Studio Ghibli website.
3494
+
3199
3495
  require 'glimmer-dsl-libui'
3200
3496
  require 'chunky_png'
3201
3497
  require 'open-uri'
@@ -3482,12 +3778,6 @@ window('Task Progress', 300, 200) {
3482
3778
 
3483
3779
  ### Basic Table Color
3484
3780
 
3485
- This example requires pre-installing `chunky_png` Ruby gem:
3486
-
3487
- ```
3488
- gem install chunky_png -v1.4.0
3489
- ```
3490
-
3491
3781
  [examples/basic_table_color.rb](examples/basic_table_color.rb)
3492
3782
 
3493
3783
  Run with this command from the root of the project if you cloned the project:
@@ -3516,6 +3806,40 @@ Linux
3516
3806
 
3517
3807
  New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3518
3808
 
3809
+ ```ruby
3810
+ # frozen_string_literal: true
3811
+
3812
+ require 'glimmer-dsl-libui'
3813
+
3814
+ include Glimmer
3815
+
3816
+ img = image(File.expand_path('../icons/glimmer.png', __dir__), 24, 24)
3817
+
3818
+ data = [
3819
+ [['cat', :red] , ['meow', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], {r: 255, g: 120, b: 0, a: 0.5}],
3820
+ [['dog', :yellow] , ['woof', {r: 240, g: 32, b: 32}] , [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], :skyblue],
3821
+ [['chicken', :beige], ['cock-a-doodle-doo', :blue] , [false, 'mammal', :red] , [img, 'Glimmer', :beige], {r: 5, g: 120, b: 110}],
3822
+ [['horse', :purple] , ['neigh', {r: 240, g: 32, b: 32}], [true, 'mammal', :green], [img, 'Glimmer', :dark_blue], '13a1fb'],
3823
+ [['cow', :gray] , ['moo', :blue] , [true, 'mammal', :green], [img, 'Glimmer', :brown], 0x12ff02]
3824
+ ]
3825
+
3826
+ window('Animals', 500, 200) {
3827
+ horizontal_box {
3828
+ table {
3829
+ text_color_column('Animal')
3830
+ text_color_column('Sound')
3831
+ checkbox_text_color_column('Description')
3832
+ image_text_color_column('GUI')
3833
+ background_color_column('Mammal')
3834
+
3835
+ cell_rows data
3836
+ }
3837
+ }
3838
+ }.show
3839
+ ```
3840
+
3841
+ 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`):
3842
+
3519
3843
  ```ruby
3520
3844
  require 'glimmer-dsl-libui'
3521
3845
  require 'chunky_png'
@@ -4723,6 +5047,200 @@ window('Area Gallery', 400, 400) {
4723
5047
  }.show
4724
5048
  ```
4725
5049
 
5050
+ ### Basic Image
5051
+
5052
+ [examples/basic_image.rb](examples/basic_image.rb)
5053
+
5054
+ Run with this command from the root of the project if you cloned the project:
5055
+
5056
+ ```
5057
+ ruby -r './lib/glimmer-dsl-libui' examples/basic_image.rb
5058
+ ```
5059
+
5060
+ Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
5061
+
5062
+ ```
5063
+ ruby -r glimmer-dsl-libui -e "require 'examples/basic_image'"
5064
+ ```
5065
+
5066
+ Mac
5067
+
5068
+ ![glimmer-dsl-libui-mac-basic-image.png](images/glimmer-dsl-libui-mac-basic-image.png)
5069
+
5070
+ Windows
5071
+
5072
+ ![glimmer-dsl-libui-windows-basic-image.png](images/glimmer-dsl-libui-windows-basic-image.png)
5073
+
5074
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
5075
+
5076
+ ```ruby
5077
+ require 'glimmer-dsl-libui'
5078
+
5079
+ include Glimmer
5080
+
5081
+ window('Basic Image', 96, 96) {
5082
+ area {
5083
+ # image is not a real LibUI control. It is built in Glimmer as a custom control that renders
5084
+ # tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
5085
+ # be used in exceptional circumstances where an image control is really needed.
5086
+ #
5087
+ # Furthermore, adding image directly under area is even slower due to taking up more memory for every
5088
+ # image pixel rendered. Check basic_image2.rb for a faster alternative using on_draw manually.
5089
+ #
5090
+ # It is recommended to pass width/height args to shrink image and achieve faster performance.
5091
+ image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
5092
+ }
5093
+ }.show
5094
+ ```
5095
+
5096
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (better performance via `on_draw`):
5097
+
5098
+ ```ruby
5099
+ # frozen_string_literal: true
5100
+
5101
+ require 'glimmer-dsl-libui'
5102
+
5103
+ include Glimmer
5104
+
5105
+ window('Basic Image', 96, 96) {
5106
+ area {
5107
+ on_draw do |area_draw_params|
5108
+ image(File.expand_path('../icons/glimmer.png', __dir__), 96, 96)
5109
+ end
5110
+ }
5111
+ }.show
5112
+ ```
5113
+
5114
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (explicit properties):
5115
+
5116
+ ```ruby
5117
+ # frozen_string_literal: true
5118
+
5119
+ require 'glimmer-dsl-libui'
5120
+
5121
+ include Glimmer
5122
+
5123
+ window('Basic Image', 96, 96) {
5124
+ area {
5125
+ # image is not a real LibUI control. It is built in Glimmer as a custom control that renders
5126
+ # tiny pixels/lines as rectangle paths. As such, it does not have good performance, but can
5127
+ # be used in exceptional circumstances where an image control is really needed.
5128
+ #
5129
+ # Furthermore, adding image directly under area is even slower due to taking up more memory for every
5130
+ # image pixel rendered. Check basic_image4.rb for a faster alternative using on_draw manually.
5131
+ #
5132
+ # It is recommended to pass width/height args to shrink image and achieve faster performance.
5133
+ image {
5134
+ file File.expand_path('../icons/glimmer.png', __dir__)
5135
+ width 96
5136
+ height 96
5137
+ }
5138
+ }
5139
+ }.show
5140
+ ```
5141
+
5142
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (better performance with `on_draw` when setting explicit properties):
5143
+
5144
+ ```ruby
5145
+ # frozen_string_literal: true
5146
+
5147
+ require 'glimmer-dsl-libui'
5148
+
5149
+ include Glimmer
5150
+
5151
+ window('Basic Image', 96, 96) {
5152
+ area {
5153
+ on_draw do |area_draw_params|
5154
+ image {
5155
+ file File.expand_path('../icons/glimmer.png', __dir__)
5156
+ width 96
5157
+ height 96
5158
+ }
5159
+ end
5160
+ }
5161
+ }.show
5162
+ ```
5163
+
5164
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 5 (fully manual pixel-by-pixel rendering):
5165
+
5166
+ ```ruby
5167
+ # frozen_string_literal: true
5168
+
5169
+ # This is the manual way of rendering an image unto an area control.
5170
+ # It could come in handy in special situations.
5171
+ # Otherwise, it is recommended to simply utilize the `image` control that
5172
+ # can be nested under area or area on_draw listener to automate all this work.
5173
+
5174
+ require 'glimmer-dsl-libui'
5175
+ require 'chunky_png'
5176
+
5177
+ include Glimmer
5178
+
5179
+ puts 'Parsing image...'; $stdout.flush
5180
+
5181
+ f = File.open(File.expand_path('../icons/glimmer.png', __dir__))
5182
+ canvas = ChunkyPNG::Canvas.from_io(f)
5183
+ f.close
5184
+ canvas.resample_nearest_neighbor!(96, 96)
5185
+ data = canvas.to_rgba_stream
5186
+ width = canvas.width
5187
+ height = canvas.height
5188
+ puts "Image width: #{width}"
5189
+ puts "Image height: #{height}"
5190
+
5191
+ puts 'Parsing colors...'; $stdout.flush
5192
+
5193
+ color_maps = height.times.map do |y|
5194
+ width.times.map do |x|
5195
+ r = data[(y*width + x)*4].ord
5196
+ g = data[(y*width + x)*4 + 1].ord
5197
+ b = data[(y*width + x)*4 + 2].ord
5198
+ a = data[(y*width + x)*4 + 3].ord
5199
+ {x: x, y: y, color: {r: r, g: g, b: b, a: a}}
5200
+ end
5201
+ end.flatten
5202
+ puts "#{color_maps.size} pixels to render..."; $stdout.flush
5203
+
5204
+ puts 'Parsing shapes...'; $stdout.flush
5205
+
5206
+ shape_maps = []
5207
+ original_color_maps = color_maps.dup
5208
+ indexed_original_color_maps = Hash[original_color_maps.each_with_index.to_a]
5209
+ color_maps.each do |color_map|
5210
+ index = indexed_original_color_maps[color_map]
5211
+ @rectangle_start_x ||= color_map[:x]
5212
+ @rectangle_width ||= 1
5213
+ if color_map[:x] < width - 1 && color_map[:color] == original_color_maps[index + 1][:color]
5214
+ @rectangle_width += 1
5215
+ else
5216
+ if color_map[:x] > 0 && color_map[:color] == original_color_maps[index - 1][:color]
5217
+ shape_maps << {x: @rectangle_start_x, y: color_map[:y], width: @rectangle_width, height: 1, color: color_map[:color]}
5218
+ else
5219
+ shape_maps << {x: color_map[:x], y: color_map[:y], width: 1, height: 1, color: color_map[:color]}
5220
+ end
5221
+ @rectangle_width = 1
5222
+ @rectangle_start_x = color_map[:x] == width - 1 ? 0 : color_map[:x] + 1
5223
+ end
5224
+ end
5225
+ puts "#{shape_maps.size} shapes to render..."; $stdout.flush
5226
+
5227
+ puts 'Rendering image...'; $stdout.flush
5228
+
5229
+ window('Basic Image', 96, 96) {
5230
+ area {
5231
+ on_draw do |area_draw_params|
5232
+ shape_maps.each do |shape_map|
5233
+ path {
5234
+ rectangle(shape_map[:x], shape_map[:y], shape_map[:width], shape_map[:height])
5235
+
5236
+ fill shape_map[:color]
5237
+ }
5238
+ end
5239
+ end
5240
+ }
5241
+ }.show
5242
+ ```
5243
+
4726
5244
  ### Histogram
4727
5245
 
4728
5246
  [examples/histogram.rb](examples/histogram.rb)