rbcurse (for ruby 1.9.x)

I have moved rbcurse to ffi-ncurses (earlier ncurses gem) since 1.3.0.

Please report bugs on github/rkumar/rbcurse mentioning version. Your program dependency should be an explicit rbcurse version since I am doing a lot of improvements, cleaning up etc in the code base.

If you are looking for the ncurses version, please goto branch rbcurse1.2.0. I am not likely to support that henceforth due to the difficulty in installing ncurses gem.

Thanks a lot to Sean O’Halpin for the ffi-ncurses gem and immediately responding to my queries. I am testing on OSX Snow Leopard with ruby 1.9.2, TERM=screen on zsh.

Check downloads at http://github.com/rkumar/rbcurse/downloads

test2.rb works - i always give it a quick run after making changes. If using ruby1.9.2, you might say: ruby -I. test2.rb.

DESCRIPTION:

A small but comprehensive widget library written in ruby for creating ncurses applications.

FEATURES

Above may be created using DSL like syntax, or hashes, and modified at runtime. Very flexible unlike ncurses forms and fields.

Current work

Old: I’ve just added vi and emacs key bindings to some classes, multiple object containers such as MultiContainer and MultiTextView. Emacs like kill-ring in TextArea and TextView. Tabbedpane can have unlimited tabs, we can scroll the tabs. Bunch of other stuff. Multiple keys can be bound to a Proc or symbol as in emacs and vim (dd or C-x C-f).

Sample programs:

PROBLEMS, ISSUES

Splitpane

Deprecated. Please use vimsplit instead. It’s cleaner and hopefully easier to use. Splitpanes suffered from the problem of the system not knowing which pane the user was issuing a command (resize) in (when there were embedded panes).

Scrollpane - Avoid this. Listboxes and textareas already implement scrolling. I was using pads

to implement a viewport, this was slow esp with scrollpanes within splitpanes, but the copywin() and related methods often gave errors or seg-faults.

The following are issues with terminals (or with ncurses-ruby in some cases) not with rbcurse.

I am developing and testing under “screen” under OS X Snow Leopard.

SYNOPSIS:

See lib/rbcurse/rwidgets.rb. For test programs, see test1, test2, testcombo etc in examples folder.

This depends only on “window” provided by ncurses. Does not use forms and fields. Minor changes and improvements may have happened to sample code below. See test programs for latest, working code.

THE following samples are only demonstrative of how widgets are built. See samples in examples folder for initialization of ncurses etc which is necessary before the following code can be run. The following samples may be slightly obsolete.

create a window and a form based on window

  @layout = { :height => 0, :width => 0, :top => 0, :left => 0 } 
  @win = VER::Window.new(@layout)

  @form = Form.new @win

create a bunch of fields with dependent labels

  r = 1; c = 22;
  %w[ name age company].each do |w|
    field = Field.new @form do
      name   w 
      row  r 
      col  c 
      display_length  30
      set_buffer "abcd #{w}" 
      set_label Label.new @form, {'text' => w}
    end
    r += 1
  end

create a variable (like TkVariable) and tie a label to it.

  $results = Variable.new
  $results.value = "A variable"
  var = RubyCurses::Label.new @form, {'text_variable' => $results, "row" => r, "col" => 22}
    r += 1

create a list and a list box based on the list.

    mylist = []
    0.upto(100) { |v| mylist << "#{v} scrollable data" }

    field = Listbox.new @form do
      name   "mylist" 
      row  r 
      col  1 
      width 40
      height 10
      list mylist
    end
    field.insert 5, "hello ruby", "so long python", "farewell java", "RIP .Net"

create a textarea for entry

    texta = TextArea.new @form do
      name   "mytext" 
      row  1 
      col  52 
      width 40
      height 20
    end
    texta << "hello there" << "Some text to go into textarea."
    texta << "HELLO ruby" << "Some text to go into textarea."

create a check box, updates a Variable

  checkbutton = CheckBox.new @form do
    text_variable $results
    #value = true
    onvalue "selected cb"
    offvalue "UNselected cb"
    text "Please click me"
    row 17
    col 22
  end

