class Canis::PromptMenu

An encapsulated form of yesterday's Most Menu

It keeps the internals away from the user. Its not really OOP in the sense that the PromptMenu is not a MenuItem. That's how it is in our Menu system, and that led to a lot of painful coding (at least for me). This is quite simple. A submenu contains a PromptMenu in its action object and is evaluated in a switch. A recursive loop handles submenus.

Prompting of menu options with suboptions etc. A block of code or symbol or proc is executed for any leaf node This allows us to define different menus for different objects on the screen, and not have to map all kinds of control keys for operations, and have the user remember them. Only one key invokes the menu and the rest are ordinary characters.

== Example

  menu = PromptMenu.new self do
    item :s, :goto_start
    item :b, :goto_bottom
    item :r, :scroll_backward
    item :l, :scroll_forward
    submenu :m, "submenu" do
      item :p, :goto_last_position
      item :r, :scroll_backward
      item :l, :scroll_forward
    end
  end
  menu.display_new :title => 'window title', :prompt => "Choose:"

Attributes

options[R]
text[R]

Public Class Methods

create_menuitem(*args) click to toggle source

Added this, since actually it could have been like this 2011-12-22

# File lib/canis/core/util/promptmenu.rb, line 101
def self.create_menuitem *args
  item = CMenuItem.new(*args.flatten)
end
new(caller, text="Choose:", &block) click to toggle source
# File lib/canis/core/util/promptmenu.rb, line 63
def initialize caller,  text="Choose:", &block
  @caller = caller
  @text = text
  @options = []
  yield_or_eval &block if block_given?
end

Public Instance Methods

add(*menuitem) click to toggle source
# File lib/canis/core/util/promptmenu.rb, line 69
def add *menuitem
  item = nil
  case menuitem.first
  when CMenuItem
    item = menuitem.first
    @options << item
  else
    case menuitem.size
    when 4
      item = CMenuItem.new(*menuitem.flatten)
    when 2
      # if user only sends key and symbol
      menuitem[3] = menuitem[1]
      item = CMenuItem.new(*menuitem.flatten)
    when 1
      if menuitem.first.is_a? Action
        item = menuitem.first
      else
        raise ArgumentError, "Don't know how to handle #{menuitem.size} : #{menuitem} "
      end
    else
      raise ArgumentError, "Don't know how to handle #{menuitem.size} : #{menuitem} "
    end
    @options << item
  end
  return item
end
Also aliased as: item
create_mitem(*args) click to toggle source
# File lib/canis/core/util/promptmenu.rb, line 97
def create_mitem *args
  item = CMenuItem.new(*args.flatten)
end
display(config={})
Alias for: display_columns
display_columns(config={}) click to toggle source

Display prompt_menu in columns using commandwindow This is an improved way of showing the “most” like menu. The earlier format would only print in one row.

# File lib/canis/core/util/promptmenu.rb, line 131
def display_columns config={}
  prompt = config[:prompt] || "Choose: "
  require 'canis/core/util/rcommandwindow'
  layout = { :height => 5, :width => Ncurses.COLS-0, :top => Ncurses.LINES-6, :left => 0 }
  rc = CommandWindow.new nil, :layout => layout, :box => true, :title => config[:title] || "Menu"
  w = rc.window
  r = 4
  c = 1
  color = $datacolor
  begin
    menu = @options
    $log.debug " DISP MENU "
    ret = 0
    len = 80
    while true
      h = {}
      valid = []
      labels = []
      menu.each{ |item|
        if item.respond_to? :hotkey
          hk = item.hotkey.to_s
        else
          raise ArgumentError, "Promptmenu needs hotkey or mnemonic"
        end
        # 187compat 2013-03-20 - 19:00 throws up
        labels << "%c. %s " % [ hk.getbyte(0), item.label ]
        h[hk] = item
        valid << hk
      }
      #$log.debug " valid are #{valid} "
      color = $datacolor
      #print_this(win, str, color, r, c)
      rc.display_menu labels, :indexing => :custom
      ch=w.getchar()
      rc.clear
      #$log.debug " got ch #{ch} "
      next if ch < 0 or ch > 255
      if ch == 3 || ch == ?\C-g.getbyte(0)
        clear_this w, r, c, color, len
        print_this(w, "Aborted.", color, r,c)
        break
      end
      ch = ch.chr
      index = valid.index ch
      if index.nil?
        clear_this w, r, c, color, len
        print_this(w, "Not valid. Valid are #{valid}. C-c/C-g to abort.", color, r,c)
        sleep 1
        next
      end
      #$log.debug " index is #{index} "
      item = h[ch]
      # I don;t think this even shows now, its useless
      if item.respond_to? :desc
        desc = item.desc
        #desc ||= "Could not find desc for #{ch} "
        desc ||= ""
        clear_this w, r, c, color, len
        print_this(w, desc, color, r,c)
      end
      action = item.action
      case action
        #when Array
      when PromptMenu
        # submenu
        menu = action.options
        title = rc.title
        rc.title title +" => " + action.text # set title of window to submenu
      when Proc
        #rc.destroy
        ##bottom needs to be refreshed somehow
        #FFI::NCurses.ungetch ?j
        rc.hide
        ret = action.call
        break
      when Symbol
        if @caller.respond_to?(action, true)
          rc.hide
          $log.debug "XXX:  IO caller responds to action #{action} "
          ret = @caller.send(action)
        elsif @caller.respond_to?(:execute_this, true)
          rc.hide
          ret = @caller.send(:execute_this, action)
        else
          alert "PromptMenu: unidentified action #{action} for #{@caller.class} "
          raise "PromptMenu: unidentified action #{action} for #{@caller.class} "
        end

        break
      else 
        $log.debug " Unidentified flying class #{action.class} "
        break
      end
    end # while
  ensure
    rc.destroy
    rc = nil
  end
end
Also aliased as: display_new, display
display_new(config={})
Alias for: display_columns
item(*menuitem)
Alias for: add
menu_tree(mt, pm = self) click to toggle source

create the whole thing using a MenuTree which has minimal information. It uses a hotkey and a code only. We are supposed to resolve the display text and actual proc from the caller using this code.

submenu(key, label, &block) click to toggle source

To allow a more rubyesque way of defining menus and submenus