class RNDK::Screen

Placeholder for RNDK Widgets.

Since all Widgets are bonded to a Screen, you pretty much won’t need to call any of the methods here.

The only methods you should worry about are:

## Developer Notes

When a Widget is created, it calls Screen#register with it’s type and self pointer.

That adds the widget pointer to an Array ‘@widget` that contains all the widgets inside this screen.

During it’s lifetime, most widgets would call only Screen#erase and Screen#refresh.

When Widget#destroy is called, we call Screen#unregister to remove it from the ‘@widget` array.

Now, what happens when the Ruby garbage collector kills the widget?

Constants

EXITCANCEL
EXITOK
NOEXIT

Attributes

exit_status[RW]

Nothing… for now

widget[RW]

Array with all the widgets currently on the screen

widget_count[RW]

How many widgets we currently have

widget_focus[RW]

Index of the current focused widget

widget_limit[RW]

Maximum widget capacity of the screen (always expands)

window[RW]

Raw Ncurses window that represents this Screen

Public Class Methods

finish() click to toggle source

Shuts down RNDK and Ncurses, plus destroying all the widgets ever created.

# File lib/rndk/core/screen.rb, line 100
def self.finish

  ## If I do this it gives me a segmentation fault.
  ## I guess that would happen because of the
  ## ruby garbage collector.
  ##
  ## What should I do instead?
  #
  # RNDK::ALL_WIDGETS.each { |obj| obj.destroy }
  # RNDK::ALL_SCREENS.each { |scr| scr.destroy }

  Ncurses.echo
  Ncurses.nocbreak
  Ncurses.endwin
end
height() click to toggle source

Returns the whole terminal screen height.

# File lib/rndk/core/screen.rb, line 63
def self.height
  Ncurses.LINES
end
lower_widget(widget) click to toggle source

Has the opposite effect of raise_widget.

# File lib/rndk/core/screen.rb, line 194
def self.lower_widget widget
  return unless widget.valid_type?

  widget.screen.swap_indexes(widget.screen_index, 0)
end
new(ncurses_window=nil) click to toggle source

Takes a Ncurses ‘WINDOW*` pointer and creates a CDKScreen.

This also starts Ncurses, if it wasn’t started before or no ‘WINDOW*` were provided

# File lib/rndk/core/screen.rb, line 72
def initialize(ncurses_window=nil)

  # If the user didn't start Ncurses for us,
  # we'll do it anyway.
  if RNDK::ALL_SCREENS.empty? or ncurses_window.nil?

    ## Why is this here?
    # Set up basic curses settings.
    # #ifdef HAVE_SETLOCALE
    # setlocale (LC_ALL, "");
    # #endif

    ncurses_window = Ncurses.initscr
    Ncurses.noecho
    Ncurses.cbreak
    Ncurses.keypad(ncurses_window, true)
  end

  RNDK::ALL_SCREENS << self
  @widget_count = 0
  @widget_limit = 2
  @widget = Array.new(@widget_limit, nil)
  @window = ncurses_window
  @widget_focus = 0
end
raise_widget(widget) click to toggle source

Raises the Widget to the top of the screen. It will now overlap any other obstructing Widgets.

‘rndktype` states what RNDK Widget type this widget is. `widget` is a pointer to the Widget itself.

# File lib/rndk/core/screen.rb, line 186
def self.raise_widget widget
  return unless widget.valid_type?

  screen = widget.screen
  screen.swap_indexes(widget.screen_index, screen.widget_count - 1)
end
width() click to toggle source

Returns the whole terminal screen width.

# File lib/rndk/core/screen.rb, line 58
def self.width
  Ncurses.COLS
end

Public Instance Methods

cleanly() { || ... } click to toggle source

Executes a block of code without modifying the screen state.

See usage right below.

# File lib/rndk/core/quick_widgets.rb, line 31
def cleanly &block
  prev_state = Ncurses.curs_set 0

  yield

  Ncurses.curs_set prev_state
  self.erase
  self.refresh
end
destroy() click to toggle source

Destroys this Screen.

@note It does nothing to the widgets inside it.

You must either destroy them separatedly
or call #destroy_widgets before.
# File lib/rndk/core/screen.rb, line 276
def destroy
  RNDK::ALL_SCREENS.delete self
end
destroy_widgets() click to toggle source

Destroys all the Widgets inside this Screen.

# File lib/rndk/core/screen.rb, line 258
def destroy_widgets
  (0...@widget_count).each do |x|
    obj    = @widget[x]
    before = @widget_count

    if obj.valid_type?
      obj.erase
      obj.destroy
      x -= (@widget_count - before)
    end
  end
end
draw() click to toggle source

Redraws all Widgets inside this Screen.

# File lib/rndk/core/screen.rb, line 201
def draw
  self.refresh
end
erase() click to toggle source

Erases all Widgets inside this Screen.

@note Erase in the sense of clearing the actual

characters on the terminal screen.
This does NOT destroy any widgets.
# File lib/rndk/core/screen.rb, line 249
def erase
  (0...@widget_count).each do |x|
    obj = @widget[x]
    obj.erase if obj.valid_type?
  end
  Ncurses.wrefresh(@window)
end
get_list_index(title, list, numbers) click to toggle source

Display a scrollable ‘list` of strings in a Dialog, allowing the user to select one.

