glimmer-dsl-swt 4.22.0.0 → 4.22.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +191 -169
- data/README.md +5 -5
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_COMMAND.md +2 -2
- data/docs/reference/GLIMMER_CONFIGURATION.md +14 -3
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +98 -20
- data/docs/reference/GLIMMER_SAMPLES.md +13 -0
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/ext/glimmer/config.rb +41 -24
- data/lib/glimmer/data_binding/observable_widget.rb +6 -6
- data/lib/glimmer/data_binding/widget_binding.rb +2 -1
- data/lib/glimmer/dsl/swt/observe_expression.rb +2 -1
- data/lib/glimmer/dsl/swt/transform_expression.rb +1 -1
- data/lib/glimmer/launcher.rb +15 -14
- data/lib/glimmer/rake_task/scaffold.rb +2 -14
- data/lib/glimmer/swt/color_proxy.rb +5 -5
- data/lib/glimmer/swt/custom/drawable.rb +4 -0
- data/lib/glimmer/swt/custom/shape/line.rb +0 -1
- data/lib/glimmer/swt/custom/shape/path.rb +2 -2
- data/lib/glimmer/swt/custom/shape/path_segment.rb +2 -2
- data/lib/glimmer/swt/custom/shape/point.rb +8 -1
- data/lib/glimmer/swt/custom/shape.rb +170 -69
- data/lib/glimmer/swt/display_proxy.rb +15 -10
- data/lib/glimmer/swt/image_proxy.rb +5 -5
- data/lib/glimmer/swt/message_box_proxy.rb +5 -5
- data/lib/glimmer/swt/shape_listener_proxy.rb +55 -0
- data/lib/glimmer/swt/transform_proxy.rb +3 -3
- data/lib/glimmer/swt/tray_proxy.rb +4 -4
- data/lib/glimmer/swt/widget_proxy.rb +5 -7
- data/lib/glimmer/ui/custom_shape.rb +34 -10
- data/lib/glimmer/ui/custom_widget.rb +3 -8
- data/lib/glimmer-dsl-swt.rb +6 -2
- data/samples/elaborate/klondike_solitaire/model/column_pile.rb +0 -1
- data/samples/elaborate/klondike_solitaire/view/column_pile.rb +3 -16
- data/samples/elaborate/klondike_solitaire/view/dealing_pile.rb +1 -1
- data/samples/elaborate/klondike_solitaire/view/dealt_pile.rb +12 -5
- data/samples/elaborate/klondike_solitaire/view/empty_playing_card.rb +2 -1
- data/samples/elaborate/klondike_solitaire/view/foundation_pile.rb +2 -2
- data/samples/elaborate/klondike_solitaire/view/hidden_playing_card.rb +2 -2
- data/samples/elaborate/klondike_solitaire/view/klondike_solitaire_menu_bar.rb +60 -0
- data/samples/elaborate/klondike_solitaire/view/playing_card.rb +3 -2
- data/samples/elaborate/klondike_solitaire.rb +13 -55
- data/samples/elaborate/mandelbrot_fractal.rb +3 -1
- data/samples/elaborate/quarto/model/game.rb +124 -0
- data/samples/elaborate/quarto/model/piece/cube.rb +31 -0
- data/samples/elaborate/quarto/model/piece/cylinder.rb +31 -0
- data/samples/elaborate/quarto/model/piece.rb +70 -0
- data/samples/elaborate/quarto/view/available_pieces_area.rb +72 -0
- data/samples/elaborate/quarto/view/board.rb +65 -0
- data/samples/elaborate/quarto/view/cell.rb +85 -0
- data/samples/elaborate/quarto/view/cube.rb +73 -0
- data/samples/elaborate/quarto/view/cylinder.rb +72 -0
- data/samples/elaborate/quarto/view/message_box_panel.rb +114 -0
- data/samples/elaborate/quarto/view/piece.rb +56 -0
- data/samples/elaborate/quarto/view/selected_piece_area.rb +69 -0
- data/samples/elaborate/quarto.rb +190 -0
- data/samples/hello/hello_custom_widget.rb +23 -5
- metadata +17 -23
- data/bin/glimmer_runner.rb +0 -4
@@ -578,11 +578,9 @@ module Glimmer
|
|
578
578
|
flyweight_swt_widget_classes[underscored_widget_name] = swt_widget_class
|
579
579
|
rescue SyntaxError, NameError => e
|
580
580
|
Glimmer::Config.logger.debug {e.full_message}
|
581
|
-
# Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
|
582
581
|
nil
|
583
582
|
rescue => e
|
584
583
|
Glimmer::Config.logger.debug {e.full_message}
|
585
|
-
# Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
|
586
584
|
nil
|
587
585
|
end
|
588
586
|
end
|
@@ -778,20 +776,20 @@ module Glimmer
|
|
778
776
|
end
|
779
777
|
end
|
780
778
|
|
781
|
-
def method_missing(
|
779
|
+
def method_missing(method_name, *args, &block)
|
782
780
|
# TODO push most of this logic down to Properties (and perhaps create Listeners module as well)
|
783
|
-
if can_handle_observation_request?(
|
784
|
-
handle_observation_request(
|
781
|
+
if block && can_handle_observation_request?(method_name)
|
782
|
+
handle_observation_request(method_name, &block)
|
785
783
|
else
|
786
784
|
super
|
787
785
|
end
|
788
786
|
end
|
789
787
|
|
790
|
-
def respond_to?(
|
788
|
+
def respond_to?(method_name, *args, &block)
|
791
789
|
result = super
|
792
790
|
return true if result
|
793
791
|
auto_exec do
|
794
|
-
can_handle_observation_request?(
|
792
|
+
can_handle_observation_request?(method_name)
|
795
793
|
end
|
796
794
|
end
|
797
795
|
|
@@ -158,17 +158,12 @@ module Glimmer
|
|
158
158
|
def after_body(&block)
|
159
159
|
@after_body_block = block
|
160
160
|
end
|
161
|
-
|
162
|
-
# Current custom shapes being rendered. Useful to yoke all observers evaluated during rendering of their custom shapes for automatical disposal on_shape_disposed
|
163
|
-
def current_custom_shapes
|
164
|
-
@current_custom_shapes ||= []
|
165
|
-
end
|
166
161
|
end
|
167
162
|
|
168
163
|
attr_reader :body_root, :args, :parent, :parent_proxy, :options
|
169
164
|
|
170
165
|
def initialize(parent, *args, options, &content)
|
171
|
-
|
166
|
+
SWT::DisplayProxy.current_custom_widgets_and_shapes << self
|
172
167
|
@parent_proxy = @parent = parent
|
173
168
|
@parent_proxy = @parent&.get_data('proxy') if @parent.respond_to?(:get_data) && @parent.get_data('proxy')
|
174
169
|
@args = args
|
@@ -183,13 +178,26 @@ module Glimmer
|
|
183
178
|
auto_exec do # TODO is this necessary given shape is a lightweight construct (not SWT widget) ?
|
184
179
|
@body_root.set_data('custom_shape', self)
|
185
180
|
end
|
181
|
+
auto_exec do
|
182
|
+
@dispose_listener_registration = @body_root.on_shape_disposed do
|
183
|
+
unless @body_root.shell_proxy.last_shell_closing?
|
184
|
+
observer_registrations.compact.each(&:deregister)
|
185
|
+
observer_registrations.clear
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
186
189
|
execute_hook('after_body')
|
190
|
+
post_add_content if content.nil?
|
187
191
|
end
|
188
192
|
|
189
193
|
# Subclasses may override to perform post initialization work on an added child
|
190
194
|
def post_initialize_child(child)
|
191
195
|
# No Op by default
|
192
196
|
end
|
197
|
+
|
198
|
+
def post_add_content
|
199
|
+
SWT::DisplayProxy.current_custom_widgets_and_shapes.delete(self)
|
200
|
+
end
|
193
201
|
|
194
202
|
def observer_registrations
|
195
203
|
@observer_registrations ||= []
|
@@ -276,17 +284,33 @@ module Glimmer
|
|
276
284
|
end
|
277
285
|
alias getData get_data # for compatibility with SWT APIs
|
278
286
|
alias data get_data # for compatibility with SWT APIs
|
287
|
+
|
288
|
+
def dispose(dispose_images: true, dispose_patterns: true, redraw: true)
|
289
|
+
body_root.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: redraw)
|
290
|
+
# @dispose_listener_registration.deregister # TODO enable once returning a true listener object or observer proc registration
|
291
|
+
end
|
292
|
+
|
293
|
+
def disposed
|
294
|
+
body_root.disposed
|
295
|
+
end
|
296
|
+
alias disposed? disposed
|
297
|
+
alias is_disposed disposed
|
279
298
|
|
280
|
-
def method_missing(
|
299
|
+
def method_missing(method_name, *args, &block)
|
281
300
|
# TODO Consider supporting a glimmer error silencing option for methods defined here
|
282
301
|
# but fail the glimmer DSL for the right reason to avoid seeing noise in the log output
|
283
|
-
|
302
|
+
if block && can_handle_observation_request?(method_name)
|
303
|
+
handle_observation_request(method_name, &block)
|
304
|
+
else
|
305
|
+
body_root.send(method_name, *args, &block)
|
306
|
+
end
|
284
307
|
end
|
285
308
|
|
286
309
|
alias local_respond_to? respond_to?
|
287
|
-
def respond_to?(
|
310
|
+
def respond_to?(method_name, *args, &block)
|
288
311
|
super or
|
289
|
-
|
312
|
+
can_handle_observation_request?(method_name) or
|
313
|
+
body_root.respond_to?(method_name, *args, &block)
|
290
314
|
end
|
291
315
|
|
292
316
|
private
|
@@ -159,17 +159,12 @@ module Glimmer
|
|
159
159
|
def after_body(&block)
|
160
160
|
@after_body_block = block
|
161
161
|
end
|
162
|
-
|
163
|
-
# Current custom widgets being rendered. Useful to yoke all observers evaluated during rendering of their custom widgets for automatical disposal on_widget_disposed
|
164
|
-
def current_custom_widgets
|
165
|
-
@current_custom_widgets ||= []
|
166
|
-
end
|
167
162
|
end
|
168
163
|
|
169
164
|
attr_reader :body_root, :swt_widget, :parent, :parent_proxy, :swt_style, :options
|
170
165
|
|
171
166
|
def initialize(parent, *swt_constants, options, &content)
|
172
|
-
|
167
|
+
SWT::DisplayProxy.current_custom_widgets_and_shapes << self
|
173
168
|
@parent_proxy = @parent = parent
|
174
169
|
@parent_proxy = @parent&.get_data('proxy') if @parent.respond_to?(:get_data) && @parent.get_data('proxy')
|
175
170
|
@swt_style = SWT::SWTProxy[*swt_constants]
|
@@ -203,7 +198,7 @@ module Glimmer
|
|
203
198
|
end
|
204
199
|
|
205
200
|
def post_add_content
|
206
|
-
|
201
|
+
SWT::DisplayProxy.current_custom_widgets_and_shapes.delete(self)
|
207
202
|
end
|
208
203
|
|
209
204
|
def observer_registrations
|
@@ -312,7 +307,7 @@ module Glimmer
|
|
312
307
|
def method_missing(method, *args, &block)
|
313
308
|
# TODO Consider supporting a glimmer error silencing option for methods defined here
|
314
309
|
# but fail the glimmer DSL for the right reason to avoid seeing noise in the log output
|
315
|
-
if can_handle_observation_request?(method)
|
310
|
+
if block && can_handle_observation_request?(method)
|
316
311
|
handle_observation_request(method, &block)
|
317
312
|
else
|
318
313
|
body_root.send(method, *args, &block)
|
data/lib/glimmer-dsl-swt.rb
CHANGED
@@ -30,9 +30,13 @@ if !['', 'false'].include?(ENV['GLIMMER_BUNDLER_SETUP'].to_s.strip.downcase)
|
|
30
30
|
end
|
31
31
|
require 'java'
|
32
32
|
require 'puts_debuggerer' if ("#{ENV['pd']}#{ENV['PD']}").to_s.downcase.include?('true')
|
33
|
-
|
33
|
+
|
34
|
+
# concurrent-ruby gem ensures glimmer relies on Concurrent data-structure classes
|
35
|
+
require 'concurrent/array'
|
36
|
+
require 'concurrent/hash'
|
37
|
+
require 'concurrent/set'
|
34
38
|
require 'glimmer'
|
35
|
-
|
39
|
+
|
36
40
|
require 'nested_inherited_jruby_include_package'
|
37
41
|
require 'super_module'
|
38
42
|
require 'date'
|
@@ -7,16 +7,6 @@ class KlondikeSolitaire
|
|
7
7
|
class ColumnPile
|
8
8
|
include Glimmer::UI::CustomShape
|
9
9
|
|
10
|
-
IMAGE_EMPTY = image(50, 80) {
|
11
|
-
rectangle(0, 0, 50, 80) {
|
12
|
-
background :dark_green
|
13
|
-
|
14
|
-
rectangle(0, 0, 49, 79, 15, 15) {
|
15
|
-
foreground :gray
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}
|
19
|
-
|
20
10
|
options :pile_x, :pile_y, :model
|
21
11
|
|
22
12
|
after_body {
|
@@ -36,13 +26,10 @@ class KlondikeSolitaire
|
|
36
26
|
card_parent_pile = card_shape.parent_pile
|
37
27
|
card_source_model = card_parent_pile.model
|
38
28
|
cards = card_source_model.remove!(card)
|
39
|
-
if cards.is_a?(Array) # if it is a column pile
|
40
|
-
cards[1..-1].each do |card|
|
41
|
-
model.add!(card)
|
42
|
-
end
|
43
|
-
end
|
29
|
+
cards[1..-1].each { |card| model.add!(card) } if cards.is_a?(Array) # if it is a column pile
|
44
30
|
drop_event.dragged_shape.dispose
|
45
31
|
rescue => e
|
32
|
+
Glimmer::Config.logger.debug { "Error encountered on drop of a card to a column pile: #{e.full_message}" }
|
46
33
|
drop_event.doit = false
|
47
34
|
end
|
48
35
|
end
|
@@ -50,7 +37,7 @@ class KlondikeSolitaire
|
|
50
37
|
}
|
51
38
|
|
52
39
|
def build_column_pile(playing_cards)
|
53
|
-
body_root.shapes.to_a.each(
|
40
|
+
body_root.shapes.to_a.dup.each { |shape| shape.dispose(redraw: false) }
|
54
41
|
current_parent = body_root
|
55
42
|
playing_cards.each_with_index do |card, i|
|
56
43
|
current_parent.content {
|
@@ -12,7 +12,7 @@ class KlondikeSolitaire
|
|
12
12
|
|
13
13
|
after_body {
|
14
14
|
observe(model, 'playing_cards.empty?') do |empty_value|
|
15
|
-
body_root.shapes.to_a.each(
|
15
|
+
body_root.shapes.to_a.each { |shape| shape.dispose(redraw: false) }
|
16
16
|
if empty_value
|
17
17
|
body_root.content {
|
18
18
|
empty_playing_card
|
@@ -13,16 +13,23 @@ class KlondikeSolitaire
|
|
13
13
|
after_body do
|
14
14
|
observe(model, 'playing_cards.empty?') do |empty_value|
|
15
15
|
if empty_value
|
16
|
-
body_root.shapes.to_a.dup.each(
|
16
|
+
body_root.shapes.to_a.dup.each { |shape| shape.dispose(redraw: false) }
|
17
17
|
body_root.content {
|
18
18
|
empty_playing_card
|
19
19
|
}
|
20
20
|
else
|
21
|
-
body_root.
|
22
|
-
|
23
|
-
|
21
|
+
body_root.shapes.each { |shape| shape.drag_source = false }
|
22
|
+
before_last_shape = body_root.shapes[-2] && body_root.shapes[-2].get_data('custom_shape').respond_to?(:model) && body_root.shapes[-2].get_data('custom_shape').model
|
23
|
+
if model.playing_cards.last == before_last_shape # happens when dragging card out
|
24
|
+
body_root.shapes.last.dispose
|
25
|
+
body_root.shapes.last.drag_source = true
|
26
|
+
else
|
27
|
+
body_root.content {
|
28
|
+
playing_card(model: model.playing_cards.last, parent_pile: self) {
|
29
|
+
drag_source true
|
30
|
+
}
|
24
31
|
}
|
25
|
-
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
@@ -13,12 +13,13 @@ class KlondikeSolitaire
|
|
13
13
|
end
|
14
14
|
|
15
15
|
body {
|
16
|
-
rectangle(card_x, card_y,
|
16
|
+
rectangle(card_x, card_y, PLAYING_CARD_WIDTH - 1, PLAYING_CARD_HEIGHT - 1, 15, 15) {
|
17
17
|
foreground :gray
|
18
18
|
|
19
19
|
if suit
|
20
20
|
text {
|
21
21
|
string Model::PlayingCard.suit_text(suit)
|
22
|
+
font height: 20
|
22
23
|
x :default
|
23
24
|
y :default
|
24
25
|
is_transparent true
|
@@ -8,10 +8,9 @@ class KlondikeSolitaire
|
|
8
8
|
|
9
9
|
options :pile_x, :pile_y, :game, :suit
|
10
10
|
|
11
|
-
attr_accessor :
|
11
|
+
attr_accessor :model
|
12
12
|
|
13
13
|
before_body do
|
14
|
-
self.current_image = image(50, 80) {empty_playing_card(suit: suit)}
|
15
14
|
self.model = game.foundation_piles[Model::PlayingCard::SUITS.index(suit)]
|
16
15
|
end
|
17
16
|
|
@@ -45,6 +44,7 @@ class KlondikeSolitaire
|
|
45
44
|
card_source_model.remove!(card)
|
46
45
|
drop_event.dragged_shape.dispose
|
47
46
|
rescue => e
|
47
|
+
Glimmer::Config.logger.debug { "Error encountered on drop of a card to a foundation pile: #{e.full_message}" }
|
48
48
|
drop_event.doit = false
|
49
49
|
end
|
50
50
|
end
|
@@ -11,11 +11,11 @@ class KlondikeSolitaire
|
|
11
11
|
end
|
12
12
|
|
13
13
|
body {
|
14
|
-
rectangle(card_x, card_y,
|
14
|
+
rectangle(card_x, card_y, PLAYING_CARD_WIDTH - 1, PLAYING_CARD_HEIGHT - 1, 15, 15) {
|
15
15
|
background :red
|
16
16
|
|
17
17
|
# border
|
18
|
-
rectangle(0, 0,
|
18
|
+
rectangle(0, 0, PLAYING_CARD_WIDTH - 1, PLAYING_CARD_HEIGHT - 1, 15, 15) {
|
19
19
|
foreground :black
|
20
20
|
}
|
21
21
|
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class KlondikeSolitaire
|
2
|
+
module View
|
3
|
+
class KlondikeSolitaireMenuBar
|
4
|
+
include Glimmer::UI::CustomWidget
|
5
|
+
|
6
|
+
option :game
|
7
|
+
|
8
|
+
before_body do
|
9
|
+
@display = display {
|
10
|
+
on_about {
|
11
|
+
display_about_dialog
|
12
|
+
}
|
13
|
+
on_preferences {
|
14
|
+
display_about_dialog
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
body {
|
20
|
+
menu_bar {
|
21
|
+
menu {
|
22
|
+
text '&Game'
|
23
|
+
menu_item {
|
24
|
+
text '&Restart'
|
25
|
+
accelerator (OS.mac? ? :command : :ctrl), :r
|
26
|
+
|
27
|
+
on_widget_selected {
|
28
|
+
game.restart!
|
29
|
+
}
|
30
|
+
}
|
31
|
+
menu_item {
|
32
|
+
text 'E&xit'
|
33
|
+
accelerator :alt, :f4
|
34
|
+
|
35
|
+
on_widget_selected {
|
36
|
+
exit(0)
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
menu {
|
41
|
+
text '&Help'
|
42
|
+
menu_item {
|
43
|
+
text '&About...'
|
44
|
+
on_widget_selected {
|
45
|
+
display_about_dialog
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
def display_about_dialog
|
53
|
+
message_box(body_root) {
|
54
|
+
text 'About'
|
55
|
+
message "Glimmer Klondike Solitaire\nGlimmer DSL for SWT Elaborate Sample"
|
56
|
+
}.open
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -11,17 +11,18 @@ class KlondikeSolitaire
|
|
11
11
|
end
|
12
12
|
|
13
13
|
body {
|
14
|
-
rectangle(card_x, card_y,
|
14
|
+
rectangle(card_x, card_y, PLAYING_CARD_WIDTH - 1, PLAYING_CARD_HEIGHT - 1, 15, 15) {
|
15
15
|
background model.hidden ? :red : :white
|
16
16
|
|
17
17
|
# border
|
18
|
-
rectangle(0, 0,
|
18
|
+
rectangle(0, 0, PLAYING_CARD_WIDTH - 1, PLAYING_CARD_HEIGHT - 1, 15, 15) {
|
19
19
|
foreground :black
|
20
20
|
}
|
21
21
|
|
22
22
|
unless model.hidden?
|
23
23
|
text {
|
24
24
|
string model ? "#{model.rank_text}#{model.suit_text}" : ""
|
25
|
+
font height: PLAYING_CARD_FONT_HEIGHT
|
25
26
|
x 5
|
26
27
|
y 5
|
27
28
|
foreground model ? model.color : :transparent
|
@@ -4,35 +4,26 @@ require_relative 'klondike_solitaire/model/game'
|
|
4
4
|
|
5
5
|
require_relative 'klondike_solitaire/view/action_panel'
|
6
6
|
require_relative 'klondike_solitaire/view/tableau'
|
7
|
+
require_relative 'klondike_solitaire/view/klondike_solitaire_menu_bar'
|
7
8
|
|
8
9
|
class KlondikeSolitaire
|
9
10
|
include Glimmer::UI::CustomShell
|
10
11
|
|
11
12
|
PLAYING_CARD_WIDTH = 50
|
12
|
-
PLAYING_CARD_HEIGHT =
|
13
|
+
PLAYING_CARD_HEIGHT = 76
|
13
14
|
PLAYING_CARD_SPACING = 5
|
15
|
+
PLAYING_CARD_FONT_HEIGHT = 16
|
14
16
|
MARGIN = 15
|
15
17
|
TABLEAU_WIDTH = 2*MARGIN + 7*(PLAYING_CARD_WIDTH + PLAYING_CARD_SPACING)
|
16
|
-
TABLEAU_HEIGHT =
|
18
|
+
TABLEAU_HEIGHT = 420
|
17
19
|
|
18
20
|
before_body do
|
19
21
|
@game = Model::Game.new
|
20
|
-
Display.app_name = 'Glimmer Klondike Solitaire'
|
21
|
-
@display = display {
|
22
|
-
on_about {
|
23
|
-
display_about_dialog
|
24
|
-
}
|
25
|
-
on_preferences {
|
26
|
-
display_about_dialog
|
27
|
-
}
|
28
|
-
}
|
29
22
|
end
|
30
23
|
|
31
24
|
body {
|
32
25
|
shell {
|
33
|
-
|
34
|
-
fill true
|
35
|
-
center true
|
26
|
+
grid_layout {
|
36
27
|
margin_width 0
|
37
28
|
margin_height 0
|
38
29
|
margin_top 15
|
@@ -41,53 +32,20 @@ class KlondikeSolitaire
|
|
41
32
|
text "Glimmer Klondike Solitaire"
|
42
33
|
background :dark_green
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
height TABLEAU_HEIGHT
|
49
|
-
}
|
35
|
+
klondike_solitaire_menu_bar(game: @game)
|
36
|
+
|
37
|
+
action_panel(game: @game) {
|
38
|
+
layout_data(:fill, :center, true, false)
|
50
39
|
}
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
text '&Restart'
|
57
|
-
accelerator (OS.mac? ? :command : :ctrl), :r
|
58
|
-
|
59
|
-
on_widget_selected {
|
60
|
-
@game.restart!
|
61
|
-
}
|
62
|
-
}
|
63
|
-
menu_item {
|
64
|
-
text 'E&xit'
|
65
|
-
accelerator :alt, :f4
|
66
|
-
|
67
|
-
on_widget_selected {
|
68
|
-
body_root.close
|
69
|
-
}
|
70
|
-
}
|
71
|
-
}
|
72
|
-
menu {
|
73
|
-
text '&Help'
|
74
|
-
menu_item {
|
75
|
-
text '&About...'
|
76
|
-
on_widget_selected {
|
77
|
-
display_about_dialog
|
78
|
-
}
|
79
|
-
}
|
41
|
+
tableau(game: @game) {
|
42
|
+
layout_data(:fill, :fill, true, true) {
|
43
|
+
width_hint TABLEAU_WIDTH
|
44
|
+
height_hint TABLEAU_HEIGHT
|
80
45
|
}
|
81
46
|
}
|
82
47
|
}
|
83
48
|
}
|
84
|
-
|
85
|
-
def display_about_dialog
|
86
|
-
message_box(body_root) {
|
87
|
-
text 'About'
|
88
|
-
message "Glimmer Klondike Solitaire\nGlimmer DSL for SWT Elaborate Sample"
|
89
|
-
}.open
|
90
|
-
end
|
91
49
|
end
|
92
50
|
|
93
51
|
KlondikeSolitaire.launch
|
@@ -21,7 +21,9 @@
|
|
21
21
|
|
22
22
|
require 'glimmer-dsl-swt'
|
23
23
|
require 'complex'
|
24
|
-
require 'concurrent
|
24
|
+
require 'concurrent/executor/fixed_thread_pool'
|
25
|
+
require 'concurrent/utility/processor_counter'
|
26
|
+
require 'concurrent/array'
|
25
27
|
|
26
28
|
# Mandelbrot multi-threaded implementation leveraging all processor cores.
|
27
29
|
class Mandelbrot
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require_relative 'piece'
|
23
|
+
require_relative 'piece/cube'
|
24
|
+
require_relative 'piece/cylinder'
|
25
|
+
|
26
|
+
class Quarto
|
27
|
+
module Model
|
28
|
+
class Game
|
29
|
+
MOVES = [:select_piece, :place_piece]
|
30
|
+
PLAYER_NUMBERS = [1, 2]
|
31
|
+
ROW_COUNT = 4
|
32
|
+
COLUMN_COUNT = 4
|
33
|
+
|
34
|
+
attr_accessor :board, :available_pieces, :selected_piece, :current_move, :current_player_number, :over, :winner_player_number
|
35
|
+
alias over? over
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
start
|
39
|
+
end
|
40
|
+
|
41
|
+
def start
|
42
|
+
self.over = false
|
43
|
+
self.board = ROW_COUNT.times.map {COLUMN_COUNT.times.map {nil}}
|
44
|
+
self.available_pieces = Piece.all_pieces.dup
|
45
|
+
self.selected_piece = nil
|
46
|
+
self.current_player_number = 1
|
47
|
+
self.current_move = MOVES.first
|
48
|
+
self.winner_player_number = nil
|
49
|
+
end
|
50
|
+
alias restart start
|
51
|
+
|
52
|
+
def select_piece(piece)
|
53
|
+
self.selected_piece = piece
|
54
|
+
next_player
|
55
|
+
next_move
|
56
|
+
end
|
57
|
+
|
58
|
+
def place_piece(piece, row:, column:)
|
59
|
+
if @board[row][column].nil?
|
60
|
+
@board[row][column] = piece
|
61
|
+
if win?
|
62
|
+
self.winner_player_number = current_player_number # must set before updating observed over attribute
|
63
|
+
self.over = true
|
64
|
+
elsif draw?
|
65
|
+
self.winner_player_number = nil # must set before updating observed over attribute
|
66
|
+
self.over = true
|
67
|
+
else
|
68
|
+
next_move
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def next_move
|
74
|
+
last_move = current_move
|
75
|
+
last_move_index = MOVES.index(last_move)
|
76
|
+
self.current_move = MOVES[(last_move_index + 1)%MOVES.size]
|
77
|
+
end
|
78
|
+
|
79
|
+
def next_player
|
80
|
+
last_player_number = current_player_number
|
81
|
+
last_player_number_index = PLAYER_NUMBERS.index(current_player_number)
|
82
|
+
self.current_player_number = PLAYER_NUMBERS[(last_player_number_index + 1)%PLAYER_NUMBERS.size]
|
83
|
+
end
|
84
|
+
|
85
|
+
def draw?
|
86
|
+
!win? && board.flatten.compact.count == 12
|
87
|
+
end
|
88
|
+
|
89
|
+
def win?
|
90
|
+
row_win? || column_win? || diagonal_win?
|
91
|
+
end
|
92
|
+
|
93
|
+
def row_win?
|
94
|
+
ROW_COUNT.times.any? { |row| equivalent_pieces?(@board[row]) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def column_win?
|
98
|
+
COLUMN_COUNT.times.any? do |column|
|
99
|
+
equivalent_pieces?(ROW_COUNT.times.map {|row| @board[row][column]})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def diagonal_win?
|
104
|
+
diagonal1_win? || diagonal2_win?
|
105
|
+
end
|
106
|
+
|
107
|
+
def diagonal1_win?
|
108
|
+
equivalent_pieces?(ROW_COUNT.times.map { |n| @board[n][n] })
|
109
|
+
end
|
110
|
+
|
111
|
+
def diagonal2_win?
|
112
|
+
equivalent_pieces?(ROW_COUNT.times.map { |n| @board[ROW_COUNT - 1 - n][n] })
|
113
|
+
end
|
114
|
+
|
115
|
+
def equivalent_pieces?(the_pieces)
|
116
|
+
return false if the_pieces.any?(&:nil?)
|
117
|
+
the_pieces.map(&:class).uniq.size == 1 ||
|
118
|
+
the_pieces.map(&:pitted).uniq.size == 1 ||
|
119
|
+
the_pieces.map(&:height).uniq.size == 1 ||
|
120
|
+
the_pieces.map(&:color).uniq.size == 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Copyright (c) 2007-2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require_relative '../piece'
|
23
|
+
|
24
|
+
class Quarto
|
25
|
+
module Model
|
26
|
+
class Piece
|
27
|
+
class Cube < Piece
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|