draw_color_repeat 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +556 -0
  4. data/VERSION +1 -0
  5. data/app/dcr.rb +51 -0
  6. data/app/dcr/launch.rb +3 -0
  7. data/app/models/dcr/command.rb +129 -0
  8. data/app/models/dcr/command/backward.rb +45 -0
  9. data/app/models/dcr/command/color.rb +120 -0
  10. data/app/models/dcr/command/empty.rb +30 -0
  11. data/app/models/dcr/command/forward.rb +47 -0
  12. data/app/models/dcr/command/left.rb +37 -0
  13. data/app/models/dcr/command/repeat.rb +42 -0
  14. data/app/models/dcr/command/right.rb +36 -0
  15. data/app/models/dcr/polygon.rb +37 -0
  16. data/app/models/dcr/program.rb +130 -0
  17. data/app/views/dcr/app_view.rb +128 -0
  18. data/app/views/dcr/compass.rb +56 -0
  19. data/bin/dcr +13 -0
  20. data/config/warble.rb +183 -0
  21. data/dcr.gemspec +0 -0
  22. data/lib/icon.rb +53 -0
  23. data/package/linux/Draw Color Repeat.png +0 -0
  24. data/package/macosx/Draw Color Repeat.icns +0 -0
  25. data/package/windows/Draw Color Repeat.ico +0 -0
  26. data/samples/aztec_pyramid.dcr +15 -0
  27. data/samples/bee_hive.dcr +15 -0
  28. data/samples/circle.dcr +4 -0
  29. data/samples/circle_of_circles.dcr +7 -0
  30. data/samples/envelope.dcr +14 -0
  31. data/samples/equilateral_triangle.dcr +6 -0
  32. data/samples/five_pointed_star.dcr +4 -0
  33. data/samples/house.dcr +25 -0
  34. data/samples/octagon.dcr +4 -0
  35. data/samples/octagon_of_octagons.dcr +6 -0
  36. data/samples/octagon_of_squares.dcr +7 -0
  37. data/samples/playing_cards.dcr +9 -0
  38. data/samples/rectangle.dcr +6 -0
  39. data/samples/sherrif_badge_star.dcr +8 -0
  40. data/samples/spider_web.dcr +6 -0
  41. data/samples/square.dcr +4 -0
  42. data/samples/stairs.dcr +16 -0
  43. data/samples/stick_figure.dcr +21 -0
  44. data/samples/sun.dcr +9 -0
  45. data/samples/swirl.dcr +7 -0
  46. data/samples/traffic_light.dcr +29 -0
  47. data/samples/triangle.dcr +5 -0
  48. data/vendor/jars/org/yaml/snakeyaml/1.28/snakeyaml-1.28.jar +0 -0
  49. metadata +207 -0
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/app/dcr.rb ADDED
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 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
+ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
23
+
24
+ begin
25
+ require 'bundler/setup'
26
+ Bundler.require(:default)
27
+ rescue
28
+ # gem mode requires manually
29
+ require 'glimmer-dsl-swt'
30
+ require 'glimmer-cp-stickfigure'
31
+ require 'strategic'
32
+ require 'equalizer'
33
+ end
34
+
35
+ require 'puts_debuggerer'
36
+ require 'views/dcr/app_view'
37
+
38
+ class Dcr
39
+ include Glimmer
40
+
41
+ APP_ROOT = File.expand_path('../..', __FILE__)
42
+ VERSION = File.read(File.join(APP_ROOT, 'VERSION'))
43
+ LICENSE = File.read(File.join(APP_ROOT, 'LICENSE.txt'))
44
+
45
+ def open
46
+ app_view.open
47
+ end
48
+ end
49
+
50
+ org.eclipse.swt.widgets.Display.app_name = 'Draw Color Repeat'
51
+ org.eclipse.swt.widgets.Display.app_version = Dcr::VERSION
data/app/dcr/launch.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative '../dcr'
2
+
3
+ Dcr.new.open
@@ -0,0 +1,129 @@
1
+ # Copyright (c) 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
+ class Dcr
23
+ # Follows the Command, Strategy, and Chain of Responsibility Design Patterns
24
+ class Command
25
+ include Strategic
26
+ include Glimmer
27
+
28
+ class << self
29
+ def create(program: , text: )
30
+ operation = parse_operation(text)
31
+ operation_strategy = strategies.detect { |strategy| strategy.match?(operation) } unless operation.nil?
32
+ operation_strategy ||= Command::Empty
33
+ operation_strategy&.new(program: program, text: text)
34
+ end
35
+
36
+ def parse_operation(text)
37
+ text.to_s.strip.downcase.match(/([^ 0-9]+)/).to_a[1]
38
+ end
39
+
40
+ def parse_value(text)
41
+ text.to_s.strip.downcase.match(/[^ 0-9]+[ ]*([^ ]*)/).to_a[1]
42
+ end
43
+
44
+ def command_alias(alias_value)
45
+ command_aliases << alias_value
46
+ end
47
+
48
+ def command_aliases
49
+ @command_aliases ||= []
50
+ end
51
+
52
+ def command_exclusion(exclusion_value)
53
+ command_exclusions << exclusion_value
54
+ end
55
+
56
+ def command_exclusions
57
+ @command_exclusions ||= []
58
+ end
59
+
60
+ def match?(operation)
61
+ (operation_derivatives(command_operation) + command_aliases - command_exclusions).include?(operation.to_s.downcase)
62
+ end
63
+
64
+ def command_operation
65
+ name.split('::').last.downcase
66
+ end
67
+
68
+ def operation_derivatives(operation)
69
+ operation_length = operation.length
70
+ operation_length.times.map {|n| operation.chars.combination(operation_length - n).to_a}.reduce(:+).map(&:join)
71
+ end
72
+ end
73
+
74
+ attr_reader :text
75
+
76
+ def initialize(program: , text: )
77
+ @program = program
78
+ @text = text
79
+ end
80
+
81
+ def operation=(new_operation)
82
+ return if parse_operation(new_operation) == parsed_operation
83
+ @text.sub(parsed_operation, new_operation)
84
+ command_index_of_self = @program.commands.index(self)
85
+ @program.commands[command_index_of_self..command_index_of_self] = create(program: @program, text: @text)
86
+ end
87
+
88
+ def value=(new_value)
89
+ return if parse_value(new_value) == parsed_value
90
+ @text.sub(parsed_value, new_value)
91
+ @program.notify_observers('commands')
92
+ end
93
+
94
+ # Subclasses must override to provide parsed operation (e.g. 'f' becomes 'forward')
95
+ def operation
96
+ parsed_operation
97
+ end
98
+
99
+ def parsed_operation
100
+ Command.parse_operation(@text)
101
+ end
102
+
103
+ def operation_options
104
+ Command.strategy_names
105
+ end
106
+
107
+ # Subclasses must override to provide parsed value (e.g. 'r' becomes 'red' or '30' becomes 30)
108
+ def value
109
+ parsed_value
110
+ end
111
+
112
+ def parsed_value
113
+ parsed_value = Command.parse_value(@text)
114
+ parsed_value.to_s.match(/\d+/) ? parsed_value.to_i : parsed_value
115
+ end
116
+
117
+ def normalized_text
118
+ "#{operation} #{value}"
119
+ end
120
+
121
+ # Subclasses must implement
122
+ def call
123
+ # No Op
124
+ end
125
+ end
126
+ end
127
+
128
+ # Require all command strategies
129
+ Dir[File.expand_path(File.join('command', '**', '*.rb'), __dir__)].each {|f| require f}
@@ -0,0 +1,45 @@
1
+ # Copyright (c) 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
+ class Dcr
23
+ class Command
24
+ class Backward < Command
25
+ command_alias 'b'
26
+
27
+ def call
28
+ p1 = java.awt.geom.Point2D::Double.new(value, 0)
29
+ p2 = java.awt.geom.Point2D::Double.new(0, 0)
30
+ t = java.awt.geom.AffineTransform.new
31
+ t.set_to_rotation(@program.angle*(Math::PI/2.0)/90.0 - Math::PI/2.0)
32
+ t.transform(p1, p2)
33
+ new_x = @program.location_x - p2.x
34
+ new_y = @program.location_y - p2.y
35
+ @program.polygons.last.point_array += [new_x, new_y]
36
+ @program.location_x = new_x
37
+ @program.location_y = new_y
38
+ end
39
+
40
+ def value
41
+ super.to_f == 0 ? 1.0 : super.to_f
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,120 @@
1
+ # Copyright (c) 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
+ class Dcr
23
+ class Command
24
+ class Color < Command
25
+ # color map from strings to Glimmer DSL for SWT colors
26
+ COLOR_MAP = {
27
+ 'black' => :black,
28
+ 'blue' => :cyan,
29
+ 'gray' => :gray,
30
+ 'grey' => :gray,
31
+ 'green' => :green,
32
+ 'orange' => [255, 127, 0],
33
+ 'pink' => :magenta,
34
+ 'purple' => :dark_magenta,
35
+ 'red' => :red,
36
+ 'white' => :white,
37
+ 'yellow' => :yellow,
38
+ }
39
+ COLOR_MAP_ALIASES = {
40
+ 'grey' => :gray,
41
+ 'k' => :black,
42
+ 'b' => :cyan,
43
+ 'a' => :gray,
44
+ 'g' => :green,
45
+ 'o' => [255, 127, 0],
46
+ 'i' => :magenta,
47
+ 'p' => :dark_magenta,
48
+ 'r' => :red,
49
+ 'w' => :white,
50
+ 'y' => :yellow,
51
+ }
52
+ command_alias 'c'
53
+ command_exclusion 'r'
54
+
55
+ class << self
56
+ attr_reader :next_color_index
57
+
58
+ def expanded_color_map
59
+ @expanded_color_map ||= COLOR_MAP.reduce({}) do |hash, pair|
60
+ color_string = pair.first
61
+ color_value = pair.last
62
+ color_hash = color_derivatives(color_string).reduce({}) do |color_derivative_hash, color_derivative|
63
+ color_derivative_hash.merge(color_derivative => color_value)
64
+ end
65
+ hash.merge(color_hash)
66
+ end.merge(COLOR_MAP_ALIASES)
67
+ end
68
+
69
+ def color_derivatives(color_string)
70
+ color_string_length = color_string.length
71
+ color_string_length.times.map {|n| color_string.chars.combination(color_string_length - n).to_a}.reduce(:+).map(&:join)
72
+ end
73
+
74
+ def next_color_string
75
+ reset_next_color_index! if @next_color_index.nil?
76
+ @next_color_index += 1
77
+ COLOR_MAP.keys[@next_color_index % COLOR_MAP.count]
78
+ end
79
+
80
+ def next_color
81
+ COLOR_MAP[next_color_string]
82
+ end
83
+
84
+ def reset_next_color_index!(next_color_index_value=nil)
85
+ @next_color_index = next_color_index_value || -2 # start at yellow (since it skips one with the first addition)
86
+ end
87
+
88
+ def normalize_color_string(color_string)
89
+ color_value = Color.expanded_color_map[color_string]
90
+ COLOR_MAP.invert[color_value]
91
+ end
92
+ end
93
+
94
+ def call
95
+ @program.polygons.last&.background = interpreted_value
96
+ @program.new_polygon!
97
+ end
98
+
99
+ def value
100
+ value_string = super.to_s
101
+ if @value_string != value_string || @value_string.empty?
102
+ @value_string = value_string
103
+ # TODO beware of the edge case where if the last value string is empty, the comparable, which includes value, ends up returning a match with yellow (first color in series) thus not updating GUI
104
+ @value = Color.expanded_color_map.keys.include?(value_string) ? Color.normalize_color_string(value_string) : next_color_string
105
+ end
106
+ @value
107
+ end
108
+
109
+ # interpreted value is used by GUI
110
+ def interpreted_value
111
+ the_value = value
112
+ COLOR_MAP[the_value]
113
+ end
114
+
115
+ def next_color_string
116
+ Color.next_color_string
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 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
+ class Dcr
23
+ class Command
24
+ # This command represents an empty line,
25
+ # which separates repeatable groups of commands
26
+ class Empty < Command
27
+ command_alias ''
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright (c) 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 '../polygon'
23
+
24
+ class Dcr
25
+ class Command
26
+ class Forward < Command
27
+ command_alias 'f'
28
+
29
+ def call
30
+ p1 = java.awt.geom.Point2D::Double.new(value, 0)
31
+ p2 = java.awt.geom.Point2D::Double.new(0, 0)
32
+ t = java.awt.geom.AffineTransform.new
33
+ t.set_to_rotation(@program.angle*(Math::PI/2.0)/90.0 - Math::PI/2.0)
34
+ t.transform(p1, p2)
35
+ new_x = @program.location_x + p2.x
36
+ new_y = @program.location_y + p2.y
37
+ @program.polygons.last.point_array += [new_x, new_y]
38
+ @program.location_x = new_x
39
+ @program.location_y = new_y
40
+ end
41
+
42
+ def value
43
+ super.to_f == 0 ? 1.0 : super.to_f
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 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
+ class Dcr
23
+ class Command
24
+ class Left < Command
25
+ command_alias 'l'
26
+ command_exclusion 'f'
27
+
28
+ def call
29
+ @program.angle -= value
30
+ end
31
+
32
+ def value
33
+ super.to_f == 0 ? 90.0 : super.to_f
34
+ end
35
+ end
36
+ end
37
+ end