class RNDK::Scroll

A scrolling items of text.

## Keybindings

Left Arrow

Shift the items left one column.

Right Arrow

Shift the items right one column.

Up Arrow

Select the previous item in the items.

Down Arrow

Select the next item in the items.

Prev Page

Scroll one page backward.

Ctrl-B

Scroll one page backward.

Next Page

Scroll one page forward.

Ctrl-F

Scroll one page forward.

1

Move to the first element in the items.

<

Move to the first element in the items.

g

Move to the first element in the items.

Home

Move to the first element in the items.

>

Move to the last element in the items.

G

Move to the last element in the items.

End

Move to the last element in the items.

$

Shift the items to the far right.

|

Shift the items to the far left.

Return

Exit the widget and return the index of the selected item. Also set the widget ‘exit_type` to `:NORMAL`.

Tab

Exit the widget and return the index of the selected item. Also set the widget ‘exit_type` to `:NORMAL`.

Escape

Exit the widget and return -1. Also set the widget ‘exit_type` `:ESCAPE_HIT`.

Ctrl-L

Refreshes the screen.

Attributes

current_item[R]
highlight[R]
item[R]

Public Class Methods

new(screen, config={}) click to toggle source

Creates a Scroll Widget.

  • ‘x` is the x position - can be an integer or `RNDK::LEFT`, `RNDK::RIGHT`, `RNDK::CENTER`.

  • ‘y` is the y position - can be an integer or `RNDK::TOP`, `RNDK::BOTTOM`, `RNDK::CENTER`.

  • ‘scroll_bar` is where the scrollbar will be placed. It can be only `RNDK::LEFT`, `RNDK::RIGHT` or `RNDK::NONE`, for no scrollbar.

  • ‘width`/`height` are integers - if either are 0, Widget will be created with full width/height of the screen. If it’s a negative value, will create with full width/height minus the value.

  • ‘title` can be more than one line - just split them with `n`s.

  • ‘items` is an Array of Strings to be shown on the Widget.

  • ‘numbers` is a flag to turn on/off line numbering at the front of the items items.

  • ‘highlight` is the attribute/color of the currently selected item at the items.

  • ‘box` if the Widget is drawn with a box outside it.

  • ‘shadow` turns on/off the shadow around the Widget.

Calls superclass method
# File lib/rndk/scroll.rb, line 62
def initialize(screen, config={})
  super()
  @widget_type = :scroll
  @supported_signals += [:before_input,
                         :after_input,
                         :after_scrolling]
  x          = 0
  y          = 0
  scroll_bar = RNDK::RIGHT
  width      = 0
  height     = 0
  title      = "scroll"
  items      = []
  numbers    = false
  highlight  = RNDK::Color[:reverse]
  box        = true
  shadow     = false

  config.each do |key, val|
    x         = val if key == :x
    y         = val if key == :y
    scroll_bar    = val if key == :scroll_bar
    width     = val if key == :width
    height    = val if key == :height
    title     = val if key == :title
    items     = val if key == :items
    numbers   = val if key == :numbers
    highlight = val if key == :highlight
    box       = val if key == :box
    shadow    = val if key == :shadow
  end

  parent_width  = Ncurses.getmaxx screen.window
  parent_height = Ncurses.getmaxy screen.window

  box_width  = width
  box_height = height

  xpos = x
  ypos = y

  scroll_adjust = 0

  self.set_box box

  # If the height is a negative value, the height will be ROWS-height,
  # otherwise the height will be the given height
  box_height = RNDK.set_widget_dimension(parent_height, height, 0)

  # If the width is a negative value, the width will be COLS-width,
  # otherwise the width will be the given width
  box_width = RNDK.set_widget_dimension(parent_width, width, 0)

  box_width = self.set_title(title, box_width)

  # Set the box height.
  if @title_lines > box_height
    box_height = @title_lines + [items.size, 8].min + 2 * @border_size
  end

  # Adjust the box width if there is a scroll bar
  if scroll_bar == RNDK::LEFT || scroll_bar == RNDK::RIGHT
    @scrollbar = true
    box_width += 1
  else
    @scrollbar = false
  end

  # Make sure we didn't extend beyond the dimensions of the window.
  @box_width = if box_width > parent_width
               then parent_width - scroll_adjust
               else box_width
               end
  @box_height = if box_height > parent_height
                then parent_height
                else box_height
                end

  self.set_view_size(items.size)

  # Rejustify the x and y positions if we need to.
  xtmp = [xpos]
  ytmp = [ypos]
  RNDK.alignxy(screen.window, xtmp, ytmp, @box_width, @box_height)
  xpos = xtmp[0]
  ypos = ytmp[0]

  # Make the scrolling window
  @win = Ncurses.newwin(@box_height, @box_width, ypos, xpos)

  # Is the scrolling window null?
  if @win.nil?
    return nil
  end

  # Turn the keypad on for the window
  Ncurses.keypad(@win, true)

  # Create the scrollbar window.
  if scroll_bar == RNDK::RIGHT
    @scrollbar_win = Ncurses.subwin(@win,
                                    self.max_view_size,
                                    1,
                                    self.Screen_YPOS(ypos),
                                    xpos + box_width - @border_size - 1)
  elsif scroll_bar == RNDK::LEFT
    @scrollbar_win = Ncurses.subwin(@win,
                                    self.max_view_size,
                                    1,
                                    self.Screen_YPOS(ypos),
                                    self.Screen_XPOS(xpos))
  else
    @scrollbar_win = nil
  end

  # create the items window
  @items_win = Ncurses.subwin(@win,
                             self.max_view_size,
                             box_width - (2 * @border_size) - scroll_adjust,
                             self.Screen_YPOS(ypos),
                             self.Screen_XPOS(xpos) + (if scroll_bar == RNDK::LEFT then 1 else 0 end))

  # Set the rest of the variables
  @screen = screen
  @parent = screen.window
  @shadow_win = nil
  @scrollbar_placement = scroll_bar
  @max_left_char = 0
  @left_char = 0
  @highlight = highlight
  # initExitType (scrollp);
  @accepts_focus = true
  @input_window = @win
  @shadow = shadow

  self.set_position(0);

  # Create the scrolling items item items and needed variables.
  return nil unless self.create_item_list(numbers, items)

  # Do we need to create a shadow?
  if shadow
    @shadow_win = Ncurses.newwin(@box_height,
                                 box_width,
                                 ypos + 1,
                                 xpos + 1)
  end

  # Standard keybindings (plus the Arrow Keys)
  self.bind_key('g') { self.scroll_begin }
  self.bind_key('1') { self.scroll_begin }
  self.bind_key('G') { self.scroll_end   }
  self.bind_key('<') { self.scroll_begin }
  self.bind_key('>') { self.scroll_end   }

  screen.register(:scroll, self);
  self
end

Public Instance Methods

activate(actions=[]) click to toggle source

Activates the Widget, letting the user interact with it.

‘actions` is an Array of characters. If it’s non-null, will inject each char on it into the Widget.

