glimmer-dsl-libui 0.11.9 → 0.12.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 +8 -0
- data/README.md +217 -5
- data/VERSION +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md +17 -116
- data/examples/class_based_custom_control_slots.rb +150 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/custom_control_slot_content_expression.rb +44 -0
- data/lib/glimmer/dsl/libui/dsl.rb +1 -0
- data/lib/glimmer/libui/control_proxy.rb +7 -2
- data/lib/glimmer/libui/custom_control.rb +3 -2
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5f1ed415725c882407b3aa780a19d0a1d7f21ad388e1aec0f98119e781b802c
|
4
|
+
data.tar.gz: 7f5a04c65e07437ab3cc86c82187cd5840ae265d72ecb46745f1e9cc7230cf96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6fe322ae6ee6772be7d8a01d24dfce89ee3c6e5296dbef1c5084c3a55b0299219dd99b33e6652ec36d49f6154422e61c21090f3bce66d74acc4c62697d9356f4
|
7
|
+
data.tar.gz: b5512ffaa585b5be77738abbe75436ad573925196180bbe40d437ae9253439de5141290bf92cb4fef4ec30880d4ed4f1c086099ff41d162e761dca6739fe5e4d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.12.0
|
4
|
+
|
5
|
+
- Custom Control Component Slots (containers that could accept content within different parts of a Custom Component)
|
6
|
+
|
7
|
+
## 0.11.10
|
8
|
+
|
9
|
+
- Fix issue with not being able to add content to the body root of a custom control by opening a block when invoking the custom control keyword
|
10
|
+
|
3
11
|
## 0.11.9
|
4
12
|
|
5
13
|
- Support Content Data-Binding to multiple model attributes via `computed_by` option (e.g. `content(@game, :scale, computed_by: [:width, :height])` or `content(@game, computed_by: [:scale, :width, :height])` will rebuild content on changes to `:scale`, `:width`, or `:height`)
|
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.12.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)
|
@@ -28,7 +28,7 @@ The main trade-off in using [Glimmer DSL for LibUI](https://rubygems.org/gems/gl
|
|
28
28
|
- [Declarative DSL syntax](#glimmer-gui-dsl-concepts) that visually maps to the GUI control hierarchy
|
29
29
|
- [Convention over configuration](#smart-defaults-and-conventions) via smart defaults and automation of low-level details
|
30
30
|
- Requiring the [least amount of syntax](#glimmer-gui-dsl-concepts) possible to build GUI
|
31
|
-
- [Custom Component](#custom-components) support (Custom Controls, Custom Windows, and Custom Shapes), including external Ruby gems (e.g. [Graphs and Charts](https://github.com/AndyObtiva/glimmer-libui-cc-graphs_and_charts))
|
31
|
+
- [Custom Component](#custom-components) support (Custom Controls, Custom Windows, and Custom Shapes), including [Component Slots](#class-based-custom-control-slots) and external Ruby gems (e.g. [Graphs and Charts](https://github.com/AndyObtiva/glimmer-libui-cc-graphs_and_charts))
|
32
32
|
- [Bidirectional/Unidirectional Data-Binding](#data-binding) to declaratively wire and automatically synchronize GUI Views with Models
|
33
33
|
- [Scaffolding](#scaffold-application) for new custom windows/controls, apps, and gems
|
34
34
|
- [Far Future Plan] Native-Executable [packaging](#packaging) on Mac, Windows, and Linux.
|
@@ -456,7 +456,7 @@ gem install glimmer-dsl-libui
|
|
456
456
|
Or install via Bundler `Gemfile`:
|
457
457
|
|
458
458
|
```ruby
|
459
|
-
gem 'glimmer-dsl-libui', '~> 0.
|
459
|
+
gem 'glimmer-dsl-libui', '~> 0.12.0'
|
460
460
|
```
|
461
461
|
|
462
462
|
Test that installation worked by running the [Glimmer Meta-Example](#examples):
|
@@ -3073,9 +3073,11 @@ Custom components like custom controls, custom windows, and custom shapes can be
|
|
3073
3073
|
|
3074
3074
|
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.
|
3075
3075
|
|
3076
|
+
Component slots are also supported, meaning containers that could accept content within different parts of a component (e.g. `address_form` can have a `header` slot and a `footer` slot to display extra information about the address being entered).
|
3077
|
+
|
3076
3078
|
There are two ways to define custom components:
|
3077
3079
|
- 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)`).
|
3078
|
-
- 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 (e.g. [Graphs and Charts Ruby gem](https://github.com/AndyObtiva/glimmer-libui-cc-graphs_and_charts)).
|
3080
|
+
- 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 (e.g. [Graphs and Charts Ruby gem](https://github.com/AndyObtiva/glimmer-libui-cc-graphs_and_charts)). They also support Component Slots.
|
3079
3081
|
|
3080
3082
|
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`).
|
3081
3083
|
|
@@ -3182,6 +3184,8 @@ window('Method-Based Custom Keyword') {
|
|
3182
3184
|
|
3183
3185
|
#### Class-Based Custom Components
|
3184
3186
|
|
3187
|
+
##### Class-Based Custom Controls
|
3188
|
+
|
3185
3189
|
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.
|
3186
3190
|
|
3187
3191
|
Example (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
@@ -3312,6 +3316,212 @@ ClassBasedCustomControls.launch
|
|
3312
3316
|
|
3313
3317
|
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](images/glimmer-dsl-libui-mac-method-based-custom-keyword.png)
|
3314
3318
|
|
3319
|
+
##### Class-Based Custom Control Slots
|
3320
|
+
|
3321
|
+
Component can have Component Slots inside layout container controls: `vertical_box`, `horizontal_box`, `form`, and `grid`.
|
3322
|
+
|
3323
|
+
Simply pass a `slot: slot_name` option to the layout container control to designate it as a Component Slot inside a Custom Control class (in the example below, we have a `:header` slot and a `:footer` slot):
|
3324
|
+
|
3325
|
+
```ruby
|
3326
|
+
body {
|
3327
|
+
vertical_box {
|
3328
|
+
vertical_box(slot: :header) {
|
3329
|
+
stretchy false
|
3330
|
+
}
|
3331
|
+
form {
|
3332
|
+
form_field(model: address, attribute: :street)
|
3333
|
+
form_field(model: address, attribute: :p_o_box)
|
3334
|
+
form_field(model: address, attribute: :city)
|
3335
|
+
form_field(model: address, attribute: :state)
|
3336
|
+
form_field(model: address, attribute: :zip_code)
|
3337
|
+
}
|
3338
|
+
vertical_box(slot: :footer) {
|
3339
|
+
stretchy false
|
3340
|
+
}
|
3341
|
+
}
|
3342
|
+
}
|
3343
|
+
```
|
3344
|
+
|
3345
|
+
Next, in the Custom Control consuming code, open a block matching the name of the Component Slot (e.g. `header {}` and `footer {}`):
|
3346
|
+
|
3347
|
+
```ruby
|
3348
|
+
address_form(address: @address) {
|
3349
|
+
header {
|
3350
|
+
label('Billing Address') {
|
3351
|
+
stretchy false
|
3352
|
+
}
|
3353
|
+
}
|
3354
|
+
footer {
|
3355
|
+
label('Billing address is used for online payments') {
|
3356
|
+
stretchy false
|
3357
|
+
}
|
3358
|
+
}
|
3359
|
+
}
|
3360
|
+
```
|
3361
|
+
|
3362
|
+
Note that the slotted labels can include properties that apply to their Component Slot container like `stretchy false`.
|
3363
|
+
|
3364
|
+
![glimmer-dsl-libui-mac-class-based-custom-control-slots.png](/images/glimmer-dsl-libui-mac-class-based-custom-control-slots.png)
|
3365
|
+
|
3366
|
+
Example ([Class-Based Custom Control Slots](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#class-based-custom-control-slots)):
|
3367
|
+
|
3368
|
+
```ruby
|
3369
|
+
require 'glimmer-dsl-libui'
|
3370
|
+
require 'facets'
|
3371
|
+
|
3372
|
+
Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
|
3373
|
+
|
3374
|
+
class FormField
|
3375
|
+
include Glimmer::LibUI::CustomControl
|
3376
|
+
|
3377
|
+
options :model, :attribute
|
3378
|
+
|
3379
|
+
body {
|
3380
|
+
entry { |e|
|
3381
|
+
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
|
3382
|
+
text <=> [model, attribute]
|
3383
|
+
}
|
3384
|
+
}
|
3385
|
+
end
|
3386
|
+
|
3387
|
+
class AddressForm
|
3388
|
+
include Glimmer::LibUI::CustomControl
|
3389
|
+
|
3390
|
+
option :address
|
3391
|
+
|
3392
|
+
body {
|
3393
|
+
vertical_box {
|
3394
|
+
vertical_box(slot: :header) {
|
3395
|
+
stretchy false
|
3396
|
+
}
|
3397
|
+
form {
|
3398
|
+
form_field(model: address, attribute: :street)
|
3399
|
+
form_field(model: address, attribute: :p_o_box)
|
3400
|
+
form_field(model: address, attribute: :city)
|
3401
|
+
form_field(model: address, attribute: :state)
|
3402
|
+
form_field(model: address, attribute: :zip_code)
|
3403
|
+
}
|
3404
|
+
vertical_box(slot: :footer) {
|
3405
|
+
stretchy false
|
3406
|
+
}
|
3407
|
+
}
|
3408
|
+
}
|
3409
|
+
end
|
3410
|
+
|
3411
|
+
class LabelPair
|
3412
|
+
include Glimmer::LibUI::CustomControl
|
3413
|
+
|
3414
|
+
options :model, :attribute, :value
|
3415
|
+
|
3416
|
+
body {
|
3417
|
+
horizontal_box {
|
3418
|
+
label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
|
3419
|
+
label(value.to_s) {
|
3420
|
+
text <= [model, attribute]
|
3421
|
+
}
|
3422
|
+
}
|
3423
|
+
}
|
3424
|
+
end
|
3425
|
+
|
3426
|
+
class AddressView
|
3427
|
+
include Glimmer::LibUI::CustomControl
|
3428
|
+
|
3429
|
+
options :address
|
3430
|
+
|
3431
|
+
body {
|
3432
|
+
vertical_box {
|
3433
|
+
vertical_box(slot: :header) {
|
3434
|
+
stretchy false
|
3435
|
+
}
|
3436
|
+
address.each_pair do |attribute, value|
|
3437
|
+
label_pair(model: address, attribute: attribute, value: value)
|
3438
|
+
end
|
3439
|
+
}
|
3440
|
+
}
|
3441
|
+
end
|
3442
|
+
|
3443
|
+
class ClassBasedCustomControlSlots
|
3444
|
+
include Glimmer::LibUI::Application # alias: Glimmer::LibUI::CustomWindow
|
3445
|
+
|
3446
|
+
before_body do
|
3447
|
+
@address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
|
3448
|
+
@address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
|
3449
|
+
end
|
3450
|
+
|
3451
|
+
body {
|
3452
|
+
window('Class-Based Custom Control Slots') {
|
3453
|
+
margined true
|
3454
|
+
|
3455
|
+
horizontal_box {
|
3456
|
+
vertical_box {
|
3457
|
+
address_form(address: @address1) {
|
3458
|
+
header {
|
3459
|
+
label('Shipping Address') {
|
3460
|
+
stretchy false
|
3461
|
+
}
|
3462
|
+
}
|
3463
|
+
footer {
|
3464
|
+
label('Shipping address is used for mailing purchases') {
|
3465
|
+
stretchy false
|
3466
|
+
}
|
3467
|
+
}
|
3468
|
+
}
|
3469
|
+
|
3470
|
+
horizontal_separator {
|
3471
|
+
stretchy false
|
3472
|
+
}
|
3473
|
+
|
3474
|
+
address_view(address: @address1) {
|
3475
|
+
header {
|
3476
|
+
label('Shipping Address (Saved)') {
|
3477
|
+
stretchy false
|
3478
|
+
}
|
3479
|
+
}
|
3480
|
+
}
|
3481
|
+
}
|
3482
|
+
|
3483
|
+
vertical_separator {
|
3484
|
+
stretchy false
|
3485
|
+
}
|
3486
|
+
|
3487
|
+
vertical_box {
|
3488
|
+
address_form(address: @address2) {
|
3489
|
+
header {
|
3490
|
+
label('Billing Address') {
|
3491
|
+
stretchy false
|
3492
|
+
}
|
3493
|
+
}
|
3494
|
+
footer {
|
3495
|
+
label('Billing address is used for online payments') {
|
3496
|
+
stretchy false
|
3497
|
+
}
|
3498
|
+
}
|
3499
|
+
}
|
3500
|
+
|
3501
|
+
horizontal_separator {
|
3502
|
+
stretchy false
|
3503
|
+
}
|
3504
|
+
|
3505
|
+
address_view(address: @address2) {
|
3506
|
+
header {
|
3507
|
+
label('Billing Address (Saved)') {
|
3508
|
+
stretchy false
|
3509
|
+
}
|
3510
|
+
}
|
3511
|
+
}
|
3512
|
+
}
|
3513
|
+
}
|
3514
|
+
}
|
3515
|
+
}
|
3516
|
+
end
|
3517
|
+
|
3518
|
+
ClassBasedCustomControlSlots.launch
|
3519
|
+
```
|
3520
|
+
|
3521
|
+
![glimmer-dsl-libui-mac-class-based-custom-control-slots.png](/images/glimmer-dsl-libui-mac-class-based-custom-control-slots.png)
|
3522
|
+
|
3523
|
+
##### Class-Based Custom Shapes
|
3524
|
+
|
3315
3525
|
Example of a `cube` custom shape (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
3316
3526
|
|
3317
3527
|
```ruby
|
@@ -3484,13 +3694,15 @@ BasicCustomShape.launch
|
|
3484
3694
|
|
3485
3695
|
![glimmer-dsl-libui-mac-basic-custom-shape.gif](/images/glimmer-dsl-libui-mac-basic-composite-shape.gif)
|
3486
3696
|
|
3697
|
+
##### Class-Based Custom Windows (Applications)
|
3698
|
+
|
3487
3699
|
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.
|
3488
3700
|
|
3489
3701
|
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.
|
3490
3702
|
|
3491
3703
|
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.
|
3492
3704
|
|
3493
|
-
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.
|
3705
|
+
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), [Class-Based Custom Control Slots](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#class-based-custom-control-slots), [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.
|
3494
3706
|
|
3495
3707
|
### Observer Pattern
|
3496
3708
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.12.0
|
@@ -20,6 +20,7 @@
|
|
20
20
|
- [Login](#login)
|
21
21
|
- [Method-Based Custom Controls](#method-based-custom-controls)
|
22
22
|
- [Class-Based Custom Controls](#class-based-custom-controls)
|
23
|
+
- [Class-Based Custom Control Slots](#class-based-custom-control-slots)
|
23
24
|
- [Area-Based Custom Controls](#area-based-custom-controls)
|
24
25
|
- [Midi Player](#midi-player)
|
25
26
|
- [Snake](#snake)
|
@@ -1546,131 +1547,31 @@ Mac | Windows | Linux
|
|
1546
1547
|
----|---------|------
|
1547
1548
|
![glimmer-dsl-libui-mac-method-based-custom-keyword.png](/images/glimmer-dsl-libui-mac-method-based-custom-keyword.png) | ![glimmer-dsl-libui-windows-method-based-custom-keyword.png](/images/glimmer-dsl-libui-windows-method-based-custom-keyword.png) | ![glimmer-dsl-libui-linux-method-based-custom-keyword.png](/images/glimmer-dsl-libui-linux-method-based-custom-keyword.png)
|
1548
1549
|
|
1549
|
-
|
1550
|
+
## Class-Based Custom Control Slots
|
1550
1551
|
|
1551
|
-
|
1552
|
-
require 'glimmer-dsl-libui'
|
1553
|
-
require 'facets'
|
1552
|
+
Class-Based Custom Controls support slots, which enable adding content to various parts of a custom control, like a header, a footer, etc...
|
1554
1553
|
|
1555
|
-
|
1554
|
+
Code: [examples/class_based_custom_control_slots.rb](/examples/class_based_custom_control_slots.rb)
|
1556
1555
|
|
1557
|
-
|
1558
|
-
include Glimmer::LibUI::CustomControl
|
1559
|
-
|
1560
|
-
options :model, :attribute
|
1561
|
-
|
1562
|
-
body {
|
1563
|
-
entry { |e|
|
1564
|
-
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
|
1565
|
-
text <=> [model, attribute]
|
1566
|
-
}
|
1567
|
-
}
|
1568
|
-
end
|
1556
|
+
Run with `glimmer examples` command if you installed the [glimmer-dsl-libui Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
1569
1557
|
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
options :address
|
1574
|
-
|
1575
|
-
body {
|
1576
|
-
form {
|
1577
|
-
form_field(model: address, attribute: :street)
|
1578
|
-
form_field(model: address, attribute: :p_o_box)
|
1579
|
-
form_field(model: address, attribute: :city)
|
1580
|
-
form_field(model: address, attribute: :state)
|
1581
|
-
form_field(model: address, attribute: :zip_code)
|
1582
|
-
}
|
1583
|
-
}
|
1584
|
-
end
|
1558
|
+
```
|
1559
|
+
glimmer examples
|
1560
|
+
```
|
1585
1561
|
|
1586
|
-
|
1587
|
-
include Glimmer::LibUI::CustomControl
|
1588
|
-
|
1589
|
-
options :model, :attribute, :value
|
1590
|
-
|
1591
|
-
body {
|
1592
|
-
horizontal_box {
|
1593
|
-
label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
|
1594
|
-
label(value.to_s) {
|
1595
|
-
text <= [model, attribute]
|
1596
|
-
}
|
1597
|
-
}
|
1598
|
-
}
|
1599
|
-
end
|
1562
|
+
Run directly with this command if you installed the [glimmer-dsl-libui Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
1600
1563
|
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
options :address
|
1605
|
-
|
1606
|
-
body {
|
1607
|
-
vertical_box {
|
1608
|
-
address.each_pair do |attribute, value|
|
1609
|
-
label_pair(model: address, attribute: attribute, value: value)
|
1610
|
-
end
|
1611
|
-
}
|
1612
|
-
}
|
1613
|
-
end
|
1564
|
+
```
|
1565
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/class_based_custom_control_slots'"
|
1566
|
+
```
|
1614
1567
|
|
1615
|
-
|
1616
|
-
include Glimmer::LibUI::Application # alias: Glimmer::LibUI::CustomWindow
|
1617
|
-
|
1618
|
-
before_body do
|
1619
|
-
@address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
|
1620
|
-
@address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
|
1621
|
-
end
|
1622
|
-
|
1623
|
-
body {
|
1624
|
-
window('Class-Based Custom Keyword') {
|
1625
|
-
margined true
|
1626
|
-
|
1627
|
-
horizontal_box {
|
1628
|
-
vertical_box {
|
1629
|
-
label('Address 1') {
|
1630
|
-
stretchy false
|
1631
|
-
}
|
1632
|
-
|
1633
|
-
address_form(address: @address1)
|
1634
|
-
|
1635
|
-
horizontal_separator {
|
1636
|
-
stretchy false
|
1637
|
-
}
|
1638
|
-
|
1639
|
-
label('Address 1 (Saved)') {
|
1640
|
-
stretchy false
|
1641
|
-
}
|
1642
|
-
|
1643
|
-
address_view(address: @address1)
|
1644
|
-
}
|
1645
|
-
|
1646
|
-
vertical_separator {
|
1647
|
-
stretchy false
|
1648
|
-
}
|
1649
|
-
|
1650
|
-
vertical_box {
|
1651
|
-
label('Address 2') {
|
1652
|
-
stretchy false
|
1653
|
-
}
|
1654
|
-
|
1655
|
-
address_form(address: @address2)
|
1656
|
-
|
1657
|
-
horizontal_separator {
|
1658
|
-
stretchy false
|
1659
|
-
}
|
1660
|
-
|
1661
|
-
label('Address 2 (Saved)') {
|
1662
|
-
stretchy false
|
1663
|
-
}
|
1664
|
-
|
1665
|
-
address_view(address: @address2)
|
1666
|
-
}
|
1667
|
-
}
|
1668
|
-
}
|
1669
|
-
}
|
1670
|
-
end
|
1568
|
+
Run with this command from the root of the project if you cloned the project:
|
1671
1569
|
|
1672
|
-
ClassBasedCustomControls.launch
|
1673
1570
|
```
|
1571
|
+
bin/glimmer examples/class_based_custom_control_slots.rb
|
1572
|
+
```
|
1573
|
+
|
1574
|
+
![glimmer-dsl-libui-mac-class-based-custom-control-slots.png](/images/glimmer-dsl-libui-mac-class-based-custom-control-slots.png)
|
1674
1575
|
|
1675
1576
|
## Area-Based Custom Controls
|
1676
1577
|
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
require 'facets'
|
3
|
+
|
4
|
+
Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
|
5
|
+
|
6
|
+
class FormField
|
7
|
+
include Glimmer::LibUI::CustomControl
|
8
|
+
|
9
|
+
options :model, :attribute
|
10
|
+
|
11
|
+
body {
|
12
|
+
entry { |e|
|
13
|
+
label attribute.to_s.underscore.split('_').map(&:capitalize).join(' ')
|
14
|
+
text <=> [model, attribute]
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
class AddressForm
|
20
|
+
include Glimmer::LibUI::CustomControl
|
21
|
+
|
22
|
+
option :address
|
23
|
+
|
24
|
+
body {
|
25
|
+
vertical_box {
|
26
|
+
vertical_box(slot: :header) {
|
27
|
+
stretchy false
|
28
|
+
}
|
29
|
+
form {
|
30
|
+
form_field(model: address, attribute: :street)
|
31
|
+
form_field(model: address, attribute: :p_o_box)
|
32
|
+
form_field(model: address, attribute: :city)
|
33
|
+
form_field(model: address, attribute: :state)
|
34
|
+
form_field(model: address, attribute: :zip_code)
|
35
|
+
}
|
36
|
+
vertical_box(slot: :footer) {
|
37
|
+
stretchy false
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
class LabelPair
|
44
|
+
include Glimmer::LibUI::CustomControl
|
45
|
+
|
46
|
+
options :model, :attribute, :value
|
47
|
+
|
48
|
+
body {
|
49
|
+
horizontal_box {
|
50
|
+
label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
|
51
|
+
label(value.to_s) {
|
52
|
+
text <= [model, attribute]
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
class AddressView
|
59
|
+
include Glimmer::LibUI::CustomControl
|
60
|
+
|
61
|
+
options :address
|
62
|
+
|
63
|
+
body {
|
64
|
+
vertical_box {
|
65
|
+
vertical_box(slot: :header) {
|
66
|
+
stretchy false
|
67
|
+
}
|
68
|
+
address.each_pair do |attribute, value|
|
69
|
+
label_pair(model: address, attribute: attribute, value: value)
|
70
|
+
end
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
class ClassBasedCustomControlSlots
|
76
|
+
include Glimmer::LibUI::Application # alias: Glimmer::LibUI::CustomWindow
|
77
|
+
|
78
|
+
before_body do
|
79
|
+
@address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
|
80
|
+
@address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
|
81
|
+
end
|
82
|
+
|
83
|
+
body {
|
84
|
+
window('Class-Based Custom Control Slots') {
|
85
|
+
margined true
|
86
|
+
|
87
|
+
horizontal_box {
|
88
|
+
vertical_box {
|
89
|
+
address_form(address: @address1) {
|
90
|
+
header {
|
91
|
+
label('Shipping Address') {
|
92
|
+
stretchy false
|
93
|
+
}
|
94
|
+
}
|
95
|
+
footer {
|
96
|
+
label('Shipping address is used for mailing purchases') {
|
97
|
+
stretchy false
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
horizontal_separator {
|
103
|
+
stretchy false
|
104
|
+
}
|
105
|
+
|
106
|
+
address_view(address: @address1) {
|
107
|
+
header {
|
108
|
+
label('Shipping Address (Saved)') {
|
109
|
+
stretchy false
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
vertical_separator {
|
116
|
+
stretchy false
|
117
|
+
}
|
118
|
+
|
119
|
+
vertical_box {
|
120
|
+
address_form(address: @address2) {
|
121
|
+
header {
|
122
|
+
label('Billing Address') {
|
123
|
+
stretchy false
|
124
|
+
}
|
125
|
+
}
|
126
|
+
footer {
|
127
|
+
label('Billing address is used for online payments') {
|
128
|
+
stretchy false
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
horizontal_separator {
|
134
|
+
stretchy false
|
135
|
+
}
|
136
|
+
|
137
|
+
address_view(address: @address2) {
|
138
|
+
header {
|
139
|
+
label('Billing Address (Saved)') {
|
140
|
+
stretchy false
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
ClassBasedCustomControlSlots.launch
|
data/glimmer-dsl-libui.gemspec
CHANGED
Binary file
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright (c) 2021-2024 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer'
|
23
|
+
require 'glimmer/dsl/expression'
|
24
|
+
require 'glimmer/libui/custom_control'
|
25
|
+
|
26
|
+
module Glimmer
|
27
|
+
module DSL
|
28
|
+
module Libui
|
29
|
+
class CustomControlSlotContentExpression < Expression
|
30
|
+
def can_interpret?(parent, keyword, *args, &block)
|
31
|
+
slot = keyword.to_s.to_sym
|
32
|
+
block_given? &&
|
33
|
+
parent.is_a?(Glimmer::LibUI::CustomControl) &&
|
34
|
+
parent.slot_controls.keys.include?(slot)
|
35
|
+
end
|
36
|
+
|
37
|
+
def interpret(parent, keyword, *args, &block)
|
38
|
+
slot = keyword.to_s.to_sym
|
39
|
+
parent.slot_controls[slot]&.content(&block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -126,13 +126,18 @@ module Glimmer
|
|
126
126
|
]
|
127
127
|
|
128
128
|
# libui returns the contained LibUI object
|
129
|
-
attr_reader :parent_proxy, :libui, :args, :keyword, :block, :content_added
|
129
|
+
attr_reader :parent_proxy, :parent_custom_control, :custom_control, :libui, :args, :options, :slot, :keyword, :block, :content_added
|
130
130
|
alias content_added? content_added
|
131
131
|
|
132
132
|
def initialize(keyword, parent, args, &block)
|
133
133
|
@keyword = keyword
|
134
|
-
@
|
134
|
+
@custom_control = CustomControl.custom_controls_being_interpreted.last
|
135
|
+
@parent_custom_control = parent if parent.is_a?(CustomControl)
|
136
|
+
@parent_proxy = parent.is_a?(CustomControl) ? parent.body_root : parent
|
135
137
|
@args = args
|
138
|
+
@options = args.last.is_a?(Hash) ? args.pop : {}
|
139
|
+
@slot = options[:slot]
|
140
|
+
custom_control.slot_controls[@slot] = self if @slot && custom_control
|
136
141
|
@block = block
|
137
142
|
@enabled = true
|
138
143
|
build_control
|
@@ -171,7 +171,7 @@ module Glimmer
|
|
171
171
|
end_eval
|
172
172
|
end
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
175
|
def before_body(&block)
|
176
176
|
@before_body_block = block
|
177
177
|
end
|
@@ -189,13 +189,14 @@ module Glimmer
|
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
-
attr_reader :body_root, :libui, :parent, :parent_proxy, :args, :keyword, :content, :options
|
192
|
+
attr_reader :body_root, :libui, :parent, :parent_proxy, :args, :keyword, :content, :options, :slot_controls
|
193
193
|
|
194
194
|
def initialize(keyword, parent, args, options, &content)
|
195
195
|
CustomControl.custom_controls_being_interpreted << self
|
196
196
|
@parent_proxy = @parent = parent
|
197
197
|
options ||= {}
|
198
198
|
@options = self.class.options.merge(options)
|
199
|
+
@slot_controls = {}
|
199
200
|
@content = ProcTracker.new(content) if content
|
200
201
|
execute_hook('before_body')
|
201
202
|
body_block = self.class.instance_variable_get("@body_block")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer-dsl-libui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
61
|
+
version: 1.0.0
|
62
62
|
- - "<"
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: 2.0.0
|
@@ -68,7 +68,7 @@ dependencies:
|
|
68
68
|
requirements:
|
69
69
|
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: 0.
|
71
|
+
version: 1.0.0
|
72
72
|
- - "<"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: 2.0.0
|
@@ -423,6 +423,7 @@ files:
|
|
423
423
|
- examples/basic_window.rb
|
424
424
|
- examples/basic_window2.rb
|
425
425
|
- examples/button_counter.rb
|
426
|
+
- examples/class_based_custom_control_slots.rb
|
426
427
|
- examples/class_based_custom_controls.rb
|
427
428
|
- examples/color_button.rb
|
428
429
|
- examples/color_button2.rb
|
@@ -504,6 +505,7 @@ files:
|
|
504
505
|
- lib/glimmer/dsl/libui/content_expression.rb
|
505
506
|
- lib/glimmer/dsl/libui/control_expression.rb
|
506
507
|
- lib/glimmer/dsl/libui/custom_control_expression.rb
|
508
|
+
- lib/glimmer/dsl/libui/custom_control_slot_content_expression.rb
|
507
509
|
- lib/glimmer/dsl/libui/custom_shape_expression.rb
|
508
510
|
- lib/glimmer/dsl/libui/data_binding_expression.rb
|
509
511
|
- lib/glimmer/dsl/libui/dsl.rb
|