require 'vedeu/cursor/cursor' require 'vedeu/geometry/coordinate' require 'vedeu/geometry/position_validator' module Vedeu # Adjusts the position of the cursor. 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. # # @note # The cursor may not be visible, but it will still move if requested. # The cursor will not exceed the border or boundary of the interface. # The cursor will move freely within the bounds of the interface, # irrespective of content. # class Move extend Forwardable def_delegators :@interface, :border, :border?, :geometry def_delegators :geometry, :left, :top, :height, :width # Returns an instance of Vedeu::Move. # # @param cursor [Cursor] # @param interface [Interface] # @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(cursor, interface, dy = 0, dx = 0) @cursor = cursor @dy = dy || 0 @dx = dx || 0 @interface = interface end # Move the named cursor, 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(direction, name = nil) if name cursor = Vedeu.cursors.by_name(name) interface = Vedeu.interfaces.find(name) else cursor = Vedeu.cursor interface = Vedeu.interfaces.current end new_cursor = Vedeu::Move.send(direction, cursor, interface) Vedeu.trigger(:_refresh_cursor_, new_cursor.name) new_cursor end # Moves the cursor down by one row. # # @param cursor [Cursor] # @param interface [Interface] # @return [Cursor] def self.down(cursor, interface) new(cursor, interface, 1, 0).move end # Moves the cursor left by one column. # # @param cursor [Cursor] # @param interface [Interface] # @return [Cursor] def self.left(cursor, interface) return cursor unless cursor.ox > 0 new(cursor, interface, 0, -1).move end # Moves the cursor right by one column. # # @param cursor [Cursor] # @param interface [Interface] # @return [Cursor] def self.right(cursor, interface) new(cursor, interface, 0, 1).move end # Moves the cursor up by one row. # # @param cursor [Cursor] # @param interface [Interface] # @return [Cursor] def self.up(cursor, interface) return cursor unless cursor.oy > 0 new(cursor, interface, -1, 0).move end # Moves the cursor to the top left coordinate of the interface. # # @param cursor [Cursor] # @param interface [Interface] # @return [Cursor] def self.origin(cursor, interface) new(cursor, interface, (0 - cursor.y), (0 - cursor.x)).move end # Returns a newly positioned and stored Cursor. # # @return [Cursor] def move Vedeu::Cursor.new(cursor.attributes.merge!(moved_attributes)).store end private # @!attribute [r] cursor # @return [Vedeu::Cursor] attr_reader :cursor # @!attribute [r] dx # @return [Fixnum] attr_reader :dx # @!attribute [r] dy # @return [Fixnum] attr_reader :dy # @!attribute [r] interface # @return [Vedeu::Interface] attr_reader :interface # @return [Hash Fixnum>] def moved_attributes { x: validator.x, y: validator.y, ox: ox, oy: oy, } end # @return [PositionValidator] def validator @validator ||= Vedeu::PositionValidator.validate(interface.name, x_position, y_position) end # @return [Fixnum] def x_position coordinate.x_position(ox) end # @return [Fixnum] def y_position coordinate.y_position(oy) end # @return [Coordinate] def coordinate @coordinate ||= Vedeu::Coordinate.new(bordered_height, bordered_width, left, top) end # Return the height of the interface, minus any borders. # # @return [Fixnum] def bordered_height return border.height if border? height end # Return the width of the interface, minus any borders. # # @return [Fixnum] def bordered_width return border.width if border? width 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