Class: Wx::SF::BoxShape

Inherits:
RectShape show all
Includes:
ManagerShape
Defined in:
lib/wx/shapes/shapes/box_shape.rb

Overview

Class encapsulates a rectangular shape derived from Wx::SF::RectShape class which acts as a box-shaped container able to manage other assigned child shapes (it can control their position). The managed shapes are stacked into defined box (slots) according to it’s primary orientation with a behaviour similar to classic Wx::BoxSizer class. The box will be automatically resized along it’s primary axis to accommodate the combined sizes of the managed shapes. The minimum size of the box along it’s secondary axis is determined by the maximum size of the managed shapes. When adding or removing shapes the stack of shapes will always be kept contiguous (without empty slots). Managed shapes will never be resized along the primary axis but may be resized and/or positioned along the secondary axis according to the contained shape’s alignment setting (EXPAND).

Direct Known Subclasses

HBoxShape, VBoxShape

Defined Under Namespace

Classes: DEFAULT, ORIENTATION

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ManagerShape

#do_alignment, #fit_shape_to_rect, #is_manager

Methods inherited from RectShape

#create_handles, #do_begin_handle, #do_on_handle, #draw_highlighted, #draw_hover, #draw_normal, #draw_shadow, #get_border, #get_border_point, #get_bounding_box, #get_fill, #get_rect_size, #on_begin_handle, #on_bottom_handle, #on_handle, #on_left_handle, #on_right_handle, #on_top_handle, #scale, #scale_rectangle, #set_border, #set_fill, #set_rect_size

Methods inherited from Shape

#accept_child, #accept_connection, #accept_currently_dragged_shapes, #accept_src_neighbour, #accept_trg_neighbour, #activate, #active?, #add_child_shape, #add_connection_point, #add_handle, #add_style, #ancestor?, #clear_accepted_childs, #clear_accepted_connections, #clear_accepted_src_neighbours, #clear_accepted_trg_neighbours, component, component_shapes, #contains?, #contains_style, #create_handles, #descendant?, #do_alignment, #does_not_accept_children?, #draw, #draw_highlighted, #draw_hover, #draw_normal, #draw_selected, #draw_shadow, #get_absolute_position, #get_accepted_children, #get_accepted_connections, #get_accepted_src_neighbours, #get_accepted_trg_neighbours, #get_assigned_connections, #get_border_point, #get_bounding_box, #get_center, #get_child_shapes, #get_children, #get_children_recursively, #get_complete_bounding_box, #get_connection_point, #get_connection_points, #get_custom_dock_point, #get_diagram, #get_grand_parent_shape, #get_h_align, #get_h_border, #get_handle, #get_handles, #get_hover_colour, #get_nearest_connection_point, #get_neighbours, #get_parent_absolute_position, #get_parent_canvas, #get_parent_shape, #get_relative_position, #get_shape_canvas, #get_style, #get_user_data, #get_v_align, #get_v_border, #has_children, #has_selected_parent?, #include_child_shape?, #inside?, #inspect, #intersects?, #is_child_accepted, #is_connection_accepted, #is_managed, #is_manager, #is_src_neighbour_accepted, #is_trg_neighbour_accepted, lines_intersection, #lines_intersection, #move_by, #move_to, #on_begin_drag, #on_begin_handle, #on_dragging, #on_end_drag, #on_end_handle, #on_handle, #on_key, #on_left_click, #on_left_double_click, #on_mouse_enter, #on_mouse_leave, #on_mouse_over, #on_right_click, #on_right_double_click, #refresh, #refresh_rect, #remove_connection_point, #remove_handle, #remove_style, #scale, #scale_children, #select, #selected?, #set_custom_dock_point, #set_diagram, #set_h_align, #set_h_border, #set_hover_colour, #set_parent_shape, #set_relative_position, #set_style, #set_user_data, #set_v_align, #set_v_border, #show, #show_handles, #to_s, #visible?

Constructor Details

#initialize(pos = Shape::DEFAULT::POSITION, size = RectShape::DEFAULT::SIZE, orientation: DEFAULT::ORIENTATION, spacing: DEFAULT::SPACING, diagram: nil) ⇒ BoxShape

