module Vedeu # Adjusts the position of the cursor or view. To use this class, call the # appropriate event: # # @example # Vedeu.trigger(:_cursor_down_) # # Vedeu.trigger(:_cursor_left_) # When a name is not given, the cursor in # # the interface which is currently in focus # # should move to the left. # # Vedeu.trigger(:_cursor_left_, 'my_interface') # # When a name is given, the cursor instance # # belonging to this interface moves to the # # left. # # Vedeu.trigger(:_cursor_right_) # Vedeu.trigger(:_cursor_up_) # # Vedeu.trigger(:_cursor_origin_) # /or/ # Vedeu.trigger(:_cursor_origin_, 'my_interface') # # Moves the cursor to the top left of the # # named or current interface in focus. # # Vedeu.trigger(:_view_down_, 'my_interface') # Vedeu.trigger(:_view_left_, 'my_interface') # Vedeu.trigger(:_view_right_, 'my_interface') # Vedeu.trigger(:_view_up_, 'my_interface') # # @note # The cursor or view may not be visible, but it will still move if # requested. # The cursor will not exceed the border or boundary of the interface, or # boundary of the visible terminal. # The cursor will move freely within the bounds of the interface, # irrespective of content. # The view will not exceed the boundary of the visible terminal. # The view will move freely within the bounds of the interface, # irrespective of content. # # @api private class Move extend Forwardable def_delegators :geometry, :x, :xn, :y, :yn # Move the named cursor or view, or that which is currently in focus in the # specified direction. # # @param direction [Symbol] The direction of travel. Directions include: # (:down, :left, :right, :up, :origin). When ':origin' the cursor is moved # to the top left of the interface. # @param name [String|NilClass] The name of the interface/cursor to be # moved; when not given, the interface currently in focus determines which # cursor instance to move. # @return [Cursor] def self.by_name(entity, direction, name = nil) name = name ? name : Vedeu.focus Vedeu::Move.send(direction, entity, name) end # Moves the cursor or view down by one row. # # @param entity [Class] # @param name [String] # @return [Cursor] def self.down(entity, name) new(entity, name, 1, 0).move end # Moves the cursor or view left by one column. # # @param entity [Class] # @param name [String] # @return [Cursor] def self.left(entity, name) new(entity, name, 0, -1).move end # Moves the cursor or view right by one column. # # @param entity [Class] # @param name [String] # @return [Cursor] def self.right(entity, name) new(entity, name, 0, 1).move end # Moves the cursor or view up by one row. # # @param entity [Class] # @param name [String] # @return [Cursor] def self.up(entity, name) new(entity, name, -1, 0).move end # Moves the cursor or view to the top left coordinate of the interface or # terminal screen. # # @param entity [Class] # @param name [String] # @return [Cursor] def self.origin(entity, name) new(entity, name, -2000, -2000).move end # Returns an instance of Vedeu::Move. # # @param entity [Class] # @param name [String] The name of the cursor or view. # @param dy [Fixnum] Move up (-1), or down (1), or no action (0). # @param dx [Fixnum] Move left (-1), or right (1), or no action (0). # @return [Move] def initialize(entity, name, dy = 0, dx = 0) @entity = entity @name = name @dy = dy @dx = dx end # Returns a newly positioned and stored cursor or view. # # @return [Vedeu::Cursor|Vedeu::Geometry] def move model = entity.new(merged_attributes).store refresh model end # @return [void] def refresh if entity.to_s == 'Vedeu::Geometry' Vedeu.trigger(:_clear_) Vedeu.trigger(:_refresh_) Vedeu.trigger(:_clear_, name) Vedeu.trigger(:_refresh_, name) else Vedeu.trigger(:_refresh_cursor_, name) end end # @return [Hash Boolean,Fixnum, String>] def merged_attributes if entity.to_s == 'Vedeu::Geometry' geometry_attributes else cursor_attributes end end protected # @!attribute [r] dx # @return [Fixnum] attr_reader :dx # @!attribute [r] dy # @return [Fixnum] attr_reader :dy # @!attribute [r] entity # @return [Fixnum] attr_reader :entity # @!attribute [r] name # @return [String] attr_reader :name private # Returns the cursors x position based on its current offset. # # @return [Fixnum] def x_position coordinate.x_position(ox) end # Returns the cursors y position based on its current offset. # # @return [Fixnum] def y_position coordinate.y_position(oy) end # @return [Coordinate] def coordinate @coordinate ||= Vedeu::Coordinate.new(name) end # @see Vedeu::Cursors#by_name def cursor @cursor ||= Vedeu.cursors.by_name(name) end # @return [Hash void>] def cursor_attributes cursor.attributes.merge!(x: x_position, y: y_position, ox: ox, oy: oy) end # @see Vedeu::Geometries#by_name def geometry @geometry ||= Vedeu.geometries.by_name(name) end # @return [Hash FalseClass,String,Fixnum>] def geometry_attributes { centred: false, maximised: false, name: name, x: (x + dx), y: (y + dy), xn: (xn + dx), yn: (yn + dy), } end # Apply the direction amount to the cursor offset. If the offset is less # than 0, correct to 0. # # @return [Fixnum] def ox ox = cursor.ox + dx ox = 0 if ox < 0 ox end # Apply the direction amount to the cursor offset. If the offset is less # than 0, correct to 0. # # @return [Fixnum] def oy oy = cursor.oy + dy oy = 0 if oy < 0 oy end end # Move end # Vedeu