[comp.windows.news] pullout.ps

don@BRILLIG.UMD.EDU (Don Hopkins) (08/28/88)

%!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% Class PulloutPieMenu
% Copyright (C) 1988 by Don Hopkins (don@brillig.umd.edu)
% 
% This program is provided free for unrestricted use and redistribution,
% provided that the headers remain intact.  No author or distributor
% accepts any responsibility for any problems with this software.
% 
% PulloutPieMenu is a subclass of PieMenu that uses cursor distance
% from the menu center to specify an argument to the menu selection.
% Each menu key has an array of possible arguments, from which the
% cursor distance selects the argument value.  The values in the
% arrays are "Things" (cf. litemenu.ps & colordemo) that are painted
% in the menu center as feedback.  The /new method of class
% PulloutPieMenu takes the same arguments that regular menus do, plus
% an additional array of argument arrays.  Each argument array
% corresponds to a menu key.  If you give just one argument array, it
% is used for all the keys, the same as with the array of actions.
% You can use getmenuarg and getmenuargindex in your menu actions to
% retrieve the argument displayed when the key was selected.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

systemdict begin

% ------------------------------------ %
% PulloutPieMenu

/PulloutPieMenu PieMenu
dictbegin
  /SliceWedges false def
  /HiLiteWithArrow? false def
  /PrinterMatch? false def
  /ArgBorder 2 def
  /EraseArgs? true def
  /MenuArgs null def
  /MenuArg null def
  /MenuArgIndex null def
  /PaintedArg null def
dictend
classbegin

  % [[args...]...] [keys...] [actions...] => menu
  /new { 
    /new super send begin
      dup length MenuKeys length lt {
	[ exch aload pop % pad out args w/ last arg
	  counttomark MenuKeys length exch sub {dup} repeat ]
      } if
      /MenuArgs exch def
      currentdict
    end
  } def

  % Need to make flipstype a no-op because /new takes a different number
  % of args!
  /flipstyle {currentdict} def

  /MenuGSave {
    /MenuGSave super send
    PrinterMatch? setprintermatch
  } def

  /DragProc {
    ChildMenu null eq {
      MenuGSave
        PieRadius dup translate
        CurrentEvent begin
          XLocation DeltaX add
          YLocation DeltaY add
        end
        SetMenuValue

        MenuValue PaintedValue ne {
          PaintMenuValue
        } if
        getmenuarg /PaintedArg load ne {
          PaintMenuArg
        } if
      grestore
    } if
  } def

  framebuffer /GLCanvas known { % SGI 4Sight?
    % Paint menus on the overlay plane
    /DamageProc { 
	/damaged currentcanvas def
	dup getcanvaslocation
	2 index setcanvas clipcanvaspath neg neg translate
	damaged setcanvas clipcanvas
	ParentMenu null ne {/DamageProc ParentMenu send} {pop} ifelse
	/paint self send
	true PaintedValue PaintSlice
        /PaintedArg load /PaintArg self send
    } def
  } {
    /DamageProc {
      MenuGSave
	damagepath clipcanvas
	/paint self send
	PaintedValue PaintSlice
	/PaintedArg load PaintArg
	newpath clipcanvas
      grestore
    } def
  } ifelse

  /PaintMenuArg {
    getmenuarg
    dup null eq  /PaintedArg load null eq  EraseArgs? or or {
      /PaintedArg load EraseArg
    } if
    dup PaintArg
    /PaintedArg exch store
  } def

  /EraseArg { % thing => -
    MenuGSave
      dup null eq {
	pop
	PieRadius dup translate
	MenuFillColor setcolor
	0 0 LabelRadius Gap sub 3 sub 0 360 arc
	fill
      } {
	PieRadius dup translate
	MenuFillColor setcolor
	ThingSize
	2 copy
	-.5 mul exch -.5 mul exch
	4 -2 roll
	ArgBorder neg 5 1 roll insetrect % Some extra padding...
	rectpath fill
      } ifelse
    grestore
  } def

  /PaintArg { % thing => -
    MenuGSave
      dup null eq {
	pop
	PieRadius dup translate
	MenuBorderColor setcolor
        MenuLineWidth setlinewidth
	MenuLineCap setlinecap
	MenuItems {
	  begin
	    gsave
	      newpath
	      ang PieSliceWidth 2 div sub rotate
	      NumbRadius 0 moveto
	      LabelRadius Gap sub 4 sub 0 lineto
              MenuBorderColor setcolor
	      stroke
	    grestore
	  end
	} forall
      } {
	PieRadius dup translate
	MenuTextColor setcolor
        dup ThingSize
	-.5 mul exch -.5 mul exch
	ShowThing
      } ifelse
    grestore
  } def

  /showat {
    PaintedArg null ne PaintedValue null ne and
    MenuCanvas null ne and MenuWidth null ne and {
      MenuGSave
        /PaintedArg load EraseArg
        /PaintedArg null store
	null PaintArg
      grestore
    } if
    /MenuArg null def
    /MenuArgIndex null def
    /showat super send
  } def

  /SetMenuValue { % x y => -
    /SetMenuValue super send
    /MenuArg
      MenuValue null eq
      {null true}
      {MenuArgs MenuValue get dup length 0 eq} ifelse {
        pop null
	/MenuArgIndex null def
      } {
        PieDistance PieRadius 1 sub min NumbRadius sub
	PieRadius NumbRadius sub div 1 index length mul floor
	/MenuArgIndex 1 index def
	get
      } ifelse
    def
  } def

  /getmenuargindex { % - => index
    MenuArgIndex
  } def

  /getmenuarg { % - => Thing
    /MenuArg load
  } def

