glimmer-dsl-libui 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +684 -215
- data/VERSION +1 -1
- data/examples/area_gallery.rb +36 -38
- data/examples/area_gallery2.rb +90 -92
- data/examples/area_gallery3.rb +39 -41
- data/examples/area_gallery4.rb +96 -98
- data/examples/basic_area2.rb +1 -1
- data/examples/basic_transform.rb +27 -0
- data/examples/dynamic_area.rb +1 -1
- data/examples/histogram.rb +119 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/arc.rb +1 -1
- data/lib/glimmer/libui/area_proxy.rb +21 -11
- data/lib/glimmer/libui/box.rb +1 -1
- data/lib/glimmer/libui/color_button_proxy.rb +67 -15
- data/lib/glimmer/libui/control_proxy.rb +4 -12
- data/lib/glimmer/libui/form_proxy.rb +1 -1
- data/lib/glimmer/libui/grid_proxy.rb +1 -1
- data/lib/glimmer/libui/matrix_proxy.rb +145 -0
- data/lib/glimmer/libui/parent.rb +36 -0
- data/lib/glimmer/libui/path_proxy.rb +14 -17
- data/lib/glimmer/libui/shape.rb +8 -9
- data/lib/glimmer/libui/transformable.rb +72 -0
- data/lib/glimmer/libui/window_proxy.rb +8 -1
- data/lib/glimmer/libui.rb +50 -0
- data/lib/glimmer-dsl-libui.rb +1 -0
- metadata +8 -2
    
        data/README.md
    CHANGED
    
    | @@ -80,50 +80,48 @@ require 'glimmer-dsl-libui' | |
| 80 80 | 
             
            include Glimmer
         | 
| 81 81 |  | 
| 82 82 | 
             
            window('Area Gallery', 400, 400) {
         | 
| 83 | 
            -
               | 
| 84 | 
            -
                 | 
| 85 | 
            -
                   | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
                   | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
                   | 
| 98 | 
            -
                     | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
                      line(400, 400)
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                      closed true
         | 
| 104 | 
            -
                    }
         | 