# File lib/rndk/scroll.rb, line 231
def activate(actions=[])
  self.draw

  if actions.nil? || actions.size == 0
    loop do
      self.fix_cursor_position
      input = self.getch

      # Inject the character into the widget.
      ret = self.inject input

      return ret if @exit_type != :EARLY_EXIT
    end
  else
    # Inject each character one at a time.
    actions.each do |action|
      ret = self.inject action

      return ret if @exit_type != :EARLY_EXIT
    end
  end

  # Set the exit type for the widget and return
  self.set_exit_type(0)
  return nil
end
destroy() click to toggle source

This function destroys

# File lib/rndk/scroll.rb, line 386
def destroy
  self.clean_title

  # Clean up the windows.
  RNDK.window_delete(@scrollbar_win)
  RNDK.window_delete(@shadow_win)
  RNDK.window_delete(@items_win)
  RNDK.window_delete(@win)

  # Clean the key bindings.
  self.clean_bindings

  # Unregister this widget
  @screen.unregister self
end
draw() click to toggle source

This function draws the scrolling items widget.

# File lib/rndk/scroll.rb, line 365
def draw
  # Draw in the shadow if we need to.
  Draw.drawShadow(@shadow_win) unless @shadow_win.nil?

  self.draw_title @win

  # Draw in the scrolling items items.
  self.draw_items @box
