glimmer-dsl-swt 4.22.0.0 → 4.22.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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
|