home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
12
/
piemenu.asc
< prev
next >
Wrap
Text File
|
1991-11-11
|
6KB
|
179 lines
_THE DESIGN AND IMPLEMENTATION OF PIE MENUS_
by Don Hopkins
[LISTING ONE]
% Code to implement the "8 Days a Week" Pie Menu
% by Don Hopkins
/pie framebuffer /new ClassPieMenu send def
[ (Today)
(Sunday)
(Monday) (Tuesday) (Wednesday) (Thursday) (Friday)
(Saturday)
] /setitemlist pie send
90 /setinitialangle pie send
false /setclockwise pie send
/can framebuffer /new ClassPieMenuCanvas send def
pie /setpiemenu can send
/minsize {100 100} /installmethod can send
/win can framebuffer /new ClassBaseWindow send def
/new ClassEventMgr send /activate win send
/place win send /map win send
[LISTING TWO]
/Layout { % - => -
PieGSave self setcanvas
/LayoutInit self send
/LayoutValidateItems self send
/LayoutItemRadius self send
/LayoutOuterRadius self send
grestore
} def
/LayoutInit { % - => -
% Deflate the menu.
/Radius 0 def
% Figure the slice width.
/SliceWidth 360 /itemcount self send 1 max div def
% Point the initial slice in the initial angle.
/ThisAngle InitialAngle store
} def
/LayoutValidateItems { % - => -
% Loop through the items, validating each one.
ItemList {
begin % item
% Measure the item.
/DisplayItem load DisplayItemSize
/ItemHeight exch def
/ItemWidth exch def
% Remember the angle and the direction.
/Angle ThisAngle def
/DX Angle cos def
/DY Angle sin def
% Figure the offset from the tip of the inner radius
% spoke to the lower left item corner, according to
% the direction of the item.
%
% Items at the very top (bottom) are centered on their
% bottom (top) edge. Items to the left (right) are
% centered on their right (left) edge.
%
DX abs .05 lt { % tippy top or bippy bottom
% Offset to the North or South edge of the item.
/XOffset ItemWidth -.5 mul def
/YOffset
DY 0 lt {ItemHeight neg} {0} ifelse
def
} { % left or right
% Offset to the East or West edge of the item.
/XOffset
DX 0 lt {ItemWidth neg} {0} ifelse
def
/YOffset ItemHeight -.5 mul def
} ifelse
% Twist around to the next item.
/ThisAngle
ThisAngle SliceWidth
Clockwise? {sub} {add} ifelse
NormalAngle
store
end % item
} forall
} def
/LayoutItemRadius { % - => -
% Figure the inner item radius, at least enough to prevent
% the items from overlapping.
/ItemRadius RadiusMin def
/itemcount self send 3 gt { % No sweat if 3 or less.
% Check each item against its next neighbor.
0 1 /itemcount self send 1 sub {
/I exch def
/NextI I 1 add /itemcount self send mod def
% See if these two items overlap.
% If they do, keep pushing the item radius out
% by RadiusStep until they don't.
{ I /CalcRect self send
NextI /CalcRect self send
rectsoverlap not {exit} if % They don't overlap!
% They overlap. Push them out a notch and try again.
/ItemRadius ItemRadius RadiusStep add def
} loop
} for
% Now that we've gone around once checking each pair,
% none of them overlap any more!
} if
% Add in some more space to be nice.
/ItemRadius ItemRadius RadiusExtra add def
} def
/LayoutOuterRadius { % - => -
% Now we need to calculate the outer radius, based on the radius
% of the farthest item corner. During the loop, Radius actually
% holds the square of the radius, since we're comparing it against
% squared item corner radii anyway.
/Radius ItemRadius dup mul def
ItemList {
begin % item
% Remember the location to center the item edge.
/x DX ItemRadius mul def
/y DY ItemRadius mul def
% Remember the location of the item's SouthWest corner.
/ItemX x XOffset add round def
/ItemY y YOffset add round def
% Figure the distance of the item's farthest corner.
% This is easy 'cause we can fold all the items into
% the NorthEast quadrant and get the same result.
DX abs .05 lt { % tippy top or bippy bottom
% (|x|,|y|) is South edge: radius^2 of NorthEast corner
x abs ItemWidth .5 mul add dup mul
y abs ItemHeight add dup mul add
} { % left or right
% (|x|,|y|) is West edge: radius^2 of NorthEast corner
x abs ItemWidth add dup mul
y abs ItemHeight .5 mul add dup mul add
} ifelse
% Remember the maximum corner radius seen so far.
Radius max /Radius exch store
end % item
} forall
% Take the square root and add some extra space.
/Radius
Radius sqrt Gap add Border add ceiling cvi
store % Whew, we're done! Time to party!
} def