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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +12 -0
  3. data/CREDITS.md +18 -0
  4. data/INSTALL.md +39 -0
  5. data/LICENSE +21 -0
  6. data/README.md +118 -0
  7. data/assets/screenshot.png +0 -0
  8. data/bin/wx-shapes +9 -0
  9. data/lib/wx/shapes/arrow_base.rb +86 -0
  10. data/lib/wx/shapes/arrows/circle_arrow.rb +39 -0
  11. data/lib/wx/shapes/arrows/diamond_arrow.rb +33 -0
  12. data/lib/wx/shapes/arrows/open_arrow.rb +56 -0
  13. data/lib/wx/shapes/arrows/solid_arrow.rb +69 -0
  14. data/lib/wx/shapes/art/shape_canvas/page.xpm +73 -0
  15. data/lib/wx/shapes/auto_layout.rb +358 -0
  16. data/lib/wx/shapes/base.rb +33 -0
  17. data/lib/wx/shapes/canvas_history.rb +84 -0
  18. data/lib/wx/shapes/connection_point.rb +238 -0
  19. data/lib/wx/shapes/core.rb +19 -0
  20. data/lib/wx/shapes/diagram.rb +659 -0
  21. data/lib/wx/shapes/events.rb +389 -0
  22. data/lib/wx/shapes/printout.rb +136 -0
  23. data/lib/wx/shapes/serializable.rb +440 -0
  24. data/lib/wx/shapes/serialize/core.rb +40 -0
  25. data/lib/wx/shapes/serialize/id.rb +82 -0
  26. data/lib/wx/shapes/serialize/wx.rb +104 -0
  27. data/lib/wx/shapes/serializer/json.rb +258 -0
  28. data/lib/wx/shapes/serializer/yaml.rb +125 -0
  29. data/lib/wx/shapes/shape.rb +2129 -0
  30. data/lib/wx/shapes/shape_canvas.rb +3285 -0
  31. data/lib/wx/shapes/shape_data_object.rb +43 -0
  32. data/lib/wx/shapes/shape_handle.rb +287 -0
  33. data/lib/wx/shapes/shape_list.rb +161 -0
  34. data/lib/wx/shapes/shapes/bitmap_shape.rb +257 -0
  35. data/lib/wx/shapes/shapes/circle_shape.rb +136 -0
  36. data/lib/wx/shapes/shapes/control_shape.rb +483 -0
  37. data/lib/wx/shapes/shapes/curve_shape.rb +231 -0
  38. data/lib/wx/shapes/shapes/diamond_shape.rb +62 -0
  39. data/lib/wx/shapes/shapes/edit_text_shape.rb +317 -0
  40. data/lib/wx/shapes/shapes/ellipse_shape.rb +106 -0
  41. data/lib/wx/shapes/shapes/flex_grid_shape.rb +78 -0
  42. data/lib/wx/shapes/shapes/grid_shape.rb +404 -0
  43. data/lib/wx/shapes/shapes/line_shape.rb +907 -0
  44. data/lib/wx/shapes/shapes/multi_sel_rect.rb +214 -0
  45. data/lib/wx/shapes/shapes/ortho_shape.rb +357 -0
  46. data/lib/wx/shapes/shapes/polygon_shape.rb +294 -0
  47. data/lib/wx/shapes/shapes/rect_shape.rb +378 -0
  48. data/lib/wx/shapes/shapes/round_ortho_shape.rb +131 -0
  49. data/lib/wx/shapes/shapes/round_rect_shape.rb +142 -0
  50. data/lib/wx/shapes/shapes/square_shape.rb +119 -0
  51. data/lib/wx/shapes/shapes/text_shape.rb +324 -0
  52. data/lib/wx/shapes/thumbnail.rb +234 -0
  53. data/lib/wx/shapes/version.rb +12 -0
  54. data/lib/wx/shapes/wx.rb +29 -0
  55. data/lib/wx/shapes.rb +18 -0
  56. data/lib/wx/wx-shapes/base.rb +87 -0
  57. data/lib/wx/wx-shapes/cmd/sampler.rb +58 -0
  58. data/lib/wx/wx-shapes/cmd/test.rb +27 -0
  59. data/rakelib/yard/templates/default/fulldoc/html/css/wxruby3.css +7 -0
  60. data/rakelib/yard/templates/default/layout/html/setup.rb +5 -0
  61. data/rakelib/yard/yard/relative_markdown_links/version.rb +8 -0
  62. data/rakelib/yard/yard/relative_markdown_links.rb +39 -0
  63. data/rakelib/yard/yard-custom-templates.rb +2 -0
  64. data/rakelib/yard/yard-relative_markdown_links.rb +4 -0
  65. data/samples/demo/art/AlignBottom.xpm +35 -0
  66. data/samples/demo/art/AlignCenter.xpm +35 -0
  67. data/samples/demo/art/AlignLeft.xpm +35 -0
  68. data/samples/demo/art/AlignMiddle.xpm +35 -0
  69. data/samples/demo/art/AlignRight.xpm +35 -0
  70. data/samples/demo/art/AlignTop.xpm +35 -0
  71. data/samples/demo/art/Bitmap.xpm +25 -0
  72. data/samples/demo/art/Circle.xpm +22 -0
  73. data/samples/demo/art/Curve.xpm +21 -0
  74. data/samples/demo/art/Diamond.xpm +22 -0
  75. data/samples/demo/art/EditText.xpm +21 -0
  76. data/samples/demo/art/Ellipse.xpm +22 -0
  77. data/samples/demo/art/FixedRect.xpm +22 -0
  78. data/samples/demo/art/FlexGrid.xpm +22 -0
  79. data/samples/demo/art/GC.xpm +23 -0
  80. data/samples/demo/art/Grid.xpm +22 -0
  81. data/samples/demo/art/Line.xpm +21 -0
  82. data/samples/demo/art/NoSource.xpm +69 -0
  83. data/samples/demo/art/OrthoLine.xpm +21 -0
  84. data/samples/demo/art/Rect.xpm +22 -0
  85. data/samples/demo/art/RoundOrthoLine.xpm +21 -0
  86. data/samples/demo/art/RoundRect.xpm +22 -0
  87. data/samples/demo/art/Shadow.xpm +23 -0
  88. data/samples/demo/art/StandAloneLine.xpm +22 -0
  89. data/samples/demo/art/Text.xpm +21 -0
  90. data/samples/demo/art/Tool.xpm +23 -0
  91. data/samples/demo/art/sample.xpm +251 -0
  92. data/samples/demo/demo.rb +658 -0
  93. data/samples/demo/frame_canvas.rb +422 -0
  94. data/samples/demo/images/motyl.bmp +0 -0
  95. data/samples/demo/images/motyl2.bmp +0 -0
  96. data/samples/sample1/art/sample.xpm +251 -0
  97. data/samples/sample1/sample.rb +263 -0
  98. data/samples/sample2/art/sample.xpm +251 -0
  99. data/samples/sample2/sample.rb +133 -0
  100. data/samples/sample2/sample_canvas.rb +35 -0
  101. data/samples/sample2/sample_shape.rb +108 -0
  102. data/samples/sample3/art/sample.xpm +251 -0
  103. data/samples/sample3/sample.rb +281 -0
  104. data/samples/sample4/art/sample.xpm +251 -0
  105. data/samples/sample4/sample.rb +180 -0
  106. data/tests/art/motyl.bmp +0 -0
  107. data/tests/lib/wxapp_runner.rb +64 -0
  108. data/tests/serializer_tests.rb +521 -0
  109. data/tests/test_grid_shapes.rb +42 -0
  110. data/tests/test_serialize.rb +7 -0
  111. data/tests/test_serialize_yaml.rb +17 -0
  112. metadata +242 -0
