class Canis::Menu

class Menu. Contains menuitems, and can be a menuitem itself.

Opens out another list of menuitems.

Attributes

coffset[RW]
col[RW]
current_menu[R]
enabled[RW]
items[R]
panel[R]
parent[RW]
row[RW]
row_margin[R]
text[R]
width[RW]
window[R]

Public Class Methods

new(text, &block) click to toggle source
Calls superclass method Canis::MenuItem::new
# File lib/canis/core/widgets/rmenu.rb, line 202
def initialize text, &block
  @text = text
  @items = []
  @enabled = true
  @current_menu = []
  super text, nil, &block
  @row ||=10
  @col ||=10
  @coffset = 0
  @@menus ||= []
  @active_index = nil # 2011-09-25 V1.3.1 otherwise crashing in select_right
end

Public Instance Methods

<<(menuitem)
Alias for: add
add(menuitem) click to toggle source

item could be menuitem or another menu (precreated)

# File lib/canis/core/widgets/rmenu.rb, line 222
def add menuitem
  #$log.debug " YYYY inside add menuitem #{menuitem.text} "
  @items << menuitem
  return self
end
Also aliased as: <<
add_separator() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 249
def add_separator 
  @items << MenuSeparator.new
end
Also aliased as: separator
array_width(a) click to toggle source

private returns length of longest item in array

# File lib/canis/core/widgets/rmenu.rb, line 542
def array_width a
  longest = a.max {|a,b| a.to_s.length <=> b.to_s.length }
  #$log.debug "array width #{longest}"
  longest.to_s.length
end
check_mnemonics(cmenu, ch) click to toggle source

checks given key against current menu's items and fires key if added on 2008-11-27 12:07

# File lib/canis/core/widgets/rmenu.rb, line 642
    def check_mnemonics cmenu, ch
#     $log.debug "inside check_mnemonics #{ch}"
      key = ch.chr.downcase rescue ""
      cmenu.items.each do |item|
        next if !item.respond_to? :mnemonic or item.mnemonic.nil?
#       $log.debug "inside check_mnemonics #{item.mnemonic}"
        if key == item.mnemonic.downcase && item.enabled # 2010-09-11 00:03 enabled
          ret = item.fire
          return ret #0 2009-01-23 00:45
        end
      end
      return :UNHANDLED
    end
clear_menus() click to toggle source

called upon firing so when we next show menubar there are not any left overs in here.

# File lib/canis/core/widgets/rmenu.rb, line 215
def clear_menus
  @@menus = []
