glimmer-dsl-tk 0.0.24 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +548 -100
- data/VERSION +1 -1
- data/glimmer-dsl-tk.gemspec +0 -0
- data/lib/glimmer/dsl/tk/format_expression.rb +39 -0
- data/lib/glimmer/dsl/tk/root_expression.rb +1 -1
- data/lib/glimmer/tk/drag_and_drop_extension.rb +112 -0
- data/lib/glimmer/tk/frame_proxy.rb +8 -0
- data/lib/glimmer/tk/label_proxy.rb +0 -9
- data/lib/glimmer/tk/radiobutton_proxy.rb +1 -1
- data/lib/glimmer/tk/root_proxy.rb +17 -35
- data/lib/glimmer/tk/spinbox_proxy.rb +52 -0
- data/lib/glimmer/tk/text_proxy.rb +350 -0
- data/lib/glimmer/tk/widget_proxy.rb +109 -35
- data/samples/elaborate/meta_sample.rb +138 -0
- data/samples/hello/hello_checkbutton.rb +0 -1
- data/samples/hello/hello_combobox.rb +2 -1
- data/samples/hello/hello_drag_and_drop.rb +159 -0
- data/samples/hello/hello_entry.rb +2 -2
- data/samples/hello/hello_radiobutton.rb +21 -1
- data/samples/hello/hello_spinbox.rb +75 -0
- data/samples/hello/hello_text.rb +222 -0
- data/samples/hello/images/copy.png +0 -0
- data/samples/hello/images/cut.png +0 -0
- data/samples/hello/images/paste.png +0 -0
- data/samples/hello/images/redo.png +0 -0
- data/samples/hello/images/undo.png +0 -0
- metadata +19 -6
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 Tk 0.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 Tk 0.0.28
|
2
2
|
## MRI Ruby Desktop Development GUI Library
|
3
3
|
[](http://badge.fury.io/rb/glimmer-dsl-tk)
|
4
4
|
[](https://github.com/AndyObtiva/glimmer-dsl-tk/actions/workflows/ruby.yml)
|
@@ -10,11 +10,9 @@
|
|
10
10
|
|
11
11
|
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [Tk](https://www.tcl.tk/) enables desktop development with [Glimmer](https://github.com/AndyObtiva/glimmer) in [Ruby](https://github.com/ruby/ruby).
|
12
12
|
|
13
|
-
[Tcl/Tk](https://www.tcl.tk/) has recently improved by gaining native looking themed widgets on Mac, Windows, and Linux in [Tk version 8.5](https://www.tcl.tk/software/tcltk/8.5.html#:~:text=Highlights%20of%20Tk%208.5&text=Font%20rendering%3A%20Now%20uses%20anti,and%20window%20layout%2C%20and%20more.).
|
13
|
+
[Tcl/Tk](https://www.tcl.tk/) has recently improved by gaining native looking themed widgets on Mac, Windows, and Linux in [Tk version 8.5](https://www.tcl.tk/software/tcltk/8.5.html#:~:text=Highlights%20of%20Tk%208.5&text=Font%20rendering%3A%20Now%20uses%20anti,and%20window%20layout%2C%20and%20more.). Additionally, [Ruby](https://www.ruby-lang.org/en/) 3.0 Ractor (formerly known as [Guilds](https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/)) supports truly parallel multi-threading, making both [MRI](https://github.com/ruby/ruby) and [Tk](https://www.tcl.tk/) finally viable for support in [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library) as an alternative to [JRuby on SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
The trade-off is that while [SWT](https://www.eclipse.org/swt/) provides a plethora of high quality reusable widgets for the Enterprise (such as [Nebula](https://www.eclipse.org/nebula/)), [Tk](https://www.tcl.tk/) enables very fast app startup time and a small memory footprint via [MRI Ruby](https://www.ruby-lang.org/en/).
|
15
|
+
The trade-off is that while [SWT](https://www.eclipse.org/swt/) provides a plethora of high quality reusable widgets for the Enterprise (such as [Nebula](https://github.com/AndyObtiva/glimmer-cw-nebula)), [Tk](https://www.tcl.tk/) has a very fast app startup time and a small memory footprint courtesy of [MRI Ruby](https://www.ruby-lang.org/en/).
|
18
16
|
|
19
17
|
[Glimmer DSL for Tk](https://github.com/AndyObtiva/glimmer-dsl-tk) aims to provide a DSL similar to the [Glimmer DSL for SWT](https://github.com/AndyObtiva/glimmer-dsl-swt) to enable more productive desktop development in Ruby with:
|
20
18
|
- Declarative DSL syntax that visually maps to the GUI widget hierarchy
|
@@ -76,18 +74,23 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
|
|
76
74
|
- [Supported Widgets](#supported-widgets)
|
77
75
|
- [Common Attributes](#common-attributes)
|
78
76
|
- [Common Themed Widget States](#common-themed-widget-states)
|
79
|
-
|
77
|
+
- [Text API](#text-api)
|
78
|
+
- [Smart Defaults and Conventions](#smart-defaults-and-conventions)
|
80
79
|
- [Grid Layout](#grid-layout)
|
81
|
-
- [
|
80
|
+
- [Image Attribute](#image-attribute)
|
81
|
+
- [Frame Padding](#frame-padding)
|
82
82
|
- [Notebook Frame](#notebook-frame)
|
83
83
|
- [Icon Photo](#icon-photo)
|
84
|
+
- [Root Background](#root-background)
|
85
|
+
- [Text Defaults](#text-defaults)
|
84
86
|
- [The Grid Geometry Manager](#the-grid-geometry-manager)
|
85
|
-
- [
|
87
|
+
- [Data-Binding](#data-binding)
|
86
88
|
- [Label Data-Binding](#label-data-binding)
|
87
89
|
- [Combobox Data-Binding](#combobox-data-binding)
|
88
90
|
- [List Single Selection Data-Binding](#list-single-selection-data-binding)
|
89
91
|
- [List Multi Selection Data-Binding](#list-multi-selection-data-binding)
|
90
92
|
- [Entry Data-Binding](#entry-data-binding)
|
93
|
+
- [Spinbox Data-Binding](#spinbox-data-binding)
|
91
94
|
- [Checkbutton Data-Binding](#checkbutton-data-binding)
|
92
95
|
- [Radiobutton Data-Binding](#radiobutton-data-binding)
|
93
96
|
- [Command Callback](#command-callback)
|
@@ -106,7 +109,10 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
|
|
106
109
|
- [Hello, List Single Selection!](#hello-list-single-selection)
|
107
110
|
- [Hello, List Multi Selection!](#hello-list-multi-selection)
|
108
111
|
- [Hello, Entry!](#hello-entry)
|
112
|
+
- [Hello, Text!](#hello-text)
|
113
|
+
- [Hello, Spinbox!](#hello-spinbox)
|
109
114
|
- [Hello, Computed!](#hello-computed)
|
115
|
+
- [Hello, Drag and Drop!](#hello-drag-and-drop)
|
110
116
|
- [Help](#help)
|
111
117
|
- [Issues](#issues)
|
112
118
|
- [Chat](#chat)
|
@@ -143,7 +149,7 @@ gem install glimmer-dsl-tk
|
|
143
149
|
|
144
150
|
Add the following to `Gemfile`:
|
145
151
|
```
|
146
|
-
gem 'glimmer-dsl-tk', '~> 0.0.
|
152
|
+
gem 'glimmer-dsl-tk', '~> 0.0.28'
|
147
153
|
```
|
148
154
|
|
149
155
|
And, then run:
|
@@ -256,6 +262,7 @@ keyword(args) | attributes | event bindings & callbacks
|
|
256
262
|
`checkbutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `onvalue` (default: `1`), `offvalue` (default: `0`) | `command {}`
|
257
263
|
`combobox` | `state`, `text` | `'ComboboxSelected'`
|
258
264
|
`entry` | `width`, `text`, `validate`, `show` (`'none', 'focus', 'focusin', 'focusout', 'key', or 'all'`) | `'validate'`, `'invalid'`, `'change'`, `validatecommand {}`, `invalidcommand {}`
|
265
|
+
`spinbox` | `text`, `from`, `to`, `increment`, `format`, [more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `command {}`, `'increment'`, `'decrement'`
|
259
266
|
`frame(text: nil)` | `width`, `height`, `borderwidth`, `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`) | None
|
260
267
|
`label` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `font` (`'default', 'text', 'fixed', 'menu', 'heading', 'caption', 'small_caption', 'icon', 'tooltip'`), `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`), `justify` (`'left', 'center', 'right'`), `foreground`, `background` | None
|
261
268
|
`list` | `selectmode`, `selection` | None
|
@@ -263,6 +270,7 @@ keyword(args) | attributes | event bindings & callbacks
|
|
263
270
|
`notebook` | None | None
|
264
271
|
`radiobutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `value` (default: `text`) | `command {}`
|
265
272
|
`root` | `title`, `iconphoto`, `background`, `alpha`, `fullscreen?`, `topmost?`, `transparent?`, `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`, `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`) | `'DELETE_WINDOW'`, `'OPEN_WINDOW'`
|
273
|
+
`text` | `text`, [many more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `'modified'`, `'selection'`
|
266
274
|
|
267
275
|
#### Common Attributes
|
268
276
|
|
@@ -312,7 +320,68 @@ keyword(args) | attributes | event bindings & callbacks
|
|
312
320
|
- `invalid?`
|
313
321
|
- `hover?`
|
314
322
|
|
315
|
-
|
323
|
+
#### Text API
|
324
|
+
|
325
|
+
[Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) automatically provides a `text` attribute for the `text` widget that enables updating its content simply without worrying about whether to manually insert by index, delete, or append.
|
326
|
+
|
327
|
+
Also, the `text` widget is enhanced by [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) to enable simpler manipulation of text options without dealing with [tags](https://tkdocs.com/tutorial/text.html) directly. Simply specify region to mutate and option/value or font_option/value, and [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) takes care of the rest by automating work of adding/removing [tags](https://tkdocs.com/tutorial/text.html) behind the scenes.
|
328
|
+
|
329
|
+
- `add_format(region_start, region_end, option, value)`
|
330
|
+
- `remove_format(region_start, region_end, option, value)`
|
331
|
+
- `toggle_format(region_start, region_end, option, value)`
|
332
|
+
- `add_font_format(region_start, region_end, font_option, value)`
|
333
|
+
- `remove_font_format(region_start, region_end, font_option, value)`
|
334
|
+
- `toggle_font_format(region_start, region_end, font_option, value)`
|
335
|
+
- `add_selection_format(region_start, region_end, option, value)`
|
336
|
+
- `remove_selection_format(region_start, region_end, option, value)`
|
337
|
+
- `toggle_selection_format(region_start, region_end, option, value)`
|
338
|
+
- `add_selection_font_format(region_start, region_end, font_option, value)`
|
339
|
+
- `remove_selection_font_format(region_start, region_end, font_option, value)`
|
340
|
+
- `toggle_selection_font_format(region_start, region_end, font_option, value)`
|
341
|
+
|
342
|
+
Available options:
|
343
|
+
|
344
|
+
- `background`
|
345
|
+
- `bgstipple`
|
346
|
+
- `borderwidth`
|
347
|
+
- `elide`
|
348
|
+
- `fgstipple`
|
349
|
+
- `foreground`
|
350
|
+
- `justify`
|
351
|
+
- `lmargin1`
|
352
|
+
- `lmargin2`
|
353
|
+
- `offset`
|
354
|
+
- `overstrike`
|
355
|
+
- `relief`
|
356
|
+
- `rmargin`
|
357
|
+
- `spacing1`
|
358
|
+
- `spacing2`
|
359
|
+
- `spacing3`
|
360
|
+
- `tabs`
|
361
|
+
- `tabstyle`
|
362
|
+
- `underline`
|
363
|
+
- `wrap`
|
364
|
+
|
365
|
+
Available font options:
|
366
|
+
|
367
|
+
- `family` (default: `'Courier New'`)
|
368
|
+
- `size` (default: `13`)
|
369
|
+
- `weight` (default: `'normal'`) (e.g. `'bold'`)
|
370
|
+
- `slant` (default: `'roman'`) (e.g. `'italic`')
|
371
|
+
- `underline` (default: `false`)
|
372
|
+
- `overstrike` (default: `false`)
|
373
|
+
|
374
|
+
Other useful built-in API methods:
|
375
|
+
|
376
|
+
- `text_cut`
|
377
|
+
- `text_copy`
|
378
|
+
- `text_paste`
|
379
|
+
- `text_edit_undo`
|
380
|
+
- `text_edit_redo`
|
381
|
+
|
382
|
+
Check out the [Hello, Text!](#hello-text) sample for a good demonstration of the `text` widget features.
|
383
|
+
|
384
|
+
### Smart Defaults and Conventions
|
316
385
|
|
317
386
|
#### Event Bindings
|
318
387
|
|
@@ -320,11 +389,25 @@ Any events that normally can be accepted by the Tk `bind` or `protocol` methods
|
|
320
389
|
|
321
390
|
#### Grid Layout
|
322
391
|
|
323
|
-
`grid` layout is the default on
|
392
|
+
`grid` layout with `sticky: 'nsew'` is the default on all widgets except toplevel widgets.
|
393
|
+
|
394
|
+
Also, any widget that is the first in a series of siblings has `column_weight` as `1` to automatically resize with window resizing by default.
|
395
|
+
|
396
|
+
To override that behavior, you may set alternative `grid` keyword args if needed (e.g. `grid sticky: '', column_weight: 0` disables the smart defaults).
|
324
397
|
|
325
|
-
####
|
398
|
+
#### Image Attribute
|
326
399
|
|
327
|
-
|
400
|
+
Widget `image` attribute (e.g. `label` `image`) can accept image path directly as an alternative to `TkPhotoImage` object in addition to key values for automatic processing of image:
|
401
|
+
- `subsample(x_divider, y_divider)`: Specifies that the source image should be reduced in size by using only every xth pixel in the X direction and yth pixel in the Y direction. Negative values will cause the image to be flipped about the Y or X axes, respectively. If y is not given, the default value is the same as x.
|
402
|
+
- `zoom(x_multiplier, y_multiplier)`: Specifies that the source region should be magnified by a factor of x in the X direction and y in the Y direction. If y is not given, the default value is the same as x. With this option, each pixel in the source image will be expanded into a block of x x y pixels in the destination image, all the same color. x and y must be greater than 0.
|
403
|
+
- `from(x1, y1, x2, y2)`: Specifies a rectangular sub-region of the source image to be copied. (x1,y1) and (x2,y2) specify diagonally opposite corners of the rectangle. If x2 and y2 are not specified, the default value is the bottom-right corner of the source image. The pixels copied will include the left and top edges of the specified rectangle but not the bottom or right edges. If the :from option is not given, the default is the whole source image.
|
404
|
+
- `to(x1, y1, x2, y2)`: Specifies a rectangular sub-region of the destination image to be affected. (x1,y1) and (x2,y2) specify diagonally opposite corners of the rectangle. If x2 and y2 are not specified, the default value is (x1,y1) plus the size of the source region (after subsampling and zooming, if specified). If x2 and y2 are specified, the source region will be replicated if necessary to fill the destination region in a tiled fashion.
|
405
|
+
- `shrink`: Specifies that the size of the destination image should be reduced, if necessary, so that the region being copied into is at the bottom-right corner of the image. This option will not affect the width or height of the image if the user has specified a non-zero value for the :width or :height configuration option, respectively.
|
406
|
+
- `compositingrule` (can be `'overlay'` or `'set'`): Specifies how transparent pixels in the source image are combined with the destination image. When a compositing rule of <tt>overlay</tt> is set, the old contents of the destination image are visible, as if the source image were printed on a piece of transparent film and placed over the top of the destination. When a compositing rule of <tt>set</tt> is set, the old contents of the destination image are discarded and the source image is used as-is. The default compositing rule is <tt>overlay</tt>.
|
407
|
+
|
408
|
+
#### Frame Padding
|
409
|
+
|
410
|
+
Frames have a padding of `15` all around by default to produce more user-friendly graphical user interfaces.
|
328
411
|
|
329
412
|
#### Notebook Frame
|
330
413
|
|
@@ -354,6 +437,16 @@ root {
|
|
354
437
|
}.open
|
355
438
|
```
|
356
439
|
|
440
|
+
#### Root Background
|
441
|
+
|
442
|
+
`root` `background` color attribute is automatically set to `'#ececec'` on the Mac to avoid having a non-native-looking light-colored background.
|
443
|
+
|
444
|
+
#### Text Defaults
|
445
|
+
|
446
|
+
`text` widget has these defaults:
|
447
|
+
- `wrap = 'none'`
|
448
|
+
- `font = {family: 'Courier New'}`
|
449
|
+
|
357
450
|
## The Grid Geometry Manager
|
358
451
|
|
359
452
|
The Grid Geometry Manager is supported via the `grid` keyword just as per the [Tk documentation](https://tkdocs.com/tutorial/grid.html), except by nesting under the widget it concerns.
|
@@ -372,9 +465,17 @@ Example:
|
|
372
465
|
}
|
373
466
|
```
|
374
467
|
|
468
|
+
Extra convenience options may be passed to `grid` when using [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk):
|
469
|
+
- `min_width`: alias for `columnminsize` being called on `TkGrid.columnconfigure`
|
470
|
+
- `min_height`: alias for `rowminsize` being called on `TkGrid.rowconfigure`
|
471
|
+
- `column_weight`: alias for `columnweight` being called on `TkGrid.columnconfigure`
|
472
|
+
- `row_weight`: alias for `rowweight` being called on `TkGrid.rowconfigure`
|
473
|
+
|
474
|
+
Note also the [Grid Layout](#grid-layout) conventions (e.g. `column_weight` is automatically set to `1` for the first widget in a series of siblings to automatically have all resize when window resize)
|
475
|
+
|
375
476
|
More details can be found in the [Hello, Computed!](#hello-computed) sample below.
|
376
477
|
|
377
|
-
##
|
478
|
+
## Data-Binding
|
378
479
|
|
379
480
|
Glimmer supports Shine syntax bidirectional data-binding via the `<=>` operator (read-write) and unidirectional data-binding via the `<=` operator (read-only), which takes a model and an attribute (the `bind` keyword may also be used as the old-style of data-binding).
|
380
481
|
|
@@ -404,7 +505,7 @@ This assumes a `Person` model with a `country` attribute representing their curr
|
|
404
505
|
|
405
506
|
```ruby
|
406
507
|
combobox {
|
407
|
-
|
508
|
+
readonly true # this applies to text editing only (item selection still triggers a write to model)
|
408
509
|
text <=> [person, :country]
|
409
510
|
}
|
410
511
|
```
|
@@ -477,6 +578,28 @@ It automatically handles all the Tk plumbing behind the scenes.
|
|
477
578
|
|
478
579
|
More details can be found in [Hello, Entry!](#hello-entry) and [Hello, Computed!](#hello-computed) samples below.
|
479
580
|
|
581
|
+
### Spinbox Data-Binding
|
582
|
+
|
583
|
+
Example:
|
584
|
+
|
585
|
+
This assumes a `Person` model with a `donation` attribute.
|
586
|
+
|
587
|
+
```ruby
|
588
|
+
spinbox {
|
589
|
+
from 1.0 # minimum value
|
590
|
+
to 150.0 # maximum value
|
591
|
+
increment 5.0 # increment on up and down
|
592
|
+
format '%0.2f'
|
593
|
+
text <=> [person, :country]
|
594
|
+
}
|
595
|
+
```
|
596
|
+
|
597
|
+
That code binds the `textvariable` value of the `spinbox` to the `donation` attribute on the `person` model.
|
598
|
+
|
599
|
+
It automatically handles all the Tk plumbing behind the scenes.
|
600
|
+
|
601
|
+
More details can be found in [Hello, Spinbox!](#hello-spinbox) sample below.
|
602
|
+
|
480
603
|
### Checkbutton Data-Binding
|
481
604
|
|
482
605
|
Example:
|
@@ -525,7 +648,7 @@ More details can be found in the [Hello, Radiobutton!](#hello-radiobutton) sampl
|
|
525
648
|
|
526
649
|
## Command Callback
|
527
650
|
|
528
|
-
`button` and `checkbutton` can set a `command` block to trigger when the user clicks the button/checkbutton. This may be done with the `command` keyword, passing in a block directly.
|
651
|
+
`button`, `spinbox`, `radiobutton` and `checkbutton` can set a `command` block to trigger when the user clicks the button/checkbutton. This may be done with the `command` keyword, passing in a block directly.
|
529
652
|
|
530
653
|
Example:
|
531
654
|
|
@@ -539,6 +662,18 @@ Example:
|
|
539
662
|
}
|
540
663
|
```
|
541
664
|
|
665
|
+
Alternatively, it can be treated as simply an event for consistency with other event bindings:
|
666
|
+
|
667
|
+
```ruby
|
668
|
+
button {
|
669
|
+
text "Reset Selection"
|
670
|
+
|
671
|
+
on('command') do
|
672
|
+
person.reset_country
|
673
|
+
end
|
674
|
+
}
|
675
|
+
```
|
676
|
+
|
542
677
|
More details can be found in the [Hello, Button!](#hello-button) sample below.
|
543
678
|
|
544
679
|
## Gotchas
|
@@ -547,6 +682,22 @@ More details can be found in the [Hello, Button!](#hello-button) sample below.
|
|
547
682
|
|
548
683
|
## Samples
|
549
684
|
|
685
|
+
The easiest way to run samples is by launching the Glimmer Meta-Sample (the Sample of Samples).
|
686
|
+
|
687
|
+
Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
688
|
+
|
689
|
+
```
|
690
|
+
ruby -r glimmer-dsl-tk -e "require 'samples/elaborate/meta_sample'"
|
691
|
+
```
|
692
|
+
|
693
|
+
Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
694
|
+
|
695
|
+
```
|
696
|
+
ruby -r ./lib/glimmer-dsl-tk.rb samples/elaborate/meta_sample.rb
|
697
|
+
```
|
698
|
+
|
699
|
+

|
700
|
+
|
550
701
|
### Hello, World!
|
551
702
|
|
552
703
|
Glimmer code (from [samples/hello/hello_world.rb](samples/hello/hello_world.rb)):
|
@@ -1107,6 +1258,8 @@ Glimmer app:
|
|
1107
1258
|
|
1108
1259
|
### Hello, Label!
|
1109
1260
|
|
1261
|
+
Icons used in this sample were made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon"> www.flaticon.com</a>
|
1262
|
+
|
1110
1263
|
Glimmer code (from [samples/hello/hello_label.rb](samples/hello/hello_label.rb)):
|
1111
1264
|
|
1112
1265
|
```ruby
|
@@ -1329,12 +1482,12 @@ Glimmer code (from [samples/hello/hello_combobox.rb](samples/hello/hello_combobo
|
|
1329
1482
|
root {
|
1330
1483
|
title 'Hello, Combobox!'
|
1331
1484
|
|
1332
|
-
combobox {
|
1333
|
-
|
1485
|
+
combobox {
|
1486
|
+
readonly true # this applies to text editing only (item selection still triggers a write to model)
|
1334
1487
|
text <=> [person, :country]
|
1335
1488
|
}
|
1336
1489
|
|
1337
|
-
button {
|
1490
|
+
button {
|
1338
1491
|
text "Reset Selection"
|
1339
1492
|
command {
|
1340
1493
|
person.reset_country
|
@@ -1438,86 +1591,6 @@ Glimmer app:
|
|
1438
1591
|
|
1439
1592
|

|
1440
1593
|
|
1441
|
-
### Hello, Computed!
|
1442
|
-
|
1443
|
-
Glimmer code (from [samples/hello/hello_computed.rb](samples/hello/hello_computed.rb)):
|
1444
|
-
|
1445
|
-
```ruby
|
1446
|
-
# ... more code precedes
|
1447
|
-
root {
|
1448
|
-
title 'Hello, Computed!'
|
1449
|
-
|
1450
|
-
frame {
|
1451
|
-
grid column: 0, row: 0, padx: 5, pady: 5
|
1452
|
-
|
1453
|
-
label {
|
1454
|
-
grid column: 0, row: 0, sticky: 'w'
|
1455
|
-
text 'First Name: '
|
1456
|
-
}
|
1457
|
-
entry {
|
1458
|
-
grid column: 1, row: 0
|
1459
|
-
width 15
|
1460
|
-
text <=> [@contact, :first_name]
|
1461
|
-
}
|
1462
|
-
|
1463
|
-
label {
|
1464
|
-
grid column: 0, row: 1, sticky: 'w'
|
1465
|
-
text 'Last Name: '
|
1466
|
-
}
|
1467
|
-
entry {
|
1468
|
-
grid column: 1, row: 1
|
1469
|
-
width 15
|
1470
|
-
text <=> [@contact, :last_name]
|
1471
|
-
}
|
1472
|
-
|
1473
|
-
label {
|
1474
|
-
grid column: 0, row: 2, sticky: 'w'
|
1475
|
-
text 'Year of Birth: '
|
1476
|
-
}
|
1477
|
-
entry {
|
1478
|
-
grid column: 1, row: 2
|
1479
|
-
width 15
|
1480
|
-
text <=> [@contact, :year_of_birth]
|
1481
|
-
}
|
1482
|
-
|
1483
|
-
label {
|
1484
|
-
grid column: 0, row: 3, sticky: 'w'
|
1485
|
-
text 'Name: '
|
1486
|
-
}
|
1487
|
-
label {
|
1488
|
-
grid column: 1, row: 3, sticky: 'w'
|
1489
|
-
text <=> [@contact, :name, computed_by: [:first_name, :last_name]]
|
1490
|
-
}
|
1491
|
-
|
1492
|
-
label {
|
1493
|
-
grid column: 0, row: 4, sticky: 'w'
|
1494
|
-
text 'Age: '
|
1495
|
-
}
|
1496
|
-
label {
|
1497
|
-
grid column: 1, row: 4, sticky: 'w'
|
1498
|
-
text <=> [@contact, :age, on_write: :to_i, computed_by: [:year_of_birth]]
|
1499
|
-
}
|
1500
|
-
}
|
1501
|
-
}.open
|
1502
|
-
# ... more code follows
|
1503
|
-
```
|
1504
|
-
|
1505
|
-
Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1506
|
-
|
1507
|
-
```
|
1508
|
-
ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_computed'"
|
1509
|
-
```
|
1510
|
-
|
1511
|
-
Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1512
|
-
|
1513
|
-
```
|
1514
|
-
ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_computed.rb
|
1515
|
-
```
|
1516
|
-
|
1517
|
-
Glimmer app:
|
1518
|
-
|
1519
|
-

|
1520
|
-
|
1521
1594
|
### Hello, Entry!
|
1522
1595
|
|
1523
1596
|
Glimmer code (from [samples/hello/hello_entry.rb](samples/hello/hello_entry.rb)):
|
@@ -1542,7 +1615,7 @@ class HelloEntry
|
|
1542
1615
|
title 'Hello, Entry!'
|
1543
1616
|
|
1544
1617
|
label {
|
1545
|
-
grid sticky: 'ew'
|
1618
|
+
grid sticky: 'ew'
|
1546
1619
|
text 'default entry'
|
1547
1620
|
}
|
1548
1621
|
entry {
|
@@ -1625,6 +1698,219 @@ Glimmer app:
|
|
1625
1698
|

|
1626
1699
|

|
1627
1700
|
|
1701
|
+
### Hello, Text!
|
1702
|
+
|
1703
|
+
Icons used in this sample were made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon"> www.flaticon.com</a>
|
1704
|
+
|
1705
|
+
Glimmer code (from [samples/hello/hello_text.rb](samples/hello/hello_text.rb)):
|
1706
|
+
|
1707
|
+
```ruby
|
1708
|
+
require 'glimmer-dsl-tk'
|
1709
|
+
|
1710
|
+
class HelloText
|
1711
|
+
include Glimmer
|
1712
|
+
|
1713
|
+
COLOR_OPTIONS = %w[black purple blue green orange yellow red white].map(&:capitalize)
|
1714
|
+
FOREGROUND_PROMPT = '<select foreground>'
|
1715
|
+
BACKGROUND_PROMPT = '<select background>'
|
1716
|
+
|
1717
|
+
def initialize
|
1718
|
+
@foreground = FOREGROUND_PROMPT
|
1719
|
+
@background = BACKGROUND_PROMPT
|
1720
|
+
end
|
1721
|
+
|
1722
|
+
attr_accessor :foreground
|
1723
|
+
|
1724
|
+
def foreground_options
|
1725
|
+
[FOREGROUND_PROMPT] + COLOR_OPTIONS
|
1726
|
+
end
|
1727
|
+
|
1728
|
+
attr_accessor :background
|
1729
|
+
|
1730
|
+
def background_options
|
1731
|
+
[BACKGROUND_PROMPT] + COLOR_OPTIONS
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
def launch
|
1735
|
+
root {
|
1736
|
+
title 'Hello, Text!'
|
1737
|
+
|
1738
|
+
frame {
|
1739
|
+
grid row: 0, column: 0
|
1740
|
+
|
1741
|
+
button {
|
1742
|
+
grid row: 0, column: 0, column_weight: 0
|
1743
|
+
text 'B'
|
1744
|
+
style font: {weight: 'bold'}
|
1745
|
+
|
1746
|
+
on('command') do
|
1747
|
+
@text.toggle_selection_font_format('weight', 'bold')
|
1748
|
+
end
|
1749
|
+
}
|
1750
|
+
|
1751
|
+
button {
|
1752
|
+
grid row: 0, column: 1, column_weight: 0
|
1753
|
+
text 'I'
|
1754
|
+
style font: {slant: 'italic'}
|
1755
|
+
|
1756
|
+
on('command') do
|
1757
|
+
@text.toggle_selection_font_format('slant', 'italic')
|
1758
|
+
end
|
1759
|
+
}
|
1760
|
+
|
1761
|
+
button {
|
1762
|
+
grid row: 0, column: 2, column_weight: 0
|
1763
|
+
text 'U'
|
1764
|
+
style font: {underline: true}
|
1765
|
+
|
1766
|
+
on('command') do
|
1767
|
+
@text.toggle_selection_font_format('underline', true)
|
1768
|
+
end
|
1769
|
+
}
|
1770
|
+
|
1771
|
+
combobox {
|
1772
|
+
grid row: 0, column: 4, column_weight: 1
|
1773
|
+
readonly true
|
1774
|
+
text <=> [self, :foreground, after_write: ->(value) { @text.add_selection_format('foreground', value == FOREGROUND_PROMPT ? 'black' : value) }]
|
1775
|
+
}
|
1776
|
+
|
1777
|
+
combobox {
|
1778
|
+
grid row: 0, column: 5, column_weight: 1
|
1779
|
+
readonly true
|
1780
|
+
text <=> [self, :background, after_write: ->(value) { @text.add_selection_format('background', value == BACKGROUND_PROMPT ? 'black' : value) }]
|
1781
|
+
}
|
1782
|
+
}
|
1783
|
+
|
1784
|
+
@text = text {
|
1785
|
+
grid row: 1, column: 0, row_weight: 1
|
1786
|
+
wrap 'word'
|
1787
|
+
text <<~MULTI_LINE_STRING
|
1788
|
+
According to the National Post, a heavy metal-loving high school principal in Canada will be allowed to keep her job, days after a public campaign to oust her made headlines around the globe.
|
1789
|
+
|
1790
|
+
Parents at Eden High School in St. Catharines, Ontario launched a petition to remove principal Sharon Burns after discovering she's an IRON MAIDEN fan.
|
1791
|
+
|
1792
|
+
The petition, titled "Eden High School Principal, Sharon Burns, Needs to Be Transferred Immediately!" read, "We are deeply disturbed that the principal assigned to the school blatantly showed Satanic symbols and her allegiance to Satanic practices on her public social media platforms where all the students can see them under @edenprincipal (not her personal account)."
|
1793
|
+
|
1794
|
+
More than 500 people signed the petition to transfer Burns after she posted a picture of herself flashing the "devil horns" hand sign with a doll of the MAIDEN zombie mascot Eddie behind her as well as a personalized license plate reading "IRNMADEN" and a handwritten note that reads "Eddie 666" on a car's dashboard.
|
1795
|
+
|
1796
|
+
|
1797
|
+
The number 666 is used to represent the devil, and is featured prominently in MAIDEN's artwork by the band, whose classic third album is titled "The Number Of The Beast".
|
1798
|
+
|
1799
|
+
The petition was later updated to state that the demand for her transfer is not because of her love for metal, but for "openly displaying her own handmade sign with the 666 clearly displayed on it".
|
1800
|
+
|
1801
|
+
The creator of the original petition wrote: "Sharon knows full well what she did was simply inappropriate, unnecessary and not professional but has yet to publicly admit so and is willing to allow people to believe a completely different story, making very real concerns seem petty."
|
1802
|
+
|
1803
|
+
Meanwhile, a counter-petition supporting Burns garnered over 20,000 signatures.
|
1804
|
+
|
1805
|
+
"It is ridiculous that a couple of parents judge her role as a principal only based on an Instagram post. (About liking the band IRON MAIDEN. That's it.) Eden High School is a public school. Not a Christian school," the petition titled "We need Mrs Burns" stated. "She has made Eden a safe space for so many people. She spreads nothing but love and kindness."
|
1806
|
+
|
1807
|
+
After the complaints were aired, the District School Board of Niagara spoke with Burns and the parents who launched the petition, and the issue is over as far as the board is concerned, Kim Sweeney, the board's chief communications officer, told the National Post. No disciplinary action or policy changes were needed.
|
1808
|
+
|
1809
|
+
"Our belief is that taste in music is subjective and we support that both students and staff enjoy a wide variety of genres," Sweeney said.
|
1810
|
+
|
1811
|
+
The original petition has since been removed.
|
1812
|
+
MULTI_LINE_STRING
|
1813
|
+
}
|
1814
|
+
}.open
|
1815
|
+
end
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
HelloText.new.launch
|
1819
|
+
```
|
1820
|
+
|
1821
|
+
Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1822
|
+
|
1823
|
+
```
|
1824
|
+
ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_text'"
|
1825
|
+
```
|
1826
|
+
|
1827
|
+
Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1828
|
+
|
1829
|
+
```
|
1830
|
+
ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_text.rb
|
1831
|
+
```
|
1832
|
+
|
1833
|
+
Glimmer app:
|
1834
|
+
|
1835
|
+

|
1836
|
+
|
1837
|
+
### Hello, Spinbox!
|
1838
|
+
|
1839
|
+
Glimmer code (from [samples/hello/hello_spinbox.rb](samples/hello/hello_spinbox.rb)):
|
1840
|
+
|
1841
|
+
```ruby
|
1842
|
+
require 'glimmer-dsl-tk'
|
1843
|
+
|
1844
|
+
class HelloSpinbox
|
1845
|
+
class Person
|
1846
|
+
attr_accessor :donation
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
include Glimmer
|
1850
|
+
|
1851
|
+
def initialize
|
1852
|
+
@person = Person.new
|
1853
|
+
@person.donation = 5.0 # in dollars
|
1854
|
+
end
|
1855
|
+
|
1856
|
+
def launch
|
1857
|
+
root {
|
1858
|
+
title 'Hello, Spinbox!'
|
1859
|
+
|
1860
|
+
label {
|
1861
|
+
text 'Please select the amount you would like to donate to the poor:'
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
frame {
|
1865
|
+
label {
|
1866
|
+
grid row: 0, column: 0
|
1867
|
+
text 'Amount:'
|
1868
|
+
font 'caption'
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
label {
|
1872
|
+
grid row: 0, column: 1
|
1873
|
+
text '$'
|
1874
|
+
}
|
1875
|
+
|
1876
|
+
spinbox { |sb|
|
1877
|
+
grid row: 0, column: 2
|
1878
|
+
from 1.0 # minimum value
|
1879
|
+
to 150.0 # maximum value
|
1880
|
+
increment 5.0 # increment on up and down
|
1881
|
+
format '%0.2f'
|
1882
|
+
text <=> [@person, :donation]
|
1883
|
+
}
|
1884
|
+
|
1885
|
+
label {
|
1886
|
+
grid row: 1, column: 0, columnspan: 3
|
1887
|
+
text <=> [@person, :donation, on_read: ->(value) { "Thank you for your donation of $#{"%.2f" % value.to_f}"}]
|
1888
|
+
}
|
1889
|
+
|
1890
|
+
}
|
1891
|
+
}.open
|
1892
|
+
end
|
1893
|
+
end
|
1894
|
+
|
1895
|
+
HelloSpinbox.new.launch
|
1896
|
+
```
|
1897
|
+
|
1898
|
+
Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1899
|
+
|
1900
|
+
```
|
1901
|
+
ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_spinbox'"
|
1902
|
+
```
|
1903
|
+
|
1904
|
+
Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
1905
|
+
|
1906
|
+
```
|
1907
|
+
ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_spinbox.rb
|
1908
|
+
```
|
1909
|
+
|
1910
|
+
Glimmer app:
|
1911
|
+
|
1912
|
+

|
1913
|
+
|
1628
1914
|
### Hello, Computed!
|
1629
1915
|
|
1630
1916
|
Glimmer code (from [samples/hello/hello_computed.rb](samples/hello/hello_computed.rb)):
|
@@ -1705,6 +1991,167 @@ Glimmer app:
|
|
1705
1991
|
|
1706
1992
|

|
1707
1993
|
|
1994
|
+
### Hello, Drag and Drop!
|
1995
|
+
|
1996
|
+
Glimmer code (from [samples/hello/hello_drag_and_drop.rb](samples/hello/hello_drag_and_drop.rb)):
|
1997
|
+
|
1998
|
+
```ruby
|
1999
|
+
require "glimmer-dsl-tk"
|
2000
|
+
require "glimmer/tk/drag_and_drop_extension"
|
2001
|
+
|
2002
|
+
include Glimmer
|
2003
|
+
|
2004
|
+
root {
|
2005
|
+
title "Hello, Drag and Drop!"
|
2006
|
+
frame {
|
2007
|
+
padding 5
|
2008
|
+
labelframe {
|
2009
|
+
text "Drag sources"
|
2010
|
+
padding 5
|
2011
|
+
label {
|
2012
|
+
text "Entry"
|
2013
|
+
grid :row => 0, :column => 0
|
2014
|
+
}
|
2015
|
+
entry {
|
2016
|
+
text "Drag entry text"
|
2017
|
+
width 30
|
2018
|
+
grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
|
2019
|
+
on_drag_start { |event|
|
2020
|
+
event.data = event.source.textvariable&.value
|
2021
|
+
event.source.configure(:cursor => "hand2")
|
2022
|
+
TkLabel.new(event.tooltip) {
|
2023
|
+
text event.data + " "
|
2024
|
+
bg "yellow"
|
2025
|
+
bitmap "warning"
|
2026
|
+
compound "right"
|
2027
|
+
}.pack
|
2028
|
+
}
|
2029
|
+
on_drag_motion { |event|
|
2030
|
+
if event.drop_accepted
|
2031
|
+
event.source.configure(:cursor => "hand1")
|
2032
|
+
else
|
2033
|
+
event.source.configure(:cursor => "hand2")
|
2034
|
+
end
|
2035
|
+
event.tooltip.geometry("+#{event.x_root + 10}+#{event.y_root - 4}")
|
2036
|
+
}
|
2037
|
+
}
|
2038
|
+
label {
|
2039
|
+
text "Label"
|
2040
|
+
grid :row => 1, :column => 0
|
2041
|
+
}
|
2042
|
+
label {
|
2043
|
+
text "Drag label text"
|
2044
|
+
width 30
|
2045
|
+
grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
|
2046
|
+
drag_source true
|
2047
|
+
}
|
2048
|
+
label {
|
2049
|
+
text "Combobox"
|
2050
|
+
grid :row => 2, :column => 0
|
2051
|
+
}
|
2052
|
+
combobox {
|
2053
|
+
text "Spain"
|
2054
|
+
values %w[USA Canada Mexico Columbia UK Australia Germany Italy Spain]
|
2055
|
+
width 27
|
2056
|
+
grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
|
2057
|
+
on_drag_start { |event|
|
2058
|
+
event.data = event.source.textvariable&.value
|
2059
|
+
}
|
2060
|
+
}
|
2061
|
+
label {
|
2062
|
+
text "Button"
|
2063
|
+
grid :row => 3, :column => 0
|
2064
|
+
}
|
2065
|
+
button {
|
2066
|
+
text "Drag it"
|
2067
|
+
grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
|
2068
|
+
drag_source true
|
2069
|
+
}
|
2070
|
+
}
|
2071
|
+
|
2072
|
+
labelframe {
|
2073
|
+
text "Drop targets"
|
2074
|
+
grid :sticky => "nsew", :pady => 15
|
2075
|
+
padding 5
|
2076
|
+
label {
|
2077
|
+
text "Entry"
|
2078
|
+
grid :row => 0, :column => 0
|
2079
|
+
}
|
2080
|
+
entry {
|
2081
|
+
width 30
|
2082
|
+
grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
|
2083
|
+
on_drop { |event|
|
2084
|
+
event.target.textvariable.value = event.data
|
2085
|
+
}
|
2086
|
+
}
|
2087
|
+
label {
|
2088
|
+
text "Label"
|
2089
|
+
grid :row => 1, :column => 0
|
2090
|
+
}
|
2091
|
+
label {
|
2092
|
+
width 30
|
2093
|
+
grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
|
2094
|
+
borderwidth 2
|
2095
|
+
relief "solid"
|
2096
|
+
on_drop { |event|
|
2097
|
+
event.target.textvariable.value = event.data
|
2098
|
+
}
|
2099
|
+
}
|
2100
|
+
label {
|
2101
|
+
text "Combobox"
|
2102
|
+
grid :row => 2, :column => 0
|
2103
|
+
}
|
2104
|
+
combobox {
|
2105
|
+
width 27
|
2106
|
+
grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
|
2107
|
+
on_drop { |event|
|
2108
|
+
event.target.textvariable.value = event.data
|
2109
|
+
}
|
2110
|
+
}
|
2111
|
+
label {
|
2112
|
+
text "Button"
|
2113
|
+
grid :row => 3, :column => 0
|
2114
|
+
}
|
2115
|
+
button {
|
2116
|
+
text "Drop here"
|
2117
|
+
grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
|
2118
|
+
on_drop { |event|
|
2119
|
+
event.target.text = event.data
|
2120
|
+
}
|
2121
|
+
}
|
2122
|
+
label {
|
2123
|
+
text "Checkbutton"
|
2124
|
+
grid :row => 4, :column => 0
|
2125
|
+
}
|
2126
|
+
checkbutton {
|
2127
|
+
text "Drop here to destroy a widget\n(except button)"
|
2128
|
+
grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
|
2129
|
+
on_drop { |event|
|
2130
|
+
event.target.text = event.data
|
2131
|
+
event.source.destroy unless event.source.is_a? Tk::Button
|
2132
|
+
}
|
2133
|
+
}
|
2134
|
+
}
|
2135
|
+
}
|
2136
|
+
}.open
|
2137
|
+
```
|
2138
|
+
|
2139
|
+
Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
2140
|
+
|
2141
|
+
```
|
2142
|
+
ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_drag_and_drop'"
|
2143
|
+
```
|
2144
|
+
|
2145
|
+
Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
|
2146
|
+
|
2147
|
+
```
|
2148
|
+
ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_drag_and_drop.rb
|
2149
|
+
```
|
2150
|
+
|
2151
|
+
Glimmer app:
|
2152
|
+
|
2153
|
+

|
2154
|
+
|
1708
2155
|
## Help
|
1709
2156
|
|
1710
2157
|
### Issues
|
@@ -1738,6 +2185,7 @@ These features have been planned or suggested. You might see them in a future ve
|
|
1738
2185
|
## Contributors
|
1739
2186
|
|
1740
2187
|
* [Andy Maleh](https://github.com/AndyObtiva) (Founder)
|
2188
|
+
* [vin1antme](https://github.com/vin1antme)
|
1741
2189
|
|
1742
2190
|
[Click here to view contributor commits.](https://github.com/AndyObtiva/glimmer-dsl-tk/graphs/contributors)
|
1743
2191
|
|