# $Id: _menu.icn,v 1.1 2003-05-31 06:09:03 jeffery Exp $
##
# This class encapsulates a drop down menu, or a sub-menu.
#
# The left, centre and right labels/images of the elements
# within it are formatted within the menu automatically.
#
class Menu : SubMenu(
max_label_left_w,
max_label_mid_w,
max_label_right_w,
temp_win,
which_open,
menus
)
method set_parent_menu_bar(x)
self$MenuComponent.set_parent_menu_bar(x)
every (!self.menus)$set_parent_menu_bar(x)
return
end
##
# Add the given component to the Menu.
#
method add(c)
put(self.menus, c)
c$set_parent_menu(self)
end
method get_which_open()
return self.which_open
end
method resize()
local cw, dy, m
cw := self.parent_menu_bar.cwin
self.h := self.max_label_left_w := self.max_label_right_w := self.max_label_mid_w := 0
dy := BORDER_WIDTH
every m := !self.menus do {
#
# Set x, y of label position for sub items.
#
m$set_label_pos(self.x + BORDER_WIDTH, self.y + dy)
#
# Set their label size.
#
m$set_label_size()
#
# Increment height; compute maximum label element widths.
#
self.h +:= m.label_h
self.max_label_left_w <:= m.label_left_w
self.max_label_right_w <:= m.label_right_w
self.max_label_mid_w <:= m.label_mid_w
dy +:= m.label_h
}
#
# Height of object is height of total labels within, plus top and bottom border widths.
#
self.h +:= 2 * BORDER_WIDTH
#
# Width is total of all maximum label elements, plus left and right border widths.
#
self.w := self.max_label_left_w + self.max_label_mid_w + self.max_label_right_w + 2 * BORDER_WIDTH
#
# Compute x, y positions of sub-menus and descend recursively.
#
every m := !self.menus do
if m$is_sub_menu() then {
m$set_abs_coords(self.x + self.w, m.label_y - BORDER_WIDTH)
m$resize()
}
end
#
# Deduce which label is under pointer, if any
#
method which_item()
local m
every m := !self.menus do {
if /m.is_shaded_flag & (m.label_y <= &y < m.label_y + m.label_h) then
return m
}
end
method display()
local cw, c
if /self.temp_win then {
#
# Open a temporary area for the menu and copy.
#
self.temp_win := WOpen("canvas=hidden", "size=" || self.w || "," || self.h)
CopyArea(self.parent_menu_bar$get_parent_win(), self.temp_win, self.x, self.y, self.w, self.h, 0, 0)
}
cw := self.parent_menu_bar.cbwin
#
# Clear area and draw rectangle around whole
#
EraseRectangle(cw, self.x, self.y, self.w, self.h)
DrawRaisedRectangle(cw, self.x, self.y, self.w, self.h,1)
#
# Draw individual items, with rectangle around open sub-item
#
every c := !self.menus do {
c$display_label()
if c === \self.which_open then
DrawRaisedRectangle(cw, c.label_x, c.label_y, self.w - 2 * BORDER_WIDTH, c.label_h,1)
}
CopyArea(cw, self.parent_menu_bar.cwin, self.x, self.y, self.w, self.h, self.x, self.y)
end
#
# If the presently selected item is a sub-menu, don't unselect it;
# just close any non-sub-menu in it by calling recursively.
#
method hide_non_menu()
if (\self.which_open)$is_sub_menu() then
return self.which_open$hide_non_menu()
else
return self$set_which_open()
end
#
# Set the selected sub item to x, whether or not it's a sub-menu
#
method set_which_open(x)
if self.which_open ~=== x then {
if (\self.which_open)$is_sub_menu() then
self.which_open$hide()
self.which_open := x
if (\self.which_open)$is_sub_menu() then
self.which_open$display()
self$display()
}
return x
end
#
# Test whether pointer within label area. Top and bottom borders are outside this region.
#
method in_button_region()
return (self.x <= &x < self.x + self.w) & (self.y + BORDER_WIDTH <= &y < self.y + self.h - BORDER_WIDTH)
end
method handle_event(e)
local t
if self$in_button_region() then {
if integer(e) = (&lpress | &rpress | &mpress) then
#
# Mouse press in region. Open the item where the pointer is
# or set to null (eg if over a shaded item).
#
self$set_which_open(self$which_item() | &null)
else if integer(e) = (&lrelease | &rrelease | &mrelease) then {
#
# Mouse released over region
#
if \self.which_open then {
#
# If item selected and not a sub-menu, return its selected
# event. If sub-menu, this will just stay open.
#
if not(self.which_open$is_sub_menu()) then
return self.which_open$select_event(e)
} else
#
# Fail completely, don't pass on event.
#
return MenuEvent(FAIL_1)
} else if integer(e) = (&ldrag | &rdrag | &mdrag) then {
#
# Drag over region.
#
if t := self$which_item() then {
if t === self.which_open then {
#
# Drag over label of open sub-item. If a menu unselect any
# items, except sub menus.
#
if t$is_sub_menu() then
t$hide_non_menu()
} else
#
# Open the selected item.
#
self$set_which_open(t)
} else
#
# Not over an item (eg shaded item). Clear selection.
#
self$set_which_open()
}
} else {
#
# Not in region.
#
if integer(e) = (&ldrag | &rdrag | &mdrag) then {
if (\self.which_open)$is_sub_menu() then
#
# Pass event on to open sub menu.
#
return self.which_open$handle_event(e)
else
#
# Clear present selection, except sub-menus.
#
self$hide_non_menu()
} else if integer(e) = (&lpress | &rpress | &mpress) then {
if (\self.which_open)$is_sub_menu() then
#
# Try open sub-menu.
#
return self.which_open$handle_event(e)
else
#
# Fail completely, pass on event to other objects.
#
return MenuEvent(FAIL_2)
} else if integer(e) = (&lrelease | &rrelease | &mrelease) then {
if (\self.which_open)$is_sub_menu() then
#
# Try open sub-menu.
#
return self.which_open$handle_event(e)
else
#
# Fail completely, don't pass on event.
#
return MenuEvent(FAIL_1)
}
}
#
# Every branch that doesn't return falls through to here. Just
# wait for next event to come along.
#
return MenuEvent(CONTINUE)
end
#
# Close this menu.
#
method hide()
local cw
#
# Recursively close open sub-menu.
#
if (\self.which_open)$is_sub_menu() then
self.which_open$hide()
self.which_open := &null
#
# Restore window area.
#
cw := self.parent_menu_bar.cwin
EraseRectangle(cw, self.x, self.y, self.w, self.h)
CopyArea(self.temp_win, self.parent_menu_bar$get_parent_win(), 0, 0, self.w, self.h, self.x, self.y)
WClose(self.temp_win)
self.temp_win := &null
end
initially(argv[])
self$SubMenu.initially()
self.menus := []
self$set_img_right(img_style("arrow_right"))
if *argv > 0 then set_fields(argv)
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.