The Accidental Rubyist

invalid byte sequence in UTF-8

rubycurses – Some code samples

with 6 comments

Here’s how you might create a messagebox (image in previous post):

     @mb = RubyCurses::MessageBox.new do
        title "Color selector"
        message "Choose a color"
        type :custom
        buttons %w[red green blue yellow]
        underlines [0,0,0,0]
      end

If you want one with an input box:

        message "Enter your name"
        type :input
        default_value "rahul"

This will give an OK and Cancel button. There are other types for OK, Yes/No, Yes/No/Cancel etc.

input message box

input message box

The “underline” property will underline the given index in the name. Since ncurses underline does not work on my terminal (Highline does), I’ve changed the color. The normal key as well as Alt/Meta key is used as a hotkey. For input dialog boxes, the normal key will be processed by the edit box so the meta key was required.

Creating a form and fields:

      @form = Form.new @win
      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

A form takes a window parameter, and manages painting and navigation of its focusable fields. We’ve also tied in a label with the field, so it can put a default location for it.

All all properties of a field can be modified at any time. The given name parameter can be used to recall them.

      @form.by_name["age"].display_length = 3
      @form.by_name["age"].maxlen = 3
      @form.by_name["age"].set_buffer  "24"
      @form.by_name["age"].chars_allowed = /\d/

      @form.by_name["name"].set_buffer  "Not focusable"
     @form.by_name["name"].set_focusable(false)
      @form.by_name["company"].type(:ALPHA)

Defining variable fields and tying them to widgets

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

This label changes whenever the value of result is changed.

Events

The form and fields have events such as ENTER and LEAVE.

      @form.bind(:ENTER) { |f|   f.label.bgcolor = $promptcolor }
      @form.bind(:LEAVE) { |f|  f.label.bgcolor = $datacolor  }

Buttons

Notable is the text and command.

      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") }
An OK and a variable button

An OK and a variable button

The name property of widgets is only for recalling them by name.

Radio Buttons

Here we create a label (using a hash, instead of the DSL way for a change).
Radio buttons are tied together by a Variable. On selection, the variable contains the value.

      Label.new @form, {'text' => "Select a language:", "row" => 20, "col" => 22}

      $radio = Variable.new
      radio1 = RadioButton.new @form do
        text_variable $radio
        text "ruby"
        value "ruby"
        row 21
        col 22
      end
      radio2 = RadioButton.new @form do
        text_variable $radio
        text  "java"
        value  "java"
        row 22
        col 22
      end

Listboxes

Don’t flee out of boredom. Just a minute more!

I create an array, and then set it in the listbox call. At a later point, i insert some more data into offset 5. Data may be deleted or inserted externally.

        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"

Checkboxes

I have lazily tied the box to the same Variable, you needn’t.

      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

Now those configuration screens should be easier to build.

Multi-line fields

multi-line text area

multi-line text area

        texta = TextArea.new @form do
          name   "mytext"
          row  1
          col  52
          width 40
          height 20
        end
        texta << "hello there" << "we are testing deletes in this application"
        texta << "HELLO there" << "WE ARE testing deletes in this application"

Menubars, menuitems

Since my pickaxe had no samples of Tk Menu’s, I pulled out my old Java Swing book from my attic, and implemented menus the way those fellers do.

menu bar showing hotkeys and separator

menu bar showing hotkeys and separator

menu showing accelerator keys

menu showing accelerator keys

menu showing a sub-menu

menu showing a sub-menu

      @mb = RubyCurses::MenuBar.new
      filemenu = RubyCurses::Menu.new "File"
      filemenu.add(item = RubyCurses::MenuItem.new("Open",'O'))
      item.command(@form) {|form|  form.printstr(@window, 23,45, "Open CALLED"); }

      filemenu.insert_separator 1
      item.accelerator = "Ctrl-X"
screen shot with menu bar

screen shot with menu bar

Now to post pictures of the screen. Its not well presented, since i’ve been busy creating widgets, but still…

Advertisements

Written by totalrecall

November 25, 2008 at 12:04 am

Posted in ncurses, rbcurse, ruby

Tagged with

6 Responses

Subscribe to comments with RSS.

  1. This is fantastic, where can we get the code? I’m sure you could get the community to help out on this if you put it on github.

    Nate Murray

    November 25, 2008 at 2:26 am

  2. Sorry, but why would anyone want to do this? Just kidding – I’m sure there’s a need somewhere… 🙂

    Ken Arnold (the creator of curses) was in my very first computer class at La Jolla High School in 1975.

    Mark Wilden

    November 25, 2008 at 4:50 am

  3. Yes I shall put it up on github, I assume its as simple as registering and creating a project.

    Mark, let me say in all this that I admire the curses/ncurses package. For 2 months I have been working extensively on forms and fields. Have reported issues and bugs to the ncurses-bugs list, some were accepted. Others, no response.

    I can understand that since ncurses has to support many platforms, they cannot take any enhancements. So i was hitting some walls here and there. And sadly, we are forced into a sequence of operations which makes it very difficult to write a friendly wrapper/library. I think you can also have only one form per window etc.

    Multiline fields don’t take newlines tabs etc. So you cant read up a file into a ML field and then dump it. If you press Enter, a newline or carriage return is not inserted.

    If I cut a line, I do not get the line so i can do a paste or Undo. I do not have the cursor positiion in the ML field. Cutting an empty line does not delete it.

    You cannot make a field readonly if your cursor is on it. …. There are many many issues i came across as i was creating my application builder. I would like to redo that entire effort using this wrapper (UGH – more refactoring!!) so it can be easily used by others.

    With this library, we have complete control since it’s in ruby. Since I am pretty new to ruby, the code should be pretty easy to understand 🙂

    totalrecall

    November 25, 2008 at 10:40 am

  4. A lot of people would benefit by this code.

    One example:
    Sysadmins who might appreciate improving their scripts with a nice interface on remote machines they administer.
    As this is curses, it would work fine over SSH.

    If you put the code on github, I am sure others in the Ruby community will help make this the best curses wrapper library yet.

    John

    November 25, 2008 at 12:44 pm

  5. Awesome! Love the syntax.
    Another immediate application comes to mind with this: As an educational tool for teaching children programming. My daughter started writing console-based programs (ie, simple games) in Ruby at 9 years old, and had something like this been available she could have made much more interesting programs. Sure, she could have gone to GUI but not only does it get much more complicated very quickly (when you take into account toolkits, etc.) but you either use GUI builders (which don’t t each you anything) or you write a LOT of code by hand. Now she’s making the jump to Ruby-based web apps. But for any future console apps I’ll certainly teach her this.

    zerohalo

    November 25, 2008 at 10:17 pm

  6. Really cool. Gotta implement Curses support for Eclipse SWT someday to get it automatically supported by Glimmer.

    Andy Maleh

    November 26, 2008 at 1:22 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: