glimmer-dsl-libui 0.9.7 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +593 -137
- 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 +19 -13
- data/lib/glimmer/rake_task.rb +18 -18
- 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.1
|
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)
|
@@ -26,7 +26,7 @@ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/gl
|
|
26
26
|
- [Declarative DSL syntax](#glimmer-gui-dsl-concepts) that visually maps to the GUI control hierarchy
|
27
27
|
- [Convention over configuration](#smart-defaults-and-conventions) via smart defaults and automation of low-level details
|
28
28
|
- Requiring the [least amount of syntax](#glimmer-gui-dsl-concepts) possible to build GUI
|
29
|
-
- [Custom
|
29
|
+
- [Custom Component](#custom-components) support (Custom Controls, Custom Windows, and Custom Shapes)
|
30
30
|
- [Bidirectional/Unidirectional Data-Binding](#data-binding) to declaratively wire and automatically synchronize GUI Views with Models
|
31
31
|
- [Scaffolding](#scaffold-application) for new custom windows/controls, apps, and gems
|
32
32
|
- [Far Future Plan] Native-Executable packaging on Mac, Windows, and Linux.
|
@@ -351,12 +351,15 @@ 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)
|
356
|
+
- [Scaffold Custom Shape](#scaffold-custom-shape)
|
357
357
|
- [Scaffold Custom Control Gem](#scaffold-custom-control-gem)
|
358
|
-
- [
|
358
|
+
- [Scaffold Custom Window Gem](#scaffold-custom-window-gem)
|
359
|
+
- [Scaffold Custom Shape Gem](#scaffold-custom-shape-gem)
|
359
360
|
- [List Custom Control Gems](#list-custom-control-gems)
|
361
|
+
- [List Custom Window Gems](#list-custom-window-gems)
|
362
|
+
- [List Custom Shape Gems](#list-custom-shape-gems)
|
360
363
|
- [List Glimmer DSLs](#list-glimmer-dsls)
|
361
364
|
- [Girb (Glimmer IRB)](#girb-glimmer-irb)
|
362
365
|
- [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
|
@@ -381,9 +384,9 @@ Learn more about the differences between various [Glimmer](https://github.com/An
|
|
381
384
|
- [Area Composite Shape](#area-composite-shape)
|
382
385
|
- [Area Animation](#area-animation)
|
383
386
|
- [Smart Defaults and Conventions](#smart-defaults-and-conventions)
|
384
|
-
- [Custom
|
385
|
-
- [Method-Based Custom
|
386
|
-
- [Class-Based Custom
|
387
|
+
- [Custom Components](#custom-components)
|
388
|
+
- [Method-Based Custom Components](#method-based-custom-components)
|
389
|
+
- [Class-Based Custom Components](#class-based-custom-components)
|
387
390
|
- [Observer Pattern](#observer-pattern)
|
388
391
|
- [Data-Binding](#data-binding)
|
389
392
|
- [Bidirectional (Two-Way) Data-Binding](#bidirectional-two-way-data-binding)
|
@@ -428,7 +431,7 @@ gem install glimmer-dsl-libui
|
|
428
431
|
Or install via Bundler `Gemfile`:
|
429
432
|
|
430
433
|
```ruby
|
431
|
-
gem 'glimmer-dsl-libui', '~> 0.
|
434
|
+
gem 'glimmer-dsl-libui', '~> 0.10.1'
|
432
435
|
```
|
433
436
|
|
434
437
|
Test that installation worked by running the [Glimmer Meta-Example](#examples):
|
@@ -624,7 +627,7 @@ Mac | Windows | Linux
|
|
624
627
|
|
625
628
|
### Scaffold Application
|
626
629
|
|
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
|
630
|
+
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
631
|
|
629
632
|
Scaffold Glimmer DSL for LibUI application with this command:
|
630
633
|
|
@@ -722,7 +725,7 @@ Or by using the raw rake command:
|
|
722
725
|
rake gemspec:generate
|
723
726
|
```
|
724
727
|
|
725
|
-
Once you install the gem (e.g. `gem install hello_world`), you can simply run the app with its
|
728
|
+
Once you install the gem (e.g. `gem install hello_world`), you can simply run the app with its executable script:
|
726
729
|
|
727
730
|
```
|
728
731
|
app_name
|
@@ -736,8 +739,198 @@ hello_world
|
|
736
739
|
|
737
740
|
![glimmer-dsl-libui-mac-scaffold-app-initial-screen.png](images/glimmer-dsl-libui-mac-scaffold-app-initial-screen.png)
|
738
741
|
|
742
|
+
### Scaffold Custom Control
|
743
|
+
|
744
|
+
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:
|
745
|
+
|
746
|
+
```
|
747
|
+
glimmer scaffold:customcontrol[name,namespace]
|
748
|
+
```
|
749
|
+
|
750
|
+
The `name` represents the [custom control](#custom-components) view class name (it can be underscored, and Glimmer will automatically classify it).
|
751
|
+
|
752
|
+
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).
|
753
|
+
|
754
|
+
You can also use the shorter `cc` alias for `customcontrol`:
|
755
|
+
|
756
|
+
```
|
757
|
+
glimmer scaffold:cc[name,namespace]
|
758
|
+
```
|
759
|
+
|
760
|
+
For example by running this command under a `hello_world` application:
|
761
|
+
|
762
|
+
```
|
763
|
+
glimmer scaffold:cc[model_form]
|
764
|
+
```
|
765
|
+
|
766
|
+
That will generate this class under `app/hello_world/view/model_form`:
|
767
|
+
|
768
|
+
```ruby
|
769
|
+
class HelloWorld
|
770
|
+
module View
|
771
|
+
class ModelForm
|
772
|
+
include Glimmer::LibUI::CustomControl
|
773
|
+
|
774
|
+
## Add options like the following to configure CustomControl by outside consumers
|
775
|
+
#
|
776
|
+
# options :custom_text, :background_color
|
777
|
+
# option :foreground_color, default: :red
|
778
|
+
|
779
|
+
# Replace example options with your own options
|
780
|
+
option :model
|
781
|
+
option :attributes
|
782
|
+
|
783
|
+
## Use before_body block to pre-initialize variables to use in body
|
784
|
+
#
|
785
|
+
#
|
786
|
+
before_body do
|
787
|
+
# Replace example code with your own before_body code
|
788
|
+
default_model_attributes = [:first_name, :last_name, :email]
|
789
|
+
default_model_class = Struct.new(*default_model_attributes)
|
790
|
+
self.model ||= default_model_class.new
|
791
|
+
self.attributes ||= default_model_attributes
|
792
|
+
end
|
793
|
+
|
794
|
+
## Use after_body block to setup observers for controls in body
|
795
|
+
#
|
796
|
+
# after_body do
|
797
|
+
#
|
798
|
+
# end
|
799
|
+
|
800
|
+
## Add control content under custom control body
|
801
|
+
##
|
802
|
+
## If you want to add a window as the top-most control,
|
803
|
+
## consider creating a custom window instead
|
804
|
+
## (Glimmer::LibUI::CustomWindow offers window convenience methods, like show and hide)
|
805
|
+
#
|
806
|
+
body {
|
807
|
+
# Replace example content (model_form custom control) with your own custom control content.
|
808
|
+
form {
|
809
|
+
attributes.each do |attribute|
|
810
|
+
entry { |e|
|
811
|
+
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
|
812
|
+
text <=> [model, attribute]
|
813
|
+
}
|
814
|
+
end
|
815
|
+
}
|
816
|
+
}
|
817
|
+
|
818
|
+
end
|
819
|
+
end
|
820
|
+
end
|
821
|
+
```
|
822
|
+
|
823
|
+
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:
|
824
|
+
|
825
|
+
```ruby
|
826
|
+
window {
|
827
|
+
vertical_box {
|
828
|
+
label('Form:')
|
829
|
+
model_form(model: some_model, attributes: array_of_attributes)
|
830
|
+
}
|
831
|
+
}
|
832
|
+
```
|
833
|
+
|
834
|
+
Here is an example that generates a [custom control](#custom-components) with a namespace:
|
835
|
+
|
836
|
+
```
|
837
|
+
glimmer scaffold:cc[model_form,common]
|
838
|
+
```
|
839
|
+
|
840
|
+
That will generate this class under `app/common/view/model_form`:
|
841
|
+
|
842
|
+
```ruby
|
843
|
+
module Common
|
844
|
+
module View
|
845
|
+
class ModelForm
|
846
|
+
include Glimmer::LibUI::CustomControl
|
847
|
+
|
848
|
+
## Add options like the following to configure CustomControl by outside consumers
|
849
|
+
#
|
850
|
+
# options :custom_text, :background_color
|
851
|
+
# option :foreground_color, default: :red
|
852
|
+
|
853
|
+
# Replace example options with your own options
|
854
|
+
option :model
|
855
|
+
option :attributes
|
856
|
+
|
857
|
+
## Use before_body block to pre-initialize variables to use in body
|
858
|
+
#
|
859
|
+
#
|
860
|
+
before_body do
|
861
|
+
# Replace example code with your own before_body code
|
862
|
+
default_model_attributes = [:first_name, :last_name, :email]
|
863
|
+
default_model_class = Struct.new(*default_model_attributes)
|
864
|
+
self.model ||= default_model_class.new
|
865
|
+
self.attributes ||= default_model_attributes
|
866
|
+
end
|
867
|
+
|
868
|
+
## Use after_body block to setup observers for controls in body
|
869
|
+
#
|
870
|
+
# after_body do
|
871
|
+
#
|
872
|
+
# end
|
873
|
+
|
874
|
+
## Add control content under custom control body
|
875
|
+
##
|
876
|
+
## If you want to add a window as the top-most control,
|
877
|
+
## consider creating a custom window instead
|
878
|
+
## (Glimmer::LibUI::CustomWindow offers window convenience methods, like show and hide)
|
879
|
+
#
|
880
|
+
body {
|
881
|
+
# Replace example content (model_form custom control) with your own custom control content.
|
882
|
+
form {
|
883
|
+
attributes.each do |attribute|
|
884
|
+
entry { |e|
|
885
|
+
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
|
886
|
+
text <=> [model, attribute]
|
887
|
+
}
|
888
|
+
end
|
889
|
+
}
|
890
|
+
}
|
891
|
+
|
892
|
+
end
|
893
|
+
end
|
894
|
+
end
|
895
|
+
```
|
896
|
+
|
897
|
+
When that file is required in another view (e.g. `require 'common/view/model_form'`), the `model_form` keyword becomes available:
|
898
|
+
|
899
|
+
```ruby
|
900
|
+
window {
|
901
|
+
vertical_box {
|
902
|
+
label('Form:')
|
903
|
+
model_form(model: some_model, attributes: array_of_attributes)
|
904
|
+
}
|
905
|
+
}
|
906
|
+
```
|
907
|
+
|
908
|
+
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:
|
909
|
+
|
910
|
+
```ruby
|
911
|
+
window {
|
912
|
+
vertical_box {
|
913
|
+
label('Form:')
|
914
|
+
common__view__model_form(model: some_model, attributes: array_of_attributes)
|
915
|
+
}
|
916
|
+
}
|
917
|
+
```
|
918
|
+
|
919
|
+
Or another `model_form` [custom control](#custom-components) view:
|
920
|
+
|
921
|
+
```ruby
|
922
|
+
window {
|
923
|
+
vertical_box {
|
924
|
+
label('Form:')
|
925
|
+
hello_world__view__model_form(model: some_model, attributes: array_of_attributes)
|
926
|
+
}
|
927
|
+
}
|
928
|
+
```
|
929
|
+
|
739
930
|
### Scaffold Custom Window
|
740
931
|
|
932
|
+
A custom window is a specialization of a custom control that has a `window` as its `body` root.
|
933
|
+
|
741
934
|
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
935
|
|
743
936
|
```
|
@@ -888,79 +1081,81 @@ Or another `train` custom window view:
|
|
888
1081
|
hello_world__view__train.show
|
889
1082
|
```
|
890
1083
|
|
891
|
-
### Scaffold Custom
|
1084
|
+
### Scaffold Custom Shape
|
892
1085
|
|
893
|
-
When you are in a scaffolded application, you can scaffold a new custom
|
1086
|
+
When you are in a scaffolded application, you can scaffold a new [custom shape](#custom-components) (a shape that you can put anything in to represent a view concept in your application) by running this command:
|
894
1087
|
|
895
1088
|
```
|
896
|
-
glimmer scaffold:
|
1089
|
+
glimmer scaffold:customshape[name,namespace]
|
897
1090
|
```
|
898
1091
|
|
899
|
-
The `name` represents the custom
|
1092
|
+
The `name` represents the [custom shape](#custom-components) view class name (it can be underscored, and Glimmer will automatically classify it).
|
900
1093
|
|
901
|
-
The `namespace` is optional and represents the module that the custom
|
1094
|
+
The `namespace` is optional and represents the module that the [custom shape](#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
1095
|
|
903
|
-
You can also use the shorter `
|
1096
|
+
You can also use the shorter `cs` alias for `customshape`:
|
904
1097
|
|
905
1098
|
```
|
906
|
-
glimmer scaffold:
|
1099
|
+
glimmer scaffold:cs[name,namespace]
|
907
1100
|
```
|
908
1101
|
|
909
1102
|
For example by running this command under a `hello_world` application:
|
910
1103
|
|
911
1104
|
```
|
912
|
-
glimmer scaffold:
|
1105
|
+
glimmer scaffold:cs[heart]
|
913
1106
|
```
|
914
1107
|
|
915
|
-
That will generate this class under `app/hello_world/view/
|
1108
|
+
That will generate this class under `app/hello_world/view/heart`:
|
916
1109
|
|
917
1110
|
```ruby
|
918
1111
|
class HelloWorld
|
919
1112
|
module View
|
920
|
-
class
|
921
|
-
include Glimmer::LibUI::
|
1113
|
+
class Heart
|
1114
|
+
include Glimmer::LibUI::CustomShape
|
922
1115
|
|
923
|
-
## Add options like the following to configure
|
1116
|
+
## Add options like the following to configure CustomShape by outside consumers
|
924
1117
|
#
|
925
|
-
# options :
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
option :
|
930
|
-
option :
|
1118
|
+
# options :option1, option2, option3
|
1119
|
+
option :background_color, default: :red
|
1120
|
+
option :size_width, default: 100
|
1121
|
+
option :size_height, default: 100
|
1122
|
+
option :location_x, default: 0
|
1123
|
+
option :location_y, default: 0
|
931
1124
|
|
932
1125
|
## Use before_body block to pre-initialize variables to use in body
|
933
1126
|
#
|
934
1127
|
#
|
935
|
-
before_body do
|
936
|
-
|
937
|
-
|
938
|
-
default_model_class = Struct.new(*default_model_attributes)
|
939
|
-
self.model ||= default_model_class.new
|
940
|
-
self.attributes ||= default_model_attributes
|
941
|
-
end
|
1128
|
+
# before_body do
|
1129
|
+
#
|
1130
|
+
# end
|
942
1131
|
|
943
|
-
## Use after_body block to setup observers for
|
1132
|
+
## Use after_body block to setup observers for shapes in body
|
944
1133
|
#
|
945
1134
|
# after_body do
|
946
1135
|
#
|
947
1136
|
# end
|
948
1137
|
|
949
|
-
## Add
|
950
|
-
##
|
951
|
-
## If you want to add a window as the top-most control,
|
952
|
-
## consider creating a custom window instead
|
953
|
-
## (Glimmer::LibUI::CustomWindow offers window convenience methods, like show and hide)
|
1138
|
+
## Add shape content under custom shape body
|
954
1139
|
#
|
955
1140
|
body {
|
956
|
-
# Replace example content (
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
1141
|
+
# Replace example content below (heart shape) with custom shape content
|
1142
|
+
shape(location_x, location_y) {
|
1143
|
+
# This fill color is shared under all direct children of `shape`
|
1144
|
+
fill background_color
|
1145
|
+
|
1146
|
+
bezier(
|
1147
|
+
size_width - size_width*0.66, size_height/2 - size_height*0.33,
|
1148
|
+
size_width*0.65 - size_width*0.66, 0 - size_height*0.33,
|
1149
|
+
size_width/2 - size_width*0.66, size_height*0.75 - size_height*0.33,
|
1150
|
+
size_width - size_width*0.66, size_height - size_height*0.33
|
1151
|
+
)
|
1152
|
+
|
1153
|
+
bezier(
|
1154
|
+
size_width - size_width*0.66, size_height/2 - size_height*0.33,
|
1155
|
+
size_width*1.35 - size_width*0.66, 0 - size_height*0.33,
|
1156
|
+
size_width*1.5 - size_width*0.66, size_height*0.75 - size_height*0.33,
|
1157
|
+
size_width - size_width*0.66, size_height - size_height*0.33
|
1158
|
+
)
|
964
1159
|
}
|
965
1160
|
}
|
966
1161
|
|
@@ -969,72 +1164,83 @@ class HelloWorld
|
|
969
1164
|
end
|
970
1165
|
```
|
971
1166
|
|
972
|
-
When the generated file is required in another view (e.g. `require 'hello_world/view/
|
1167
|
+
When the generated file is required in another view (e.g. `require 'hello_world/view/heart'`), the [custom shape](#custom-components) keyword `heart` become available and reusable, like by calling:
|
973
1168
|
|
974
1169
|
```ruby
|
975
1170
|
window {
|
976
|
-
|
977
|
-
|
978
|
-
|
1171
|
+
area {
|
1172
|
+
heart
|
1173
|
+
}
|
1174
|
+
}
|
1175
|
+
```
|
1176
|
+
|
1177
|
+
You can pass `heart` options (as defined with `option` near the top of the class):
|
1178
|
+
|
1179
|
+
```ruby
|
1180
|
+
window {
|
1181
|
+
area {
|
1182
|
+
heart(location_x: 25, location_y: 50)
|
979
1183
|
}
|
980
1184
|
}
|
981
1185
|
```
|
982
1186
|
|
983
|
-
Here is an example that generates a custom
|
1187
|
+
Here is an example that generates a [custom shape](#custom-components) with a namespace:
|
984
1188
|
|
985
1189
|
```
|
986
|
-
glimmer scaffold:
|
1190
|
+
glimmer scaffold:cs[heart,acme]
|
987
1191
|
```
|
988
1192
|
|
989
|
-
That will generate this class under `app/
|
1193
|
+
That will generate this class under `app/acme/view/heart`:
|
990
1194
|
|
991
1195
|
```ruby
|
992
|
-
module
|
1196
|
+
module Acme
|
993
1197
|
module View
|
994
|
-
class
|
995
|
-
include Glimmer::LibUI::
|
1198
|
+
class Heart
|
1199
|
+
include Glimmer::LibUI::CustomShape
|
996
1200
|
|
997
|
-
## Add options like the following to configure
|
1201
|
+
## Add options like the following to configure CustomShape by outside consumers
|
998
1202
|
#
|
999
|
-
# options :
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
option :
|
1004
|
-
option :
|
1203
|
+
# options :option1, option2, option3
|
1204
|
+
option :background_color, default: :red
|
1205
|
+
option :size_width, default: 100
|
1206
|
+
option :size_height, default: 100
|
1207
|
+
option :location_x, default: 0
|
1208
|
+
option :location_y, default: 0
|
1005
1209
|
|
1006
1210
|
## Use before_body block to pre-initialize variables to use in body
|
1007
1211
|
#
|
1008
1212
|
#
|
1009
|
-
before_body do
|
1010
|
-
|
1011
|
-
|
1012
|
-
default_model_class = Struct.new(*default_model_attributes)
|
1013
|
-
self.model ||= default_model_class.new
|
1014
|
-
self.attributes ||= default_model_attributes
|
1015
|
-
end
|
1213
|
+
# before_body do
|
1214
|
+
#
|
1215
|
+
# end
|
1016
1216
|
|
1017
|
-
## Use after_body block to setup observers for
|
1217
|
+
## Use after_body block to setup observers for shapes in body
|
1018
1218
|
#
|
1019
1219
|
# after_body do
|
1020
1220
|
#
|
1021
1221
|
# end
|
1022
1222
|
|
1023
|
-
## Add
|
1024
|
-
##
|
1025
|
-
## If you want to add a window as the top-most control,
|
1026
|
-
## consider creating a custom window instead
|
1027
|
-
## (Glimmer::LibUI::CustomWindow offers window convenience methods, like show and hide)
|
1223
|
+
## Add shape content under custom shape body
|
1028
1224
|
#
|
1029
1225
|
body {
|
1030
|
-
# Replace example content (
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1226
|
+
# Replace example content below (heart shape) with your own custom shape content
|
1227
|
+
shape(location_x, location_y) {
|
1228
|
+
# This fill color is shared under all direct children of `shape`
|
1229
|
+
fill background_color
|
1230
|
+
|
1231
|
+
bezier(
|
1232
|
+
size_width - size_width*0.66, size_height/2 - size_height*0.33,
|
1233
|
+
size_width*0.65 - size_width*0.66, 0 - size_height*0.33,
|
1234
|
+
size_width/2 - size_width*0.66, size_height*0.75 - size_height*0.33,
|
1235
|
+
size_width - size_width*0.66, size_height - size_height*0.33
|
1236
|
+
)
|
1237
|
+
|
1238
|
+
bezier(
|
1239
|
+
size_width - size_width*0.66, size_height/2 - size_height*0.33,
|
1240
|
+
size_width*1.35 - size_width*0.66, 0 - size_height*0.33,
|
1241
|
+
size_width*1.5 - size_width*0.66, size_height*0.75 - size_height*0.33,
|
1242
|
+
size_width - size_width*0.66, size_height - size_height*0.33
|
1243
|
+
)
|
1038
1244
|
}
|
1039
1245
|
}
|
1040
1246
|
|
@@ -1043,42 +1249,105 @@ module Common
|
|
1043
1249
|
end
|
1044
1250
|
```
|
1045
1251
|
|
1046
|
-
When that file is required in another view (e.g. `require '
|
1252
|
+
When that file is required in another view (e.g. `require 'acme/view/heart'`), the `heart` keyword becomes available:
|
1047
1253
|
|
1048
1254
|
```ruby
|
1049
1255
|
window {
|
1050
|
-
|
1051
|
-
|
1052
|
-
model_form(model: some_model, attributes: array_of_attributes)
|
1256
|
+
area {
|
1257
|
+
heart
|
1053
1258
|
}
|
1054
1259
|
}
|
1055
1260
|
```
|
1056
1261
|
|
1057
|
-
If for whatever reason, you end up with 2 custom
|
1262
|
+
If for whatever reason, you end up with 2 [custom shape](#custom-components) views having the same name with different namespaces, then you can invoke the specific [custom shape](#custom-components) you want by including the Ruby namespace in underscored format separated by double-underscores:
|
1058
1263
|
|
1059
1264
|
```ruby
|
1060
1265
|
window {
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1266
|
+
area {
|
1267
|
+
acme__view__heart
|
1268
|
+
}
|
1269
|
+
}
|
1270
|
+
```
|
1271
|
+
|
1272
|
+
Or another `heart` [custom shape](#custom-components) view:
|
1273
|
+
|
1274
|
+
```ruby
|
1275
|
+
window {
|
1276
|
+
area {
|
1277
|
+
hello_world__view__heart
|
1064
1278
|
}
|
1065
1279
|
}
|
1066
1280
|
```
|
1067
1281
|
|
1068
|
-
|
1282
|
+
### Scaffold Custom Control Gem
|
1283
|
+
|
1284
|
+
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:
|
1285
|
+
|
1286
|
+
```
|
1287
|
+
glimmer scaffold:gem:customcontrol[name,namespace]
|
1288
|
+
```
|
1289
|
+
|
1290
|
+
That will generate a [custom control](#custom-components) gem project under the naming convention: `glimmer-libui-cc-name-namespace`
|
1291
|
+
|
1292
|
+
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.
|
1293
|
+
|
1294
|
+
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).
|
1295
|
+
|
1296
|
+
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.
|
1297
|
+
|
1298
|
+
Here is a shorter alias for the [custom control](#custom-components) gem scaffolding command:
|
1299
|
+
|
1300
|
+
```
|
1301
|
+
glimmer scaffold:gem:cc[name,namespace]
|
1302
|
+
```
|
1303
|
+
|
1304
|
+
You can package the newly scaffolded project as a Ruby gem by running this command:
|
1305
|
+
|
1306
|
+
```
|
1307
|
+
glimmer package:gem
|
1308
|
+
```
|
1309
|
+
|
1310
|
+
Or by using the raw rake command:
|
1311
|
+
|
1312
|
+
```
|
1313
|
+
rake build
|
1314
|
+
```
|
1315
|
+
|
1316
|
+
You can generate the application gemspec explicitly if needed with this command (though it is not needed to build the gem):
|
1317
|
+
|
1318
|
+
```
|
1319
|
+
glimmer package:gemspec
|
1320
|
+
```
|
1321
|
+
|
1322
|
+
Or by using the raw rake command:
|
1323
|
+
|
1324
|
+
```
|
1325
|
+
rake gemspec:generate
|
1326
|
+
```
|
1327
|
+
|
1328
|
+
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`, `Glimmer::LibUI::CustomControl`, or `Glimmer::LibUI::CustomShape` is mixed.
|
1329
|
+
|
1330
|
+
For example:
|
1069
1331
|
|
1070
1332
|
```ruby
|
1333
|
+
require 'glimmer-libui-cc-model_form-acme'
|
1334
|
+
|
1335
|
+
...
|
1071
1336
|
window {
|
1072
1337
|
vertical_box {
|
1073
1338
|
label('Form:')
|
1074
|
-
|
1339
|
+
|
1340
|
+
model_form(model: some_model, attributes: some_attributes)
|
1075
1341
|
}
|
1076
1342
|
}
|
1343
|
+
...
|
1077
1344
|
```
|
1078
1345
|
|
1079
1346
|
### Scaffold Custom Window Gem
|
1080
1347
|
|
1081
|
-
|
1348
|
+
A custom window is a specialization of a custom control that has a `window` as its `body` root.
|
1349
|
+
|
1350
|
+
You can scaffold a Ruby gem around a reusable custom window to expose publicly and make available for multiple projects by running this command:
|
1082
1351
|
|
1083
1352
|
```
|
1084
1353
|
glimmer scaffold:gem:customwindow[name,namespace]
|
@@ -1122,9 +1391,9 @@ Or by using the raw rake command:
|
|
1122
1391
|
rake gemspec:generate
|
1123
1392
|
```
|
1124
1393
|
|
1125
|
-
The project optionally allows you to run the custom window as its own separate app with a
|
1394
|
+
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.
|
1126
1395
|
|
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::
|
1396
|
+
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`, `Glimmer::LibUI::CustomControl`, or `Glimmer::LibUI::CustomShape` is mixed.
|
1128
1397
|
|
1129
1398
|
For example:
|
1130
1399
|
|
@@ -1136,26 +1405,26 @@ greeter.show
|
|
1136
1405
|
...
|
1137
1406
|
```
|
1138
1407
|
|
1139
|
-
### Scaffold Custom
|
1408
|
+
### Scaffold Custom Shape Gem
|
1140
1409
|
|
1141
|
-
You can scaffold a Ruby gem around a reusable custom
|
1410
|
+
You can scaffold a Ruby gem around a reusable [custom shape](#custom-components) to expose publicly and make available for multiple projects by running this command:
|
1142
1411
|
|
1143
1412
|
```
|
1144
|
-
glimmer scaffold:gem:
|
1413
|
+
glimmer scaffold:gem:customshape[name,namespace]
|
1145
1414
|
```
|
1146
1415
|
|
1147
|
-
That will generate a custom
|
1416
|
+
That will generate a [custom shape](#custom-components) gem project under the naming convention: `glimmer-libui-cc-name-namespace`
|
1148
1417
|
|
1149
|
-
The naming convention helps with discoverability of Ruby gems using the command `glimmer list:gems:
|
1418
|
+
The naming convention helps with discoverability of Ruby gems using the command `glimmer list:gems:customshape[query]` (or alias: `glimmer list:gems:cs[query]`) where filtering `query` is optional.
|
1150
1419
|
|
1151
|
-
The `name` is the custom
|
1420
|
+
The `name` is the [custom shape](#custom-components) class name, which must not contain dashes by convention (multiple words can be concatenated or can use underscores between them).
|
1152
1421
|
|
1153
|
-
The `namespace` is needed to avoid clashing with other custom
|
1422
|
+
The `namespace` is needed to avoid clashing with other [custom shape](#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
1423
|
|
1155
|
-
Here is a shorter alias for the custom
|
1424
|
+
Here is a shorter alias for the [custom shape](#custom-components) gem scaffolding command:
|
1156
1425
|
|
1157
1426
|
```
|
1158
|
-
glimmer scaffold:gem:
|
1427
|
+
glimmer scaffold:gem:cs[name,namespace]
|
1159
1428
|
```
|
1160
1429
|
|
1161
1430
|
You can package the newly scaffolded project as a Ruby gem by running this command:
|
@@ -1182,24 +1451,40 @@ Or by using the raw rake command:
|
|
1182
1451
|
rake gemspec:generate
|
1183
1452
|
```
|
1184
1453
|
|
1185
|
-
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::
|
1454
|
+
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`, `Glimmer::LibUI::CustomControl`, or `Glimmer::LibUI::CustomShape` is mixed.
|
1186
1455
|
|
1187
1456
|
For example:
|
1188
1457
|
|
1189
1458
|
```ruby
|
1190
|
-
require 'glimmer-libui-
|
1459
|
+
require 'glimmer-libui-cs-heart-acme'
|
1191
1460
|
|
1192
1461
|
...
|
1193
1462
|
window {
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
model_form(model: some_model, attributes: some_attributes)
|
1463
|
+
area {
|
1464
|
+
heart
|
1198
1465
|
}
|
1199
1466
|
}
|
1200
1467
|
...
|
1201
1468
|
```
|
1202
1469
|
|
1470
|
+
### List Custom Control Gems
|
1471
|
+
|
1472
|
+
Custom control gems are scaffolded to follow the naming convention: `glimmer-libui-cc-name-namespace`
|
1473
|
+
|
1474
|
+
The naming convention helps with discoverability of Ruby gems using the command:
|
1475
|
+
|
1476
|
+
```
|
1477
|
+
glimmer list:gems:customcontrol[query]
|
1478
|
+
```
|
1479
|
+
|
1480
|
+
Or by using the shorter alias:
|
1481
|
+
|
1482
|
+
```
|
1483
|
+
glimmer list:gems:cc[query]
|
1484
|
+
```
|
1485
|
+
|
1486
|
+
The filtering `query` is optional.
|
1487
|
+
|
1203
1488
|
### List Custom Window Gems
|
1204
1489
|
|
1205
1490
|
Custom window gems are scaffolded to follow the naming convention: `glimmer-libui-cw-name-namespace`
|
@@ -1218,21 +1503,20 @@ glimmer list:gems:cw[query]
|
|
1218
1503
|
|
1219
1504
|
The filtering `query` is optional.
|
1220
1505
|
|
1506
|
+
### List Custom Shape Gems
|
1221
1507
|
|
1222
|
-
|
1223
|
-
|
1224
|
-
Custom control gems are scaffolded to follow the naming convention: `glimmer-libui-cw-name-namespace`
|
1508
|
+
Custom shape gems are scaffolded to follow the naming convention: `glimmer-libui-cs-name-namespace`
|
1225
1509
|
|
1226
1510
|
The naming convention helps with discoverability of Ruby gems using the command:
|
1227
1511
|
|
1228
1512
|
```
|
1229
|
-
glimmer list:gems:
|
1513
|
+
glimmer list:gems:customshape[query]
|
1230
1514
|
```
|
1231
1515
|
|
1232
1516
|
Or by using the shorter alias:
|
1233
1517
|
|
1234
1518
|
```
|
1235
|
-
glimmer list:gems:
|
1519
|
+
glimmer list:gems:cs[query]
|
1236
1520
|
```
|
1237
1521
|
|
1238
1522
|
The filtering `query` is optional.
|
@@ -1725,7 +2009,7 @@ Learn more by checking out [examples](#examples).
|
|
1725
2009
|
|
1726
2010
|
[EARLY ALPHA FEATURE]
|
1727
2011
|
|
1728
|
-
`refined_table` is a custom control provided exclusively by [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
2012
|
+
`refined_table` is a [custom control](#custom-components) provided exclusively by [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui)
|
1729
2013
|
that includes filtering and pagination support out of the box and can handle very large amounts of data (e.g. 50,000 rows).
|
1730
2014
|
|
1731
2015
|
It is currently an early alpha feature, so please test-drive and report issues if you encounter any.
|
@@ -1747,7 +2031,7 @@ API:
|
|
1747
2031
|
|
1748
2032
|
- `refined_model_array` (`Array`): `model_array` with filtering and pagination applied (useful to grab a table row model by index).
|
1749
2033
|
- `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
|
2034
|
+
- `table_proxy`: control proxy object for the `table` contained in the `refined_table` [custom control](#custom-components)
|
1751
2035
|
|
1752
2036
|
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
2037
|
|
@@ -1990,7 +2274,7 @@ Mac | Windows | Linux
|
|
1990
2274
|
**(ALPHA FEATURE)**
|
1991
2275
|
|
1992
2276
|
[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).
|
2277
|
+
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
2278
|
|
1995
2279
|
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
2280
|
- It only supports the `.png` file format.
|
@@ -2163,7 +2447,7 @@ One final note is that in Linux, table images grow and shrink with the image siz
|
|
2163
2447
|
|
2164
2448
|
![linux table image](images/glimmer-dsl-libui-linux-basic-table-image.png)
|
2165
2449
|
|
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.
|
2450
|
+
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
2451
|
|
2168
2452
|
#### Colors
|
2169
2453
|
|
@@ -2476,7 +2760,7 @@ BasicCompositeShape.launch
|
|
2476
2760
|
|
2477
2761
|
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
2762
|
|
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)):
|
2763
|
+
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
2764
|
|
2481
2765
|
```ruby
|
2482
2766
|
require 'glimmer-dsl-libui'
|
@@ -2605,21 +2889,21 @@ SpinnerExample.new.launch
|
|
2605
2889
|
- 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
2890
|
- Color alpha value defaults to `1.0` when not specified.
|
2607
2891
|
|
2608
|
-
### Custom
|
2892
|
+
### Custom Components
|
2609
2893
|
|
2610
|
-
Custom
|
2894
|
+
Custom components like custom controls, custom windows, and custom shapes can be defined to provide new features or act as composites of existing controls/shapes that need to be reused multiple times in an application or across multiple applications. Custom components save a lot of development time through reuse, improving productivity and maintainability immensely.
|
2611
2895
|
|
2612
2896
|
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
2897
|
|
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
|
2898
|
+
There are two ways to define custom components:
|
2899
|
+
- Method-Based: simply define a method representing the custom component you want (e.g. `address_view`) with any options needed (e.g. `address(address_model: some_model)`).
|
2900
|
+
- Class-Based: define a class matching the camelcased name of the custom component by convention (e.g. the `address_view` custom component keyword would have a class called `AddressView`) and `include Glimmer::LibUI::CustomControl`, `include Glimmer::LibUI::CustomWindow`, or `include Glimmer::LibUI::CustomShape` depending on if the component represents a standard control, a whole window, or an [area canvas graphics shape](#area-path-shapes). Classes add the benefit of being able to distribute the custom components into a separate file for external reuse from multiple views or for sharing as a Ruby gem.
|
2617
2901
|
|
2618
|
-
It is OK to use the terms "custom control" and "custom keyword" synonymously though "custom
|
2902
|
+
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
2903
|
|
2620
2904
|
#### Method-Based Custom Controls
|
2621
2905
|
|
2622
|
-
Simply define a method representing the custom
|
2906
|
+
Simply define a method representing the custom component you want (e.g. `address_view`) with any arguments needed (e.g. `address(address_model)`).
|
2623
2907
|
|
2624
2908
|
Example that defines `form_field`, `address_form`, `label_pair`, and `address_view` keywords (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
2625
2909
|
|
@@ -2718,9 +3002,9 @@ window('Method-Based Custom Keyword') {
|
|
2718
3002
|
|
2719
3003
|
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
|
2720
3004
|
|
2721
|
-
#### Class-Based Custom
|
3005
|
+
#### Class-Based Custom Components
|
2722
3006
|
|
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
|
3007
|
+
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
3008
|
|
2725
3009
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
2726
3010
|
|
@@ -2850,13 +3134,185 @@ ClassBasedCustomControls.launch
|
|
2850
3134
|
|
2851
3135
|
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
|
2852
3136
|
|
2853
|
-
|
3137
|
+
Example of a `cube` custom shape (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
3138
|
+
|
3139
|
+
```ruby
|
3140
|
+
require 'glimmer-dsl-libui'
|
3141
|
+
|
3142
|
+
# class-based custom shape using Glimmer::LibUI::CustomShape mixin, which automatically
|
3143
|
+
# augments the Glimmer GUI DSL with the underscored version of the class name: `cube`
|
3144
|
+
# while accepting hash options matching the options declared on the class.
|
3145
|
+
# (e.g. `cube(location_x: 50, location_y: 100)` )
|
3146
|
+
class Cube
|
3147
|
+
include Glimmer::LibUI::CustomShape
|
3148
|
+
|
3149
|
+
DEFAULT_SIZE = 28
|
3150
|
+
|
3151
|
+
option :location_x, default: 0
|
3152
|
+
option :location_y, default: 0
|
3153
|
+
option :rectangle_width, default: nil
|
3154
|
+
option :rectangle_height, default: nil
|
3155
|
+
option :cube_height, default: 75
|
3156
|
+
option :background_color, default: :brown
|
3157
|
+
option :foreground_color
|
3158
|
+
option :line_thickness, default: 1
|
3159
|
+
|
3160
|
+
# The before_body block executes before building the body
|
3161
|
+
before_body do
|
3162
|
+
self.rectangle_width ||= rectangle_height || cube_height || DEFAULT_SIZE
|
3163
|
+
self.rectangle_height ||= rectangle_width || cube_height || DEFAULT_SIZE
|
3164
|
+
self.cube_height ||= rectangle_width || rectangle_height || DEFAULT_SIZE
|
3165
|
+
if foreground_color
|
3166
|
+
self.foreground_color = Glimmer::LibUI.interpret_color(foreground_color)
|
3167
|
+
self.foreground_color[:thickness] ||= line_thickness
|
3168
|
+
else
|
3169
|
+
self.foreground_color = [0, 0, 0, thickness: line_thickness]
|
3170
|
+
end
|
3171
|
+
end
|
3172
|
+
|
3173
|
+
# Optionally, after_body could be defined to perform operations after building the body
|
3174
|
+
# like setting up observers.
|
3175
|
+
#
|
3176
|
+
# after_body do
|
3177
|
+
# end
|
3178
|
+
|
3179
|
+
body {
|
3180
|
+
# the shape keyword (alias for composite_shape) enables building a composite shape that is treated as one shape
|
3181
|
+
# like a cube containing polygons, a polyline, a rectangle, and a line
|
3182
|
+
# with the fill and stroke colors getting inherited by all children that do not specify them
|
3183
|
+
shape(location_x, location_y) {
|
3184
|
+
fill background_color
|
3185
|
+
stroke foreground_color
|
3186
|
+
|
3187
|
+
bottom = polygon(0, cube_height + rectangle_height / 2.0,
|
3188
|
+
rectangle_width / 2.0, cube_height,
|
3189
|
+
rectangle_width, cube_height + rectangle_height / 2.0,
|
3190
|
+
rectangle_width / 2.0, cube_height + rectangle_height) {
|
3191
|
+
# inherits fill property from parent shape if not set
|
3192
|
+
# inherits stroke property from parent shape if not set
|
3193
|
+
}
|
3194
|
+
body = rectangle(0, rectangle_height / 2.0, rectangle_width, cube_height) {
|
3195
|
+
# inherits fill property from parent shape if not set
|
3196
|
+
# stroke is overridden to ensure a different value from parent
|
3197
|
+
stroke thickness: 0
|
3198
|
+
}
|
3199
|
+
polyline(0, rectangle_height / 2.0 + cube_height,
|
3200
|
+
0, rectangle_height / 2.0,
|
3201
|
+
rectangle_width, rectangle_height / 2.0,
|
3202
|
+
rectangle_width, rectangle_height / 2.0 + cube_height) {
|
3203
|
+
# inherits stroke property from parent shape if not set
|
3204
|
+
}
|
3205
|
+
top = polygon(0, rectangle_height / 2.0,
|
3206
|
+
rectangle_width / 2.0, 0,
|
3207
|
+
rectangle_width, rectangle_height / 2.0,
|
3208
|
+
rectangle_width / 2.0, rectangle_height) {
|
3209
|
+
# inherits fill property from parent shape if not set
|
3210
|
+
# inherits stroke property from parent shape if not set
|
3211
|
+
}
|
3212
|
+
line(rectangle_width / 2.0, cube_height + rectangle_height,
|
3213
|
+
rectangle_width / 2.0, rectangle_height) {
|
3214
|
+
# inherits stroke property from parent shape if not set
|
3215
|
+
}
|
3216
|
+
}
|
3217
|
+
}
|
3218
|
+
end
|
3219
|
+
|
3220
|
+
class BasicCustomShape
|
3221
|
+
include Glimmer::LibUI::Application
|
3222
|
+
|
3223
|
+
body {
|
3224
|
+
window {
|
3225
|
+
title 'Basic Custom Shape'
|
3226
|
+
content_size 200, 225
|
3227
|
+
|
3228
|
+
@area = area {
|
3229
|
+
rectangle(0, 0, 200, 225) {
|
3230
|
+
fill :white
|
3231
|
+
}
|
3232
|
+
|
3233
|
+
7.times do |n|
|
3234
|
+
x_location = (rand*125).to_i%200 + (rand*15).to_i
|
3235
|
+
y_location = (rand*125).to_i%200 + (rand*15).to_i
|
3236
|
+
shape_color = [rand*125 + 130, rand*125 + 130, rand*125 + 130]
|
3237
|
+
shape_size = 20+n
|
3238
|
+
|
3239
|
+
cube(
|
3240
|
+
location_x: x_location,
|
3241
|
+
location_y: y_location,
|
3242
|
+
rectangle_width: shape_size*2,
|
3243
|
+
rectangle_height: shape_size,
|
3244
|
+
cube_height: shape_size*2,
|
3245
|
+
background_color: shape_color,
|
3246
|
+
line_thickness: 2
|
3247
|
+
) { |the_shape|
|
3248
|
+
on_mouse_up do |area_mouse_event|
|
3249
|
+
# Change color on mouse up without dragging
|
3250
|
+
if @drag_shape.nil?
|
3251
|
+
background_color = [rand(255), rand(255), rand(255)]
|
3252
|
+
the_shape.fill = background_color
|
3253
|
+
end
|
3254
|
+
end
|
3255
|
+
|
3256
|
+
on_mouse_drag_start do |area_mouse_event|
|
3257
|
+
@drag_shape = the_shape
|
3258
|
+
@drag_x = area_mouse_event[:x]
|
3259
|
+
@drag_y = area_mouse_event[:y]
|
3260
|
+
end
|
3261
|
+
|
3262
|
+
on_mouse_drag do |area_mouse_event|
|
3263
|
+
if @drag_shape && @drag_x && @drag_y
|
3264
|
+
drag_distance_width = area_mouse_event[:x] - @drag_x
|
3265
|
+
drag_distance_height = area_mouse_event[:y] - @drag_y
|
3266
|
+
@drag_shape.x += drag_distance_width
|
3267
|
+
@drag_shape.y += drag_distance_height
|
3268
|
+
@drag_x = area_mouse_event[:x]
|
3269
|
+
@drag_y = area_mouse_event[:y]
|
3270
|
+
end
|
3271
|
+
end
|
3272
|
+
|
3273
|
+
on_mouse_drop do |area_mouse_event|
|
3274
|
+
@drag_shape = nil
|
3275
|
+
@drag_x = nil
|
3276
|
+
@drag_y = nil
|
3277
|
+
end
|
3278
|
+
}
|
3279
|
+
end
|
3280
|
+
|
3281
|
+
# this general area on_mouse_drag listener is needed to ensure that dragging a shape
|
3282
|
+
# outside of its boundaries would still move the dragged shape
|
3283
|
+
on_mouse_drag do |area_mouse_event|
|
3284
|
+
if @drag_shape && @drag_x && @drag_y
|
3285
|
+
drag_distance_width = area_mouse_event[:x] - @drag_x
|
3286
|
+
drag_distance_height = area_mouse_event[:y] - @drag_y
|
3287
|
+
@drag_shape.x += drag_distance_width
|
3288
|
+
@drag_shape.y += drag_distance_height
|
3289
|
+
@drag_x = area_mouse_event[:x]
|
3290
|
+
@drag_y = area_mouse_event[:y]
|
3291
|
+
end
|
3292
|
+
end
|
3293
|
+
|
3294
|
+
on_mouse_drop do |area_mouse_event|
|
3295
|
+
@drag_shape = nil
|
3296
|
+
@drag_x = nil
|
3297
|
+
@drag_y = nil
|
3298
|
+
end
|
3299
|
+
}
|
3300
|
+
}
|
3301
|
+
}
|
3302
|
+
end
|
3303
|
+
|
3304
|
+
BasicCustomShape.launch
|
3305
|
+
```
|
3306
|
+
|
3307
|
+
![glimmer-dsl-libui-mac-basic-custom-shape.gif](/images/glimmer-dsl-libui-mac-basic-composite-shape.gif)
|
3308
|
+
|
3309
|
+
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
3310
|
|
2855
3311
|
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
3312
|
|
2857
3313
|
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
3314
|
|
2859
|
-
Learn more from custom control usage in [Method-Based Custom
|
3315
|
+
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
3316
|
|
2861
3317
|
### Observer Pattern
|
2862
3318
|
|