classend def

end % systemdict

don@BRILLIG.UMD.EDU (Don Hopkins) (03/13/89)

You'll need the following class definition to run the
Pseudo-Scientific Visualizer. The CyberSpace deck uses pullout pie
menus if they're defined. You can select the "util... molecule" menu
item over an object in CyberSpace, to view it with the visualizer.
(I'll integrate them better later!) (PS: softmenu.ps doesn't wort work
with pullout menus yet...)

	-Don

%!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% Class PulloutPieMenu
% Copyright (C) 1988 by Don Hopkins (don@brillig.umd.edu)
% 
% This program is provided free for unrestricted use and redistribution,
% provided that the headers remain intact.  No author or distributor
% accepts any responsibility for any problems with this software.
% 
% PulloutPieMenu is a subclass of PieMenu that uses cursor distance
% from the menu center to specify an argument to the menu selection.
% Each menu key has an array of possible arguments, from which the
% cursor distance selects the argument value.  The values in the
% arrays are "Things" (cf. litemenu.ps & colordemo) that are painted
% in the menu center as feedback.  The /new method of class
% PulloutPieMenu takes the same arguments that regular menus do, plus
% an additional array of argument arrays.  Each argument array
% corresponds to a menu key.  If you give just one argument array, it
% is used for all the keys, the same as with the array of actions.
% You can use getmenuarg and getmenuargindex in your menu actions to
% retrieve the argument displayed when the key was selected.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

systemdict begin

% ------------------------------------ %
% PulloutPieMenu

/PulloutPieMenu PieMenu
dictbegin
  /SliceWedges false def
  /HiLiteWithArrow? false def
  /PrinterMatch? false def
  /ArgBorder 2 def
  /EraseArgs? true def
  /MenuArgs null def
  /MenuArg null def
  /MenuArgIndex null def
  /PaintedArg null def
