glimmer-dsl-swt 4.18.5.1 → 4.18.6.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +15 -12
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +205 -24
  6. data/docs/reference/GLIMMER_SAMPLES.md +8 -0
  7. data/glimmer-dsl-swt.gemspec +8 -3
  8. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  9. data/lib/glimmer/swt/custom/drawable.rb +10 -2
  10. data/lib/glimmer/swt/custom/shape.rb +449 -54
  11. data/lib/glimmer/swt/custom/shape/arc.rb +35 -0
  12. data/lib/glimmer/swt/custom/shape/cubic.rb +108 -0
  13. data/lib/glimmer/swt/custom/shape/focus.rb +2 -2
  14. data/lib/glimmer/swt/custom/shape/image.rb +35 -9
  15. data/lib/glimmer/swt/custom/shape/line.rb +121 -4
  16. data/lib/glimmer/swt/custom/shape/oval.rb +18 -0
  17. data/lib/glimmer/swt/custom/shape/path.rb +197 -0
  18. data/lib/glimmer/swt/custom/shape/path_segment.rb +86 -0
  19. data/lib/glimmer/swt/custom/shape/point.rb +42 -4
  20. data/lib/glimmer/swt/custom/shape/polygon.rb +105 -15
  21. data/lib/glimmer/swt/custom/shape/polyline.rb +88 -15
  22. data/lib/glimmer/swt/custom/shape/quad.rb +104 -0
  23. data/lib/glimmer/swt/custom/shape/rectangle.rb +19 -0
  24. data/lib/glimmer/swt/custom/shape/text.rb +13 -3
  25. data/lib/glimmer/swt/dialog_proxy.rb +4 -0
  26. data/lib/glimmer/swt/proxy_properties.rb +1 -1
  27. data/lib/glimmer/swt/transform_proxy.rb +20 -4
  28. data/lib/glimmer/swt/widget_proxy.rb +17 -1
  29. data/samples/elaborate/contact_manager.rb +2 -0
  30. data/samples/elaborate/login.rb +2 -0
  31. data/samples/elaborate/mandelbrot_fractal.rb +2 -1
  32. data/samples/elaborate/meta_sample.rb +1 -0
  33. data/samples/elaborate/tetris.rb +2 -1
  34. data/samples/elaborate/tic_tac_toe.rb +2 -0
  35. data/samples/elaborate/user_profile.rb +10 -8
  36. data/samples/hello/hello_browser.rb +2 -0
  37. data/samples/hello/hello_button.rb +2 -0
  38. data/samples/hello/hello_canvas.rb +40 -23
  39. data/samples/hello/hello_canvas_animation.rb +2 -0
  40. data/samples/hello/hello_canvas_path.rb +223 -0
  41. data/samples/hello/hello_canvas_transform.rb +2 -0
  42. data/samples/hello/hello_checkbox.rb +2 -0
  43. data/samples/hello/hello_checkbox_group.rb +2 -0
  44. data/samples/hello/hello_code_text.rb +2 -0
  45. data/samples/hello/hello_color_dialog.rb +2 -0
  46. data/samples/hello/hello_combo.rb +2 -0
  47. data/samples/hello/hello_computed.rb +2 -0
  48. data/samples/hello/hello_cursor.rb +2 -0
  49. data/samples/hello/hello_custom_shell.rb +1 -0
  50. data/samples/hello/hello_custom_widget.rb +2 -0
  51. data/samples/hello/hello_date_time.rb +2 -0
  52. data/samples/hello/hello_dialog.rb +2 -0
  53. data/samples/hello/hello_directory_dialog.rb +2 -0
  54. data/samples/hello/hello_drag_and_drop.rb +5 -3
  55. data/samples/hello/hello_expand_bar.rb +2 -0
  56. data/samples/hello/hello_file_dialog.rb +2 -0
  57. data/samples/hello/hello_font_dialog.rb +2 -0
  58. data/samples/hello/hello_group.rb +2 -0
  59. data/samples/hello/hello_link.rb +2 -0
  60. data/samples/hello/hello_list_multi_selection.rb +2 -0
  61. data/samples/hello/hello_list_single_selection.rb +2 -0
  62. data/samples/hello/hello_menu_bar.rb +2 -0
  63. data/samples/hello/hello_message_box.rb +2 -0
  64. data/samples/hello/hello_pop_up_context_menu.rb +2 -0
  65. data/samples/hello/hello_progress_bar.rb +2 -0
  66. data/samples/hello/hello_radio.rb +2 -0
  67. data/samples/hello/hello_radio_group.rb +2 -0
  68. data/samples/hello/hello_sash_form.rb +2 -0
  69. data/samples/hello/hello_spinner.rb +2 -0
  70. data/samples/hello/hello_styled_text.rb +19 -17
  71. data/samples/hello/hello_tab.rb +2 -0
  72. data/samples/hello/hello_table.rb +2 -0
  73. data/samples/hello/hello_world.rb +2 -0
  74. metadata +7 -2
