glimmer-dsl-opal 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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