wxruby3-shapes 0.9.0.pre.beta.3

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 (112) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +12 -0
  3. data/CREDITS.md +18 -0
  4. data/INSTALL.md +39 -0
  5. data/LICENSE +21 -0
  6. data/README.md +118 -0
  7. data/assets/screenshot.png +0 -0
  8. data/bin/wx-shapes +9 -0
  9. data/lib/wx/shapes/arrow_base.rb +86 -0
  10. data/lib/wx/shapes/arrows/circle_arrow.rb +39 -0
  11. data/lib/wx/shapes/arrows/diamond_arrow.rb +33 -0
  12. data/lib/wx/shapes/arrows/open_arrow.rb +56 -0
  13. data/lib/wx/shapes/arrows/solid_arrow.rb +69 -0
  14. data/lib/wx/shapes/art/shape_canvas/page.xpm +73 -0
  15. data/lib/wx/shapes/auto_layout.rb +358 -0
  16. data/lib/wx/shapes/base.rb +33 -0
  17. data/lib/wx/shapes/canvas_history.rb +84 -0
  18. data/lib/wx/shapes/connection_point.rb +238 -0
  19. data/lib/wx/shapes/core.rb +19 -0
  20. data/lib/wx/shapes/diagram.rb +659 -0
  21. data/lib/wx/shapes/events.rb +389 -0
  22. data/lib/wx/shapes/printout.rb +136 -0
  23. data/lib/wx/shapes/serializable.rb +440 -0
  24. data/lib/wx/shapes/serialize/core.rb +40 -0
  25. data/lib/wx/shapes/serialize/id.rb +82 -0
  26. data/lib/wx/shapes/serialize/wx.rb +104 -0
  27. data/lib/wx/shapes/serializer/json.rb +258 -0
  28. data/lib/wx/shapes/serializer/yaml.rb +125 -0
  29. data/lib/wx/shapes/shape.rb +2129 -0
  30. data/lib/wx/shapes/shape_canvas.rb +3285 -0
  31. data/lib/wx/shapes/shape_data_object.rb +43 -0
  32. data/lib/wx/shapes/shape_handle.rb +287 -0
  33. data/lib/wx/shapes/shape_list.rb +161 -0
  34. data/lib/wx/shapes/shapes/bitmap_shape.rb +257 -0
  35. data/lib/wx/shapes/shapes/circle_shape.rb +136 -0
  36. data/lib/wx/shapes/shapes/control_shape.rb +483 -0
  37. data/lib/wx/shapes/shapes/curve_shape.rb +231 -0
  38. data/lib/wx/shapes/shapes/diamond_shape.rb +62 -0
  39. data/lib/wx/shapes/shapes/edit_text_shape.rb +317 -0
  40. data/lib/wx/shapes/shapes/ellipse_shape.rb +106 -0
  41. data/lib/wx/shapes/shapes/flex_grid_shape.rb +78 -0
  42. data/lib/wx/shapes/shapes/grid_shape.rb +404 -0
  43. data/lib/wx/shapes/shapes/line_shape.rb +907 -0
  44. data/lib/wx/shapes/shapes/multi_sel_rect.rb +214 -0
  45. data/lib/wx/shapes/shapes/ortho_shape.rb +357 -0
  46. data/lib/wx/shapes/shapes/polygon_shape.rb +294 -0
  47. data/lib/wx/shapes/shapes/rect_shape.rb +378 -0
  48. data/lib/wx/shapes/shapes/round_ortho_shape.rb +131 -0
  49. data/lib/wx/shapes/shapes/round_rect_shape.rb +142 -0
  50. data/lib/wx/shapes/shapes/square_shape.rb +119 -0
  51. data/lib/wx/shapes/shapes/text_shape.rb +324 -0
  52. data/lib/wx/shapes/thumbnail.rb +234 -0
  53. data/lib/wx/shapes/version.rb +12 -0
  54. data/lib/wx/shapes/wx.rb +29 -0
  55. data/lib/wx/shapes.rb +18 -0
  56. data/lib/wx/wx-shapes/base.rb +87 -0
  57. data/lib/wx/wx-shapes/cmd/sampler.rb +58 -0
  58. data/lib/wx/wx-shapes/cmd/test.rb +27 -0
  59. data/rakelib/yard/templates/default/fulldoc/html/css/wxruby3.css +7 -0
  60. data/rakelib/yard/templates/default/layout/html/setup.rb +5 -0
  61. data/rakelib/yard/yard/relative_markdown_links/version.rb +8 -0
  62. data/rakelib/yard/yard/relative_markdown_links.rb +39 -0
  63. data/rakelib/yard/yard-custom-templates.rb +2 -0
  64. data/rakelib/yard/yard-relative_markdown_links.rb +4 -0
  65. data/samples/demo/art/AlignBottom.xpm +35 -0
  66. data/samples/demo/art/AlignCenter.xpm +35 -0
  67. data/samples/demo/art/AlignLeft.xpm +35 -0
  68. data/samples/demo/art/AlignMiddle.xpm +35 -0
  69. data/samples/demo/art/AlignRight.xpm +35 -0
  70. data/samples/demo/art/AlignTop.xpm +35 -0
  71. data/samples/demo/art/Bitmap.xpm +25 -0
  72. data/samples/demo/art/Circle.xpm +22 -0
  73. data/samples/demo/art/Curve.xpm +21 -0
  74. data/samples/demo/art/Diamond.xpm +22 -0
  75. data/samples/demo/art/EditText.xpm +21 -0
  76. data/samples/demo/art/Ellipse.xpm +22 -0
  77. data/samples/demo/art/FixedRect.xpm +22 -0
  78. data/samples/demo/art/FlexGrid.xpm +22 -0
  79. data/samples/demo/art/GC.xpm +23 -0
  80. data/samples/demo/art/Grid.xpm +22 -0
  81. data/samples/demo/art/Line.xpm +21 -0
  82. data/samples/demo/art/NoSource.xpm +69 -0
  83. data/samples/demo/art/OrthoLine.xpm +21 -0
  84. data/samples/demo/art/Rect.xpm +22 -0
  85. data/samples/demo/art/RoundOrthoLine.xpm +21 -0
  86. data/samples/demo/art/RoundRect.xpm +22 -0
  87. data/samples/demo/art/Shadow.xpm +23 -0
  88. data/samples/demo/art/StandAloneLine.xpm +22 -0
  89. data/samples/demo/art/Text.xpm +21 -0
  90. data/samples/demo/art/Tool.xpm +23 -0
  91. data/samples/demo/art/sample.xpm +251 -0
  92. data/samples/demo/demo.rb +658 -0
  93. data/samples/demo/frame_canvas.rb +422 -0
  94. data/samples/demo/images/motyl.bmp +0 -0
  95. data/samples/demo/images/motyl2.bmp +0 -0
  96. data/samples/sample1/art/sample.xpm +251 -0
  97. data/samples/sample1/sample.rb +263 -0
  98. data/samples/sample2/art/sample.xpm +251 -0
  99. data/samples/sample2/sample.rb +133 -0
  100. data/samples/sample2/sample_canvas.rb +35 -0
  101. data/samples/sample2/sample_shape.rb +108 -0
  102. data/samples/sample3/art/sample.xpm +251 -0
  103. data/samples/sample3/sample.rb +281 -0
  104. data/samples/sample4/art/sample.xpm +251 -0
  105. data/samples/sample4/sample.rb +180 -0
  106. data/tests/art/motyl.bmp +0 -0
  107. data/tests/lib/wxapp_runner.rb +64 -0
  108. data/tests/serializer_tests.rb +521 -0
  109. data/tests/test_grid_shapes.rb +42 -0
  110. data/tests/test_serialize.rb +7 -0
  111. data/tests/test_serialize_yaml.rb +17 -0
  112. metadata +242 -0
