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.
- checksums.yaml +4 -4
- data/README.md +704 -40
- data/VERSION +1 -1
- data/lib/glimmer-dsl-opal.rb +3 -2
- data/lib/glimmer/data_binding/element_binding.rb +1 -1
- data/lib/glimmer/data_binding/ext/observable_model.rb +40 -0
- data/lib/glimmer/data_binding/list_selection_binding.rb +51 -0
- data/lib/glimmer/dsl/opal/async_exec_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/browser_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/button_expression.rb +1 -0
- data/lib/glimmer/dsl/opal/dsl.rb +15 -1
- data/lib/glimmer/dsl/opal/grid_layout_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/layout_data_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/list_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/list_selection_data_binding_expression.rb +42 -0
- data/lib/glimmer/dsl/opal/message_box_expression.rb +20 -0
- data/lib/glimmer/dsl/opal/observe_expression.rb +32 -0
- data/lib/glimmer/dsl/opal/property_expression.rb +6 -2
- data/lib/glimmer/dsl/opal/tab_folder_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/tab_item_expression.rb +17 -0
- data/lib/glimmer/dsl/opal/text_expression.rb +22 -0
- data/lib/glimmer/opal/display_proxy.rb +23 -0
- data/lib/glimmer/opal/div_proxy.rb +9 -1
- data/lib/glimmer/opal/document_proxy.rb +131 -5
- data/lib/glimmer/opal/element_proxy.rb +246 -11
- data/lib/glimmer/opal/grid_layout_proxy.rb +54 -0
- data/lib/glimmer/opal/iframe_proxy.rb +23 -0
- data/lib/glimmer/opal/input_proxy.rb +16 -1
- data/lib/glimmer/opal/label_proxy.rb +2 -1
- data/lib/glimmer/opal/layout_data_proxy.rb +31 -0
- data/lib/glimmer/opal/list_proxy.rb +80 -0
- data/lib/glimmer/opal/modal.rb +94 -0
- data/lib/glimmer/opal/point.rb +5 -0
- data/lib/glimmer/opal/property_owner.rb +22 -0
- data/lib/glimmer/opal/select_proxy.rb +2 -1
- data/lib/glimmer/opal/tab_folder.rb +46 -0
- data/lib/glimmer/opal/tab_item.rb +98 -0
- data/lib/samples/elaborate/login.rb +0 -1
- data/lib/samples/elaborate/tic_tac_toe.rb +5 -5
- data/lib/samples/hello/hello_tab.rb +2 -2
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1e27d44e69248f9febb6c2b8ce6d58d5f6a876d451b09d293769e3296e8c1ff
|
4
|
+
data.tar.gz: 30f77e89b509c325d8e609a2b6cda35425acb2b3e6f48ed8113c724208a1c0e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
[](http://badge.fury.io/rb/glimmer-dsl-opal)
|
4
3
|
[](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.
|
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
|
-
##
|
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
|
-

|
34
|
-
|
35
|
-
Glimmer app on the web (using `glimmer-dsl-opal` gem):
|
36
|
-
|
37
|
-

|
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
|
-
- `
|
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-
|
70
|
-
gem '
|
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
|
-
|
77
|
+
Add the following line to the top of an empty `app/assets/javascripts/application.js.rb`
|
79
78
|
|
80
|
-
|
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
|
-

|
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
|

|
113
118
|
|
114
|
-
|
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
|
-

|
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
|

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
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
|
+

|
476
|
+

|
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
|
+

|
490
|
+

|
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
|
+

|
590
|
+

|
591
|
+

|
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
|
+

|
605
|
+

|
606
|
+

|
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
|
+

|
819
|
+

|
820
|
+

|
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
|
+

|
834
|
+

|
835
|
+

|
836
|
+
|
173
837
|
## Help
|
174
838
|
|
175
839
|
### Issues
|