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.
- checksums.yaml +7 -0
- data/.yardopts +12 -0
- data/CREDITS.md +18 -0
- data/INSTALL.md +39 -0
- data/LICENSE +21 -0
- data/README.md +118 -0
- data/assets/screenshot.png +0 -0
- data/bin/wx-shapes +9 -0
- data/lib/wx/shapes/arrow_base.rb +86 -0
- data/lib/wx/shapes/arrows/circle_arrow.rb +39 -0
- data/lib/wx/shapes/arrows/diamond_arrow.rb +33 -0
- data/lib/wx/shapes/arrows/open_arrow.rb +56 -0
- data/lib/wx/shapes/arrows/solid_arrow.rb +69 -0
- data/lib/wx/shapes/art/shape_canvas/page.xpm +73 -0
- data/lib/wx/shapes/auto_layout.rb +358 -0
- data/lib/wx/shapes/base.rb +33 -0
- data/lib/wx/shapes/canvas_history.rb +84 -0
- data/lib/wx/shapes/connection_point.rb +238 -0
- data/lib/wx/shapes/core.rb +19 -0
- data/lib/wx/shapes/diagram.rb +659 -0
- data/lib/wx/shapes/events.rb +389 -0
- data/lib/wx/shapes/printout.rb +136 -0
- data/lib/wx/shapes/serializable.rb +440 -0
- data/lib/wx/shapes/serialize/core.rb +40 -0
- data/lib/wx/shapes/serialize/id.rb +82 -0
- data/lib/wx/shapes/serialize/wx.rb +104 -0
- data/lib/wx/shapes/serializer/json.rb +258 -0
- data/lib/wx/shapes/serializer/yaml.rb +125 -0
- data/lib/wx/shapes/shape.rb +2129 -0
- data/lib/wx/shapes/shape_canvas.rb +3285 -0
- data/lib/wx/shapes/shape_data_object.rb +43 -0
- data/lib/wx/shapes/shape_handle.rb +287 -0
- data/lib/wx/shapes/shape_list.rb +161 -0
- data/lib/wx/shapes/shapes/bitmap_shape.rb +257 -0
- data/lib/wx/shapes/shapes/circle_shape.rb +136 -0
- data/lib/wx/shapes/shapes/control_shape.rb +483 -0
- data/lib/wx/shapes/shapes/curve_shape.rb +231 -0
- data/lib/wx/shapes/shapes/diamond_shape.rb +62 -0
- data/lib/wx/shapes/shapes/edit_text_shape.rb +317 -0
- data/lib/wx/shapes/shapes/ellipse_shape.rb +106 -0
- data/lib/wx/shapes/shapes/flex_grid_shape.rb +78 -0
- data/lib/wx/shapes/shapes/grid_shape.rb +404 -0
- data/lib/wx/shapes/shapes/line_shape.rb +907 -0
- data/lib/wx/shapes/shapes/multi_sel_rect.rb +214 -0
- data/lib/wx/shapes/shapes/ortho_shape.rb +357 -0
- data/lib/wx/shapes/shapes/polygon_shape.rb +294 -0
- data/lib/wx/shapes/shapes/rect_shape.rb +378 -0
- data/lib/wx/shapes/shapes/round_ortho_shape.rb +131 -0
- data/lib/wx/shapes/shapes/round_rect_shape.rb +142 -0
- data/lib/wx/shapes/shapes/square_shape.rb +119 -0
- data/lib/wx/shapes/shapes/text_shape.rb +324 -0
- data/lib/wx/shapes/thumbnail.rb +234 -0
- data/lib/wx/shapes/version.rb +12 -0
- data/lib/wx/shapes/wx.rb +29 -0
- data/lib/wx/shapes.rb +18 -0
- data/lib/wx/wx-shapes/base.rb +87 -0
- data/lib/wx/wx-shapes/cmd/sampler.rb +58 -0
- data/lib/wx/wx-shapes/cmd/test.rb +27 -0
- data/rakelib/yard/templates/default/fulldoc/html/css/wxruby3.css +7 -0
- data/rakelib/yard/templates/default/layout/html/setup.rb +5 -0
- data/rakelib/yard/yard/relative_markdown_links/version.rb +8 -0
- data/rakelib/yard/yard/relative_markdown_links.rb +39 -0
- data/rakelib/yard/yard-custom-templates.rb +2 -0
- data/rakelib/yard/yard-relative_markdown_links.rb +4 -0
- data/samples/demo/art/AlignBottom.xpm +35 -0
- data/samples/demo/art/AlignCenter.xpm +35 -0
- data/samples/demo/art/AlignLeft.xpm +35 -0
- data/samples/demo/art/AlignMiddle.xpm +35 -0
- data/samples/demo/art/AlignRight.xpm +35 -0
- data/samples/demo/art/AlignTop.xpm +35 -0
- data/samples/demo/art/Bitmap.xpm +25 -0
- data/samples/demo/art/Circle.xpm +22 -0
- data/samples/demo/art/Curve.xpm +21 -0
- data/samples/demo/art/Diamond.xpm +22 -0
- data/samples/demo/art/EditText.xpm +21 -0
- data/samples/demo/art/Ellipse.xpm +22 -0
- data/samples/demo/art/FixedRect.xpm +22 -0
- data/samples/demo/art/FlexGrid.xpm +22 -0
- data/samples/demo/art/GC.xpm +23 -0
- data/samples/demo/art/Grid.xpm +22 -0
- data/samples/demo/art/Line.xpm +21 -0
- data/samples/demo/art/NoSource.xpm +69 -0
- data/samples/demo/art/OrthoLine.xpm +21 -0
- data/samples/demo/art/Rect.xpm +22 -0
- data/samples/demo/art/RoundOrthoLine.xpm +21 -0
- data/samples/demo/art/RoundRect.xpm +22 -0
- data/samples/demo/art/Shadow.xpm +23 -0
- data/samples/demo/art/StandAloneLine.xpm +22 -0
- data/samples/demo/art/Text.xpm +21 -0
- data/samples/demo/art/Tool.xpm +23 -0
- data/samples/demo/art/sample.xpm +251 -0
- data/samples/demo/demo.rb +658 -0
- data/samples/demo/frame_canvas.rb +422 -0
- data/samples/demo/images/motyl.bmp +0 -0
- data/samples/demo/images/motyl2.bmp +0 -0
- data/samples/sample1/art/sample.xpm +251 -0
- data/samples/sample1/sample.rb +263 -0
- data/samples/sample2/art/sample.xpm +251 -0
- data/samples/sample2/sample.rb +133 -0
- data/samples/sample2/sample_canvas.rb +35 -0
- data/samples/sample2/sample_shape.rb +108 -0
- data/samples/sample3/art/sample.xpm +251 -0
- data/samples/sample3/sample.rb +281 -0
- data/samples/sample4/art/sample.xpm +251 -0
- data/samples/sample4/sample.rb +180 -0
- data/tests/art/motyl.bmp +0 -0
- data/tests/lib/wxapp_runner.rb +64 -0
- data/tests/serializer_tests.rb +521 -0
- data/tests/test_grid_shapes.rb +42 -0
- data/tests/test_serialize.rb +7 -0
- data/tests/test_serialize_yaml.rb +17 -0
- 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
|