wxruby3-shapes 0.9.0.pre.beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +12 -0
  3. data/CREDITS.md +18 -0
  4. data/INSTALL.md +39 -0
  5. data/LICENSE +21 -0
  6. data/README.md +118 -0
  7. data/assets/screenshot.png +0 -0
  8. data/bin/wx-shapes +9 -0
  9. data/lib/wx/shapes/arrow_base.rb +86 -0
  10. data/lib/wx/shapes/arrows/circle_arrow.rb +39 -0
  11. data/lib/wx/shapes/arrows/diamond_arrow.rb +33 -0
  12. data/lib/wx/shapes/arrows/open_arrow.rb +56 -0
  13. data/lib/wx/shapes/arrows/solid_arrow.rb +69 -0
  14. data/lib/wx/shapes/art/shape_canvas/page.xpm +73 -0
  15. data/lib/wx/shapes/auto_layout.rb +358 -0
  16. data/lib/wx/shapes/base.rb +33 -0
  17. data/lib/wx/shapes/canvas_history.rb +84 -0
  18. data/lib/wx/shapes/connection_point.rb +238 -0
  19. data/lib/wx/shapes/core.rb +19 -0
  20. data/lib/wx/shapes/diagram.rb +659 -0
  21. data/lib/wx/shapes/events.rb +389 -0
  22. data/lib/wx/shapes/printout.rb +136 -0
  23. data/lib/wx/shapes/serializable.rb +440 -0
  24. data/lib/wx/shapes/serialize/core.rb +40 -0
  25. data/lib/wx/shapes/serialize/id.rb +82 -0
  26. data/lib/wx/shapes/serialize/wx.rb +104 -0
  27. data/lib/wx/shapes/serializer/json.rb +258 -0
  28. data/lib/wx/shapes/serializer/yaml.rb +125 -0
  29. data/lib/wx/shapes/shape.rb +2129 -0
  30. data/lib/wx/shapes/shape_canvas.rb +3285 -0
  31. data/lib/wx/shapes/shape_data_object.rb +43 -0
  32. data/lib/wx/shapes/shape_handle.rb +287 -0
  33. data/lib/wx/shapes/shape_list.rb +161 -0
  34. data/lib/wx/shapes/shapes/bitmap_shape.rb +257 -0
  35. data/lib/wx/shapes/shapes/circle_shape.rb +136 -0
  36. data/lib/wx/shapes/shapes/control_shape.rb +483 -0
  37. data/lib/wx/shapes/shapes/curve_shape.rb +231 -0
  38. data/lib/wx/shapes/shapes/diamond_shape.rb +62 -0
  39. data/lib/wx/shapes/shapes/edit_text_shape.rb +317 -0
  40. data/lib/wx/shapes/shapes/ellipse_shape.rb +106 -0
  41. data/lib/wx/shapes/shapes/flex_grid_shape.rb +78 -0
  42. data/lib/wx/shapes/shapes/grid_shape.rb +404 -0
  43. data/lib/wx/shapes/shapes/line_shape.rb +907 -0
  44. data/lib/wx/shapes/shapes/multi_sel_rect.rb +214 -0
  45. data/lib/wx/shapes/shapes/ortho_shape.rb +357 -0
  46. data/lib/wx/shapes/shapes/polygon_shape.rb +294 -0
  47. data/lib/wx/shapes/shapes/rect_shape.rb +378 -0
  48. data/lib/wx/shapes/shapes/round_ortho_shape.rb +131 -0
  49. data/lib/wx/shapes/shapes/round_rect_shape.rb +142 -0
  50. data/lib/wx/shapes/shapes/square_shape.rb +119 -0
  51. data/lib/wx/shapes/shapes/text_shape.rb +324 -0
  52. data/lib/wx/shapes/thumbnail.rb +234 -0
  53. data/lib/wx/shapes/version.rb +12 -0
  54. data/lib/wx/shapes/wx.rb +29 -0
  55. data/lib/wx/shapes.rb +18 -0
  56. data/lib/wx/wx-shapes/base.rb +87 -0
  57. data/lib/wx/wx-shapes/cmd/sampler.rb +58 -0
  58. data/lib/wx/wx-shapes/cmd/test.rb +27 -0
  59. data/rakelib/yard/templates/default/fulldoc/html/css/wxruby3.css +7 -0
  60. data/rakelib/yard/templates/default/layout/html/setup.rb +5 -0
  61. data/rakelib/yard/yard/relative_markdown_links/version.rb +8 -0
  62. data/rakelib/yard/yard/relative_markdown_links.rb +39 -0
  63. data/rakelib/yard/yard-custom-templates.rb +2 -0
  64. data/rakelib/yard/yard-relative_markdown_links.rb +4 -0
  65. data/samples/demo/art/AlignBottom.xpm +35 -0
  66. data/samples/demo/art/AlignCenter.xpm +35 -0
  67. data/samples/demo/art/AlignLeft.xpm +35 -0
  68. data/samples/demo/art/AlignMiddle.xpm +35 -0
  69. data/samples/demo/art/AlignRight.xpm +35 -0
  70. data/samples/demo/art/AlignTop.xpm +35 -0
  71. data/samples/demo/art/Bitmap.xpm +25 -0
  72. data/samples/demo/art/Circle.xpm +22 -0
  73. data/samples/demo/art/Curve.xpm +21 -0
  74. data/samples/demo/art/Diamond.xpm +22 -0
  75. data/samples/demo/art/EditText.xpm +21 -0
  76. data/samples/demo/art/Ellipse.xpm +22 -0
  77. data/samples/demo/art/FixedRect.xpm +22 -0
  78. data/samples/demo/art/FlexGrid.xpm +22 -0
  79. data/samples/demo/art/GC.xpm +23 -0
  80. data/samples/demo/art/Grid.xpm +22 -0
  81. data/samples/demo/art/Line.xpm +21 -0
  82. data/samples/demo/art/NoSource.xpm +69 -0
  83. data/samples/demo/art/OrthoLine.xpm +21 -0
  84. data/samples/demo/art/Rect.xpm +22 -0
  85. data/samples/demo/art/RoundOrthoLine.xpm +21 -0
  86. data/samples/demo/art/RoundRect.xpm +22 -0
  87. data/samples/demo/art/Shadow.xpm +23 -0
  88. data/samples/demo/art/StandAloneLine.xpm +22 -0
  89. data/samples/demo/art/Text.xpm +21 -0
  90. data/samples/demo/art/Tool.xpm +23 -0
  91. data/samples/demo/art/sample.xpm +251 -0
  92. data/samples/demo/demo.rb +658 -0
  93. data/samples/demo/frame_canvas.rb +422 -0
  94. data/samples/demo/images/motyl.bmp +0 -0
  95. data/samples/demo/images/motyl2.bmp +0 -0
  96. data/samples/sample1/art/sample.xpm +251 -0
  97. data/samples/sample1/sample.rb +263 -0
  98. data/samples/sample2/art/sample.xpm +251 -0
  99. data/samples/sample2/sample.rb +133 -0
  100. data/samples/sample2/sample_canvas.rb +35 -0
  101. data/samples/sample2/sample_shape.rb +108 -0
  102. data/samples/sample3/art/sample.xpm +251 -0
  103. data/samples/sample3/sample.rb +281 -0
  104. data/samples/sample4/art/sample.xpm +251 -0
  105. data/samples/sample4/sample.rb +180 -0
  106. data/tests/art/motyl.bmp +0 -0
  107. data/tests/lib/wxapp_runner.rb +64 -0
  108. data/tests/serializer_tests.rb +521 -0
  109. data/tests/test_grid_shapes.rb +42 -0
  110. data/tests/test_serialize.rb +7 -0
  111. data/tests/test_serialize_yaml.rb +17 -0
  112. metadata +242 -0
@@ -0,0 +1,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