end
erase() click to toggle source

This function erases the scrolling items from the screen.

# File lib/rndk/scroll.rb, line 403
def erase
  RNDK.window_erase(@win)
  RNDK.window_erase(@shadow_win)
end
focus() click to toggle source
  # do this to update the view size, etc
  self.set_position(@current_item)
end

end

# File lib/rndk/scroll.rb, line 516
def focus
  self.draw_current
  Ncurses.wrefresh @items_win
end
get_highlight(highlight) click to toggle source
# File lib/rndk/scroll.rb, line 445
def get_highlight(highlight)
  return @highlight
end
get_items(items) click to toggle source
# File lib/rndk/scroll.rb, line 432
def get_items(items)
  (0...@item.size).each do |x|
    items << RNDK.chtype2Char(@item[x])
  end

  @item.size
end
inject(input) click to toggle source

@see Widget#inject

# File lib/rndk/scroll.rb, line 259
def inject input
  ret = nil
  complete = false

  self.set_exit_type 0

  # Draw the scrolling items
  self.draw_items @box

  # Calls a pre-process block if exists.
  # They can interrup input.
  continue = run_signal_binding(:before_input, input)

  if continue

    # Check for a predefined key binding.
    if self.is_bound? input
      self.run_key_binding input

    else
      case input

      when Ncurses::KEY_UP
        self.scroll_up
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_DOWN
        self.scroll_down
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_LEFT
        self.scroll_left
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_RIGHT
        self.scroll_right
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_PPAGE
        self.scroll_page_up
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_NPAGE
        self.scroll_page_down
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_HOME
        self.scroll_begin
        run_signal_binding(:after_scrolling, @current_item)

      when Ncurses::KEY_END
        self.scroll_end
        run_signal_binding(:after_scrolling, @current_item)

      when RNDK::BACKCHAR
        self.scroll_page_up
        run_signal_binding(:after_scrolling, @current_item)

      when RNDK::FORCHAR
        self.scroll_page_down
        run_signal_binding(:after_scrolling, @current_item)

      when '$' then @left_char = @max_left_char
      when '|' then @left_char = 0

      when RNDK::KEY_ESC
        self.set_exit_type(input)
        complete = true

      when Ncurses::ERR
        self.set_exit_type(input)
        complete = true

      when RNDK::REFRESH
        @screen.erase
        @screen.refresh

      when RNDK::KEY_TAB, Ncurses::KEY_ENTER, RNDK::KEY_RETURN
        self.set_exit_type(input)
        ret = @current_item
        complete = true
      end
    end

    run_signal_binding(:after_input, input) if not complete
  end

  if not complete
    self.draw_items @box
    self.set_exit_type(0)
  end

  self.fix_cursor_position
  @result_data = ret

  ret
end
move(x, y, relative, refresh_flag) click to toggle source

This moves the scroll field to the given location.

# File lib/rndk/scroll.rb, line 358
def move(x, y, relative, refresh_flag)
  windows = [@win, @items_win, @shadow_win, @scrollbar_win]

  self.move_specific(x, y, relative, refresh_flag, windows, [])
end
position() click to toggle source

@see Widget#position

Calls superclass method
# File lib/rndk/scroll.rb, line 222
def position
  super @win
end
set(items, numbers, highlight, box) click to toggle source

This sets certain attributes of the scrolling items.

# File lib/rndk/scroll.rb, line 409
def set(items, numbers, highlight, box)
  self.set_items(items, numbers)
  self.set_highlight(highlight)
  self.set_box(box)
end
set_bg_color(attrib) click to toggle source

This sets the background attribute of the widget.