change field properties at any time by referring to them by name

  @form.by_name["age"].display_length = 3
  @form.by_name["age"].maxlen = 3
  @form.by_name["age"].set_buffer  "24"
  @form.by_name["name"].set_buffer  "Not focusable"
  @form.by_name["age"].chars_allowed = /\d/
  @form.by_name["company"].type(:ALPHA)
  @form.by_name["name"].set_focusable(false)

  @form.by_name["password"].color 'red'
  @form.by_name["password"].bgcolor 'blue'

  # restrict entry to some values
  password.values(%w[ scotty tiger secret qwerty])

  # validation using ruby's regular expressions

  field.valid_regex(/^[A-Z]\d+/)

bind events to forms, and fields

  @form.bind(:ENTER) { |f|   f.label.bgcolor = $promptcolor if f.instance_of? RubyCurses::Field}
  @form.bind(:LEAVE) { |f|  f.label.bgcolor = $datacolor  if f.instance_of? RubyCurses::Field}

create buttons

  ok_button = Button.new @form do
    text "OK"
    name "OK"
    row 18
    col 22
  end
  ok_button.command { |form| $results.value = "OK PRESS:";form.printstr(@window, 23,45, "OK CALLED") }
    #text "Cancel"
  cancel_button = Button.new @form do
    text_variable $results
    row 18
    col 28
  end
  cancel_button.command { |form| form.printstr(@window, 23,45, "Cancel CALLED"); throw(:close); }

create radio buttons

  colorlabel = Label.new @form, {'text' => "Select a color:", "row" => 20,
      "col" => 22, "color"=> "cyan"}
  $radio = Variable.new
  radio1 = RadioButton.new @form do
    text_variable $radio
    text "red"
    value "red"
    color "red"
    row 21
    col 22
  end
  radio2 = RadioButton.new @form do
    text_variable $radio
    text  "green"
    value  "green"
    color "green"
    row 22
    col 22
  end

create a messagebox

  @mb = RubyCurses::MessageBox.new do
    title "Enter your name"
    message "Enter your name"
    type :input
    default_value "rahul"
    default_button 0
  end
    #title "Color selector"
    #type :custom
    #buttons %w[red green blue yellow]
    #underlines [0,0,0,0]
  
 $log.debug "MBOX : #{@mb.selected_index} "
 $log.debug "MBOX : #{@mb.input_value} "

create a read-only scrollable view of data

    @textview = TextView.new @form do
      name   "myView" 
      row  16 
      col  52 
      width 40
      height 7
    end
    content = File.open("../../README.markdown","r").readlines
    @textview.set_content content

    ## set it to point to row 21
    @textview.top_row 21


    # lets scroll the text view as we scroll the listbox

    listb.bind(:ENTER_ROW, @textview) { |arow, tview| tview.top_row arow }
    
    # lets scroll the text view to the line you enter in the numeric
    # field
    @form.by_name["line"].bind(:LEAVE, @textview) { |fld, tv| tv.top_row(fld.getvalue.to_i) }

    # lets scroll the text view to the first match of the regex you
    # enter
    @form.by_name["regex"].bind(:LEAVE, @textview) { |fld, tv| tv.top_row(tv.find_first_match(fld.getvalue)) }

    # change the value of colorlabel to the selected radiobutton
    # (red or green)

    $radio.update_command(colorlabel) {|tv, label|  label.color tv.value}

    # change the attribute of colorlabel to bold or normal

    $results.update_command(colorlabel,checkbutton) {|tv, label, cb| 
        attrs =  cb.value ? 'bold' : nil; label.attrs(attrs)}

  # during menu creation, create a checkboxmenuitem

  item = RubyCurses::CheckBoxMenuItem.new "CheckMe"

  # when selected, make colorlabel attribute reverse.

  item.command(colorlabel){|it, label| att = it.getvalue ? 'reverse' :
      nil; label.attrs(att); label.repaint}

REQUIREMENTS:

(Note: 1.8.6 users: pls report any issues and suggest a fix or alternative if you encounter a method_missing)

INSTALL:

(In following commands, use sudo if installing gems in readonly are such as /opt/local/).

gem install rbcurse

Now go to the the examples folder and execute some examples. Each sample writes to a log file named rbc13.log (earlier view.log). If the examples folder is readonly, you will have to set LOGDIR to a writable folder as below.

cd examples 
ruby test2.rb
LOGDIR=~/tmp ruby test1.rb

LICENSE:

Copyright (c) 2008 -2010 rkumar

Same as ruby license.