Class: Canis::PromptMenu

Inherits:
Object show all
Includes:
Io
Defined in:
lib/canis/core/util/promptmenu.rb

Overview

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:"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Io

#__create_footer_window, #clear_this, #get_file, #print_this, #rb_getchar, #rb_gets, #rb_getstr, #warn

Constructor Details

#initialize(caller, text = "Choose:", &block) ⇒ PromptMenu

Returns a new instance of PromptMenu.



63
64
65
66
67
68
# 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

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



62
63
64
# File 'lib/canis/core/util/promptmenu.rb', line 62

def options
  @options
end

#textObject (readonly)

Returns the value of attribute text.



61
62
63
# File 'lib/canis/core/util/promptmenu.rb', line 61

def text
  @text
end

Class Method Details

.create_menuitem(*args) ⇒ Object

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



101
102
103
# File 'lib/canis/core/util/promptmenu.rb', line 101

def self.create_menuitem *args
  item = CMenuItem.new(*args.flatten)
end

Instance Method Details

#add(*menuitem) ⇒ Object Also known as: item



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 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

#create_mitem(*args) ⇒ Object



97
98
99
# File 'lib/canis/core/util/promptmenu.rb', line 97

def create_mitem *args
  item = CMenuItem.new(*args.flatten)
end

#display_columns(config = {}) ⇒ Object Also known as: display_new, display

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.



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# 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

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.



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/canis/core/util/promptmenu.rb', line 107

def menu_tree mt, pm = self
  mt.each_pair { |ch, code| 
    if code.is_a? Canis::MenuTree
      item = pm.add(ch, code.value, "") 
      current = PromptMenu.new @caller, code.value
      item.action = current
      menu_tree code, current
    else
      item = pm.add(ch, code.to_s, "", code) 
    end
  }
end

To allow a more rubyesque way of defining menus and submenus



121
122
123
124
125
# File 'lib/canis/core/util/promptmenu.rb', line 121

def submenu key, label, &block
  item = CMenuItem.new(key, label)
  @options << item
  item.action = PromptMenu.new @caller, label, &block
end