| 83 | 
            +
              area {
         | 
| 84 | 
            +
                path { # declarative stable path
         | 
| 85 | 
            +
                  square(0, 0, 100)
         | 
| 86 | 
            +
                  square(100, 100, 400)
         | 
| 87 | 
            +
                  
         | 
| 88 | 
            +
                  fill r: 102, g: 102, b: 204
         | 
| 89 | 
            +
                }
         | 
| 90 | 
            +
                path { # declarative stable path
         | 
| 91 | 
            +
                  rectangle(0, 100, 100, 400)
         | 
| 92 | 
            +
                  rectangle(100, 0, 400, 100)
         | 
| 93 | 
            +
                  
         | 
| 94 | 
            +
                  fill r: 204, g: 102, b: 204
         | 
| 95 | 
            +
                }
         | 
| 96 | 
            +
                path { # declarative stable path
         | 
| 97 | 
            +
                  figure(100, 100) {
         | 
| 98 | 
            +
                    line(100, 400)
         | 
| 99 | 
            +
                    line(400, 100)
         | 
| 100 | 
            +
                    line(400, 400)
         | 
| 105 101 |  | 
| 106 | 
            -
                     | 
| 107 | 
            -
                    stroke r: 0, g: 0, b: 0
         | 
| 102 | 
            +
                    closed true
         | 
| 108 103 | 
             
                  }
         | 
| 109 | 
            -
                  path { # declarative stable path
         | 
| 110 | 
            -
                    figure(0, 0) {
         | 
| 111 | 
            -
                      bezier(200, 100, 100, 200, 400, 100)
         | 
| 112 | 
            -
                      bezier(300, 100, 100, 300, 100, 400)
         | 
| 113 | 
            -
                      bezier(100, 300, 300, 100, 400, 400)
         | 
| 114 104 |  | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 105 | 
            +
                  fill r: 202, g: 102, b: 104, a: 0.5
         | 
| 106 | 
            +
                  stroke r: 0, g: 0, b: 0
         | 
| 107 | 
            +
                }
         | 
| 108 | 
            +
                path { # declarative stable path
         | 
| 109 | 
            +
                  figure(0, 0) {
         | 
| 110 | 
            +
                    bezier(200, 100, 100, 200, 400, 100)
         | 
| 111 | 
            +
                    bezier(300, 100, 100, 300, 100, 400)
         | 
| 112 | 
            +
                    bezier(100, 300, 300, 100, 400, 400)
         | 
| 117 113 |  | 
| 118 | 
            -
                     | 
| 119 | 
            -
                    stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 114 | 
            +
                    closed true
         | 
| 120 115 | 
             
                  }
         | 
| 121 | 
            -
                  path { # declarative stable path
         | 
| 122 | 
            -
                    arc(200, 200, 90, 0, 360, false)
         | 
| 123 116 |  | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 117 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 118 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 119 | 
            +
                }
         | 
| 120 | 
            +
                path { # declarative stable path
         | 
| 121 | 
            +
                  arc(200, 200, 90, 0, 360, false)
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 124 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 127 125 | 
             
                }
         | 
| 128 126 | 
             
              }
         | 
| 129 127 | 
             
            }.show
         | 
| @@ -186,6 +184,8 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes | |
| 186 184 | 
             
                - [Basic Area](#basic-area)
         | 
| 187 185 | 
             
                - [Dynamic Area](#dynamic-area)
         | 
| 188 186 | 
             
                - [Area Gallery](#area-gallery)
         | 
| 187 | 
            +
                - [Histogram](#histogram)
         | 
| 188 | 
            +
                - [Basic Transform](#basic-transform)
         | 
| 189 189 | 
             
              - [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
         | 
| 190 190 | 
             
              - [Help](#help)
         | 
| 191 191 | 
             
                - [Issues](#issues)
         | 
| @@ -374,6 +374,7 @@ Control(Args) | Properties | Listeners | |
| 374 374 | 
             
            `image_text_column(name as String)` | None | None
         | 
| 375 375 | 
             
            `label(text as String)` | `text` (`String`) | None
         | 
| 376 376 | 
             
            `line(x as Numeric, y as Numeric)` | `x` (`Numeric`), `y` (`Numeric`) | None
         | 
| 377 | 
            +
            `matrix(m11 = nil as Numeric, m12 = nil as Numeric, m21 = nil as Numeric, m22 = nil as Numeric, m31 = nil as Numeric, m32 = nil as Numeric)` | `m11` (`Numeric`), `m12` (`Numeric`), `m21` (`Numeric`), `m22` (`Numeric`), `m31` (`Numeric`), `m32` (`Numeric`) | None
         | 
| 377 378 | 
             
            `menu(text as String)` | None | None
         | 
| 378 379 | 
             
            `menu_item(text as String)` | `checked` (Boolean) | `on_clicked`
         | 
| 379 380 | 
             
            `multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
         | 
| @@ -530,9 +531,9 @@ Learn more by checking out [examples](#examples). | |
| 530 531 |  | 
| 531 532 | 
             
            ### Area API
         | 
| 532 533 |  | 
| 533 | 
            -
            The `area` control can be used in one of two ways:
         | 
| 534 | 
            -
            - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically.  | 
| 535 | 
            -
            - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block and nest `path | 
| 534 | 
            +
            The `area` control is a canvas-like control for drawing paths that can be used in one of two ways:
         | 
| 535 | 
            +
            - Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are preserved across redraws assuming there would be few stable paths (mostly for decorative reasons).
         | 
| 536 | 
            +
            - Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block that receives a `area_draw_params` argument and nest `path` and figures like `rectangle` and all drawing logic is generated automatically. Path proxy objects are destroyed (thrown-away) at the end of drawing, thus having less memory overhead for drawing thousands of dynamic paths.
         | 
| 536 537 |  | 
| 537 538 | 
             
            Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
         | 
| 538 539 |  | 
| @@ -558,7 +559,7 @@ window('Basic Area', 400, 400) { | |
| 558 559 |  | 
| 559 560 | 
             
            
         | 
| 560 561 |  | 
| 561 | 
            -
            Here is the same example using a semi-declarative `area` with `on_draw` listener and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
         | 
| 562 | 
            +
            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)):
         | 
| 562 563 |  | 
| 563 564 | 
             
            ```ruby
         | 
| 564 565 | 
             
            require 'glimmer-dsl-libui'
         | 
| @@ -571,7 +572,7 @@ window('Basic Area', 400, 400) { | |
| 571 572 | 
             
              vertical_box {
         | 
| 572 573 | 
             
                area {
         | 
| 573 574 | 
             
                  on_draw do |area_draw_params|
         | 
| 574 | 
            -
                    path | 
| 575 | 
            +
                    path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 575 576 | 
             
                      rectangle(0, 0, 400, 400)
         | 
| 576 577 |  | 
| 577 578 | 
             
                      fill r: 102, g: 102, b: 204, a: 1.0
         | 
| @@ -592,9 +593,85 @@ Available nested `path` shapes: | |
| 592 593 | 
             
            - `bezier(c1_x as Numeric, c1_y as Numeric, c2_x as Numeric, c2_y as Numeric, end_x as Numeric, end_y as Numeric)`
         | 
| 593 594 | 
             
            - `figure(x=nil as Numeric, y=nil as Numeric)` (composite that can contain other shapes) (can set `closed true` to connect last point to first point automatically)
         | 
| 594 595 |  | 
| 595 | 
            -
             | 
| 596 | 
            +
            Check [examples/area_gallery.rb](#area-gallery) for an overiew of all `path` shapes.
         | 
| 597 | 
            +
             | 
| 598 | 
            +
            The `area_draw_params` argument for `on_draw` block is a hash consisting of the following keys:
         | 
| 599 | 
            +
            - `:context`: the drawing context object
         | 
| 600 | 
            +
            - `:area_width`: area width
         | 
| 601 | 
            +
            - `:area_height`: area height
         | 
| 602 | 
            +
            - `:clip_x`: clip region top-left x coordinate
         | 
| 603 | 
            +
            - `:clip_y`: clip region top-left y coordinate
         | 
| 604 | 
            +
            - `:clip_width`: clip region width
         | 
| 605 | 
            +
            - `:clip_height`: clip region height
         | 
| 606 | 
            +
             | 
| 607 | 
            +
            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.
         | 
| 608 | 
            +
             | 
| 609 | 
            +
            To redraw an `area`, you may call the `#queue_redraw_all` method, or simply `#redraw`.
         | 
| 610 | 
            +
             | 
| 611 | 
            +
            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.
         | 
| 596 612 |  | 
| 597 | 
            -
             | 
| 613 | 
            +
            When instantiating a `matrix` object, it always starts with identity matrix.
         | 
| 614 | 
            +
             | 
| 615 | 
            +
            Here are the following operations that can be performed in a `matrix` body:
         | 
| 616 | 
            +
            - `identity` [alias: `set_identity`]: resets matrix to identity matrix
         | 
| 617 | 
            +
            - `translate(x as Numeric, y as Numeric)`
         | 
| 618 | 
            +
            - `scale(x_center = 0 as Numeric, y_center = 0 as Numeric, x as Numeric, y as Numeric)`
         | 
| 619 | 
            +
            - `skew(x = 0 as Numeric, y = 0 as Numeric, x_amount as Numeric, y_amount as Numeric)`
         | 
| 620 | 
            +
            - `rotate(x = 0 as Numeric, y = 0 as Numeric, degrees as Numeric)`
         | 
| 621 | 
            +
             | 
| 622 | 
            +
            Example of using transform matrix (you may copy/paste in [`girb`](#girb-glimmer-irb)):
         | 
| 623 | 
            +
             | 
| 624 | 
            +
            ```ruby
         | 
| 625 | 
            +
            require 'glimmer-dsl-libui'
         | 
| 626 | 
            +
             | 
| 627 | 
            +
            include Glimmer
         | 
| 628 | 
            +
             | 
| 629 | 
            +
            window('Basic Transform', 350, 350) {
         | 
| 630 | 
            +
              area {
         | 
| 631 | 
            +
                path {
         | 
| 632 | 
            +
                  square(0, 0, 350)
         | 
| 633 | 
            +
                  
         | 
| 634 | 
            +
                  fill r: 255, g: 255, b: 0
         | 
| 635 | 
            +
                }
         | 
| 636 | 
            +
                40.times do |n|
         | 
| 637 | 
            +
                  path {
         | 
| 638 | 
            +
                    square(0, 0, 100)
         | 
| 639 | 
            +
                    
         | 
| 640 | 
            +
                    fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
         | 
| 641 | 
            +
                    stroke color: 0, thickness: 2
         | 
| 642 | 
            +
                    transform {
         | 
| 643 | 
            +
                      skew 0.15, 0.15
         | 
| 644 | 
            +
                      translate 50, 50
         | 
| 645 | 
            +
                      rotate 100, 100, -9 * n
         | 
| 646 | 
            +
                      scale 1.1, 1.1
         | 
| 647 | 
            +
                    }
         | 
| 648 | 
            +
                  }
         | 
| 649 | 
            +
                end
         | 
| 650 | 
            +
              }
         | 
| 651 | 
            +
            }.show
         | 
| 652 | 
            +
            ```
         | 
| 653 | 
            +
             | 
| 654 | 
            +
            Keep in mind that this part could be written differently when there is a need to reuse the matrix:
         | 
| 655 | 
            +
             | 
| 656 | 
            +
            ```ruby
         | 
| 657 | 
            +
            transform {
         | 
| 658 | 
            +
              translate 100, 100
         | 
| 659 | 
            +
              rotate 100, 100, -9 * n
         | 
| 660 | 
            +
            }
         | 
| 661 | 
            +
            ```
         | 
| 662 | 
            +
             | 
| 663 | 
            +
            Alternatively:
         | 
| 664 | 
            +
             | 
| 665 | 
            +
            ```ruby
         | 
| 666 | 
            +
            m1 = matrix {
         | 
| 667 | 
            +
              translate 100, 100
         | 
| 668 | 
            +
              rotate 100, 100, -9 * n
         | 
| 669 | 
            +
            }
         | 
| 670 | 
            +
            transform m1
         | 
| 671 | 
            +
            # and then reuse m1 elsewhere too
         | 
| 672 | 
            +
            ```
         | 
| 673 | 
            +
             | 
| 674 | 
            +
            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.
         | 
| 598 675 |  | 
| 599 676 | 
             
            ### Smart Defaults and Conventions
         | 
| 600 677 |  | 
| @@ -627,6 +704,8 @@ To redraw an `area`, you may call `#queue_redraw_all` method. | |
| 627 704 | 
             
            - `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
         | 
| 628 705 | 
             
            - Observe figure properties (e.g. `rectangle` `width`) for changes and automatically redraw containing area accordingly
         | 
| 629 706 | 
             
            - Observe `path` `fill` and `stroke` hashes for changes and automatically redraw containing area accordingly
         | 
| 707 | 
            +
            - All controls are protected from garbage collection until no longer needed (explicitly destroyed), so there is no need to worry about surprises.
         | 
| 708 | 
            +
            - All resources are freed automatically once no longer needed or left to garbage collection.
         | 
| 630 709 |  | 
| 631 710 | 
             
            ### API Gotchas
         | 
| 632 711 |  | 
| @@ -810,7 +889,7 @@ window('hello world', 300, 200, true) { | |
| 810 889 | 
             
            }.show
         | 
| 811 890 | 
             
            ```
         | 
| 812 891 |  | 
| 813 | 
            -
            [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
         | 
| 892 | 
            +
            [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting `window` properties instead of arguments):
         | 
| 814 893 |  | 
| 815 894 | 
             
            ```ruby
         | 
| 816 895 | 
             
            require 'glimmer-dsl-libui'
         | 
| @@ -2956,7 +3035,7 @@ window('Basic Area', 400, 400) { | |
| 2956 3035 | 
             
            }.show
         | 
| 2957 3036 | 
             
            ```
         | 
| 2958 3037 |  | 
| 2959 | 
            -
            [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
         | 
| 3038 | 
            +
            [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (semi-declarative `on_draw` dynamic `path` approach):
         | 
| 2960 3039 |  | 
| 2961 3040 | 
             
            ```ruby
         | 
| 2962 3041 | 
             
            require 'glimmer-dsl-libui'
         | 
| @@ -2969,7 +3048,7 @@ window('Basic Area', 400, 400) { | |
| 2969 3048 | 
             
              vertical_box {
         | 
| 2970 3049 | 
             
                area {
         | 
| 2971 3050 | 
             
                  on_draw do |area_draw_params|
         | 
| 2972 | 
            -
                    path | 
| 3051 | 
            +
                    path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 2973 3052 | 
             
                      rectangle(0, 0, 400, 400)
         | 
| 2974 3053 |  | 
| 2975 3054 | 
             
                      fill r: 102, g: 102, b: 204, a: 1.0
         | 
| @@ -3099,7 +3178,7 @@ window('Dynamic Area', 240, 500) { | |
| 3099 3178 |  | 
| 3100 3179 | 
             
                @area = area {
         | 
| 3101 3180 | 
             
                  on_draw do |area_draw_params|
         | 
| 3102 | 
            -
                    path | 
| 3181 | 
            +
                    path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3103 3182 | 
             
                      rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
         | 
| 3104 3183 |  | 
| 3105 3184 | 
             
                      fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
         | 
| @@ -3110,7 +3189,7 @@ window('Dynamic Area', 240, 500) { | |
| 3110 3189 | 
             
            }.show
         | 
| 3111 3190 | 
             
            ```
         | 
| 3112 3191 |  | 
| 3113 | 
            -
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2:
         | 
| 3192 | 
            +
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (declarative stable `path` approach):
         | 
| 3114 3193 |  | 
| 3115 3194 | 
             
            ```ruby
         | 
| 3116 3195 | 
             
            require 'glimmer-dsl-libui'
         | 
| @@ -3244,21 +3323,192 @@ require 'glimmer-dsl-libui' | |
| 3244 3323 | 
             
            include Glimmer
         | 
| 3245 3324 |  | 
| 3246 3325 | 
             
            window('Area Gallery', 400, 400) {
         | 
| 3247 | 
            -
               | 
| 3248 | 
            -
                 | 
| 3249 | 
            -
                   | 
| 3326 | 
            +
              area {
         | 
| 3327 | 
            +
                path { # declarative stable path
         | 
| 3328 | 
            +
                  square(0, 0, 100)
         | 
| 3329 | 
            +
                  square(100, 100, 400)
         | 
| 3330 | 
            +
                  
         | 
| 3331 | 
            +
                  fill r: 102, g: 102, b: 204
         | 
| 3332 | 
            +
                }
         | 
| 3333 | 
            +
                path { # declarative stable path
         | 
| 3334 | 
            +
                  rectangle(0, 100, 100, 400)
         | 
| 3335 | 
            +
                  rectangle(100, 0, 400, 100)
         | 
| 3336 | 
            +
                  
         | 
| 3337 | 
            +
                  fill r: 204, g: 102, b: 204
         | 
| 3338 | 
            +
                }
         | 
| 3339 | 
            +
                path { # declarative stable path
         | 
| 3340 | 
            +
                  figure(100, 100) {
         | 
| 3341 | 
            +
                    line(100, 400)
         | 
| 3342 | 
            +
                    line(400, 100)
         | 
| 3343 | 
            +
                    line(400, 400)
         | 
| 3344 | 
            +
             | 
| 3345 | 
            +
                    closed true
         | 
| 3346 | 
            +
                  }
         | 
| 3347 | 
            +
             | 
| 3348 | 
            +
                  fill r: 202, g: 102, b: 104, a: 0.5
         | 
| 3349 | 
            +
                  stroke r: 0, g: 0, b: 0
         | 
| 3350 | 
            +
                }
         | 
| 3351 | 
            +
                path { # declarative stable path
         | 
| 3352 | 
            +
                  figure(0, 0) {
         | 
| 3353 | 
            +
                    bezier(200, 100, 100, 200, 400, 100)
         | 
| 3354 | 
            +
                    bezier(300, 100, 100, 300, 100, 400)
         | 
| 3355 | 
            +
                    bezier(100, 300, 300, 100, 400, 400)
         | 
| 3356 | 
            +
             | 
| 3357 | 
            +
                    closed true
         | 
| 3358 | 
            +
                  }
         | 
| 3359 | 
            +
             | 
| 3360 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3361 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3362 | 
            +
                }
         | 
| 3363 | 
            +
                path { # declarative stable path
         | 
| 3364 | 
            +
                  arc(200, 200, 90, 0, 360, false)
         | 
| 3365 | 
            +
             | 
| 3366 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3367 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3368 | 
            +
                }
         | 
| 3369 | 
            +
              }
         | 
| 3370 | 
            +
            }.show
         | 
| 3371 | 
            +
            ```
         | 
| 3372 | 
            +
             | 
| 3373 | 
            +
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (setting shape properties instead of arguments):
         | 
| 3374 | 
            +
             | 
| 3375 | 
            +
            ```ruby
         | 
| 3376 | 
            +
            require 'glimmer-dsl-libui'
         | 
| 3377 | 
            +
             | 
| 3378 | 
            +
            include Glimmer
         | 
| 3379 | 
            +
             | 
| 3380 | 
            +
            window('Area Gallery', 400, 400) {
         | 
| 3381 | 
            +
              area {
         | 
| 3382 | 
            +
                path { # declarative stable path
         | 
| 3383 | 
            +
                  square {
         | 
| 3384 | 
            +
                    x 0
         | 
| 3385 | 
            +
                    y 0
         | 
| 3386 | 
            +
                    length 100
         | 
| 3387 | 
            +
                  }
         | 
| 3388 | 
            +
                  square {
         | 
| 3389 | 
            +
                    x 100
         | 
| 3390 | 
            +
                    y 100
         | 
| 3391 | 
            +
                    length 400
         | 
| 3392 | 
            +
                  }
         | 
| 3393 | 
            +
                  
         | 
| 3394 | 
            +
                  fill r: 102, g: 102, b: 204
         | 
| 3395 | 
            +
                }
         | 
| 3396 | 
            +
                path { # declarative stable path
         | 
| 3397 | 
            +
                  rectangle {
         | 
| 3398 | 
            +
                    x 0
         | 
| 3399 | 
            +
                    y 100
         | 
| 3400 | 
            +
                    width 100
         | 
| 3401 | 
            +
                    height 400
         | 
| 3402 | 
            +
                  }
         | 
| 3403 | 
            +
                  rectangle {
         | 
| 3404 | 
            +
                    x 100
         | 
| 3405 | 
            +
                    y 0
         | 
| 3406 | 
            +
                    width 400
         | 
| 3407 | 
            +
                    height 100
         | 
| 3408 | 
            +
                  }
         | 
| 3409 | 
            +
                  
         | 
| 3410 | 
            +
                  fill r: 204, g: 102, b: 204
         | 
| 3411 | 
            +
                }
         | 
| 3412 | 
            +
                path { # declarative stable path
         | 
| 3413 | 
            +
                  figure {
         | 
| 3414 | 
            +
                    x 100
         | 
| 3415 | 
            +
                    y 100
         | 
| 3416 | 
            +
                    
         | 
| 3417 | 
            +
                    line {
         | 
| 3418 | 
            +
                      x 100
         | 
| 3419 | 
            +
                      y 400
         | 
| 3420 | 
            +
                    }
         | 
| 3421 | 
            +
                    line {
         | 
| 3422 | 
            +
                      x 400
         | 
| 3423 | 
            +
                      y 100
         | 
| 3424 | 
            +
                    }
         | 
| 3425 | 
            +
                    line {
         | 
| 3426 | 
            +
                      x 400
         | 
| 3427 | 
            +
                      y 400
         | 
| 3428 | 
            +
                    }
         | 
| 3429 | 
            +
             | 
| 3430 | 
            +
                    closed true
         | 
| 3431 | 
            +
                  }
         | 
| 3432 | 
            +
             | 
| 3433 | 
            +
                  fill r: 202, g: 102, b: 104, a: 0.5
         | 
| 3434 | 
            +
                  stroke r: 0, g: 0, b: 0
         | 
| 3435 | 
            +
                }
         | 
| 3436 | 
            +
                path { # declarative stable path
         | 
| 3437 | 
            +
                  figure {
         | 
| 3438 | 
            +
                    x 0
         | 
| 3439 | 
            +
                    y 0
         | 
| 3440 | 
            +
                    
         | 
| 3441 | 
            +
                    bezier {
         | 
| 3442 | 
            +
                      c1_x 200
         | 
| 3443 | 
            +
                      c1_y 100
         | 
| 3444 | 
            +
                      c2_x 100
         | 
| 3445 | 
            +
                      c2_y 200
         | 
| 3446 | 
            +
                      end_x 400
         | 
| 3447 | 
            +
                      end_y 100
         | 
| 3448 | 
            +
                    }
         | 
| 3449 | 
            +
                    bezier {
         | 
| 3450 | 
            +
                      c1_x 300
         | 
| 3451 | 
            +
                      c1_y 100
         | 
| 3452 | 
            +
                      c2_x 100
         | 
| 3453 | 
            +
                      c2_y 300
         | 
| 3454 | 
            +
                      end_x 100
         | 
| 3455 | 
            +
                      end_y 400
         | 
| 3456 | 
            +
                    }
         | 
| 3457 | 
            +
                    bezier {
         | 
| 3458 | 
            +
                      c1_x 100
         | 
| 3459 | 
            +
                      c1_y 300
         | 
| 3460 | 
            +
                      c2_x 300
         | 
| 3461 | 
            +
                      c2_y 100
         | 
| 3462 | 
            +
                      end_x 400
         | 
| 3463 | 
            +
                      end_y 400
         | 
| 3464 | 
            +
                    }
         | 
| 3465 | 
            +
             | 
| 3466 | 
            +
                    closed true
         | 
| 3467 | 
            +
                  }
         | 
| 3468 | 
            +
             | 
| 3469 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3470 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3471 | 
            +
                }
         | 
| 3472 | 
            +
                path { # declarative stable path
         | 
| 3473 | 
            +
                  arc {
         | 
| 3474 | 
            +
                    x_center 200
         | 
| 3475 | 
            +
                    y_center 200
         | 
| 3476 | 
            +
                    radius 90
         | 
| 3477 | 
            +
                    start_angle 0
         | 
| 3478 | 
            +
                    sweep 360
         | 
| 3479 | 
            +
                    is_negative false
         | 
| 3480 | 
            +
                  }
         | 
| 3481 | 
            +
             | 
| 3482 | 
            +
                  fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3483 | 
            +
                  stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3484 | 
            +
                }
         | 
| 3485 | 
            +
              }
         | 
| 3486 | 
            +
            }.show
         | 
| 3487 | 
            +
            ```
         | 
| 3488 | 
            +
             | 
| 3489 | 
            +
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 3 (semi-declarative `on_draw` dynamic `path` approach):
         | 
| 3490 | 
            +
             | 
| 3491 | 
            +
            ```ruby
         | 
| 3492 | 
            +
            require 'glimmer-dsl-libui'
         | 
| 3493 | 
            +
             | 
| 3494 | 
            +
            include Glimmer
         | 
| 3495 | 
            +
             | 
| 3496 | 
            +
            window('Area Gallery', 400, 400) {
         | 
| 3497 | 
            +
              area {
         | 
| 3498 | 
            +
                on_draw do |area_draw_params|
         | 
| 3499 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3250 3500 | 
             
                    square(0, 0, 100)
         | 
| 3251 3501 | 
             
                    square(100, 100, 400)
         | 
| 3252 3502 |  | 
| 3253 3503 | 
             
                    fill r: 102, g: 102, b: 204
         | 
| 3254 3504 | 
             
                  }
         | 
| 3255 | 
            -
                  path { #  | 
| 3505 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3256 3506 | 
             
                    rectangle(0, 100, 100, 400)
         | 
| 3257 3507 | 
             
                    rectangle(100, 0, 400, 100)
         | 
| 3258 | 
            -
             | 
| 3508 | 
            +
             | 
| 3259 3509 | 
             
                    fill r: 204, g: 102, b: 204
         | 
| 3260 3510 | 
             
                  }
         | 
| 3261 | 
            -
                  path { #  | 
| 3511 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3262 3512 | 
             
                    figure(100, 100) {
         | 
| 3263 3513 | 
             
                      line(100, 400)
         | 
| 3264 3514 | 
             
                      line(400, 100)
         | 
| @@ -3270,7 +3520,7 @@ window('Area Gallery', 400, 400) { | |
| 3270 3520 | 
             
                    fill r: 202, g: 102, b: 104, a: 0.5
         | 
| 3271 3521 | 
             
                    stroke r: 0, g: 0, b: 0
         | 
| 3272 3522 | 
             
                  }
         | 
| 3273 | 
            -
                  path { #  | 
| 3523 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3274 3524 | 
             
                    figure(0, 0) {
         | 
| 3275 3525 | 
             
                      bezier(200, 100, 100, 200, 400, 100)
         | 
| 3276 3526 | 
             
                      bezier(300, 100, 100, 300, 100, 400)
         | 
| @@ -3282,18 +3532,18 @@ window('Area Gallery', 400, 400) { | |
| 3282 3532 | 
             
                    fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3283 3533 | 
             
                    stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3284 3534 | 
             
                  }
         | 
| 3285 | 
            -
                  path { #  | 
| 3535 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3286 3536 | 
             
                    arc(200, 200, 90, 0, 360, false)
         | 
| 3287 3537 |  | 
| 3288 3538 | 
             
                    fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3289 3539 | 
             
                    stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3290 3540 | 
             
                  }
         | 
| 3291 | 
            -
                 | 
| 3541 | 
            +
                end
         | 
| 3292 3542 | 
             
              }
         | 
| 3293 3543 | 
             
            }.show
         | 
| 3294 3544 | 
             
            ```
         | 
| 3295 3545 |  | 
| 3296 | 
            -
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version  | 
| 3546 | 
            +
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 4 (setting shape properties instead of arguments with semi-declarative `on_draw` dynamic `path` approach):
         | 
| 3297 3547 |  | 
| 3298 3548 | 
             
            ```ruby
         | 
| 3299 3549 | 
             
            require 'glimmer-dsl-libui'
         | 
| @@ -3301,9 +3551,9 @@ require 'glimmer-dsl-libui' | |
| 3301 3551 | 
             
            include Glimmer
         | 
| 3302 3552 |  | 
| 3303 3553 | 
             
            window('Area Gallery', 400, 400) {
         | 
| 3304 | 
            -
               | 
| 3305 | 
            -
                 | 
| 3306 | 
            -
                  path { #  | 
| 3554 | 
            +
              area {
         | 
| 3555 | 
            +
                on_draw do |area_draw_params|
         | 
| 3556 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3307 3557 | 
             
                    square {
         | 
| 3308 3558 | 
             
                      x 0
         | 
| 3309 3559 | 
             
                      y 0
         | 
| @@ -3317,7 +3567,7 @@ window('Area Gallery', 400, 400) { | |
| 3317 3567 |  | 
| 3318 3568 | 
             
                    fill r: 102, g: 102, b: 204
         | 
| 3319 3569 | 
             
                  }
         | 
| 3320 | 
            -
                  path { #  | 
| 3570 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3321 3571 | 
             
                    rectangle {
         | 
| 3322 3572 | 
             
                      x 0
         | 
| 3323 3573 | 
             
                      y 100
         | 
| @@ -3333,7 +3583,7 @@ window('Area Gallery', 400, 400) { | |
| 3333 3583 |  | 
| 3334 3584 | 
             
                    fill r: 204, g: 102, b: 204
         | 
| 3335 3585 | 
             
                  }
         | 
| 3336 | 
            -
                  path { #  | 
| 3586 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3337 3587 | 
             
                    figure {
         | 
| 3338 3588 | 
             
                      x 100
         | 
| 3339 3589 | 
             
                      y 100
         | 
| @@ -3357,7 +3607,7 @@ window('Area Gallery', 400, 400) { | |
| 3357 3607 | 
             
                    fill r: 202, g: 102, b: 104, a: 0.5
         | 
| 3358 3608 | 
             
                    stroke r: 0, g: 0, b: 0
         | 
| 3359 3609 | 
             
                  }
         | 
| 3360 | 
            -
                  path { #  | 
| 3610 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3361 3611 | 
             
                    figure {
         | 
| 3362 3612 | 
             
                      x 0
         | 
| 3363 3613 | 
             
                      y 0
         | 
| @@ -3393,7 +3643,7 @@ window('Area Gallery', 400, 400) { | |
| 3393 3643 | 
             
                    fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3394 3644 | 
             
                    stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3395 3645 | 
             
                  }
         | 
| 3396 | 
            -
                  path { #  | 
| 3646 | 
            +
                  path { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3397 3647 | 
             
                    arc {
         | 
| 3398 3648 | 
             
                      x_center 200
         | 
| 3399 3649 | 
             
                      y_center 200
         | 
| @@ -3406,183 +3656,346 @@ window('Area Gallery', 400, 400) { | |
| 3406 3656 | 
             
                    fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3407 3657 | 
             
                    stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3408 3658 | 
             
                  }
         | 
| 3409 | 
            -
                 | 
| 3659 | 
            +
                end
         | 
| 3410 3660 | 
             
              }
         | 
| 3411 3661 | 
             
            }.show
         | 
| 3412 3662 | 
             
            ```
         | 
| 3413 3663 |  | 
| 3414 | 
            -
             | 
| 3664 | 
            +
            ### Histogram
         | 
| 3665 | 
            +
             | 
| 3666 | 
            +
            [examples/histogram.rb](examples/histogram.rb)
         | 
| 3667 | 
            +
             | 
| 3668 | 
            +
            Run with this command from the root of the project if you cloned the project:
         | 
| 3669 | 
            +
             | 
| 3670 | 
            +
            ```
         | 
| 3671 | 
            +
            ruby -r './lib/glimmer-dsl-libui' examples/histogram.rb
         | 
| 3672 | 
            +
            ```
         | 
| 3673 | 
            +
             | 
| 3674 | 
            +
            Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
         | 
| 3675 | 
            +
             | 
| 3676 | 
            +
            ```
         | 
| 3677 | 
            +
            ruby -r glimmer-dsl-libui -e "require 'examples/histogram'"
         | 
| 3678 | 
            +
            ```
         | 
| 3679 | 
            +
             | 
| 3680 | 
            +
            Mac
         | 
| 3681 | 
            +
             | 
| 3682 | 
            +
            
         | 
| 3683 | 
            +
             | 
| 3684 | 
            +
            Linux
         | 
| 3685 | 
            +
             | 
| 3686 | 
            +
            
         | 
| 3687 | 
            +
             | 
| 3688 | 
            +
            [LibUI](https://github.com/kojix2/LibUI) Original Version:
         | 
| 3415 3689 |  | 
| 3416 3690 | 
             
            ```ruby
         | 
| 3417 | 
            -
             | 
| 3691 | 
            +
            # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
         | 
| 3418 3692 |  | 
| 3419 | 
            -
             | 
| 3693 | 
            +
            require 'libui'
         | 
| 3420 3694 |  | 
| 3421 | 
            -
             | 
| 3422 | 
            -
              vertical_box {
         | 
| 3423 | 
            -
                area {
         | 
| 3424 | 
            -
                  on_draw do |area_draw_params|
         | 
| 3425 | 
            -
                    path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3426 | 
            -
                      square(0, 0, 100)
         | 
| 3427 | 
            -
                      square(100, 100, 400)
         | 
| 3428 | 
            -
                      
         | 
| 3429 | 
            -
                      fill r: 102, g: 102, b: 204
         | 
| 3430 | 
            -
                    }
         | 
| 3431 | 
            -
                    path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3432 | 
            -
                      rectangle(0, 100, 100, 400)
         | 
| 3433 | 
            -
                      rectangle(100, 0, 400, 100)
         | 
| 3695 | 
            +
            UI = LibUI
         | 
| 3434 3696 |  | 
| 3435 | 
            -
             | 
| 3436 | 
            -
             | 
| 3437 | 
            -
             | 
| 3438 | 
            -
             | 
| 3439 | 
            -
             | 
| 3440 | 
            -
             | 
| 3441 | 
            -
             | 
| 3697 | 
            +
            X_OFF_LEFT   = 20
         | 
| 3698 | 
            +
            Y_OFF_TOP    = 20
         | 
| 3699 | 
            +
            X_OFF_RIGHT  = 20
         | 
| 3700 | 
            +
            Y_OFF_BOTTOM = 20
         | 
| 3701 | 
            +
            POINT_RADIUS = 5
         | 
| 3702 | 
            +
             | 
| 3703 | 
            +
            init         = UI.init
         | 
| 3704 | 
            +
            handler      = UI::FFI::AreaHandler.malloc
         | 
| 3705 | 
            +
            histogram    = UI.new_area(handler)
         | 
| 3706 | 
            +
            brush        = UI::FFI::DrawBrush.malloc
         | 
| 3707 | 
            +
            color_button = UI.new_color_button
         | 
| 3708 | 
            +
            blue         = 0x1E90FF
         | 
| 3709 | 
            +
            datapoints   = []
         | 
| 3710 | 
            +
             | 
| 3711 | 
            +
            def graph_size(area_width, area_height)
         | 
| 3712 | 
            +
              graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
         | 
| 3713 | 
            +
              graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
         | 
| 3714 | 
            +
              [graph_width, graph_height]
         | 
| 3715 | 
            +
            end
         | 
| 3442 3716 |  | 
| 3443 | 
            -
             | 
| 3444 | 
            -
                      }
         | 
| 3717 | 
            +
            matrix = UI::FFI::DrawMatrix.malloc
         | 
| 3445 3718 |  | 
| 3446 | 
            -
             | 
| 3447 | 
            -
             | 
| 3448 | 
            -
             | 
| 3449 | 
            -
                    path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3450 | 
            -
                      figure(0, 0) {
         | 
| 3451 | 
            -
                        bezier(200, 100, 100, 200, 400, 100)
         | 
| 3452 | 
            -
                        bezier(300, 100, 100, 300, 100, 400)
         | 
| 3453 | 
            -
                        bezier(100, 300, 300, 100, 400, 400)
         | 
| 3719 | 
            +
            def point_locations(datapoints, width, height)
         | 
| 3720 | 
            +
              xincr = width / 9.0 # 10 - 1 to make the last point be at the end
         | 
| 3721 | 
            +
              yincr = height / 100.0
         | 
| 3454 3722 |  | 
| 3455 | 
            -
             | 
| 3456 | 
            -
             | 
| 3723 | 
            +
              data = []
         | 
| 3724 | 
            +
              datapoints.each_with_index do |dp, i|
         | 
| 3725 | 
            +
                val = 100 - UI.spinbox_value(dp)
         | 
| 3726 | 
            +
                data << [xincr * i, yincr * val]
         | 
| 3727 | 
            +
                i += 1
         | 
| 3728 | 
            +
              end
         | 
| 3457 3729 |  | 
| 3458 | 
            -
             | 
| 3459 | 
            -
             | 
| 3460 | 
            -
                    }
         | 
| 3461 | 
            -
                    path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
         | 
| 3462 | 
            -
                      arc(200, 200, 90, 0, 360, false)
         | 
| 3730 | 
            +
              data
         | 
| 3731 | 
            +
            end
         | 
| 3463 3732 |  | 
| 3464 | 
            -
             | 
| 3465 | 
            -
             | 
| 3466 | 
            -
             | 
| 3467 | 
            -
             | 
| 3468 | 
            -
             | 
| 3469 | 
            -
               | 
| 3470 | 
            -
             | 
| 3733 | 
            +
            def construct_graph(datapoints, width, height, should_extend)
         | 
| 3734 | 
            +
              locations = point_locations(datapoints, width, height)
         | 
| 3735 | 
            +
              path = UI.draw_new_path(0) # winding
         | 
| 3736 | 
            +
              first_location = locations[0] # x and y
         | 
| 3737 | 
            +
              UI.draw_path_new_figure(path, first_location[0], first_location[1])
         | 
| 3738 | 
            +
              locations.each do |loc|
         | 
| 3739 | 
            +
                UI.draw_path_line_to(path, loc[0], loc[1])
         | 
| 3740 | 
            +
              end
         | 
| 3741 | 
            +
             | 
| 3742 | 
            +
              if should_extend
         | 
| 3743 | 
            +
                UI.draw_path_line_to(path, width, height)
         | 
| 3744 | 
            +
                UI.draw_path_line_to(path, 0, height)
         | 
| 3745 | 
            +
                UI.draw_path_close_figure(path)
         | 
| 3746 | 
            +
              end
         | 
| 3747 | 
            +
             | 
| 3748 | 
            +
              UI.draw_path_end(path)
         | 
| 3749 | 
            +
             | 
| 3750 | 
            +
              path
         | 
| 3751 | 
            +
            end
         | 
| 3752 | 
            +
             | 
| 3753 | 
            +
            handler_draw_event = Fiddle::Closure::BlockCaller.new(
         | 
| 3754 | 
            +
              0, [1, 1, 1]
         | 
| 3755 | 
            +
            ) do |_area_handler, _area, area_draw_params|
         | 
| 3756 | 
            +
              area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
         | 
| 3757 | 
            +
              path = UI.draw_new_path(0) # winding
         | 
| 3758 | 
            +
              UI.draw_path_add_rectangle(path, 0, 0, area_draw_params.AreaWidth, area_draw_params.AreaHeight)
         | 
| 3759 | 
            +
              UI.draw_path_end(path)
         | 
| 3760 | 
            +
              set_solid_brush(brush, 0xFFFFFF, 1.0) # white
         | 
| 3761 | 
            +
              UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
         | 
| 3762 | 
            +
              UI.draw_free_path(path)
         | 
| 3763 | 
            +
              dsp = UI::FFI::DrawStrokeParams.malloc
         | 
| 3764 | 
            +
              dsp.Cap = 0 # flat
         | 
| 3765 | 
            +
              dsp.Join = 0 # miter
         | 
| 3766 | 
            +
              dsp.Thickness = 2
         | 
| 3767 | 
            +
              dsp.MiterLimit = 10 # DEFAULT_MITER_LIMIT
         | 
| 3768 | 
            +
              dashes = Fiddle::Pointer.malloc(8)
         | 
| 3769 | 
            +
              dsp.Dashes = dashes
         | 
| 3770 | 
            +
              dsp.NumDashes = 0
         | 
| 3771 | 
            +
              dsp.DashPhase = 0
         | 
| 3772 | 
            +
             | 
| 3773 | 
            +
              # draw axes
         | 
| 3774 | 
            +
              set_solid_brush(brush, 0x000000, 1.0) # black
         | 
| 3775 | 
            +
              graph_width, graph_height = *graph_size(area_draw_params.AreaWidth, area_draw_params.AreaHeight)
         | 
| 3776 | 
            +
             | 
| 3777 | 
            +
              path = UI.draw_new_path(0) # winding
         | 
| 3778 | 
            +
              UI.draw_path_new_figure(path, X_OFF_LEFT, Y_OFF_TOP)
         | 
| 3779 | 
            +
              UI.draw_path_line_to(path, X_OFF_LEFT, Y_OFF_TOP + graph_height)
         | 
| 3780 | 
            +
              UI.draw_path_line_to(path, X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
         | 
| 3781 | 
            +
              UI.draw_path_end(path)
         | 
| 3782 | 
            +
              UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
         | 
| 3783 | 
            +
              UI.draw_free_path(path)
         | 
| 3784 | 
            +
             | 
| 3785 | 
            +
              # now transform the coordinate space so (0, 0) is the top-left corner of the graph
         | 
| 3786 | 
            +
              UI.draw_matrix_set_identity(matrix)
         | 
| 3787 | 
            +
              UI.draw_matrix_translate(matrix, X_OFF_LEFT, Y_OFF_TOP)
         | 
| 3788 | 
            +
              UI.draw_transform(area_draw_params.Context, matrix)
         | 
| 3789 | 
            +
             | 
| 3790 | 
            +
              # now get the color for the graph itself and set up the brush
         | 
| 3791 | 
            +
              #  uiColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA)
         | 
| 3792 | 
            +
              graph_r = Fiddle::Pointer.malloc(8) # double
         | 
| 3793 | 
            +
              graph_g = Fiddle::Pointer.malloc(8) # double
         | 
| 3794 | 
            +
              graph_b = Fiddle::Pointer.malloc(8) # double
         | 
| 3795 | 
            +
              graph_a = Fiddle::Pointer.malloc(8) # double
         | 
| 3796 | 
            +
             | 
| 3797 | 
            +
              UI.color_button_color(color_button, graph_r, graph_g, graph_b, graph_a)
         | 
| 3798 | 
            +
              brush.Type = 0 # solid
         | 
| 3799 | 
            +
              brush.R = graph_r[0, 8].unpack1('d')
         | 
| 3800 | 
            +
              brush.G = graph_g[0, 8].unpack1('d')
         | 
| 3801 | 
            +
              brush.B = graph_b[0, 8].unpack1('d')
         | 
| 3802 | 
            +
             | 
| 3803 | 
            +
              # now create the fill for the graph below the graph line
         | 
| 3804 | 
            +
              path = construct_graph(datapoints, graph_width, graph_height, true)
         | 
| 3805 | 
            +
              brush.A = graph_a[0, 8].unpack1('d') / 2.0
         | 
| 3806 | 
            +
              UI.draw_fill(area_draw_params.Context, path, brush)
         | 
| 3807 | 
            +
              UI.draw_free_path(path)
         | 
| 3808 | 
            +
             | 
| 3809 | 
            +
              # now draw the histogram line
         | 
| 3810 | 
            +
              path = construct_graph(datapoints, graph_width, graph_height, false)
         | 
| 3811 | 
            +
              brush.A = graph_a[0, 8].unpack1('d')
         | 
| 3812 | 
            +
              UI.draw_stroke(area_draw_params.Context, path, brush, dsp)
         | 
| 3813 | 
            +
              UI.draw_free_path(path)
         | 
| 3814 | 
            +
            end
         | 
| 3815 | 
            +
             | 
| 3816 | 
            +
            handler.Draw         = handler_draw_event
         | 
| 3817 | 
            +
             | 
| 3818 | 
            +
            # Assigning to local variables
         | 
| 3819 | 
            +
            # This is intended to protect Fiddle::Closure from garbage collection.
         | 
| 3820 | 
            +
            # See https://github.com/kojix2/LibUI/issues/8
         | 
| 3821 | 
            +
            handler.MouseEvent   = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
         | 
| 3822 | 
            +
            handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
         | 
| 3823 | 
            +
            handler.DragBroken   = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
         | 
| 3824 | 
            +
            handler.KeyEvent     = (c4 = Fiddle::Closure::BlockCaller.new(1, [0]) { 0 })
         | 
| 3825 | 
            +
             | 
| 3826 | 
            +
            UI.freeInitError(init) unless init.nil?
         | 
| 3827 | 
            +
             | 
| 3828 | 
            +
            hbox = UI.new_horizontal_box
         | 
| 3829 | 
            +
            UI.box_set_padded(hbox, 1)
         | 
| 3830 | 
            +
             | 
| 3831 | 
            +
            vbox = UI.new_vertical_box
         | 
| 3832 | 
            +
            UI.box_set_padded(vbox, 1)
         | 
| 3833 | 
            +
            UI.box_append(hbox, vbox, 0)
         | 
| 3834 | 
            +
            UI.box_append(hbox, histogram, 1)
         | 
| 3835 | 
            +
             | 
| 3836 | 
            +
            datapoints = Array.new(10) do
         | 
| 3837 | 
            +
              UI.new_spinbox(0, 100).tap do |datapoint|
         | 
| 3838 | 
            +
                UI.spinbox_set_value(datapoint, Random.new.rand(90))
         | 
| 3839 | 
            +
                UI.spinbox_on_changed(datapoint) do
         | 
| 3840 | 
            +
                  UI.area_queue_redraw_all(histogram)
         | 
| 3841 | 
            +
                end
         | 
| 3842 | 
            +
                UI.box_append(vbox, datapoint, 0)
         | 
| 3843 | 
            +
              end
         | 
| 3844 | 
            +
            end
         | 
| 3845 | 
            +
             | 
| 3846 | 
            +
            def set_solid_brush(brush, color, alpha)
         | 
| 3847 | 
            +
              brush.Type = 0 # solid
         | 
| 3848 | 
            +
              brush.R = ((color >> 16) & 0xFF) / 255.0
         | 
| 3849 | 
            +
              brush.G = ((color >> 8) & 0xFF) / 255.0
         | 
| 3850 | 
            +
              brush.B = (color & 0xFF) / 255.0
         | 
| 3851 | 
            +
              brush.A = alpha
         | 
| 3852 | 
            +
              brush
         | 
| 3853 | 
            +
            end
         | 
| 3854 | 
            +
             | 
| 3855 | 
            +
            set_solid_brush(brush, blue, 1.0)
         | 
| 3856 | 
            +
            UI.color_button_set_color(color_button, brush.R, brush.G, brush.B, brush.A)
         | 
| 3857 | 
            +
             | 
| 3858 | 
            +
            UI.color_button_on_changed(color_button) do
         | 
| 3859 | 
            +
              UI.area_queue_redraw_all(histogram)
         | 
| 3860 | 
            +
            end
         | 
| 3861 | 
            +
             | 
| 3862 | 
            +
            UI.box_append(vbox, color_button, 0)
         | 
| 3863 | 
            +
             | 
| 3864 | 
            +
            MAIN_WINDOW = UI.new_window('histogram example', 640, 480, 1)
         | 
| 3865 | 
            +
            UI.window_set_margined(MAIN_WINDOW, 1)
         | 
| 3866 | 
            +
            UI.window_set_child(MAIN_WINDOW, hbox)
         | 
| 3867 | 
            +
             | 
| 3868 | 
            +
            should_quit = proc do |_ptr|
         | 
| 3869 | 
            +
              UI.control_destroy(MAIN_WINDOW)
         | 
| 3870 | 
            +
              UI.quit
         | 
| 3871 | 
            +
              0
         | 
| 3872 | 
            +
            end
         | 
| 3873 | 
            +
             | 
| 3874 | 
            +
            UI.window_on_closing(MAIN_WINDOW, should_quit)
         | 
| 3875 | 
            +
            UI.on_should_quit(should_quit)
         | 
| 3876 | 
            +
            UI.control_show(MAIN_WINDOW)
         | 
| 3877 | 
            +
             | 
| 3878 | 
            +
            UI.main
         | 
| 3879 | 
            +
            UI.quit
         | 
| 3471 3880 | 
             
            ```
         | 
| 3472 3881 |  | 
| 3473 | 
            -
             | 
| 3882 | 
            +
            [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
         | 
| 3474 3883 |  | 
| 3475 3884 | 
             
            ```ruby
         | 
| 3885 | 
            +
            # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
         | 
| 3886 | 
            +
             | 
| 3476 3887 | 
             
            require 'glimmer-dsl-libui'
         | 
| 3477 3888 |  | 
| 3478 3889 | 
             
            include Glimmer
         | 
| 3479 3890 |  | 
| 3480 | 
            -
             | 
| 3481 | 
            -
             | 
| 3482 | 
            -
             | 
| 3483 | 
            -
             | 
| 3484 | 
            -
             | 
| 3485 | 
            -
             | 
| 3486 | 
            -
             | 
| 3487 | 
            -
             | 
| 3488 | 
            -
             | 
| 3489 | 
            -
             | 
| 3490 | 
            -
             | 
| 3491 | 
            -
             | 
| 3492 | 
            -
             | 
| 3493 | 
            -
             | 
| 3494 | 
            -
             | 
| 3891 | 
            +
            X_OFF_LEFT   = 20
         | 
| 3892 | 
            +
            Y_OFF_TOP    = 20
         | 
| 3893 | 
            +
            X_OFF_RIGHT  = 20
         | 
| 3894 | 
            +
            Y_OFF_BOTTOM = 20
         | 
| 3895 | 
            +
            POINT_RADIUS = 5
         | 
| 3896 | 
            +
             | 
| 3897 | 
            +
            COLOR_BLUE   = 0x1E90FF
         | 
| 3898 | 
            +
             | 
| 3899 | 
            +
            def graph_size(area_width, area_height)
         | 
| 3900 | 
            +
              graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
         | 
| 3901 | 
            +
              graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
         | 
| 3902 | 
            +
              [graph_width, graph_height]
         | 
| 3903 | 
            +
            end
         | 
| 3904 | 
            +
             | 
| 3905 | 
            +
            def point_locations(datapoints, width, height)
         | 
| 3906 | 
            +
              xincr = width / 9.0 # 10 - 1 to make the last point be at the end
         | 
| 3907 | 
            +
              yincr = height / 100.0
         | 
| 3908 | 
            +
             | 
| 3909 | 
            +
              data = []
         | 
| 3910 | 
            +
              datapoints.each_with_index do |dp, i|
         | 
| 3911 | 
            +
                val = 100 - dp.value
         | 
| 3912 | 
            +
                data << [xincr * i, yincr * val]
         | 
| 3913 | 
            +
                i += 1
         | 
| 3914 | 
            +
              end
         | 
| 3915 | 
            +
             | 
| 3916 | 
            +
              data
         | 
| 3917 | 
            +
            end
         | 
| 3918 | 
            +
             | 
| 3919 | 
            +
            def graph_path(datapoints, width, height, should_extend, &block)
         | 
| 3920 | 
            +
              locations = point_locations(datapoints, width, height)
         | 
| 3921 | 
            +
              path {
         | 
| 3922 | 
            +
                first_location = locations[0] # x and y
         | 
| 3923 | 
            +
                figure(first_location[0], first_location[1]) {
         | 
| 3924 | 
            +
                  locations.each do |loc|
         | 
| 3925 | 
            +
                    line(loc[0], loc[1])
         | 
| 3926 | 
            +
                  end
         | 
| 3927 | 
            +
                  if should_extend
         | 
| 3928 | 
            +
                    line(width, height)
         | 
| 3929 | 
            +
                    line(0, height)
         | 
| 3930 | 
            +
                    
         | 
| 3931 | 
            +
                    closed true
         | 
| 3932 | 
            +
                  end
         | 
| 3933 | 
            +
                }
         | 
| 3934 | 
            +
                
         | 
| 3935 | 
            +
                # now transform the coordinate space so (0, 0) is the top-left corner of the graph
         | 
| 3936 | 
            +
                transform {
         | 
| 3937 | 
            +
                  translate X_OFF_LEFT, Y_OFF_TOP
         | 
| 3938 | 
            +
                }
         | 
| 3939 | 
            +
                
         | 
| 3940 | 
            +
                block.call
         | 
| 3941 | 
            +
              }
         | 
| 3942 | 
            +
            end
         | 
| 3943 | 
            +
             | 
| 3944 | 
            +
            window('histogram example', 640, 480) {
         | 
| 3945 | 
            +
              margined true
         | 
| 3946 | 
            +
              
         | 
| 3947 | 
            +
              horizontal_box {
         | 
| 3948 | 
            +
                vertical_box {
         | 
| 3949 | 
            +
                  stretchy false
         | 
| 3950 | 
            +
                  
         | 
| 3951 | 
            +
                  @datapoints = 10.times.map do
         | 
| 3952 | 
            +
                    spinbox(0, 100) { |datapoint|
         | 
| 3953 | 
            +
                      stretchy false
         | 
| 3954 | 
            +
                      value Random.new.rand(90)
         | 
| 3495 3955 |  | 
| 3496 | 
            -
                       | 
| 3956 | 
            +
                      on_changed do
         | 
| 3957 | 
            +
                        @area.queue_redraw_all
         | 
| 3958 | 
            +
                      end
         | 
| 3497 3959 | 
             
                    }
         | 
| 3498 | 
            -
             | 
| 3499 | 
            -
             | 
| 3500 | 
            -
             | 
| 3501 | 
            -
             | 
| 3502 | 
            -
             | 
| 3503 | 
            -
             | 
| 3504 | 
            -
             | 
| 3505 | 
            -
                       | 
| 3506 | 
            -
             | 
| 3507 | 
            -
             | 
| 3508 | 
            -
             | 
| 3509 | 
            -
             | 
| 3510 | 
            -
             | 
| 3960 | 
            +
                  end
         | 
| 3961 | 
            +
                  
         | 
| 3962 | 
            +
                  @color_button = color_button {
         | 
| 3963 | 
            +
                    stretchy false
         | 
| 3964 | 
            +
                    color COLOR_BLUE
         | 
| 3965 | 
            +
                    
         | 
| 3966 | 
            +
                    on_changed do
         | 
| 3967 | 
            +
                      @area.queue_redraw_all
         | 
| 3968 | 
            +
                    end
         | 
| 3969 | 
            +
                  }
         | 
| 3970 | 
            +
                }
         | 
| 3971 | 
            +
                
         | 
| 3972 | 
            +
                @area = area {
         | 
| 3973 | 
            +
                  on_draw do |area_draw_params|
         | 
| 3974 | 
            +
                    path {
         | 
| 3975 | 
            +
                      rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height])
         | 
| 3511 3976 |  | 
| 3512 | 
            -
                      fill  | 
| 3977 | 
            +
                      fill color: 0xFFFFFF
         | 
| 3513 3978 | 
             
                    }
         | 
| 3514 | 
            -
                     | 
| 3515 | 
            -
             | 
| 3516 | 
            -
             | 
| 3517 | 
            -
             | 
| 3518 | 
            -
             | 
| 3519 | 
            -
                        line  | 
| 3520 | 
            -
             | 
| 3521 | 
            -
                          y 400
         | 
| 3522 | 
            -
                        }
         | 
| 3523 | 
            -
                        line {
         | 
| 3524 | 
            -
                          x 400
         | 
| 3525 | 
            -
                          y 100
         | 
| 3526 | 
            -
                        }
         | 
| 3527 | 
            -
                        line {
         | 
| 3528 | 
            -
                          x 400
         | 
| 3529 | 
            -
                          y 400
         | 
| 3530 | 
            -
                        }
         | 
| 3531 | 
            -
              
         | 
| 3532 | 
            -
                        closed true
         | 
| 3979 | 
            +
                    
         | 
| 3980 | 
            +
                    graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
         | 
| 3981 | 
            +
                  
         | 
| 3982 | 
            +
                    path {
         | 
| 3983 | 
            +
                      figure(X_OFF_LEFT, Y_OFF_TOP) {
         | 
| 3984 | 
            +
                        line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
         | 
| 3985 | 
            +
                        line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
         | 
| 3533 3986 | 
             
                      }
         | 
| 3534 | 
            -
             | 
| 3535 | 
            -
                       | 
| 3536 | 
            -
                      stroke r: 0, g: 0, b: 0
         | 
| 3987 | 
            +
                      
         | 
| 3988 | 
            +
                      stroke color: 0x000000, thickness: 2, miter_limit: 10
         | 
| 3537 3989 | 
             
                    }
         | 
| 3538 | 
            -
             | 
| 3539 | 
            -
             | 
| 3540 | 
            -
             | 
| 3541 | 
            -
             | 
| 3542 | 
            -
                        
         | 
| 3543 | 
            -
                        bezier {
         | 
| 3544 | 
            -
                          c1_x 200
         | 
| 3545 | 
            -
                          c1_y 100
         | 
| 3546 | 
            -
                          c2_x 100
         | 
| 3547 | 
            -
                          c2_y 200
         | 
| 3548 | 
            -
                          end_x 400
         | 
| 3549 | 
            -
                          end_y 100
         | 
| 3550 | 
            -
                        }
         | 
| 3551 | 
            -
                        bezier {
         | 
| 3552 | 
            -
                          c1_x 300
         | 
| 3553 | 
            -
                          c1_y 100
         | 
| 3554 | 
            -
                          c2_x 100
         | 
| 3555 | 
            -
                          c2_y 300
         | 
| 3556 | 
            -
                          end_x 100
         | 
| 3557 | 
            -
                          end_y 400
         | 
| 3558 | 
            -
                        }
         | 
| 3559 | 
            -
                        bezier {
         | 
| 3560 | 
            -
                          c1_x 100
         | 
| 3561 | 
            -
                          c1_y 300
         | 
| 3562 | 
            -
                          c2_x 300
         | 
| 3563 | 
            -
                          c2_y 100
         | 
| 3564 | 
            -
                          end_x 400
         | 
| 3565 | 
            -
                          end_y 400
         | 
| 3566 | 
            -
                        }
         | 
| 3567 | 
            -
              
         | 
| 3568 | 
            -
                        closed true
         | 
| 3569 | 
            -
                      }
         | 
| 3570 | 
            -
              
         | 
| 3571 | 
            -
                      fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3572 | 
            -
                      stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3990 | 
            +
                  
         | 
| 3991 | 
            +
                    # now create the fill for the graph below the graph line
         | 
| 3992 | 
            +
                    graph_path(@datapoints, graph_width, graph_height, true) {
         | 
| 3993 | 
            +
                      fill @color_button.color.merge(a: 0.5)
         | 
| 3573 3994 | 
             
                    }
         | 
| 3574 | 
            -
                     | 
| 3575 | 
            -
             | 
| 3576 | 
            -
             | 
| 3577 | 
            -
             | 
| 3578 | 
            -
                        radius 90
         | 
| 3579 | 
            -
                        start_angle 0
         | 
| 3580 | 
            -
                        sweep 360
         | 
| 3581 | 
            -
                        is_negative false
         | 
| 3582 | 
            -
                      }
         | 
| 3583 | 
            -
              
         | 
| 3584 | 
            -
                      fill r: 202, g: 102, b: 204, a: 0.5
         | 
| 3585 | 
            -
                      stroke thickness: 2, r: 0, g: 0, b: 0
         | 
| 3995 | 
            +
                    
         | 
| 3996 | 
            +
                    # now draw the histogram line
         | 
| 3997 | 
            +
                    graph_path(@datapoints, graph_width, graph_height, false) {
         | 
| 3998 | 
            +
                      stroke @color_button.color.merge(thickness: 2, miter_limit: 10)
         | 
| 3586 3999 | 
             
                    }
         | 
| 3587 4000 | 
             
                  end
         | 
| 3588 4001 | 
             
                }
         | 
| @@ -3590,6 +4003,62 @@ window('Area Gallery', 400, 400) { | |
| 3590 4003 | 
             
            }.show
         | 
| 3591 4004 | 
             
            ```
         | 
| 3592 4005 |  | 
| 4006 | 
            +
            ### Basic Transform
         | 
| 4007 | 
            +
             | 
| 4008 | 
            +
            [examples/basic_transform.rb](examples/basic_transform.rb)
         | 
| 4009 | 
            +
             | 
| 4010 | 
            +
            Run with this command from the root of the project if you cloned the project:
         | 
| 4011 | 
            +
             | 
| 4012 | 
            +
            ```
         | 
| 4013 | 
            +
            ruby -r './lib/glimmer-dsl-libui' examples/basic_transform.rb
         | 
| 4014 | 
            +
            ```
         | 
| 4015 | 
            +
             | 
| 4016 | 
            +
            Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
         | 
| 4017 | 
            +
             | 
| 4018 | 
            +
            ```
         | 
| 4019 | 
            +
            ruby -r glimmer-dsl-libui -e "require 'examples/basic_transform'"
         | 
| 4020 | 
            +
            ```
         | 
| 4021 | 
            +
             | 
| 4022 | 
            +
            Mac
         | 
| 4023 | 
            +
             | 
| 4024 | 
            +
            
         | 
| 4025 | 
            +
             | 
| 4026 | 
            +
            Linux
         | 
| 4027 | 
            +
             | 
| 4028 | 
            +
            
         | 
| 4029 | 
            +
             | 
| 4030 | 
            +
            New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
         | 
| 4031 | 
            +
             | 
| 4032 | 
            +
            ```ruby
         | 
| 4033 | 
            +
            require 'glimmer-dsl-libui'
         | 
| 4034 | 
            +
             | 
| 4035 | 
            +
            include Glimmer
         | 
| 4036 | 
            +
             | 
| 4037 | 
            +
            window('Basic Transform', 350, 350) {
         | 
| 4038 | 
            +
              area {
         | 
| 4039 | 
            +
                path {
         | 
| 4040 | 
            +
                  square(0, 0, 350)
         | 
| 4041 | 
            +
                  
         | 
| 4042 | 
            +
                  fill r: 255, g: 255, b: 0
         | 
| 4043 | 
            +
                }
         | 
| 4044 | 
            +
                40.times do |n|
         | 
| 4045 | 
            +
                  path {
         | 
| 4046 | 
            +
                    square(0, 0, 100)
         | 
| 4047 | 
            +
                    
         | 
| 4048 | 
            +
                    fill r: [255 - n*5, 0].max, g: [n*5, 255].min, b: 0, a: 0.5
         | 
| 4049 | 
            +
                    stroke color: 0, thickness: 2
         | 
| 4050 | 
            +
                    transform {
         | 
| 4051 | 
            +
                      skew 0.15, 0.15
         | 
| 4052 | 
            +
                      translate 50, 50
         | 
| 4053 | 
            +
                      rotate 100, 100, -9 * n
         | 
| 4054 | 
            +
                      scale 1.1, 1.1
         | 
| 4055 | 
            +
                    }
         | 
| 4056 | 
            +
                  }
         | 
| 4057 | 
            +
                end
         | 
| 4058 | 
            +
              }
         | 
| 4059 | 
            +
            }.show
         | 
| 4060 | 
            +
            ```
         | 
| 4061 | 
            +
             | 
| 3593 4062 | 
             
            ## Contributing to glimmer-dsl-libui
         | 
| 3594 4063 |  | 
| 3595 4064 | 
             
            -   Check out the latest master to make sure the feature hasn't been
         |