wxruby3-shapes 0.9.0.pre.beta.3 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/INSTALL.md +5 -7
- data/README.md +38 -6
- data/assets/logo.svg +339 -0
- data/assets/logo.xpm +60 -0
- data/assets/screenshot.png +0 -0
- data/assets/social.png +0 -0
- data/bin/wx-shapes +1 -1
- data/lib/wx/shapes/arrow_base.rb +4 -11
- data/lib/wx/shapes/arrows/circle_arrow.rb +22 -11
- data/lib/wx/shapes/arrows/circle_prong_arrow.rb +48 -0
- data/lib/wx/shapes/arrows/cross_bar_arrow.rb +57 -0
- data/lib/wx/shapes/arrows/cross_bar_circle_arrow.rb +56 -0
- data/lib/wx/shapes/arrows/cross_bar_prong_arrow.rb +49 -0
- data/lib/wx/shapes/arrows/crossed_circle.rb +46 -0
- data/lib/wx/shapes/arrows/cup_arrow.rb +65 -0
- data/lib/wx/shapes/arrows/diamond_arrow.rb +8 -13
- data/lib/wx/shapes/arrows/double_cross_bar_arrow.rb +27 -0
- data/lib/wx/shapes/arrows/filled_arrow.rb +60 -0
- data/lib/wx/shapes/arrows/line_arrow.rb +67 -0
- data/lib/wx/shapes/arrows/open_arrow.rb +22 -23
- data/lib/wx/shapes/arrows/prong_arrow.rb +42 -0
- data/lib/wx/shapes/arrows/solid_arrow.rb +21 -35
- data/lib/wx/shapes/arrows/square_arrow.rb +37 -0
- data/lib/wx/shapes/auto_layout.rb +2 -2
- data/lib/wx/shapes/base.rb +1 -1
- data/lib/wx/shapes/canvas_history.rb +20 -0
- data/lib/wx/shapes/connection_point.rb +10 -6
- data/lib/wx/shapes/diagram.rb +98 -78
- data/lib/wx/shapes/events.rb +8 -8
- data/lib/wx/shapes/printout.rb +3 -16
- data/lib/wx/shapes/serializable.rb +2 -436
- data/lib/wx/shapes/serialize/wx.rb +30 -18
- data/lib/wx/shapes/shape.rb +211 -168
- data/lib/wx/shapes/shape_canvas.rb +728 -267
- data/lib/wx/shapes/shape_data_object.rb +99 -18
- data/lib/wx/shapes/shape_handle.rb +18 -11
- data/lib/wx/shapes/shape_list.rb +34 -67
- data/lib/wx/shapes/shapes/bitmap_shape.rb +23 -24
- data/lib/wx/shapes/shapes/box_shape.rb +389 -0
- data/lib/wx/shapes/shapes/circle_shape.rb +19 -22
- data/lib/wx/shapes/shapes/control_shape.rb +77 -41
- data/lib/wx/shapes/shapes/curve_shape.rb +38 -31
- data/lib/wx/shapes/shapes/diamond_shape.rb +7 -17
- data/lib/wx/shapes/shapes/edit_text_shape.rb +6 -9
- data/lib/wx/shapes/shapes/ellipse_shape.rb +12 -15
- data/lib/wx/shapes/shapes/flex_grid_shape.rb +58 -33
- data/lib/wx/shapes/shapes/grid_shape.rb +259 -161
- data/lib/wx/shapes/shapes/line_shape.rb +155 -161
- data/lib/wx/shapes/shapes/manager_shape.rb +77 -0
- data/lib/wx/shapes/shapes/multi_sel_rect.rb +8 -8
- data/lib/wx/shapes/shapes/ortho_shape.rb +31 -36
- data/lib/wx/shapes/shapes/polygon_shape.rb +23 -29
- data/lib/wx/shapes/shapes/rect_shape.rb +95 -53
- data/lib/wx/shapes/shapes/round_ortho_shape.rb +6 -8
- data/lib/wx/shapes/shapes/round_rect_shape.rb +20 -24
- data/lib/wx/shapes/shapes/square_shape.rb +14 -17
- data/lib/wx/shapes/shapes/text_shape.rb +95 -53
- data/lib/wx/shapes/version.rb +1 -1
- data/lib/wx/shapes/wx.rb +16 -7
- data/lib/wx/wx-shapes/cmd/test.rb +1 -1
- data/samples/demo/arrows.json +1 -0
- data/samples/demo/arrows.yaml +793 -0
- data/samples/demo/art/HBox.xpm +22 -0
- data/samples/demo/art/VBox.xpm +22 -0
- data/samples/demo/art/logo.xpm +60 -0
- data/samples/demo/class.json +1 -0
- data/samples/demo/class.yaml +5631 -0
- data/samples/demo/demo.rb +301 -91
- data/samples/demo/dialogs.rb +1405 -0
- data/samples/demo/erd.json +1 -0
- data/samples/demo/erd.yaml +4072 -0
- data/samples/demo/frame_canvas.rb +409 -33
- data/samples/sample1/art/logo.xpm +60 -0
- data/samples/sample1/sample.rb +11 -11
- data/samples/sample2/art/logo.xpm +60 -0
- data/samples/sample2/sample.rb +2 -2
- data/samples/sample2/sample_shape.rb +15 -15
- data/samples/sample3/art/logo.xpm +60 -0
- data/samples/sample3/sample.rb +3 -3
- data/samples/sample4/art/logo.xpm +60 -0
- data/samples/sample4/sample.rb +2 -2
- data/tests/lib/wxapp_runner.rb +4 -0
- data/tests/serializer_tests.rb +8 -441
- data/tests/test_grid_shapes.rb +2 -2
- data/tests/test_serialize_xml.rb +17 -0
- data/tests/test_serialize_yaml.rb +2 -2
- metadata +78 -28
- data/lib/wx/shapes/serialize/core.rb +0 -40
- data/lib/wx/shapes/serialize/id.rb +0 -82
- data/lib/wx/shapes/serializer/json.rb +0 -258
- data/lib/wx/shapes/serializer/yaml.rb +0 -125
- data/samples/demo/art/sample.xpm +0 -251
- data/samples/sample1/art/sample.xpm +0 -251
- data/samples/sample2/art/sample.xpm +0 -251
- data/samples/sample3/art/sample.xpm +0 -251
- data/samples/sample4/art/sample.xpm +0 -251
@@ -2,6 +2,7 @@
|
|
2
2
|
# Copyright (c) M.J.N. Corino, The Netherlands
|
3
3
|
|
4
4
|
require 'wx/shapes/shapes/rect_shape'
|
5
|
+
require 'wx/shapes/shapes/manager_shape'
|
5
6
|
|
6
7
|
module Wx::SF
|
7
8
|
|
@@ -10,45 +11,75 @@ module Wx::SF
|
|
10
11
|
# shapes are aligned into defined grid with a behaviour similar to classic Wx::GridSizer class.
|
11
12
|
class GridShape < RectShape
|
12
13
|
|
14
|
+
include ManagerShape
|
15
|
+
|
13
16
|
# default values
|
14
17
|
module DEFAULT
|
15
|
-
# Default value of GridShape @rows data member.
|
16
|
-
ROWS = 3
|
17
18
|
# Default value of GridShape @cols data member.
|
18
|
-
|
19
|
+
COLUMNS = 3
|
19
20
|
# Default value of GridShape @cell_space data member.
|
20
21
|
CELLSPACE = 5
|
21
22
|
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# @param [Wx::RealPoint] pos Initial position
|
30
|
-
# @param [Wx::RealPoint] size Initial size
|
31
|
-
# @param [Integer] cols Number of grid rows
|
32
|
-
# @param [Integer] rows Number of grid columns
|
33
|
-
# @param [Integer] cell_space Additional space between managed shapes
|
34
|
-
# @param [Wx::SF::Diagram] diagram parent diagram
|
35
|
-
def initialize(*args)
|
36
|
-
if args.empty?
|
37
|
-
super()
|
38
|
-
@rows = DEFAULT::ROWS
|
39
|
-
@cols = DEFAULT::COLS
|
40
|
-
@cell_space = DEFAULT::CELLSPACE
|
41
|
-
else
|
42
|
-
pos, size, rows, cols, cell_space, diagram = args
|
43
|
-
super(pos, size, diagram)
|
44
|
-
@rows = rows || 0
|
45
|
-
@cols = cols || 0
|
46
|
-
@cell_space = cell_space || 0
|
24
|
+
class << self
|
25
|
+
|
26
|
+
# Returns the minimum size for *empty* grids
|
27
|
+
# @return [Wx::Size]
|
28
|
+
def get_min_size
|
29
|
+
@min_size ||= Wx::Size.new(20, 20)
|
47
30
|
end
|
31
|
+
alias :min_size :get_min_size
|
32
|
+
|
33
|
+
# Sets the minimum size for *empty* grids
|
34
|
+
# @overload set_min_size(sz)
|
35
|
+
# @param [Wx::Size] sz
|
36
|
+
# @overload set_min_size(w, h)
|
37
|
+
# @param [Integer] w
|
38
|
+
# @param [Integer] h
|
39
|
+
def set_min_size(arg1, arg2 = nil)
|
40
|
+
@min_size = if arg2.nil?
|
41
|
+
raise ArgumentError, 'Expected Wx::Size' unless Wx::Size === arg1
|
42
|
+
arg1
|
43
|
+
else
|
44
|
+
Wx::Size.new(arg1, arg2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias :min_size= :set_min_size
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
property :cols, :max_rows, :cell_space, :cells
|
52
|
+
|
53
|
+
# Constructor.
|
54
|
+
# @param [Wx::RealPoint,Wx::Point] pos Initial position
|
55
|
+
# @param [Wx::RealPoint,Wx::Size,Wx::Point] size Initial size
|
56
|
+
# @param [Integer] cols Number of grid columns
|
57
|
+
# @param [Integer] max_rows Maximum number of grid rows
|
58
|
+
# @param [Integer] cell_space Additional space between managed shapes
|
59
|
+
# @param [Wx::SF::Diagram] diagram parent diagram
|
60
|
+
def initialize(pos = Shape::DEFAULT::POSITION, size = RectShape::DEFAULT::SIZE,
|
61
|
+
cols: DEFAULT::COLUMNS, max_rows: 0, cell_space: DEFAULT::CELLSPACE, diagram: nil)
|
62
|
+
super(pos, size, diagram: diagram)
|
63
|
+
@cols = [1, cols.to_i].max # at least one column
|
64
|
+
@max_rows = [0, max_rows.to_i].max # no or >=1 max rows
|
65
|
+
@cell_space = [0, cell_space.to_i].max
|
66
|
+
@rows = 1
|
48
67
|
@cells = []
|
49
68
|
remove_style(Shape::STYLE::SIZE_CHANGE)
|
50
69
|
end
|
51
70
|
|
71
|
+
attr_reader :max_rows
|
72
|
+
|
73
|
+
# Sets the maximum number of rows for the grid (by default there this value is 0 == no maximum).
|
74
|
+
# In case the number of already managed cells exceeds the new maximum no change is made.
|
75
|
+
# @return [Integer] the active maximum
|
76
|
+
def set_max_rows(num)
|
77
|
+
# only change as long as this does not invalidate already managed cells
|
78
|
+
@max_rows = num unless (num * @cols) < @cells.size
|
79
|
+
@max_rows
|
80
|
+
end
|
81
|
+
alias :max_rows= :set_max_rows
|
82
|
+
|
52
83
|
# Set grid dimensions.
|
53
84
|
# @param [Integer] rows Number of rows
|
54
85
|
# @param [Integer] cols Number of columns
|
@@ -67,6 +98,13 @@ module Wx::SF
|
|
67
98
|
[@rows, @cols]
|
68
99
|
end
|
69
100
|
|
101
|
+
# Get number of available grid cells
|
102
|
+
# @return [Integer]
|
103
|
+
def get_cell_count
|
104
|
+
@rows * @cols
|
105
|
+
end
|
106
|
+
alias :cell_count :get_cell_count
|
107
|
+
|
70
108
|
# Set space between grid cells (managed shapes).
|
71
109
|
# @param [Integer] cellspace Cellspace size
|
72
110
|
def set_cell_space(cellspace)
|
@@ -81,14 +119,14 @@ module Wx::SF
|
|
81
119
|
end
|
82
120
|
alias :cell_space :get_cell_space
|
83
121
|
|
84
|
-
# Iterate all cells. If a block is given passes row, col and
|
122
|
+
# Iterate all cells. If a block is given passes row, col and shape (if any) for each cell to block.
|
85
123
|
# Returns Enumerator if no block given.
|
86
124
|
# @overload each_cell()
|
87
125
|
# @return [Enumerator]
|
88
126
|
# @overload each_cell(&block)
|
89
127
|
# @yieldparam [Integer] row
|
90
128
|
# @yieldparam [Integer] col
|
91
|
-
# @yieldparam [
|
129
|
+
# @yieldparam [shape,nil] shape
|
92
130
|
# @return [Object]
|
93
131
|
def each_cell(&block)
|
94
132
|
if block
|
@@ -108,40 +146,40 @@ module Wx::SF
|
|
108
146
|
end
|
109
147
|
end
|
110
148
|
|
149
|
+
# Clear the cell at given row and column index
|
150
|
+
# @param [Integer] row
|
151
|
+
# @param [Integer] col
|
152
|
+
# @return [Boolean] true if cell existed, false otherwise
|
153
|
+
# Note that this function doesn't remove managed (child) shapes from the parent grid shape
|
154
|
+
# (they are still its child shapes but aren't managed anymore).
|
111
155
|
def clear_cell(row, col)
|
112
156
|
if row>=0 && row<@rows && col>=0 && col<@cols
|
113
157
|
@cells[row*@cols + col] = nil
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
def get_cell(row, col)
|
118
|
-
if row>=0 && row<@rows && col>=0 && col<@cols
|
119
|
-
@cells[row*@cols + col]
|
158
|
+
true
|
159
|
+
else
|
160
|
+
false
|
120
161
|
end
|
121
162
|
end
|
122
163
|
|
123
164
|
# Get managed shape specified by lexicographic cell index.
|
124
165
|
# @overload get_managed_shape(index)
|
125
166
|
# @param [Integer] index Lexicographic index of requested shape
|
126
|
-
# @return [Shape] shape object of given cell index if exists, otherwise nil
|
167
|
+
# @return [Shape, nil] shape object of given cell index if exists, otherwise nil
|
127
168
|
# @overload get_managed_shape(row, col)
|
128
169
|
# @param [Integer] row Zero-base row index
|
129
170
|
# @param [Integer] col Zero-based column index
|
130
|
-
# @return [Shape] shape object stored in specified grid cell if exists, otherwise nil
|
171
|
+
# @return [Shape, nil] shape object stored in specified grid cell if exists, otherwise nil
|
131
172
|
def get_managed_shape(*args)
|
132
173
|
index = args.size == 1 ? args.first : (args[0]*@cols)+args[1]
|
133
|
-
|
134
|
-
return @child_shapes.find { |child| @cells[index] == child.id }
|
135
|
-
end
|
136
|
-
nil
|
174
|
+
@cells[index]
|
137
175
|
end
|
138
176
|
|
139
|
-
# Clear information about managed shapes and set number of rows
|
177
|
+
# Clear information about managed shapes and set number of rows to 1 (number of columns does not change).
|
140
178
|
#
|
141
179
|
# Note that this function doesn't remove managed (child) shapes from the parent grid shape
|
142
180
|
# (they are still its child shapes but aren't managed anymore).
|
143
181
|
def clear_grid
|
144
|
-
@rows =
|
182
|
+
@rows = 1
|
145
183
|
@cells = []
|
146
184
|
end
|
147
185
|
|
@@ -155,12 +193,14 @@ module Wx::SF
|
|
155
193
|
end
|
156
194
|
|
157
195
|
# Insert given shape to the grid at the given position.
|
196
|
+
# In case a shape is inserted in a cell already occupied the cells at that position and following will
|
197
|
+
# be shifted to the next lexicographic position.
|
198
|
+
# A maximum row setting may prevent a new shape of being inserted.
|
158
199
|
# @overload insert_to_grid(row, col, shape)
|
159
200
|
# Note that the grid can grow in a vertical direction only, so if the user specifies a desired
|
160
201
|
# horizontal position bigger than the current number of columns is then this function exits with
|
161
202
|
# an error (false) return value. If specified vertical position exceeds the number or grid rows than
|
162
|
-
# the grid is resized.
|
163
|
-
# lexicographic position.
|
203
|
+
# the grid is resized.
|
164
204
|
# @param [Integer] row Vertical position
|
165
205
|
# @param [Integer] col Horizontal position
|
166
206
|
# @param [Shape] shape shape to insert
|
@@ -168,9 +208,8 @@ module Wx::SF
|
|
168
208
|
# @overload insert_to_grid(index, shape)
|
169
209
|
# Note that the given index is a lexicographic position of inserted shape. The given shape is inserted before
|
170
210
|
# the existing item 'index', thus insert_to_grid(0, something) will insert an item in such way that it will become
|
171
|
-
# the first grid element.
|
172
|
-
#
|
173
|
-
# @param [Integer] index Lexicographic position of inserted shape
|
211
|
+
# the first grid element.
|
212
|
+
# @param [Integer] index Lexicographic position of inserted shape (>= 0)
|
174
213
|
# @param [Shape] shape shape to insert
|
175
214
|
# @return [Boolean] true on success, otherwise false
|
176
215
|
def insert_to_grid(*args)
|
@@ -178,10 +217,15 @@ module Wx::SF
|
|
178
217
|
row, col, shape = args
|
179
218
|
if shape && shape.is_a?(Shape) && is_child_accepted(shape.class)
|
180
219
|
# protect duplicated occurrences
|
181
|
-
return false if @cells.index(shape
|
220
|
+
return false if @cells.index(shape)
|
182
221
|
|
183
222
|
# protect unbounded horizontal index (grid can grow in a vertical direction only)
|
184
223
|
return false if col >= @cols
|
224
|
+
# protect maximum rows
|
225
|
+
index = row * @cols + col
|
226
|
+
return false if @max_rows > 0 &&
|
227
|
+
(row >= @max_rows || # cannot insert beyond max_rows
|
228
|
+
(@cells[index] && @cells.size >= (@max_rows * @cols))) # cannot grow beyond max_rows
|
185
229
|
|
186
230
|
# add the shape to the children list if necessary
|
187
231
|
unless @child_shapes.include?(shape)
|
@@ -192,23 +236,29 @@ module Wx::SF
|
|
192
236
|
end
|
193
237
|
end
|
194
238
|
|
195
|
-
@cells
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
@rows = @cells.size / @cols
|
239
|
+
if @cells[index]
|
240
|
+
@cells.insert(row * @cols + col, shape)
|
241
|
+
else
|
242
|
+
@cells[index] = shape
|
200
243
|
end
|
201
244
|
|
245
|
+
# adjust row count
|
246
|
+
update_rows
|
247
|
+
|
202
248
|
return true
|
203
249
|
end
|
204
250
|
else
|
205
251
|
index, shape = args
|
206
252
|
if shape && shape.is_a?(Shape) && is_child_accepted(shape.class)
|
207
253
|
# protect duplicated occurrences
|
208
|
-
return false if @cells.index(shape
|
254
|
+
return false if @cells.index(shape)
|
209
255
|
|
210
256
|
# protect unbounded index
|
211
|
-
|
257
|
+
max_size = @cols * @max_rows
|
258
|
+
return false if index < 0 ||
|
259
|
+
(@max_rows > 0 &&
|
260
|
+
(index >= max_size || # cannot insert beyond max_rows
|
261
|
+
(@cells[index] && @cells.size >= (@cols * @max_rows)))) # cannot grow beyond max_rows
|
212
262
|
|
213
263
|
# add the shape to the children list if necessary
|
214
264
|
unless @child_shapes.include?(shape)
|
@@ -219,170 +269,218 @@ module Wx::SF
|
|
219
269
|
end
|
220
270
|
end
|
221
271
|
|
222
|
-
@cells
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
@rows = @cells.size / @cols
|
272
|
+
if @cells[index]
|
273
|
+
@cells.insert(index, shape)
|
274
|
+
else
|
275
|
+
@cells[index] = shape
|
227
276
|
end
|
228
277
|
|
278
|
+
# adjust row count
|
279
|
+
update_rows
|
280
|
+
|
229
281
|
return true
|
230
282
|
end
|
231
283
|
end
|
232
284
|
false
|
233
285
|
end
|
234
286
|
|
235
|
-
# Remove
|
236
|
-
# Shifts any occupied cells beyond the cell containing the given
|
237
|
-
# @param [
|
287
|
+
# Remove given shape from the grid.
|
288
|
+
# Shifts any occupied cells beyond the cell containing the given shape to the previous lexicographic position.
|
289
|
+
# @param [Shape] shape shape which should be removed
|
290
|
+
# @return [Shape,nil] removed shape or nil if not found
|
238
291
|
# @note Note this does *not* remove the shape as a child shape.
|
239
|
-
def remove_from_grid(
|
240
|
-
@cells.delete(
|
292
|
+
def remove_from_grid(shape)
|
293
|
+
if @cells.delete(shape)
|
294
|
+
# remove trailing empty cells
|
295
|
+
@cells.pop until @cells.last
|
296
|
+
# update row count
|
297
|
+
@rows = @cells.size / @cols
|
298
|
+
@rows += 1 if (@cells.size % @cols) > 0
|
299
|
+
return shape
|
300
|
+
end
|
301
|
+
nil
|
241
302
|
end
|
242
303
|
|
243
|
-
# Update shape (align all child shapes
|
244
|
-
def update
|
304
|
+
# Update shape (align all child shapes and resize it to fit them)
|
305
|
+
def update(recurse= true)
|
245
306
|
# check for existence of de-assigned shapes
|
246
|
-
@cells.delete_if do |
|
247
|
-
|
307
|
+
@cells.delete_if do |shape|
|
308
|
+
shape && !@child_shapes.include?(shape)
|
248
309
|
end
|
249
310
|
|
250
|
-
# check whether all child shapes
|
311
|
+
# check whether all child shapes are present in the cells array...
|
251
312
|
@child_shapes.each do |child|
|
252
|
-
|
313
|
+
unless @cells.include?(child)
|
314
|
+
# see if we can match the position of the new child with the position of another
|
315
|
+
# (previously assigned) managed shape
|
316
|
+
position_child_cell(child)
|
317
|
+
end
|
253
318
|
end
|
254
319
|
|
255
320
|
# do self-alignment
|
256
321
|
do_alignment
|
257
|
-
|
258
|
-
# do alignment of shape's children
|
259
|
-
do_children_layout
|
260
|
-
|
322
|
+
|
261
323
|
# fit the shape to its children
|
262
324
|
fit_to_children unless has_style?(STYLE::NO_FIT_TO_CHILDREN)
|
263
325
|
|
264
326
|
# do it recursively on all parent shapes
|
265
|
-
get_parent_shape.update if get_parent_shape
|
327
|
+
get_parent_shape.update(recurse) if recurse && get_parent_shape
|
266
328
|
end
|
267
329
|
|
268
330
|
# Resize the shape to bound all child shapes. The function can be overridden if necessary.
|
269
331
|
def fit_to_children
|
270
|
-
#
|
271
|
-
|
272
|
-
# get bounding box of the shape and children set be inside it
|
332
|
+
# get bounding box of the shape and children set to be inside it
|
273
333
|
abs_pos = get_absolute_position
|
274
334
|
ch_bb = Wx::Rect.new(abs_pos.to_point, [0, 0])
|
275
335
|
|
276
336
|
@child_shapes.each do |child|
|
277
|
-
child.get_complete_bounding_box(ch_bb, BBMODE::SELF | BBMODE::CHILDREN) if child.has_style?(STYLE::ALWAYS_INSIDE)
|
337
|
+
ch_bb = child.get_complete_bounding_box(ch_bb, BBMODE::SELF | BBMODE::CHILDREN) if child.has_style?(STYLE::ALWAYS_INSIDE)
|
278
338
|
end
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
ch_bb.
|
283
|
-
|
339
|
+
|
340
|
+
if @child_shapes.empty?
|
341
|
+
# do not let the empty grid shape 'disappear' due to zero sizes...
|
342
|
+
ch_bb.size = GridShape.min_size - @cell_space
|
343
|
+
end
|
344
|
+
|
345
|
+
@rect_size = Wx::RealPoint.new(ch_bb.width + @cell_space, ch_bb.height + @cell_space)
|
346
|
+
end
|
347
|
+
|
348
|
+
# Event handler called when any shape is dropped above this shape (and the dropped
|
349
|
+
# shape is accepted as a child of this shape). The function can be overridden if necessary.
|
350
|
+
#
|
351
|
+
# The function is called by the framework (by the shape canvas).
|
352
|
+
# @param [Wx::RealPoint] _pos Relative position of dropped shape
|
353
|
+
# @param [Shape] child dropped shape
|
354
|
+
def on_child_dropped(_pos, child)
|
355
|
+
# see if we can match the position of the new child with the position of another
|
356
|
+
# (previously assigned) managed shape
|
357
|
+
if child && !child.is_a?(LineShape)
|
358
|
+
# insert child based on it's current (possibly dropped) position
|
359
|
+
position_child_cell(child)
|
284
360
|
end
|
285
|
-
|
286
|
-
@rect_size = Wx::RealPoint.new(ch_bb.width + 2*@cell_space, ch_bb.height + 2*@cell_space)
|
287
361
|
end
|
288
362
|
|
363
|
+
protected
|
364
|
+
|
289
365
|
# Do layout of assigned child shapes
|
290
366
|
def do_children_layout
|
291
367
|
return if @cols == 0 || @rows == 0
|
292
|
-
|
293
|
-
max_rect = Wx::Rect.new(0,0,0,0)
|
294
|
-
|
295
|
-
# get maximum size of all managed (child) shapes
|
296
|
-
@child_shapes.each do |shape|
|
297
|
-
curr_rect = shape.get_bounding_box
|
298
368
|
|
299
|
-
|
300
|
-
max_rect.set_height(curr_rect.height) if shape.get_v_align != VALIGN::EXPAND && curr_rect.height > max_rect.height
|
301
|
-
end
|
369
|
+
max_size = get_max_child_size
|
302
370
|
|
303
|
-
@cells.each_with_index do |
|
304
|
-
if
|
305
|
-
shape = @child_shapes[id]
|
371
|
+
@cells.each_with_index do |shape, i|
|
372
|
+
if shape
|
306
373
|
col = (i % @cols)
|
307
374
|
row = (i / @cols)
|
308
375
|
|
309
|
-
fit_shape_to_rect(shape, Wx::Rect.new(col*
|
310
|
-
row*
|
311
|
-
|
376
|
+
fit_shape_to_rect(shape, Wx::Rect.new(col*max_size.width + (col+1)*@cell_space,
|
377
|
+
row*max_size.height + (row+1)*@cell_space,
|
378
|
+
max_size.width, max_size.height))
|
312
379
|
end
|
313
380
|
end
|
314
381
|
end
|
315
382
|
|
316
|
-
#
|
317
|
-
#
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
append_to_grid(child) if child && !child.is_a?(LineShape)
|
383
|
+
# called after the shape has been newly imported/pasted/dropped
|
384
|
+
# checks the cells for stale links
|
385
|
+
def on_import
|
386
|
+
# check for existence of non-included shapes
|
387
|
+
@cells.delete_if do |shape|
|
388
|
+
shape && !@child_shapes.include?(shape)
|
389
|
+
end
|
324
390
|
end
|
325
391
|
|
326
|
-
|
392
|
+
# update row count
|
393
|
+
def update_rows
|
394
|
+
# remove trailing empty cells (if any)
|
395
|
+
@cells.pop until @cells.last
|
396
|
+
@rows = @cells.size / @cols
|
397
|
+
@rows += 1 if (@cells.size % @cols) > 0
|
398
|
+
end
|
327
399
|
|
328
|
-
#
|
329
|
-
#
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
400
|
+
# returns maximum size of all managed (child) shapes
|
401
|
+
# @return [Wx::Size]
|
402
|
+
def get_max_child_size
|
403
|
+
@child_shapes.inject(Wx::Size.new(0, 0)) do |max_size, shape|
|
404
|
+
child_rect = shape.get_bounding_box
|
405
|
+
|
406
|
+
max_size.set_width(child_rect.width) if shape.get_h_align != HALIGN::EXPAND && child_rect.width > max_size.width
|
407
|
+
max_size.set_height(child_rect.height) if shape.get_v_align != VALIGN::EXPAND && child_rect.height > max_size.height
|
408
|
+
max_size
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def find_cell(child_rect)
|
413
|
+
max_size = get_max_child_size
|
414
|
+
child_centre = child_rect.get_position
|
415
|
+
child_centre.x += child_rect.width/2
|
416
|
+
child_centre.y += child_rect.height/2
|
417
|
+
# find the cell index where the new or dragged child is positioned above and in front of
|
418
|
+
offset = get_bounding_box.top_left
|
419
|
+
cell_count.times.find do |cell|
|
420
|
+
col = (cell % @cols)
|
421
|
+
row = (cell / @cols)
|
422
|
+
cell_rct = Wx::Rect.new(col*max_size.width + (col+1)*@cell_space,
|
423
|
+
row*max_size.height + (row+1)*@cell_space,
|
424
|
+
max_size.width, max_size.height).offset!(offset)
|
425
|
+
child_centre.x <= cell_rct.right && child_centre.y <= cell_rct.bottom
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def position_child_cell(child)
|
430
|
+
crct = child.get_bounding_box
|
431
|
+
# see if the child already had a cell in this grid (moving a child)
|
432
|
+
child_index = @cells.index(child)
|
433
|
+
# if the child intersects this box shape we look
|
434
|
+
# for the cell it should go into (if any)
|
435
|
+
if @cells.size>0 && intersects?(crct)
|
436
|
+
# find the cell index where the new child is positioned above and in front of
|
437
|
+
index = find_cell(crct)
|
438
|
+
# now see where to put the new/moved child
|
439
|
+
if index # found a matching cell?
|
440
|
+
# if the child being inserted already had a slot
|
441
|
+
if child_index
|
442
|
+
# if the newly found index equals the existing index there is nothing to do
|
443
|
+
return if child_index == index
|
444
|
+
# else clear the child's current cell; this provides support for reordering child shapes by dragging
|
445
|
+
@cells[child_index] = nil
|
446
|
+
end
|
447
|
+
# insert/move the child
|
448
|
+
unless insert_to_grid(index, child)
|
449
|
+
# if failed to insert (max rows exceeded?) restore the child to it's previous cell
|
450
|
+
if child_index
|
451
|
+
@cells[child_index] = child
|
452
|
+
else # or make the child a toplevel shape
|
453
|
+
# move relative to current parent (if any)
|
454
|
+
child.move_by(child.get_parent_shape.get_absolute_position) if child.get_parent_shape
|
455
|
+
diagram.reparent_shape(child, nil)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
return # done
|
352
459
|
end
|
353
|
-
else
|
354
|
-
shape.set_relative_position(prev_pos.x, rct.top)
|
355
460
|
end
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
#
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
if shape.has_style?(STYLE::SIZE_CHANGE)
|
369
|
-
shape.set_relative_position(rct.left + shape.get_h_border, prev_pos.y)
|
370
|
-
shape.scale((rct.width - 2*shape.get_h_border).to_f/shape_bb.width, 1.9)
|
461
|
+
# otherwise append
|
462
|
+
# clear the child's current cell if already part of grid
|
463
|
+
@cells[child_index] = nil if child_index
|
464
|
+
# append
|
465
|
+
unless append_to_grid(child)
|
466
|
+
# if failed to append (max rows exceeded?) restore the child to it's previous cell
|
467
|
+
if child_index
|
468
|
+
@cells[child_index] = child
|
469
|
+
else # or make the child a toplevel shape
|
470
|
+
# move relative to current parent (if any)
|
471
|
+
child.move_by(child.get_parent_shape.get_absolute_position) if child.get_parent_shape
|
472
|
+
diagram.reparent_shape(child, nil)
|
371
473
|
end
|
372
|
-
else
|
373
|
-
shape.set_relative_position(rct.left, prev_pos.y)
|
374
474
|
end
|
375
475
|
end
|
376
476
|
|
377
477
|
private
|
378
478
|
|
379
|
-
#
|
479
|
+
# (de-)serialization only.
|
380
480
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
def set_rows(num)
|
385
|
-
@rows = num
|
481
|
+
# default deserialization finalizer
|
482
|
+
def create
|
483
|
+
update_rows
|
386
484
|
end
|
387
485
|
|
388
486
|
def get_cols
|