glimmer-dsl-opal 0.0.2 → 0.0.7

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +704 -40
  3. data/VERSION +1 -1
  4. data/lib/glimmer-dsl-opal.rb +3 -2
  5. data/lib/glimmer/data_binding/element_binding.rb +1 -1
  6. data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
  7. data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
  8. data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
  9. data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
  10. data/lib/glimmer/dsl/opal/button_expression.rb +1 -0
  11. data/lib/glimmer/dsl/opal/dsl.rb +15 -1
  12. data/lib/glimmer/dsl/opal/grid_layout_expression.rb +17 -0
  13. data/lib/glimmer/dsl/opal/layout_data_expression.rb +17 -0
  14. data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
  15. data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
  16. data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
  17. data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
  18. data/lib/glimmer/dsl/opal/property_expression.rb +6 -2
  19. data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
  20. data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
  21. data/lib/glimmer/dsl/opal/text_expression.rb +22 -0
  22. data/lib/glimmer/opal/display_proxy.rb +23 -0
  23. data/lib/glimmer/opal/div_proxy.rb +9 -1
  24. data/lib/glimmer/opal/document_proxy.rb +131 -5
  25. data/lib/glimmer/opal/element_proxy.rb +246 -11
  26. data/lib/glimmer/opal/grid_layout_proxy.rb +54 -0
  27. data/lib/glimmer/opal/iframe_proxy.rb +23 -0
  28. data/lib/glimmer/opal/input_proxy.rb +16 -1
  29. data/lib/glimmer/opal/label_proxy.rb +2 -1
  30. data/lib/glimmer/opal/layout_data_proxy.rb +31 -0
  31. data/lib/glimmer/opal/list_proxy.rb +80 -0
  32. data/lib/glimmer/opal/modal.rb +94 -0
  33. data/lib/glimmer/opal/point.rb +5 -0
  34. data/lib/glimmer/opal/property_owner.rb +22 -0
  35. data/lib/glimmer/opal/select_proxy.rb +2 -1
  36. data/lib/glimmer/opal/tab_folder.rb +46 -0
  37. data/lib/glimmer/opal/tab_item.rb +98 -0
  38. data/lib/samples/elaborate/login.rb +0 -1
  39. data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
  40. data/lib/samples/hello/hello_tab.rb +2 -2
  41. metadata +25 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43ffbba379c5bade234cf2a2263be49565bff77120e7449e17ea7095461520c5
4
- data.tar.gz: 990340e899f8bf37a98ea0ea4e78941ccb48e4e55e0faddbb2b4ea7d010c8c0c
3
+ metadata.gz: b1e27d44e69248f9febb6c2b8ce6d58d5f6a876d451b09d293769e3296e8c1ff
4
+ data.tar.gz: 30f77e89b509c325d8e609a2b6cda35425acb2b3e6f48ed8113c724208a1c0e9
5
5
  SHA512:
