# Krzysztof B. Wicher 2008 version v0.6
#
# Menu = Widget emulating pop-up menu with a given ":title" and ":width" and
# at the given coordinates (":left", ":top") in the current slot.
# One can choose if the menu will pop-up upon hoovering on -
# :pop_up_on_click=>false or upon clicking on the title - :pop_up_on_click=>true
# One can choose to leave menu open upon moving mouse out - :pop_out_on_leave=>false
# or to hide it - :pop_out_on_leave=>false
# Menu items are loaded from the ":items" array. One can also specify the items in the menu
# which should be inactive/unresposive to the hoovering and clicking ":blocked" array.
# Moreover, one can dinamically change the ":items" and ":blocked" using attr_accessors.
# Method returns the "item" clicked.
# ":state" attr-accessor allows to disable (:disabled) and enable (:enable) the menu
# State can be toggled by using "toggle_state" method.
# For simplicity method hard-codes menu colors
class Menu < Shoes::Widget
attr_accessor :items, :blocked, :state
def set_blocked(blocked)
@blocked=blocked
end
def toggle_state
case @state
when :enabled then @state=:disabled
when :disabled then @state=:enabled
end
end
def initialize opts={}
@state=:enabled
@title=opts[:title]
@items=opts[:items]
@blocked=opts[:blocked]
@leavee=opts[:pop_out_on_leave]
@width=opts[:width]
hor_mult=0
vert_mult=0
showed=false
clicke=opts[:pop_up_on_click]
case opts[:orientation]
when :ver then vert_mult=25
when :hor then hor_mult=@width
end
nostroke
fill yellow
m=[]
flot = flow :top=>0, :left=>0, :width=>@width-1, :height=>24 do
background yellow
para @title, :align=>'center'
leave do
flot.clear do
background yellow
para @title, :align=>'center'
end
end
end
fl=stack :left=>0, :top=>0, :width=>(hor_mult+1)*@items.size+@width, :height=>(vert_mult+1)*@items.size+25 do
leave do
if showed
if @leavee==true
m.each_index do|l|
m[l].clear
m[l].remove
end
showed=false
end
end
end
# IF POP-UP BY CLICKING
if clicke==true
flot.click do
if @state==:enabled
flot.hover do
flot.clear do
background orange
para @title, :align=>'center'
end
end
if showed==false
showed=true
@items.each_with_index do |i,l|
m[l]=stack :top=>vert_mult*(l+1),:left=>hor_mult*(l+1),:width=>@width-1,:height=>24 do
if not @blocked.include?(i)
background red
para @items[l]
else
background gray
para @items[l]
end
end
m[l].hover do
if not @blocked.include?(i)
m[l].clear do
background green
para @items[l]
end
end
end
m[l].leave do
if not @blocked.include?(i)
m[l].clear do
background red
para @items[l]
end
end
end
m[l].click do
if not @blocked.include?(i)
showed=false
res=i
m.each{|i| i.remove}
yield res
end
end
end
else
m.each{|i| i.remove}
showed=false
end
end
end
#IF POP-UP BY HOVER
elsif clicke==false
flot.hover do
if @state==:enabled
flot.clear do
background orange
para @title, :align=>'center'
end
showed=true
@items.each_with_index do |i,l|
m[l]=stack :top=>(vert_mult*(l+1)),:left=>hor_mult*(l+1),:width=>@width-1,:height=>24 do
if not @blocked.include?(i)
background red
para @items[l]
else
background gray
para @items[l]
end
end
m[l].hover do
if not @blocked.include? i
m[l].clear do
background green
para @items[l]
end
end
end
m[l].leave do
if not @blocked.include?(i)
m[l].clear do
background red
para @items[l]
end
end
end
m[l].click do
if not @blocked.include?(i)
res=i
m.each{|i|
i.clear
i.remove}
showed=false
yield res
end
end
m[l].show
end
end
end
end
end
end
end
# TEST APPLICATION
Shoes.app :width=>450, :height=>350 do
stack do
subtitle "Menu test"
@t=edit_line "Click the menu"
items=["item1","item2", "item3"]
items1=["it1","it2", "it3", "it4"]
m1=menu(:title=>"Menu1",:left=>80, :top=>100, :width=>70, :items=>items,:blocked=>["item2"], :orientation=>:ver, :pop_up_on_click=>true, :pop_out_on_leave=>false){|x| @t.text=x}
m2=menu(:title=>"Menu2",:left=>10, :top=>130, :width=>70, :items=>items1, :blocked=>["it3"], :orientation=>:hor, :pop_up_on_click=>false, :pop_out_on_leave=>true){|x| alert "You clicked: #{x}"}
button "Close", :top=>180, :left=> 200 do
close
end
button "Change Menu2 items", :top=>220, :left=> 200 do
m2.items=["it3", "it4"]
end
button "Change back Menu2 items", :top=>260, :left=> 200 do
m2.items=["it1","it2", "it3", "it4"]
end
button "Toggle enable/disable Menu2", :top=>300, :left=> 200 do
m2.toggle_state
end
end
end