@return The index in the list of the value selected.

If ‘numbers` is true, the displayed list items will be numbered.

@note ‘list` must be Arrays of Strings.

# File lib/rndk/core/quick_widgets.rb, line 226
def get_list_index(title, list, numbers)
  return nil if list.class != Array or list.empty?

  selected = -1
  height = 10
  width = -1
  len = 0

  # Determine the height of the list.
  if list.size < 10
    height = list.size + if title.size == 0 then 2 else 3 end
  end

  # Determine the width of the list.
  list.each { |item| width = [width, item.size + 10].max }

  width = [width, title.size].max
  width += 5

  scrollp = RNDK::Scroll.new(self, {
                               :x => RNDK::CENTER,
                               :y => RNDK::CENTER,
                               :width => width,
                               :height => height,
                               :title => title,
                               :items => list,
                               :numbers => numbers
                             })
  if scrollp.nil?
    self.refresh
    return -1
  end

  selected = scrollp.activate

  # Check how they exited.
  if scrollp.exit_type != :NORMAL
    selected = -1
  end

  scrollp.destroy
  self.refresh

  selected
end
get_string(title, label, initial_text="") click to toggle source

Pops up an Entry Widget and returns the value supplied by the user.

‘title`, `label` and `initial_text` are passed to the Widget.

# File lib/rndk/core/quick_widgets.rb, line 276
def get_string(title, label, initial_text="")

  widget = RNDK::Entry.new(self, {
                             :x => RNDK::CENTER,
                             :y => RNDK::CENTER,
                             :title => title,
                             :label => label,
                             :field_width => 40,
                             :initial_text => initial_text
                           })

  value = widget.activate

  # Make sure they exited normally.
  if widget.exit_type != :NORMAL
    widget.destroy
    return nil
  end

  # Return a copy of the string typed in.
  value = widget.get_text.clone
  widget.destroy

  value
end
popup_dialog(message, buttons) click to toggle source

Shows a centered pop-up Dialog box with ‘message` label and each button label on `buttons`.

@return The user choice or ‘nil` if wrong parameters

were given.

@note: ‘message` and `buttons` must be Arrays of Strings.

popup_label(message) click to toggle source

Quickly pops up a ‘message`.

Creates a centered pop-up Label Widget that waits until the user hits a character.

@note: ‘message` must be a String or an Array of Strings.

popup_label_color(message, attrib) click to toggle source

Quickly pops up a ‘message`, using `attrib` for the background of the dialog.

@note: ‘message` must be an array of strings.

refresh() click to toggle source

Redraws all Widgets inside this Screen.

# File lib/rndk/core/screen.rb, line 206
def refresh
  focused = -1
  visible = -1

  RNDK.window_refresh(@window)

  # We erase all the invisible widgets, then only draw it all back, so
  # that the widgets can overlap, and the visible ones will always be
  # drawn after all the invisible ones are erased
  (0...@widget_count).each do |x|
    obj = @widget[x]
    if obj.valid_type?
      if obj.is_visible
        if visible < 0
          visible = x
        end
        if obj.has_focus && focused < 0
          focused = x
        end
      else
        obj.erase
      end
    end
  end

  (0...@widget_count).each do |x|
    obj = @widget[x]

    if obj.valid_type?
      obj.has_focus = (x == focused)

      if obj.is_visible
        obj.draw
      end
    end
  end
end
register(rndktype, widget) click to toggle source

Adds a Widget to this Screen.

@note This is called automatically when a widget is created.

  • ‘rndktype` states what RNDK Widget type this widget is.

  • ‘widget` is a pointer to the Widget itself.

# File lib/rndk/core/screen.rb, line 123
def register(rndktype, widget)

  # Expanding the limit by 2
  if (@widget_count + 1) >= @widget_limit
    @widget_limit += 2
    @widget_limit *= 2
    @widget.concat Array.new(@widget_limit - @widget.size, nil)
  end

  if widget.valid_type?
    self.set_screen_index(@widget_count, widget)
    @widget_count += 1
  end
end
select_file(title) click to toggle source