@@ -0,0 +1,86 @@
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 'glimmer/swt/custom/shape'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ module Custom
27
+ # Represents a path to be drawn on a control/widget/canvas/display
28
+ # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
29
+ class Shape
30
+ # Represents path segments like point, line, quad, and cubic curves
31
+ # Shapes could mix in
32
+ module PathSegment
33
+ # Subclasses must override and implement to indicate method name to invoke on SWT Path object to add segment
34
+ def path_segment_method_name
35
+ nil
36
+ end
37
+ # Subclasses must override and implement to indicate args to pass when invoking SWT Path object method
38
+ def path_segment_args
39
+ []
40
+ end
41
+ # Subclasses may override to provide name of method to invoke for geometry object obtained from the Java AWT library java.awt.geom.Path2D.Double (e.g. curveTo vs cubicTo)
42
+ def path_segment_geometry_method_name
43
+ path_segment_method_name
44
+ end
45
+ # Subclasses must override and implement to indicate args to pass when invoking SWT Path object method
46
+ def path_segment_geometry_args
47
+ path_segment_args
48
+ end
49
+ # Subclasses must override to indicate otherwise
50
+ def previous_point_connected?
51
+ true
52
+ end
53
+
54
+ def dispose
55
+ parent.post_dispose_content(self) if parent.is_a?(Path)
56
+ end
57
+
58
+ def first_path_segment?
59
+ parent.path_segments.first == self
60
+ end
61
+
62
+ def previous_path_segment
63
+ parent.path_segments[parent.path_segments.index(self) - 1] || self
64
+ end
65
+
66
+ def add_to_swt_path(swt_path)
67
+ if @swt_path != swt_path
68
+ @swt_path = swt_path
69
+ the_path_segment_args = path_segment_args.dup
70
+ if !previous_point_connected? && !is_a?(Point)
71
+ if the_path_segment_args.count > 2
72
+ point = the_path_segment_args.shift, the_path_segment_args.shift
73
+ @swt_path.moveTo(*point)
74
+ elsif first_path_segment? && self.class != Path
75
+ point = the_path_segment_args[0..1]
76
+ @swt_path.moveTo(*point)
77
+ end
78
+ end
79
+ @swt_path.send(path_segment_method_name, *the_path_segment_args)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/swt/custom/shape'
23
+ require 'glimmer/swt/custom/shape/path_segment'
23
24
  require 'glimmer/swt/swt_proxy'
24
25
  require 'glimmer/swt/display_proxy'
25
26
  require 'glimmer/swt/color_proxy'
@@ -33,18 +34,55 @@ module Glimmer
33
34
  # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
34
35
  class Shape
35
36
  class Point < Shape
37
+ include PathSegment
38
+
36
39
  def parameter_names
37
40
  [:x, :y]
38
41
  end
39
42
 
43
+ def width
44
+ 1
45
+ end
46
+
47
+ def height
48
+ 1
49
+ end
50
+
40
51
  def include?(x, y)
41
- x.to_i.between?(self.x.to_i - 2, self.x.to_i + 2) && y.to_i.between?(self.y.to_i - 2, self.y.to_i + 2)
52
+ # give it some fuzz (helps makes mouse clicking easier)
53
+ x.to_i.between?(self.absolute_x.to_i - 2, self.absolute_x.to_i + 2) && y.to_i.between?(self.absolute_y.to_i - 2, self.absolute_y.to_i + 2)
54
+ end
55
+ alias contain? include?
56
+
57
+ def path_segment_method_name
58
+ 'addRectangle'
59
+ end
60
+
61
+ def path_segment_args
62
+ @args + [1, 1]
42
63
  end