# File lib/rndk/scroll.rb, line 376
def set_bg_color(attrib)
  Ncurses.wbkgd(@win, attrib)
  Ncurses.wbkgd(@items_win, attrib)

  unless @scrollbar_win.nil?
    Ncurses.wbkgd(@scrollbar_win, attrib)
  end
end
set_highlight(highlight) click to toggle source

This sets the highlight of the scrolling items.

# File lib/rndk/scroll.rb, line 441
def set_highlight(highlight)
  @highlight = highlight
end
set_items(items, numbers) click to toggle source

Sets the scrolling items items. See Scroll#initialize.

# File lib/rndk/scroll.rb, line 417
def set_items(items, numbers)
  return unless self.create_item_list(numbers, items)

  # Clean up the display.
  (0...@view_size).each do |x|
    Draw.writeBlanks(@win, 1, x, RNDK::HORIZONTAL, 0, @box_width - 2);
  end

  self.set_view_size(items.size)
  self.set_position(0)
  self.erase

  @left_char = 0
end
unfocus() click to toggle source
# File lib/rndk/scroll.rb, line 521
def unfocus
  self.draw_current
  Ncurses.wrefresh @items_win
end

Protected Instance Methods

alloc_items_arrays(old_size, new_size) click to toggle source
# File lib/rndk/scroll.rb, line 583
def alloc_items_arrays(old_size, new_size)

  new_items = Array.new new_size
  new_len  = Array.new new_size
  new_pos  = Array.new new_size

  (0...old_size).each do |n|
    new_items[n] = @item[n]
    new_len[n]  = @item_len[n]
    new_pos[n]  = @item_pos[n]
  end

  @item     = new_items
  @item_len = new_len
  @item_pos = new_pos

  true
end
alloc_items_item(which, work, used, number, value) click to toggle source

Creates a single item on the scroll items.

# File lib/rndk/scroll.rb, line 603
def alloc_items_item(which, work, used, number, value)

  if number > 0
    value = "%4d. %s" % [number, value]
  end

  item_len = []
  item_pos = []
  @item[which] = RNDK.char2Chtype(value, item_len, item_pos)
  @item_len[which] = item_len[0]
  @item_pos[which] = item_pos[0]

  @item_pos[which] = RNDK.justifyString(@box_width,
                                        @item_len[which],
                                        @item_pos[which])
  true
end
available_width() click to toggle source
# File lib/rndk/scroll.rb, line 652
def available_width
  @box_width - (2 * @border_size)
end
create_item_list(numbers, items) click to toggle source

Creates the scrolling items information and sets up the needed variables for the scrolling items to work correctly.

# File lib/rndk/scroll.rb, line 538
def create_item_list(numbers, items)
  status = false

  # If any element is not a String, try to convert
  # it anyway.
  items.each_with_index do |item, i|
    if item.class != String
      items[i] = item.to_s
    end
  end

  if items.size > 0
    widest_item = 0
    x = 0
    have = 0
    temp = ''

    if alloc_items_arrays(0, items.size)
      # Create the items in the scrolling items.
      status = true
      (0...items.size).each do |x|
        number = if numbers then x + 1 else 0 end

        unless self.alloc_items_item(x, temp, have, number, items[x])
          status = false
          break
        end

        widest_item = [@item_len[x], widest_item].max
      end

      if status
        self.update_view_width widest_item

        # Keep the boolean flag 'numbers'
        @numbers = numbers
      end
    end

  else
    status = true  # null items is ok - for a while
  end
  status
end
draw_current() click to toggle source
# File lib/rndk/scroll.rb, line 743
def draw_current
  # Rehighlight the current menu item.
  screen_pos = @item_pos[@current_item] - @left_char
  highlight = if self.has_focus
              then @highlight
              else RNDK::Color[:normal]
              end

  Draw.writeChtypeAttrib(@items_win,
                         if screen_pos >= 0 then screen_pos else 0 end,
                         @current_high, @item[@current_item], highlight, RNDK::HORIZONTAL,
                         if screen_pos >= 0 then 0 else 1 - screen_pos end,
                         @item_len[@current_item])