Displays a file-selection dialog with ‘title`.

@return The selected filename, or ‘nil` if none was selected.

TODO FIXME This widget is VERY buggy.

# File lib/rndk/core/quick_widgets.rb, line 191
def select_file title

  fselect = RNDK::Fselect.new(self, {
                                :x => RNDK::CENTER,
                                :y => RNDK::CENTER,
                                :width =>-20,
                                :height => -4,
                                :title => title,
                                :label => 'File: '
                              })

  filename = fselect.activate

  # Check the way the user exited the selector.
  if fselect.exit_type != :NORMAL
    fselect.destroy
    self.refresh
    return nil
  end

  # Otherwise...
  fselect.destroy
  self.refresh
  filename
end
unregister(widget) click to toggle source

Removes a Widget from this Screen.

@note This is called automatically when a widget is destroyed.

This does NOT destroy the widget, it removes the Widget from any further refreshes by Screen#refresh.

‘rndktype` states what RNDK Widget type this widget is. `widget` is a pointer to the Widget itself.

# File lib/rndk/core/screen.rb, line 148
def unregister widget
  return unless (widget.valid_type? and (widget.screen_index >= 0))

  index = widget.screen_index
  widget.screen_index = -1

  # Resequence the widgets
  (index...self.widget_count - 1).each do |x|
    self.set_screen_index(x, self.widget[x+1])
  end

  if self.widget_count <= 1
    # if no more widgets, remove the array
    self.widget = []
    self.widget_count = 0
    self.widget_limit = 0

  else
    self.widget[self.widget_count] = nil
    self.widget_count -= 1

    # Update the widget-focus
    if self.widget_focus == index
      self.widget_focus -= 1
      Traverse.set_next_focus(screen)

    elsif self.widget_focus > index
      self.widget_focus -= 1
    end
  end
end
view_file(title, filename, buttons) click to toggle source

Reads ‘filename`’s contents and display it on a Viewer Widget.

‘title` and `buttons` are applied to the Widget.

The viewer shows the contents of the file supplied by the ‘filename` value.

It returns the index of the button selected, or -1 if the file does not exist or if the widget was exited early.

# File lib/rndk/core/quick_widgets.rb, line 165
def view_file(title, filename, buttons)

  info = []
  result = 0

  # Open the file and read the contents.
  lines = RNDK.read_file filename

  # If we couldn't read the file, return an error.
  if lines == -1
    result = lines
  else
    result = self.view_info(title,
                            info,
                            buttons,
                            true)
  end
  result
end
view_info(title, info, buttons, hide_control_chars=true) click to toggle source

Display a long string set ‘info` in a Viewer Widget.

‘title` and `buttons` are applied to the Widget.

‘hide_control_chars` tells if we want to hide those ugly `^J`, `^M` chars.

@return The index of the selected button. @note ‘info` and `buttons` must be Arrays of Strings.

# File lib/rndk/core/quick_widgets.rb, line 120
def view_info(title, info, buttons, hide_control_chars=true)
  return nil if info.class != Array or info.empty?
  return nil if buttons.class != Array or buttons.empty?

  selected = -1

  # Create the file viewer to view the file selected.
  viewer = RNDK::Viewer.new(self, {
                              :x => RNDK::CENTER,
                              :y => RNDK::CENTER,
                              :width => -6,
                              :height => -16,
                              :buttons => buttons,
                              :shadow => true
                            })

  # Set up the viewer title, and the contents of the widget.
  viewer.set({
               :title => title,
               :items => info,
               :hide_control_chars => hide_control_chars
             })

  selected = viewer.activate

  # Make sure they exited normally.
  if viewer.exit_type != :NORMAL
    viewer.destroy
    return -1
  end

  # Clean up and return the button index selected
  viewer.destroy
  selected
end

Protected Instance Methods

set_screen_index(number, obj) click to toggle source
# File lib/rndk/core/screen.rb, line 282
def set_screen_index(number, obj)
  obj.screen_index = number
  obj.screen = self
  @widget[number] = obj
end
swap_indexes(n1, n2) click to toggle source

Swap positions of widgets with indexes ‘n1` and `n2`.

# File lib/rndk/core/screen.rb, line 293
def swap_indexes(n1, n2)
  return unless (n1 != n2) and (self.valid_index? n1) and (self.valid_index? n2)

  o1 = @widget[n1]
  o2 = @widget[n2]
  self.set_screen_index(n1, o2)
  self.set_screen_index(n2, o1)

  if @widget_focus == n1
    @widget_focus = n2

  elsif @widget_focus == n2
    @widget_focus = n1
  end
end
valid_index?(n) click to toggle source
# File lib/rndk/core/screen.rb, line 288
def valid_index? n
  (n >= 0) and (n < @widget_count)
end