dictend
classbegin

  % [[args...]...] [keys...] [actions...] => menu
  /new { 
    /new super send begin
      dup length MenuKeys length lt {
	[ exch aload pop % pad out args w/ last arg
	  counttomark MenuKeys length exch sub {dup} repeat ]
      } if
      /MenuArgs exch def
      currentdict
    end
  } def

  % Need to make flipstyle a no-op because /new takes a different number
  % of args, and actions might depend on MenuArg! Scratch that.
  % Instead, let's just make a new instance of ourselves, of
  % the same class. 
  /flipstyle {
    0 1 MenuActions length 1 sub {
	dup getmenuaction % fixed to use getmenuaction!
	dup type /dicttype eq {
	    /flipstyle exch send	% i menu'
	    MenuActions 3 1 roll put	% -
	} {pop pop} ifelse
    } for
    MenuArgs MenuKeys MenuActions /new ClassName load send
    dup /LabelMinRadius LabelMinRadius put % hack
  } def

  /MenuGSave {
    /MenuGSave super send
    PrinterMatch? setprintermatch
  } def

  /DragProc {
    ChildMenu null eq {
      MenuGSave
        PieRadius dup translate
        CurrentEvent begin
          XLocation DeltaX add
          YLocation DeltaY add
        end
        SetMenuValue

        MenuValue PaintedValue ne {
          PaintMenuValue
        } if
        getmenuarg /PaintedArg load ne {
          PaintMenuArg
        } if
      grestore
    } if
  } def

  framebuffer /GLCanvas known { % SGI 4Sight?
    % Paint menus on the overlay plane
      /paint {
	/paint super send
	/PaintedArg load /PaintArg self send
      } def
  } {
    /DamageProc {
      MenuGSave
	damagepath clipcanvas
	/paint self send
	PaintedValue PaintSlice
	/PaintedArg load PaintArg
	newpath clipcanvas
      grestore
    } def
  } ifelse

  /PaintMenuArg {
    getmenuarg
    dup null eq  /PaintedArg load null eq  EraseArgs? or or {
      % The null...pop is to get around the fact that 4Sight's ThingSize
      % recognizes [(string) /name] as a special case, and eats both,
      % which hoses us if we call it with just a /name, but with a 
      % (string) on the stack before that. 
      null /PaintedArg load EraseArg pop
    } if
    dup PaintArg
    /PaintedArg exch store
  } def

  /EraseArg { % thing => -
    MenuGSave
      dup null eq {
	pop
	PieRadius dup translate
	MenuFillColor setcolor
	0 0 LabelRadius Gap sub 3 sub 0 360 arc
	fill
      } {
	PieRadius dup translate
	MenuFillColor setcolor
% dup /toggle3 eq {/foo dbgbreak} if
	ThingSize
	2 copy
	-.5 mul exch -.5 mul exch
	4 -2 roll
	ArgBorder neg 5 1 roll insetrect % Some extra padding...
	rectpath fill
      } ifelse
    grestore
  } def

  /PaintArg { % thing => -
    MenuGSave
      dup null eq {
	pop
	PieRadius dup translate
	MenuBorderColor setcolor
        MenuLineWidth setlinewidth
	MenuLineCap setlinecap
	MenuItems {
	  begin
	    gsave
	      newpath
	      ang PieSliceWidth 2 div sub rotate
	      NumbRadius 0 moveto
	      LabelRadius Gap sub 4 sub 0 lineto
              MenuBorderColor setcolor
	      stroke
	    grestore
	  end
	} forall
      } {
	PieRadius dup translate
	MenuTextColor setcolor
        dup ThingSize
	-.5 mul exch -.5 mul exch
	ShowThing
      } ifelse
    grestore
  } def

  /showat {
    PaintedArg null ne PaintedValue null ne and
    MenuCanvas null ne and MenuWidth null ne and {
      MenuGSave
        /PaintedArg load EraseArg
        /PaintedArg null store
	null PaintArg
      grestore
    } if
    /MenuArg null def
    /MenuArgIndex null def
    /showat super send
  } def

  /SetMenuValue { % x y => -
    /SetMenuValue super send
    /MenuArg
      MenuValue null eq
      {null true}
      {MenuArgs MenuValue get dup length 0 eq} ifelse {
        pop null
	/MenuArgIndex null def
      } {
        PieDistance PieRadius 1 sub min NumbRadius sub
	PieRadius NumbRadius sub div 1 index length mul floor
	/MenuArgIndex 1 index def
	get
      } ifelse
    def
  } def

  /getmenuargindex { % - => index
    MenuArgIndex
  } def

  /getmenuarg { % - => Thing
    /MenuArg load
  } def

classend def

end % systemdict