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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +392 -216
- data/VERSION +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md +5 -5
- data/docs/examples/GLIMMER-DSL-LIBUI-BASIC-EXAMPLES.md +23 -0
- data/examples/basic_composite_shape.rb +2 -0
- data/examples/basic_custom_shape.rb +168 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/custom_shape_expression.rb +58 -0
- data/lib/glimmer/dsl/libui/dsl.rb +1 -0
- data/lib/glimmer/dsl/libui/listener_expression.rb +6 -1
- data/lib/glimmer/launcher.rb +2 -5
- data/lib/glimmer/libui/custom_control.rb +25 -19
- data/lib/glimmer/libui/custom_shape.rb +258 -0
- data/lib/glimmer/rake_task/scaffold.rb +1 -2
- data/lib/glimmer-dsl-libui.rb +1 -1
- metadata +5 -2
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.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
|
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
|
385
|
-
- [Method-Based Custom
|
386
|
-
- [Class-Based Custom
|
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.
|
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
|
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
|
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
|
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
|
-
|
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:
|
934
|
+
glimmer scaffold:customwindow[name,namespace]
|
1085
935
|
```
|
1086
936
|
|
1087
|
-
|
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
|
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
|
-
|
941
|
+
You can also use the shorter `cw` alias for `customwindow`:
|
1096
942
|
|
1097
943
|
```
|
1098
|
-
glimmer scaffold:
|
944
|
+
glimmer scaffold:cw[name,namespace]
|
1099
945
|
```
|
1100
946
|
|
1101
|
-
|
947
|
+
For example by running this command under a `hello_world` application:
|
1102
948
|
|
1103
949
|
```
|
1104
|
-
glimmer
|
950
|
+
glimmer scaffold:cw[greeting_window]
|
1105
951
|
```
|
1106
952
|
|
1107
|
-
|
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
|
-
|
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
|
-
|
1008
|
+
Here is an example that generates a custom window with a namespace:
|
1114
1009
|
|
1115
1010
|
```
|
1116
|
-
glimmer
|
1011
|
+
glimmer scaffold:cw[train,station]
|
1117
1012
|
```
|
1118
1013
|
|
1119
|
-
|
1014
|
+
That will generate this class under `app/station/view/train`:
|
1120
1015
|
|
1121
|
-
```
|
1122
|
-
|
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
|
-
|
1063
|
+
When that file is required in another view (e.g. `require 'station/view/train'`), the `train` keyword becomes available:
|
1126
1064
|
|
1127
|
-
|
1065
|
+
```ruby
|
1066
|
+
train.show
|
1067
|
+
```
|
1128
1068
|
|
1129
|
-
|
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
|
-
|
1072
|
+
station__view__train.show
|
1073
|
+
```
|
1133
1074
|
|
1134
|
-
|
1135
|
-
|
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
|
2612
|
+
### Custom Components
|
2609
2613
|
|
2610
|
-
Custom
|
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
|
2615
|
-
- Method-Based: simply define a method representing the custom
|
2616
|
-
- Class-Based: define a class matching the camelcased name of the custom
|
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
|
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
|
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
|
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
|
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
|
-
|
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
|
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
|
|