43
64
 
44
- def move_by(x_delta, y_delta)
45
- self.x += x_delta
46
- self.y += y_delta
65
+ def path_segment_geometry_method_name
66
+ 'moveTo'
47
67
  end
68
+
69
+ def path_segment_geometry_args
70
+ @args
71
+ end
72
+
73
+ def previous_point_connected?
74
+ false
75
+ end
76
+
77
+ def eql?(other)
78
+ x == (other && other.respond_to?(:x) && other.x) && y == (other && other.respond_to?(:y) && other.y)
79
+ end
80
+ alias == eql?
81
+
82
+ def hash
83
+ [x, y].hash
84
+ end
85
+
48
86
  end
49
87
  end
50
88
  end
@@ -37,35 +37,125 @@ module Glimmer
37
37
  [:point_array]
38
38
  end
39
39
 
40
- def size
41
- point_array.size / 2
40
+ def location_parameter_names
41
+ parameter_names
42
+ end
43
+
44
+ def point_count
45
+ point_array.count / 2
42
46
  end
43
47
 
44
48
  def [](index)
45
- index = 0 if index == size
49
+ index = 0 if index == point_count
46
50
  org.eclipse.swt.graphics.Point.new(point_array[index * 2], point_array[index * 2 + 1])
47
51
  end
48
52
 
49
- def include?(x, y)
50
- c = false
51
- i = -1
52
- j = self.size
53
- while (i += 1) < (self.size + 1)
54
- if ((self[i].y <= y && y < self[j].y) ||
55
- (self[j].y <= y && y < self[i].y))
56
- if (x < (self[j].x - self[i].x) * (y - self[i].y) /
57
- (self[j].y - self[i].y) + self[i].x)
58
- c = !c
53
+ def x_array
54
+ point_array.each_with_index.select {|pair| pair.last.even?}.map(&:first)
55
+ end
56
+
57
+ def y_array
58
+ point_array.each_with_index.select {|pair| pair.last.odd?}.map(&:first)
59
+ end
60
+
61
+ def point_xy_array
62
+ x_array.zip(y_array)
63
+ end
64
+
65
+ def absolute_point_array
66
+ if parent.is_a?(Shape)
67
+ point_array.each_with_index.map do |coordinate, i|
68
+ if i.even?
69
+ parent.absolute_x + coordinate
70
+ else
71
+ parent.absolute_y + coordinate
59
72
  end
60
- j = i
61
73
  end
74
+ else
75
+ point_array
62
76
  end
63
- c
64
77
  end
65
78
 
79
+ def absolute_x_array
80
+ absolute_point_array.each_with_index.select {|pair| pair.last.even?}.map(&:first)
81
+ end
82
+
83
+ def absolute_y_array
84
+ absolute_point_array.each_with_index.select {|pair| pair.last.odd?}.map(&:first)
85
+ end
86
+
87
+ def absolute_point_xy_array
88
+ absolute_x_array.zip(absolute_y_array)
89
+ end
90
+
91
+ def bounds
92
+ the_point_array = point_array
93
+ if the_point_array != @bounds_point_array
94
+ @bounds_point_array = point_array
95
+ shape_bounds = geometry.getBounds2D
96
+ @bounds = org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
97
+ end
98
+ @bounds
99
+ end
100
+
101
+ def size
102
+ the_point_array = point_array
103
+ if the_point_array != @size_point_array
104
+ @size_point_array = point_array
105
+ shape_bounds = geometry.getBounds2D
106
+ @size = org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
107
+ end
108
+ @size
109
+ end
110
+
111
+ def geometry
112
+ the_point_array = point_array
113
+ if the_point_array != @geometry_point_array
114
+ @geometry_point_array = point_array
115
+ @geometry = java.awt.Polygon.new(absolute_x_array.to_java(:int), absolute_y_array.to_java(:int), point_count)
116
+ end
117
+ @geometry
118
+ end
119
+
120
+ # Logical x coordinate relative to parent
121
+ def x
122
+ x_value = bounds.x
123
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
124
+ x_value
125
+ end
126
+
127
+ # Logical y coordinate relative to parent
128
+ def y
129
+ y_value = bounds.y
130
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
131
+ y_value
132
+ end
133
+
134
+ def width
135
+ size.x
136
+ end
137
+
138
+ def height
139
+ size.y
140
+ end
141
+
142
+ def contain?(x, y)
143
+ geometry.contains(x, y)
144
+ end
145
+
146
+ def include?(x, y)
147
+ comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
148
+ comparison_lines.any? {|line| Line.include?(line.first.first, line.first.last, line.last.first, line.last.last, x, y)}
149
+ end
150
+
66
151
  def move_by(x_delta, y_delta)
