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:
-
Screen#initialize
-
Screen#finish
## 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
Nothing… for now
Array with all the widgets currently on the screen
How many widgets we currently have
Index of the current focused widget
Maximum widget capacity of the screen (always expands)
Raw Ncurses window that represents this Screen
Public Class Methods
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
Returns the whole terminal screen height.
# File lib/rndk/core/screen.rb, line 63 def self.height Ncurses.LINES end
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
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
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
Returns the whole terminal screen width.
# File lib/rndk/core/screen.rb, line 58 def self.width Ncurses.COLS end
Public Instance Methods
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
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
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
Redraws all Widgets inside this Screen
.
# File lib/rndk/core/screen.rb, line 201 def draw self.refresh end
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
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
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
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.
# File lib/rndk/core/quick_widgets.rb, line 92 def popup_dialog(message, buttons) return nil if message.empty? or buttons.empty? choice = 0 self.cleanly do popup = RNDK::Dialog.new(self, { :x => RNDK::CENTER, :y => RNDK::CENTER, :text => message, :buttons => buttons }) popup.draw choice = popup.activate popup.destroy end choice end
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.
# File lib/rndk/core/quick_widgets.rb, line 47 def popup_label message self.cleanly do popup = RNDK::Label.new(self, { :x => RNDK::CENTER, :y => RNDK::CENTER, :text => message }) popup.draw # Wait for some input. Ncurses.keypad(popup.win, true) popup.getch popup.destroy end end
Quickly pops up a ‘message`, using `attrib` for the background of the dialog.
@note: ‘message` must be an array of strings.
# File lib/rndk/core/quick_widgets.rb, line 67 def popup_label_color(message, attrib) self.cleanly do popup = RNDK::Label.new(self, { :x => RNDK::CENTER, :y => RNDK::CENTER, :text => message }) popup.set_bg_color attrib popup.draw # Wait for some input Ncurses.keypad(popup.win, true) popup.getch popup.destroy end end
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
@note This is called automatically when a widget is created.
# 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
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
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
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
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
# 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 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
# File lib/rndk/core/screen.rb, line 288 def valid_index? n (n >= 0) and (n < @widget_count) end