lib/wx/shapes/shape.rb in wxruby3-shapes-0.9.0.pre.beta.3 vs lib/wx/shapes/shape.rb in wxruby3-shapes-0.9.5
- old
+ new
@@ -1,9 +1,10 @@
# Wx::SF::Shape - base shape class
# Copyright (c) M.J.N. Corino, The Netherlands
require 'wx/shapes/serializable'
+require 'wx/shapes/shapes/manager_shape'
require 'set'
module Wx::SF
@@ -27,19 +28,20 @@
# This class also declares set of virtual functions used as event handlers for various
# events (moving, sizing, drawing, mouse events, serialization and deserialization requests, ...)
# mostly triggered by a parent shape canvas.
class Shape
- include Serializable
+ include FIRM::Serializable
- property :id, :active, :visibility, :style,
+ property :active, :visibility, :style,
:accepted_children, :accepted_connections,
:accepted_src_neighbours, :accepted_trg_neighbours,
- :hover_colour, :relative_position,
+ :relative_position,
:h_align, :v_align, :h_border, :v_border,
:custom_dock_point, :connection_points,
:user_data
+ property({ hover_colour: :serialize_hover_colour }, optional: true)
property child_shapes: :serialize_child_shapes
class SEARCHMODE < Wx::Enum
# Depth-First-Search algorithm
DFS = self.new(0)
@@ -100,12 +102,14 @@
HOVERING = self.new(8)
# Shape is highlighted at shape dragging
HIGHLIGHTING = self.new(16)
# Shape is always inside its parent
ALWAYS_INSIDE = self.new(32)
- # User data is destroyed at the shape deletion
- DELETE_USER_DATA = self.new(64)
+ # Shape is not drawn. Does not apply to children.
+ # Should be combined with PROPAGATE_DRAGGING | PROPAGATE_SELECTION | PROPAGATE_INTERACTIVE_CONNECTION | PROPAGATE_HOVERING | PROPAGATE_HIGHLIGHTING | PROPAGATE_DROPPING
+ # in most cases.
+ NOT_DRAWN = self.new(64)
# The DEL key is processed by the shape (not by the shape canvas)
PROCESS_DEL = self.new(128)
# Show handles if the shape is selected
SHOW_HANDLES = self.new(256)
# Show shadow under the shape
@@ -122,25 +126,30 @@
PROPAGATE_INTERACTIVE_CONNECTION = self.new(16384)
# Do no resize the shape to fit its children automatically
NO_FIT_TO_CHILDREN = self.new(32768)
# Propagate hovering to parent.
PROPAGATE_HOVERING = self.new(65536)
- # Propagate hovering to parent.
+ # Propagate highlighting to parent.
PROPAGATE_HIGHLIGHTING = self.new(131072)
+ # Propagate dropping to parent.
+ PROPAGATE_DROPPING = self.new(262144)
# Default shape style
- DEFAULT_SHAPE_STYLE = PARENT_CHANGE | POSITION_CHANGE | SIZE_CHANGE | HOVERING | HIGHLIGHTING | SHOW_HANDLES | ALWAYS_INSIDE | DELETE_USER_DATA
+ DEFAULT_SHAPE_STYLE = PARENT_CHANGE | POSITION_CHANGE | SIZE_CHANGE | HOVERING | HIGHLIGHTING | SHOW_HANDLES | ALWAYS_INSIDE
+ # Shortcut for all propagation options
+ PROPAGATE_ALL = PROPAGATE_DRAGGING | PROPAGATE_SELECTION | PROPAGATE_INTERACTIVE_CONNECTION | PROPAGATE_HOVERING | PROPAGATE_HIGHLIGHTING | PROPAGATE_DROPPING
end
# Default values
module DEFAULT
+ class << self
+ # Default value of Wx::SF::Shape @hoverColor data member
+ def hover_colour; Wx::Colour.new(120, 120, 255); end
+ end
# Default value of Wx::SF::Shape @visible data member
VISIBILITY = true
# Default value of Wx::SF::Shape @active data member
ACTIVITY = true
- # Default value of Wx::SF::Shape @hoverColor data member
- HOVERCOLOUR = Wx::Colour.new(120, 120, 255) if Wx::App.is_main_loop_running
- Wx.add_delayed_constant(self, :HOVERCOLOUR) { Wx::Colour.new(120, 120, 255) }
# Default value of Wx::SF::Shape @relativePosition data member
POSITION = Wx::RealPoint.new(0, 0)
# Default value of Wx::SF::Shape @vAlign data member
VALIGN = VALIGN::NONE
# Default value of Wx::SF::Shape @hAlign data member
@@ -170,11 +179,11 @@
# for setters and <code>"#{comp_id}()"</code> or <code>"get_#{comp_id}"</code> for getters.
# @param [String,Symbol] comp_id id of component property
# @overload component(hash)
# Specifies one or more serialized component properties with associated setter/getter method ids/procs/lambda-s.
# @example
- # property(
+ # component(
# prop_a: ->(obj, *val) {
# obj.my_prop_a_setter(val.first) unless val.empty?
# obj.my_prop_a_getter
# },
# prop_b: Proc.new { |obj, *val|
@@ -225,39 +234,28 @@
self
end
protected :from_serialized
end
include ComponentSerializerMethods
- __CODE
+ __CODE
end
end
- # @overload initialize()
- # default constructor
- # @overload initialize(pos, manager)
- # @param [Wx::RealPoint] pos Initial relative position
- # @param [Diagram] diagram containing diagram
- def initialize(*args)
- pos, diagram = args
+ # Constructor
+ # @param [Wx::RealPoint, Wx::Point] pos Initial relative position
+ # @param [Diagram] diagram containing diagram
+ def initialize(pos = DEFAULT::POSITION, diagram: nil)
::Kernel.raise ArgumentError, "Invalid arguments pos: #{pos}, diagram: #{diagram}" unless
- args.empty? || (Wx::RealPoint === pos && (diagram.nil? || Wx::SF::Diagram === diagram))
+ Wx::RealPoint === pos && (diagram.nil? || Wx::SF::Diagram === diagram)
- @id = Serializable::ID.new
@diagram = diagram
@parent_shape = nil
@child_shapes = ShapeList.new
@components = ::Set.new
- if @diagram
- if @diagram.shape_canvas
- @hover_color = @diagram.shape_canvas.hover_colour
- else
- @hover_color = DEFAULT::HOVERCOLOUR;
- end
- else
- @hover_color = DEFAULT::HOVERCOLOUR;
- end
+ # by default the common canvas hover colour will be used
+ @hover_color = nil
@selected = false
@mouse_over = false
@first_move = false
@highlight_parent = false
@@ -271,39 +269,21 @@
@h_align = DEFAULT::HALIGN
@v_border = DEFAULT::VBORDER
@h_border = DEFAULT::HBORDER
@custom_dock_point = DEFAULT::DOCK_POINT
- if pos && get_parent_shape
- @relative_position = pos.to_real_point - get_parent_absolute_position
- else
- @relative_position = DEFAULT::POSITION.dup
- end
+ @relative_position = Wx::RealPoint === pos ? pos.dup : pos.to_real_point
@handles = []
@connection_pts = []
@accepted_children = ::Set.new
@accepted_connections = ::Set.new
@accepted_src_neighbours = ::Set.new
@accepted_trg_neighbours = ::Set.new
end
- # Get the shape's id
- # @return [Wx::SF::Serializable::ID]
- def get_id
- @id
- end
- alias :id :get_id
-
- # Set the shape's id. Deserialization only.
- # @param [Wx::SF::Serializable::ID] id
- def set_id(id)
- @id = id
- end
- private :set_id
-
# Set managing diagram
# @param [Wx::SF::Diagram] diagram
def set_diagram(diagram)
if @diagram != diagram
@diagram = diagram
@@ -341,28 +321,41 @@
# Adds child shape is accepted. Removes the child shape as a toplevel diagram shape if appropriate.
# @param [Wx::SF::Shape] child child shape to add
# @return [Wx::SF::Shape,nil] added child shape or nil if not accepted
def add_child_shape(child)
+ raise SFException, 'Illegal attempt to add self as Shape child' if child == self
if is_child_accepted(child.class)
if child.get_diagram
- child.get_diagram.reparent_shape(child, shape)
+ child.get_diagram.reparent_shape(child, self)
else
child.set_parent_shape(self)
end
child.update
return child
end
nil
end
+
+ # Returns true if the given shape is included in the child shapes list.
+ # Performs a recursive search in case :recursive is true.
+ # @param [shape] shape shape to match
+ # @param [Boolean] recursive pass true to search recursively, false for non-recursive
+ # @return [Boolean] true if included, otherwise false
+ def include_child_shape?(shape, recursive = false)
+ @child_shapes.include?(shape, recursive)
+ end
+
# Set parent shape object.
# @param [Wx::SF::Shape] parent
# @note Note that this does not check this shape against the acceptance list of the parent. Use #add_child_shape if that is required.
# @note Note that this does not add (if parent == nil) or remove (if parent != nil) the shape from the diagram's
# toplevel shapes. Use Diagram#reparent_shape when that is needed.
def set_parent_shape(parent)
+ raise SFException, 'Illegal to set Shape parent to self' if parent == self
+ raise SFException, 'Illegal to set Shape parent to (grand-)child of self' if parent && include_child_shape?(parent, true)
@parent_shape.send(:remove_child, self) if @parent_shape
parent.send(:add_child, self) if parent
set_diagram(parent.get_diagram) if parent
@parent_shape = parent
end
@@ -381,11 +374,11 @@
@parent_shape ? @parent_shape.get_grand_parent_shape : self
end
alias :grand_parent_shape :get_grand_parent_shape
# Refresh (redraw) the shape
- # @param [Boolean] delayed If true then the shape canvas will be rather invalidated than refreshed.
+ # @param [Boolean] delayed If true then the shape canvas will be invalidated rather than refreshed.
# @see ShapeCanvas#invalidate_rect
# @see ShapeCanvas#refresh_invalidated_rect
def refresh(delayed = false)
refresh_rect(get_bounding_box, delayed)
end
@@ -398,30 +391,34 @@
# @param [Boolean] children true if the shape's children should be drawn as well
def draw(dc, children = WITHCHILDREN)
return unless @diagram && @diagram.shape_canvas
return unless @visible
- # draw the shape shadow if required
- draw_shadow(dc) if !@selected && has_style?(STYLE::SHOW_SHADOW)
+ unless has_style?(STYLE::NOT_DRAWN)
- # first, draw itself
- if @mouse_over && (@highlight_parent || has_style?(STYLE::HOVERING))
- if @highlight_parent
- draw_highlighted(dc)
- @highlight_parent = false
+ # draw the shape shadow if required
+ draw_shadow(dc) if !@selected && has_style?(STYLE::SHOW_SHADOW)
+
+ # first, draw itself
+ if @mouse_over && (@highlight_parent || has_style?(STYLE::HOVERING))
+ if @highlight_parent
+ draw_highlighted(dc)
+ @highlight_parent = false
+ else
+ draw_hover(dc)
+ end
else
- draw_hover(dc)
+ draw_normal(dc)
end
- else
- draw_normal(dc)
- end
- draw_selected(dc) if @selected
+ draw_selected(dc) if @selected
- # ... then draw connection points ...
- @connection_pts.each { |cpt| cpt.draw(dc) }
+ # ... then draw connection points ...
+ @connection_pts.each { |cpt| cpt.draw(dc) } unless has_style?(STYLE::PROPAGATE_INTERACTIVE_CONNECTION)
+ end
+
# ... then draw child shapes
if children
@child_shapes.each { |child| child.draw(dc) }
end
end
@@ -458,15 +455,14 @@
# Get the shape's absolute position in the canvas (calculated as a summation
# of all relative positions in the shapes' hierarchy. The function can be overridden if necessary.
# @return [Wx::RealPoint] Shape's position
def get_absolute_position
# HINT: overload it for custom actions...
- parent_shape = get_parent_shape
- if parent_shape
+ if @parent_shape
@relative_position + get_parent_absolute_position
else
- @relative_position.dup
+ @relative_position
end
end
# Get intersection point of the shape border and a line leading from
# 'start' point to 'finish' point. Default implementation does nothing. The function can be overridden if necessary.
@@ -499,11 +495,11 @@
@handles.each { |h| h.show(show) }
end
# Set shape's style.
#
- # 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
+ # Default value is STYLE::PARENT_CHANGE | STYLE::POSITION_CHANGE | STYLE::SIZE_CHANGE | STYLE::HOVERING | STYLE::HIGHLIGHTING | STYLE::SHOW_HANDLES | STYLE::ALWAYS_INSIDE
# @param [Integer] style Combination of the shape's styles
# @see STYLE
def set_style(style)
@style = style
end
@@ -521,11 +517,11 @@
end
def remove_style(style)
@style &= ~style
end
def contains_style(style)
- (@style & style) != 0
+ @style.allbits?(style)
end
alias :contains_style? :contains_style
alias :has_style? :contains_style
# Find out whether this shape has some children.
@@ -608,11 +604,11 @@
Wx::Rect.new
end
# Get shape's bounding box which includes also associated child shapes and connections.
- # @param [Wx::Rect] rct bounding rectangle
+ # @param [Wx::Rect, nil] rct bounding rectangle
# @param [BBMODE] mask Bit mask of object types which should be included into calculation
# @return [Wx::Rect] returned bounding box
# @see BBMODE
def get_complete_bounding_box(rct, mask = BBMODE::ALL)
_get_complete_bounding_box(rct, mask)
@@ -687,21 +683,35 @@
@relative_position.y += y
@diagram.set_modified(true) if @diagram
end
- # Update the shape's position in order to its alignment
- def do_alignment
- parent = get_parent_shape
+ # Returns true if this shape manages (size/position/alignment) of it's child shapes.
+ # Returns false by default.
+ # @return [Boolean]
+ def is_manager
+ false
+ end
+ alias :manager? :is_manager
- if parent && !parent.is_a?(Wx::SF::GridShape)
+ # Returns true if this shape is managed (size/position/alignment) by it's parent shape.
+ # @return [Boolean]
+ def is_managed
+ !!@parent_shape&.is_manager
+ end
+ alias :managed? :is_managed
- if parent.is_a?(Wx::SF::LineShape)
+
+ # Update the shape's position in order to its alignment
+ def do_alignment
+ # align to parent unless parent is manager
+ unless @parent_shape.nil? || managed?
+ if @parent_shape.is_a?(Wx::SF::LineShape)
line_pos = get_parent_absolute_position
parent_bb = Wx::Rect.new(line_pos.x.to_i, line_pos.y.to_i, 1, 1)
else
- parent_bb = parent.get_bounding_box
+ parent_bb = @parent_shape.get_bounding_box
end
shape_bb = get_bounding_box
# do vertical alignment
@@ -720,23 +730,23 @@
@relative_position.y = @v_border
scale(1.0, ((parent_bb.height - 2*@v_border)/shape_bb.height).to_f)
end
when VALIGN::LINE_START
- if parent.is_a?(Wx::SF::LineShape)
- line_start, line_end = parent.get_line_segment(0)
+ if @parent_shape.is_a?(Wx::SF::LineShape)
+ line_start, line_end = @parent_shape.get_line_segment(0)
if line_end.y >= line_start.y
@relative_position.y = line_start.y - line_pos.y + @v_border
else
@relative_position.y = line_start.y - line_pos.y - shape_bb.height - @v_border
end
end
when VALIGN::LINE_END
- if parent.is_a?(Wx::SF::LineShape)
- line_start, line_end = parent.get_line_segment(parent.get_control_points.get_count)
+ if @parent_shape.is_a?(Wx::SF::LineShape)
+ line_start, line_end = @parent_shape.get_line_segment(parent.get_control_points.get_count)
if line_end.y >= line_start.y
@relative_position.y = line_end.y - line_pos.y - shape_bb.height - @v_border
else
@relative_position.y = line_end.y - line_pos.y + @v_border
@@ -760,24 +770,24 @@
@relative_position.x = @h_border
scale(((parent_bb.width - 2*@h_border)/shape_bb.width).to_f, 1.0)
end
when HALIGN::LINE_START
- if parent.is_a?(Wx::SF::LineShape)
- line_start, line_end = parent.get_line_segment(0)
+ if @parent_shape.is_a?(Wx::SF::LineShape)
+ line_start, line_end = @parent_shape.get_line_segment(0)
if line_end.x >= line_start.x
@relative_position.x = line_start.x - line_pos.x + @h_border
else
@relative_position.x = line_start.x - line_pos.x - shape_bb.width - @h_border
end
end
when HALIGN::LINE_END
- if parent.is_a?(Wx::SF::LineShape)
- line_start, line_end = parent.get_line_segment(parent.get_control_points.get_count)
+ if @parent_shape.is_a?(Wx::SF::LineShape)
+ line_start, line_end = @parent_shape.get_line_segment(@parent_shape.get_control_points.get_count)
if line_end.x >= line_start.x
@relative_position.x = line_end.x - line_pos.x - shape_bb.width - @h_border
else
@relative_position.x = line_end.x - line_pos.x + @h_border
@@ -786,23 +796,23 @@
end
end
end
# Update shape (align all child shapes and resize it to fit them)
- def update
+ def update(recurse = true)
# do self-alignment
do_alignment
# do alignment of shape's children (if required)
@child_shapes.each { |child| child.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 (parent = get_parent_shape)
- parent.update
+ if recurse && (parent = get_parent_shape)
+ parent.update(recurse)
end
end
# Resize the shape to bound all child shapes. The function can be overridden if necessary.
def fit_to_children
@@ -812,15 +822,21 @@
# Function returns true if the shape is selected, otherwise returns false
def selected?
@selected
end
+ # Returns true if any (grand-)parent is selected?
+ def has_selected_parent?
+ @parent_shape&.selected? || @parent_shape&.has_selected_parent?
+ end
+ alias :selected_parent? :has_selected_parent?
+
# Set the shape as a selected/deselected one
# @param [Boolean] state Selection state (true is selected, false is deselected)
def select(state)
@selected = state
- show_handles(state && (@style & STYLE::SHOW_HANDLES) != 0)
+ show_handles(state && has_style?(STYLE::SHOW_HANDLES))
end
# Set shape's relative position. Absolute shape's position is then calculated
# as a summation of the relative positions of this shape and all parent shapes in the shape's
# hierarchy.
@@ -838,11 +854,11 @@
# Get shape's relative position.
# @return [Wx::RealPoint] Current relative position
# @see #get_absolute_position
def get_relative_position
- @relative_position.dup
+ @relative_position
end
# Set vertical alignment of this shape inside its parent
# @param [VALIGN] val Alignment type
# @see VALIGN
@@ -940,11 +956,11 @@
end
# Associate user data with the shape.
# If the data object is properly set then its marked properties will be serialized
# together with the parent shape. This means the user data must either be a serializable
- # core type or a Wx::SF::Serializable.
+ # core type or a FIRM::Serializable.
# @param [Object] data user data
def set_user_data(data)
@user_data = data
end
alias :user_data= :set_user_data
@@ -988,11 +1004,11 @@
alias :hover_colour= :set_hover_colour
# Get shape's hover color
# @return [Wx::Colour] Current hover color
def get_hover_colour
- @hover_color
+ @hover_color || (@diagram&.shape_canvas ? @diagram.shape_canvas.hover_colour : DEFAULT.hover_colour)
end
alias :hover_colour :get_hover_colour
# Function returns value of a shape's activation flag.
# Non-active shapes are visible, but don't receive (process) any events.
@@ -1028,25 +1044,25 @@
# @return [Boolean]
# @see #is_shape_accepted
def accept_currently_dragged_shapes
return false unless get_shape_canvas
- unless is_child_accepted(ACCEPT_ALL)
+ unless @accepted_children.include?(ACCEPT_ALL)
lst_selection = get_shape_canvas.get_selected_shapes
- return false if lst_selection.any? { |shape| !@accepted_children.include?(shape.class.name) }
+ return false if lst_selection.any? { |shape| !@accepted_children.include?(shape.class) }
end
true
end
# Add given shape type to an acceptance list. The acceptance list contains class
# names of the shapes which can be accepted as children of this shape.
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
# @param [Class] type Class of accepted shape object
# @see #is_child_accepted
def accept_child(type)
- ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
+ ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class)
@accepted_children << type
end
# Get shape types acceptance list.
# @return [Set<String>] String set with class names of accepted shape types.
@@ -1054,10 +1070,18 @@
def get_accepted_children
@accepted_children
end
alias :accepted_children :get_accepted_children
+ # Tells whether the shape does not accept ANY children
+ # @return [Boolean] true if no children accepted, false otherwise
+ def does_not_accept_children?
+ @accepted_children.empty?
+ end
+ alias :no_children_accepted? :does_not_accept_children?
+ alias :accepts_no_children? :does_not_accept_children?
+
# Tells whether the given connection type is accepted by this shape (it means
# whether this shape can be connected to another one by a connection of given type).
#
# The function is typically used by the framework during interactive connection creation.
# @param [Class] type Class of examined connection object
@@ -1071,11 +1095,11 @@
# names of the connection which can be accepted by this shape.
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
# @param [Class] type Class of accepted connection object
# @see #is_connection_accepted
def accept_connection(type)
- ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
+ ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class)
@accepted_connections << type
end
# Get connection types acceptance list.
# @return [Set<String>] String set with class names of accepted connection types.
@@ -1100,11 +1124,11 @@
# names of the shape types which can be accepted by this shape as its source neighbour.
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
# @param [Class] type Class of accepted connection object
# @see #is_src_neighbour_accepted
def accept_src_neighbour(type)
- ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
+ ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class)
@accepted_src_neighbours << type
end
# Get source neighbour types acceptance list.
# @return [Set<String>] String set with class names of accepted source neighbours types.
@@ -1129,11 +1153,11 @@
# names of the shape types which can be accepted by this shape as its target neighbour.
# Note: Constant value {Wx::SF::ACCEPT_ALL} behaves like any class.
# @param [Class] type Class of accepted connection object
# @see #is_trg_neighbour_accepted
def accept_trg_neighbour(type)
- ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class) || type == ACCEPT_ALL
+ ::Kernel.raise ArgumentError, 'Class or ACCEPT_ALL expected' unless type.is_a?(::Class)
@accepted_trg_neighbours << type
end
# Get target neighbour types acceptance list.
# @return [Set<String>] String set with class names of accepted target neighbours types.
@@ -1212,14 +1236,14 @@
end
alias :connection_points :get_connection_points
# Get connection point of given type assigned to the shape.
# @param [Wx::SF::ConnectionPoint::CPTYPE] type Connection point type
- # @param [Integer] id Optional connection point ID
+ # @param [Integer, nil] id Optional connection point ID
# @return [Wx::SF::ConnectionPoint,nil] connection point if exists, otherwise nil
# @see Wx::SF::ConnectionPoint::CPTYPE
- def get_connection_point(type, id = -1)
+ def get_connection_point(type, id = nil)
@connection_pts.find { |cp| cp.type == type && cp.id == id }
end
alias :connection_point :get_connection_point
# Get connection point closest to the given position.
@@ -1240,20 +1264,20 @@
# Assign connection point of given type to the shape.
# @overload add_connection_point(type, persistent: true)
# @param [Wx::SF::ConnectionPoint::CPTYPE] type Connection point type
# @param [Boolean] persistent true if the connection point should be serialized
- # @return [Wx::SF::ConnectionPoint] new connection point
+ # @return [Wx::SF::ConnectionPoint, nil] new connection point if succeeded, otherwise nil
# @overload add_connection_point(relpos, id=-1, persistent: true)
# @param [Wx::RealPoint] relpos Relative position in percentages
# @param [Integer] id connection point ID
# @param [Boolean] persistent true if the connection point should be serialized
- # @return [Wx::SF::ConnectionPoint] new connection point
+ # @return [Wx::SF::ConnectionPoint, nil] new connection point if succeeded, otherwise nil
# @overload add_connection_point(cp, persistent: true)
# @param [Wx::SF::ConnectionPoint] cp connection point (shape will take the ownership)
# @param [Boolean] persistent true if the connection point should be serialized
- # @return [Wx::SF::ConnectionPoint] added connection point
+ # @return [Wx::SF::ConnectionPoint, nil] added connection point if succeeded, otherwise nil
# @see Wx::SF::ConnectionPoint::CPTYPE
def add_connection_point(arg, *rest, persistent: true)
cp = nil
case arg
when ConnectionPoint::CPTYPE
@@ -1290,11 +1314,11 @@
# @see Wx::SF::ShapeCanvas
def on_left_click(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DOWN, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DOWN, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1308,11 +1332,11 @@
# @see Wx::SF::ShapeCanvas
def on_right_click(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DOWN, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DOWN, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1326,11 +1350,11 @@
# @see Wx::SF::ShapeCanvas
def on_left_double_click(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DCLICK, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_LEFT_DCLICK, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1344,11 +1368,11 @@
# @see Wx::SF::ShapeCanvas
def on_right_double_click(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DCLICK, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_RIGHT_DCLICK, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1362,11 +1386,11 @@
# @see Wx::SF::ShapeCanvas
def on_begin_drag(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_BEGIN, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_BEGIN, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1380,11 +1404,11 @@
# @see Wx::SF::ShapeCanvas
def on_dragging(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1398,11 +1422,11 @@
# @see Wx::SF::ShapeCanvas
def on_end_drag(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_END, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_DRAG_END, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1415,11 +1439,11 @@
# @param [Wx::SF::Shape::Handle] handle dragged handle
def on_begin_handle(handle)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_BEGIN, self.id)
+ evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_BEGIN, self.object_id)
evt.set_shape(self)
evt.set_handle(handle)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1432,11 +1456,11 @@
# @param [Wx::SF::Shape::Handle] handle dragged handle
def on_handle(handle)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE, self.id)
+ evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE, self.object_id)
evt.set_shape(self)
evt.set_handle(handle)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1449,11 +1473,11 @@
# @param [Wx::SF::Shape::Handle] handle dragged handle
def on_end_handle(handle)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_END, self.id)
+ evt = Wx::SF::ShapeHandleEvent.new(Wx::SF::EVT_SF_SHAPE_HANDLE_END, self.object_id)
evt.set_shape(self)
evt.set_handle(handle)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1466,11 +1490,11 @@
# @param [Wx::Point] pos Current mouse position
def on_mouse_enter(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_ENTER, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_ENTER, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1483,11 +1507,11 @@
# @param [Wx::Point] pos Current mouse position
def on_mouse_over(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_OVER, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_OVER, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1500,11 +1524,11 @@
# @param [Wx::Point] pos Current mouse position
def on_mouse_leave(pos)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_LEAVE, self.id)
+ evt = Wx::SF::ShapeMouseEvent.new(Wx::SF::EVT_SF_SHAPE_MOUSE_LEAVE, self.object_id)
evt.set_shape(self)
evt.set_mouse_position(pos)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
@@ -1520,11 +1544,11 @@
# @see Wx::SF::Shape::_on_key
def on_key(key)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeKeyEvent.new(Wx::SF::EVT_SF_SHAPE_KEYDOWN, self.id)
+ evt = Wx::SF::ShapeKeyEvent.new(Wx::SF::EVT_SF_SHAPE_KEYDOWN, self.object_id)
evt.set_shape(self)
evt.set_key_code(key)
get_shape_canvas.get_event_handler.process_event(evt)
end
@@ -1540,27 +1564,34 @@
# @param [Wx::SF::Shape] child dropped shape
def on_child_dropped(_pos, child)
# HINT: overload it for custom actions...
if has_style?(STYLE::EMIT_EVENTS) && get_shape_canvas
- evt = Wx::SF::ShapeChildDropEvent.new(Wx::SF::EVT_SF_SHAPE_CHILD_DROP, self.id)
+ evt = Wx::SF::ShapeChildDropEvent.new(Wx::SF::EVT_SF_SHAPE_CHILD_DROP, self.object_id)
evt.set_shape(self)
evt.set_child_shape(child)
get_shape_canvas.get_event_handler.process_event(evt)
end
end
def to_s
- "#<#{self.class}:#{id.to_i}#{parent_shape ? " parent=#{parent_shape.id.to_i}" : ''}>"
+ "#<#{self.class}:#{self.object_id}#{@parent_shape ? " parent=#{@parent_shape.object_id}" : ''}>"
end
def inspect
to_s
end
protected
+ # called after the shape has been newly imported/pasted/dropped
+ # allows for checking stale links
+ # by default does nothing
+ def on_import
+ # nothing
+ end
+
# Draw the shape in the normal way. The function can be overridden if necessary.
# @param [Wx::DC] _dc Reference to device context where the shape will be drawn to
def draw_normal(_dc)
# HINT: overload it for custom actions...
end
@@ -1612,25 +1643,25 @@
end
# Get absolute position of the shape parent.
# @return [Wx::RealPoint] Absolute position of the shape parent if exists, otherwise 0,0
def get_parent_absolute_position
- if parent = get_parent_shape
- if parent.is_a?(Wx::SF::LineShape) && @custom_dock_point != DEFAULT::DOCK_POINT
- return parent.get_dock_point_position(@custom_dock_point)
+ if @parent_shape
+ if @parent_shape.is_a?(Wx::SF::LineShape) && @custom_dock_point != DEFAULT::DOCK_POINT
+ return @parent_shape.get_dock_point_position(@custom_dock_point)
else
- return parent.get_absolute_position
+ return @parent_shape.get_absolute_position
end
end
Wx::RealPoint.new(0, 0)
end
private
# Auxiliary function called by GetNeighbours function.
- # @param [Class,nil] shapeInfo Line object type
+ # @param [Class,nil] shape_info Line object type
# @param [CONNECTMODE] condir Connection direction
# @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)
# @param [Array<Wx::SF::Shape] neighbours List to add neighbour shapes to
@@ -1647,20 +1678,20 @@
# find opposite shapes in direct branches
lst_connections.each do |line|
case condir
when CONNECTMODE::STARTING
- opposite = @diagram.find_shape(line.get_trg_shape_id)
+ opposite = line.get_trg_shape
when CONNECTMODE::ENDING
- opposite = @diagram.find_shape(line.get_src_shape_id)
+ opposite = line.get_src_shape
when CONNECTMODE::BOTH
- if @id == line.get_src_shape_id
- opposite = @diagram.find_shape(line.get_trg_shape_id)
+ if self == line.get_src_shape
+ opposite = line.get_trg_shape
else
- opposite = @diagram.find_shape(line.get_src_shape_id)
+ opposite = line.get_src_shape
end
end
# add opposite shape to the list (if applicable)
neighbours << opposite if opposite && !opposite.is_a?(Wx::SF::LineShape) && !neighbours.include?(opposite)
@@ -1672,36 +1703,36 @@
processed << self
if opposite.is_a?(Wx::SF::LineShape)
case condir
when CONNECTMODE::STARTING
- opposite = @diagram.find_shape(opposite.get_src_shape_id)
+ opposite = opposite.get_src_shape
if opposite.is_a?(Wx::SF::LineShape)
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
elsif !neighbours.include?(opposite)
neighbours << opposite
end
when CONNECTMODE::ENDING
- opposite = @diagram.find_shape(opposite.get_trg_shape_id)
+ opposite = opposite.get_trg_shape
if opposite.is_a?(Wx::SF::LineShape)
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
elsif !neighbours.include?(opposite)
neighbours << opposite
end
when CONNECTMODE::BOTH
- opposite = @diagram.find_shape(opposite.get_src_shape_id)
+ opposite = opposite.get_src_shape
if opposite.is_a?(Wx::SF::LineShape)
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
elsif !neighbours.include?(opposite)
neighbours << opposite
end
- opposite = @diagram.find_shape(opposite.get_trg_shape_id)
+ opposite = opposite.get_trg_shape
if opposite.is_a?(Wx::SF::LineShape)
opposite.__send__(:_get_neighbours, shape_info, condir, direct, neighbours, processed)
elsif !neighbours.include?(opposite)
neighbours << opposite
end
@@ -1713,11 +1744,11 @@
end
end
end
# Auxiliary function called by GetCompleteBoundingBox function.
- # @param [Wx::Rect] rct bounding rectangle to update
+ # @param [Wx::Rect, nil] rct bounding rectangle to update
# @param [BBMODE] mask Bit mask of object types which should be included into calculation
# @param [Set<Wx::SF::Shape] processed set to keep track of processed shapes
# @return [Wx::Rect] bounding rectangle
# @see BBMODE
def _get_complete_bounding_box(rct, mask = BBMODE::ALL, processed = ::Set.new)
@@ -1725,18 +1756,22 @@
return rct if processed.include?(self)
processed << self
# first, get bounding box of the current shape
- if (mask & BBMODE::SELF) != 0
- if rct.is_empty
- rct.assign(get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i))
+ if mask.allbits?(BBMODE::SELF)
+ if rct.nil?
+ rct = get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i)
else
- rct.union!(get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i))
+ if rct.empty?
+ rct += get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i)
+ else
+ rct.union!(get_bounding_box.inflate!(@h_border.abs.to_i, @v_border.abs.to_i))
+ end
# add also shadow offset if necessary
- if (mask & BBMODE::SHADOW) != 0 && has_style?(STYLE::SHOW_SHADOW) && get_parent_canvas
+ if mask.allbits?(BBMODE::SHADOW) && has_style?(STYLE::SHOW_SHADOW) && !has_style(STYLE::NOT_DRAWN) && get_parent_canvas
n_offset = get_parent_canvas.get_shadow_offset
if n_offset.x < 0
rct.set_x(rct.x + n_offset.x.to_i)
rct.set_width(rct.width - n_offset.x.to_i)
@@ -1756,11 +1791,11 @@
mask |= BBMODE::SELF
end
# get list of all connection lines assigned to the shape and find their child shapes
lst_children = []
- if (mask & BBMODE::CONNECTIONS) != 0
+ if mask.allbits?(BBMODE::CONNECTIONS)
lst_lines = get_assigned_connections(Wx::SF::LineShape, CONNECTMODE::BOTH)
lst_lines.each do |line|
# rct.union!(line.get_bounding_box)
lst_children << line
@@ -1769,19 +1804,19 @@
line.get_child_shapes(ANY, NORECURSIVE, SEARCHMODE::BFS, lst_children)
end
end
# get children of this shape
- if (mask & BBMODE::CHILDREN) != 0
+ if mask.allbits?(BBMODE::CHILDREN)
get_child_shapes(ANY, NORECURSIVE, SEARCHMODE::BFS, lst_children)
# now, call this function for all children recursively...
lst_children.each do |child|
- child.send(:_get_complete_bounding_box, rct, mask, processed)
+ rct = child.send(:_get_complete_bounding_box, rct, mask, processed)
end
end
- rct
+ rct || Wx::Rect.new
end
# Original protected event handler called when the mouse pointer is moving around the shape canvas.
# The function is called by the framework (by the shape canvas). After processing the event
# relevant overridable event handlers are called.
@@ -1798,11 +1833,11 @@
# send the event to the shape handles too...
@handles.each { |h| h.__send__(:_on_mouse_move, pos) }
# send the event to the connection points too...
- @connection_pts.each { |cp| cp.__send__(:_on_mouse_move, pos) }
+ @connection_pts.each { |cp| cp.__send__(:_on_mouse_move, pos) } unless has_style?(STYLE::PROPAGATE_INTERACTIVE_CONNECTION)
# determine, whether the shape should be highlighted for any reason
if canvas
case canvas.get_mode
when Wx::SF::ShapeCanvas::MODE::SHAPEMOVE
@@ -1870,12 +1905,12 @@
return unless @active
@first_move = true
on_begin_drag(pos)
- if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
- get_parent_shape.__send__(:_on_begin_drag, pos)
+ if @parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
+ @parent_shape.__send__(:_on_begin_drag, pos)
end
end
# Original protected event handler called during a dragging process.
# The function is called by the framework (by the shape canvas). After processing the event
@@ -1889,30 +1924,30 @@
if @first_move
@mouse_offset = Wx::RealPoint.new(pos.x, pos.y) - get_absolute_position
end
# get shape BB BEFORE movement and combine it with BB of assigned lines
- prev_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
+ prev_bb = get_complete_bounding_box(nil, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
move_to(pos.x - @mouse_offset.x, pos.y - @mouse_offset.y)
on_dragging(pos)
# GUI controls in child control shapes must be updated explicitly
lst_child_ctrls = get_child_shapes(Wx::SF::ControlShape, RECURSIVE)
lst_child_ctrls.each { |ctrl| ctrl.update_control }
# get shape BB AFTER movement and combine it with BB of assigned lines
- curr_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
+ curr_bb = get_complete_bounding_box(nil, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
# update canvas
refresh_rect(prev_bb.union!(curr_bb), DELAYED)
@first_move = false
end
- if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
- get_parent_shape.__send__(:_on_dragging, pos)
+ if @parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
+ @parent_shape.__send__(:_on_dragging, pos)
end
end
# Original protected event handler called at the end of dragging process.
# The function is called by the framework (by the shape canvas). After processing the event
@@ -1922,12 +1957,12 @@
def _on_end_drag(pos)
return unless @active
on_end_drag(pos)
- if get_parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
- get_parent_shape.__send__(:_on_end_drag, pos)
+ if @parent_shape && has_style?(STYLE::PROPAGATE_DRAGGING)
+ @parent_shape.__send__(:_on_end_drag, pos)
end
end
# Original protected event handler called when any key is pressed (in the shape canvas).
# The function is called by the framework (by the shape canvas).
@@ -1944,21 +1979,21 @@
dx = 1.0
dy = 1.0
f_refresh_all = false
if canvas.has_style?(Wx::SF::ShapeCanvas::STYLE::GRID_USE)
- dx = canvas.get_grid_size.x
- dy = canvas.get_grid_size.y
+ dx = canvas.get_grid_size
+ dy = canvas.get_grid_size
end
lst_selection = canvas.get_selected_shapes
if (lst_selection.size > 1) && lst_selection.include?(self)
f_refresh_all = true
end
- prev_bb = Wx::Rect.new
- if !f_refresh_all
+ prev_bb = nil
+ unless f_refresh_all
prev_bb = get_complete_bounding_box(prev_bb, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
end
if on_key(key)
case key
@@ -1975,14 +2010,13 @@
move_by(0, dy) if has_style?(STYLE::POSITION_CHANGE)
end
end
if !f_refresh_all
- curr_bb = get_complete_bounding_box(Wx::Rect.new, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
+ curr_bb = get_complete_bounding_box(prev_bb, BBMODE::SELF | BBMODE::CONNECTIONS | BBMODE::CHILDREN | BBMODE::SHADOW)
- prev_bb.union!(curr_bb)
- refresh_rect(prev_bb, DELAYED)
+ refresh_rect(curr_bb, DELAYED)
else
canvas.refresh(false)
end
end
end
@@ -1993,13 +2027,13 @@
# @param [Wx::SF::Shape::Handle] handle dragged handle
def _on_handle(handle)
return unless @diagram
if @parent_shape
- prev_bb = get_grand_parent_shape.get_complete_bounding_box(Wx::Rect.new)
+ prev_bb = get_grand_parent_shape.get_complete_bounding_box(nil)
else
- prev_bb = get_complete_bounding_box(Wx::Rect.new)
+ prev_bb = get_complete_bounding_box(nil)
end
# call appropriate user-defined handler
on_handle(handle)
@@ -2012,13 +2046,13 @@
# update shape
update
if @parent_shape
- curr_bb = get_grand_parent_shape.get_complete_bounding_box(Wx::Rect.new)
+ curr_bb = get_grand_parent_shape.get_complete_bounding_box(nil)
else
- curr_bb = get_complete_bounding_box(Wx::Rect.new)
+ curr_bb = get_complete_bounding_box(nil)
end
# refresh shape
refresh_rect(curr_bb.union!(prev_bb), DELAYED)
end
@@ -2060,23 +2094,32 @@
end
def update_child_parents
@child_shapes.each do |shape|
shape.instance_variable_set(:@parent_shape, self)
- shape.send(:update_child_parents)
end
end
# (de-)serialize child shapes. Exclusively for deserialization.
def serialize_child_shapes(*val)
unless val.empty?
@child_shapes = val.first
+ # @parent_shape is not serialized, instead we rely on child shapes being (de-)serialized
+ # by their parent (child shapes restored before restoring parent child list) and let
+ # the parent reset the @parent_shape attributes of their children.
+ # That way the links never get out of sync.
update_child_parents
end
@child_shapes
end
+ # (de-)serialize hover colour; allows for nil values
+ def serialize_hover_colour(*val)
+ @hover_colour = val.first unless val.empty?
+ @hover_colour
+ end
+
public
# Returns intersection point of two lines (if any)
# @param [Wx::RealPoint] from1
# @param [Wx::RealPoint] to1
@@ -2101,13 +2144,13 @@
return nil if ka == kb
xi = (b1*c2 - c1*b2) / (a1*b2 - a2*b1)
yi = -(a1*c2 - a2*c1) / (a1*b2 - a2*b1)
- if( ((from1.x - xi)*(xi - to1.x) >= 0.0) &&
- ((from2.x - xi)*(xi - to2.x) >= 0.0) &&
- ((from1.y - yi)*(yi - to1.y) >= 0.0) &&
- ((from2.y - yi)*(yi - to2.y) >= 0.0) )
+ if ((from1.x - xi) * (xi - to1.x) >= 0.0) &&
+ ((from2.x - xi) * (xi - to2.x) >= 0.0) &&
+ ((from1.y - yi) * (yi - to1.y) >= 0.0) &&
+ ((from2.y - yi) * (yi - to2.y) >= 0.0)
return Wx::RealPoint.new(xi, yi)
end
nil
end