@@ -0,0 +1,43 @@
1
+ # Wx::SF::ShapeDataObject - shape data object class
2
+ # Copyright (c) M.J.N. Corino, The Netherlands
3
+
4
+ module Wx::SF
5
+
6
+ # Class encapsulating data object used during clipboard operations with shapes.
7
+ class ShapeDataObject < Wx::DataObjectSimpleBase
8
+
9
+ DataFormatID = 'ShapeFrameWorkDataFormat1_0'
10
+
11
+ # @overload initialize()
12
+ # Default constructor
13
+ # @overload initialize(selection)
14
+ # User constructor
15
+ # @param [Array<Wx::SF::Shape>] selection List of shapes which should be stored in the data object
16
+ def initialize(selection = nil)
17
+ super(Wx::DataFormat.new(DataFormatID))
18
+ @data = selection ? selection.serialize : ''
19
+ end
20
+
21
+ # Returns size of the data object
22
+ # @return [Integer]
23
+ def _get_data_size
24
+ @data.bytesize
25
+ end
26
+
27
+ # Exports data from data object.
28
+ # @return [Boolean] true on success, otherwise false
29
+ def _get_data
30
+ @data
31
+ end
32
+
33
+ # Function should inport data from data object from given buffer.
34
+ # @param [String] buf External input data buffer
35
+ # @return [Boolean] true on success, otherwise false
36
+ def _set_data(buf)
37
+ @data = buf ? buf : ''
38
+ true
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,287 @@
1
+ # Wx::SF::Shape::Handle - shape handle class
2
+ # Copyright (c) M.J.N. Corino, The Netherlands
3
+
4
+ module Wx::SF
5
+
6
+ class Shape
7
+
8
+ # Class encapsulates shape's handle. The class shouldn't be used separately; see
9
+ # Wx::Shape class for more detailed information about functions used for managing of shape
10
+ # handles and handling their events
11
+ class Handle
12
+
13
+ # Handle type
14
+ class TYPE < Wx::Enum
15
+ LEFTTOP = self.new(0)
16
+ TOP = self.new(1)
17
+ RIGHTTOP = self.new(2)
18
+ RIGHT = self.new(3)
19
+ RIGHTBOTTOM = self.new(4)
20
+ BOTTOM = self.new(5)
21
+ LEFTBOTTOM = self.new(6)
22
+ LEFT = self.new(7)
23
+ LINECTRL = self.new(8)
24
+ LINESTART = self.new(9)
25
+ LINEEND = self.new(10)
26
+ UNDEF = self.new(11)
27
+ end
28
+
29
+ # Constructor
30
+ # @param [Wx::Shape] parent Parent shape
31
+ # @param [TYPE] type Handle type
32
+ # @param [Integer] id Handle ID (useful only for line controls handles)
33
+ def initialize(parent=nil, type=TYPE::UNDEF, id=-1)
34
+ @parent_shape = parent
35
+ @type = type
36
+ @id = id
37
+ @start_pos = Wx::Point.new
38
+ @prev_pos = Wx::Point.new
39
+ @curr_pos = Wx::Point.new
40
+
41
+ @visible = false
42
+ @mouse_over = false
43
+ end
44
+
45
+ # Set or get handle's ID.
46
+ attr_accessor :id
47
+
48
+ # Get Handle type
49
+ # @return [TYPE] Handle type
50
+ def get_type
51
+ @type
52
+ end
53
+ alias :type :get_type
54
+
55
+ # Set Handle type
56
+ # @param [TYPE] type Handle type to set
57
+ def set_type(type)
58
+ @type = type
59
+ end
60
+ alias :type= :set_type
61
+
62
+ # Get parent shape.
63
+ # @return [Wx::Shape] parent shape
64
+ def get_parent_shape
65
+ @parent_shape
66
+ end
67
+ alias :parent_shape :get_parent_shape
68
+
69
+ # Get current handle position.
70
+ # @return [Wx::Point] Handle position
71
+ def get_position
72
+ @curr_pos
73
+ end
74
+ alias :position :get_position
75
+
76
+ # Get current handle delta (difference between current and previous position).
77
+ # @return [Wx::Point] Handle delta
78
+ def get_delta
79
+ @curr_pos - @prev_pos
80
+ end
81
+ alias :delta :get_delta
82
+
83
+ # Get current total handle delta (difference between current and starting position
84
+ # stored at the beginning of the dragging process).
85
+ # @return [Wx::Point] Total handle delta
86
+ def get_total_delta
87
+ @curr_pos - @start_pos
88
+ end
89
+ alias :total_delta :get_total_delta
90
+
91
+ # Show/hide handle
92
+ # @param [Boolean] show true if the handle should be visible (active), otherwise false
93
+ def show(show = true)
94
+ @visible = !!show
95
+ end
96
+
97
+ # Returns true if the handle is visible, otherwise false
98
+ def visible?
99
+ @visible
100
+ end
101
+
102
+ # Refresh (repaint) the handle
103
+ # @return [void]
104
+ def refresh
105
+ @parent_shape.refresh(DELAYED) if @parent_shape
106
+ end
107
+
108
+ # Find out whether given point is inside the handle.
109
+ # @param [Wx::Point,Array(Integer,Integer)] pos Examined point
110
+ # @return [Boolean] true if the point is inside the handle, otherwise false
111
+ def contains(pos)
112
+ handle_rect.contains?(pos)
113
+ end
114
+ alias contains? :contains
115
+
116
+ protected
117
+
118
+ # Draw handle.
119
+ # @param [Wx::DC] dc Device context where the handle will be drawn
120
+ def draw(dc)
121
+ if @visible && @parent_shape
122
+ if @mouse_over
123
+ draw_hover(dc)
124
+ else
125
+ draw_normal(dc)
126
+ end
127
+ end
128
+ end
129
+
130
+ # Draw handle in the normal way.
131
+ # @param [Wx::DC] dc Device context where the handle will be drawn
132
+ def draw_normal(dc)
133
+ dc.with_pen(Wx::PLATFORM == 'WXGTK' ? Wx::TRANSPARENT_PEN : Wx::BLACK_PEN) do
134
+ if ShapeCanvas::gc_enabled?
135
+ dc.brush = Wx::Brush.new(Wx::Colour.new(0, 0, 0, 128))
136
+ else
137
+ dc.brush = Wx::BLACK_BRUSH
138
+ # dc.logical_function = Wx::RasterOperationMode::INVERT
139
+ end
140
+
141
+ dc.draw_rectangle(handle_rect)
142
+ # dc.logical_function = Wx::RasterOperationMode::COPY
143
+
144
+ dc.brush = Wx::NULL_BRUSH
145
+ end
146
+ end
147
+
148
+ # Draw handle in the "hover" way (the mouse pointer is above the handle area).
149
+ # @param [Wx::DC] dc Device context where the handle will be drawn
150
+ def draw_hover(dc)
151
+ if @parent_shape.contains_style(Shape::STYLE::SIZE_CHANGE)
152
+ dc.with_pen(Wx::BLACK_PEN) do
153
+ dc.with_brush(Wx::Brush.new(@parent_shape.hover_colour)) do
154
+ dc.draw_rectangle(handle_rect)
155
+ end
156
+ end
157
+ else
158
+ draw_normal(dc)
159
+ end
160
+ end
161
+
162
+ # Set parent shape.
163
+ # @param [Wx::Shape] parent parent shape to set
164
+ def parent_shape=(parent)
165
+ @parent_shape = parent
166
+ end
167
+
168
+ # Get handle rectangle.
169
+ # @return [Wx::Rect] Handle rectangle
170
+ def handle_rect
171
+ if @parent_shape
172
+ brct = @parent_shape.get_bounding_box
173
+ case @type
174
+ when TYPE::LEFTTOP
175
+ hrct = Wx::Rect.new(brct.top_left, Wx::Size.new(7,7))
176
+ when TYPE::TOP
177
+ hrct = Wx::Rect.new(Wx::Point.new(brct.left + brct.width/2, brct.top), Wx::Size.new(7,7))
178
+ when TYPE::RIGHTTOP
179
+ hrct = Wx::Rect.new(brct.top_right, Wx::Size.new(7,7))
180
+ when TYPE::RIGHT
181
+ hrct = Wx::Rect.new(Wx::Point.new(brct.right, brct.top + brct.height/2), Wx::Size.new(7,7))
182
+ when TYPE::RIGHTBOTTOM
183
+ hrct = Wx::Rect.new(brct.bottom_right, Wx::Size.new(7,7))
184
+ when TYPE::BOTTOM
185
+ hrct = Wx::Rect.new(Wx::Point.new(brct.left + brct.width/2, brct.bottom), Wx::Size.new(7,7))
186
+ when TYPE::LEFTBOTTOM
187
+ hrct = Wx::Rect.new(brct.bottom_left, Wx::Size.new(7,7))
188
+ when TYPE::LEFT
189
+ hrct = Wx::Rect.new(Wx::Point.new(brct.left, brct.top + brct.height/2), Wx::Size.new(7,7))
190
+ when TYPE::LINECTRL
191
+ pt = @parent_shape.get_control_points[@id]
192
+ hrct = Wx::Rect.new(Wx::Point.new(pt.x.to_i, pt.y.to_i), Wx::Size.new(7,7))
193
+ when TYPE::LINEEND, TYPE::LINESTART
194
+ pt = @type == TYPE::LINESTART ? @parent_shape.src_point : @parent_shape.trg_point
195
+ hrct = Wx::Rect.new(Wx::Point.new(pt.x.to_i, pt.y.to_i), Wx::Size.new(7,7))
196
+ else
197
+ hrct = Wx::Rect.new
198
+ end
199
+
200
+ hrct.offset!(-3, -3)
201
+ else
202
+ Wx::Rect.new
203
+ end
204
+ end
205
+
206
+ private
207
+
208
+ # Event handler called when the mouse pointer is moving above shape canvas.
209
+ # @param [Wx::Point] pos Current mouse position
210
+ def _on_mouse_move(pos)
211
+ if @visible
212
+ if contains?(pos)
213
+ unless @mouse_over
214
+ @mouse_over = true
215
+ refresh
216
+ end
217
+ else
218
+ if @mouse_over
219
+ @mouse_over = false
220
+ refresh
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ # Event handler called when the handle is started to be dragged.
227
+ # @param [Wx::Point] pos Current mouse position
228
+ def _on_begin_drag(pos)
229
+ @prev_pos = @start_pos = @curr_pos = pos
230
+ @parent_shape.on_begin_handle(self) if @parent_shape
231
+ end
232
+
233
+ # Event handler called when the handle is dragged.
234
+ # @param [Wx::Point] pos Current mouse position
235
+ def _on_dragging(pos)
236
+ if @visible && @parent_shape && @parent_shape.contains_style(Shape::STYLE::SIZE_CHANGE)
237
+ if pos != @prev_pos
238
+ prev_rct = @parent_shape.get_bounding_box
239
+
240
+ @curr_pos = pos
241
+
242
+ case @type
243
+ when TYPE::LEFTTOP
244
+ @parent_shape.send(:_on_handle, self) if (pos.x < prev_rct.right) && (pos.y < prev_rct.bottom)
245
+
246
+ when TYPE::TOP
247
+ @parent_shape.send(:_on_handle, self) if (pos.y < prev_rct.bottom)
248
+
249
+ when TYPE::RIGHTTOP
250
+ @parent_shape.send(:_on_handle, self) if ((pos.x > prev_rct.left) && (pos.y < prev_rct.bottom))
251
+
252
+ when TYPE::RIGHT
253
+ @parent_shape.send(:_on_handle, self) if (pos.x > prev_rct.left)
254
+
255
+ when TYPE::RIGHTBOTTOM
256
+ @parent_shape.send(:_on_handle, self) if ((pos.x > prev_rct.left) && (pos.y > prev_rct.top))
257
+
258
+ when TYPE::BOTTOM
259
+ @parent_shape.send(:_on_handle, self) if (pos.y > prev_rct.top)
260
+
261
+ when TYPE::LEFTBOTTOM
262
+ @parent_shape.send(:_on_handle, self) if ((pos.x < prev_rct.right) && (pos.y > prev_rct.top))
263
+
264
+ when TYPE::LEFT
265
+ @parent_shape.send(:_on_handle, self) if (pos.x < prev_rct.right)
266
+
267
+ when TYPE::LINESTART, TYPE::LINEEND, TYPE::LINECTRL
268
+ @parent_shape.send(:_on_handle, self)
269
+
270
+ end
271
+ end
272
+
273
+ @prev_pos = pos
274
+ end
275
+ end
276
+
277
+ # Event handler called when the handle is released.
278
+ # @param [Wx::Point] _pos Current mouse position
279
+ def _on_end_drag(_pos)
280
+ @parent_shape.on_end_handle(self) if @parent_shape
281
+ end
282
+
283
+ end
284
+
285
+ end
286
+
287
+ end
@@ -0,0 +1,161 @@
1
+ # Wx::SF::Shape - shape list class
2
+ # Copyright (c) M.J.N. Corino, The Netherlands
3
+
4
+ require 'wx/shapes/serializable'
5
+
6
+ module Wx::SF
7
+
8
+ # This class implements an indexed container for unique, non-nil, shapes (no duplicates).
9
+ class ShapeList
10
+
11
+ include Serializable
12
+ include ::Enumerable
13
+
14
+ property :list
15
+
16
+ # Constructor.
17
+ # @param [ShapeList,::Enumerable,Shape,nil] enum shape container to copy, single shape to add or nil
18
+ def initialize(enum = nil)
19
+ if enum
20
+ if enum.is_a?(ShapeList)
21
+ @list = enum.instance_variable_get('@list').dup
22
+ @index = enum.instance_variable_get('@index').dup
23
+ elsif enum.is_a?(::Enumerable)
24
+ @list = []
25
+ @index = {}
26
+ enum.each { |elem| self << elem }
27
+ else
28
+ @list = []
29
+ @index = {}
30
+ self << enum
31
+ end
32
+ else
33
+ @list = []
34
+ @index = {}
35
+ end
36
+ end
37
+
38
+ # Iterates over contained shapes.
39
+ # When a block given, passes each successive shape to the block.
40
+ # Allows the array to be modified during iteration.
41
+ # When no block given, returns a new ::Enumerator.
42
+ # @yieldparam [Shape] shape
43
+ # @return [self]
44
+ def each(&block)
45
+ @list.each(&block)
46
+ self
47
+ end
48
+
49
+ # Recursively collects shapes and returns collection.
50
+ # @param [Array<Shape>] collection container to return collected shapes in
51
+ def all(collection = [])
52
+ @list.inject(collection) { |list, shape| shape.instance_variable_get('@child_shapes').all(list << shape) }
53
+ end
54
+
55
+ # Returns true if the no shapes are contained, false otherwise.
56
+ # @return [Boolean]
57
+ def empty?
58
+ @list.empty?
59
+ end
60
+
61
+ # Empties the shape list.
62
+ # @return [self]
63
+ def clear
64
+ @list.clear
65
+ @index.clear
66
+ self
67
+ end
68
+
69
+ # Appends a new shape to the list if not yet in list.
70
+ # @param [Shape] shape shape to add
71
+ # @return [self]
72
+ def append(shape)
73
+ unless @index.has_key?(check_elem(shape).id)
74
+ @list << shape
75
+ @index[shape.id] = shape
76
+ end
77
+ self
78
+ end
79
+ alias :push :append
80
+ alias :<< :append
81
+
82
+ # Removes the first shape from the list (if any) and returns that.
83
+ # @return [Shape,nil] removed shape or nil if list empty
84
+ def shift
85
+ return nil if @list.empty?
86
+ @index.delete(@list.shift.id)
87
+ end
88
+
89
+ # Removes the last shape from the list (if any) and returns that.
90
+ # @return [Shape,nil] removed shape or nil if list empty
91
+ def pop
92
+ return nil if @list.empty?
93
+ @index.delete(@list.pop.id)
94
+ end
95
+
96
+ # Removes a shape matching the key given from the list and returns that.
97
+ # @param [Shape,Serializable::ID] key shape or shape ID to match
98
+ # @return [Shape,nil] removed shape or nil if none matched
99
+ def delete(key)
100
+ if key.is_a?(Shape)
101
+ return @list.delete(key) if @index.delete(key.id)
102
+ elsif key.is_a?(Serializable::ID)
103
+ return @list.delete(@index.delete(key)) if @index.has_key?(key)
104
+ end
105
+ nil
106
+ end
107
+
108
+ # Returns true if a shape matches the given key or false if no shape matches.
109
+ # @param [Shape,Serializable::ID] key shape or shape ID to match
110
+ # @param [Boolean] recursive pass true to search recursively, false for non-recursive
111
+ # @return [Boolean]
112
+ def include?(key, recursive = false)
113
+ found = if key.is_a?(Serializable::ID)
114
+ @index.has_key?(key)
115
+ else
116
+ @list.include?(key)
117
+ end
118
+ found || (recursive && @list.any? { |child| child.instance_variable_get('@child_shapes').include?(key, recursive) })
119
+ end
120
+
121
+ # Returns the shape matching the given key or nil if no shape matches.
122
+ # Does not modify the list.
123
+ # @param [Integer,Serializable::ID] key shape list index or shape ID to match
124
+ # @param [Boolean] recursive pass true to search recursively, false for non-recursive
125
+ # @return [Shape,nil] matched shape or nil if none matched
126
+ def get(key, recursive = false)
127
+ shape = if key.is_a?(Serializable::ID)
128
+ @index[key]
129
+ else
130
+ @list.at(key.to_i)
131
+ end
132
+ shape || (recursive && @list.find { |child| child.get(key, recursive) })
133
+ end
134
+ alias :[] :get
135
+
136
+ private
137
+
138
+ # Get shape array. Serialization only.
139
+ # @return [Array<Shape>]
140
+ def get_list
141
+ @list
142
+ end
143
+
144
+ # Set shape array from deserialization.
145
+ # @param [Array<Shape>] list
146
+ def set_list(list)
147
+ @list = list
148
+ @list.each { |shape| @index[shape.id] = shape }
149
+ end
150
+
151
+ # Check intended list item
152
+ # @param [Shape] shape intended list item
153
+ # @return [Shape] checked shape
154
+ def check_elem(shape)
155
+ ::Kernel.raise TypeError, 'Expected a Wx::SF::Shape' unless shape.is_a?(Wx::SF::Shape)
156
+ shape
157
+ end
158
+
159
+ end
160
+
161
+ end