glimmer-dsl-libui 0.9.7 → 0.10.0

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.9.7
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.10.0
2
2
  ## Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library ([Fukuoka Award Winning](http://www.digitalfukuoka.jp/topics/187?locale=ja))
3
3
  ### The Quickest Way From Zero To GUI
4
4
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
@@ -351,10 +351,10 @@ Learn more about the differences between various [Glimmer](https://github.com/An
351
351
  - [Run Application](#run-application)
352
352
  - [Run Examples](#run-examples)
353
353
  - [Scaffold Application](#scaffold-application)
354
- - [Scaffold Custom Window](#scaffold-custom-window)
355
354
  - [Scaffold Custom Control](#scaffold-custom-control)
356
- - [Scaffold Custom Window Gem](#scaffold-custom-window-gem)
355
+ - [Scaffold Custom Window](#scaffold-custom-window)
357
356
  - [Scaffold Custom Control Gem](#scaffold-custom-control-gem)
357
+ - [Scaffold Custom Window Gem](#scaffold-custom-window-gem)
358
358
  - [List Custom Window Gems](#list-custom-window-gems)
359
359
  - [List Custom Control Gems](#list-custom-control-gems)
360
360
  - [List Glimmer DSLs](#list-glimmer-dsls)
@@ -381,9 +381,9 @@ Learn more about the differences between various [Glimmer](https://github.com/An
381
381
  - [Area Composite Shape](#area-composite-shape)
382
382
  - [Area Animation](#area-animation)
383
383
  - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
384
- - [Custom Controls](#custom-controls)
385
- - [Method-Based Custom Controls](#method-based-custom-controls)
386
- - [Class-Based Custom Controls](#class-based-custom-controls)
384
+ - [Custom Components](#custom-components)
385
+ - [Method-Based Custom Components](#method-based-custom-components)
386
+ - [Class-Based Custom Components](#class-based-custom-components)
387
387
  - [Observer Pattern](#observer-pattern)
388
388
  - [Data-Binding](#data-binding)
389
389
  - [Bidirectional (Two-Way) Data-Binding](#bidirectional-two-way-data-binding)
@@ -428,7 +428,7 @@ gem install glimmer-dsl-libui
428
428
  Or install via Bundler `Gemfile`:
429
429
 
430
430
  ```ruby
431
- gem 'glimmer-dsl-libui', '~> 0.9.7'
431
+ gem 'glimmer-dsl-libui', '~> 0.10.0'
432
432
  ```
433
433
 
434
434
  Test that installation worked by running the [Glimmer Meta-Example](#examples):
@@ -624,7 +624,7 @@ Mac | Windows | Linux
624
624
 
625
625
  ### Scaffold Application
626
626
 
627
- Application scaffolding enables automatically generating the directories/files of a new desktop GUI application that follows the MVC architecture and can be packaged as a Ruby gem that includes a binary script for running the app conveniently.
627
+ Application scaffolding enables automatically generating the directories/files of a new desktop GUI application that follows the MVC architecture and can be packaged as a Ruby gem that includes an executable script for running the app conveniently. It also ensures that software engineers follow the recommended Glimmer DSL for LibUI conventions and best practices. Application Scaffolding greatly improves software engineering productivity when building desktop applications with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui).
628
628
 
629
629
  Scaffold Glimmer DSL for LibUI application with this command:
630
630
 
@@ -722,7 +722,7 @@ Or by using the raw rake command:
722
722
  rake gemspec:generate
723
723
  ```
724
724
 
725
- Once you install the gem (e.g. `gem install hello_world`), you can simply run the app with its binary script:
725
+ Once you install the gem (e.g. `gem install hello_world`), you can simply run the app with its executable script:
726
726
 
727
727
  ```
728
728
  app_name
@@ -736,169 +736,17 @@ hello_world
736
736
 
737
737
  ![glimmer-dsl-libui-mac-scaffold-app-initial-screen.png](images/glimmer-dsl-libui-mac-scaffold-app-initial-screen.png)
738
738
 
739
- ### Scaffold Custom Window
740
-
741
- When you are in a scaffolded application, you can scaffold a new custom window (a window that you can put anything in to represent a view concept in your application) by running this command:
742
-
743
- ```
744
- glimmer scaffold:customwindow[name,namespace]
745
- ```
746
-
747
- The `name` represents the custom window view class name (it can be underscored, and Glimmer will automatically classify it).
748
-
749
- The `namespace` is optional and represents the module that the custom window view class will live under. If left off, the main application class namespace is used (e.g. the top-level `HelloWorld` class namespace for a `hello_world` application).
750
-
751
- You can also use the shorter `cw` alias for `customwindow`:
752
-
753
- ```
754
- glimmer scaffold:cw[name,namespace]
755
- ```
756
-
757
- For example by running this command under a `hello_world` application:
758
-
759
- ```
760
- glimmer scaffold:cw[greeting_window]
761
- ```
762
-
763
- That will generate this class under `app/hello_world/view/greeting_window`:
764
-
765
- ```ruby
766
- class HelloWorld
767
- module View
768
- class GreetingWindow
769
- include Glimmer::LibUI::CustomWindow
770
-
771
-
772
- ## Add options like the following to configure CustomWindow by outside consumers
773
- #
774
- # options :title, :background_color
775
- # option :width, default: 320
776
- # option :height, default: 240
777
-
778
- ## Use before_body block to pre-initialize variables to use in body and
779
- # to setup application menu
780
- #
781
- # before_body do
782
- #
783
- # end
784
-
785
- ## Use after_body block to setup observers for controls in body
786
- #
787
- # after_body do
788
- #
789
- # end
790
-
791
- ## Add control content inside custom window body
792
- ## Top-most control must be a window or another custom window
793
- #
794
- body {
795
- window {
796
- # Replace example content below with custom window content
797
- content_size 240, 240
798
- title 'Hello World'
799
-
800
- margined true
801
-
802
- label {
803
- text 'Hello World'
804
- }
805
- }
806
- }
807
- end
808
- end
809
- end
810
- ```
811
-
812
- When the generated file is required in another view (e.g. `require 'hello_world/view/greeting_window'`), the custom window keyword `greeting_window` become available and reusable, like by calling:
813
-
814
- ```ruby
815
- greeting_window.show
816
- ```
817
-
818
- Here is an example that generates a custom window with a namespace:
819
-
820
- ```
821
- glimmer scaffold:cw[train,station]
822
- ```
823
-
824
- That will generate this class under `app/station/view/train`:
825
-
826
- ```ruby
827
- module Station
828
- module View
829
- class Train
830
- include Glimmer::LibUI::CustomWindow
831
-
832
-
833
- ## Add options like the following to configure CustomWindow by outside consumers
834
- #
835
- # options :title, :background_color
836
- # option :width, default: 320
837
- # option :height, default: 240
838
-
839
- ## Use before_body block to pre-initialize variables to use in body and
840
- # to setup application menu
841
- #
842
- # before_body do
843
- #
844
- # end
845
-
846
- ## Use after_body block to setup observers for controls in body
847
- #
848
- # after_body do
849
- #
850
- # end
851
-
852
- ## Add control content inside custom window body
853
- ## Top-most control must be a window or another custom window
854
- #
855
- body {
856
- window {
857
- # Replace example content below with custom window content
858
- content_size 240, 240
859
- title 'Station'
860
-
861
- margined true
862
-
863
- label {
864
- text 'Station'
865
- }
866
- }
867
- }
868
- end
869
- end
870
- end
871
- ```
872
-
873
- When that file is required in another view (e.g. `require 'station/view/train'`), the `train` keyword becomes available:
874
-
875
- ```ruby
876
- train.show
877
- ```
878
-
879
- If for whatever reason, you end up with 2 custom window views having the same name with different namespaces, then you can invoke the specific custom window you want by including the Ruby namespace in underscored format separated by double-underscores:
880
-
881
- ```ruby
882
- station__view__train.show
883
- ```
884
-
885
- Or another `train` custom window view:
886
-
887
- ```ruby
888
- hello_world__view__train.show
889
- ```
890
-
891
739
  ### Scaffold Custom Control
892
740
 
893
- When you are in a scaffolded application, you can scaffold a new custom control (a control that you can put anything in to represent a view concept in your application) by running this command:
741
+ When you are in a scaffolded application, you can scaffold a new [custom control](#custom-components) (a control that you can put anything in to represent a view concept in your application) by running this command:
894
742
 
895
743
  ```
896
744
  glimmer scaffold:customcontrol[name,namespace]
897
745
  ```
898
746
 
899
- The `name` represents the custom control view class name (it can be underscored, and Glimmer will automatically classify it).
747
+ The `name` represents the [custom control](#custom-components) view class name (it can be underscored, and Glimmer will automatically classify it).
900
748
 
901
- The `namespace` is optional and represents the module that the custom control view class will live under. If left off, the main application class namespace is used (e.g. the top-level `HelloWorld` class namespace for a `hello_world` application).
749
+ The `namespace` is optional and represents the module that the [custom control](#custom-components) view class will live under. If left off, the main application class namespace is used (e.g. the top-level `HelloWorld` class namespace for a `hello_world` application).
902
750
 
903
751
  You can also use the shorter `cc` alias for `customcontrol`:
904
752
 
@@ -969,7 +817,7 @@ class HelloWorld
969
817
  end
970
818
  ```
971
819
 
972
- When the generated file is required in another view (e.g. `require 'hello_world/view/model_form'`), the custom control keyword `model_form` become available and reusable, like by calling:
820
+ When the generated file is required in another view (e.g. `require 'hello_world/view/model_form'`), the [custom control](#custom-components) keyword `model_form` become available and reusable, like by calling:
973
821
 
974
822
  ```ruby
975
823
  window {
@@ -980,7 +828,7 @@ window {
980
828
  }
981
829
  ```
982
830
 
983
- Here is an example that generates a custom control with a namespace:
831
+ Here is an example that generates a [custom control](#custom-components) with a namespace:
984
832
 
985
833
  ```
986
834
  glimmer scaffold:cw[model_form,common]
@@ -1054,7 +902,7 @@ window {
1054
902
  }
1055
903
  ```
1056
904
 
1057
- If for whatever reason, you end up with 2 custom control views having the same name with different namespaces, then you can invoke the specific custom control you want by including the Ruby namespace in underscored format separated by double-underscores:
905
+ If for whatever reason, you end up with 2 [custom control](#custom-components) views having the same name with different namespaces, then you can invoke the specific [custom control](#custom-components) you want by including the Ruby namespace in underscored format separated by double-underscores:
1058
906
 
1059
907
  ```ruby
1060
908
  window {
@@ -1065,7 +913,7 @@ window {
1065
913
  }
1066
914
  ```
1067
915
 
1068
- Or another `model_form` custom control view:
916
+ Or another `model_form` [custom control](#custom-components) view:
1069
917
 
1070
918
  ```ruby
1071
919
  window {
@@ -1076,83 +924,177 @@ window {
1076
924
  }
1077
925
  ```
1078
926
 
1079
- ### Scaffold Custom Window Gem
927
+ ### Scaffold Custom Window
928
+
929
+ A custom window is a specialization of a custom control that has a `window` as its `body` root.
1080
930
 
1081
- You can scaffold a Ruby gem around a reusable custom window by running this command:
931
+ When you are in a scaffolded application, you can scaffold a new custom window (a window that you can put anything in to represent a view concept in your application) by running this command:
1082
932
 
1083
933
  ```
1084
- glimmer scaffold:gem:customwindow[name,namespace]
934
+ glimmer scaffold:customwindow[name,namespace]
1085
935
  ```
1086
936
 
1087
- That will generate a custom window gem project under the naming convention: `glimmer-libui-cw-name-namespace`
1088
-
1089
- The naming convention helps with discoverability of Ruby gems using the command `glimmer list:gems:customwindow[query]` (or alias: `glimmer list:gems:cw[query]`) where filtering `query` is optional.
1090
-
1091
- The `name` is the custom window class name, which must not contain dashes by convention (multiple words can be concatenated or can use underscores between them).
937
+ The `name` represents the custom window view class name (it can be underscored, and Glimmer will automatically classify it).
1092
938
 
1093
- The `namespace` is needed to avoid clashing with other custom window gems that other software engineers might have thought of. It is recommended not to include dashes between words in it by convention yet concatenated words or underscores between them.
939
+ The `namespace` is optional and represents the module that the custom window view class will live under. If left off, the main application class namespace is used (e.g. the top-level `HelloWorld` class namespace for a `hello_world` application).
1094
940
 
1095
- Here is a shorter alias for the custom window gem scaffolding command:
941
+ You can also use the shorter `cw` alias for `customwindow`:
1096
942
 
1097
943
  ```
1098
- glimmer scaffold:gem:cw[name,namespace]
944
+ glimmer scaffold:cw[name,namespace]
1099
945
  ```
1100
946
 
1101
- You can package the newly scaffolded project as a Ruby gem by running this command:
947
+ For example by running this command under a `hello_world` application:
1102
948
 
1103
949
  ```
1104
- glimmer package:gem
950
+ glimmer scaffold:cw[greeting_window]
1105
951
  ```
1106
952
 
1107
- Or by using the raw rake command:
953
+ That will generate this class under `app/hello_world/view/greeting_window`:
1108
954
 
955
+ ```ruby
956
+ class HelloWorld
957
+ module View
958
+ class GreetingWindow
959
+ include Glimmer::LibUI::CustomWindow
960
+
961
+
962
+ ## Add options like the following to configure CustomWindow by outside consumers
963
+ #
964
+ # options :title, :background_color
965
+ # option :width, default: 320
966
+ # option :height, default: 240
967
+
968
+ ## Use before_body block to pre-initialize variables to use in body and
969
+ # to setup application menu
970
+ #
971
+ # before_body do
972
+ #
973
+ # end
974
+
975
+ ## Use after_body block to setup observers for controls in body
976
+ #
977
+ # after_body do
978
+ #
979
+ # end
980
+
981
+ ## Add control content inside custom window body
982
+ ## Top-most control must be a window or another custom window
983
+ #
984
+ body {
985
+ window {
986
+ # Replace example content below with custom window content
987
+ content_size 240, 240
988
+ title 'Hello World'
989
+
990
+ margined true
991
+
992
+ label {
993
+ text 'Hello World'
994
+ }
995
+ }
996
+ }
997
+ end
998
+ end
999
+ end
1109
1000
  ```
1110
- rake build
1001
+
1002
+ When the generated file is required in another view (e.g. `require 'hello_world/view/greeting_window'`), the custom window keyword `greeting_window` become available and reusable, like by calling:
1003
+
1004
+ ```ruby
1005
+ greeting_window.show
1111
1006
  ```
1112
1007
 
1113
- You can generate the application gemspec explicitly if needed with this command (though it is not needed to build the gem):
1008
+ Here is an example that generates a custom window with a namespace:
1114
1009
 
1115
1010
  ```
1116
- glimmer package:gemspec
1011
+ glimmer scaffold:cw[train,station]
1117
1012
  ```
1118
1013
 
1119
- Or by using the raw rake command:
1014
+ That will generate this class under `app/station/view/train`:
1120
1015
 
1121
- ```
1122
- rake gemspec:generate
1016
+ ```ruby
1017
+ module Station
1018
+ module View
1019
+ class Train
1020
+ include Glimmer::LibUI::CustomWindow
1021
+
1022
+
1023
+ ## Add options like the following to configure CustomWindow by outside consumers
1024
+ #
1025
+ # options :title, :background_color
1026
+ # option :width, default: 320
1027
+ # option :height, default: 240
1028
+
1029
+ ## Use before_body block to pre-initialize variables to use in body and
1030
+ # to setup application menu
1031
+ #
1032
+ # before_body do
1033
+ #
1034
+ # end
1035
+
1036
+ ## Use after_body block to setup observers for controls in body
1037
+ #
1038
+ # after_body do
1039
+ #
1040
+ # end
1041
+
1042
+ ## Add control content inside custom window body
1043
+ ## Top-most control must be a window or another custom window
1044
+ #
1045
+ body {
1046
+ window {
1047
+ # Replace example content below with custom window content
1048
+ content_size 240, 240
1049
+ title 'Station'
1050
+
1051
+ margined true
1052
+
1053
+ label {
1054
+ text 'Station'
1055
+ }
1056
+ }
1057
+ }
1058
+ end
1059
+ end
1060
+ end
1123
1061
  ```
1124
1062
 
1125
- The project optionally allows you to run the custom window as its own separate app with a binary script (`bin/gem_name`) to see it, which helps with prototyping it.
1063
+ When that file is required in another view (e.g. `require 'station/view/train'`), the `train` keyword becomes available:
1126
1064
 
1127
- But, typically consumers of the gem would include it in their own project, which makes the gem keyword available in the Glimmer GUI DSL anywhere `Glimmer`. `Glimmer::LibUI::Application`, `Glimmer::LibUI::CustomWindow`, or `Glimmer::LibUI::CustomControl` is mixed.
1065
+ ```ruby
1066
+ train.show
1067
+ ```
1128
1068
 
1129
- For example:
1069
+ If for whatever reason, you end up with 2 custom window views having the same name with different namespaces, then you can invoke the specific custom window you want by including the Ruby namespace in underscored format separated by double-underscores:
1130
1070
 
1131
1071
  ```ruby
1132
- require 'glimmer-libui-cw-greeter-acme'
1072
+ station__view__train.show
1073
+ ```
1133
1074
 
1134
- ...
1135
- greeter.show
1136
- ...
1075
+ Or another `train` custom window view:
1076
+
1077
+ ```ruby
1078
+ hello_world__view__train.show
1137
1079
  ```
1138
1080
 
1139
1081
  ### Scaffold Custom Control Gem
1140
1082
 
1141
- You can scaffold a Ruby gem around a reusable custom control by running this command:
1083
+ You can scaffold a Ruby gem around a reusable [custom control](#custom-components) to expose publicly and make available for multiple projects by running this command:
1142
1084
 
1143
1085
  ```
1144
1086
  glimmer scaffold:gem:customcontrol[name,namespace]
1145
1087
  ```
1146
1088
 
1147
- That will generate a custom control gem project under the naming convention: `glimmer-libui-cc-name-namespace`
1089
+ That will generate a [custom control](#custom-components) gem project under the naming convention: `glimmer-libui-cc-name-namespace`
1148
1090
 
1149
1091
  The naming convention helps with discoverability of Ruby gems using the command `glimmer list:gems:customcontrol[query]` (or alias: `glimmer list:gems:cc[query]`) where filtering `query` is optional.
1150
1092
 
1151
- The `name` is the custom control class name, which must not contain dashes by convention (multiple words can be concatenated or can use underscores between them).
1093
+ The `name` is the [custom control](#custom-components) class name, which must not contain dashes by convention (multiple words can be concatenated or can use underscores between them).
1152
1094
 
1153
- The `namespace` is needed to avoid clashing with other custom control gems that other software engineers might have thought of. It is recommended not to include dashes between words in it by convention yet concatenated words or underscores between them.
1095
+ The `namespace` is needed to avoid clashing with other [custom control](#custom-components) gems that other software engineers might have thought of. It is recommended not to include dashes between words in it by convention yet concatenated words or underscores between them.
1154
1096
 
1155
- Here is a shorter alias for the custom control gem scaffolding command:
1097
+ Here is a shorter alias for the [custom control](#custom-components) gem scaffolding command:
1156
1098
 
1157
1099
  ```
1158
1100
  glimmer scaffold:gem:cc[name,namespace]
@@ -1200,6 +1142,68 @@ window {
1200
1142
  ...
1201
1143
  ```
1202
1144
 
1145
+ ### Scaffold Custom Window Gem
1146
+
1147
+ A custom window is a specialization of a custom control that has a `window` as its `body` root.
1148
+
1149
+ You can scaffold a Ruby gem around a reusable custom window to expose publicly and make available for multiple projects by running this command:
1150
+
1151
+ ```
1152
+ glimmer scaffold:gem:customwindow[name,namespace]
1153
+ ```
1154
+
1155
+ That will generate a custom window gem project under the naming convention: `glimmer-libui-cw-name-namespace`
1156
+
1157
+ The naming convention helps with discoverability of Ruby gems using the command `glimmer list:gems:customwindow[query]` (or alias: `glimmer list:gems:cw[query]`) where filtering `query` is optional.
1158
+
1159
+ The `name` is the custom window class name, which must not contain dashes by convention (multiple words can be concatenated or can use underscores between them).
1160
+
1161
+ The `namespace` is needed to avoid clashing with other custom window gems that other software engineers might have thought of. It is recommended not to include dashes between words in it by convention yet concatenated words or underscores between them.
1162
+
1163
+ Here is a shorter alias for the custom window gem scaffolding command:
1164
+
1165
+ ```
1166
+ glimmer scaffold:gem:cw[name,namespace]
1167
+ ```
1168
+
1169
+ You can package the newly scaffolded project as a Ruby gem by running this command:
1170
+
1171
+ ```
1172
+ glimmer package:gem
1173
+ ```
1174
+
1175
+ Or by using the raw rake command:
1176
+
1177
+ ```
1178
+ rake build
1179
+ ```
1180
+
1181
+ You can generate the application gemspec explicitly if needed with this command (though it is not needed to build the gem):
1182
+
1183
+ ```
1184
+ glimmer package:gemspec
1185
+ ```
1186
+
1187
+ Or by using the raw rake command:
1188
+
1189
+ ```
1190
+ rake gemspec:generate
1191
+ ```
1192
+
1193
+ The project optionally allows you to run the custom window as its own separate app with a executable script (`bin/gem_name`) to see it, which helps with prototyping it.
1194
+
1195
+ But, typically consumers of the gem would include it in their own project, which makes the gem keyword available in the Glimmer GUI DSL anywhere `Glimmer`. `Glimmer::LibUI::Application`, `Glimmer::LibUI::CustomWindow`, or `Glimmer::LibUI::CustomControl` is mixed.
1196
+
1197
+ For example:
1198
+
1199
+ ```ruby
1200
+ require 'glimmer-libui-cw-greeter-acme'
1201
+
1202
+ ...
1203
+ greeter.show
1204
+ ...
1205
+ ```
1206
+
1203
1207
  ### List Custom Window Gems
1204
1208
 
1205
1209
  Custom window gems are scaffolded to follow the naming convention: `glimmer-libui-cw-name-namespace`
@@ -1725,7 +1729,7 @@ Learn more by checking out [examples](#examples).
1725
1729
 
1726
1730
  [EARLY ALPHA FEATURE]
1727
1731
 
1728
- `refined_table` is a custom control provided exclusively by [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
1732
+ `refined_table` is a [custom control](#custom-components) provided exclusively by [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
1729
1733
  that includes filtering and pagination support out of the box and can handle very large amounts of data (e.g. 50,000 rows).
1730
1734
 
1731
1735
  It is currently an early alpha feature, so please test-drive and report issues if you encounter any.
@@ -1747,7 +1751,7 @@ API:
1747
1751
 
1748
1752
  - `refined_model_array` (`Array`): `model_array` with filtering and pagination applied (useful to grab a table row model by index).
1749
1753
  - `filtered_model_array` (`Array`): `model_array` with filtering applied, but without pagination
1750
- - `table_proxy`: control proxy object for the `table` contained in the `refined_table` custom control
1754
+ - `table_proxy`: control proxy object for the `table` contained in the `refined_table` [custom control](#custom-components)
1751
1755
 
1752
1756
  If the initial `model_array` has no more than a single page of data, then pagination buttons are hidden (but, the filter field remains).
1753
1757
 
@@ -1990,7 +1994,7 @@ Mac | Windows | Linux
1990
1994
  **(ALPHA FEATURE)**
1991
1995
 
1992
1996
  [libui-ng](https://github.com/libui-ng/libui-ng) does not support `image` rendering outside of `table` yet.
1993
- 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).
1997
+ 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](#custom-components) that renders an image unto an `area` pixel by pixel (and when possible to optimize, line by line).
1994
1998
 
1995
1999
  Given that it is very new and is not a [libui-ng](https://github.com/libui-ng/libui-ng)-native control, please keep these notes in mind:
1996
2000
  - It only supports the `.png` file format.
@@ -2163,7 +2167,7 @@ One final note is that in Linux, table images grow and shrink with the image siz
2163
2167
 
2164
2168
  ![linux table image](images/glimmer-dsl-libui-linux-basic-table-image.png)
2165
2169
 
2166
- Check out [examples/basic_image.rb](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-image) (all versions) for examples of using `image` Glimmer custom control.
2170
+ Check out [examples/basic_image.rb](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-image) (all versions) for examples of using `image` Glimmer [custom control](#custom-components).
2167
2171
 
2168
2172
  #### Colors
2169
2173
 
@@ -2476,7 +2480,7 @@ BasicCompositeShape.launch
2476
2480
 
2477
2481
  If you need to animate `area` vector graphics, you just have to use the [`Glimmer::LibUI::timer`](#libui-operations) method along with making changes to shape attributes.
2478
2482
 
2479
- Spinner example that has a fully customizable method-based custom control called `spinner`, which is destroyed if you click on it (you may copy/paste in [`girb`](#girb-glimmer-irb)):
2483
+ Spinner example that has a fully customizable method-based [custom control](#custom-components) called `spinner`, which is destroyed if you click on it (you may copy/paste in [`girb`](#girb-glimmer-irb)):
2480
2484
 
2481
2485
  ```ruby
2482
2486
  require 'glimmer-dsl-libui'
@@ -2605,21 +2609,21 @@ SpinnerExample.new.launch
2605
2609
  - 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)
2606
2610
  - Color alpha value defaults to `1.0` when not specified.
2607
2611
 
2608
- ### Custom Controls
2612
+ ### Custom Components
2609
2613
 
2610
- Custom controls can be defined to represent custom controls (components) that provide new features or act as composites of [existing controls](#supported-keywords) that need to be reused multiple times in an application or across multiple applications. Custom controls save a lot of development time, improving productivity and maintainability immensely.
2614
+ Custom components like custom controls, custom windows, and custom shapes can be defined to provide new features or act as composites of [existing controls](#supported-keywords) that need to be reused multiple times in an application or across multiple applications. Custom controls save a lot of development time, improving productivity and maintainability immensely.
2611
2615
 
2612
2616
  For example, you can define a custom `address_view` control as an aggregate of multiple `label` controls to reuse multiple times as a standard address View, displaying street, city, state, and zip code.
2613
2617
 
2614
- There are two ways to define custom controls:
2615
- - Method-Based: simply define a method representing the custom control you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
2616
- - Class-Based: define a class matching the camelcased name of the custom control by convention (e.g. the `address_view` custom control keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`. Classes add the benefit of being able to distribute the custom controls into separate files and reuse externally from multiple places or share via Ruby gems.
2618
+ There are two ways to define [custom components](#custom-components):
2619
+ - Method-Based: simply define a method representing the [custom component](#custom-components) you want (e.g. `address_view`) with any options needed (e.g. `address(address_model: some_model)`).
2620
+ - Class-Based: define a class matching the camelcased name of the [custom component](#custom-components) by convention (e.g. the `address_view` [custom component](#custom-components) keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`, `include Glimmer::LibUI::CustomWindow`, `include Glimmer::LibUI::CustomShape` depending on if the component represents a standard control, a whole window, or an area canvas graphics shape. Classes add the benefit of being able to distribute the [custom component](#custom-components)s into a separate file for external reuse from multiple views or for sharing as a Ruby gem.
2617
2621
 
2618
- It is OK to use the terms "custom control" and "custom keyword" synonymously though "custom keyword" is a broader term that covers things other than controls too like custom shapes (e.g. `cylinder`), custom attributed strings (e.g. `alternating_color_string`), and custom transforms (`isometric_transform`).
2622
+ It is OK to use the terms "custom control", "custom component", and "custom keyword" synonymously though "custom component" is a broader term that covers things other than controls too like custom shapes (e.g. `cube`), custom attributed strings (e.g. `alternating_color_string`), and custom transforms (`isometric_transform`).
2619
2623
 
2620
2624
  #### Method-Based Custom Controls
2621
2625
 
2622
- Simply define a method representing the custom control you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
2626
+ Simply define a method representing the [custom component](#custom-components) you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
2623
2627
 
2624
2628
  Example that defines `form_field`, `address_form`, `label_pair`, and `address_view` keywords (you may copy/paste in [`girb`](#girb-glimmer-irb)):
2625
2629
 
@@ -2718,9 +2722,9 @@ window('Method-Based Custom Keyword') {
2718
2722
 
2719
2723
  ![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
2720
2724
 
2721
- #### Class-Based Custom Controls
2725
+ #### Class-Based Custom Components
2722
2726
 
2723
- Define a class matching the camelcased name of the custom control by convention (e.g. the `address_view` custom control keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`. Classes add the benefit of being able to distribute the custom controls into separate files and reuse externally from multiple places or share via Ruby gems.
2727
+ Define a class matching the camelcased name of the [custom control](#custom-components) by convention (e.g. the `address_view` [custom control](#custom-components) keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`. Classes add the benefit of being able to distribute the [custom control](#custom-components)s into separate files and reuse externally from multiple places or share via Ruby gems.
2724
2728
 
2725
2729
  Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
2726
2730
 
@@ -2850,13 +2854,185 @@ ClassBasedCustomControls.launch
2850
2854
 
2851
2855
  ![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
2852
2856
 
2853
- You can also define Custom Window keywords, that is custom controls with `window` being the body root. These are also known as Applications. To define a Custom Window, you `include Glimmer::LibUI::CustomWindow` or `include Glimmer:LibUI::Application` and then you can invoke the `::launch` method on the class.
2857
+ Example of a `cube` custom shape (you may copy/paste in [`girb`](#girb-glimmer-irb)):
2858
+
2859
+ ```ruby
2860
+ require 'glimmer-dsl-libui'
2861
+
2862
+ # class-based custom shape using Glimmer::LibUI::CustomShape mixin, which automatically
2863
+ # augments the Glimmer GUI DSL with the underscored version of the class name: `cube`
2864
+ # while accepting hash options matching the options declared on the class.
2865
+ # (e.g. `cube(location_x: 50, location_y: 100)` )
2866
+ class Cube
2867
+ include Glimmer::LibUI::CustomShape
2868
+
2869
+ DEFAULT_SIZE = 28
2870
+
2871
+ option :location_x, default: 0
2872
+ option :location_y, default: 0
2873
+ option :rectangle_width, default: nil
2874
+ option :rectangle_height, default: nil
2875
+ option :cube_height, default: 75
2876
+ option :background_color, default: :brown
2877
+ option :foreground_color
2878
+ option :line_thickness, default: 1
2879
+
2880
+ # The before_body block executes before building the body
2881
+ before_body do
2882
+ self.rectangle_width ||= rectangle_height || cube_height || DEFAULT_SIZE
2883
+ self.rectangle_height ||= rectangle_width || cube_height || DEFAULT_SIZE
2884
+ self.cube_height ||= rectangle_width || rectangle_height || DEFAULT_SIZE
2885
+ if foreground_color
2886
+ self.foreground_color = Glimmer::LibUI.interpret_color(foreground_color)
2887
+ self.foreground_color[:thickness] ||= line_thickness
2888
+ else
2889
+ self.foreground_color = [0, 0, 0, thickness: line_thickness]
2890
+ end
2891
+ end
2892
+
2893
+ # Optionally, after_body could be defined to perform operations after building the body
2894
+ # like setting up observers.
2895
+ #
2896
+ # after_body do
2897
+ # end
2898
+
2899
+ body {
2900
+ # the shape keyword (alias for composite_shape) enables building a composite shape that is treated as one shape
2901
+ # like a cube containing polygons, a polyline, a rectangle, and a line
2902
+ # with the fill and stroke colors getting inherited by all children that do not specify them
2903
+ shape(location_x, location_y) {
2904
+ fill background_color
2905
+ stroke foreground_color
2906
+
2907
+ bottom = polygon(0, cube_height + rectangle_height / 2.0,
2908
+ rectangle_width / 2.0, cube_height,
2909
+ rectangle_width, cube_height + rectangle_height / 2.0,
2910
+ rectangle_width / 2.0, cube_height + rectangle_height) {
2911
+ # inherits fill property from parent shape if not set
2912
+ # inherits stroke property from parent shape if not set
2913
+ }
2914
+ body = rectangle(0, rectangle_height / 2.0, rectangle_width, cube_height) {
2915
+ # inherits fill property from parent shape if not set
2916
+ # stroke is overridden to ensure a different value from parent
2917
+ stroke thickness: 0
2918
+ }
2919
+ polyline(0, rectangle_height / 2.0 + cube_height,
2920
+ 0, rectangle_height / 2.0,
2921
+ rectangle_width, rectangle_height / 2.0,
2922
+ rectangle_width, rectangle_height / 2.0 + cube_height) {
2923
+ # inherits stroke property from parent shape if not set
2924
+ }
2925
+ top = polygon(0, rectangle_height / 2.0,
2926
+ rectangle_width / 2.0, 0,
2927
+ rectangle_width, rectangle_height / 2.0,
2928
+ rectangle_width / 2.0, rectangle_height) {
2929
+ # inherits fill property from parent shape if not set
2930
+ # inherits stroke property from parent shape if not set
2931
+ }
2932
+ line(rectangle_width / 2.0, cube_height + rectangle_height,
2933
+ rectangle_width / 2.0, rectangle_height) {
2934
+ # inherits stroke property from parent shape if not set
2935
+ }
2936
+ }
2937
+ }
2938
+ end
2939
+
2940
+ class BasicCustomShape
2941
+ include Glimmer::LibUI::Application
2942
+
2943
+ body {
2944
+ window {
2945
+ title 'Basic Custom Shape'
2946
+ content_size 200, 225
2947
+
2948
+ @area = area {
2949
+ rectangle(0, 0, 200, 225) {
2950
+ fill :white
2951
+ }
2952
+
2953
+ 7.times do |n|
2954
+ x_location = (rand*125).to_i%200 + (rand*15).to_i
2955
+ y_location = (rand*125).to_i%200 + (rand*15).to_i
2956
+ shape_color = [rand*125 + 130, rand*125 + 130, rand*125 + 130]
2957
+ shape_size = 20+n
2958
+
2959
+ cube(
2960
+ location_x: x_location,
2961
+ location_y: y_location,
2962
+ rectangle_width: shape_size*2,
2963
+ rectangle_height: shape_size,
2964
+ cube_height: shape_size*2,
2965
+ background_color: shape_color,
2966
+ line_thickness: 2
2967
+ ) { |the_shape|
2968
+ on_mouse_up do |area_mouse_event|
2969
+ # Change color on mouse up without dragging
2970
+ if @drag_shape.nil?
2971
+ background_color = [rand(255), rand(255), rand(255)]
2972
+ the_shape.fill = background_color
2973
+ end
2974
+ end
2975
+
2976
+ on_mouse_drag_start do |area_mouse_event|
2977
+ @drag_shape = the_shape
2978
+ @drag_x = area_mouse_event[:x]
2979
+ @drag_y = area_mouse_event[:y]
2980
+ end
2981
+
2982
+ on_mouse_drag do |area_mouse_event|
2983
+ if @drag_shape && @drag_x && @drag_y
2984
+ drag_distance_width = area_mouse_event[:x] - @drag_x
2985
+ drag_distance_height = area_mouse_event[:y] - @drag_y
2986
+ @drag_shape.x += drag_distance_width
2987
+ @drag_shape.y += drag_distance_height
2988
+ @drag_x = area_mouse_event[:x]
2989
+ @drag_y = area_mouse_event[:y]
2990
+ end
2991
+ end
2992
+
2993
+ on_mouse_drop do |area_mouse_event|
2994
+ @drag_shape = nil
2995
+ @drag_x = nil
2996
+ @drag_y = nil
2997
+ end
2998
+ }
2999
+ end
3000
+
3001
+ # this general area on_mouse_drag listener is needed to ensure that dragging a shape
3002
+ # outside of its boundaries would still move the dragged shape
3003
+ on_mouse_drag do |area_mouse_event|
3004
+ if @drag_shape && @drag_x && @drag_y
3005
+ drag_distance_width = area_mouse_event[:x] - @drag_x
3006
+ drag_distance_height = area_mouse_event[:y] - @drag_y
3007
+ @drag_shape.x += drag_distance_width
3008
+ @drag_shape.y += drag_distance_height
3009
+ @drag_x = area_mouse_event[:x]
3010
+ @drag_y = area_mouse_event[:y]
3011
+ end
3012
+ end
3013
+
3014
+ on_mouse_drop do |area_mouse_event|
3015
+ @drag_shape = nil
3016
+ @drag_x = nil
3017
+ @drag_y = nil
3018
+ end
3019
+ }
3020
+ }
3021
+ }
3022
+ end
3023
+
3024
+ BasicCustomShape.launch
3025
+ ```
3026
+
3027
+ ![glimmer-dsl-libui-mac-basic-custom-shape.gif](/images/glimmer-dsl-libui-mac-basic-composite-shape.gif)
3028
+
3029
+ You can also define Custom Window keywords, that is [custom control](#custom-components)s with `window` being the body root. These are also known as Applications. To define a Custom Window, you `include Glimmer::LibUI::CustomWindow` or `include Glimmer:LibUI::Application` and then you can invoke the `::launch` method on the class.
2854
3030
 
2855
3031
  The [`area`](#area-api) control can be utilized to build non-native custom controls from scratch by leveraging vector graphics, formattable text, keyboard events, and mouse events. This is demonstrated in the [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls) example.
2856
3032
 
2857
3033
  Defining custom controls enables unlimited extension of the [Glimmer GUI DSL](#glimmer-gui-dsl). The sky is the limit on what can be done with custom controls as a result. You can compose new visual vocabulary to build applications in any domain from higher concepts rather than [mere standard controls](#supported-keywords). For example, in a traffic signaling app, you could define `street`, `light_signal`, `traffic_sign`, and `car` as custom keywords and build your application from these concepts directly, saving enormous time and achieving much higher productivity.
2858
3034
 
2859
- Learn more from custom control usage in [Method-Based Custom Keyword](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#method-based-custom-keyword), [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls), [Basic Scrolling Area](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-scrolling-area), [Histogram](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#histogram), and [Tetris](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#tetris) examples.
3035
+ Learn more from custom control usage in [Method-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#method--based-custom-controls), [Class-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#class-based-custom-controls), [Area-Based Custom Controls](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#area-based-custom-controls), [Basic Composite Shape](), [Basic Custom Shape](), [Basic Scrolling Area](/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md#basic-scrolling-area), [Histogram](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#histogram), and [Tetris](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#tetris) examples.
2860
3036
 
2861
3037
  ### Observer Pattern
2862
3038