home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 12 / piemenu.asc < prev    next >
Text File  |  1991-11-11  |  6KB  |  179 lines

  1. _THE DESIGN AND IMPLEMENTATION OF PIE MENUS_
  2. by Don Hopkins
  3.  
  4. [LISTING ONE]
  5.  
  6. % Code to implement the "8 Days a Week" Pie Menu 
  7. % by Don Hopkins
  8.  
  9. /pie framebuffer /new ClassPieMenu send def
  10. [ (Today)
  11.   (Sunday)
  12.   (Monday) (Tuesday) (Wednesday) (Thursday) (Friday)
  13.   (Saturday)
  14. ] /setitemlist pie send
  15. 90 /setinitialangle pie send
  16. false /setclockwise pie send
  17.  
  18. /can framebuffer /new ClassPieMenuCanvas send def
  19. pie /setpiemenu can send
  20. /minsize {100 100} /installmethod can send
  21. /win can framebuffer /new ClassBaseWindow send def
  22. /new ClassEventMgr send /activate win send
  23. /place win send /map win send
  24.  
  25.  
  26. [LISTING TWO]
  27.  
  28.     /Layout { % - => -
  29.         PieGSave self setcanvas
  30.             /LayoutInit self send
  31.             /LayoutValidateItems self send
  32.             /LayoutItemRadius self send
  33.             /LayoutOuterRadius self send
  34.         grestore
  35.     } def
  36.  
  37.     /LayoutInit { % - => -
  38.         % Deflate the menu.
  39.         /Radius 0 def
  40.         % Figure the slice width.
  41.         /SliceWidth 360 /itemcount self send 1 max div def
  42.         % Point the initial slice in the initial angle.
  43.         /ThisAngle InitialAngle store
  44.     } def
  45.  
  46.  
  47.     /LayoutValidateItems { % - => -
  48.         % Loop through the items, validating each one.
  49.         ItemList {
  50.             begin % item
  51.  
  52.                 % Measure the item.
  53.                 /DisplayItem load DisplayItemSize
  54.                 /ItemHeight exch def
  55.                 /ItemWidth exch def
  56.  
  57.                 % Remember the angle and the direction.
  58.                 /Angle ThisAngle def
  59.                 /DX Angle cos def
  60.                 /DY Angle sin def
  61.  
  62.                 % Figure the offset from the tip of the inner radius
  63.                 % spoke to the lower left item corner, according to
  64.                 % the direction of the item.
  65.                 %
  66.                 % Items at the very top (bottom) are centered on their
  67.                 % bottom (top) edge. Items to the left (right) are
  68.                 % centered on their right (left) edge.
  69.                 %
  70.                 DX abs .05 lt { % tippy top or bippy bottom
  71.  
  72.                     % Offset to the North or South edge of the item.
  73.                     /XOffset ItemWidth -.5 mul def
  74.                     /YOffset
  75.                         DY 0 lt {ItemHeight neg} {0} ifelse
  76.                     def
  77.  
  78.                 } { % left or right
  79.  
  80.                     % Offset to the East or West edge of the item.
  81.                     /XOffset
  82.                         DX 0 lt {ItemWidth neg} {0} ifelse
  83.                     def
  84.                     /YOffset ItemHeight -.5 mul def
  85.  
  86.                 } ifelse
  87.  
  88.                 % Twist around to the next item.
  89.                 /ThisAngle
  90.                     ThisAngle SliceWidth
  91.                     Clockwise? {sub} {add} ifelse
  92.                     NormalAngle
  93.                 store
  94.  
  95.             end % item
  96.         } forall
  97.     } def
  98.  
  99.     /LayoutItemRadius { % - => -
  100.         % Figure the inner item radius, at least enough to prevent
  101.  
  102.         % the items from overlapping.
  103.         /ItemRadius RadiusMin def
  104.         /itemcount self send 3 gt { % No sweat if 3 or less.
  105.  
  106.             % Check each item against its next neighbor.
  107.             0 1 /itemcount self send 1 sub {
  108.  
  109.                 /I exch def
  110.                 /NextI I 1 add /itemcount self send mod def
  111.  
  112.                 % See if these two items overlap.
  113.                 % If they do, keep pushing the item radius out
  114.                 % by RadiusStep until they don't.
  115.                 {   I /CalcRect self send
  116.                     NextI /CalcRect self send
  117.                     rectsoverlap not {exit} if % They don't overlap!
  118.  
  119.                     % They overlap. Push them out a notch and try again.
  120.                     /ItemRadius ItemRadius RadiusStep add def
  121.                 } loop
  122.  
  123.             } for
  124.             % Now that we've gone around once checking each pair,
  125.             % none of them overlap any more!
  126.         } if
  127.  
  128.         % Add in some more space to be nice.
  129.         /ItemRadius ItemRadius RadiusExtra add def
  130.     } def
  131.  
  132.     /LayoutOuterRadius { % - => -
  133.         % Now we need to calculate the outer radius, based on the radius
  134.         % of the farthest item corner. During the loop, Radius actually
  135.         % holds the square of the radius, since we're comparing it against
  136.         % squared item corner radii anyway.
  137.         /Radius ItemRadius dup mul def
  138.         ItemList {
  139.             begin % item
  140.  
  141.                 % Remember the location to center the item edge.
  142.                 /x DX ItemRadius mul def
  143.                 /y DY ItemRadius mul def
  144.  
  145.                 % Remember the location of the item's SouthWest corner.
  146.                 /ItemX x XOffset add round def
  147.                 /ItemY y YOffset add round def
  148.  
  149.                 % Figure the distance of the item's farthest corner.
  150.                 % This is easy 'cause we can fold all the items into
  151.                 % the NorthEast quadrant and get the same result.
  152.                 DX abs .05 lt { % tippy top or bippy bottom
  153.  
  154.                     % (|x|,|y|) is South edge: radius^2 of NorthEast corner
  155.                     x abs ItemWidth .5 mul add dup mul
  156.                     y abs ItemHeight add dup mul add
  157.  
  158.  
  159.                 } { % left or right
  160.  
  161.                     % (|x|,|y|) is West edge: radius^2 of NorthEast corner
  162.                     x abs ItemWidth add dup mul
  163.                     y abs ItemHeight .5 mul add dup mul add
  164.  
  165.                 } ifelse
  166.  
  167.                 % Remember the maximum corner radius seen so far.
  168.                 Radius max /Radius exch store
  169.             end % item
  170.         } forall
  171.  
  172.         % Take the square root and add some extra space.
  173.         /Radius
  174.             Radius sqrt Gap add Border add ceiling cvi
  175.         store % Whew, we're done! Time to party!
  176.     } def
  177.  
  178.  
  179.