wxruby3-shapes 0.9.0.pre.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,2129 @@
|
|
1
|
+
# Wx::SF::Shape - base shape class
|
2
|
+
# Copyright (c) M.J.N. Corino, The Netherlands
|
3
|
+
|
4
|
+
require 'wx/shapes/serializable'
|
5
|
+
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
module Wx::SF
|
9
|
+
|
10
|
+
class ERRCODE < Wx::Enum
|
11
|
+
OK = self.new(0)
|
12
|
+
NOT_CREATED = self.new(1)
|
13
|
+
NOT_ACCEPTED = self.new(2)
|
14
|
+
INVALID_INPUT = self.new(3)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Base class for all shapes providing fundamental functionality and publishing set
|
18
|
+
# of virtual functions which must be defined by the user in derived shapes. This class
|
19
|
+
# shouldn't be used as it is.
|
20
|
+
#
|
21
|
+
# Shape objects derived from this class use hierarchical approach. It means that every
|
22
|
+
# shape must have defined parent shape (can be NULL for topmost shapes). An absolute
|
23
|
+
# shape position is then calculated as a summation of all relative positions of all parent
|
24
|
+
# shapes. Also the size of the parent shape can be limited be a bounding box of all
|
25
|
+
# children shapes.
|
26
|
+
#
|
27
|
+
# This class also declares set of virtual functions used as event handlers for various
|
28
|
+
# events (moving, sizing, drawing, mouse events, serialization and deserialization requests, ...)
|
29
|
+
# mostly triggered by a parent shape canvas.
|
30
|
+
class Shape
|
31
|
+
|
32
|
+
include Serializable
|
33
|
+
|
34
|
+
property :id, :active, :visibility, :style,
|
35
|
+
:accepted_children, :accepted_connections,
|
36
|
+
:accepted_src_neighbours, :accepted_trg_neighbours,
|
37
|
+
:hover_colour, :relative_position,
|
38
|
+
:h_align, :v_align, :h_border, :v_border,
|
39
|
+
:custom_dock_point, :connection_points,
|
40
|
+
:user_data
|
41
|
+
property child_shapes: :serialize_child_shapes
|
42
|
+
|
43
|
+
class SEARCHMODE < Wx::Enum
|
44
|
+
# Depth-First-Search algorithm
|
45
|
+
DFS = self.new(0)
|
46
|
+
# Breadth-First-Search algorithm
|
47
|
+
BFS = self.new(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Bit flags for Wx::SF::Shape get_complete_bounding_box function
|
51
|
+
class BBMODE < Wx::Enum
|
52
|
+
SELF = self.new(1)
|
53
|
+
CHILDREN = self.new(2)
|
54
|
+
CONNECTIONS = self.new(4)
|
55
|
+
SHADOW = self.new(8)
|
56
|
+
ALL = self.new(15)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Search mode flags for get_assigned_connections function
|
60
|
+
class CONNECTMODE < Wx::Enum
|
61
|
+
# Search for connection starting in examined shape
|
62
|
+
STARTING = self.new(0)
|
63
|
+
# Search for connection ending in examined shape
|
64
|
+
ENDING = self.new(1)
|
65
|
+
# Search for both starting and ending connections
|
66
|
+
BOTH = self.new(2)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Flags for set_v_align function
|
70
|
+
class VALIGN < Wx::Enum
|
71
|
+
NONE = self.new(0)
|
72
|
+
TOP = self.new(1)
|
73
|
+
MIDDLE = self.new(2)
|
74
|
+
BOTTOM = self.new(3)
|
75
|
+
EXPAND = self.new(4)
|
76
|
+
LINE_START = self.new(5)
|
77
|
+
LINE_END = self.new(6)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Flags for set_h_align function
|
81
|
+
class HALIGN < Wx::Enum
|
82
|
+
NONE = self.new(0)
|
83
|
+
LEFT = self.new(1)
|
84
|
+
CENTER = self.new(2)
|
85
|
+
RIGHT = self.new(3)
|
86
|
+
EXPAND = self.new(4)
|
87
|
+
LINE_START = self.new(5)
|
88
|
+
LINE_END = self.new(6)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Basic shape's styles used with set_style function
|
92
|
+
class STYLE < Wx::Enum
|
93
|
+
# Interactive parent change is allowed
|
94
|
+
PARENT_CHANGE = self.new(1)
|
95
|
+
# Interactive position change is allowed
|
96
|
+
POSITION_CHANGE = self.new(2)
|
97
|
+
# Interactive size change is allowed
|
98
|
+
SIZE_CHANGE = self.new(4)
|
99
|
+
# Shape is highlighted at mouse hovering
|
100
|
+
HOVERING = self.new(8)
|
101
|
+
# Shape is highlighted at shape dragging
|
102
|
+
HIGHLIGHTING = self.new(16)
|
103
|
+
# Shape is always inside its parent
|
104
|
+
ALWAYS_INSIDE = self.new(32)
|
105
|
+
# User data is destroyed at the shape deletion
|
106
|
+
DELETE_USER_DATA = self.new(64)
|
107
|
+
# The DEL key is processed by the shape (not by the shape canvas)
|
108
|
+
PROCESS_DEL = self.new(128)
|
109
|
+
# Show handles if the shape is selected
|
110
|
+
SHOW_HANDLES = self.new(256)
|
111
|
+
# Show shadow under the shape
|
112
|
+
SHOW_SHADOW = self.new(512)
|
113
|
+
# Lock children relative position if the parent is resized
|
114
|
+
LOCK_CHILDREN = self.new(1024)
|
115
|
+
# Emit events (catchable in shape canvas)
|
116
|
+
EMIT_EVENTS = self.new(2048)
|
117
|
+
# Propagate mouse dragging event to parent shape
|
118
|
+
PROPAGATE_DRAGGING = self.new(4096)
|
119
|
+
# Propagate selection to parent shape (it means this shape cannot be selected because its focus is redirected to its parent shape)
|
120
|
+
PROPAGATE_SELECTION = self.new(8192)
|
121
|
+
# Propagate interactive connection request to parent shape (it means this shape cannot be connected interactively because this feature is redirected to its parent shape)
|
122
|
+
PROPAGATE_INTERACTIVE_CONNECTION = self.new(16384)
|
123
|
+
# Do no resize the shape to fit its children automatically
|
124
|
+
NO_FIT_TO_CHILDREN = self.new(32768)
|
125
|
+
# Propagate hovering to parent.
|
126
|
+
PROPAGATE_HOVERING = self.new(65536)
|
127
|
+
# Propagate hovering to parent.
|
128
|
+
PROPAGATE_HIGHLIGHTING = self.new(131072)
|
129
|
+
# Default shape style
|
130
|
+
DEFAULT_SHAPE_STYLE = PARENT_CHANGE | POSITION_CHANGE | SIZE_CHANGE | HOVERING | HIGHLIGHTING | SHOW_HANDLES | ALWAYS_INSIDE | DELETE_USER_DATA
|
131
|
+
end
|
132
|
+
|
133
|
+
# Default values
|
134
|
+
module DEFAULT
|
135
|
+
# Default value of Wx::SF::Shape @visible data member
|
136
|
+
VISIBILITY = true
|
137
|
+
# Default value of Wx::SF::Shape @active data member
|
138
|
+
ACTIVITY = true
|
139
|
+
# Default value of Wx::SF::Shape @hoverColor data member
|
140
|
+
HOVERCOLOUR = Wx::Colour.new(120, 120, 255) if Wx::App.is_main_loop_running
|
141
|
+
Wx.add_delayed_constant(self, :HOVERCOLOUR) { Wx::Colour.new(120, 120, 255) }
|
142
|
+
# Default value of Wx::SF::Shape @relativePosition data member
|
143
|
+
POSITION = Wx::RealPoint.new(0, 0)
|
144
|
+
# Default value of Wx::SF::Shape @vAlign data member
|
145
|
+
VALIGN = VALIGN::NONE
|
146
|
+
# Default value of Wx::SF::Shape @hAlign data member
|
147
|
+
HALIGN = HALIGN::NONE
|
148
|
+
# Default value of Wx::SF::Shape @vBorder data member
|
149
|
+
VBORDER = 0.0
|
150
|
+
# Default value of Wx::SF::Shape @hBorder data member
|
151
|
+
HBORDER = 0.0
|
152
|
+
# Default value of Wx::SF::Shape @style data member
|
153
|
+
DEFAULT_STYLE = STYLE::DEFAULT_SHAPE_STYLE
|
154
|
+
# Default value of Wx::SF::Shape @customDockPoint data member
|
155
|
+
DOCK_POINT = -3
|
156
|
+
end
|
157
|
+
|
158
|
+
# Provide Shape and derivatives with component set container
|
159
|
+
class << self
|
160
|
+
def component_shapes
|
161
|
+
@component_shapes ||= ::Set.new
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Declare a component shape property for the shape class.
|
166
|
+
# @overload component(*comp_id)
|
167
|
+
# Specifies one or more serialized component properties.
|
168
|
+
# The serialization framework will determine the availability of setter and getter methods
|
169
|
+
# automatically by looking for methods <code>"#{comp_id}=(v)"</code>, <code>"set_#{comp_id}(v)"</code> or <code>"#{comp_id}(v)"</code>
|
170
|
+
# for setters and <code>"#{comp_id}()"</code> or <code>"get_#{comp_id}"</code> for getters.
|
171
|
+
# @param [String,Symbol] comp_id id of component property
|
172
|
+
# @overload component(hash)
|
173
|
+
# Specifies one or more serialized component properties with associated setter/getter method ids/procs/lambda-s.
|
174
|
+
# @example
|
175
|
+
# property(
|
176
|
+
# prop_a: ->(obj, *val) {
|
177
|
+
# obj.my_prop_a_setter(val.first) unless val.empty?
|
178
|
+
# obj.my_prop_a_getter
|
179
|
+
# },
|
180
|
+
# prop_b: Proc.new { |obj, *val|
|
181
|
+
# obj.my_prop_b_setter(val.first) unless val.empty?
|
182
|
+
# obj.my_prop_b_getter
|
183
|
+
# },
|
184
|
+
# prop_c: :serialization_method)
|
185
|
+
# Procs with setter support MUST accept 1 or 2 arguments (1 for getter, 2 for setter).
|
186
|
+
# @note Use `*val` to specify the optional value argument for setter requests instead of `val=nil`
|
187
|
+
# to be able to support setting explicit nil values.
|
188
|
+
# @param [Hash] hash a hash of pairs of property ids and getter/setter procs
|
189
|
+
def self.component(*args)
|
190
|
+
args.flatten.each do |arg|
|
191
|
+
if arg.is_a?(::Hash)
|
192
|
+
arg.each_pair do |pn, pp|
|
193
|
+
# define serialized property for component (checks for duplicates)
|
194
|
+
property({pn => pp}, force: true)
|
195
|
+
# get the property definition and register as component
|
196
|
+
component_shapes << self.serializer_properties.last
|
197
|
+
end
|
198
|
+
else
|
199
|
+
# define serialized property for component (checks for duplicates)
|
200
|
+
property(arg, force: true)
|
201
|
+
# get the property definition and register as component
|
202
|
+
component_shapes << self.serializer_properties.last
|
203
|
+
end
|
204
|
+
end
|
205
|
+
# check if the current class already has the appropriate support
|
206
|
+
unless self.const_defined?(:ComponentSerializerMethods)
|
207
|
+
class << self
|
208
|
+
def disable_component_serialize(obj)
|
209
|
+
component_shapes.each { |pd| pd.get(obj).disable_serialize }
|
210
|
+
superclass.disable_component_serialize(obj) if superclass.respond_to?(:disable_component_serialize)
|
211
|
+
end
|
212
|
+
|
213
|
+
# override the #new method
|
214
|
+
def new(*)
|
215
|
+
instance = super
|
216
|
+
disable_component_serialize(instance)
|
217
|
+
instance
|
218
|
+
end
|
219
|
+
end
|
220
|
+
self.class_eval <<~__CODE
|
221
|
+
module ComponentSerializerMethods
|
222
|
+
def from_serialized(hash)
|
223
|
+
super(hash)
|
224
|
+
#{self.name}.component_shapes.each { |pd| pd.get(self).set_parent_shape(self) }
|
225
|
+
self
|
226
|
+
end
|
227
|
+
protected :from_serialized
|
228
|
+
end
|
229
|
+
include ComponentSerializerMethods
|
230
|
+
__CODE
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# @overload initialize()
|
235
|
+
# default constructor
|
236
|
+
# @overload initialize(pos, manager)
|
237
|
+
# @param [Wx::RealPoint] pos Initial relative position
|
238
|
+
# @param [Diagram] diagram containing diagram
|
239
|
+
def initialize(*args)
|
240
|
+
pos, diagram = args
|
241
|
+
::Kernel.raise ArgumentError, "Invalid arguments pos: #{pos}, diagram: #{diagram}" unless
|
242
|
+
args.empty? || (Wx::RealPoint === pos && (diagram.nil? || Wx::SF::Diagram === diagram))
|
243
|
+
|
244
|
+
@id = Serializable::ID.new
|
245
|
+
@diagram = diagram
|
246
|
+
@parent_shape = nil
|
247
|
+
@child_shapes = ShapeList.new
|
248
|
+
@components = ::Set.new
|
249
|
+
|
250
|
+
if @diagram
|
251
|
+
if @diagram.shape_canvas
|
252
|
+
@hover_color = @diagram.shape_canvas.hover_colour
|
253
|
+
else
|
254
|
+
@hover_color = DEFAULT::HOVERCOLOUR;
|
255
|
+
end
|
256
|
+
else
|
257
|
+
@hover_color = DEFAULT::HOVERCOLOUR;
|
258
|
+
end
|
259
|
+
|
260
|
+
@selected = false
|
261
|
+
@mouse_over = false
|
262
|
+
@first_move = false
|
263
|
+
@highlight_parent = false
|
264
|
+
@user_data = nil
|
265
|
+
|
266
|
+
# archived properties
|
267
|
+
@visible = DEFAULT::VISIBILITY
|
268
|
+
@active = DEFAULT::ACTIVITY
|
269
|
+
@style = DEFAULT::DEFAULT_STYLE
|
270
|
+
@v_align = DEFAULT::VALIGN
|
271
|
+
@h_align = DEFAULT::HALIGN
|
272
|
+
@v_border = DEFAULT::VBORDER
|
273
|
+
@h_border = DEFAULT::HBORDER
|
274
|
+
@custom_dock_point = DEFAULT::DOCK_POINT
|
275
|
+
|
276
|
+
if pos && get_parent_shape
|
277
|
+
@relative_position = pos.to_real_point - get_parent_absolute_position
|
278
|
+
else
|
279
|
+
@relative_position = DEFAULT::POSITION.dup
|
280
|
+
end
|
281
|
+
|
282
|
+
@handles = []
|
283
|
+
@connection_pts = []
|
284
|
+
|
285
|
+
@accepted_children = ::Set.new
|
286
|
+
@accepted_connections = ::Set.new
|
287
|
+
@accepted_src_neighbours = ::Set.new
|
288
|
+
@accepted_trg_neighbours = ::Set.new
|
289
|
+
end
|
290
|
+
|
291
|
+
# Get the shape's id
|
292
|
+
# @return [Wx::SF::Serializable::ID]
|
293
|
+
def get_id
|
294
|
+
@id
|
295
|
+
end
|
296
|
+
alias :id :get_id
|
297
|
+
|
298
|
+
# Set the shape's id. Deserialization only.
|
299
|
+
# @param [Wx::SF::Serializable::ID] id
|
300
|
+
def set_id(id)
|
301
|
+
@id = id
|
302
|
+
end
|
303
|
+
private :set_id
|
304
|
+
|
305
|
+
# Set managing diagram
|
306
|
+
# @param [Wx::SF::Diagram] diagram
|
307
|
+
def set_diagram(diagram)
|
308
|
+
if @diagram != diagram
|
309
|
+
@diagram = diagram
|
310
|
+
@child_shapes.each { |child| child.set_diagram(diagram) }
|
311
|
+
end
|
312
|
+
self
|
313
|
+
end
|
314
|
+
|
315
|
+
# Get managing diagram
|
316
|
+
# @return [Wx::SF::Diagram]
|
317
|
+
def get_diagram
|
318
|
+
@diagram
|
319
|
+
end
|
320
|
+
alias :diagram :get_diagram
|
321
|
+
|
322
|
+
# Get the shape canvas of the parent diagram
|
323
|
+
# @return [Wx::SF::ShapeCanvas,nil]
|
324
|
+
def get_parent_canvas
|
325
|
+
@diagram ? @diagram.get_shape_canvas : nil
|
326
|
+
end
|
327
|
+
|
328
|
+
# Add a child shape
|
329
|
+
# @param [Wx::SF::Shape] shape
|
330
|
+
def add_child(shape)
|
331
|
+
@child_shapes << shape if shape
|
332
|
+
end
|
333
|
+
private :add_child
|
334
|
+
|
335
|
+
# Remove a child shape
|
336
|
+
# @param [Wx::SF::Shape] shape
|
337
|
+
def remove_child(shape)
|
338
|
+
@child_shapes.delete(shape) if shape
|
339
|
+
end
|
340
|
+
private :remove_child
|
341
|
+
|
342
|
+
# Adds child shape is accepted. Removes the child shape as a toplevel diagram shape if appropriate.
|
343
|
+
# @param [Wx::SF::Shape] child child shape to add
|
344
|
+
# @return [Wx::SF::Shape,nil] added child shape or nil if not accepted
|
345
|
+
def add_child_shape(child)
|
346
|
+
if is_child_accepted(child.class)
|
347
|
+
if child.get_diagram
|
348
|
+
child.get_diagram.reparent_shape(child, shape)
|
349
|
+
else
|
350
|
+
child.set_parent_shape(self)
|
351
|
+
end
|
352
|
+
child.update
|
353
|
+
return child
|
354
|
+
end
|
355
|
+
nil
|
356
|
+
end
|
357
|
+
|
358
|
+
# Set parent shape object.
|
359
|
+
# @param [Wx::SF::Shape] parent
|
360
|
+
# @note Note that this does not check this shape against the acceptance list of the parent. Use #add_child_shape if that is required.
|
361
|
+
# @note Note that this does not add (if parent == nil) or remove (if parent != nil) the shape from the diagram's
|
362
|
+
# toplevel shapes. Use Diagram#reparent_shape when that is needed.
|
363
|
+
def set_parent_shape(parent)
|
364
|
+
@parent_shape.send(:remove_child, self) if @parent_shape
|
365
|
+
parent.send(:add_child, self) if parent
|
366
|
+
set_diagram(parent.get_diagram) if parent
|
367
|
+
@parent_shape = parent
|
368
|
+
end
|
369
|
+
alias :parent_shape= :set_parent_shape
|
370
|
+
|
371
|
+
# Get parent shape
|
372
|
+
# @return [Wx::SF::Shape,nil] parent shape
|
373
|
+
def get_parent_shape
|
374
|
+
@parent_shape
|
375
|
+
end
|
376
|
+
alias :parent_shape :get_parent_shape
|
377
|
+
|
378
|
+
# Get pointer to the topmost parent shape
|
379
|
+
# @return [Wx::SF::Shape] topmost parent shape
|
380
|
+
def get_grand_parent_shape
|
381
|
+
@parent_shape ? @parent_shape.get_grand_parent_shape : self
|
382
|
+
end
|
383
|
+
alias :grand_parent_shape :get_grand_parent_shape
|
384
|
+
|
385
|
+
# Refresh (redraw) the shape
|
386
|
+
# @param [Boolean] delayed If true then the shape canvas will be rather invalidated than refreshed.
|
387
|
+
# @see ShapeCanvas#invalidate_rect
|
388
|
+
# @see ShapeCanvas#refresh_invalidated_rect
|
389
|
+
def refresh(delayed = false)
|
390
|
+
refresh_rect(get_bounding_box, delayed)
|
391
|
+
end
|
392
|
+
|
393
|
+
# Draw shape. Default implementation tests basic shape visual states
|
394
|
+
# (normal/ready, mouse is over the shape, dragged shape can be accepted) and
|
395
|
+
# call appropriate virtual functions (DrawNormal, DrawHover, DrawHighlighted)
|
396
|
+
# for its visualisation. The function can be overridden if necessary.
|
397
|
+
# @param [Wx::DC] dc Reference to a device context where the shape will be drawn to
|
398
|
+
# @param [Boolean] children true if the shape's children should be drawn as well
|
399
|
+
def draw(dc, children = WITHCHILDREN)
|
400
|
+
return unless @diagram && @diagram.shape_canvas
|
401
|
+
return unless @visible
|
402
|
+
|
403
|
+
# draw the shape shadow if required
|
404
|
+
draw_shadow(dc) if !@selected && has_style?(STYLE::SHOW_SHADOW)
|
405
|
+
|
406
|
+
# first, draw itself
|
407
|
+
if @mouse_over && (@highlight_parent || has_style?(STYLE::HOVERING))
|
408
|
+
if @highlight_parent
|
409
|
+
draw_highlighted(dc)
|
410
|
+
@highlight_parent = false
|
411
|
+
else
|
412
|
+
draw_hover(dc)
|
413
|
+
end
|
414
|
+
else
|
415
|
+
draw_normal(dc)
|
416
|
+
end
|
417
|
+
|
418
|
+
draw_selected(dc) if @selected
|
419
|
+
|
420
|
+
# ... then draw connection points ...
|
421
|
+
@connection_pts.each { |cpt| cpt.draw(dc) }
|
422
|
+
|
423
|
+
# ... then draw child shapes
|
424
|
+
if children
|
425
|
+
@child_shapes.each { |child| child.draw(dc) }
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# Test whether the given point is inside the shape. The function
|
430
|
+
# can be overridden if necessary.
|
431
|
+
# @param [Wx::Point] pos Examined point
|
432
|
+
# @return [Boolean] true if the point is inside the shape area, otherwise false
|
433
|
+
def contains?(pos)
|
434
|
+
# HINT: overload it for custom actions...
|
435
|
+
|
436
|
+
get_bounding_box.contains?(pos)
|
437
|
+
end
|
438
|
+
|
439
|
+
# Test whether the shape is completely inside given rectangle. The function
|
440
|
+
# can be overridden if necessary.
|
441
|
+
# @param [Wx::Rect] rct Examined rectangle
|
442
|
+
# @return [Boolean] true if the shape is completely inside given rectangle, otherwise false
|
443
|
+
def inside?(rct)
|
444
|
+
# HINT: overload it for custom actions...
|
445
|
+
|
446
|
+
rct.contains?(get_bounding_box)
|
447
|
+
end
|
448
|
+
|
449
|
+
# Test whether the given rectangle intersects the shape.
|
450
|
+
# @param [Wx::Rect] rct Examined rectangle
|
451
|
+
# @return [Boolean] true if the examined rectangle intersects the shape, otherwise false
|
452
|
+
def intersects?(rct)
|
453
|
+
# HINT: overload it for custom actions...
|
454
|
+
|
455
|
+
rct.intersects(get_bounding_box)
|
456
|
+
end
|
457
|
+
|
458
|
+
# Get the shape's absolute position in the canvas (calculated as a summation
|
459
|
+
# of all relative positions in the shapes' hierarchy. The function can be overridden if necessary.
|
460
|
+
# @return [Wx::RealPoint] Shape's position
|
461
|
+
def get_absolute_position
|
462
|
+
# HINT: overload it for custom actions...
|
463
|
+
parent_shape = get_parent_shape
|
464
|
+
if parent_shape
|
465
|
+
@relative_position + get_parent_absolute_position
|
466
|
+
else
|
467
|
+
@relative_position.dup
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
# Get intersection point of the shape border and a line leading from
|
472
|
+
# 'start' point to 'finish' point. Default implementation does nothing. The function can be overridden if necessary.
|
473
|
+
# @param [Wx::RealPoint] _start Starting point of the virtual intersection line
|
474
|
+
# @param [Wx::RealPoint] _finish Ending point of the virtual intersection line
|
475
|
+
# @return [Wx::RealPoint] Intersection point
|
476
|
+
def get_border_point(_start, _finish)
|
477
|
+
# HINT: overload it for custom actions...
|
478
|
+
Wx::RealPoint.new
|
479
|
+
end
|
480
|
+
|
481
|
+
# Get shape's center. Default implementation does nothing. The function can be overridden if necessary.
|
482
|
+
# @return [Wx::RealPoint] Center point
|
483
|
+
def get_center
|
484
|
+
# HINT: overload it for custom actions...
|
485
|
+
|
486
|
+
bb = get_bounding_box
|
487
|
+
Wx::RealPoint.new(bb.left + bb.width/2, bb.top + bb.height/2)
|
488
|
+
end
|
489
|
+
|
490
|
+
# Function called by the framework responsible for creation of shape handles
|
491
|
+
# at the creation time. Default implementation does nothing. The function can be overridden if necessary.
|
492
|
+
def create_handles
|
493
|
+
# HINT: overload it for custom actions...
|
494
|
+
end
|
495
|
+
|
496
|
+
# Show/hide shape handles. Hidden handles are inactive.
|
497
|
+
# @param [Boolean] show true for showing, false for hiding
|
498
|
+
def show_handles(show)
|
499
|
+
@handles.each { |h| h.show(show) }
|
500
|
+
end
|
501
|
+
|
502
|
+
# Set shape's style.
|
503
|
+
#
|
504
|
+
# Default value is STYLE::PARENT_CHANGE | STYLE::POSITION_CHANGE | STYLE::SIZE_CHANGE | STYLE::HOVERING | STYLE::HIGHLIGHTING | STYLE::SHOW_HANDLES | STYLE::ALWAYS_INSIDE | STYLE::DELETE_USER_DATA
|
505
|
+
# @param [Integer] style Combination of the shape's styles
|
506
|
+
# @see STYLE
|
507
|
+
def set_style(style)
|
508
|
+
@style = style
|
509
|
+
end
|
510
|
+
alias :style= :set_style
|
511
|
+
|
512
|
+
# Get current shape style.
|
513
|
+
# @return [Integer] shape style
|
514
|
+
def get_style
|
515
|
+
@style
|
516
|
+
end
|
517
|
+
alias :style :get_style
|
518
|
+
|
519
|
+
def add_style(style)
|
520
|
+
@style |= style
|
521
|
+
end
|
522
|
+
def remove_style(style)
|
523
|
+
@style &= ~style
|
524
|
+
end
|
525
|
+
def contains_style(style)
|
526
|
+
(@style & style) != 0
|
527
|
+
end
|
528
|
+
alias :contains_style? :contains_style
|
529
|
+
alias :has_style? :contains_style
|
530
|
+
|
531
|
+
# Find out whether this shape has some children.
|
532
|
+
# @return [Boolean] true if the parent shape has children, otherwise false
|
533
|
+
def has_children
|
534
|
+
!@child_shapes.empty?
|
535
|
+
end
|
536
|
+
alias :has_children? :has_children
|
537
|
+
|
538
|
+
# Get children of given type.
|
539
|
+
# @param [Class,nil] type Child shape type (if nil then all children are returned)
|
540
|
+
# @param [Array<Wx::SF::Shape>] list list where all found child shapes will be appended
|
541
|
+
# @return [Array<Wx::SF::Shape>] list with appended child shapes
|
542
|
+
def get_children(type, list)
|
543
|
+
@child_shapes.each_with_object(list) { |child, lst| lst << child if type.nil? || type === child }
|
544
|
+
end
|
545
|
+
|
546
|
+
# Get all children of given type recursively (i.e. children of children of .... ).
|
547
|
+
# @param [Class,nil] type Child shape type (if nil then all children are returned)
|
548
|
+
# @param [Array<Wx::SF::Shape>] list list where all found child shapes will be appended
|
549
|
+
# @param [SEARCHMODE] mode Search mode. User can choose Depth-First-Search or Breadth-First-Search algorithm (BFS is default)
|
550
|
+
# @see SEARCHMODE
|
551
|
+
def get_children_recursively(type, mode = SEARCHMODE::BFS, list = [])
|
552
|
+
@child_shapes.each do |child|
|
553
|
+
list << child if type.nil? || type === child
|
554
|
+
child.get_children_recursively(type, mode, list) if mode == SEARCHMODE::DFS
|
555
|
+
end
|
556
|
+
if mode == SEARCHMODE::BFS
|
557
|
+
@child_shapes.each { |child| child.get_children_recursively(type, mode, list) }
|
558
|
+
end
|
559
|
+
list
|
560
|
+
end
|
561
|
+
|
562
|
+
# Get child shapes associated with this (parent) shape.
|
563
|
+
# @param [Class,nil] type Type of searched child shapes (nil for any type)
|
564
|
+
# @param [Boolean] recursive Set this flag true if also children of children of ... should be found (also RECURSIVE or NORECURSIVE constants can be used).
|
565
|
+
# @param [SEARCHMODE] mode Search mode (has sense only for recursive search)
|
566
|
+
# @param [Array<Wx::SF::Shape>] list of child shapes to fill
|
567
|
+
# @return [Array<Wx::SF::Shape>] list of child shapes filled
|
568
|
+
def get_child_shapes(type, recursive = NORECURSIVE, mode = SEARCHMODE::BFS, list = [])
|
569
|
+
if recursive
|
570
|
+
get_children_recursively(type, mode, list)
|
571
|
+
else
|
572
|
+
get_children(type, list)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
# Get neighbour shapes connected to this shape.
|
577
|
+
# @param [Class,nil] shape_info Line object type
|
578
|
+
# @param [CONNECTMODE] condir Connection direction
|
579
|
+
# @param [Boolean] direct Set this flag to true if only closest shapes should be found, otherwise also shapes connected by forked lines will be found (also constants DIRECT and INDIRECT can be used)
|
580
|
+
# @param [Array<Wx::SF::Shape>] neighbours List of neighbour shapes
|
581
|
+
# @return [Array<Wx::SF::Shape>] list of neighbour shapes filled
|
582
|
+
# @see CONNECTMODE
|
583
|
+
def get_neighbours(shape_info, condir, direct = DIRECT, neighbours = [])
|
584
|
+
unless Wx::SF::LineShape === self
|
585
|
+
_get_neighbours(shape_info, condir, direct, neighbours)
|
586
|
+
# delete starting object if necessary (can be added in a case of complex connection network)
|
587
|
+
neighbours.delete(self)
|
588
|
+
end
|
589
|
+
neighbours
|
590
|
+
end
|
591
|
+
|
592
|
+
# Get list of connections assigned to this shape.
|
593
|
+
# @note For proper functionality the shape must be managed by a diagram manager.
|
594
|
+
# @param [Class] shape_info Line object type
|
595
|
+
# @param [CONNECTMODE] mode Search mode
|
596
|
+
# @param [Array<Wx::SF::Shape>] lines shape list where all found connections will be stored
|
597
|
+
# @return [Array<Wx::SF::Shape>] list of connection shapes filled
|
598
|
+
# @see CONNECTMODE
|
599
|
+
def get_assigned_connections(shape_info, mode, lines = [])
|
600
|
+
@diagram.get_assigned_connections(self, shape_info, mode, lines) if @diagram
|
601
|
+
lines
|
602
|
+
end
|
603
|
+
|
604
|
+
# Get shape's bounding box. The function can be overridden if necessary.
|
605
|
+
# @return [Wx::Rect] Bounding rectangle
|
606
|
+
def get_bounding_box
|
607
|
+
# HINT: overload it for custom actions...
|
608
|
+
|
609
|
+
Wx::Rect.new
|
610
|
+
end
|
611
|
+
|
612
|
+
# Get shape's bounding box which includes also associated child shapes and connections.
|
613
|
+
# @param [Wx::Rect] rct bounding rectangle
|
614
|
+
# @param [BBMODE] mask Bit mask of object types which should be included into calculation
|
615
|
+
# @return [Wx::Rect] returned bounding box
|
616
|
+
# @see BBMODE
|
617
|
+
def get_complete_bounding_box(rct, mask = BBMODE::ALL)
|
618
|
+
_get_complete_bounding_box(rct, mask)
|
619
|
+
end
|
620
|
+
|
621
|
+
# Scale the shape size in both directions. The function can be overridden if necessary
|
622
|
+
# (new implementation should call default one or scale shape's children manually if necessary).
|
623
|
+
# @overload scale(x,y, children: WITHCHILDREN)
|
624
|
+
# @param [Float] x Horizontal scale factor
|
625
|
+
# @param [Float] y Vertical scale factor
|
626
|
+
# @param [Boolean] children true if the shape's children should be scaled as well, otherwise the shape will be updated after scaling via #update function.
|
627
|
+
# @overload scale(scale, children: WITHCHILDREN)
|
628
|
+
# @param [Wx::RealPoint] scale scale factors
|
629
|
+
# @param [Boolean] children true if the shape's children should be scaled as well, otherwise the shape will be updated after scaling via #update function.
|
630
|
+
def scale(*args, children: WITHCHILDREN)
|
631
|
+
# HINT: overload it for custom actions...
|
632
|
+
|
633
|
+
x, y = (args.size == 1 ? args.first : args)
|
634
|
+
scale_children(x, y) if children
|
635
|
+
|
636
|
+
@diagram.set_modified(true) if @diagram
|
637
|
+
# self.update
|
638
|
+
end
|
639
|
+
|
640
|
+
# Scale shape's children
|
641
|
+
# @param [Float] x Horizontal scale factor
|
642
|
+
# @param [Float] y Vertical scale factor
|
643
|
+
# @see Scale
|
644
|
+
def scale_children(x, y)
|
645
|
+
lst_children = get_child_shapes(ANY, RECURSIVE)
|
646
|
+
|
647
|
+
lst_children.each do |shape|
|
648
|
+
if shape.has_style?(STYLE::SIZE_CHANGE) && shape.is_a?(Wx::SF::TextShape)
|
649
|
+
shape.scale(x, y, children: WITHOUTCHILDREN)
|
650
|
+
end
|
651
|
+
|
652
|
+
if shape.has_style?(STYLE::POSITION_CHANGE) && (shape.get_v_align == VALIGN::NONE || shape.get_h_align == HALIGN::NONE)
|
653
|
+
shape.set_relative_position(shape.get_relative_position.x*x, shape.get_relative_position.y*y)
|
654
|
+
end
|
655
|
+
|
656
|
+
# re-align shapes which have set any alignment mode
|
657
|
+
shape.do_alignment
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
# Move the shape to the given absolute position. The function can be overridden if necessary.
|
662
|
+
# @overload move_to(x,y)
|
663
|
+
# @param [Float] x X coordinate
|
664
|
+
# @param [Float] y Y coordinate
|
665
|
+
# @overload move_to(pos)
|
666
|
+
# @param [Wx::RealPoint] pos New absolute position
|
667
|
+
def move_to(*args)
|
668
|
+
# HINT: overload it for custom actions...
|
669
|
+
|
670
|
+
pos = (args.size == 1 ? args.first.to_real_point : Wx::RealPoint.new(*args))
|
671
|
+
@relative_position = pos - get_parent_absolute_position
|
672
|
+
|
673
|
+
@diagram.set_modified(true) if @diagram
|
674
|
+
end
|
675
|
+
|
676
|
+
# Move the shape by the given offset. The function can be overridden if necessary.
|
677
|
+
# @overload move_by(x,y)
|
678
|
+
# @param [Float] x X offset
|
679
|
+
# @param [Float] y Y offset
|
680
|
+
# @overload move_by(delta)
|
681
|
+
# @param [Wx::RealPoint] delta Offset
|
682
|
+
def move_by(*args)
|
683
|
+
# HINT: overload it for custom actions...
|
684
|
+
|
685
|
+
x, y = (args.size == 1 ? args.first : args)
|
686
|
+
@relative_position.x += x
|
687
|
+
@relative_position.y += y
|
688
|
+
|
689
|
+
@diagram.set_modified(true) if @diagram
|
690
|
+
end
|
691
|
+
|
692
|
+
# Update the shape's position in order to its alignment
|
693
|
+
def do_alignment
|
694
|
+
parent = get_parent_shape
|
695
|
+
|
696
|
+
if parent && !parent.is_a?(Wx::SF::GridShape)
|
697
|
+
|
698
|
+
if parent.is_a?(Wx::SF::LineShape)
|
699
|
+
line_pos = get_parent_absolute_position
|
700
|
+
parent_bb = Wx::Rect.new(line_pos.x.to_i, line_pos.y.to_i, 1, 1)
|
701
|
+
else
|
702
|
+
parent_bb = parent.get_bounding_box
|
703
|
+
end
|
704
|
+
|
705
|
+
shape_bb = get_bounding_box
|
706
|
+
|
707
|
+
# do vertical alignment
|
708
|
+
case @v_align
|
709
|
+
when VALIGN::TOP
|
710
|
+
@relative_position.y = @v_border
|
711
|
+
|
712
|
+
when VALIGN::MIDDLE
|
713
|
+
@relative_position.y = parent_bb.height/2 - shape_bb.height/2
|
714
|
+
|
715
|
+
when VALIGN::BOTTOM
|
716
|
+
@relative_position.y = parent_bb.height - shape_bb.height - @v_border
|
717
|
+
|
718
|
+
when VALIGN::EXPAND
|
719
|
+
if has_style?(STYLE::SIZE_CHANGE)
|
720
|
+
@relative_position.y = @v_border
|
721
|
+
scale(1.0, ((parent_bb.height - 2*@v_border)/shape_bb.height).to_f)
|
722
|
+
end
|
723
|
+
|
724
|
+
when VALIGN::LINE_START
|
725
|
+
if parent.is_a?(Wx::SF::LineShape)
|
726
|
+
line_start, line_end = parent.get_line_segment(0)
|
727
|
+
|
728
|
+
if line_end.y >= line_start.y
|
729
|
+
@relative_position.y = line_start.y - line_pos.y + @v_border
|
730
|
+
else
|
731
|
+
@relative_position.y = line_start.y - line_pos.y - shape_bb.height - @v_border
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
when VALIGN::LINE_END
|
736
|
+
if parent.is_a?(Wx::SF::LineShape)
|
737
|
+
line_start, line_end = parent.get_line_segment(parent.get_control_points.get_count)
|
738
|
+
|
739
|
+
if line_end.y >= line_start.y
|
740
|
+
@relative_position.y = line_end.y - line_pos.y - shape_bb.height - @v_border
|
741
|
+
else
|
742
|
+
@relative_position.y = line_end.y - line_pos.y + @v_border
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
# do horizontal alignment
|
748
|
+
case @h_align
|
749
|
+
when HALIGN::LEFT
|
750
|
+
@relative_position.x = @h_border
|
751
|
+
|
752
|
+
when HALIGN::CENTER
|
753
|
+
@relative_position.x = parent_bb.width/2 - shape_bb.width/2
|
754
|
+
|
755
|
+
when HALIGN::RIGHT
|
756
|
+
@relative_position.x = parent_bb.width - shape_bb.width - @h_border
|
757
|
+
|
758
|
+
when HALIGN::EXPAND
|
759
|
+
if has_style?(STYLE::SIZE_CHANGE)
|
760
|
+
@relative_position.x = @h_border
|
761
|
+
scale(((parent_bb.width - 2*@h_border)/shape_bb.width).to_f, 1.0)
|
762
|
+
end
|
763
|
+
|
764
|
+
when HALIGN::LINE_START
|
765
|
+
if parent.is_a?(Wx::SF::LineShape)
|
766
|
+
line_start, line_end = parent.get_line_segment(0)
|
767
|
+
|
768
|
+
if line_end.x >= line_start.x
|
769
|
+
|
770
|
+
@relative_position.x = line_start.x - line_pos.x + @h_border
|
771
|
+
else
|
772
|
+
@relative_position.x = line_start.x - line_pos.x - shape_bb.width - @h_border
|
773
|
+
end
|
774
|
+
end
|
775
|
+
|
776
|
+
when HALIGN::LINE_END
|
777
|
+
if parent.is_a?(Wx::SF::LineShape)
|
778
|
+
line_start, line_end = parent.get_line_segment(parent.get_control_points.get_count)
|
779
|
+
|
780
|
+
if line_end.x >= line_start.x
|
781
|
+
@relative_position.x = line_end.x - line_pos.x - shape_bb.width - @h_border
|
782
|
+
else
|
783
|
+
@relative_position.x = line_end.x - line_pos.x + @h_border
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
# Update shape (align all child shapes and resize it to fit them)
|
791
|
+
def update
|
792
|
+
# do self-alignment
|
793
|
+
do_alignment
|
794
|
+
|
795
|
+
# do alignment of shape's children (if required)
|
796
|
+
@child_shapes.each { |child| child.do_alignment }
|
797
|
+
|
798
|
+
# fit the shape to its children
|
799
|
+
fit_to_children unless has_style?(STYLE::NO_FIT_TO_CHILDREN)
|
800
|
+
|
801
|
+
# do it recursively on all parent shapes
|
802
|
+
if (parent = get_parent_shape)
|
803
|
+
parent.update
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
# Resize the shape to bound all child shapes. The function can be overridden if necessary.
|
808
|
+
def fit_to_children
|
809
|
+
# HINT: overload it for custom actions...
|
810
|
+
end
|
811
|
+
|
812
|
+
# Function returns true if the shape is selected, otherwise returns false
|
813
|
+
def selected?
|
814
|
+
@selected
|
815
|
+
end
|
816
|
+
|
817
|
+
# Set the shape as a selected/deselected one
|
818
|
+
# @param [Boolean] state Selection state (true is selected, false is deselected)
|
819
|
+
def select(state)
|
820
|
+
@selected = state
|
821
|
+
show_handles(state && (@style & STYLE::SHOW_HANDLES) != 0)
|
822
|
+
end
|
823
|
+
|
824
|
+
# Set shape's relative position. Absolute shape's position is then calculated
|
825
|
+
# as a summation of the relative positions of this shape and all parent shapes in the shape's
|
826
|
+
# hierarchy.
|
827
|
+
# @overload set_relative_position(pos)
|
828
|
+
# @param [Wx::RealPoint] pos New relative position
|
829
|
+
# @overload set_relative_position(x,y)
|
830
|
+
# @param [Float] x Horizontal coordinate of new relative position
|
831
|
+
# @param [Float] y Vertical coordinate of new relative position
|
832
|
+
# @see #move_to
|
833
|
+
def set_relative_position(*arg)
|
834
|
+
x, y = (arg.size == 1 ? arg.first.to_real_point : arg)
|
835
|
+
@relative_position.x = x
|
836
|
+
@relative_position.y = y
|
837
|
+
end
|
838
|
+
|
839
|
+
# Get shape's relative position.
|
840
|
+
# @return [Wx::RealPoint] Current relative position
|
841
|
+
# @see #get_absolute_position
|
842
|
+
def get_relative_position
|
843
|
+
@relative_position.dup
|
844
|
+
end
|
845
|
+
|
846
|
+
# Set vertical alignment of this shape inside its parent
|
847
|
+
# @param [VALIGN] val Alignment type
|
848
|
+
# @see VALIGN
|
849
|
+
def set_v_align(val)
|
850
|
+
@v_align = val
|
851
|
+
end
|
852
|
+
alias :v_align= :set_v_align
|
853
|
+
|
854
|
+
# Get vertical alignment of this shape inside its parent
|
855
|
+
# @return [VALIGN] Alignment type
|
856
|
+
# @see VALIGN
|
857
|
+
def get_v_align
|
858
|
+
@v_align
|
859
|
+
end
|
860
|
+
alias :v_align :get_v_align
|
861
|
+
|
862
|
+
# Set horizontal alignment of this shape inside its parent
|
863
|
+
# @param [HALIGN] val Horizontal type
|
864
|
+
# @see HALIGN
|
865
|
+
def set_h_align(val)
|
866
|
+
@h_align = val
|
867
|
+
end
|
868
|
+
alias :h_align= :set_h_align
|
869
|
+
|
870
|
+
# Get horizontal alignment of this shape inside its parent
|
871
|
+
# @return [HALIGN] Alignment type
|
872
|
+
# @see HALIGN
|
873
|
+
def get_h_align
|
874
|
+
@h_align
|
875
|
+
end
|
876
|
+
alias :h_align :get_h_align
|
877
|
+
|
878
|
+
# Set vertical border between this shape and its parent (if vertical
|
879
|
+
# alignment is set).
|
880
|
+
# @param [Float] border Vertical border
|
881
|
+
# @see #set_v_align
|
882
|
+
def set_v_border(border)
|
883
|
+
@v_border = border
|
884
|
+
end
|
885
|
+
alias :v_border= :set_v_border
|
886
|
+
|
887
|
+
# Get vertical border between this shape and its parent (if vertical
|
888
|
+
# alignment is set).
|
889
|
+
# @return [Float] Vertical border
|
890
|
+
# @see #set_v_align
|
891
|
+
def get_v_border
|
892
|
+
@v_border
|
893
|
+
end
|
894
|
+
alias :v_border :get_v_border
|
895
|
+
|
896
|
+
# Set horizontal border between this shape and its parent (if horizontal
|
897
|
+
# alignment is set).
|
898
|
+
# @param [Float] border Horizontal border
|
899
|
+
# @see #set_h_align
|
900
|
+
def set_h_border(border)
|
901
|
+
@h_border = border
|
902
|
+
end
|
903
|
+
alias :h_border= :set_h_border
|
904
|
+
|
905
|
+
# Get horizontal border between this shape and its parent (if horizontal
|
906
|
+
# alignment is set).
|
907
|
+
# @return [Float] Vertical border
|
908
|
+
# @see #set_h_align
|
909
|
+
def get_h_border
|
910
|
+
@h_border
|
911
|
+
end
|
912
|
+
alias :h_border :get_h_border
|
913
|
+
|
914
|
+
# Set custom dock point used if the shape is child shape of a line shape.
|
915
|
+
# @param [Integer] dp Custom dock point
|
916
|
+
def set_custom_dock_point(dp)
|
917
|
+
@custom_dock_point = dp
|
918
|
+
end
|
919
|
+
alias :custom_dock_point= :set_custom_dock_point
|
920
|
+
|
921
|
+
# Get custom dock point used if the shape is child shape of a line shape.
|
922
|
+
# @return [Integer] Custom dock point
|
923
|
+
def get_custom_dock_point
|
924
|
+
@custom_dock_point
|
925
|
+
end
|
926
|
+
alias :custom_dock_point :get_custom_dock_point
|
927
|
+
|
928
|
+
# Determine whether this shape is ancestor of given child shape.
|
929
|
+
# @param [Wx::SF::Shape] child child shape.
|
930
|
+
# @return true if this shape is parent of given child shape, otherwise false
|
931
|
+
def ancestor?(child)
|
932
|
+
@child_shapes.include?(child) || @child_shapes.any? { |c| c.ancestor?(child) }
|
933
|
+
end
|
934
|
+
|
935
|
+
# Determine whether this shape is descendant of given parent shape.
|
936
|
+
# @param [Wx::SF::Shape] parent parent shape
|
937
|
+
# @return true if this shape is a child of given parent shape, otherwise false
|
938
|
+
def descendant?(parent)
|
939
|
+
parent && parent.ancestor?(self)
|
940
|
+
end
|
941
|
+
|
942
|
+
# Associate user data with the shape.
|
943
|
+
# If the data object is properly set then its marked properties will be serialized
|
944
|
+
# together with the parent shape. This means the user data must either be a serializable
|
945
|
+
# core type or a Wx::SF::Serializable.
|
946
|
+
# @param [Object] data user data
|
947
|
+
def set_user_data(data)
|
948
|
+
@user_data = data
|
949
|
+
end
|
950
|
+
alias :user_data= :set_user_data
|
951
|
+
|
952
|
+
# Get associated user data.
|
953
|
+
# @return [Object,nil] user data
|
954
|
+
def get_user_data
|
955
|
+
@user_data
|
956
|
+
end
|
957
|
+
alias :user_data :get_user_data
|
958
|
+
|
959
|
+
# Get shape's diagram canvas
|
960
|
+
# @return [Wx::SF::ShapeCanvas,nil] shape canvas if assigned via diagram, otherwise nil
|
961
|
+
# @see Wx::SF::Diagram
|
962
|
+
def get_shape_canvas
|
963
|
+
return nil unless @diagram
|
964
|
+
|
965
|
+
@diagram.shape_canvas
|
966
|
+
end
|
967
|
+
alias :shape_canvas :get_shape_canvas
|
968
|
+
|
969
|
+
# Get the shape's visibility status
|
970
|
+
# @return [Boolean] true if the shape is visible, otherwise false
|
971
|
+
def visible?
|
972
|
+
@visible
|
973
|
+
end
|
974
|
+
alias :visibility :visible?
|
975
|
+
|
976
|
+
# Show/hide shape
|
977
|
+
# @param [Boolean] show Set the parameter to true if the shape should be visible, otherwise use false
|
978
|
+
def show(show)
|
979
|
+
@visible = show
|
980
|
+
end
|
981
|
+
alias :set_visibility :show
|
982
|
+
|
983
|
+
# Set shape's hover color
|
984
|
+
# @param [Wx::Colour,String,Symbol] col Hover color
|
985
|
+
def set_hover_colour(col)
|
986
|
+
@hover_color = Wx::Colour === col ? col : Wx::Colour.new(col)
|
987
|
+
end
|
988
|
+
alias :hover_colour= :set_hover_colour
|
989
|
+
|
990
|
+
# Get shape's hover color
|
991
|
+
# @return [Wx::Colour] Current hover color
|
992
|
+
def get_hover_colour
|
993
|
+
@hover_color
|
994
|
+
end
|
995
|
+
alias :hover_colour :get_hover_colour
|
996
|
+
|
997
|
+
# Function returns value of a shape's activation flag.
|
998
|
+
# Non-active shapes are visible, but don't receive (process) any events.
|
999
|
+
# @return [Boolean] true if the shape is active, otherwise false
|
1000
|
+
def active?
|
1001
|
+
@active
|
1002
|
+
end
|
1003
|
+
alias :active :active?
|
1004
|
+
|
1005
|
+
# Shape's activation/deactivation
|
1006
|
+
# Deactivated shapes are visible, but don't receive (process) any events.
|
1007
|
+
# @param [Boolean] active true for activation, false for deactivation
|
1008
|
+
# @see #show
|
1009
|
+
def activate(active)
|
1010
|
+
@active = active
|
1011
|
+
end
|
1012
|
+
alias :set_active :activate
|
1013
|
+
|
1014
|
+
# Tells whether the given shape type is accepted by this shape (it means
|
1015
|
+
# whether this shape can be its parent).
|
1016
|
+
#
|
1017
|
+
# The function is typically used by the framework for determination whether a dropped
|
1018
|
+
# shape can be assigned to an underlying shape as its child.
|
1019
|
+
# @param [Class] type Class of examined shape object
|
1020
|
+
# @return [Boolean] true if the shape type is accepted, otherwise false.
|
1021
|
+
def is_child_accepted(type)
|
1022
|
+
@accepted_children.include?(type) || @accepted_children.include?(ACCEPT_ALL)
|
1023
|
+
end
|
1024
|
+
alias :child_accepted? :is_child_accepted
|
1025
|
+
|
1026
|
+
# Returns true if *all* currently dragged shapes can be accepted
|
1027
|
+
# as children of this shape.
|
1028
|
+
# @return [Boolean]
|
1029
|
+
# @see #is_shape_accepted
|
1030
|
+
def accept_currently_dragged_shapes
|
1031
|
+
return false unless get_shape_canvas
|
1032
|
+
|
1033
|
+
unless is_child_accepted(ACCEPT_ALL)
|
1034
|
+
lst_selection = get_shape_canvas.get_selected_shapes
|
1035
|
+
|
1036
|
+
return false if lst_selection.any? { |shape| !@accepted_children.include?(shape.class.name) }
|
1037
|
+
end
|
1038
|
+
true
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
# Add given shape type to an acceptance list. The acceptance list contains class
|
1042
|
+
# names of the shapes which can be accepted as children of this shape.
|
1043
|
+
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
|
1044
|
+
# @param [Class] type Class of accepted shape object
|
1045
|
+
# @see #is_child_accepted
|
1046
|
+
def accept_child(type)
|
1047
|
+
::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
|
1048
|
+
@accepted_children << type
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
# Get shape types acceptance list.
|
1052
|
+
# @return [Set<String>] String set with class names of accepted shape types.
|
1053
|
+
# @see #is_child_accepted
|
1054
|
+
def get_accepted_children
|
1055
|
+
@accepted_children
|
1056
|
+
end
|
1057
|
+
alias :accepted_children :get_accepted_children
|
1058
|
+
|
1059
|
+
# Tells whether the given connection type is accepted by this shape (it means
|
1060
|
+
# whether this shape can be connected to another one by a connection of given type).
|
1061
|
+
#
|
1062
|
+
# The function is typically used by the framework during interactive connection creation.
|
1063
|
+
# @param [Class] type Class of examined connection object
|
1064
|
+
# @return true if the connection type is accepted, otherwise false.
|
1065
|
+
def is_connection_accepted(type)
|
1066
|
+
@accepted_connections.include?(type) || @accepted_connections.include?(ACCEPT_ALL)
|
1067
|
+
end
|
1068
|
+
alias :connection_accepted? :is_connection_accepted
|
1069
|
+
|
1070
|
+
# Add given connection type to an acceptance list. The acceptance list contains class
|
1071
|
+
# names of the connection which can be accepted by this shape.
|
1072
|
+
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
|
1073
|
+
# @param [Class] type Class of accepted connection object
|
1074
|
+
# @see #is_connection_accepted
|
1075
|
+
def accept_connection(type)
|
1076
|
+
::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
|
1077
|
+
@accepted_connections << type
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
# Get connection types acceptance list.
|
1081
|
+
# @return [Set<String>] String set with class names of accepted connection types.
|
1082
|
+
# @see #is_connection_accepted
|
1083
|
+
def get_accepted_connections
|
1084
|
+
@accepted_connections
|
1085
|
+
end
|
1086
|
+
alias :accepted_connections :get_accepted_connections
|
1087
|
+
|
1088
|
+
# Tells whether the given shape type is accepted by this shape as its source neighbour(it means
|
1089
|
+
# whether this shape can be connected from another one of given type).
|
1090
|
+
#
|
1091
|
+
# The function is typically used by the framework during interactive connection creation.
|
1092
|
+
# @param [Class] type Class of examined connection object
|
1093
|
+
# @return true if the shape type is accepted, otherwise false.
|
1094
|
+
def is_src_neighbour_accepted(type)
|
1095
|
+
@accepted_src_neighbours.include?(type) || @accepted_src_neighbours.include?(ACCEPT_ALL)
|
1096
|
+
end
|
1097
|
+
alias :src_neighbour_accepted? :is_src_neighbour_accepted
|
1098
|
+
|
1099
|
+
# Add given shape type to an source neighbours' acceptance list. The acceptance list contains class
|
1100
|
+
# names of the shape types which can be accepted by this shape as its source neighbour.
|
1101
|
+
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
|
1102
|
+
# @param [Class] type Class of accepted connection object
|
1103
|
+
# @see #is_src_neighbour_accepted
|
1104
|
+
def accept_src_neighbour(type)
|
1105
|
+
::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
|
1106
|
+
@accepted_src_neighbours << type
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
# Get source neighbour types acceptance list.
|
1110
|
+
# @return [Set<String>] String set with class names of accepted source neighbours types.
|
1111
|
+
# @see #is_src_neighbour_accepted
|
1112
|
+
def get_accepted_src_neighbours
|
1113
|
+
@accepted_src_neighbours
|
1114
|
+
end
|
1115
|
+
alias :accepted_src_neighbours :get_accepted_src_neighbours
|
1116
|
+
|
1117
|
+
# Tells whether the given shape type is accepted by this shape as its target neighbour(it means
|
1118
|
+
# whether this shape can be connected to another one of given type).
|
1119
|
+
#
|
1120
|
+
# The function is typically used by the framework during interactive connection creation.
|
1121
|
+
# @param [Class] type Class of examined connection object
|
1122
|
+
# @return [Boolean] true if the shape type is accepted, otherwise false.
|
1123
|
+
def is_trg_neighbour_accepted(type)
|
1124
|
+
@accepted_trg_neighbours.include?(type) || @accepted_trg_neighbours.include?(ACCEPT_ALL)
|
1125
|
+
end
|
1126
|
+
alias :trg_neighbour_accepted? :is_trg_neighbour_accepted
|
1127
|
+
|
1128
|
+
# Add given shape type to an target neighbours' acceptance list. The acceptance list contains class
|
1129
|
+
# names of the shape types which can be accepted by this shape as its target neighbour.
|
1130
|
+
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
|
1131
|
+
# @param [Class] type Class of accepted connection object
|
1132
|
+
# @see #is_trg_neighbour_accepted
|
1133
|
+
def accept_trg_neighbour(type)
|
1134
|
+
::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
|
1135
|
+
@accepted_trg_neighbours << type
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
# Get target neighbour types acceptance list.
|
1139
|
+
# @return [Set<String>] String set with class names of accepted target neighbours types.
|
1140
|
+
# @see #is_trg_neighbour_accepted
|
1141
|
+
def get_accepted_trg_neighbours
|
1142
|
+
@accepted_trg_neighbours
|
1143
|
+
end
|
1144
|
+
alias :accepted_trg_neighbours :get_accepted_trg_neighbours
|
1145
|
+
|
1146
|
+
# Clear shape object acceptance list
|
1147
|
+
# @see #accept_child
|
1148
|
+
def clear_accepted_childs
|
1149
|
+
@accepted_children.clear
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
# Clear connection object acceptance list
|
1153
|
+
# @see #accept_connection
|
1154
|
+
def clear_accepted_connections
|
1155
|
+
@accepted_connections.clear
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
# Clear source neighbour objects acceptance list
|
1159
|
+
# @see #accept_src_neighbour
|
1160
|
+
def clear_accepted_src_neighbours
|
1161
|
+
@accepted_src_neighbours.clear
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
# Clear target neighbour objects acceptance list
|
1165
|
+
# @see #accept_trg_neighbour
|
1166
|
+
def clear_accepted_trg_neighbours
|
1167
|
+
@accepted_trg_neighbours.clear
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
# Get list of currently assigned shape handles.
|
1171
|
+
# @return [Array<Wx::SF::Shape::Handle>] handle list
|
1172
|
+
def get_handles
|
1173
|
+
@handles
|
1174
|
+
end
|
1175
|
+
alias :handles :get_handles
|
1176
|
+
|
1177
|
+
# Get shape handle.
|
1178
|
+
# @param [Wx::SF::Shape::Handle::TYPE] type Handle type
|
1179
|
+
# @param [Integer] id Handle ID (useful only for line control points)
|
1180
|
+
# @return [Wx::SF::Shape::Handle,nil] shape handle object if exist
|
1181
|
+
# @see Wx::SF::Shape::Handle
|
1182
|
+
def get_handle(type, id = -1)
|
1183
|
+
@handles.find { |h| h.type == type && (id == -1 || h.id == id) }
|
1184
|
+
end
|
1185
|
+
alias :handle :get_handle
|
1186
|
+
|
1187
|
+
# Add new handle to the shape.
|
1188
|
+
#
|
1189
|
+
# The function creates new instance of shape handle (if it doesn't exist yet)
|
1190
|
+
# and inserts it into handle list.
|
1191
|
+
# @param [Wx::SF::Shape::Handle::TYPE] type Handle type
|
1192
|
+
# @param [Integer] id Handle ID (useful only for line control points)
|
1193
|
+
# @see Wx::SF::Shape::Handle
|
1194
|
+
def add_handle(type, id = -1)
|
1195
|
+
unless get_handle(type, id)
|
1196
|
+
@handles << Handle.new(self, type, id)
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
# Remove given shape handle (if exists).
|
1201
|
+
# @param [Wx::SF::Shape::Handle::TYPE] type Handle type
|
1202
|
+
# @param [Integer] id Handle ID (useful only for line control points)
|
1203
|
+
# @see Wx::SF::Shape::Handle
|
1204
|
+
def remove_handle(type, id = -1)
|
1205
|
+
@handles.delete_if { |h| h.type == type && (id == -1 || h.id == id) }
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
# Get reference to connection points list.
|
1209
|
+
# @return [Array<Wx::SF::ConnectionPoint>] connection points list
|
1210
|
+
def get_connection_points
|
1211
|
+
@connection_pts
|
1212
|
+
end
|
1213
|
+
alias :connection_points :get_connection_points
|
1214
|
+
|
1215
|
+
# Get connection point of given type assigned to the shape.
|
1216
|
+
# @param [Wx::SF::ConnectionPoint::CPTYPE] type Connection point type
|
1217
|
+
# @param [Integer] id Optional connection point ID
|
1218
|
+
# @return [Wx::SF::ConnectionPoint,nil] connection point if exists, otherwise nil
|
1219
|
+
# @see Wx::SF::ConnectionPoint::CPTYPE
|
1220
|
+
def get_connection_point(type, id = -1)
|
1221
|
+
@connection_pts.find { |cp| cp.type == type && cp.id == id }
|
1222
|
+
end
|
1223
|
+
alias :connection_point :get_connection_point
|
1224
|
+
|
1225
|
+
# Get connection point closest to the given position.
|
1226
|
+
# @param [Wx::RealPoint] pos Position
|
1227
|
+
# @return [Wx::SF::ConnectionPoint,nil] closest connection point if exists, otherwise nil
|
1228
|
+
def get_nearest_connection_point(pos)
|
1229
|
+
pos = pos.to_real_point
|
1230
|
+
min_dist = Float::MAX
|
1231
|
+
@connection_pts.inject(nil) do |nearest, cp|
|
1232
|
+
if (curr_dist = pos.distance_to(cp.get_connection_point)) < min_dist
|
1233
|
+
min_dist = curr_dist
|
1234
|
+
nearest = cp
|
1235
|
+
end
|
1236
|
+
nearest
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
alias :nearest_connection_point :get_nearest_connection_point
|
1240
|
+
|
1241
|
+
# Assign connection point of given type to the shape.
|
1242
|
+
# @overload add_connection_point(type, persistent: true)
|
1243
|
+
# @param [Wx::SF::ConnectionPoint::CPTYPE] type Connection point type
|
1244
|
+
# @param [Boolean] persistent true if the connection point should be serialized
|
1245
|
+
# @return [Wx::SF::ConnectionPoint] new connection point
|
1246
|
+
# @overload add_connection_point(relpos, id=-1, persistent: true)
|
1247
|
+
# @param [Wx::RealPoint] relpos Relative position in percentages
|
1248
|
+
# @param [Integer] id connection point ID
|
1249
|
+
# @param [Boolean] persistent true if the connection point should be serialized
|
1250
|
+
# @return [Wx::SF::ConnectionPoint] new connection point
|
1251
|
+
# @overload add_connection_point(cp, persistent: true)
|
1252
|
+
# @param [Wx::SF::ConnectionPoint] cp connection point (shape will take the ownership)
|
1253
|
+
# @param [Boolean] persistent true if the connection point should be serialized
|
1254
|
+
# @return [Wx::SF::ConnectionPoint] added connection point
|
1255
|
+
# @see Wx::SF::ConnectionPoint::CPTYPE
|
1256
|
+
def add_connection_point(arg, *rest, persistent: true)
|
1257
|
+
cp = nil
|
1258
|
+
case arg
|
1259
|
+
when ConnectionPoint::CPTYPE
|
1260
|
+
unless get_connection_point(arg)
|
1261
|
+
cp = ConnectionPoint.new(self, arg)
|
1262
|
+
cp.disable_serialize unless persistent
|
1263
|
+
end
|
1264
|
+
when Wx::RealPoint, ::Array
|
1265
|
+
cp = ConnectionPoint.new(self, arg.to_real_point, *rest)
|
1266
|
+
cp.disable_serialize unless persistent
|
1267
|
+
when ConnectionPoint
|
1268
|
+
cp = arg
|
1269
|
+
cp.disable_serialize unless persistent
|
1270
|
+
else
|
1271
|
+
::Kernel.raise ArgumentError, "Invalid arguments: arg: #{arg}, rest: #{rest}"
|
1272
|
+
end
|
1273
|
+
@connection_pts << cp if cp
|
1274
|
+
cp
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
# Remove connection point of given type from the shape (if present).
|
1278
|
+
# @param [Wx::SF::ConnectionPoint::CPTYPE] type Connection point type
|
1279
|
+
# @see Wx::SF::ConnectionPoint::CPTYPE
|
1280
|
+
def remove_connection_point(type)
|
1281
|
+
@connection_pts.delete_if { |cp| cp.type == type }
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
# Event handler called when the shape is clicked by
|
1285
|
+
# the left mouse button. The function can be overridden if necessary.
|
1286
|
+
#
|
1287
|
+
# The function is called by the framework (by the shape canvas).
|
1288
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_LEFT_DOWN event.
|
1289
|
+
# @param [Wx::Point] pos Current mouse position
|
1290
|
+
# @see Wx::SF::ShapeCanvas
|
1291
|
+
def on_left_click(pos)
|
1292
|
+
# HINT: overload it for custom actions...
|
1293
|
+
|
1294
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1295
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DOWN, self.id)
|
1296
|
+
evt.set_shape(self)
|
1297
|
+
evt.set_mouse_position(pos)
|
1298
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1299
|
+
end
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
# Event handler called when the shape is clicked by
|
1303
|
+
# the right mouse button. The function can be overridden if necessary.
|
1304
|
+
#
|
1305
|
+
# The function is called by the framework (by the shape canvas).
|
1306
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_RIGHT_DOWN event.
|
1307
|
+
# @param [Wx::Point] pos Current mouse position
|
1308
|
+
# @see Wx::SF::ShapeCanvas
|
1309
|
+
def on_right_click(pos)
|
1310
|
+
# HINT: overload it for custom actions...
|
1311
|
+
|
1312
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1313
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DOWN, self.id)
|
1314
|
+
evt.set_shape(self)
|
1315
|
+
evt.set_mouse_position(pos)
|
1316
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
# Event handler called when the shape is double-clicked by
|
1321
|
+
# the left mouse button. The function can be overridden if necessary.
|
1322
|
+
#
|
1323
|
+
# The function is called by the framework (by the shape canvas).
|
1324
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_LEFT_DCLICK event.
|
1325
|
+
# @param [Wx::Point] pos Current mouse position
|
1326
|
+
# @see Wx::SF::ShapeCanvas
|
1327
|
+
def on_left_double_click(pos)
|
1328
|
+
# HINT: overload it for custom actions...
|
1329
|
+
|
1330
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1331
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DCLICK, self.id)
|
1332
|
+
evt.set_shape(self)
|
1333
|
+
evt.set_mouse_position(pos)
|
1334
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1335
|
+
end
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
# Event handler called when the shape is double-clicked by
|
1339
|
+
# the right mouse button. The function can be overridden if necessary.
|
1340
|
+
#
|
1341
|
+
# The function is called by the framework (by the shape canvas).
|
1342
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_RIGHT_DCLICK event.
|
1343
|
+
# @param [Wx::Point] pos Current mouse position
|
1344
|
+
# @see Wx::SF::ShapeCanvas
|
1345
|
+
def on_right_double_click(pos)
|
1346
|
+
# HINT: overload it for custom actions...
|
1347
|
+
|
1348
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1349
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DCLICK, self.id)
|
1350
|
+
evt.set_shape(self)
|
1351
|
+
evt.set_mouse_position(pos)
|
1352
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
# Event handler called at the beginning of the shape dragging process.
|
1357
|
+
# The function can be overridden if necessary.
|
1358
|
+
#
|
1359
|
+
# The function is called by the framework (by the shape canvas).
|
1360
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_DRAG_BEGIN event.
|
1361
|
+
# @param [Wx::Point] pos Current mouse position
|
1362
|
+
# @see Wx::SF::ShapeCanvas
|
1363
|
+
def on_begin_drag(pos)
|
1364
|
+
# HINT: overload it for custom actions...
|
1365
|
+
|
1366
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1367
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_BEGIN, self.id)
|
1368
|
+
evt.set_shape(self)
|
1369
|
+
evt.set_mouse_position(pos)
|
1370
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1371
|
+
end
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
# Event handler called during the shape dragging process.
|
1375
|
+
# The function can be overridden if necessary.
|
1376
|
+
#
|
1377
|
+
# The function is called by the framework (by the shape canvas).
|
1378
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_DRAG event.
|
1379
|
+
# @param [Wx::Point] pos Current mouse position
|
1380
|
+
# @see Wx::SF::ShapeCanvas
|
1381
|
+
def on_dragging(pos)
|
1382
|
+
# HINT: overload it for custom actions...
|
1383
|
+
|
1384
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1385
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG, self.id)
|
1386
|
+
evt.set_shape(self)
|
1387
|
+
evt.set_mouse_position(pos)
|
1388
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1389
|
+
end
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
# Event handler called at the end of the shape dragging process.
|
1393
|
+
# The function can be overridden if necessary.
|
1394
|
+
#
|
1395
|
+
# The function is called by the framework (by the shape canvas).
|
1396
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_DRAG_END event.
|
1397
|
+
# @param [Wx::Point] pos Current mouse position
|
1398
|
+
# @see Wx::SF::ShapeCanvas
|
1399
|
+
def on_end_drag(pos)
|
1400
|
+
# HINT: overload it for custom actions...
|
1401
|
+
|
1402
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1403
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_END, self.id)
|
1404
|
+
evt.set_shape(self)
|
1405
|
+
evt.set_mouse_position(pos)
|
1406
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1407
|
+
end
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
# Event handler called when the user started to drag the shape handle.
|
1411
|
+
# The function can be overridden if necessary.
|
1412
|
+
#
|
1413
|
+
# The function is called by the framework (by the shape canvas).
|
1414
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_HANDLE_BEGIN event.
|
1415
|
+
# @param [Wx::SF::Shape::Handle] handle dragged handle
|
1416
|
+
def on_begin_handle(handle)
|
1417
|
+
# HINT: overload it for custom actions...
|
1418
|
+
|
1419
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1420
|
+
evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_BEGIN, self.id)
|
1421
|
+
evt.set_shape(self)
|
1422
|
+
evt.set_handle(handle)
|
1423
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
# Event handler called during dragging of the shape handle.
|
1428
|
+
# The function can be overridden if necessary.
|
1429
|
+
#
|
1430
|
+
# The function is called by the framework (by the shape canvas).
|
1431
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_HANDLE event.
|
1432
|
+
# @param [Wx::SF::Shape::Handle] handle dragged handle
|
1433
|
+
def on_handle(handle)
|
1434
|
+
# HINT: overload it for custom actions...
|
1435
|
+
|
1436
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1437
|
+
evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE, self.id)
|
1438
|
+
evt.set_shape(self)
|
1439
|
+
evt.set_handle(handle)
|
1440
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1441
|
+
end
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
# Event handler called when the user finished dragging of the shape handle.
|
1445
|
+
# The function can be overridden if necessary.
|
1446
|
+
#
|
1447
|
+
# The function is called by the framework (by the shape canvas).
|
1448
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_HANDLE_END event.
|
1449
|
+
# @param [Wx::SF::Shape::Handle] handle dragged handle
|
1450
|
+
def on_end_handle(handle)
|
1451
|
+
# HINT: overload it for custom actions...
|
1452
|
+
|
1453
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1454
|
+
evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_END, self.id)
|
1455
|
+
evt.set_shape(self)
|
1456
|
+
evt.set_handle(handle)
|
1457
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1458
|
+
end
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
# Event handler called when a mouse pointer enters the shape area.
|
1462
|
+
# The function can be overridden if necessary.
|
1463
|
+
#
|
1464
|
+
# The function is called by the framework (by the shape canvas).
|
1465
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_MOUSE_ENTER event.
|
1466
|
+
# @param [Wx::Point] pos Current mouse position
|
1467
|
+
def on_mouse_enter(pos)
|
1468
|
+
# HINT: overload it for custom actions...
|
1469
|
+
|
1470
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1471
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_ENTER, self.id)
|
1472
|
+
evt.set_shape(self)
|
1473
|
+
evt.set_mouse_position(pos)
|
1474
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1475
|
+
end
|
1476
|
+
end
|
1477
|
+
|
1478
|
+
# Event handler called when a mouse pointer moves above the shape area.
|
1479
|
+
# The function can be overridden if necessary.
|
1480
|
+
#
|
1481
|
+
# The function is called by the framework (by the shape canvas).
|
1482
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_MOUSE_OVER event.
|
1483
|
+
# @param [Wx::Point] pos Current mouse position
|
1484
|
+
def on_mouse_over(pos)
|
1485
|
+
# HINT: overload it for custom actions...
|
1486
|
+
|
1487
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1488
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_OVER, self.id)
|
1489
|
+
evt.set_shape(self)
|
1490
|
+
evt.set_mouse_position(pos)
|
1491
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
# Event handler called when a mouse pointer leaves the shape area.
|
1496
|
+
# The function can be overridden if necessary.
|
1497
|
+
#
|
1498
|
+
# The function is called by the framework (by the shape canvas).
|
1499
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_MOUSE_LEAVE event.
|
1500
|
+
# @param [Wx::Point] pos Current mouse position
|
1501
|
+
def on_mouse_leave(pos)
|
1502
|
+
# HINT: overload it for custom actions...
|
1503
|
+
|
1504
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1505
|
+
evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_LEAVE, self.id)
|
1506
|
+
evt.set_shape(self)
|
1507
|
+
evt.set_mouse_position(pos)
|
1508
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1509
|
+
end
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
# Event handler called when any key is pressed (in the shape canvas).
|
1513
|
+
# The function can be overridden if necessary.
|
1514
|
+
#
|
1515
|
+
# The function is called by the framework (by the shape canvas).
|
1516
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_KEYDOWN event.
|
1517
|
+
# @param [Integer] key The key code
|
1518
|
+
# @return The function must return true if the default event routine should be called
|
1519
|
+
# as well, otherwise false
|
1520
|
+
# @see Wx::SF::Shape::_on_key
|
1521
|
+
def on_key(key)
|
1522
|
+
# HINT: overload it for custom actions...
|
1523
|
+
|
1524
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1525
|
+
evt = Wx::SF::ShapeKeyEvent.new(Wx::SF::EVT_SF_SHAPE_KEYDOWN, self.id)
|
1526
|
+
evt.set_shape(self)
|
1527
|
+
evt.set_key_code(key)
|
1528
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1529
|
+
end
|
1530
|
+
|
1531
|
+
true
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
# Event handler called when any shape is dropped above this shape (and the dropped
|
1535
|
+
# shape is accepted as a child of this shape). The function can be overridden if necessary.
|
1536
|
+
#
|
1537
|
+
# The function is called by the framework (by the shape canvas).
|
1538
|
+
# Default implementation emits Wx::SF::EVT_SF_SHAPE_CHILD_DROP event.
|
1539
|
+
# @param [Wx::RealPoint] _pos Relative position of dropped shape
|
1540
|
+
# @param [Wx::SF::Shape] child dropped shape
|
1541
|
+
def on_child_dropped(_pos, child)
|
1542
|
+
# HINT: overload it for custom actions...
|
1543
|
+
|
1544
|
+
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
|
1545
|
+
evt = Wx::SF::ShapeChildDropEvent.new(Wx::SF::EVT_SF_SHAPE_CHILD_DROP, self.id)
|
1546
|
+
evt.set_shape(self)
|
1547
|
+
evt.set_child_shape(child)
|
1548
|
+
get_shape_canvas.get_event_handler.process_event(evt)
|
1549
|
+
end
|
1550
|
+
end
|
1551
|
+
|
1552
|
+
def to_s
|
1553
|
+
"#<#{self.class}:#{id.to_i}#{parent_shape ? " parent=#{parent_shape.id.to_i}" : ''}>"
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
def inspect
|
1557
|
+
to_s
|
1558
|
+
end
|
1559
|
+
|
1560
|
+
protected
|
1561
|
+
|
1562
|
+
# Draw the shape in the normal way. The function can be overridden if necessary.
|
1563
|
+
# @param [Wx::DC] _dc Reference to device context where the shape will be drawn to
|
1564
|
+
def draw_normal(_dc)
|
1565
|
+
# HINT: overload it for custom actions...
|
1566
|
+
end
|
1567
|
+
|
1568
|
+
# Draw the shape in the selected way. The function can be overridden if necessary.
|
1569
|
+
# @param [Wx::DC] dc Reference to device context where the shape will be drawn to
|
1570
|
+
def draw_selected(dc)
|
1571
|
+
# HINT: overload it for custom actions...
|
1572
|
+
|
1573
|
+
if has_style?(STYLE::SHOW_HANDLES)
|
1574
|
+
@handles.each { |h| h.send(:draw, dc) }
|
1575
|
+
end
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
# Draw the shape in the hover mode (the mouse cursor is above the shape).
|
1579
|
+
# The function can be overridden if necessary.
|
1580
|
+
# @param [Wx::DC] _dc Reference to device context where the shape will be drawn to
|
1581
|
+
def draw_hover(_dc)
|
1582
|
+
# HINT: overload it for custom actions...
|
1583
|
+
end
|
1584
|
+
|
1585
|
+
# Draw the shape in the highlighted mode (another shape is dragged over this
|
1586
|
+
# shape and this shape will accept the dragged one if it will be dropped on it).
|
1587
|
+
# The function can be overridden if necessary.
|
1588
|
+
# @param [Wx::DC] _dc Reference to device context where the shape will be drawn to
|
1589
|
+
def draw_highlighted(_dc)
|
1590
|
+
# HINT: overload it for custom actions...
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
# Draw shadow under the shape. The function can be overridden if necessary.
|
1594
|
+
# @param [Wx::DC] _dc Reference to device context where the shadow will be drawn to
|
1595
|
+
def draw_shadow(_dc)
|
1596
|
+
# HINT: overload it for custom actions...
|
1597
|
+
end
|
1598
|
+
|
1599
|
+
# Repaint the shape
|
1600
|
+
# @param [Wx::Rect] rct Canvas portion that should be updated
|
1601
|
+
# @param [Boolean] delayed If true then the shape canvas will be rather invalidated than refreshed.
|
1602
|
+
# @see Wx::SF::ShapeCanvas#invalidate_rect
|
1603
|
+
# @see Wx::SF::ShapeCanvas#refresh_invalidated_rect
|
1604
|
+
def refresh_rect(rct, delayed = false)
|
1605
|
+
if get_shape_canvas
|
1606
|
+
if delayed
|
1607
|
+
get_shape_canvas.invalidate_rect(rct)
|
1608
|
+
else
|
1609
|
+
get_shape_canvas.refresh_canvas(false, rct)
|
1610
|
+
end
|
1611
|
+
end
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
# Get absolute position of the shape parent.
|
1615
|
+
# @return [Wx::RealPoint] Absolute position of the shape parent if exists, otherwise 0,0
|
1616
|
+
def get_parent_absolute_position
|
1617
|
+
if parent = get_parent_shape
|
1618
|
+
if parent.is_a?(Wx::SF::LineShape) && @custom_dock_point != DEFAULT::DOCK_POINT
|
1619
|
+
return parent.get_dock_point_position(@custom_dock_point)
|
1620
|
+
else
|
1621
|
+
return parent.get_absolute_position
|
1622
|
+
end
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
Wx::RealPoint.new(0, 0)
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
private
|
1629
|
+
|
1630
|
+
# Auxiliary function called by GetNeighbours function.
|
1631
|
+
# @param [Class,nil] shapeInfo Line object type
|
1632
|
+
# @param [CONNECTMODE] condir Connection direction
|
1633
|
+
# @param [Boolean] direct Set this flag to TRUE if only closest shapes should be found,
|
1634
|
+
# otherwise also shapes connected by forked lines will be found (also
|
1635
|
+
# constants DIRECT and INDIRECT can be used)
|
1636
|
+
# @param [Array<Wx::SF::Shape] neighbours List to add neighbour shapes to
|
1637
|
+
# @param [Set<Wx::SF::Shape] processed set to keep track of processed shapes
|
1638
|
+
# @return [Array<Wx::SF::Shape] List of neighbour shapes
|
1639
|
+
# @see #get_neighbours
|
1640
|
+
def _get_neighbours(shape_info, condir, direct, neighbours, processed = ::Set.new)
|
1641
|
+
if @diagram
|
1642
|
+
return if processed.include?(self)
|
1643
|
+
|
1644
|
+
opposite = nil
|
1645
|
+
|
1646
|
+
lst_connections = get_assigned_connections(shape_info, condir)
|
1647
|
+
|
1648
|
+
# find opposite shapes in direct branches
|
1649
|
+
lst_connections.each do |line|
|
1650
|
+
case condir
|
1651
|
+
when CONNECTMODE::STARTING
|
1652
|
+
opposite = @diagram.find_shape(line.get_trg_shape_id)
|
1653
|
+
|
1654
|
+
when CONNECTMODE::ENDING
|
1655
|
+
opposite = @diagram.find_shape(line.get_src_shape_id)
|
1656
|
+
|
1657
|
+
when CONNECTMODE::BOTH
|
1658
|
+
if @id == line.get_src_shape_id
|
1659
|
+
opposite = @diagram.find_shape(line.get_trg_shape_id)
|
1660
|
+
else
|
1661
|
+
opposite = @diagram.find_shape(line.get_src_shape_id)
|
1662
|
+
end
|
1663
|
+
end
|
1664
|
+
|
1665
|
+
# add opposite shape to the list (if applicable)
|
1666
|
+
neighbours << opposite if opposite && !opposite.is_a?(Wx::SF::LineShape) && !neighbours.include?(opposite)
|
1667
|
+
|
1668
|
+
# find next shapes
|
1669
|
+
if !direct && opposite
|
1670
|
+
# in the case of indirect branches we must differentiate between connections
|
1671
|
+
# and ordinary shapes
|
1672
|
+
processed << self
|
1673
|
+
|
1674
|
+
if opposite.is_a?(Wx::SF::LineShape)
|
1675
|
+
case condir
|
1676
|
+
when CONNECTMODE::STARTING
|
1677
|
+
opposite = @diagram.find_shape(opposite.get_src_shape_id)
|
1678
|
+
|
1679
|
+
if opposite.is_a?(Wx::SF::LineShape)
|
1680
|
+
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
|
1681
|
+
elsif !neighbours.include?(opposite)
|
1682
|
+
neighbours << opposite
|
1683
|
+
end
|
1684
|
+
|
1685
|
+
when CONNECTMODE::ENDING
|
1686
|
+
opposite = @diagram.find_shape(opposite.get_trg_shape_id)
|
1687
|
+
|
1688
|
+
if opposite.is_a?(Wx::SF::LineShape)
|
1689
|
+
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
|
1690
|
+
elsif !neighbours.include?(opposite)
|
1691
|
+
neighbours << opposite
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
when CONNECTMODE::BOTH
|
1695
|
+
opposite = @diagram.find_shape(opposite.get_src_shape_id)
|
1696
|
+
if opposite.is_a?(Wx::SF::LineShape)
|
1697
|
+
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
|
1698
|
+
elsif !neighbours.include?(opposite)
|
1699
|
+
neighbours << opposite
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
opposite = @diagram.find_shape(opposite.get_trg_shape_id)
|
1703
|
+
if opposite.is_a?(Wx::SF::LineShape)
|
1704
|
+
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
|
1705
|
+
elsif !neighbours.include?(opposite)
|
1706
|
+
neighbours << opposite
|
1707
|
+
end
|
1708
|
+
end
|
1709
|
+
else
|
1710
|
+
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
|
1711
|
+
end
|
1712
|
+
end
|
1713
|
+
end
|
1714
|
+
end
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
# Auxiliary function called by GetCompleteBoundingBox function.
|
1718
|
+
# @param [Wx::Rect] rct bounding rectangle to update
|
1719
|
+
# @param [BBMODE] mask Bit mask of object types which should be included into calculation
|
1720
|
+
# @param [Set<Wx::SF::Shape] processed set to keep track of processed shapes
|
1721
|
+
# @return [Wx::Rect] bounding rectangle
|
1722
|
+
# @see BBMODE
|
1723
|
+
def _get_complete_bounding_box(rct, mask = BBMODE::ALL, processed = ::Set.new)
|
1724
|
+
return rct unless @diagram
|
1725
|
+
return rct if processed.include?(self)
|
1726
|
+
|
1727
|
+
processed << self
|
1728
|
+
|
1729
|
+
# first, get bounding box of the current shape
|
1730
|
+
if (mask & BBMODE::SELF) != 0
|
1731
|
+
if rct.is_empty
|
1732
|
+
rct.assign(get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i))
|
1733
|
+
else
|
1734
|
+
rct.union!(get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i))
|
1735
|
+
|
1736
|
+
# add also shadow offset if necessary
|
1737
|
+
if (mask & BBMODE::SHADOW) != 0 && has_style?(STYLE::SHOW_SHADOW) && get_parent_canvas
|
1738
|
+
n_offset = get_parent_canvas.get_shadow_offset
|
1739
|
+
|
1740
|
+
if n_offset.x < 0
|
1741
|
+
rct.set_x(rct.x + n_offset.x.to_i)
|
1742
|
+
rct.set_width(rct.width - n_offset.x.to_i)
|
1743
|
+
else
|
1744
|
+
rct.set_width(rct.width + n_offset.x.to_i)
|
1745
|
+
end
|
1746
|
+
|
1747
|
+
if n_offset.y < 0
|
1748
|
+
rct.set_y(rct.y + n_offset.y.to_i)
|
1749
|
+
rct.set_height(rct.height - n_offset.y.to_i)
|
1750
|
+
else
|
1751
|
+
rct.set_height(rct.height + n_offset.y.to_i)
|
1752
|
+
end
|
1753
|
+
end
|
1754
|
+
end
|
1755
|
+
else
|
1756
|
+
mask |= BBMODE::SELF
|
1757
|
+
end
|
1758
|
+
|
1759
|
+
# get list of all connection lines assigned to the shape and find their child shapes
|
1760
|
+
lst_children = []
|
1761
|
+
if (mask & BBMODE::CONNECTIONS) != 0
|
1762
|
+
lst_lines = get_assigned_connections(Wx::SF::LineShape, CONNECTMODE::BOTH)
|
1763
|
+
|
1764
|
+
lst_lines.each do |line|
|
1765
|
+
# rct.union!(line.get_bounding_box)
|
1766
|
+
lst_children << line
|
1767
|
+
|
1768
|
+
# get children of the connections
|
1769
|
+
line.get_child_shapes(ANY, NORECURSIVE, SEARCHMODE::BFS, lst_children)
|
1770
|
+
end
|
1771
|
+
end
|
1772
|
+
|
1773
|
+
# get children of this shape
|
1774
|
+
if (mask & BBMODE::CHILDREN) != 0
|
1775
|
+
get_child_shapes(ANY, NORECURSIVE, SEARCHMODE::BFS, lst_children)
|
1776
|
+
|
1777
|
+
# now, call this function for all children recursively...
|
1778
|
+
lst_children.each do |child|
|
1779
|
+
child.send(:_get_complete_bounding_box, rct, mask, processed)
|
1780
|
+
end
|
1781
|
+
end
|
1782
|
+
rct
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
# Original protected event handler called when the mouse pointer is moving around the shape canvas.
|
1786
|
+
# The function is called by the framework (by the shape canvas). After processing the event
|
1787
|
+
# relevant overridable event handlers are called.
|
1788
|
+
# @param [Wx::Point] pos Current mouse position
|
1789
|
+
# @see Wx::SF::Shape#on_mouse_enter
|
1790
|
+
# @see Wx::SF::Shape#on_mouse_over
|
1791
|
+
# @see Wx::SF::Shape#on_mouse_leave
|
1792
|
+
def _on_mouse_move(pos)
|
1793
|
+
return unless @diagram
|
1794
|
+
|
1795
|
+
if @visible && @active
|
1796
|
+
f_update_shape = false
|
1797
|
+
canvas = get_shape_canvas
|
1798
|
+
|
1799
|
+
# send the event to the shape handles too...
|
1800
|
+
@handles.each { |h| h.__send__(:_on_mouse_move, pos) }
|
1801
|
+
|
1802
|
+
# send the event to the connection points too...
|
1803
|
+
@connection_pts.each { |cp| cp.__send__(:_on_mouse_move, pos) }
|
1804
|
+
|
1805
|
+
# determine, whether the shape should be highlighted for any reason
|
1806
|
+
if canvas
|
1807
|
+
case canvas.get_mode
|
1808
|
+
when Wx::SF::ShapeCanvas::MODE::SHAPEMOVE
|
1809
|
+
if has_style?(STYLE::HIGHLIGHTING) && canvas.has_style?(Wx::SF::ShapeCanvas::STYLE::HIGHLIGHTING)
|
1810
|
+
shape_under_cursor = canvas.get_shape_under_cursor(Wx::SF::ShapeCanvas::SEARCHMODE::UNSELECTED)
|
1811
|
+
while shape_under_cursor
|
1812
|
+
break unless shape_under_cursor.has_style?(STYLE::PROPAGATE_HIGHLIGHTING)
|
1813
|
+
shape_under_cursor = shape_under_cursor.get_parent_shape
|
1814
|
+
end
|
1815
|
+
if shape_under_cursor == self
|
1816
|
+
f_update_shape = @highlight_parent = accept_currently_dragged_shapes
|
1817
|
+
end
|
1818
|
+
end
|
1819
|
+
|
1820
|
+
when Wx::SF::ShapeCanvas::MODE::HANDLEMOVE
|
1821
|
+
if has_style?(STYLE::HOVERING) && canvas.has_style?(Wx::SF::ShapeCanvas::STYLE::HOVERING)
|
1822
|
+
shape_under_cursor = canvas.get_shape_under_cursor(Wx::SF::ShapeCanvas::SEARCHMODE::UNSELECTED)
|
1823
|
+
while shape_under_cursor
|
1824
|
+
break unless shape_under_cursor.has_style?(STYLE::PROPAGATE_HOVERING)
|
1825
|
+
shape_under_cursor = shape_under_cursor.get_parent_shape
|
1826
|
+
end
|
1827
|
+
|
1828
|
+
f_update_shape = true if shape_under_cursor == self
|
1829
|
+
@highlight_parent = false
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
else
|
1833
|
+
if has_style?(STYLE::HOVERING) && canvas.has_style?(Wx::SF::ShapeCanvas::STYLE::HOVERING)
|
1834
|
+
shape_under_cursor = canvas.get_shape_under_cursor
|
1835
|
+
while shape_under_cursor
|
1836
|
+
break unless shape_under_cursor.has_style?(STYLE::PROPAGATE_HOVERING)
|
1837
|
+
shape_under_cursor = shape_under_cursor.get_parent_shape
|
1838
|
+
end
|
1839
|
+
|
1840
|
+
f_update_shape = true if shape_under_cursor == self
|
1841
|
+
@highlight_parent = false
|
1842
|
+
end
|
1843
|
+
end
|
1844
|
+
end
|
1845
|
+
|
1846
|
+
if contains?(pos) && f_update_shape
|
1847
|
+
if !@mouse_over
|
1848
|
+
@mouse_over = true
|
1849
|
+
on_mouse_enter(pos)
|
1850
|
+
refresh(DELAYED)
|
1851
|
+
else
|
1852
|
+
on_mouse_over(pos)
|
1853
|
+
end
|
1854
|
+
else
|
1855
|
+
if @mouse_over
|
1856
|
+
@mouse_over = false
|
1857
|
+
on_mouse_leave(pos)
|
1858
|
+
refresh(DELAYED)
|
1859
|
+
end
|
1860
|
+
end
|
1861
|
+
end
|
1862
|
+
end
|
1863
|
+
|
1864
|
+
# Original protected event handler called at the beginning of dragging process.
|
1865
|
+
# The function is called by the framework (by the shape canvas). After processing the event
|
1866
|
+
# an overridable event handler is called.
|
1867
|
+
# @param [Wx::Point] pos Current mouse position
|
1868
|
+
# @see Wx::SF::Shape#on_begin_drag
|
1869
|
+
def _on_begin_drag(pos)
|
1870
|
+
return unless @active
|
1871
|
+
|
1872
|
+
@first_move = true
|
1873
|
+
on_begin_drag(pos)
|
1874
|
+
|
1875
|
+
if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
|
1876
|
+
get_parent_shape.__send__(:_on_begin_drag, pos)
|
1877
|
+
end
|
1878
|
+
end
|
1879
|
+
|
1880
|
+
# Original protected event handler called during a dragging process.
|
1881
|
+
# The function is called by the framework (by the shape canvas). After processing the event
|
1882
|
+
# an overridable event handler is called.
|
1883
|
+
# @param [Wx::Point] pos Current mouse position
|
1884
|
+
# @see Wx::SF::Shape#on_dragging
|
1885
|
+
def _on_dragging(pos)
|
1886
|
+
return unless @diagram
|
1887
|
+
|
1888
|
+
if @visible && @active && has_style?(STYLE::POSITION_CHANGE)
|
1889
|
+
if @first_move
|
1890
|
+
@mouse_offset = Wx::RealPoint.new(pos.x, pos.y) - get_absolute_position
|
1891
|
+
end
|
1892
|
+
|
1893
|
+
# get shape BB BEFORE movement and combine it with BB of assigned lines
|
1894
|
+
prev_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
|
1895
|
+
|
1896
|
+
move_to(pos.x - @mouse_offset.x, pos.y - @mouse_offset.y)
|
1897
|
+
on_dragging(pos)
|
1898
|
+
|
1899
|
+
# GUI controls in child control shapes must be updated explicitly
|
1900
|
+
lst_child_ctrls = get_child_shapes(Wx::SF::ControlShape, RECURSIVE)
|
1901
|
+
lst_child_ctrls.each { |ctrl| ctrl.update_control }
|
1902
|
+
|
1903
|
+
# get shape BB AFTER movement and combine it with BB of assigned lines
|
1904
|
+
curr_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
|
1905
|
+
|
1906
|
+
# update canvas
|
1907
|
+
refresh_rect(prev_bb.union!(curr_bb), DELAYED)
|
1908
|
+
|
1909
|
+
@first_move = false
|
1910
|
+
end
|
1911
|
+
|
1912
|
+
if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
|
1913
|
+
get_parent_shape.__send__(:_on_dragging, pos)
|
1914
|
+
end
|
1915
|
+
end
|
1916
|
+
|
1917
|
+
# Original protected event handler called at the end of dragging process.
|
1918
|
+
# The function is called by the framework (by the shape canvas). After processing the event
|
1919
|
+
# an overridable event handler is called.
|
1920
|
+
# @param [Wx::Point] pos Current mouse position
|
1921
|
+
# @see Wx::SF::Shape#on_end_drag
|
1922
|
+
def _on_end_drag(pos)
|
1923
|
+
return unless @active
|
1924
|
+
|
1925
|
+
on_end_drag(pos)
|
1926
|
+
|
1927
|
+
if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
|
1928
|
+
get_parent_shape.__send__(:_on_end_drag, pos)
|
1929
|
+
end
|
1930
|
+
end
|
1931
|
+
|
1932
|
+
# Original protected event handler called when any key is pressed (in the shape canvas).
|
1933
|
+
# The function is called by the framework (by the shape canvas).
|
1934
|
+
# Default implementation performs operations necessary for proper shape's
|
1935
|
+
# moving and repainting.
|
1936
|
+
# @param [Integer] key The key code
|
1937
|
+
# @see Wx::SF::Shape#on_key
|
1938
|
+
def _on_key(key)
|
1939
|
+
canvas = get_shape_canvas
|
1940
|
+
|
1941
|
+
return unless canvas
|
1942
|
+
|
1943
|
+
if @visible && @active
|
1944
|
+
dx = 1.0
|
1945
|
+
dy = 1.0
|
1946
|
+
f_refresh_all = false
|
1947
|
+
|
1948
|
+
if canvas.has_style?(Wx::SF::ShapeCanvas::STYLE::GRID_USE)
|
1949
|
+
dx = canvas.get_grid_size.x
|
1950
|
+
dy = canvas.get_grid_size.y
|
1951
|
+
end
|
1952
|
+
|
1953
|
+
lst_selection = canvas.get_selected_shapes
|
1954
|
+
if (lst_selection.size > 1) && lst_selection.include?(self)
|
1955
|
+
f_refresh_all = true
|
1956
|
+
end
|
1957
|
+
|
1958
|
+
prev_bb = Wx::Rect.new
|
1959
|
+
if !f_refresh_all
|
1960
|
+
prev_bb = get_complete_bounding_box(prev_bb, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
|
1961
|
+
end
|
1962
|
+
|
1963
|
+
if on_key(key)
|
1964
|
+
case key
|
1965
|
+
when Wx::K_LEFT
|
1966
|
+
move_by(-dx, 0) if has_style?(STYLE::POSITION_CHANGE)
|
1967
|
+
|
1968
|
+
when Wx::K_RIGHT
|
1969
|
+
move_by(dx, 0) if has_style?(STYLE::POSITION_CHANGE)
|
1970
|
+
|
1971
|
+
when Wx::K_UP
|
1972
|
+
move_by(0, -dy) if has_style?(STYLE::POSITION_CHANGE)
|
1973
|
+
|
1974
|
+
when Wx::K_DOWN
|
1975
|
+
move_by(0, dy) if has_style?(STYLE::POSITION_CHANGE)
|
1976
|
+
end
|
1977
|
+
end
|
1978
|
+
|
1979
|
+
if !f_refresh_all
|
1980
|
+
curr_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
|
1981
|
+
|
1982
|
+
prev_bb.union!(curr_bb)
|
1983
|
+
refresh_rect(prev_bb, DELAYED)
|
1984
|
+
else
|
1985
|
+
canvas.refresh(false)
|
1986
|
+
end
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
# Original protected event handler called during dragging of the shape handle.
|
1991
|
+
# The function is called by the framework (by the shape canvas).
|
1992
|
+
# Default implementation manages the child shapes' alignment (if set).
|
1993
|
+
# @param [Wx::SF::Shape::Handle] handle dragged handle
|
1994
|
+
def _on_handle(handle)
|
1995
|
+
return unless @diagram
|
1996
|
+
|
1997
|
+
if @parent_shape
|
1998
|
+
prev_bb = get_grand_parent_shape.get_complete_bounding_box(Wx::Rect.new)
|
1999
|
+
else
|
2000
|
+
prev_bb = get_complete_bounding_box(Wx::Rect.new)
|
2001
|
+
end
|
2002
|
+
|
2003
|
+
# call appropriate user-defined handler
|
2004
|
+
on_handle(handle)
|
2005
|
+
|
2006
|
+
# align children
|
2007
|
+
@child_shapes.each do |child|
|
2008
|
+
if child.get_v_align != VALIGN::NONE || child.get_h_align != HALIGN::NONE
|
2009
|
+
child.do_alignment
|
2010
|
+
end
|
2011
|
+
end
|
2012
|
+
|
2013
|
+
# update shape
|
2014
|
+
update
|
2015
|
+
|
2016
|
+
if @parent_shape
|
2017
|
+
curr_bb = get_grand_parent_shape.get_complete_bounding_box(Wx::Rect.new)
|
2018
|
+
else
|
2019
|
+
curr_bb = get_complete_bounding_box(Wx::Rect.new)
|
2020
|
+
end
|
2021
|
+
|
2022
|
+
# refresh shape
|
2023
|
+
refresh_rect(curr_bb.union!(prev_bb), DELAYED)
|
2024
|
+
end
|
2025
|
+
|
2026
|
+
# Event handler called by ShapeCanvas to request,report canvas changes.
|
2027
|
+
# Default implementation does nothing.
|
2028
|
+
# @param [ShapeCanvas::CHANGE] _change change type indicator
|
2029
|
+
# @param [Array] _args any additional arguments
|
2030
|
+
# @return [Boolean]
|
2031
|
+
def _on_canvas(_change, *_args)
|
2032
|
+
# overridden in some derived shapes
|
2033
|
+
true
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
# Sets accepted children. Exclusively for deserialization.
|
2037
|
+
def set_accepted_children(set)
|
2038
|
+
@accepted_children.replace(set.collect { |e| e.is_a?(::String) ? ::Object.const_get(e) : e })
|
2039
|
+
end
|
2040
|
+
|
2041
|
+
# Sets accepted connection. Exclusively for deserialization.
|
2042
|
+
def set_accepted_connections(set)
|
2043
|
+
@accepted_connections.replace(set.collect { |e| e.is_a?(::String) ? ::Object.const_get(e) : e })
|
2044
|
+
end
|
2045
|
+
|
2046
|
+
# Sets accepted src neighbours. Exclusively for deserialization.
|
2047
|
+
def set_accepted_src_neighbours(set)
|
2048
|
+
@accepted_src_neighbours.replace(set.collect { |e| e.is_a?(::String) ? ::Object.const_get(e) : e })
|
2049
|
+
end
|
2050
|
+
|
2051
|
+
# Sets accepted trg neighbours. Exclusively for deserialization.
|
2052
|
+
def set_accepted_trg_neighbours(set)
|
2053
|
+
@accepted_trg_neighbours.replace(set.collect { |e| e.is_a?(::String) ? ::Object.const_get(e) : e })
|
2054
|
+
end
|
2055
|
+
|
2056
|
+
# Sets connection points. Exclusively for deserialization.
|
2057
|
+
def set_connection_points(list)
|
2058
|
+
@connection_pts.replace(list)
|
2059
|
+
@connection_pts.each { |cp| cp.parent_shape = self }
|
2060
|
+
end
|
2061
|
+
|
2062
|
+
def update_child_parents
|
2063
|
+
@child_shapes.each do |shape|
|
2064
|
+
shape.instance_variable_set(:@parent_shape, self)
|
2065
|
+
shape.send(:update_child_parents)
|
2066
|
+
end
|
2067
|
+
end
|
2068
|
+
|
2069
|
+
# (de-)serialize child shapes. Exclusively for deserialization.
|
2070
|
+
def serialize_child_shapes(*val)
|
2071
|
+
unless val.empty?
|
2072
|
+
@child_shapes = val.first
|
2073
|
+
update_child_parents
|
2074
|
+
end
|
2075
|
+
@child_shapes
|
2076
|
+
end
|
2077
|
+
|
2078
|
+
public
|
2079
|
+
|
2080
|
+
# Returns intersection point of two lines (if any)
|
2081
|
+
# @param [Wx::RealPoint] from1
|
2082
|
+
# @param [Wx::RealPoint] to1
|
2083
|
+
# @param [Wx::RealPoint] from2
|
2084
|
+
# @param [Wx::RealPoint] to2
|
2085
|
+
# @return [Wx::RealPoint,nil] intersection point or nil
|
2086
|
+
def self.lines_intersection(from1, to1, from2, to2)
|
2087
|
+
# create line 1 info
|
2088
|
+
a1 = to1.y - from1.y
|
2089
|
+
b1 = from1.x - to1.x
|
2090
|
+
c1 = -a1*from1.x - b1*from1.y
|
2091
|
+
|
2092
|
+
# create line 2 info
|
2093
|
+
a2 = to2.y - from2.y
|
2094
|
+
b2 = from2.x - to2.x
|
2095
|
+
c2 = -a2*from2.x - b2*from2.y
|
2096
|
+
|
2097
|
+
# check, whether the lines are parallel...
|
2098
|
+
ka = a1 / a2
|
2099
|
+
kb = b1 / b2
|
2100
|
+
|
2101
|
+
return nil if ka == kb
|
2102
|
+
|
2103
|
+
xi = (b1*c2 - c1*b2) / (a1*b2 - a2*b1)
|
2104
|
+
yi = -(a1*c2 - a2*c1) / (a1*b2 - a2*b1)
|
2105
|
+
|
2106
|
+
if( ((from1.x - xi)*(xi - to1.x) >= 0.0) &&
|
2107
|
+
((from2.x - xi)*(xi - to2.x) >= 0.0) &&
|
2108
|
+
((from1.y - yi)*(yi - to1.y) >= 0.0) &&
|
2109
|
+
((from2.y - yi)*(yi - to2.y) >= 0.0) )
|
2110
|
+
return Wx::RealPoint.new(xi, yi)
|
2111
|
+
end
|
2112
|
+
|
2113
|
+
nil
|
2114
|
+
end
|
2115
|
+
|
2116
|
+
# Allow shapes to call class method as instance method.
|
2117
|
+
def lines_intersection(*args)
|
2118
|
+
Shape.lines_intersection(*args)
|
2119
|
+
end
|
2120
|
+
|
2121
|
+
end # class Shape
|
2122
|
+
|
2123
|
+
end # module Wx::SF
|
2124
|
+
|
2125
|
+
require 'wx/shapes/shape_handle'
|
2126
|
+
|
2127
|
+
Dir[File.join(__dir__, 'shapes', '*.rb')].each do |f|
|
2128
|
+
require "wx/shapes/shapes/#{File.basename(f, '.rb')}"
|
2129
|
+
end
|