Constructor.

Parameters:



71
72
73
74
75
76
# File 'lib/wx/shapes/shapes/box_shape.rb', line 71

def initialize(pos = Shape::DEFAULT::POSITION, size = RectShape::DEFAULT::SIZE, orientation: DEFAULT::ORIENTATION, spacing: DEFAULT::SPACING, diagram: nil)
  super(pos, size, diagram: diagram)
  @orientation = orientation || DEFAULT::ORIENTATION
  @spacing = spacing || 0
  @slots = []
end

Class Method Details

.get_min_sizeWx::Size Also known as: min_size

Returns the minimum size for empty boxes

Returns:



40
41
42
# File 'lib/wx/shapes/shapes/box_shape.rb', line 40

def get_min_size
  @min_size ||= Wx::Size.new(20, 20)
end

.set_min_size(sz) ⇒ Object .set_min_size(w, h) ⇒ Object Also known as: min_size=

Sets the minimum size for empty boxes

Overloads:

  • .set_min_size(sz) ⇒ Object

    Parameters:

  • .set_min_size(w, h) ⇒ Object

    Parameters:

    • w (Integer)
    • h (Integer)


51
52
53
54
55
56
57
58
# File 'lib/wx/shapes/shapes/box_shape.rb', line 51

def set_min_size(arg1, arg2 = nil)
  @min_size = if arg2.nil?
                raise ArgumentError, 'Expected Wx::Size' unless Wx::Size === arg1
                arg1
              else
                Wx::Size.new(arg1, arg2)
              end
end

Instance Method Details

#append_to_box(shape) ⇒ Boolean

Append given shape to the box at the last managed position.

Parameters:

  • shape (Shape)

    shape to append

Returns:

  • (Boolean)

    true on success, otherwise false



147
148
149
# File 'lib/wx/shapes/shapes/box_shape.rb', line 147

def append_to_box(shape)
  insert_to_box(@slots.size, shape)
end

#clear_boxObject

Clear information about managed shapes and remove all slots.

Note that this function doesn’t remove managed (child) shapes from the parent box shape (they are still its child shapes but aren’t managed anymore).



140
141
142
# File 'lib/wx/shapes/shapes/box_shape.rb', line 140

def clear_box
  @slots.clear
end

#do_children_layoutObject (protected)

Do layout of assigned child shapes



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/wx/shapes/shapes/box_shape.rb', line 261

def do_children_layout
  return if @slots.empty?

  max_size = 0

  # get maximum size of all managed (child) shapes
  @child_shapes.each do |shape|
    curr_rect = shape.get_bounding_box
    curr_rect.inflate!(shape.h_border.abs.to_i, shape.v_border.abs.to_i)

    if @orientation == ORIENTATION::VERTICAL
      max_size = curr_rect.width if shape.get_h_align != HALIGN::EXPAND && curr_rect.width > max_size
    else
      max_size = curr_rect.height if shape.get_v_align != VALIGN::EXPAND && curr_rect.height > max_size
    end
  end

  # if this box itself is expanded for the appropriate dimension check the max child size against the box size
  if @orientation == ORIENTATION::VERTICAL && get_h_align == HALIGN::EXPAND
    box_rect = get_bounding_box
    # if this box is horizontally expanded use it's width if larger
    max_size = box_rect.width - 2*@spacing if (box_rect.width-2*@spacing) > max_size
  elsif @orientation == ORIENTATION::HORIZONTAL && get_v_align == VALIGN::EXPAND
    box_rect = get_bounding_box
    # if this box is vertically expanded use it's height if larger
    max_size = box_rect.height - 2*@spacing if (box_rect.height-2*@spacing) > max_size
  end

  offset = @spacing
  @slots.each do |shape|
    if @orientation == ORIENTATION::VERTICAL
      shape_h = shape.get_bounding_box.height + (2*shape.get_v_border).to_i
      fit_shape_to_rect(shape, Wx::Rect.new(@spacing,
                                            offset,
                                            max_size, shape_h))
      offset += shape_h+@spacing
    else
      shape_w = shape.get_bounding_box.width + (2*shape.get_h_border).to_i
      fit_shape_to_rect(shape, Wx::Rect.new(offset,
                                            @spacing,
                                            shape_w, max_size))
      offset += shape_w+@spacing
    end
  end
