// tapedeck.c // // Control definition function for tapedeck-like buttons // // by John D. de Boer #include #include "common.h" #include "cstring.h" #include "cyber.h" #include "disk.h" #include "frame.h" #include "graph.h" #include "tapedeck.h" typedef struct { window *wind; // the window short part, // most recent part hit or tracked var; // variation code } TDStruct; typedef TDStruct **TDHand; extern ToolboxObjectClassRef TDOCR; static bool TDInit = 0; // Resizing static void resize(ControlRef C) { TDHand DH; if (!C) return; DH=(TDHand)GetControlDataHandle(C); if (!DH) return; } // Quartz drawing void tdpoly(window *W, short VAR) { switch (VAR) { case projMinus: beginpath(W); moveto(W,2,4); line4(W,6,0,0,2,-6,0,0,-2); fill(W); break; case projPlus: beginpath(W); moveto(W,2,4); line4(W,2,0,0,-2,2,0,0,2); line4(W,2,0,0,2,-2,0,0,2); line4(W,-2,0,0,-2,-2,0,0,-2); fill(W); break; case projLeftArrow: beginpath(W); moveto(W,1.5,5); line4(W,3.5,-3.5,0,2.5,3,0,0,2); line3(W,-3,0,0,2.5,-3.5,-3.5); fill(W); break; case projRightArrow: beginpath(W); moveto(W,2,4); line4(W,3,0,0,-2.5,3.5,3.5,-3.5,3.5); line3(W,0,-2.5,-3,0,0,-2); fill(W); break; case projUpArrow: beginpath(W); moveto(W,4,2); line4(W,2,0,0,3,2.5,0,-3.5,3.5); line3(W,-3.5,-3.5,2.5,0,0,-3); fill(W); break; case projDownArrow: beginpath(W); moveto(W,5,1.5); line4(W,3.5,3.5,-2.5,0,0,3,-2,0); line3(W,0,-3,-2.5,0,3.5,-3.5); fill(W); break; case projInArrow: beginpath(W); addcircle(W,5,5,3.3); addcircle(W,5,5,2.7); fill(W); beginpath(W); addcircle(W,5,5,0.8); fill(W); break; case projOutArrow: beginpath(W); addcircle(W,5,5,3.3); addcircle(W,5,5,2.7); fill(W); beginpath(W); moveto(W,3.4,2.6); line3(W,1.6,1.6,1.6,-1.6,0.8,0.8); line3(W,-1.6,1.6,1.6,1.6,-0.8,0.8); line3(W,-1.6,-1.6,-1.6,1.6,-0.8,-0.8); line3(W,1.6,-1.6,-1.6,-1.6,0.8,-0.8); fill(W); break; case tdSquare: beginpath(W); moveto(W,3,3); line4(W,4,0,0,4,-4,0,0,-4); fill(W); break; case tdCircle: beginpath(W); addcircle(W,5,5,2.5); fill(W); break; case tdLeftTriangle: beginpath(W); moveto(W,3,5); line3(W,3,-3,0,6,-3,-3); fill(W); break; case tdRightTriangle: beginpath(W); moveto(W,4,2); line3(W,3,3,-3,3,0,-6); fill(W); break; case tdUpTriangle: beginpath(W); moveto(W,2,4); line3(W,3,3,3,-3,-6,0); fill(W); break; case tdDownTriangle: beginpath(W); moveto(W,5,3); line3(W,-3,3,6,0,-3,-3); fill(W); break; case tdDoubleLeftTriangle: beginpath(W); moveto(W,1.5,5); line3(W,3,-3,0,6,-3,-3); moveto(W,5,5); line3(W,3,-3,0,6,-3,-3); fill(W); break; case tdDoubleRightTriangle: beginpath(W); moveto(W,2,2); line3(W,3,3,-3,3,0,-6); moveto(W,5.5,2); line3(W,3,3,-3,3,0,-6); fill(W); break; case tdvarMailAndBuckler: beginpath(W); moveto(W,1.5,2); line4(W,2.5,0,1,1,1,-1,2.5,0); line4(W,0,2,-1.5,0,0,4,-4,0); line3(W,0,-4,-1.5,0,0,-2); stroke(W); beginpath(W); addcircle(W,6.5,6.5,2); fill(W); break; } } static void qdraw(window *W, rect R, short VAR, bool Focus, bool On) { rect Src; colour B,G; if (!W || !W->q2d) return; savegraphics(W); settop(&R,top(R) - 1.0); cliprect(W,R); setrgb(&B,0.4,0.65,0.83); setrgb(&G,0.9,0.9,0.9); fillcolour(W,Focus ? (On ? &B : &B) : &G); fillrect(W,R); penindex(W,grey); penwidth(W,0.5); framerect(W,R); setrect(&Src,0.0,0.0,10.0,10.0); transform(W,Src,R); fillindex(W,black); penindex(W,black); penwidth(W,1.0); tdpoly(W,VAR); restoregraphics(W); } // Drawing static void draw(ControlRef C) { WindowRef WP; TDHand DH; int HILITE; ControlPartCode PART; Rect R; rect Q; window *W; if (!C || !IsControlVisible(C)) return; DH=(TDHand)GetControlDataHandle(C); if (!DH) return; WP=GetControlOwner(C); if (!WP) return; HILITE=GetControlHilite(C); PART=(*DH)->part; GetControlBounds(C,&R); cgrect(&R,&Q); Q.origin.y=0.0; W=(*DH)->wind; if (!W) return; qdraw(W,Q,(*DH)->var,PART!=kControlNoPart,HILITE!=kControlNoPart); /*Info.state= kThemeStateActive;//(PART==kControlNoPart) ? kThemeStateActive : kThemeStatePressed; Info.adornment= (PART==kControlNoPart) ? kThemeAdornmentDefault : kThemeAdornmentFocus; Info.value= (HILITE==kControlNoPart) ? kThemeButtonOff : kThemeButtonOn; savegraf(&G); SetPortWindowPort(WP); SetOrigin(0,0); GetControlBounds(C,&R); DrawThemeButton(&R,kThemeLargeBevelButton,&Info,NULL,NULL,NULL,0); if (IsControlActive(C))*/ } // Initialisation static void init(ControlRef C, short VAR) { WindowRef WP; window *W; TDHand DH; WP=GetControlOwner(C); if (!WP) return; W=windowfromlist(WP); if (!W) return; DH=(TDHand)NewHandle(sizeof(TDStruct)); SetControlDataHandle(C,(Handle)DH); (*DH)->part=kControlNoPart; (*DH)->wind=W; (*DH)->var=VAR; } // Other messages static ControlPartCode test(ControlRef C, Point P, bool Debug) { Rect R,D; bool Hit; if (!IsControlVisible(C)) return kControlNoPart; GetControlBounds(C,&R); Hit=PtInRect(P,&R); if (Debug) { D=R; } return Hit ? TDPart : kControlNoPart; } static void disp(ControlRef C) { TDHand DH; DH=(TDHand)GetControlDataHandle(C); DisposeHandle((void *)DH); } // Message handling static pascal OSStatus tdcntldef(EventHandlerCallRef EH, EventRef E, void *userData) { UInt32 msg; OSStatus err; SInt32 size; Collection Co; ControlRef C; Point P; UInt16 var; ControlPartCode Part; MouseTrackingResult mtr; UInt32 mods; WindowRef WP; GrafPtr GP; ControlActionUPP Proc; TDHand DH; int count; err=GetEventParameter(E,kEventParamDirectObject,typeControlRef,NULL,sizeof(ControlRef),NULL,&C); msg=GetEventKind(E); switch (msg) { case kEventControlInitialize: err=GetEventParameter(E,kEventParamInitCollection,typeCollection,NULL,sizeof(Collection),NULL,&Co); size=sizeof(UInt16); err=GetCollectionItem(Co,'TVAR',0,&size,&var); init(C,var); return noErr; case kEventControlDispose: disp(C); return noErr; case kEventControlDraw: draw(C); return noErr; case kEventControlHitTest: err=GetEventParameter(E,kEventParamMouseLocation,typeQDPoint,NULL,sizeof(Point),NULL,&P); // local Part=test(C,P,0); SetEventParameter(E,kEventParamControlPart,typeControlPartCode,sizeof(ControlPartCode),&Part); DH=(TDHand)GetControlDataHandle(C); if (DH) (*DH)->part=Part; return noErr; case kEventControlTrack: WP=GetControlOwner(C); if (!WP) return noErr; GP=GetWindowPort(WP); if (!GP) return noErr; DH=(TDHand)GetControlDataHandle(C); if (!DH) return noErr; Proc=GetControlAction(C); for (count=0;;count++) { float Wait; Wait= (count==0) ? 0.0 : ((count==1 ? 0.33 : 0.05) * kEventDurationSecond); err=TrackMouseLocationWithOptions(GP,0,Wait,&P,&mods,&mtr); // local? if (mtr==kMouseTrackingMouseUp) break; Part=test(C,P,1); (*DH)->part=Part; draw(C); if (Part!=kControlNoPart && Proc) Proc(C,Part); } (*DH)->part=kControlNoPart; draw(C); SetEventParameter(E,kEventParamControlPart,typeControlPartCode,sizeof(ControlPartCode),&Part); return noErr; case kEventControlBoundsChanged: resize(C); return noErr; } return eventNotHandledErr; } void inittd(void) { EventTypeSpec ET[6]; EventHandlerUPP TDUPP; if (TDInit) return; ET[0].eventClass=kEventClassControl; ET[0].eventKind=kEventControlInitialize; ET[1].eventClass=kEventClassControl; ET[1].eventKind=kEventControlDispose; ET[2].eventClass=kEventClassControl; ET[2].eventKind=kEventControlDraw; ET[3].eventClass=kEventClassControl; ET[3].eventKind=kEventControlHitTest; ET[4].eventClass=kEventClassControl; ET[4].eventKind=kEventControlTrack; ET[5].eventClass=kEventClassControl; ET[5].eventKind=kEventControlBoundsChanged; TDUPP=NewEventHandlerUPP(&tdcntldef); RegisterToolboxObjectClass(CFSTR("Tapedeck"),NULL,6,ET,TDUPP,NULL,&TDOCR); TDInit=1; }