end
draw_items(box) click to toggle source

Draws the scrolling items.

# File lib/rndk/scroll.rb, line 668
def draw_items box

  # If the items is empty, don't draw anything.
  if @item.size > 0

    # Redraw the items
    (0...@view_size).each do |j|
      k = j + @current_top

      Draw.writeBlanks(@items_win,
                       0,
                       j,
                       RNDK::HORIZONTAL, 0,
                       @box_width - (2 * @border_size))

      # Draw the elements in the scrolling items.
      if k < @item.size

        screen_pos = @item_pos[k] - @left_char
        ypos = j

        # Write in the correct line.
        Draw.writeChtype(@items_win,
                         if screen_pos >= 0 then screen_pos else 1 end,
                         ypos, @item[k], RNDK::HORIZONTAL,
                         if screen_pos >= 0 then 0 else 1 - screen_pos end,
                         @item_len[k])
      end
    end

    self.draw_current

    # Determine where the toggle is supposed to be.
    unless @scrollbar_win.nil?
      @toggle_pos = (@current_item * @step).floor

      # Make sure the toggle button doesn't go out of bounds.
      if @toggle_pos >= Ncurses.getmaxy(@scrollbar_win)
        @toggle_pos = Ncurses.getmaxy(@scrollbar_win) - 1
      end

      # Draw the scrollbar
      Ncurses.mvwvline(@scrollbar_win,
                       0,
                       0,
                       Ncurses::ACS_CKBOARD,
                       Ncurses.getmaxy(@scrollbar_win))

      Ncurses.mvwvline(@scrollbar_win,
                       @toggle_pos,
                       0,
                       ' '.ord | RNDK::Color[:reverse],
                       @toggle_size)
    end
  end

  Draw.drawObjBox(@win, self) if box
  Ncurses.wrefresh @win
end
fix_cursor_position() click to toggle source

Put the cursor on the currently-selected item’s row.

# File lib/rndk/scroll.rb, line 759
def fix_cursor_position
  scrollbar_adj = if @scrollbar_placement == LEFT then 1 else 0 end
  ypos = self.Screen_YPOS(@current_item - @current_top)
  xpos = self.Screen_XPOS(0) + scrollbar_adj

  Ncurses.wmove(@input_window, ypos, xpos)
  Ncurses.wrefresh(@input_window)
end
get_current_top() click to toggle source
# File lib/rndk/scroll.rb, line 728
def get_current_top
  @current_top
end
insert_items_item(item) click to toggle source
# File lib/rndk/scroll.rb, line 644
def insert_items_item(item)
  @item = @item[0..item] + @item[item..-1]
  @item_len = @item_len[0..item] + @item_len[item..-1]
  @item_pos = @item_pos[0..item] + @item_pos[item..-1]

  true
end
resequence() click to toggle source

Resequence the numbers after an insertion/deletion.

# File lib/rndk/scroll.rb, line 622
def resequence
  return unless @numbers

  (0...@item.size).each do |j|
    target = @item[j]

    source = "%4d. %s" % [j + 1, ""]

    k = 0
    while k < source.size
      # handle deletions that change the length of number
      if (source[k] == ".") and (target[k] != ".")
        source = source[0...k] + source[k+1..-1]
      end

      target[k] &= RNDK::Color[:extract]
      target[k] |= source[k].ord
      k += 1
    end
  end
end
set_current_top(item) click to toggle source
# File lib/rndk/scroll.rb, line 732
def set_current_top(item)
  if item < 0
    item = 0
  elsif item > @max_top_item
    item = @max_top_item
  end
  @current_top = item

  self.set_position(item);
end
update_view_width(widest) click to toggle source
# File lib/rndk/scroll.rb, line 656
def update_view_width(widest)
  @max_left_char = if @box_width > widest
                   then 0
                   else widest - self.available_width
                   end
end
widest_item() click to toggle source
# File lib/rndk/scroll.rb, line 663
def widest_item
  @max_left_char + self.available_width
end