end

#each_slotEnumerator #each_slot {|slot, shape| ... } ⇒ Object

Iterate all slots. If a block is given passes slot index and shape for each slot to block. Returns Enumerator if no block given.

Overloads:

  • #each_slotEnumerator

    Returns:

    • (Enumerator)
  • #each_slot {|slot, shape| ... } ⇒ Object

    Yield Parameters:

    • slot (Integer)
    • shape (Shape, nil)

    Returns:

    • (Object)


115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/wx/shapes/shapes/box_shape.rb', line 115

def each_slot(&block)
  if block
    @slots.each_with_index do |shape, slot|
      block.call(slot, shape)
    end
  else
    ::Enumerator.new do |y|
      @slots.each_with_index do |shape, slot|
        y << [slot, shape]
      end
    end
  end
end

#find_child_slot(child) ⇒ Object (protected)



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/wx/shapes/shapes/box_shape.rb', line 316

def find_child_slot(child)
  crct = child.get_bounding_box
  # if the child intersects this box shape we look
  # for the slot it should go into
  if intersects?(crct)
    # find the slot with a shape that is positioned below/after
    # the new child
    slot = @slots.find_index do |shape|
      # determine if new child is positioned above/in front of existing child shape
      srct = shape.get_bounding_box
      if @orientation == ORIENTATION::VERTICAL
        crct.bottom <= srct.bottom || crct.top <= srct.top
      else
        crct.right <= srct.right || crct.left <= srct.left
      end
    end
    if slot # if found
      # insert before other shape
      @slots.insert(slot, child)
      return
    end
  end
  # otherwise append
  @slots << child
end

#fit_to_childrenObject

Resize the shape to bound all child shapes. The function can be overridden if necessary.



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/wx/shapes/shapes/box_shape.rb', line 219

def fit_to_children
  # get bounding box of the shape and children set to be inside it
  abs_pos = get_absolute_position
  ch_bb = Wx::Rect.new(abs_pos.to_point, [0, 0])

  @child_shapes.each do |child|
    ch_bb = child.get_complete_bounding_box(ch_bb, BBMODE::SELF | BBMODE::CHILDREN) if child.has_style?(STYLE::ALWAYS_INSIDE)
  end

  if @child_shapes.empty?
    # do not let the empty box shape 'disappear' due to zero sizes...
    ch_bb.width = get_h_align == HALIGN::EXPAND ? @rect_size.x.to_i-@spacing : GridShape.min_size.width
    ch_bb.height = get_v_align == VALIGN::EXPAND ? @rect_size.y.to_i-@spacing : GridShape.min_size.height
  end

  @rect_size = Wx::RealPoint.new(ch_bb.width + @spacing, ch_bb.height + @spacing)
end

#get_managed_shape(slot) ⇒ Shape?

Get managed shape specified by slot index.

Parameters:

  • slot (Integer)

    slot index of requested shape

Returns:

  • (Shape, nil)

    shape object of given slot if exists, otherwise nil



132
133
134
# File 'lib/wx/shapes/shapes/box_shape.rb', line 132

def get_managed_shape(slot)
  @slots[slot]
end

#get_orientationWx::SF::BoxShape::ORIENTATION Also known as: orientation

Get the box shape orientation.



80
81
82
# File 'lib/wx/shapes/shapes/box_shape.rb', line 80

def get_orientation
  @orientation
end

#get_slot_countInteger Also known as: slot_count

Get number of filled slots (i.e. managed shapes)

Returns:

  • (Integer)


87
88
89
# File 'lib/wx/shapes/shapes/box_shape.rb', line 87

def get_slot_count
  @slots.size
end

#get_spacingInteger Also known as: spacing

Get space between slots (managed shapes).

