# frozen_string_literal: true module Vedeu module Cursors # Each interface has its own Cursor which maintains the position # and visibility of the cursor within that interface. # # @api private # class Cursor include Vedeu::Repositories::Model include Vedeu::Toggleable extend Forwardable def_delegators :geometry, :bx, :bxn, :by, :byn # @!attribute [r] name # @return [String|Symbol] attr_reader :name # @!attribute [w] ox # @return [Fixnum] attr_writer :ox # @!attribute [w] oy # @return [Fixnum] attr_writer :oy # @!attribute [w] x # @return [Fixnum] attr_writer :x # @!attribute [w] y # @return [Fixnum] attr_writer :y # Returns a new instance of Vedeu::Cursors::Cursor. # # @param attributes [Hash Boolean|Fixnum|String| # Vedeu::Cursors::Repository>] # @option attributes name [String|Symbol] The name of the # interface this cursor belongs to. # @option attributes ox [Fixnum] The offset x coordinate. # @option attributes oy [Fixnum] The offset y coordinate. # @option attributes repository # [Vedeu::Repositories::Repository] # @option attributes visible [Boolean] The visibility of the # cursor. # @option attributes x [Fixnum] The terminal x coordinate for # the cursor. # @option attributes y [Fixnum] The terminal y coordinate for # the cursor. # @return [Vedeu::Cursors::Cursor] def initialize(attributes = {}) defaults.merge!(attributes).each do |key, value| instance_variable_set("@#{key}", value) end end # @return [Hash Boolean|Fixnum|String| # Vedeu::Cursors::Repository>] def attributes { name: @name, ox: ox, oy: oy, repository: @repository, visible: @visible, x: x, y: y, } end # An object is equal when its values are the same. # # @param other [Vedeu::Cursors::Cursor] # @return [Boolean] def eql?(other) self.class == other.class && name == other.name end alias == eql? # @return [String] def inspect "name:'#{name}' x:#{x} y:#{y} ox:#{ox} oy:#{oy} visible:#{visible}" end # {include:file:docs/events/by_name/cursor_down.md} # @return [Vedeu::Cursors::Cursor] def move_down(offset = 1) @oy += offset || 1 @y = coordinate(oy, :y).y self end # {include:file:docs/events/by_name/cursor_left.md} # @return [Vedeu::Cursors::Cursor] def move_left(offset = 1) @ox -= offset || 1 @x = coordinate(ox, :x).x self end # {include:file:docs/events/by_name/cursor_origin.md} # @return [Vedeu::Cursors::Cursor] def move_origin @x = bx @y = by @ox = 0 @oy = 0 store end # {include:file:docs/events/by_name/cursor_right.md} # @return [Vedeu::Cursors::Cursor] def move_right(offset = 1) @ox += offset || 1 @x = coordinate(ox, :x).x self end # {include:file:docs/events/by_name/cursor_up.md} # @return [Vedeu::Cursors::Cursor] def move_up(offset = 1) @oy -= offset || 1 @y = coordinate(oy, :y).y self end # Renders the cursor. # # @return [Array] def render Vedeu.render_output(escape_sequence) end # @return [Array] def to_a position.to_a end # Returns an escape sequence to position the cursor and set its # visibility. When passed a block, will position the cursor, # yield and return the original position. # # @param block [Proc] # @return [String] def to_s(&block) return escape_sequence.to_s unless block_given? "#{position}#{yield}#{escape_sequence}" end alias to_str to_s # {include:file:docs/events/by_name/hide_cursor.md} # @return [Vedeu::Cells::Cursor] def hide super Vedeu.log(type: :cursor, message: "Hiding cursor: '#{name}'") render end # @return [Fixnum] def ox @ox = @ox < 0 ? 0 : @ox end # @return [Fixnum] def oy @oy = @oy < 0 ? 0 : @oy end # Return the position of this cursor. # # @return [Vedeu::Geometries::Position] def position @position = Vedeu::Geometries::Position.coerce([y, x]) end # {include:file:docs/events/by_name/show_cursor.md} # @return [Vedeu::Cells::Cursor] def show super Vedeu.log(type: :cursor, message: "Showing cursor: '#{name}'") render end # @return [Fixnum] The column/character coordinate. def x @x = Vedeu::Point.coerce(value: @x, min: bx, max: bxn).value end # @return [Fixnum] The row/line coordinate. def y @y = Vedeu::Point.coerce(value: @y, min: by, max: byn).value end private # Returns the geometry for the interface. # # @return (see Vedeu::Geometries::Repository#by_name) def geometry @geometry ||= Vedeu.geometries.by_name(name) end # Determine correct x and y related coordinates. # # @return [Vedeu::Cursors::Coordinate] def coordinate(offset, type) Vedeu::Cursors::Coordinate.new(name: name, offset: offset, type: type) end # The default values for a new instance of this class. # # @return [Hash Boolean|Fixnum|String| # Vedeu::Cursors::Repository>] def defaults { name: '', ox: 0, oy: 0, repository: Vedeu.cursors, visible: false, x: 1, y: 1, } end # @return [Vedeu::Cells::Cursor] def escape_sequence Vedeu::Cells::Cursor.new(position: position, value: visibility) end # @return [Hash Fixnum>] def new_attributes(new_y = y, new_x = x, new_oy = oy, new_ox = ox) attributes.merge!(x: new_x, y: new_y, ox: new_ox, oy: new_oy) end # Returns the escape sequence for setting the visibility of the # cursor. # # @return [String] def visibility return Vedeu.esc.show_cursor if visible? Vedeu.esc.hide_cursor end end # Cursor end # Cursors # @!method hide_cursor # @see Vedeu::Toggleable::ClassMethods.hide # @!method show_cursor # @see Vedeu::Toggleable::ClassMethods#show # @!method toggle_cursor # @see Vedeu::Toggleable::ClassMethods#toggle def_delegators Vedeu::Cursors::Cursor, :hide_cursor, :show_cursor, :toggle_cursor # :nocov: # See {file:docs/cursors.md#vedeuhide_cursor__} Vedeu.bind(:_hide_cursor_) { |name| Vedeu.hide_cursor(name) } Vedeu.bind_alias(:_cursor_hide_, :_hide_cursor_) # See {file:docs/cursors.md#vedeushow_cursor__} Vedeu.bind(:_show_cursor_) { |name| Vedeu.show_cursor(name) } Vedeu.bind_alias(:_cursor_show_, :_show_cursor_) # See {file:docs/cursors.md#vedeutoggle_cursor__} Vedeu.bind(:_toggle_cursor_) { |name| Vedeu.toggle_cursor(name) } # See {file:docs/events/by_name/cursor_left.md} Vedeu.bind(:_cursor_left_) do |name, offset| Vedeu::Cursors::Move.move(name, :move_left, offset) end # See {file:docs/events/by_name/cursor_down.md} Vedeu.bind(:_cursor_down_) do |name, offset| Vedeu::Cursors::Move.move(name, :move_down, offset) end # See {file:docs/events/by_name/cursor_up.md} Vedeu.bind(:_cursor_up_) do |name, offset| Vedeu::Cursors::Move.move(name, :move_up, offset) end # See {file:docs/events/by_name/cursor_right.md} Vedeu.bind(:_cursor_right_) do |name, offset| Vedeu::Cursors::Move.move(name, :move_right, offset) end # See {file:docs/cursors.md} Vedeu.bind(:_cursor_origin_) do |name| Vedeu.cursors.by_name(name).move_origin Vedeu.trigger(:_refresh_cursor_, name) end Vedeu.bind_alias(:_cursor_reset_, :_cursor_origin_) # See {file:docs/cursors.md} Vedeu.bind(:_cursor_position_) do |name| Vedeu.cursors.by_name(name).inspect end # See {file:docs/cursors.md} Vedeu.bind(:_cursor_reposition_) do |name, y, x| Vedeu::Cursors::Reposition.new(name: name, y: y, x: x, mode: :absolute).reposition end # See {file:docs/cursors.md} Vedeu.bind(:_cursor_top_) do |name| name ||= Vedeu.focus Vedeu::Cursors::Reposition.new(name: name, y: 0, x: 0, mode: :relative).reposition Vedeu.trigger(:_clear_view_, name) Vedeu.trigger(:_refresh_view_, name) end # See {file:docs/cursors.md} Vedeu.bind(:_cursor_bottom_) do |name| name ||= Vedeu.focus count = Vedeu.buffers.by_name(name).size Vedeu::Cursors::Reposition.new(name: name, y: count, x: 0, mode: :relative).reposition Vedeu.trigger(:_clear_view_, name) Vedeu.trigger(:_refresh_view_, name) end # :nocov: end # Vedeu