@@ -0,0 +1,404 @@
1
+ # Wx::SF::GridShape - grid shape class
2
+ # Copyright (c) M.J.N. Corino, The Netherlands
3
+
4
+ require 'wx/shapes/shapes/rect_shape'
5
+
6
+ module Wx::SF
7
+
8
+ # Class encapsulates a rectangular shape derived from Wx::SF::RectShape class which acts as a grid-based
9
+ # container able to manage other assigned child shapes (it can control their position). The managed
10
+ # shapes are aligned into defined grid with a behaviour similar to classic Wx::GridSizer class.
11
+ class GridShape < RectShape
12
+
13
+ # default values
14
+ module DEFAULT
15
+ # Default value of GridShape @rows data member.
16
+ ROWS = 3
17
+ # Default value of GridShape @cols data member.
18
+ COLS = 3
19
+ # Default value of GridShape @cell_space data member.
20
+ CELLSPACE = 5
21
+ end
22
+
23
+ property :rows, :cols, :cell_space, :cells
24
+
25
+ # @overload initialize()
26
+ # Default constructor.
27
+ # @overload initialize(pos, size, rows, cols, cell_space, diagram)
28
+ # User constructor.
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
47
+ end
48
+ @cells = []
49
+ remove_style(Shape::STYLE::SIZE_CHANGE)
50
+ end
51
+
52
+ # Set grid dimensions.
53
+ # @param [Integer] rows Number of rows
54
+ # @param [Integer] cols Number of columns
55
+ def set_dimensions(rows, cols)
56
+ return if (new_size = rows * cols) == 0
57
+
58
+ @rows = rows
59
+ @cols = cols
60
+
61
+ @cells.slice!(0, new_size) if new_size < @cells.size
62
+ end
63
+
64
+ # Get grid dimensions.
65
+ # @return [Array(Integer,Integer)] row and col numbers
66
+ def get_dimensions
67
+ [@rows, @cols]
68
+ end
69
+
70
+ # Set space between grid cells (managed shapes).
71
+ # @param [Integer] cellspace Cellspace size
72
+ def set_cell_space(cellspace)
73
+ @cell_space = cellspace
74
+ end
75
+ alias :cell_space= :set_cell_space
76
+
77
+ # Get space between grid cells (managed shapes).
78
+ # @return [Integer] Cellspace size
79
+ def get_cell_space
80
+ @cell_space
81
+ end
82
+ alias :cell_space :get_cell_space
83
+
84
+ # Iterate all cells. If a block is given passes row, col and id for each cell to block.
85
+ # Returns Enumerator if no block given.
86
+ # @overload each_cell()
87
+ # @return [Enumerator]
88
+ # @overload each_cell(&block)
89
+ # @yieldparam [Integer] row
90
+ # @yieldparam [Integer] col
91
+ # @yieldparam [Wx::SF::Serializable::ID,nil] id
92
+ # @return [Object]
93
+ def each_cell(&block)
94
+ if block
95
+ @rows.times do |row|
96
+ @cols.times do |col|
97
+ block.call(row, col, @cells[row*@cols + col])
98
+ end
99
+ end
100
+ else
101
+ ::Enumerator.new do |y|
102
+ @rows.times do |row|
103
+ @cols.times do |col|
104
+ y << [row, col, @cells[row*@cols + col]]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def clear_cell(row, col)
112
+ if row>=0 && row<@rows && col>=0 && col<@cols
113
+ @cells[row*@cols + col] = nil
114
+ end
115
+ end
116
+
117
+ def get_cell(row, col)
118
+ if row>=0 && row<@rows && col>=0 && col<@cols
119
+ @cells[row*@cols + col]
120
+ end
121
+ end
122
+
123
+ # Get managed shape specified by lexicographic cell index.
124
+ # @overload get_managed_shape(index)
125
+ # @param [Integer] index Lexicographic index of requested shape
126
+ # @return [Shape] shape object of given cell index if exists, otherwise nil
127
+ # @overload get_managed_shape(row, col)
128
+ # @param [Integer] row Zero-base row index
129
+ # @param [Integer] col Zero-based column index
130
+ # @return [Shape] shape object stored in specified grid cell if exists, otherwise nil
131
+ def get_managed_shape(*args)
132
+ index = args.size == 1 ? args.first : (args[0]*@cols)+args[1]
133
+ if index>=0 && index<@cells.size && @cells[index]
134
+ return @child_shapes.find { |child| @cells[index] == child.id }
135
+ end
136
+ nil
137
+ end
138
+
139
+ # Clear information about managed shapes and set number of rows and columns to zero.
140
+ #
141
+ # Note that this function doesn't remove managed (child) shapes from the parent grid shape
142
+ # (they are still its child shapes but aren't managed anymore).
143
+ def clear_grid
144
+ @rows = @cols = 0
145
+ @cells = []
146
+ end
147
+
148
+ # Append given shape to the grid at the last managed position.
149
+ # @param [Shape] shape shape to append
150
+ def append_to_grid(shape)
151
+ row = @cells.size / @cols
152
+ col = @cells.size - row*@cols
153
+
154
+ insert_to_grid(row, col, shape)
155
+ end
156
+
157
+ # Insert given shape to the grid at the given position.
158
+ # @overload insert_to_grid(row, col, shape)
159
+ # Note that the grid can grow in a vertical direction only, so if the user specifies a desired
160
+ # horizontal position bigger than the current number of columns is then this function exits with
161
+ # an error (false) return value. If specified vertical position exceeds the number or grid rows than
162
+ # the grid is resized. Any occupied grid cells at given position or beyond will be shifted to the next
163
+ # lexicographic position.
164
+ # @param [Integer] row Vertical position
165
+ # @param [Integer] col Horizontal position
166
+ # @param [Shape] shape shape to insert
167
+ # @return [Boolean] true on success, otherwise false
168
+ # @overload insert_to_grid(index, shape)
169
+ # Note that the given index is a lexicographic position of inserted shape. The given shape is inserted before
170
+ # 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. Any occupied grid cells at given position or beyond will be shifted to the next
172
+ # lexicographic position.
173
+ # @param [Integer] index Lexicographic position of inserted shape
174
+ # @param [Shape] shape shape to insert
175
+ # @return [Boolean] true on success, otherwise false
176
+ def insert_to_grid(*args)
177
+ if args.size > 2
178
+ row, col, shape = args
179
+ if shape && shape.is_a?(Shape) && is_child_accepted(shape.class)
180
+ # protect duplicated occurrences
181
+ return false if @cells.index(shape.id)
182
+
183
+ # protect unbounded horizontal index (grid can grow in a vertical direction only)
184
+ return false if col >= @cols
185
+
186
+ # add the shape to the children list if necessary
187
+ unless @child_shapes.include?(shape)
188
+ if @diagram
189
+ @diagram.reparent_shape(shape, self)
190
+ else
191
+ shape.set_parent_shape(self)
192
+ end
193
+ end
194
+
195
+ @cells.insert(row * @cols + col, shape.id)
196
+
197
+ # adjust row count if necessary
198
+ if @cells.size > (@rows * @cols)
199
+ @rows = @cells.size / @cols
200
+ end
201
+
202
+ return true
203
+ end
204
+ else
205
+ index, shape = args
206
+ if shape && shape.is_a?(Shape) && is_child_accepted(shape.class)
207
+ # protect duplicated occurrences
208
+ return false if @cells.index(shape.id)
209
+
210
+ # protect unbounded index
211
+ return false if index >= (@rows * @cols)
212
+
213
+ # add the shape to the children list if necessary
214
+ unless @child_shapes.include?(shape)
215
+ if @diagram
216
+ @diagram.reparent_shape(shape, self)
217
+ else
218
+ shape.set_parent_shape(self)
219
+ end
220
+ end
221
+
222
+ @cells.insert(index, shape.id)
223
+
224
+ # adjust row count if necessary
225
+ if @cells.size > (@rows * @cols)
226
+ @rows = @cells.size / @cols
227
+ end
228
+
229
+ return true
230
+ end
231
+ end
232
+ false
233
+ end
234
+
235
+ # Remove shape with given ID from the grid.
236
+ # Shifts any occupied cells beyond the cell containing the given id to the previous lexicographic position.
237
+ # @param [Serializable::ID] id ID of shape which should be removed
238
+ # @note Note this does *not* remove the shape as a child shape.
239
+ def remove_from_grid(id)
240
+ @cells.delete(id)
241
+ end
242
+
243
+ # Update shape (align all child shapes an resize it to fit them)
244
+ def update
245
+ # check for existence of de-assigned shapes
246
+ @cells.delete_if do |id|
247
+ @child_shapes.find { |child| child.id == id }.nil?
248
+ end
249
+
250
+ # check whether all child shapes' IDs are present in the cells array...
251
+ @child_shapes.each do |child|
252
+ @cells << child.id unless @cells.include?(child.id)
253
+ end
254
+
255
+ # do self-alignment
256
+ do_alignment
257
+
258
+ # do alignment of shape's children
259
+ do_children_layout
260
+
261
+ # fit the shape to its children
262
+ fit_to_children unless has_style?(STYLE::NO_FIT_TO_CHILDREN)
263
+
264
+ # do it recursively on all parent shapes
265
+ get_parent_shape.update if get_parent_shape
266
+ end
267
+
268
+ # Resize the shape to bound all child shapes. The function can be overridden if necessary.
269
+ def fit_to_children
270
+ # HINT: overload it for custom actions...
271
+
272
+ # get bounding box of the shape and children set be inside it
273
+ abs_pos = get_absolute_position
274
+ ch_bb = Wx::Rect.new(abs_pos.to_point, [0, 0])
275
+
276
+ @child_shapes.each do |child|
277
+ child.get_complete_bounding_box(ch_bb, BBMODE::SELF | BBMODE::CHILDREN) if child.has_style?(STYLE::ALWAYS_INSIDE)
278
+ end
279
+
280
+ # do not let the grid shape 'disappear' due to zero sizes...
281
+ if (ch_bb.width == 0 || ch_bb.height == 0) && @cell_space == 0
282
+ ch_bb.set_width(10)
283
+ ch_bb.set_height(10)
284
+ end
285
+
286
+ @rect_size = Wx::RealPoint.new(ch_bb.width + 2*@cell_space, ch_bb.height + 2*@cell_space)
287
+ end
288
+
289
+ # Do layout of assigned child shapes
290
+ def do_children_layout
291
+ 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
+
299
+ max_rect.set_width(curr_rect.width) if shape.get_h_align != HALIGN::EXPAND && curr_rect.width > max_rect.width
300
+ max_rect.set_height(curr_rect.height) if shape.get_v_align != VALIGN::EXPAND && curr_rect.height > max_rect.height
301
+ end
302
+
303
+ @cells.each_with_index do |id, i|
304
+ if id
305
+ shape = @child_shapes[id]
306
+ col = (i % @cols)
307
+ row = (i / @cols)
308
+
309
+ fit_shape_to_rect(shape, Wx::Rect.new(col*max_rect.width + (col+1)*@cell_space,
310
+ row*max_rect.height + (row+1)*@cell_space,
311
+ max_rect.width, max_rect.height))
312
+ end
313
+ end
314
+ end
315
+
316
+ # Event handler called when any shape is dropped above this shape (and the dropped
317
+ # shape is accepted as a child of this shape). The function can be overridden if necessary.
318
+ #
319
+ # The function is called by the framework (by the shape canvas).
320
+ # @param [Wx::RealPoint] _pos Relative position of dropped shape
321
+ # @param [Shape] child dropped shape
322
+ def on_child_dropped(_pos, child)
323
+ append_to_grid(child) if child && !child.is_a?(LineShape)
324
+ end
325
+
326
+ protected
327
+
328
+ # Move and resize given shape so it will fit the given bounding rectangle.
329
+ #
330
+ # The shape is aligned inside the given bounding rectangle in accordance to the shape's
331
+ # valign and halign flags.
332
+ # @param [Shape] shape modified shape
333
+ # @param [Wx::Rect] rct Bounding rectangle
334
+ # @see Shape#set_v_align
335
+ # @see Shape#set_h_align
336
+ def fit_shape_to_rect(shape, rct)
337
+ shape_bb = shape.get_bounding_box
338
+ prev_pos = shape.get_relative_position
339
+
340
+ # do vertical alignment
341
+ case shape.get_v_align
342
+ when VALIGN::TOP
343
+ shape.set_relative_position(prev_pos.x, rct.top + shape.get_v_border)
344
+ when VALIGN::MIDDLE
345
+ shape.set_relative_position(prev_pos.x, rct.top + (rct.height/2 - shape_bb.height/2))
346
+ when VALIGN::BOTTOM
347
+ shape.set_relative_position(prev_pos.x, rct.bottom - shape_bb.height - shape.get_v_border)
348
+ when VALIGN::EXPAND
349
+ if shape.has_style?(STYLE::SIZE_CHANGE)
350
+ shape.set_relative_position(prev_pos.x, rct.top + shape.get_v_border)
351
+ shape.scale(1.0, (rct.height - 2*shape.get_v_border).to_f/shape_bb.height)
352
+ end
353
+ else
354
+ shape.set_relative_position(prev_pos.x, rct.top)
355
+ end
356
+
357
+ prev_pos = shape.get_relative_position
358
+
359
+ # do horizontal alignment
360
+ case shape.get_h_align
361
+ when HALIGN::LEFT
362
+ shape.set_relative_position(rct.left + shape.get_h_border, prev_pos.y)
363
+ when HALIGN::CENTER
364
+ shape.set_relative_position(rct.left + (rct.width/2 - shape_bb.width/2), prev_pos.y)
365
+ when HALIGN::RIGHT
366
+ shape.set_relative_position(rct.right - shape_bb.width - shape.get_h_border, prev_pos.y)
367
+ when HALIGN::EXPAND
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)
371
+ end
372
+ else
373
+ shape.set_relative_position(rct.left, prev_pos.y)
374
+ end
375
+ end
376
+
377
+ private
378
+
379
+ # Deserialization only.
380
+
381
+ def get_rows
382
+ @rows
383
+ end
384
+ def set_rows(num)
385
+ @rows = num
386
+ end
387
+
388
+ def get_cols
389
+ @cols
390
+ end
391
+ def set_cols(num)
392
+ @cols = num
393
+ end
394
+
395
+ def get_cells
396
+ @cells
397
+ end
398
+ def set_cells(cells)
399
+ @cells = cells
400
+ end
401
+
402
+ end
403
+
404
+ end