67
152
  self.point_array = point_array.each_with_index.map {|coordinate, i| i.even? ? coordinate + x_delta : coordinate + y_delta}
68
153
  end
154
+
155
+ def irregular?
156
+ true
157
+ end
158
+
69
159
  end
70
160
  end
71
161
  end
@@ -37,35 +37,108 @@ module Glimmer
37
37
  [:point_array]
38
38
  end
39
39
 
40
- def size
41
- point_array.size / 2
40
+ def location_parameter_names
41
+ parameter_names
42
+ end
43
+
44
+ def point_count
45
+ point_array.count / 2
42
46
  end
43
47
 
44
48
  def [](index)
45
- index = 0 if index == size
49
+ index = 0 if index == point_count
46
50
  org.eclipse.swt.graphics.Point.new(point_array[index * 2], point_array[index * 2 + 1])
47
51
  end
48
52
 
49
- def include?(x, y)
50
- c = false
51
- i = -1
52
- j = self.size
53
- while (i += 1) < (self.size + 1)
54
- if ((self[i].y <= y && y < self[j].y) ||
55
- (self[j].y <= y && y < self[i].y))
56
- if (x < (self[j].x - self[i].x) * (y - self[i].y) /
57
- (self[j].y - self[i].y) + self[i].x)
58
- c = !c
53
+ def x_array
54
+ point_array.each_with_index.select {|pair| pair.last.even?}.map(&:first)
55
+ end
56
+
57
+ def y_array
58
+ point_array.each_with_index.select {|pair| pair.last.odd?}.map(&:first)
59
+ end
60
+
61
+ def point_xy_array
62
+ x_array.zip(y_array)
63
+ end
64
+
65
+ def absolute_point_array
66
+ if parent.is_a?(Shape)
67
+ point_array.each_with_index.map do |coordinate, i|
68
+ if i.even?
69
+ parent.absolute_x + coordinate
70
+ else
71
+ parent.absolute_y + coordinate
59
72
  end
60
- j = i
61
73
  end
74
+ else
75
+ point_array
62
76
  end
63
- c
64
77
  end
65
78
 
79
+ def absolute_x_array
80
+ absolute_point_array.each_with_index.select {|pair| pair.last.even?}.map(&:first)
81
+ end
82
+
83
+ def absolute_y_array
84
+ absolute_point_array.each_with_index.select {|pair| pair.last.odd?}.map(&:first)
85
+ end
86
+
87
+ def absolute_point_xy_array
88
+ absolute_x_array.zip(absolute_y_array)
89
+ end
90
+
91
+ def bounds
92
+ shape_bounds = geometry.getBounds2D
93
+ org.eclipse.swt.graphics.Rectangle.new(shape_bounds.x, shape_bounds.y, shape_bounds.width, shape_bounds.height)
94
+ end
95
+
96
+ def size
97
+ shape_bounds = geometry.getBounds2D
98
+ org.eclipse.swt.graphics.Point.new(shape_bounds.width, shape_bounds.height)
99
+ end
100
+
101
+ def geometry
102
+ java.awt.Polygon.new(absolute_x_array.to_java(:int), absolute_y_array.to_java(:int), point_count)
103
+ end
104
+
105
+ # Logical x coordinate relative to parent
106
+ def x
107
+ x_value = bounds.x
108
+ x_value -= parent.absolute_x if parent.is_a?(Shape)
109
+ x_value
110
+ end
111
+
112
+ # Logical y coordinate relative to parent
113
+ def y
114
+ y_value = bounds.y
115
+ y_value -= parent.absolute_y if parent.is_a?(Shape)
116
+ y_value
117
+ end
118
+
119
+ def width
120
+ bounds.width
121
+ end
122
+
123
+ def height
124
+ bounds.height
125
+ end
126
+
127
+ def include?(x, y)
128
+ comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
129
+ comparison_lines.pop # ignore last pair since you don't want to compare last point with first point
130
+ comparison_lines.any? {|line| Line.include?(line.first.first, line.first.last, line.last.first, line.last.last, x, y)}
131
+ end
132
+ alias contain? include?
133
+
66
134
  def move_by(x_delta, y_delta)