Returns:

  • (Integer)

    Spacing size



102
103
104
# File 'lib/wx/shapes/shapes/box_shape.rb', line 102

def get_spacing
  @spacing
end

#insert_to_box(slot, shape) ⇒ Boolean

Insert given shape to the box at the given position. The given shape is inserted before the existing item at index ‘slot’, thus insert_to_box(0, something) will insert an item in such way that it will become the first box element. Any occupied slots at given position or beyond will be shifted to the next position.

Parameters:

  • slot (Integer)

    slot index for inserted shape

  • shape (Shape)

    shape to insert

Returns:

  • (Boolean)

    true on success, otherwise false



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/wx/shapes/shapes/box_shape.rb', line 158

def insert_to_box(slot, shape)
  if shape && shape.is_a?(Shape) && is_child_accepted(shape.class)
    # protect duplicated occurrences
    return false if @slots.index(shape)

    # protect unbounded index
    return false if slot > @slots.size

    # add the shape to the children list if necessary
    unless @child_shapes.include?(shape)
      if @diagram
        @diagram.reparent_shape(shape, self)
      else
        shape.set_parent_shape(self)
      end
    end

    @slots.insert(slot, shape)

    return true
  end
  false
end

#on_child_dropped(_pos, child) ⇒ Object

Event handler called when any shape is dropped above this shape (and the dropped shape is accepted as a child of this shape). The function can be overridden if necessary.

The function is called by the framework (by the shape canvas).

Parameters:

  • _pos (Wx::RealPoint)

    Relative position of dropped shape

  • child (Shape)

    dropped shape



243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/wx/shapes/shapes/box_shape.rb', line 243

def on_child_dropped(_pos, child)
  # see if we can match the position of the new child with the position of another
  # (previously assigned) managed shape
  if child && !child.is_a?(LineShape)
    # if the child already had a slot
    if @slots.index(child)
      # remove it from there; this provides support for reordering child shapes by dragging
      remove_from_box(child)
    end

    # insert child based on it's current (possibly dropped) position
    find_child_slot(child)
  end
end

#on_importObject (protected)

called after the shape has been newly imported/pasted/dropped checks the slots for stale links



309
310
311
312
313
314
# File 'lib/wx/shapes/shapes/box_shape.rb', line 309

def on_import
  # check for existence of non-included shapes
  @slots.delete_if do |shape|
    !@child_shapes.include?(shape)
  end
end

#remove_from_box(shape) ⇒ Object

Note:

Note this does not remove the shape as a child shape.

Remove given shape from the box. Shifts any occupied cells beyond the slots containing the given shape to the previous position.

Parameters:

  • shape (Shape)

    shape which should be removed



186
187
188
# File 'lib/wx/shapes/shapes/box_shape.rb', line 186

def remove_from_box(shape)
  @slots.delete(shape)
end

#set_spacing(spacing) ⇒ Integer Also known as: spacing=

Set space between slots (managed shapes).

Parameters:

  • spacing (Integer)

    Spacing size

Returns:

  • (Integer)

    new spacing size



95
96
97
# File 'lib/wx/shapes/shapes/box_shape.rb', line 95

def set_spacing(spacing)
  @spacing = spacing
end

#update(recurse = true) ⇒ Object

Update shape (align all child shapes and resize it to fit them)



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/wx/shapes/shapes/box_shape.rb', line 191

def update(recurse = true)
  # check for stale links to of de-assigned shapes
  @slots.delete_if do |shape|
    !@child_shapes.include?(shape)
  end

  # check whether all child shapes are present in the slots array...
  @child_shapes.each do |child|
    unless @slots.include?(child)
      # see if we can match the position of the new child with the position of another
      # (previously assigned) managed shape
      find_child_slot(child)
    end
  end

  # do self-alignment
  do_alignment

  # fit the shape to its children
  fit_to_children unless has_style?(STYLE::NO_FIT_TO_CHILDREN)

  # do it recursively on all parent shapes
  if recurse && (parent = get_parent_shape)
    parent.update(recurse)
  end
end