end
create_window() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 471
    def create_window  # menu
      margin = 2 # flush against parent
      @width = array_width(@items) + 1 # adding 1 since menus append a ">" 2011-09-24
      $log.debug "create window menu #{@text}: r #{@row} ,col #{@col}, wd #{@width}   " 
      t = @row+1
      h = @items.length+3
      ww = @width+margin
      ww1 = @width
      max = Ncurses.LINES-1
      if t + h > max
        t = 2 # one below menubar, not touching
        if h > max
          i = ((h*1.0)/max).ceil
          h = max - 1
          ww = ww * i # FIXME we need to calculate
        end
      end # t + 1
      $log.debug "create window menu #{@text}: t  #{t} ,h #{h}, w: #{ww} , col #{@col}   max #{max}   " 

      #@layout = { :height => @items.length+3, :width => ww, :top => @row+1, :left => @col }
      # earlier col had the offset to start the next level, I was not using it to print
      # but with mulitple cols i am using it. So, this col will overwrite existing menu.
      @layout = { :height => h-1, :width => ww, :top => t, :left => @coffset } 
      @win = Canis::Window.new(@layout)
      @window = @win
      @window.name = "WINDOW:menu"
      @color_pair ||= get_color($datacolor, @color, @bgcolor)
      @rev_color_pair ||= get_color($reversecolor, @color, @bgcolor)
      @win.bkgd(Ncurses.COLOR_PAIR(@color_pair));
      @panel = @win.panel
        #@window.printstring( 0, 0, "+%s+" % ("-"*@width), $reversecolor)
        @window.printstring( 0, 0, "+%s+" % ("-"*(ww1)), @rev_color_pair)
        saved_r = 1
        r = 1
        #saved_c = @col+@width+margin # margins???
        saved_c = 0 ; # actual program uses 0 in repain for col
        c = saved_c
            $log.debug "create window menu #{@text}: first col  r  #{r} ,c #{c}" 
        @items.each do |item|
          #break if r > h # added 2011-09-24 for large number of items - causes error
          if r >= h-2
            @window.printstring( h-2, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
            r = saved_r
            c += (@width + 2)
            @window.printstring( 0, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
            $log.debug "create window menu #{@text}: new col  r  #{r} ,c #{c}, #{item.text} " 
          end
            item.row = r
            item.col = c
            item.coffset = @coffset+@width+margin # margins???


            item.width = @width
            #item.window = @window
            item.parent = self
            item.color = @color; item.bgcolor = @bgcolor
            item.repaint
          r+=1
        end
#        @window.printstring( r, 0, "+%s+" % ("-"*@width), $reversecolor) # changed 2011 2011-09-24
        @window.printstring( h-2, 0, "+%s+" % ("-"*(ww1)), @rev_color_pair)
        # in case of multiple rows
        @window.printstring( r, c, "+%s+" % ("-"*(ww1)), @rev_color_pair)
        # added box with proper ncurses extended char set 2014-08-27 - 14:30
        @window.print_border_only 0,0,h-2, ww, @rev_color_pair
        select_item 0
      @window.refresh
      return @window
    end
destroy() click to toggle source

destroys windows and each item within (submenus)

# File lib/canis/core/widgets/rmenu.rb, line 548
def destroy
  $log.debug "DESTROY menu #{@text}"
  return if @window.nil?
  @visible = false
  #2014-05-12 - 20:53 next 3 replaced with destroy since destroy refreshes root window.
  #panel = @window.panel
  #Ncurses::Panel.del_panel(panel.pointer) if !panel.nil?
  #@window.delwin if !@window.nil?
  @window.destroy
  @items.each do |item|
    item.destroy
  end
  @window = nil
end
fire() click to toggle source

menu -

# File lib/canis/core/widgets/rmenu.rb, line 273
def fire
  $log.debug "menu fire called: #{text}  " 
  if @window.nil?
    #repaint
    # added 2011-09-24 adding ability to generate list of items
    if @item_list
      # generate a list, but we need to know what to do with that list.
      @items = []
      l = @item_list.call self, *@item_list_args if !@item_list.nil?
      if l.nil? || l.size == 0
        item(:NO_MENUITEMS)
      else
        # for each element returned create a menuitem, and attach the command to it.
        l.each { |e| it = item(e); 
          if @command # there should be a command otherwise what's the point
            it.command(@args) do @command.call(it, it.text) end;
          else
            it.command(@args) do alert("No command attached to #{it.text} ") end;
            $log.warn "No command attached to item_list "
          end
        }
      end
      $log.debug "menu got items #{@items.count} " 
    end
    if @items.empty? # user did not specify any items
        item(:NO_MENUITEMS)
    end
    create_window 
    if !@parent.is_a? Canis::MenuBar 
      @parent.current_menu << self
      @@menus << self # NEW
    end
  else
    ### shouod this not just show ?
    $log.debug "menu fire called: #{text} ELSE XXX WHEN IS THIS CALLED ? 658 #{@items[@active_index].text}  " 
    if @active_index # sometimes no menu item specified 2011-09-24 NEWMENU
      return @items[@active_index].fire # this should happen if selected. else selected()
    end
  end
  #@action.call if !@action.nil?
end
get_item(i) click to toggle source

added 2009-01-21 12:09 NEW

# File lib/canis/core/widgets/rmenu.rb, line 255
def get_item i
  @items[i]
end
handle_key(ch) click to toggle source

menu LEFT, RIGHT, DOWN, UP, ENTER item could be menuitem or another menu

# File lib/canis/core/widgets/rmenu.rb, line 565
def handle_key ch
  if !@current_menu.empty?
    cmenu = @current_menu.last
  else 
    cmenu = self
  end
  if !@@menus.empty?
   cmenu = @@menus.last
  else 
   cmenu = self
  end
  case ch
  when KEY_DOWN
    cmenu.select_next_item
    #return cmenu.fire # XXX 2010-10-16 21:39 trying out
    if cmenu.is_a? Canis::Menu 
      #alert "is a menu" # this gets triggered even when we are on items
    end
  when KEY_UP
    cmenu.select_prev_item
  when KEY_ENTER, 10, 13, 32 # added 32 2008-11-27 23:50
    return cmenu.fire
  when KEY_LEFT
    if cmenu.parent.is_a? Canis::Menu 
   #$log.debug "LEFT IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
   #$log.debug "left IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
    end
    ret = cmenu.select_left_item # 2011-09-24 V1.3.1 attempt to goto left item if columns
    if ret == :UNHANDLED
      if cmenu.parent.is_a? Canis::MenuBar #and !cmenu.parent.current_menu.empty?
        #$log.debug " ABOU TO DESTROY DUE TO LEFT"
        cmenu.current_menu.pop
        @@menus.pop ## NEW
        cmenu.destroy
        return :UNHANDLED
      end
      # LEFT on a menu list allows me to close and return to higher level
      if cmenu.parent.is_a? Canis::Menu #and !cmenu.parent.current_menu.empty?
        #$log.debug " ABOU TO DESTROY DUE TO LEFT"
        cmenu.current_menu.pop
        @@menus.pop ## NEW
        cmenu.destroy
        #return :UNHANDLED
      end
    end
  when KEY_RIGHT
   $log.debug "RIGHTIN MENU : #{text}  "
   if cmenu.active_index
    if cmenu.items[cmenu.active_index].is_a?  Canis::Menu 
      #alert "could fire here cmenu: #{cmenu.text}, par: #{cmenu.parent.text} "
      cmenu.fire
      return
   #$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.parent.current_menu.length}"
   #$log.debug "right IN MENU : #{cmenu.parent.class} len: #{cmenu.current_menu.length}"
    end
   end
   # This introduces a bug if no open items
   ret = cmenu.select_right_item # 2011-09-24 V1.3.1 attempt to goto right item if columns
   #alert "attempting to select right #{ret} "
    if ret == :UNHANDLED
      #if cmenu.parent.is_a? Canis::Menu and !cmenu.parent.current_menu.empty?
      if cmenu.parent.is_a? Canis::MenuBar #and !cmenu.current_menu.empty?
        $log.debug " ABOU TO DESTROY DUE TO RIGHT"
        cmenu.current_menu.pop
        @@menus.pop
        cmenu.destroy
        return :UNHANDLED
      end
    end
  else
    ret = check_mnemonics cmenu, ch
    return ret
  end
end
highlight(tf=true) click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 452
def highlight tf=true # menu
  if @parent.is_a? Canis::MenuBar  # top level menu
    #acolor = get_color($datacolor, @bgcolor, @color)
    #@parent.window.printstring( @row, @col, " %s " % text, acolor)
    @color_pair  ||= get_color($reversecolor, @color, @bgcolor)
      att =  Ncurses::A_REVERSE
      @parent.window.mvchgat(y=@row, x=@col+1, text.length+1, att, @color_pair, nil)
  else
    #$log.debug "MENU SUBMENU menu highlight: #{text} #{@row} #{@col}, PW #{@parent.width}  "
    acolor = tf ? $datacolor : $reversecolor
    att = tf ? Ncurses::A_REVERSE : Ncurses::A_NORMAL
    #@parent.window.mvchgat(y=@row, x=1, @width, Ncurses::A_NORMAL, color, nil)
    #@parent.window.mvchgat(y=@row, x=1, @parent.width, Ncurses::A_NORMAL, color, nil)
    # above line did not work with vt100/vt200 next does
    #      @parent.window.mvchgat(y=@row, x=1, @parent.width, att, $reversecolor, nil) # changed 2011 2011-09-24
    @parent.window.mvchgat(y=@row, x=1, @parent.width, att, @color_pair, nil)
    @parent.window.wrefresh
  end
end
insert_separator(ix) click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 246
def insert_separator ix
  @items.insert ix, MenuSeparator.new
end
item(text, mnem=nil, &block) click to toggle source

add item method which could be used from blocks add 2010-09-10 12:20 simplifying

# File lib/canis/core/widgets/rmenu.rb, line 231
def item text, mnem=nil, &block
  #$log.debug "YYYY inside M: menuitem text #{text}  "
  m =  MenuItem.new text, mnem, &block 
  add m
  return m
end
item_list(*args, &block) click to toggle source

generate an item list at runtime for this menu

# File lib/canis/core/widgets/rmenu.rb, line 267
def item_list *args, &block 
  $log.debug ">>>item_list : #{@text} "
  @item_list = block if block_given?
  @item_list_args = args
end
menu(text, &block) click to toggle source

create a menu within a menu add menu method which could be used from blocks add 2010-09-10 12:20 simplifying

on_enter() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 415
def on_enter # menu.on_enter
  #$log.debug "menu onenter: #{text} #{@row} #{@col}  "
  # call parent method. XXX
    #if @parent.is_a? Canis::MenuBar
      #acolor = get_color($datacolor, @bgcolor, @color)
      #@parent.window.printstring( @row, @col, " %s " % text, acolor)
    #else
      highlight
    #end
    if !@window.nil? #and @parent.selected
      #$log.debug "menu onenter: #{text} calling window,show"
      @window.show
      select_item 0
    elsif @parent.is_a? Canis::MenuBar and  @parent.selected
      # only on the top level do we open a window if a previous one was opened
      #$log.debug "menu onenter: #{text} calling repaint CLASS: #{@parent.class}"
    #  repaint
      create_window
    end
end
on_leave() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 435
    def on_leave # menu.on_leave
      #$log.debug "menu onleave: #{text} #{@row} #{@col}  "
      # call parent method. XXX
      @color_pair  ||= get_color($reversecolor, @color, @bgcolor)
        if @parent.is_a? Canis::MenuBar 
#          @parent.window.printstring( @row, @col, " %s " % text, $reversecolor) # changed 2011 2011-09-24
          @parent.window.printstring( @row, @col, " %s " % text, @color_pair)
          @window.hide if !@window.nil?
        else
          #$log.debug "MENU SUBMEN. menu onleave: #{text} #{@row} #{@col}  "
          # parent is a menu
          highlight false
          #@parent.current_menu.pop
          #@@menus.pop
          #destroy
        end
    end
remove(n) click to toggle source

added 2009-01-21 12:09 NEW

# File lib/canis/core/widgets/rmenu.rb, line 259
def remove n
  if n.is_a? Integer
    @items.delete_at n
  else
    @items.delete n
  end
end
repaint() click to toggle source

user has clicked down, we shoud display items DRAW menuitems

# File lib/canis/core/widgets/rmenu.rb, line 316
def repaint # menu.repaint
  # OMG will not print anything if no items !
  # When we do item generation this list will be empty
  #return if @items.nil? or @items.empty? # commented 2011-09-24 NEWMENU
  #$log.debug "menu repaint: #{text} row #{@row} col #{@col}  "
  @color_pair  = get_color($reversecolor, @color, @bgcolor)
  if !@parent.is_a? Canis::MenuBar 
    @parent.window.printstring( @row, 0, "|%-*s>|" % [@width-1, text], @color_pair)
    @parent.window.refresh
  end
  if @window.nil?
    #create_window
  else
    @window.show
    select_item 0
    @window.refresh
  end
end
select_item(ix0) click to toggle source

recursive if given one not enabled goes to next enabled

# File lib/canis/core/widgets/rmenu.rb, line 336
def select_item ix0
  return if @items.nil? or @items.empty?
   #$log.debug "insdie select  item :  #{ix0} active: #{@active_index}"
  if !@active_index.nil?
    @items[@active_index].on_leave 
  end
  previtem = @active_index
  @active_index = ix0
  if @items[ix0].enabled
    @items[ix0].on_enter
  else
    #$log.debug "insdie sele nxt item ENABLED FALSE :  #{ix0}"
    if @active_index > previtem
      select_next_item
    else
      select_prev_item
    end
  end
  @window.refresh
end
select_left_item() click to toggle source

If multi-column menuitems then try going to a left item (prev column same row) NOTE It should only come here if items are open, otherwise row and col will be blank. NOTE active_index nil means no items open

# File lib/canis/core/widgets/rmenu.rb, line 380
def select_left_item
  return :UNHANDLED if @items.nil? or @items.empty? or @active_index.nil?
  index = nil
  crow = @items[@active_index].row 
  ccol = @items[@active_index].col 
  @items.each_with_index { |e, i| index = i if e.row == crow && e.col < ccol }
  if index
    select_item index
  else
    return :UNHANDLED
  end
end
select_next_item() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 356
def select_next_item
  return if @items.nil? or @items.empty?
   #$log.debug "insdie sele nxt item :  #{@active_index}"
  @active_index = -1 if @active_index.nil?
  if @active_index < @items.length-1
    select_item @active_index + 1
  else
  #  select_item 0
  end
end
select_prev_item() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 366
def select_prev_item
  return if @items.nil? or @items.empty?
   #$log.debug "insdie sele prv item :  #{@active_index}"
  if @active_index > 0
    select_item @active_index - 1
  else
  #select_item @items.length-1
  end
end
select_right_item() click to toggle source

@since 1.3.1 2011-09-24 If multi-column menuitems then try going to a right item (next column same row) Only if items are open, not from a menubar menu

# File lib/canis/core/widgets/rmenu.rb, line 395
def select_right_item
  return :UNHANDLED if @items.nil? or @items.empty? or @active_index.nil?
  crow = @items[@active_index].row 
  ccol = @items[@active_index].col 
  #alert "inside select right with #{@items.size} #{@items[@active_index].text}: items. r #{crow} col #{ccol}  "
  index = nil
  @items.each_with_index { |e, i| 
    $log.debug " select_right #{e.row} == #{crow} , #{e.col} > #{ccol}  " if $log.debug? 
    if e.row == crow && e.col > ccol 
      index = i
      $log.debug "YYY select_right #{e.row} == #{crow} , #{e.col} > #{ccol} FOUND #{i}  " if $log.debug? 
      break
    end
  }
  if index
    select_item index
  else
    return :UNHANDLED
  end
end
separator()
Alias for: add_separator
show() click to toggle source

menu

# File lib/canis/core/widgets/rmenu.rb, line 656
def show # menu.show
  #$log.debug "show (menu) : #{@text} "
  if @window.nil?
    create_window #@col+@width
  end
    @window.show 
    select_item 0
end
to_s() click to toggle source
# File lib/canis/core/widgets/rmenu.rb, line 218
def to_s
  @text
end