67
135
  self.point_array = point_array.each_with_index.map {|coordinate, i| i.even? ? coordinate + x_delta : coordinate + y_delta}
68
136
  end
137
+
138
+ def irregular?
139
+ true
140
+ end
141
+
69
142
  end
70
143
  end
71
144
  end
@@ -0,0 +1,104 @@
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 'glimmer/swt/custom/shape'
23
+ require 'glimmer/swt/custom/shape/path_segment'
24
+ require 'glimmer/swt/swt_proxy'
25
+ require 'glimmer/swt/display_proxy'
26
+ require 'glimmer/swt/color_proxy'
27
+ require 'glimmer/swt/font_proxy'
28
+ require 'glimmer/swt/transform_proxy'
29
+
30
+ module Glimmer
31
+ module SWT
32
+ module Custom
33
+ # Represents a shape (graphics) to be drawn on a control/widget/canvas/display
34
+ # That is because Shape is drawn on a parent as graphics and doesn't have an SWT widget for itself
35
+ class Shape
36
+ class Quad < Path
37
+ def parameter_names
38
+ [:point_array]
39
+ end
40
+
41
+ def geometry
42
+ if @point_array != @geometry_point_array
43
+ @geometry_point_array = @point_array
44
+ @geometry = Java::JavaAwtGeom::Path2D::Double.new
45
+ @geometry.send(path_segment_geometry_method_name, *path_segment_geometry_args)
46
+ end
47
+ @geometry
48
+ end
49
+
50
+ def contain?(x, y)
51
+ include?(x, y, filled: true)
52
+ end
53
+
54
+ # checks if drawn or filled rectangle includes the point denoted by x and y (if drawn, it only returns true if point lies on the edge)
55
+ def include?(x, y, filled: nil)
56
+ filled = filled? if filled.nil?
57
+ makeshift_gc = org.eclipse.swt.graphics.GC.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
58
+ swt_path = org.eclipse.swt.graphics.Path.new(Glimmer::SWT::DisplayProxy.instance.swt_display)
59
+ the_path_segment_args = path_segment_args.dup
60
+ if previous_point_connected?
61
+ the_previous_path_segment = previous_path_segment
62
+ swt_path.moveTo(the_previous_path_segment.x, the_previous_path_segment.y)
63
+ else
64
+ swt_path.moveTo(the_path_segment_args.shift, the_path_segment_args.shift)
65
+ end
66
+ swt_path.quadTo(*the_path_segment_args)
67
+ swt_path.contains(x.to_f, y.to_f, makeshift_gc, !filled)
68
+ ensure
69
+ swt_path.dispose
70
+ end
71
+
72
+ def move_by(x_delta, y_delta)
73
+ the_point_array = @args.compact
74
+ the_point_array = the_point_array.first if the_point_array.first.is_a?(Array)
75
+ self.point_array = the_point_array.each_with_index.map {|coordinate, i| i.even? ? coordinate + x_delta : coordinate + y_delta}
76
+ end
77
+
78
+ def path_segment_method_name
79
+ 'quadTo'
80
+ end
81
+
82
+ def path_segment_args
83
+ # TODO make args auto-infer control points if previous_point_connected is true or if there is only a point_array with 1 point
84
+ @args.to_a
85
+ end
86
+
87
+ def previous_point_connected?
88
+ @args.compact.count <= 4 && !first_path_segment?
89
+ end
90
+
91
+ def eql?(other)
92
+ point_array == (other && other.respond_to?(:point_array) && other.point_array)
93
+ end
94
+ alias == eql?
95
+
96
+ def hash
97
+ point_array.hash
98
+ end
99
+
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end