don@CS.UMD.EDU (Don Hopkins) (02/11/90)
This is an implementation of tab frames, on top of the Open Look frame class in tNt (the NeWS toolkit, aka NDE). It runs under Open Windows 1.0 (aka X11/NeWS). Instead of having the title at the top of the window, tab frames have the title in a tab stuck to the window edge, that you can drag around to any of the four edges by pressing the Adjust (middle) button down over the title (when the cursor is a + sign) and dragging it to where you want. Notice that the tab sticks to the end of an edge until you actually go around the corner. (This is so it's easy to move it to the end of an edge.) Double clicking the Point (left) button on the border or tab "zooms" the window as usual, except that the window is reshaped so it's on the left edge of the screen, full height, with its tab along its right edge, just below the previous tab. It is convenient to zoom a bunch of windows and have them all overlapping, but with all of their tabs visible (showing their titles). You can click the Point (left) button on the tab to bring the window to the top. It could be smarter about the layout, but this is just a start. Also I have added resize controls to the window edges to complement the Open Look resize corners. These are useful when you want to change the window height without changing the width, or vice verse. (You'll want to do that a lot with tab frames, like when you want to make a zoomed window shorter.) Least importantly, I added a fake 3-D look (wooo golly gee) to the tabs. When a tab frame has the input focus, its tab appears to pop out (with beveled edges around the window title). Personally I don't think 3-D window frames are particularly useful (unless they *really* *are* 3-D, and fly out at you like the SGI button demo). It would be poor form to make the window borders thicker and slow down the drawing for no other reason than fake 3-D. In this implementation, only the tab of the window which has the input focus (where keyboard input is directed) is displayed in fake 3-D. This is less distracting than having *all* the tabs in fake 3-D, and makes it painfully obvious *which* tab frame has the keyboard focus. I would appreciate feedback: what kind of automatic window and tab layout policy would be most convenient, least obnoxious? I am thinking of implementing snap dragging, to help line up windows and tabs, but for now the Open Look screen edge snapping works pretty well. One of these days I will incorporate pie menus into the tab frame window manager (ala quickwin.ps). Summer before last, I implemented tab frames under NeWS 1.1 for UniPress Emacs V2.20, and found them very convenient for editing lots of files at once (UniPress Emacs supports multiple windows, which can get very confusing without the help of the tabs). The idea is totally unoriginal, as useful for window managment as it is for address books, so feel free to implement it for other window systems without fear of being sued. My code is freely redistributable. For a demo, put the enclosed code in the file NeWS/tabframe.ps, and type: % psh NeWS/tabframe.ps % psh /demo TabBaseFrame send /demo TabCommandFrame send If you are pleased, and want to install tab frames as your default frame class (so you get them around all your X windows (if you run pswm) as well as your NeWS windows), put the following into your .startup.ps file: UserProfile /OpenLookFrame { ClassFrame /DefaultClass { TabFrame } put } put [ /TabFrame (NeWS/tabframe.ps) ] DefineAutoLoads There are still a few rough edges (of course the most obvious rough edge is considered a feature), but I plan on developing this further, so please tell me about any problems you have, and send me suggestions for enhancements, top of the head comments, incoherent raving brainstorms, etc. -Don Here is the enclosed code (NeWS/tabframe.ps): %! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % tNt Tab Frames, release 1.0 % Copyright (C) 1990 % By Don Hopkins, University of Maryland Human Computer Interaction Lab % Started, May 13 1989. % Reimplemented mostly from scratch for X11/NeWS FCS. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Copyright (C) 1990 by Don Hopkins. All rights reserved. % This program is provided for unrestricted use, provided that this % copyright message is preserved. There is no warranty, and no author % or distributer accepts responsibility for any damage caused by this % program. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % To get TabFrame as the default frame class automatically upon startup, put % the following into your .startup.ps file: % % UserProfile /OpenLookFrame { % ClassFrame /DefaultClass { TabFrame } put % } put % % [ % /TabFrame (NeWS/tabframe.ps) % ] DefineAutoLoads % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% systemdict begin %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % TabFrame % /TabFrame OpenLookFrame dictbegin /TabEdge /Top def /TabPosition 0 def dictend classbegin /ThreeDee? true def % /ThreeDee? framebuffer /Color get def /Contrast .1 def /Bright .75 dup dup rgbcolor def /Dim .25 dup dup rgbcolor def /LabelMinWidth 8 def /SelStroke 2 def /UnSelStroke 1 def /ZoomX 0 def /ZoomY 0 def /ZoomWidth 512 def framebuffer true getbbox /ZoomHeight exch def pop pop pop /ZoomTabEdge /Right def /ZoomTabPos 1 def /ZoomTabPosition { ZoomTabPos TabHeight ZoomHeight div sub dup 0 lt { pop 1 } if /ZoomTabPos 1 index store } def /LabelCreate { % - => - /Label [ { /TabNotify parent send pop } OpenLookTabFrameLabel ] /addclient self send } def /ReshapeCreate { % - => - /Reshape [{/ReshapeNotify /parent self send send} OpenLookTabFrameCorners] /addclient self send } def /ReshapeNotify { % object => - gsave pop % Parent setcanvas currentcursorlocation /stretchany self send grestore } def /stretchany { % event|x y => - dup type /eventtype eq { begin XLocation YLocation end } if 20 dict begin /y exch def /x exch def bbox unfittab 2 copy /h exch def /w exch def rect2points /y1 exch def /x1 exch def /y0 exch def /x0 exch def x x0 w .3 mul add le /Left { x x0 w .7 mul add ge /Right /Middle ifelse } ifelse % xpart y y0 h .3 mul add le /Bottom { y y0 h .7 mul add ge /Top /Middle ifelse } ifelse % xpart ypart dup /Bottom eq { /y0 y1 /y1 y0 def def } if 1 index /Left eq { /x0 x1 /x1 x0 def def } if (%%) sprintf cvn x1 y1 x1 x sub y1 y sub % edge x1 y1 x1-x y1-y [x0 y0] cvx % edge x1 y1 x1-x y1-y X0Y0proc end 5 index { /MiddleRight /MiddleLeft { {begin XLocation DeltaX add Y1 end} } /TopMiddle /BottomMiddle /MiddleMiddle { {begin X1 YLocation DeltaY add end} } /Default { {begin XLocation DeltaX add YLocation DeltaY add end} } } case [/xhair /xhair_m Parent] { InitOverlay InstallXYProcs /DeltaY exch def /DeltaX exch def /Y1 exch def /X1 exch def /Edge exch def /Moved? false def }{ Changed? {erasepage BBox fittab /path self send stroke} if /Moved? true def }{ erasepage null SetGlobalCursor Moved? { x0 x min y0 y min x0 x sub abs y0 y sub abs invalidatetab % /TabWidth unpromote /HeaderWidth unpromote fittab rect2points true } false ifelse } /UpTransition getfromuser { /anchorbox self send /reshape self send } if } def /TabNotify { % canvas => - pop DragTab } def /DragTab { % - => - gsave Parent setcanvas 10 dict begin bbox unfittab rect2points /top exch def /right exch def /bottom exch def /left exch def parent setcanvas null null [/xhair /xhair_m Parent] { InitOverlay InstallXYProcs } { Changed? { TabEdge { /Left { x left gt { y top gt { /Top setedge } { y bottom lt { /Bottom setedge } { x right gt { /Right setedge } if } ifelse } ifelse } if } /Right { x right lt { y top gt { /Top setedge } { y bottom lt { /Bottom setedge } { x left lt { /Left setedge } if } ifelse } ifelse } if } /Top { y top lt { x left lt { /Left setedge } { x right gt { /Right setedge } { y bottom lt { /Bottom setedge } if } ifelse } ifelse } if } /Bottom { y bottom gt { x left lt { /Left setedge } { x right gt { /Right setedge } { y top gt { /Top setedge } if } ifelse } ifelse } if } } case TabEdge { /Left /Right { y bottom sub TabHeight .5 mul sub top bottom sub TabHeight sub 1 max div 0 max 1 min } /Top /Bottom { x left sub TabWidth .5 mul sub right left sub TabWidth sub 1 max div 0 max 1 min } } case setposition erasepage left bottom right 2 index sub top 2 index sub % x y w h fittab /path self send stroke } if } {erasepage null SetGlobalCursor Changed?} [/UpTransition /DownTransition] getfromuser { left bottom right 2 index sub top 2 index sub % x y w h ?validate % XXX fittab minsize % x y w h mw mh 3 -1 roll max % x y w mw H 3 1 roll max % x y H W exch % x y W H /reshape self send } { % do something appropriate } ifelse end % tempdict grestore } def /invalidatetab { /TabWidth unpromote /TabHeight unpromote /TabX unpromote /TabY unpromote /HeaderWidth unpromote /HeaderHeight unpromote } def /setedge { % /Left|/Right|/Top|/Bottom => - /TabEdge exch store invalidatetab invalidate } def /resetedge { % edge => - bbox unfittab 5 -1 roll setedge ?validate % XXX? fittab reshape } def /setposition { % 0..1 => - /TabPosition exch store invalidatetab invalidate } def /BorderLeft { % - => l BorderEdge TabEdge /Left eq { TabWidth add } if } def /BorderRight { % - => r BorderEdge TabEdge /Right eq { TabWidth add } if } def /BorderBottom { % - => b /BorderBottom super send TabEdge /Bottom eq { TabHeight add } if } def /BorderTop { % - => t BorderEdge TabEdge /Top eq { TabHeight add } if } def /TabSize { % - => w h BorderEdge dup add % ThreeDee? { SelStroke add } if dup HeaderWidth add exch HeaderHeight add } def /CalcTabXY { % width height => x y TabEdge { /Left { % width height exch pop 0 exch % 0 height TabHeight sub TabPosition mul round % 0 y } /Right { % width height exch TabWidth sub % height x exch TabHeight sub TabPosition mul round % x y } /Top { % width height exch TabWidth sub TabPosition mul round % height x exch TabHeight sub % x y } /Bottom { % width height pop TabWidth sub TabPosition mul round % x 0 % x 0 } } case } def /validate { invalidatetab /BorderLeft unpromote /BorderLeft /BorderLeft self send promote /BorderRight unpromote /BorderRight /BorderRight self send promote /validate super send } def /TabX { TabXY /TabY exch promote /TabX exch promote TabX } def /TabY { TabXY /TabY exch promote /TabX exch promote TabY } def /TabXY { % - => x y Width Height CalcTabXY } def /TabWidth { TabSize /TabHeight exch promote /TabWidth exch promote TabWidth } def /TabHeight { TabSize /TabHeight exch promote /TabWidth exch promote TabHeight } def /HeaderWidth { HeaderSize /HeaderHeight exch promote /HeaderWidth exch promote HeaderWidth } def /HeaderHeight { HeaderSize /HeaderHeight exch promote /HeaderWidth exch promote HeaderHeight } def /HeaderSize { % - => w h 0 0 % W H /Label /getbyname self send { /preferredsize exch send % W H w h 3 -1 roll max % W w H 3 1 roll add % H W LabelMinWidth max HeaderPadding add exch % W H } if /Pin /getbyname self send { /minsize exch send % W H w h 3 -1 roll max % W w H 3 1 roll add % H W HeaderPadding add exch % W H } if /Close /getbyname self send { /minsize exch send % W H w h 3 -1 roll max % W w H 3 1 roll add % H W HeaderPadding add exch % W H } if 2 { exch dup 0 ne { HeaderPadding dup add add } if } repeat } def % erase the current frame header. Used when changing busy state. % /EraseHeader { % - => - FillColor setcolor TabX BorderEdge add TabY BorderEdge add HeaderWidth HeaderHeight rectpath fill } def % Paint the frames current focus state. % /PaintHeader { % busy? focus? => - % Only paint the header if we have one of these ornaments. % Label Close or Pin or { exch { pop BusyColor setcolor TabX BorderEdge add TabY BorderEdge add HeaderWidth HeaderHeight rectpath fill } { % {TextColor} {FillColor} ifelse % setcolor % ClickToType { % TabX BorderEdge add TabY BorderEdge add % HeaderWidth HeaderHeight % rectpath fill % }{ % Draw the two lines for follow-mouse focus. % Having a different highlight depending on what % focus mode got us here sounds like donkey-doo but % it's in the spec so we implement it. % ThreeDee? { gsave 10 dict begin /focus? 1 index def { framebuffer /Color get { FillColor colorhsb 3 copy % h s b h s b Contrast sub 0 max hsbcolor % h s b dim 4 1 roll % dim r g b Contrast add 1 min hsbcolor % dim bright } { Dim Bright } ifelse } { FillColor dup % dim bright } ifelse /l BorderEdge SelStroke sub def TabX BorderEdge add TabY BorderEdge add moveto l neg dup rlineto 0 HeaderHeight l dup add add rlineto HeaderWidth l dup add add 0 rlineto l neg dup rlineto HeaderWidth neg 0 rlineto 0 HeaderHeight neg rlineto closepath setcolor fill TabX BorderEdge add .75 add TabY BorderEdge add .75 sub moveto l neg dup rlineto HeaderWidth l dup add add 0 rlineto 0 HeaderHeight l dup add add rlineto l neg dup rlineto 0 HeaderHeight neg rlineto HeaderWidth neg 0 rlineto closepath setcolor fill TabX BorderEdge add TabY BorderEdge add .25 add 2 copy % x y x y HeaderWidth .5 sub HeaderHeight .5 sub % x y x y w h rectpath % x y 2 copy moveto l neg dup rlineto 2 copy HeaderHeight add .5 sub moveto l dup neg exch rlineto exch HeaderWidth add .5 sub exch 2 copy moveto l dup neg rlineto HeaderHeight add .5 sub moveto l dup rlineto focus? {TextColor} {FillColor} ifelse setcolor stroke end grestore } { {TextColor} {FillColor} ifelse setcolor currentlinewidth 2 setlinewidth TabX BorderEdge add TabY BorderEdge add HeaderWidth HeaderHeight rectpath stroke setlinewidth } ifelse % } ifelse } ifelse } { pop pop } ifelse } def % Overide: Take the label, the footer and the resize corners % into account. % /MinSize { % - => minwidth minheight % Because of the unique factorization of client layout % from client creation we must make sure the frame has % been correctly layed out here in order to get the % right minsize. % /?validate self send /Client getbyname { /minsize exch send } { 0 0 } ifelse fitclient TabEdge dup /Left eq exch /Right eq or { TabHeight max } { exch TabWidth max exch } ifelse } def % Overide: Take the label, the footer and the resize corners % into account. % /PreferredSize { % - => preferredwidth preferredheight % Because of the unique factorization of client layout % from client creation we must make sure the frame has % been correctly layed out here in order to get the % right preferredsize. % /?validate self send /PreferredSize OpenLookFrame /SuperSend load exec % XXX } def /SuperSend /supersend load def % Layout /FooterLayout { % - => - /Left /getbyname self send { BorderEdge 2 mul 1 add dup TabEdge /Left eq { TabWidth add } if exch SelStroke FooterPad add TabEdge /Bottom eq { TabHeight add } if Width TabEdge dup /Right eq exch /Left eq or { TabWidth sub } if .5 mul 3 -1 roll sub 1 sub /preferredsize 4 index send exch pop /reshape 6 -1 roll send } if /Right /getbyname self send { Width TabEdge dup /Right eq exch /Left eq or { TabWidth sub } if .5 mul dup TabEdge /Left eq { TabWidth add } if exch SelStroke FooterPad add TabEdge /Bottom eq { TabHeight add } if exch BorderEdge 2 mul 1 add sub /preferredsize 4 index send exch pop /reshape 6 -1 roll send } if } def /ReshapeLayout { % - => - /Reshape /getbyname self send { bbox unfittab /reshape 6 -1 roll send } if } def /CloseLayout { % - => - /Close /getbyname self send { % close TabX BorderEdge add HeaderPadding add % close x /minsize 2 index send % close x w h HeaderHeight 1 index sub % close x w h hh-h .5 mul .5 add truncate % close x w h _(hh-h)/2+.5_ TabY BorderEdge add add % close x w h y 3 1 roll % close x y w h /reshape 6 -1 roll send % } if } def /PinLayout { % - => - /Pin /getbyname self send { TabX BorderEdge add HeaderPadding add % pin x /Close getbyname self send { /minsize exch send pop add HeaderPadding add } if /minsize 2 index send % pin x w h HeaderHeight 1 index sub % pin x w h hh-h .5 mul % pin x w h (hh-h)/2 TabY BorderEdge add add % pin x w h y 3 1 roll % pin x y w h /reshape 6 -1 roll send % } if } def /LabelLayout { % - => - /Label /getbyname self send { TabX BorderEdge add HeaderPadding add % x /Pin /getbyname self send { /bbox exch send rect2points pop 3 1 roll pop pop HeaderPadding add max } if /Close /getbyname self send { /bbox exch send rect2points pop 3 1 roll pop pop HeaderPadding add max } if /preferredsize 2 index send % x w h exch 8 max exch HeaderHeight 1 index sub .5 mul % x w h y TabY BorderEdge add add % x w h y 3 1 roll % x y w h /reshape 6 -1 roll send } if } def /setlabel { % graphic|thing|null => - /Label /getbyname self send { invalidate /setlabel exch send } {pop} ifelse } def % This is the next available position to place a window at. % It is where the upper left corner of the window should go. /NextPosition null store /WindowYIncrement -37 store /WindowXIncrement 0 store /WindowRows 0 store /setgravity { % /Left|/Right|/Top|/Bottom => - /Gravity exch store /NextPosition null store /WindowRows 0 store Gravity { /UpperLeft { /InitialDefaultPosition { % w h => x y pop pop /bbox /parent self send send exch pop add } def /WindowYIncrement -37 store /WindowXIncrement 0 store } /UpperRight { /InitialDefaultPosition { % w h => x y pop /bbox /parent self send send 3 -1 roll add 3 1 roll add 3 -1 roll sub exch } store /WindowYIncrement -37 store /WindowXIncrement 0 store } /LowerLeft { /InitialDefaultPosition { % w h => x y exch pop /location /parent self send send 3 -1 roll add } store /WindowYIncrement 37 store /WindowXIncrement 0 store } /LowerRight { /InitialDefaultPosition { % w h => x y /bbox /parent self send send pop 3 -1 roll add 4 -1 roll sub exch 3 -1 roll add } store /WindowYIncrement 37 store /WindowXIncrement 0 store } /Default {} } case } def /UpperLeft setgravity /path { % x y w h => - 10 dict begin /mat matrix currentmatrix def /h exch def /w exch def translate TabEdge { /Left { TabWidth 0 moveto 0 h TabHeight sub TabPosition mul round rlineto TabWidth neg 0 rlineto 0 TabHeight rlineto TabWidth 0 rlineto TabWidth h lineto w h lineto w 0 lineto closepath } /Right { h TabHeight sub TabPosition mul round 0 0 moveto 0 h rlineto w TabWidth sub 0 rlineto 0 1 index TabHeight add h sub rlineto TabWidth 0 rlineto 0 TabHeight neg rlineto TabWidth neg 0 rlineto 0 exch neg rlineto closepath } /Top { 0 0 moveto 0 h TabHeight sub rlineto w TabWidth sub TabPosition mul round 0 rlineto 0 TabHeight rlineto TabWidth 0 rlineto 0 TabHeight neg rlineto w h TabHeight sub lineto w 0 lineto closepath } /Bottom { 0 TabHeight moveto 0 h TabHeight sub rlineto w 0 rlineto 0 h TabHeight sub neg rlineto w TabWidth sub TabPosition mul round TabWidth add TabHeight lineto 0 TabHeight neg rlineto TabWidth neg 0 rlineto 0 TabHeight rlineto closepath } } case mat setmatrix end % tempdict } def % given tabbed frame bbox, returns bbox of frame w/out tab /unfittab { % x y w h => x' y' w' h' TabEdge { /Left { 4 -1 roll TabWidth add 4 1 roll exch TabWidth sub exch } /Right { exch TabWidth sub exch } /Top { TabHeight sub } /Bottom { 3 -1 roll TabHeight add 3 1 roll TabHeight sub } } case } def % given untabbed frame bbox, returns bbox of frame with tab /fittab { % x' y' w' h' => x y w h TabEdge { /Left { 4 -1 roll TabWidth sub 4 1 roll exch TabWidth add exch } /Right { exch TabWidth add exch } /Top { TabHeight add } /Bottom { 3 -1 roll TabHeight sub 3 1 roll TabHeight add } } case } def % Return the corner farthest from the given x y. % Coordinates are in the parents space. % /farthestcorner { % x y => x' y' /bbox self send 4 copy rect2points 10 4 roll unfittab rect2points % x y x0 y0 x1 y1 X0 Y0 X1 Y1 3 index 6 index sub abs 2 index 7 index sub abs gt {9} {7} ifelse index 3 index 6 index sub abs 2 index 7 index sub abs gt {9} {7} ifelse index mark 13 3 roll cleartomark % x y X0 Y0 X1 Y1 x' y' => x' y' } def /StrokeCanvas { % color inset => - % REMIND: Should this use thick lines? exch setcolor gsave dup add setlinewidth /bbox self send /path self send stroke grestore } def % Grow to full (screen) size (true) or revert to normal size (false). % /zoom { % bool => - dup /zoomed? self send eq {pop} { gsave % bool framebuffer setcanvas % bool { /UnZoomedSize [ /bbox self send unfittab TabEdge TabPosition ] promote ZoomTabPosition setposition ZoomTabEdge setedge ZoomX ZoomY ZoomWidth ZoomHeight ?validate % XXX? fittab }{ UnZoomedSize aload pop setposition setedge ?validate % XXX? fittab /UnZoomedSize /unpromote self send } ifelse /reshape self send grestore } ifelse /mapped? self send not {true /open self send} if } def % make a default base frame with footer & grow control; then call vanilla % initialization procs for labels, footer, reshape etc. /demo { % - => window 10 dict begin % make a base frame and initialize it: [ FlexBag ] [/Footer true] framebuffer /newdefault ClassName load send /frame exch def /bag /client frame send def [ (Top) null { /Top /resetedge /parent target send send } (Bottom) null { /Bottom /resetedge /parent target send send } (Left) null { /Left /resetedge /parent target send send } (Right) null { /Right /resetedge /parent target send send } ] framebuffer /new OpenLookMenu send /setmenu bag send /Right /setedge frame send random /setposition frame send null random random 4 div random 4 div .75 add hsbcolor null /setcolors frame send null random random random 4 div .75 add hsbcolor null /setcolors bag send (Tab Frame) /setlabel frame send (Take a look) (and feel free!) /setfooter frame send 200 100 200 500 /reshape frame send /activate frame send /map frame send frame end } def classend def /TabBaseFrame [OpenLookBaseFrame TabFrame] [] classbegin classend def /TabPropertyFrame [OpenLookPropertyFrame TabFrame] [] classbegin classend def /TabCommandFrame [OpenLookCommandFrame TabFrame] [] classbegin classend def /TabHelpFrame [OpenLookHelpFrame TabFrame] [] classbegin classend def { /BaseFrameClass { TabBaseFrame } def /PropertyFrameClass { TabPropertyFrame } def /CommandFrameClass { TabCommandFrame } def /HelpFrameClass { TabHelpFrame } def } ClassFrame send { /DefaultClass { TabBaseFrame } def } ClassBaseFrame send { /DefaultClass { TabPropertyFrame } def } ClassPropertyFrame send { /DefaultClass { TabCommandFrame } def } ClassCommandFrame send { /DefaultClass { TabHelpFrame } def } ClassHelpFrame send %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % OpenLookTabFrameCorners % /OpenLookTabFrameCorners OpenLookFrameCorners [] classbegin /Edges { % x y w h delta => - 20 dict begin /d exch def /h exch def /w exch def /y exch def /x exch def /-d d neg def /D d 2 mul def /-D D neg def /X x w add def /Y y h add def x y h .5 mul add [ 0 d d -D -d ] polyrectpath X y h .5 mul add [ 0 -d -d D d ] polyrectpath x w .5 mul add y [ d d -D -d ] polyrectpath x w .5 mul add Y [ d -d -D d ] polyrectpath end } def % Override % % Hack: the path should be made from Corners; however, because % in 1.1 a fat line cannot intercept the clip, we use a fudge: % we make the path slightly larger than desired. % /path { % x y w h => - Delta 2 add 5 copy Corners Edges } def /PaintCanvas { % - => - % Fat line problem: we can't do the obvious: % FillColor setcolor clippath fill % 1 setlinequality 2 setlinewidth % StrokeColor setcolor clippath stroke .5 .5 Width 1 sub Height 1 sub Delta 5 copy Corners Edges FillColor setcolor gsave fill grestore StrokeColor setcolor stroke } def classend def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % OpenLookTabFrameLabel % /OpenLookTabFrameLabel [ClassControl OpenLookFrameLabel] [] classbegin /EventHandler { % event => - % callnotify puts self on stack and calls NotifyUser /callnotify self send } def /EventsConsumed /MatchedEvents def /ControlButton AdjustButton def % Which mouse button to use classend def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% end % systemdict