6
- metadata.gz: 49e2e4d81cf84643f7e645ce30c474a0262c11bebd7f708db25068fc4fd6acb53d7e98779c028b2d459165749523444ecf7a0fb4de653bc2a6c6409b05f606d9
7
- data.tar.gz: 68179f29cc621c861c6243ef2dc54dff6558be4f394c0ab7bb47c0cffe683fe77cf1e3fdbc5f00b7c8646bdfb6cd7580bed4162e88353149be003bad32ce34ea
6
+ metadata.gz: 6ee6ca73fef3795d270cf4980fd4392beb39bc2a4f240f5a0fe10014772206aa5da1ca502559a13da2abb3191f681d5f76041003d207736c4469be2709476d73
7
+ data.tar.gz: 381fde33081fca87a978babb4e3048acfacf70a56de249eb5ea44be9dd0c6f60139b278601d929110eb6f687f3dd65c31287458d8c98c0fc1e31c59c3b842d71
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
-
2
- # Glimmer DSL for Opal 0.0.2 Alpha (Web GUI for Desktop Apps)
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=65 /> Glimmer DSL for Opal 0.0.7 (Web GUI for Desktop Apps)
3
2
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-opal.svg)](http://badge.fury.io/rb/glimmer-dsl-opal)
4
3
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5
4
 
@@ -7,36 +6,27 @@
7
6
 
8
7
  It enables running [Glimmer](https://github.com/AndyObtiva/glimmer) desktop apps on the web via [Rails](https://rubyonrails.org/) 5 and [Opal](https://opalrb.com/) 1.
9
8
 
10
- NOTE: Alpha Version 0.0.2 only supports Hello, World! and Hello, Combo! capabilities.
9
+ NOTE: Alpha Version 0.0.7 only supports capabilities for the following [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) [samples](https://github.com/AndyObtiva/glimmer#samples):
10
+
11
+ Hello Samples:
12
+ - [Hello, World!](#hello-world)
13
+ - [Hello, Combo!](#hello-combo)
14
+ - [Hello, Computed!](#hello-computed)
15
+ - [Hello, List Single Selection!](#hello-list-single-selection)
16
+ - [Hello, List Multi Selection!](#hello-list-multi-selection)
17
+ - [Hello, Browser!](#hello-browser)
18
+ - [Hello, Tab!](#hello-tab)
19
+
20
+ Elaborate Samples:
21
+ - [Login](#login)
22
+ - [Tic Tac Toe](#tic-tac-toe)
11
23
 
12
24
  Other Glimmer DSL gems:
13
25
  - [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI)
14
26
  - [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
15
27
  - [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
16
28
 
17
- ## Hello, World!
18
-
19
- Glimmer code (from SWT desktop app sample [`samples/hello/hello_world.rb`](https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/samples/hello/hello_world.rb)):
20
- ```ruby
21
- include Glimmer
22
-
23
- shell {
24
- text 'Glimmer'
25
- label {
26
- text 'Hello, World!'
27
- }
28
- }.open
29
- ```
30
-
31
- Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
32
-
33
- ![Glimmer DSL for Opal Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
34
-
35
- Glimmer app on the web (using `glimmer-dsl-opal` gem):
36
-
37
- ![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
38
-
39
- ## Supported Widgets
29
+ ## Supported Glimmer DSL Keywords
40
30
 
41
31
  The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt) have partial support in Opal:
42
32
 
@@ -44,7 +34,15 @@ The following keywords from [glimmer-dsl-swt](https://github.com/AndyObtiva/glim
44
34
  - `label`
45
35
  - `combo`
46
36
  - `button`
47
- - `composite` (single-column `grid_layout` only)
37
+ - `text`
38
+ - `composite`
39
+ - `list` & `list(:multi)`
40
+ - `tab_folder`
41
+ - `tab_item`
42
+ - `on_widget_selected`
43
+ - `on_modify_text`
44
+ - `grid_layout`
45
+ - `layout_data`
48
46
 
49
47
  ## Pre-requisites
50
48
 
@@ -63,11 +61,12 @@ rails new hello_world
63
61
 
64
62
  Follow instructions to setup opal with a rails application: config/initializers/assets.rb
65
63
 
66
- Add the following to `Gemfile`:
64
+ Add the following to `Gemfile` (NOTE: if you run into issues, they are probably fixed in master or development/wip branch, you may check out instead):
67
65
  ```
68
- gem 'opal-rails'
69
- gem 'opal-browser'
70
- gem 'glimmer-dsl-opal', '~> 0.0.2', require: false
66
+ gem 'opal-rails', '~> 1.1.2'
67
+ gem 'opal-async', '~> 1.1.0'
68
+ gem 'opal-browser', '~> 0.2.0'
69
+ gem 'glimmer-dsl-opal', '~> 0.0.7', require: false
71
70
  ```
72
71
 
73
72
  Edit `config/initializers/assets.rb` and add:
@@ -75,15 +74,21 @@ Edit `config/initializers/assets.rb` and add:
75
74
  Opal.use_gem 'glimmer-dsl-opal'
76
75
  ```
77
76
 
78
- ## Examples
77
+ Add the following line to the top of an empty `app/assets/javascripts/application.js.rb`
79
78
 
80
- ### Hello, World!
79
+ ```ruby
80
+ require 'glimmer-dsl-opal' # brings opal and opal browser too
81
+ ```
82
+
83
+ ## Samples
84
+
85
+ ### Hello Samples
86
+
87
+ #### Hello, World!
81
88
 
82
89
  Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
83
90
 
84
91
  ```ruby
85
- require 'glimmer-dsl-opal' # brings opal and opal browser too
86
-
87
92
  include Glimmer
88
93
 
89
94
  shell {
@@ -96,7 +101,7 @@ shell {
96
101
 
97
102
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
98
103
 
99
- ![Glimmer DSL for Opal Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
104
+ ![Glimmer DSL for SWT Hello World](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-world.png)
100
105
 
101
106
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
102
107
 
@@ -111,13 +116,11 @@ You should see "Hello, World!"
111
116
 
112
117
  ![Glimmer DSL for Opal Hello World](images/glimmer-dsl-opal-hello-world.png)
113
118
 
114
- ### Hello, Combo!
119
+ #### Hello, Combo!
115
120
 
116
121
  Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
117
122
 
118
123
  ```ruby
119
- require 'glimmer-dsl-opal' # brings opal and opal browser too
120
-
121
124
  class Person
122
125
  attr_accessor :country, :country_options
123
126
 
@@ -155,7 +158,7 @@ HelloCombo.new.launch
155
158
  ```
156
159
  Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
157
160
 
158
- ![Glimmer DSL for Opal Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
161
+ ![Glimmer DSL for SWT Hello Combo](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-combo.png)
159
162
 
160
163
  Glimmer app on the web (using `glimmer-dsl-opal` gem):
161
164
 
@@ -170,6 +173,667 @@ You should see "Hello, Combo!"
170
173
 
171
174
  ![Glimmer DSL for Opal Hello Combo](images/glimmer-dsl-opal-hello-combo.png)
172
175
 
176
+ #### Hello, Computed!
177
+
178
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
179
+
180
+ ```ruby
181
+ class HelloComputed
182
+ class Contact
183
+ attr_accessor :first_name, :last_name, :year_of_birth
184
+
185
+ def initialize(attribute_map)
186
+ @first_name = attribute_map[:first_name]
187
+ @last_name = attribute_map[:last_name]
188
+ @year_of_birth = attribute_map[:year_of_birth]
189
+ end
190
+
191
+ def name
192
+ "#{last_name}, #{first_name}"
193
+ end
194
+
195
+ def age
196
+ Time.now.year - year_of_birth.to_i
197
+ rescue
198
+ 0
199
+ end
200
+ end
201
+ end
202
+
203
+ class HelloComputed
204
+ include Glimmer
205
+
206
+ def initialize
207
+ @contact = Contact.new(
208
+ first_name: "Barry",
209
+ last_name: "McKibbin",
210
+ year_of_birth: 1985
211
+ )
212
+ end
213
+
214
+ def launch
215
+ shell {
216
+ text "Hello Computed"
217
+ composite {
218
+ grid_layout {
219
+ num_columns 2
220
+ make_columns_equal_width true
221
+ horizontal_spacing 20
222
+ vertical_spacing 10
223
+ }
224
+ label {text "First &Name: "}
225
+ text {
226
+ text bind(@contact, :first_name)
227
+ layout_data {
228
+ horizontalAlignment :fill
229
+ grabExcessHorizontalSpace true
230
+ }
231
+ }
232
+ label {text "&Last Name: "}
233
+ text {
234
+ text bind(@contact, :last_name)
235
+ layout_data {
236
+ horizontalAlignment :fill
237
+ grabExcessHorizontalSpace true
238
+ }
239
+ }
240
+ label {text "&Year of Birth: "}
241
+ text {
242
+ text bind(@contact, :year_of_birth)
243
+ layout_data {
244
+ horizontalAlignment :fill
245
+ grabExcessHorizontalSpace true
246
+ }
247
+ }
248
+ label {text "Name: "}
249
+ label {
250
+ text bind(@contact, :name, computed_by: [:first_name, :last_name])
251
+ layout_data {
252
+ horizontalAlignment :fill
253
+ grabExcessHorizontalSpace true
254
+ }
255
+ }
256
+ label {text "Age: "}
257
+ label {
258
+ text bind(@contact, :age, on_write: :to_i, computed_by: [:year_of_birth])
259
+ layout_data {
260
+ horizontalAlignment :fill
261
+ grabExcessHorizontalSpace true
262
+ }
263
+ }
264
+ }
265
+ }.open
266
+ end
267
+ end
268
+
269
+ HelloComputed.new.launch
270
+ ```
271
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
272
+
273
+ ![Glimmer DSL for SWT Hello Computed](https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-hello-computed.png)
274
+
275
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
276
+
277
+ Start the Rails server:
278
+ ```
279
+ rails s
280
+ ```
281
+
282
+ Visit `http://localhost:3000`
283
+
284
+ You should see "Hello, Computed!"
285
+
286
+ ![Glimmer DSL for Opal Hello Computed](images/glimmer-dsl-opal-hello-computed.png)
287
+
288
+ #### Hello, List Single Selection!
289
+
290
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
291
+
292
+ ```ruby
293
+ class Person
294
+ attr_accessor :country, :country_options
295
+
296
+ def initialize
297
+ self.country_options=["", "Canada", "US", "Mexico"]
298
+ self.country = "Canada"
299
+ end
300
+
301
+ def reset_country
302
+ self.country = "Canada"
303
+ end
304
+ end
305
+
306
+ class HelloListSingleSelection
307
+ include Glimmer
308
+ def launch
309
+ person = Person.new
310
+ shell {
311
+ composite {
312
+ list {
313
+ selection bind(person, :country)
314
+ }
315
+ button {
316
+ text "Reset"
317
+ on_widget_selected do
318
+ person.reset_country
319
+ end
320
+ }
321
+ }
322
+ }.open
323
+ end
324
+ end
325
+
326
+ HelloListSingleSelection.new.launch
327
+ ```
328
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
329
+
330
+ ![Glimmer DSL for SWT Hello List Single Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-single-selection.png)
331
+
332
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
333
+
334
+ Start the Rails server:
335
+ ```
336
+ rails s
337
+ ```
338
+
339
+ Visit `http://localhost:3000`
340
+
341
+ You should see "Hello, List Single Selection!"
342
+
343
+ ![Glimmer DSL for Opal Hello List Single Selection](images/glimmer-dsl-opal-hello-list-single-selection.png)
344
+
345
+ #### Hello, List Multi Selection!
346
+
347
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
348
+
349
+ ```ruby
350
+ class Person
351
+ attr_accessor :provinces, :provinces_options
352
+
353
+ def initialize
354
+ self.provinces_options=[
355
+ "",
356
+ "Quebec",
357
+ "Ontario",
358
+ "Manitoba",
359
+ "Saskatchewan",
360
+ "Alberta",
361
+ "British Columbia",
362
+ "Nova Skotia",
363
+ "Newfoundland"
364
+ ]
365
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
366
+ end
367
+
368
+ def reset_provinces
369
+ self.provinces = ["Quebec", "Manitoba", "Alberta"]
370
+ end
371
+ end
372
+
373
+ class HelloListMultiSelection
374
+ include Glimmer
375
+ def launch
376
+ person = Person.new
377
+ shell {
378
+ composite {
379
+ list(:multi) {
380
+ selection bind(person, :provinces)
381
+ }
382
+ button {
383
+ text "Reset"
384
+ on_widget_selected do
385
+ person.reset_provinces
386
+ end
387
+ }
388
+ }
389
+ }.open
390
+ end
391
+ end
392
+
393
+ HelloListMultiSelection.new.launch
394
+ ```
395
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
396
+
397
+ ![Glimmer DSL for SWT Hello List Multi Selection](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-list-multi-selection.png)
398
+
399
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
400
+
401
+ Start the Rails server:
402
+ ```
403
+ rails s
404
+ ```
405
+
406
+ Visit `http://localhost:3000`
407
+
408
+ You should see "Hello, List Multi Selection!"
409
+
410
+ ![Glimmer DSL for Opal Hello List Multi Selection](images/glimmer-dsl-opal-hello-list-multi-selection.png)
411
+
412
+ #### Hello, Browser!
413
+
414
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
415
+
416
+ ```ruby
417
+ include Glimmer
418
+
419
+ shell {
420
+ minimum_size 1024, 860
421
+ browser {
422
+ url 'http://brightonresort.com/about'
423
+ }
424
+ }.open
425
+ ```
426
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
427
+
428
+ ![Glimmer DSL for SWT Hello Browser](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-browser.png)
429
+
430
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
431
+
432
+ Start the Rails server:
433
+ ```
434
+ rails s
435
+ ```
436
+
437
+ Visit `http://localhost:3000`
438
+
439
+ You should see "Hello, Browser!"
440
+
441
+ ![Glimmer DSL for Opal Hello Browser](images/glimmer-dsl-opal-hello-browser.png)
442
+
443
+ #### Hello, Tab!
444
+
445
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
446
+
447
+ ```ruby
448
+ class HelloTab
449
+ include Glimmer
450
+ def launch
451
+ shell {
452
+ text "Hello, Tab!"
453
+ tab_folder {
454
+ tab_item {
455
+ text "English"
456
+ label {
457
+ text "Hello, World!"
458
+ }
459
+ }
460
+ tab_item {
461
+ text "French"
462
+ label {
463
+ text "Bonjour, Univers!"
464
+ }
465
+ }
466
+ }
467
+ }.open
468
+ end
469
+ end
470
+
471
+ HelloTab.new.launch
472
+ ```
473
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
474
+
475
+ ![Glimmer DSL for SWT Hello Tab English](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-english.png)
476
+ ![Glimmer DSL for SWT Hello Tab French](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-hello-tab-french.png)
477
+
478
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
479
+
480
+ Start the Rails server:
481
+ ```
482
+ rails s
483
+ ```
484
+
485
+ Visit `http://localhost:3000`
486
+
487
+ You should see "Hello, Tab!"
488
+
489
+ ![Glimmer DSL for Opal Hello Tab English](images/glimmer-dsl-opal-hello-tab-english.png)
490
+ ![Glimmer DSL for Opal Hello Tab French](images/glimmer-dsl-opal-hello-tab-french.png)
491
+
492
+ ### Elaborate Samples
493
+
494
+ #### Login
495
+
496
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
497
+
498
+ ```ruby
499
+ require "observer"
500
+
501
+ #Presents login screen data
502
+ class LoginPresenter
503
+
504
+ attr_accessor :user_name
505
+ attr_accessor :password
506
+ attr_accessor :status
507
+
508
+ def initialize
509
+ @user_name = ""
510
+ @password = ""
511
+ @status = "Logged Out"
512
+ end
513
+
514
+ def status=(status)
515
+ @status = status
516
+
517
+ #TODO add feature to bind dependent properties to master property (2017-07-25 nested data binding)
518
+ notify_observers("logged_in")
519
+ notify_observers("logged_out")
520
+ end
521
+
522
+ def logged_in
523
+ self.status == "Logged In"
524
+ end
525
+
526
+ def logged_out
527
+ !self.logged_in
528
+ end
529
+
530
+ def login
531
+ self.status = "Logged In"
532
+ end
533
+
534
+ def logout
535
+ self.user_name = ""
536
+ self.password = ""
537
+ self.status = "Logged Out"
538
+ end
539
+
540
+ end
541
+
542
+ #Login screen
543
+ class Login
544
+ include Glimmer
545
+
546
+ def launch
547
+ presenter = LoginPresenter.new
548
+ @shell = shell {
549
+ text "Login"
550
+ composite {
551
+ grid_layout 2, false #two columns with differing widths
552
+
553
+ label { text "Username:" } # goes in column 1
554
+ text { # goes in column 2
555
+ text bind(presenter, :user_name)
556
+ enabled bind(presenter, :logged_out)
557
+ }
558
+
559
+ label { text "Password:" }
560
+ text(:password, :border) {
561
+ text bind(presenter, :password)
562
+ enabled bind(presenter, :logged_out)
563
+ }
564
+
565
+ label { text "Status:" }
566
+ label { text bind(presenter, :status) }
567
+
568
+ button {
569
+ text "Login"
570
+ enabled bind(presenter, :logged_out)
571
+ on_widget_selected { presenter.login }
572
+ }
573
+
574
+ button {
575
+ text "Logout"
576
+ enabled bind(presenter, :logged_in)
577
+ on_widget_selected { presenter.logout }
578
+ }
579
+ }
580
+ }
581
+ @shell.open
582
+ end
583
+ end
584
+
585
+ Login.new.launch
586
+ ```
587
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
588
+
589
+ ![Glimmer DSL for SWT Login](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login.png)
590
+ ![Glimmer DSL for SWT Login Filled In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-filled-in.png)
591
+ ![Glimmer DSL for SWT Login Logged In](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-login-logged-in.png)
592
+
593
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
594
+
595
+ Start the Rails server:
596
+ ```
597
+ rails s
598
+ ```
599
+
600
+ Visit `http://localhost:3000`
601
+
602
+ You should see "Login" dialog
603
+
604
+ ![Glimmer DSL for Opal Login](images/glimmer-dsl-opal-login.png)
605
+ ![Glimmer DSL for Opal Login Filled In](images/glimmer-dsl-opal-login-filled-in.png)
606
+ ![Glimmer DSL for Opal Login Logged In](images/glimmer-dsl-opal-login-logged-in.png)
607
+
608
+ #### Tic Tac Toe
609
+
610
+ Add the following Glimmer code to `app/assets/javascripts/application.js.rb`
611
+
612
+ ```ruby
613
+ class TicTacToe
614
+ class Cell
615
+ EMPTY = ""
616
+ attr_accessor :sign, :empty
617
+
618
+ def initialize
619
+ reset
620
+ end
621
+
622
+ def mark(sign)
623
+ self.sign = sign
624
+ end
625
+
626
+ def reset
627
+ self.sign = EMPTY
628
+ end
629
+
630
+ def sign=(sign_symbol)
631
+ @sign = sign_symbol
632
+ self.empty = sign == EMPTY
633
+ end
634
+
635
+ def marked
636
+ !empty
637
+ end
638
+ end
639
+ end
640
+
641
+ class TicTacToe
642
+ class Board
643
+ DRAW = :draw
644
+ IN_PROGRESS = :in_progress
645
+ WIN = :win
646
+ attr :winning_sign
647
+ attr_accessor :game_status
648
+
649
+ def initialize
650
+ @sign_state_machine = {nil => "X", "X" => "O", "O" => "X"}
651
+ build_grid
652
+ @winning_sign = Cell::EMPTY
653
+ @game_status = IN_PROGRESS
654
+ end
655
+
656
+ #row and column numbers are 1-based
657
+ def mark(row, column)
658
+ self[row, column].mark(current_sign)
659
+ game_over? #updates winning sign
660
+ end
661
+
662
+ def current_sign
663
+ @current_sign = @sign_state_machine[@current_sign]
664
+ end
665
+
666
+ def [](row, column)
667
+ @grid[row-1][column-1]
668
+ end
669
+
670
+ def game_over?
671
+ win? or draw?
672
+ end
673
+
674
+ def win?
675
+ win = (row_win? or column_win? or diagonal_win?)
676
+ self.game_status=WIN if win
677
+ win
678
+ end
679
+
680
+ def reset
681
+ (1..3).each do |row|
682
+ (1..3).each do |column|
683
+ self[row, column].reset
684
+ end
685
+ end
686
+ @winning_sign = Cell::EMPTY
687
+ @current_sign = nil
688
+ self.game_status=IN_PROGRESS
689
+ end
690
+
691
+ private
692
+
693
+ def build_grid
694
+ @grid = []
695
+ 3.times do |row_index| #0-based
696
+ @grid << []
697
+ 3.times { @grid[row_index] << Cell.new }
698
+ end
699
+ end
700
+
701
+ def row_win?
702
+ (1..3).each do |row|
703
+ if row_has_same_sign(row)
704
+ @winning_sign = self[row, 1].sign
705
+ return true
706
+ end
707
+ end
708
+ false
709
+ end
710
+
711
+ def column_win?
712
+ (1..3).each do |column|
713
+ if column_has_same_sign(column)
714
+ @winning_sign = self[1, column].sign
715
+ return true
716
+ end
717
+ end
718
+ false
719
+ end
720
+
721
+ #needs refactoring if we ever decide to make the board size dynamic
722
+ def diagonal_win?
723
+ if (self[1, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[3, 3].sign) and self[1, 1].marked
724
+ @winning_sign = self[1, 1].sign
725
+ return true
726
+ end
727
+ if (self[3, 1].sign == self[2, 2].sign) and (self[2, 2].sign == self[1, 3].sign) and self[3, 1].marked
728
+ @winning_sign = self[3, 1].sign
729
+ return true
730
+ end
731
+ false
732
+ end
733
+
734
+ def draw?
735
+ @board_full = true
736
+ 3.times do |x|
737
+ 3.times do |y|
738
+ @board_full = false if self[x, y].empty
739
+ end
740
+ end
741
+ self.game_status = DRAW if @board_full
742
+ @board_full
743
+ end
744
+
745
+ def row_has_same_sign(number)
746
+ row_sign = self[number, 1].sign
747
+ [2, 3].each do |column|
748
+ return false unless row_sign == (self[number, column].sign)
749
+ end
750
+ true if self[number, 1].marked
751
+ end
752
+
753
+ def column_has_same_sign(number)
754
+ column_sign = self[1, number].sign
755
+ [2, 3].each do |row|
756
+ return false unless column_sign == (self[row, number].sign)
757
+ end
758
+ true if self[1, number].marked
759
+ end
760
+
761
+ end
762
+ end
763
+
764
+ class TicTacToe
765
+ include Glimmer
766
+
767
+ def initialize
768
+ @tic_tac_toe_board = Board.new
769
+ @shell = shell {
770
+ text "Tic-Tac-Toe"
771
+ composite {
772
+ grid_layout 3, true
773
+ (1..3).each { |row|
774
+ (1..3).each { |column|
775
+ button {
776
+ layout_data :fill, :fill, true, true
777
+ text bind(@tic_tac_toe_board[row, column], :sign)
778
+ enabled bind(@tic_tac_toe_board[row, column], :empty)
779
+ on_widget_selected {
780
+ @tic_tac_toe_board.mark(row, column)
781
+ }
782
+ }
783
+ }
784
+ }
785
+ }
786
+ }
787
+ observe(@tic_tac_toe_board, :game_status) { |game_status|
788
+ display_win_message if game_status == Board::WIN
789
+ display_draw_message if game_status == Board::DRAW
790
+ }
791
+ end
792
+
793
+ def display_win_message
794
+ display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
795
+ end
796
+
797
+ def display_draw_message
798
+ display_game_over_message("Draw!")
799
+ end
800
+
801
+ def display_game_over_message(message_text)
802
+ message_box(@shell) {
803
+ text 'Game Over'
804
+ message message_text
805
+ }.open
806
+ @tic_tac_toe_board.reset
807
+ end
808
+
809
+ def open
810
+ @shell.open
811
+ end
812
+ end
813
+
814
+ TicTacToe.new.open
815
+ ```
816
+ Glimmer app on the desktop (using [`glimmer-dsl-swt`](https://github.com/AndyObtiva/glimmer-dsl-swt) gem):
817
+
818
+ ![Glimmer DSL for SWT Tic Tac Toe](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe.png)
819
+ ![Glimmer DSL for SWT Tic Tac Toe In Progress](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-in-progress.png)
820
+ ![Glimmer DSL for SWT Tic Tac Toe Game Over](https://github.com/AndyObtiva/glimmer/raw/master/images/glimmer-tic-tac-toe-game-over.png)
821
+
822
+ Glimmer app on the web (using `glimmer-dsl-opal` gem):
823
+
824
+ Start the Rails server:
825
+ ```
826
+ rails s
827
+ ```
828
+
829
+ Visit `http://localhost:3000`
830
+
831
+ You should see "Tic Tac Toe"
832
+
833
+ ![Glimmer DSL for Opal Tic Tac Toe](images/glimmer-dsl-opal-tic-tac-toe.png)
834
+ ![Glimmer DSL for Opal Tic Tac Toe In Progress](images/glimmer-dsl-opal-tic-tac-toe-in-progress.png)
835
+ ![Glimmer DSL for Opal Tic Tac Toe Game Over](images/glimmer-dsl-opal-tic-tac-toe-game-over.png)
836
+
173
837
  ## Help
174
838
 
175
839
  ### Issues