home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** File: Window.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1990-1993 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /* You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes. */
-
- /* •••• Except for a couple of places (marked by ••••), this is the only file that
- ** changed to turn AppWannabe into pbClock. Since the changes here are relatively
- ** extensive, I didn't mark them with ••••, although they are commented. */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "App.h" /* Get the application includes/typedefs, etc. */
- #include "App.defs.h" /* Get various application definitions. */
- #include "App.protos.h" /* Get the prototypes for application. */
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __FONTS__
- #include <Fonts.h>
- #endif
-
- #ifndef __LOWMEM__
- #include <LowMem.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- static void ContentCommon(WindowPtr window, EventRecord *event, short cnum, short action,
- RGBColor *oldc, RGBColor *newc);
- static void FetchClockValues(FileRecHndl frHndl, short field);
- static Boolean TrackArrowProc(ControlHandle ctl, short part, EventRecord *event);
- static Boolean TrackRadioProc(ControlHandle ctl, short part, EventRecord *event);
- static void SwitchClocks(FileRecHndl frHndl, EventRecord *event, short cnum);
- static void HiliteTabAndReturn(FileRecHndl frHndl);
- static Boolean DigitsOnly(TEHandle teHndl, EventRecord *event, short *handled);
- static OSErr BackLayerProc(LayerObj theLayer, short message);
- static OSErr WorkLayerProc(LayerObj theLayer, short message);
- static short MyGetRadioButtonChoice(WindowPtr window, short famNum);
- static short MyGetButtonVariant(ControlHandle ctl, Boolean *stop);
-
- static Point gArcLocs[60]; /* Used to cache data for speed up. */
-
- static LayerObj gBackLayer[2], gWorkLayer;
- /* These are globals so that they can be created just once. This speeds up
- ** clock redraws after the first one. In the DrawClocks function, first
- ** a windowLayer is created that is the size/location of the left clock.
- ** Then, if gWorkLayer hasn't been created yet, it is created as a below-layer
- ** for windowLayer. I force a depth of 1 for gWorkLayer since the clocks are
- ** only b/w.
- **
- ** Since gWorkLayer and gBackLayer are used as a pair, when gWorkLayer is created,
- ** so is gBackLayer. If they were already created when DrawClocks is called, then
- ** they are inserted into the windowLayer "chain" just below windowLayer.
- ** Once they are created and attached, they are used, and then just windowLayer
- ** is disposed of, leaving gWorkLayer and gBackLayer around for the next usage.
- **
- ** The only other trick with these guys is that the AppsToGo editor can be used
- ** on this application while it is running. It is possible that the left and right
- ** clock controls (which are just data controls, and used for their size/position)
- ** are changed. This would mean that the cached layers could be wrong. Therefore
- ** in the OpenApplication function (which is called at startup of the application
- ** and at editor restart time), we need to get rid of them if they exist. By
- ** getting rid of them, the next time that DrawClocks is called, it will create
- ** them again, based on the new size of the clock controls. */
-
- typedef struct {
- long drawTime;
- short numMoves, timeControl, numRemaining, numTimeControls;
- } DrawClocksInfo;
- /* This is the info that the layer procs need. We put it into a structure
- ** because when we create a layer, we only get to pass in a single refcon
- ** value. The refcon value will point to one of these structures. */
-
-
-
- /*****************************************************************************/
-
-
-
- Boolean gNoDefaultDocument = false;
- /* Set to true if app should boot with no default document. */
- /* This tells DTS.Lib..framework what you want. */
-
- OSType gAppWindowType = kDocFileType; /* Main document type. */
- long gAppWindowAttr = kwAppWindow; /* Main window attributes. */
-
- short gMinVersion = kMinVersion; /* Minimum document version app can support. */
- short gMaxVersion = kMaxVersion; /* Maximum document version app can support. */
- /* More informing DTS.Lib..framework. */
-
- extern long gTimer;
-
- extern short gPrintPage; /* Non-zero means we are printing. */
- /* DTS.Lib..framework global. */
-
- extern RgnHandle gCursorRgn; /* We handle cursors here, so we need */
- extern CursPtr gCursorPtr; /* to know about these things. */
- /* Above are DTS.Lib..framework globals. */
-
- extern GetButtonVariantProcPtr gGetButtonVariant;
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Calculate application specific frame area (Called by DoCalcFrameRgn).
- ** You are passed an empty region. You are supposed to add any custom frame
- ** parts that this document uses. Typically there are no frame portions, as
- ** they are accounted for in other ways. The scrollbars and grow icon will
- ** automatically be contributed to the calculation of the frame region.
- ** If you use sidebars, these are also added in automatically. This is only
- ** used if the frame region is more complicated than can automatically be
- ** handled. So, almost always, you will simply leave the region empty. */
-
- #pragma segment TheDoc
- void CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, rgn)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
- ** a window. Other applications might want to call FindControl, TEClick, etc., to
- ** further process the click. */
-
- #pragma segment TheDoc
- void ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
- {
- #ifndef __MWERKS__
- #pragma unused (firstClick)
- #endif
-
- WindowPtr oldPort;
- FileRecHndl frHndl;
- TreeObjHndl root;
- ControlHandle ctl;
- short action, cnum, lr;
- RGBColor oldc, newc;
-
- GetPort(&oldPort);
- SetPort(window);
- if (gQDVersion) {
- GetBackColor(&oldc);
- newc.red = newc.green = newc.blue = 0xFFFF;
- RGBBackColor(&newc);
- } /* The window color is non-white, but the control area containing TEControls
- ** is white. Therefore we have to set the backColor to white before doing
- ** teControl operations, or else we will get some weird results. */
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- root = (*frHndl)->d.doc.root;
-
- cnum = IsCtlEvent(window, event, &ctl, &action);
-
- switch (cnum) {
-
- case kLeftClockRadio:
- case kRightClockRadio:
- case kBothClocksRadio:
- case kSetClocks:
- case kResetClocks:
- case kStartClocks:
- case kPauseClocks:
- case kTabButton:
- case kReturnButton:
- ContentCommon(window, event, cnum, action, &oldc, &newc);
- break;
-
- default:
- if (cnum) {
- FetchClockValues(frHndl, 0);
- /* For any other control click, fetch the values. FetchClockValues also
- ** properly closes fields, which is really why we are doing this. */
-
- if ((cnum >= kTimeControl1Hours) && (cnum < kTimeControlEndRange)) {
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- lr = MyGetRadioButtonChoice(window, 0);
- DrawClock(frHndl, (lr & 0x01));
- if (lr == 2) DrawClock(frHndl, 1);
- }
- }
- break;
- }
-
- if (gQDVersion)
- RGBBackColor(&oldc);
-
- SetPort(oldPort);
- return;
- }
-
- static void ContentCommon(WindowPtr window, EventRecord *event, short cnum, short action,
- RGBColor *oldc, RGBColor *newc)
- {
- ControlHandle ctl, cc;
- FileRecHndl frHndl;
- TreeObjHndl root;
- short rs, nm, i;
- Str15 pstr;
- long diff, timer, t1, t2;
- TEHandle te;
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- root = (*frHndl)->d.doc.root;
-
- switch (cnum) {
-
- case kLeftClockRadio:
- case kRightClockRadio:
- case kBothClocksRadio:
- InitContent(frHndl, window);
- if (MyGetRadioButtonChoice(window, 0) == 2) { /* If "both" radio button selected... */
- FetchClockValues(frHndl, 0);
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- /* If both clocks being set, propagate clock setting. */
- }
- DrawClocks(frHndl);
- break;
-
- case kSetClocks:
- RGBBackColor(oldc);
- DisplayControlSet(window, 'pbc2', kwHideAll); /* Hide the run clocks controls. */
- RGBBackColor(newc);
- DisplayControlSet(window, 'pbc3', kwShowAll); /* Show the set clocks controls. */
-
- CNum2Ctl(window, kStartClocksText, &cc); /* The title of kStartClocksText is used to */
- pcpy(pstr, (*cc)->contrlTitle); /* determine if the clocks are running. Therefore */
- CNum2Ctl(window, kPauseClocks, &cc); /* flag the clocks as stopped when setting them. */
- SetStyledCTitle(cc, pstr);
-
- CTEWindActivate(window, true); /* Reactivate last-active TEControl. */
- te = CTEFindActive(window); /* Show selection range of active TEControl. */
- if (te) CTESetSelect(0, 999, te);
-
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- /* The timeRemaining fields are what is drawn in the clocks, so reset their
- ** values so that we can display the time that the user is entering. */
-
- mDerefRoot(root)->rightStart = -1; /* Nobody has started the clocks yet flag. */
- mDerefRoot(root)->numMoves[0] = 0;
- mDerefRoot(root)->numMoves[1] = 0;
- DrawClocks(frHndl); /* Show the user the reset values. */
- break;
-
- case kResetClocks:
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- mDerefRoot(root)->rightStart = -1; /* Nobody has started the clocks yet flag. */
- mDerefRoot(root)->numMoves[0] = 0;
- mDerefRoot(root)->numMoves[1] = 0;
- (*frHndl)->d.doc.timer = event->when; /* Sync up the ticks. */
- CNum2Ctl(window, kPauseClocks, &ctl);
- (*ctl)->contrlValue = 0; /* Reset balloon help for control. */
- CNum2Ctl(window, kStopClocksText, &cc); /* Put clocks in non-pause play mode. */
- pcpy(pstr, (*cc)->contrlTitle);
- SetStyledCTitle(ctl, pstr);
- DrawClocks(frHndl); /* Show the user the reset values. */
- HiliteTabAndReturn(frHndl); /* Adjust the rest of the controls. */
- break;
-
- case kStartClocks:
- FetchClockValues(frHndl, 0);
- /* Get the control values and place them into the document.
- ** This also closes any open field. */
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- mDerefRoot(root)->rightStart = -1; /* Nobody has started the clocks yet flag. */
- mDerefRoot(root)->numMoves[0] = 0;
- mDerefRoot(root)->numMoves[1] = 0;
- DrawClocks(frHndl); /* Show the user the reset values. */
- CNum2Ctl(window, kStopClocksText, &ctl);
- pcpy(pstr, (*ctl)->contrlTitle);
- CNum2Ctl(window, kPauseClocks, &ctl);
- (*ctl)->contrlValue = 0;
- SetStyledCTitle(ctl, pstr);
- CNum2Ctl(window, kNoClockButtonClick, &ctl);
- (*ctl)->contrlVis = 0; /* Prevent an erase when the kwHideAll is done. */
- HiliteTabAndReturn(frHndl);
- RGBBackColor(oldc);
- DisplayControlSet(window, 'pbc3', kwHideAll);
- RGBBackColor(newc);
- DisplayControlSet(window, 'pbc2', kwShowAll);
- (*frHndl)->d.doc.timer = event->when; /* Sync up the ticks. */
- break;
-
- case kPauseClocks:
- CNum2Ctl(window, kPauseClocks, &ctl);
- if (ClocksPaused(window)) {
- (*frHndl)->d.doc.timer = event->when; /* If currently paused, start 'em up again. */
- (*ctl)->contrlValue = 0;
- CNum2Ctl(window, kStopClocksText, &cc);
- }
- else {
- ContentCommon(window, event, kUpdateClock, action, oldc, newc);
- /* This is just a cute way to call some common code. */
- (*ctl)->contrlValue = 2; /* Clocks stopped has different balloon help. */
- CNum2Ctl(window, kStartClocksText, &cc);
- }
- pcpy(pstr, (*cc)->contrlTitle);
- SetStyledCTitle(ctl, pstr);
- HiliteTabAndReturn(frHndl);
- break;
-
- case kTabButton:
- case kReturnButton:
- ContentCommon(window, event, kUpdateClock, action, oldc, newc);
- /* This is just a cute way to call some common code. */
- SwitchClocks(frHndl, event, cnum);
- HiliteTabAndReturn(frHndl);
- break;
-
- case kUpdateClock: /* No such control. It's a common utility message. */
- timer = (*frHndl)->d.doc.timer;
- (*frHndl)->d.doc.timer = event->when;
- if (timer) {
- rs = mDerefRoot(root)->rightStart;
- nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
- if (rs > -1) {
- i = nm + rs;
- i &= 0x01;
- diff = event->when - timer;
- if (diff < 0) diff = 0;
- t1 = mDerefRoot(root)->timeRemaining[i];
- t2 = t1 - diff;
- if (t2 < 0) t2 = 0;
- mDerefRoot(root)->timeRemaining[i] = t2;
- if ((t1 / 60) != (t2 / 60)) DrawClock(frHndl, i);
- }
- }
- break;
- }
- }
-
- static void HiliteTabAndReturn(FileRecHndl frHndl)
- {
- WindowPtr window;
- TreeObjHndl root;
- short t, r, rs, nm, lcRunning, rcRunning, pauseHilite, btn;
- ControlHandle ctl;
- long t1, t2;
-
- window = (*frHndl)->fileState.window;
- root = (*frHndl)->d.doc.root;
-
- pauseHilite = 0;
- lcRunning = rcRunning = 0;
- if (ClocksPaused(window)) {
- CNum2Ctl(window, kNoClockButtonClick, &ctl);
- (*ctl)->contrlVis = 255;
- /* This masks out the buttons on the top of the clock. When this control
- ** is visible, clicks wil go to it, instead of the buttons, which are
- ** behind this control. This control does nothing with the click.
- ** Therefore the clock buttons are effectively disabled. */
- t = r = 255; /* tab and return to be disabled. */
- }
- else {
- CNum2Ctl(window, kNoClockButtonClick, &ctl);
- (*ctl)->contrlVis = 0; /* Enable clicks on clock buttons. */
- t = r = 0; /* Assume tab and return as enabled. */
- rs = mDerefRoot(root)->rightStart;
- if (rs > -1) {
- nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
- if (!((nm + rs) & 0x01)) {
- r = 255; /* return disabled. */
- lcRunning = 1; /* left clock running. */
- }
- else {
- rcRunning = 1; /* tab disabled. */
- t = 255; /* right clock disabled. */
- }
- }
- else pauseHilite = 255; /* pause button grayed out. */
-
- if (!(t1 = mDerefRoot(root)->timeRemaining[0])) t = 255; /* If no time on left, gray out tab. */
- if (!(t2 = mDerefRoot(root)->timeRemaining[1])) r = 255; /* If no time on right, gray out return. */
- if (!(t1 | t2)) pauseHilite = 255; /* If nobody has moved yet, gray out pause clock button. */
- }
-
- CNum2Ctl(window, kTabButton, &ctl);
- if ((*ctl)->contrlHilite != t) { /* If control changed... */
- UseControlStyle(ctl);
- HiliteControl(ctl, t);
- UseControlStyle(nil);
- }
- if (!t) { /* Do context-sensitive balloon help for tab. */
- if (!r)
- (*ctl)->contrlValue = 0;
- else
- (*ctl)->contrlValue = 2;
- }
- else {
- if (!r)
- (*ctl)->contrlValue = 3;
- else
- (*ctl)->contrlValue = 4;
- }
-
- CNum2Ctl(window, kLeftClock, &ctl);
- (*ctl)->contrlValue = lcRunning; /* Context sensistve balloon help value for left clock face. */
-
- CNum2Ctl(window, kReturnButton, &ctl);
- if ((*ctl)->contrlHilite != r) { /* If control changed... */
- UseControlStyle(ctl);
- HiliteControl(ctl, r);
- UseControlStyle(nil);
- }
- if (!r) { /* Do context-sensitive balloon help for return. */
- if (!t)
- (*ctl)->contrlValue = 0;
- else
- (*ctl)->contrlValue = 2;
- }
- else {
- if (!t)
- (*ctl)->contrlValue = 3;
- else
- (*ctl)->contrlValue = 4;
- }
-
- CNum2Ctl(window, kRightClock, &ctl);
- (*ctl)->contrlValue = rcRunning; /* Context sensistve balloon help value for right clock face. */
-
- CNum2Ctl(window, kPauseClocks, &ctl);
- if ((*ctl)->contrlHilite != pauseHilite) { /* If control changed... */
- (*ctl)->contrlHilite = pauseHilite;
- DoDraw1Control(ctl, false);
- }
-
- btn = 2;
- if ((lcRunning) && (!rcRunning)) btn = 0;
- if ((!lcRunning) && (rcRunning)) btn = 1;
- CNum2Ctl(window, kLeftClock + 2, &ctl); /* Left clock button. */
- if ((*ctl)->contrlValue != btn) {
- (*ctl)->contrlValue = btn;
- DoDraw1Control(ctl, false);
- }
-
- if (btn < 2) btn ^= 0x01;
- CNum2Ctl(window, kRightClock + 2, &ctl); /* Right clock button. */
- if ((*ctl)->contrlValue != btn) {
- (*ctl)->contrlValue = btn;
- DoDraw1Control(ctl, false);
- }
- }
-
- short ClocksPaused(WindowPtr window)
- {
- ControlHandle ctl;
- Str63 p0, p1;
-
- CNum2Ctl(window, kPauseClocks, &ctl);
- pcpy(p0, (*ctl)->contrlTitle);
- CNum2Ctl(window, kStopClocksText, &ctl);
- pcpy(p1, (*ctl)->contrlTitle);
- return(pcmp(p0, p1)); /* If button DOESN'T compare to stopText, then they are stopped. */
- }
-
- static void FetchClockValues(FileRecHndl frHndl, short field)
- {
- WindowPtr window;
- TreeObjHndl root;
- ControlHandle ctl, ch, cm;
- short lr1, lr2, i, cn1, cn2;
- Str15 pstr, ph, pm;
- long h, m, tc1, tc2, tc3;
-
- /* I didn't spend much time typing the below code, or any other part of this sample for
- ** that matter. I realize that this could probably be done much better/smaller, but
- ** I was coding against a clock, so cut me some slack. */
-
- window = (*frHndl)->fileState.window;
- root = (*frHndl)->d.doc.root;
-
- lr1 = MyGetRadioButtonChoice(window, 0);
- if (lr1 < 2) lr1 = lr2 = (3 * lr1);
- else {
- lr1 = 0;
- lr2 = 3;
- } /* Get the left/right clock offsets. This is based on which control is selected
- ** in the family of radio buttons. (We only have one family -- 0.) */
-
- for (i = 0; i < 3; ++i) {
- cn1 = kTimeControl1Hours + i * (kTimeControl2Hours - kTimeControl1Hours);
- cn2 = kTimeControl1Minutes + i * (kTimeControl2Minutes - kTimeControl1Minutes);
- if ((!field) || (field == cn1) || (field == cn2)) {
- CNum2Ctl(window, cn1, &ch);
- CNum2Ctl(window, cn2, &cm);
- /* Use the delta as an offset. This is correct, based on the ctlID's I chose. */
- /* The controls gotten are the hours/minutes control for timeControl i, for whichever
- ** clock is currently chosen. */
- CTEGetPStr(ch, ph);
- h = p2dec(ph, nil);
- CTEGetPStr(cm, pm);
- m = p2dec(pm, nil);
- if (m > 59) {
- ++h;
- if (h > 99) h = 0;
- m -= 60;
- ph[0] = pm[0] = 0;
- }
- if (ph[0] < 2) {
- pcpypaddec(ph, '0', 2, 2, h);
- CTEPutPStr(ch, ph);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(ch));
- }
- if (pm[0] < 2) {
- pcpypaddec(pm, '0', 2, 2, m);
- CTEPutPStr(cm, pm);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(cm));
- }
- mDerefRoot(root)->timeControl[lr1 + i] = (60 * h + m) * 60 * 60;
- mDerefRoot(root)->timeControl[lr2 + i] = (60 * h + m) * 60 * 60;
- /* Munge the hours and minutes values into a single long tick value. */
- }
- }
-
- if ((!field) || ((field >= kTC1NumMoves) && (field <= kTC3NumMoves))) {
-
- CNum2Ctl(window, kTC1NumMoves, &ctl);
- CTEGetPStr(ctl, pstr);
- tc1 = p2dec(pstr, nil); /* TimeControl 1 value. */
-
- CNum2Ctl(window, kTC2NumMoves, &ctl);
- CTEGetPStr(ctl, pstr);
- tc2 = p2dec(pstr, nil); /* TimeControl 2 value. */
-
- CNum2Ctl(window, kTC3NumMoves, &ctl);
- CTEGetPStr(ctl, pstr);
- tc3 = p2dec(pstr, nil); /* TimeControl 3 value. */
-
- if (!tc1) {
- tc2 = 0; /* If no timeControl 1, then no timeControl 2. */
- CNum2Ctl(window, kTC1NumMoves, &ctl);
- UseControlStyle(ctl);
- CTEPutPStr(ctl, "\p"); /* Change a potential 0 into a nullField. */
- UseControlStyle(nil);
- }
- if (!tc2) { /* Same logic as above. */
- tc3 = 0;
- CNum2Ctl(window, kTC2NumMoves, &ctl);
- UseControlStyle(ctl);
- CTEPutPStr(ctl, "\p");
- UseControlStyle(nil);
- }
- if (!tc3) { /* Same logic as above. */
- CNum2Ctl(window, kTC3NumMoves, &ctl);
- UseControlStyle(ctl);
- CTEPutPStr(ctl, "\p");
- UseControlStyle(nil);
- }
-
- mDerefRoot(root)->numMovesInTimeControl[0] = tc1; /* Save 'em. */
- mDerefRoot(root)->numMovesInTimeControl[1] = tc2;
- mDerefRoot(root)->numMovesInTimeControl[2] = tc3;
- }
- }
-
- static Boolean TrackArrowProc(ControlHandle ctl, short part, EventRecord *event)
- {
- #ifndef __MWERKS__
- #pragma unused (part, event)
- #endif
-
- WindowPtr window, oldPort;
- short cnum, i, hrAdjust;
- ControlHandle cc, ccc;
- Str15 pstr, ppp;
- Point pt;
- Rect crct;
- long dt, tc;
-
- /* This be one of the workhorses of this sample. The arrow controls have a TrackProc
- ** set for them in InitContent. When the user clicks on an arrow, we end up here.
- ** It is this code's responsibility to track the control, and to update the hour/minute
- ** fields accordingly. */
-
- dt = TickCount() + LMGetDoubleTime();
- /* We don't want to start zooming right away. This is our delay before repeat. */
-
- window = (*ctl)->contrlOwner; /* We have to find out who we are talking about. */
- cnum = Ctl2CNum(ctl);
- crct = (*ctl)->contrlRect; /* That's enough info on where we are. */
-
- GetPort(&oldPort);
- SetPort(window);
-
- CNum2Ctl(window, (cnum & 0xFFFC), &cc);
- /* Note that I carefully selected the ctlID's so that I could do this kind of stuff.
- ** The arrow's ctlID relates it to the TEControl that it adjusts. cc is that field. */
- UseControlStyle(cc);
- CTEGetPStr(cc, pstr); /* We now have the currelt text from the related TEControl. */
-
- tc = 0x7FFFFFFFL; /* Use a ridiculous initial value. */
- do {
- if (tc > dt) { /* First time through, duh... */
- GetMouse(&pt);
- if (PtInRect(pt, &crct)) { /* Is user actually still on the arrow? */
- HiliteControl(ctl, 1);
- hrAdjust = 0; /* Assume that we won't adjust the hour field. */
- i = p2dec(pstr, nil);
- (cnum & 0x01) ? ++i : --i; /* Up arrow or down arrow hit -- the bits tell us. */
- if (cnum & 0x04) { /* If minute field... */
- if (i < 0) {
- i = 59;
- hrAdjust = -1; /* Roll-over, so we will adjust the hour field, as well. */
- }
- if (i > 59) {
- i = 0;
- hrAdjust = 1; /* Roll-over, so we will adjust the hour field, as well. */
- }
- }
- else {
- if (i < 0) i = 99;
- if (i > 99) i = 0;
- }
- pcpypaddec(pstr, '0', 2, 2, i);
- CTEPutPStr(cc, pstr);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(cc));
- if (hrAdjust) { /* If there was a minute roll-over... */
- i = (cnum ^ 0x04);
- CNum2Ctl(window, (i & 0xFFFC), &ccc);
- CTEGetPStr(ccc, ppp);
- i = p2dec(ppp, nil) + hrAdjust;
- if (i < 0) i = 99;
- if (i > 99) i = 0;
- pcpypaddec(ppp, '0', 2, 2, i);
- CTEPutPStr(ccc, ppp);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(ccc));
- }
- SetWindowDirty(window); /* There was a change, so flag it. */
- }
- else HiliteControl(ctl, 0);
- dt += 6; /* Repeat rate is 1/10 of a second. */
- }
- tc = TickCount();
- } while (StillDown());
-
- HiliteControl(ctl, 0);
-
- UseControlStyle(nil);
- SetPort(oldPort);
- return(true);
- }
-
- static Boolean TrackRadioProc(ControlHandle ctl, short part, EventRecord *event)
- {
- #ifndef __MWERKS__
- #pragma unused (part)
- #endif
-
- WindowPtr window;
- FileRecHndl frHndl;
- TreeObjHndl root;
- static ControlActionUPP cupp;
-
- window = (*ctl)->contrlOwner; /* We have to find out who we are talking about. */
- frHndl = (FileRecHndl)GetWRefCon(window);
- root = (*frHndl)->d.doc.root;
-
- FetchClockValues(frHndl, 0); /* We're here BEFORE the radio buttons switch. */
- mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
- mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
- /* Move clock values where DrawClock can display them. */
-
- if (event->what != mouseDown) return(true); /* Keypresses "tracked". */
-
- if (!cupp) cupp = (ControlActionUPP)(-1);
- return(TrackControl(ctl, event->where, cupp));
- }
-
- Boolean DigitsOnly(TEHandle te, EventRecord *event, short *handled)
- {
- #ifndef __MWERKS__
- #pragma unused (te, handled)
- #endif
-
- char key;
- short i;
- Boolean validChar;
-
- key = event->message & charCodeMask; /* Cut & paste from some other app I had. */
- i = event->modifiers & keyCodeMask;
- if (i & cmdKey) return(false);
- if (i & optionKey) return(false);
- if (key == 8) return(false);
- if (key == 9) return(false);
- if ((key >= 28) && (key <= 31)) return(false);
-
- validChar = false;
- if ((key >= '0') && (key <= '9')) validChar = true;
-
- if (validChar) return(false);
-
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* DoKeyDown() is first called by the application. Then if the key isn't a menu
- ** key, DoKeyDown() calls this code. Here are the rules for this function:
- **
- ** 1) If you handle the key, return(true). This completes the key handling.
- ** 2) If you don't handle the key, you return false. However, there are two
- ** situations for not handling the key:
- ** a) You want someone else to.
- ** b) You want nobody else to look at the key.
- ** This is what the boolean passThrough is for. If you wish the next window
- ** to have a look at the key, set the boolean passThrough to true. passThrough
- ** is already initialized to false, which is the common case, so you only have
- ** to worry about setting it true.
- **
- ** If you have a window that never processes keys and always passes them through,
- ** just set the contentKeyProc to nil. This will indicate to the application
- ** framework that all keys should be passed through this window. DTS.Draw has
- ** such a window. Its palette window doesn't accept keys. They are passed through
- ** to document windows. */
-
- #pragma segment TheDoc
- Boolean ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
- {
- #ifndef __MWERKS__
- #pragma unused (passThrough)
- #endif
-
- WindowPtr oldPort;
- FileRecHndl frHndl;
- TreeObjHndl root;
- short cnum, action, i;
- long lcc, rcc;
- ControlHandle ctl;
- TEHandle te1, te2;
- RGBColor oldc, newc;
-
- GetPort(&oldPort);
- SetPort(window);
- if (gQDVersion) {
- GetBackColor(&oldc);
- newc.red = newc.green = newc.blue = 0xFFFF;
- RGBBackColor(&newc);
- }
-
- frHndl = (FileRecHndl)GetWRefCon(window);
- root = (*frHndl)->d.doc.root;
-
- /* This is a bit different than the usual AppsToGo ContentKey function. Since this
- ** app is actually modal (clocks running or not), we need to determine if it is
- ** correct to call IsCtlEvent or not. If the clocks are running, then the tab
- ** key is used as a clock button. If we call IsCtlEvent, it will be used to
- ** advance to the next TEControl. Therefore we need to check if the clocks are
- ** running. We do this by checking the reset control. If it is inactive, then
- ** the user clicked on it to start the clock mode. */
-
- te1 = CTEFindActive(window);
- cnum = IsCtlEvent(window, event, nil, &action);
-
- if (cnum == kCRAdvance) { /* Use the c/r key to advance to next field vertically. */
- ctl = CTEViewFromTE(te1);
- i = Ctl2CNum(ctl) + 40;
- if (i == 320) i = 204;
- if (i == 324) i = 300;
- if (i == 420) i = 200;
- CNum2Ctl(window, i, &ctl);
- CTEActivate(true, (TEHandle)GetControlReference(ctl));
- CTESetSelect(0, 3, (TEHandle)GetControlReference(ctl));
- }
-
- te2 = CTEFindActive(window);
-
- if (te1 != te2) { /* Keypress changed field, so close the old one. */
- ctl = CTEViewFromTE(te1);
- FetchClockValues(frHndl, Ctl2CNum(ctl)); /* Specifically fetch the old field. */
- lcc = mDerefRoot(root)->timeRemaining[0] - mDerefRoot(root)->timeControl[0];
- rcc = mDerefRoot(root)->timeRemaining[1] - mDerefRoot(root)->timeControl[3];
- mDerefRoot(root)->timeRemaining[0] -= lcc;
- mDerefRoot(root)->timeRemaining[1] -= rcc;
- if (lcc) DrawClock(frHndl, 0); /* Draw the left clock if it needs updating. */
- if (rcc) DrawClock(frHndl, 1); /* Draw the right clock if it needs updating. */
- }
-
- if (action == 2) SetWindowDirty(window);
- /* If a TEControl was changed, dirty the document. */
-
- switch (cnum) {
- case kLeftClockRadio:
- case kRightClockRadio:
- case kBothClocksRadio:
- case kSetClocks:
- case kResetClocks:
- case kStartClocks:
- case kPauseClocks:
- case kTabButton:
- case kReturnButton:
- ContentCommon(window, event, cnum, action, &oldc, &newc);
- break;
- }
-
- if (gQDVersion)
- RGBBackColor(&oldc);
-
- SetPort(oldPort);
- return(true);
- }
-
- static void SwitchClocks(FileRecHndl frHndl, EventRecord *event, short cnum)
- {
- TreeObjHndl root;
- short i, rs, nm, nm1, nm2, nm3;
- long tc;
-
- root = (*frHndl)->d.doc.root;
-
- rs = mDerefRoot(root)->rightStart;
- nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
- if (rs < 0) { /* If clocks haven't been started yet. */
- (*frHndl)->d.doc.timer = event->when;
- if (cnum == kTabButton)
- mDerefRoot(root)->rightStart = 1; /* Start the right clock. */
- if (cnum == kReturnButton)
- mDerefRoot(root)->rightStart = 0; /* Start the left clock. */
- DrawClocks(frHndl);
- return;
- }
-
- nm1 = mDerefRoot(root)->numMovesInTimeControl[0]; /* Get the timeControl landmarks. */
- nm2 = mDerefRoot(root)->numMovesInTimeControl[1];
- nm3 = mDerefRoot(root)->numMovesInTimeControl[2];
- i = nm + rs; /* Determine which clock is running. */
-
- if (cnum == kTabButton) { /* If tab was pressed... */
-
- if (!(i & 0x01)) { /* If tab should have been pressed... */
-
- for (nm = ++mDerefRoot(root)->numMoves[0];;) { /* for is for break control purposes. */
-
- if (!nm1) break;
- tc = mDerefRoot(root)->timeControl[1];
- if (!tc) break;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[0] += tc;
- break;
- }
-
- if (!nm2) break;
- tc = mDerefRoot(root)->timeControl[2];
- if (!tc) break;
- nm1 += nm2;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[0] += tc;
- break;
- }
-
- if (!nm3) break;
- for (;nm1 += nm3 ;) {
- if (nm < nm1) break;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[0] += tc;
- break;
- }
- }
-
- break;
- }
- }
-
- DrawClock(frHndl, 0);
- DrawClock(frHndl, 1);
- }
-
- if (cnum == kReturnButton) { /* If return was pressed... */
-
- if (i & 0x01) { /* If return should have been pressed... */
-
- for (nm = ++mDerefRoot(root)->numMoves[1];;) { /* for is for break control purposes. */
-
- if (!nm1) break;
- tc = mDerefRoot(root)->timeControl[1 + 3];
- if (!tc) break;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[1] += tc;
- break;
- }
-
- if (!nm2) break;
- tc = mDerefRoot(root)->timeControl[2 + 3];
- if (!tc) break;
- nm1 += nm2;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[1] += tc;
- break;
- }
-
- if (!nm3) break;
- for (;nm1 += nm3 ;) {
- if (nm < nm1) break;
- if (nm == nm1) {
- mDerefRoot(root)->timeRemaining[1] += tc;
- break;
- }
- }
-
- break;
- }
- }
-
- DrawClock(frHndl, 1);
- DrawClock(frHndl, 0);
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Draw application specific content (Called by DoDrawFrame).
- **
- ** If your application has any custom frame areas, or if it uses sidebars,
- ** this is the function that you would put the frame drawing code. The
- ** document scrollbars and grow icon drawing is handled by DTS.framework.
- ** Just do the sidebar and custom areas here. */
-
- #pragma segment TheDoc
- void DrawFrame(FileRecHndl frHndl, WindowPtr window, Boolean activate)
- {
- MoveTo(0, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, 16383);
-
- BeginFrame(window);
- DoDrawControls(window, activate);
- EndFrame(window);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Frees up any application-specific memory in the document. This is called by
- ** DoFreeDocument, which is called by DisposeDocument(). The application would
- ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
- **
- ** The document may have a bunch of handles off the main handle of the document.
- ** This is where they are freed. DisposeDocument calls this prior to releasing
- ** the ram for the main handle of the document, so release everything else
- ** here, or you will have a memory leak.
- **
- ** NOTE: Calling DefaultFreeDocument() frees up all memory used by a
- ** hierarchical document (see TreeObj package). */
-
- #pragma segment TheDoc
- OSErr FreeDocument(FileRecHndl frHndl)
- {
- return(DefaultFreeDocument(frHndl));
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Any additional window disposal tasks can be handled here. */
-
- #pragma segment TheDoc
- OSErr FreeWindow(FileRecHndl frHndl, WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- WindowPtr ww;
- FileRecHndl ff;
-
- if ((*frHndl)->fileState.sfType == kDocFileType) {
- for (ww = nil; (ww = GetNextWindow(ww, 0)) != nil;) {
- ff = (FileRecHndl)GetWRefCon(ww);
- if ((*ff)->fileState.sfType == kViewHierFileType) {
- if ((*frHndl)->d.doc.root == (*ff)->d.doc.root) {
- DisposeOneWindow(ww, kClose);
- ww = nil;
- }
- }
- }
- }
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Image the document into the current port.
- **
- ** The only thing tricky about this function is that it needs to key off of
- ** the global variable gPrintPage. gPrintPage is the current page that is
- ** being printed. If gPrintPage is 0, then you are drawing to the window.
- **
- ** For when printing:
- **
- ** If gPrintPage is non-0, that is the page to be printed. If after imaging
- ** the page there are no more pages, you should set gPrintPage to 0. This
- ** indicates to the print loop that the end of the document has been reached.
- ** Even if the user indicated in the job dialog to print more pages, setting
- ** gPrintPage to 0 states that the last page has been printed. This is necessary
- ** because the print loop can't know when printing is done. The imaging procedure
- ** is the logical one to state when everything has been imaged. */
-
- #pragma segment TheDoc
- OSErr ImageDocument(FileRecHndl frHndl)
- {
- WindowPtr window;
- RGBColor oldc, newc;
-
- window = (*frHndl)->fileState.window;
-
- if (gQDVersion) {
- GetBackColor(&oldc);
- newc.red = newc.green = newc.blue = 0xFFFF;
- RGBBackColor(&newc);
- }
-
- DrawClocks(frHndl);
- DoDrawControls(window, false);
- /* It's either a clock or a control, and we don't support printing, so that's it. */
-
- if (gQDVersion)
- RGBBackColor(&oldc);
-
- gPrintPage = 0;
- return(noErr);
- }
-
- void DrawClocks(FileRecHndl frHndl)
- {
- DrawClock(frHndl, 0);
- DrawClock(frHndl, 1);
- HiliteTabAndReturn(frHndl);
- }
-
- void DrawClock(FileRecHndl frHndl, short clock)
- {
- WindowPtr window;
- TreeObjHndl root;
- ControlHandle ctl;
- Rect rct;
- RgnHandle oldClip, newClip;
- LayerObj windowLayer;
- DrawClocksInfo dcInfo;
- short activeClock, rs, lr;
- RGBColor oldc, newc;
-
- window = (*frHndl)->fileState.window;
- root = (*frHndl)->d.doc.root;
-
- SetPort(window);
-
- CNum2Ctl(window, clock + kLeftClock, &ctl);
- rct = (*ctl)->contrlRect;
-
- NewLayer(&windowLayer, nil, nil, window, 0, 0);
- (*windowLayer)->dstRect = rct;
-
- if (!gWorkLayer) { /* If we don't have offscreen layers yet, make 'em. */
- NewLayer(&gWorkLayer, windowLayer, WorkLayerProc, nil, 8, 0);
- NewLayer(&gBackLayer[0], gWorkLayer, BackLayerProc, nil, 1, 0);
- NewLayer(&gBackLayer[1], gWorkLayer, BackLayerProc, nil, 1, 1);
- DetachLayer(gWorkLayer);
- DetachLayer(gBackLayer[0]);
- DetachLayer(gBackLayer[1]);
- } /* Note that on an AppsToGo editor restart, OpenApplication disposes of the
- ** global offscreen layers and resets them to nil. This means that this
- ** code will be executed when the program starts up initially, or whevever
- ** the AppsToGo editor issues a restart. */
-
- activeClock = 0;
- rs = mDerefRoot(root)->rightStart;
- if (rs > -1) {
- lr = mDerefRoot(root)->numMoves[0];
- lr += mDerefRoot(root)->numMoves[1];
- lr += rs;
- lr &= 0x01;
- if (clock == lr) ++activeClock;
- }
-
- InsertLayer(gWorkLayer, gBackLayer[activeClock], 0);
- InsertLayer(windowLayer, gWorkLayer, 0);
-
- InvalLayer(windowLayer, rct, false);
- dcInfo.drawTime = mDerefRoot(root)->timeRemaining[clock];
- dcInfo.numMoves = mDerefRoot(root)->numMoves[clock];
-
- dcInfo.numTimeControls = 1;
- if (mDerefRoot(root)->numMovesInTimeControl[1]) {
- if (mDerefRoot(root)->timeControl[1 + (3 * clock)]) {
- ++dcInfo.numTimeControls;
- if (mDerefRoot(root)->numMovesInTimeControl[2]) {
- if (mDerefRoot(root)->timeControl[2 + (3 * clock)]) {
- ++dcInfo.numTimeControls;
- }
- }
- }
- }
-
- dcInfo.timeControl = 1;
- dcInfo.numRemaining = mDerefRoot(root)->numMovesInTimeControl[0] - dcInfo.numMoves;
- if (dcInfo.numRemaining < 1) {
- ++dcInfo.timeControl;
- dcInfo.numRemaining += mDerefRoot(root)->numMovesInTimeControl[1];
- }
- if (dcInfo.numRemaining < 1) {
- ++dcInfo.timeControl;
- dcInfo.numRemaining += mDerefRoot(root)->numMovesInTimeControl[2];
- }
-
- (*gWorkLayer)->layerData = (long)&dcInfo;
- /* Now it knows... */
-
- OpenRgn();
- FrameOval(&rct);
- CloseRgn(newClip = NewRgn());
- GetClip(oldClip = NewRgn());
- SetClip(newClip);
-
- if (gQDVersion) {
- GetBackColor(&oldc);
- newc.red = newc.green = newc.blue = 0xFFFF;
- RGBBackColor(&newc);
- }
-
- UpdateLayer(windowLayer); /* Draw the clock. */
-
- if (gQDVersion)
- RGBBackColor(&oldc);
-
- SetClip(oldClip);
- DisposeRgn(oldClip);
- DisposeRgn(newClip);
-
- DisposeLayer(windowLayer);
- /* This orphans gWorkLayer and gBackLayer, which means that they will be around
- ** next time this is called, unless OpenApplication is called. */
- }
-
- static OSErr BackLayerProc(LayerObj theLayer, short message)
- {
- OSErr err;
- Rect rct, rr;
- Point cc, pp;
- short i, j, dh, dv, hh, vv;
- RgnHandle rgn;
-
- err = noErr;
-
- switch (message) {
- case kLayerInit:
- err = DefaultLayerProc(theLayer, message);
- if (!err) {
- SetLayerWorld(theLayer);
- rct = GetEffectiveDstRect(theLayer);
- cc.h = (rct.left + rct.right) / 2;
- cc.v = (rct.top + rct.bottom) / 2;
- rgn = NewRgn();
- for (i = 60; i >= 45; --i) {
- EraseRect(&rct);
- FrameArc(&rct, -6 * i, 1);
- if (gQDVersion)
- BitMapToRegion(rgn, (BitMapPtr)(*((CGrafPtr)(*theLayer)->layerPort)->portPixMap));
- else
- BitMapToRegion(rgn, &(*theLayer)->layerPort->portBits);
- j = i % 60;
- pp.h = (*rgn)->rgnBBox.left;
- pp.v = (*rgn)->rgnBBox.top;
- gArcLocs[j].h = pp.h;
- gArcLocs[j].v = pp.v;
- j = 90 - i;
- gArcLocs[j].h = pp.h;
- gArcLocs[j].v = rct.bottom - (pp.v - rct.top);
- j = 60 - j;
- gArcLocs[j].h = rct.left + (rct.right - pp.h);
- gArcLocs[j].v = rct.bottom - (pp.v - rct.top);
- j = 60 - i;
- gArcLocs[j].h = rct.left + (rct.right - pp.h);
- gArcLocs[j].v = pp.v;
- } /* The above looks awful, but it is relatively simple. Since the arc code
- ** doesn't use trig, if we used trig to compute where the points were, we
- ** may be a bit off. Therefore we will use the arc rendering code itself
- ** to determine where the minute marks are on the oval. To do this, we
- ** image a single degree, and then call BitMapToRegion to get a region that
- ** is the single pixel. The bounding box of this region will serve as the
- ** coordinate for the minute-mark. To save time, and to guarantee symmetry,
- ** we do only one quadrant, and reflect the coordinate into the other 4. */
-
- if ((*theLayer)->layerData) PenSize(2, 2);
- FrameOval(&rct);
- PenSize(1, 1);
- /* We haven't done a lone EraseRect for the offscreen yet. This is okay
- ** because we did one prior to the FrameArc in the above loop. Since the
- ** FrameArc code does a portion of an oval, the remaining pixel will be
- ** properly covered by this FrameOval. */
-
- for (i = 0; i < 60; ++i) {
- dh = cc.h - gArcLocs[i].h;
- dh *= 5;
- dh /= (cc.h - rct.left);
- dv = cc.v - gArcLocs[i].v;
- dv *= 5;
- dv /= (cc.v - rct.top);
- PenSize(2, 2);
- hh = gArcLocs[i].h + dh;
- vv = gArcLocs[i].v + dv;
- if (i % 5)
- SetRect(&rr, hh - 1, vv - 1, hh + 1, vv + 1);
- else
- SetRect(&rr, hh - 2, vv - 2, hh + 2, vv + 2);
- PaintOval(&rr);
- }
-
- DisposeRgn(rgn);
- ResetLayerWorld(theLayer);
- }
- break;
- default:
- err = DefaultLayerProc(theLayer, message);
- /* Default behavior for everything else. */
- break;
- }
-
- return(err);
- }
-
- static OSErr WorkLayerProc(LayerObj theLayer, short message)
- {
- WindowPtr window;
- ControlHandle ctl;
- Str63 pstr;
- OSErr err;
- Rect rct, r;
- short dx, dy;
- Point cc, pp, p;
- long t, h, m, s;
- RgnHandle rgn;
- DrawClocksInfo dcInfo;
-
- err = noErr;
-
- switch (message) {
-
- case kLayerInit:
- err = DefaultLayerProc(theLayer, message);
- break;
-
- case kLayerUpdate:
- DefaultLayerProc(theLayer, message);
-
- SetLayerWorld(theLayer);
-
- dcInfo = *(DrawClocksInfo *)((*theLayer)->layerData);
-
- rct = GetEffectiveDstRect(theLayer);
- cc.h = (rct.left + rct.right) / 2;
- cc.v = (rct.top + rct.bottom) / 2;
-
- t = dcInfo.drawTime;
- if ((t) && (t < 60)) t = 60; /* Only show 0 when completely out of time. */
- t = dcInfo.drawTime / 60;
- s = t % 60;
- t /= 60;
- m = t % 60;
- t /= 60;
- h = t;
-
- window = (*(*theLayer)->aboveLayer)->layerPort;
-
- CNum2Ctl(window, kDigitalDisplay, &ctl); /* Get the font/size/style set by */
- UseControlStyle(ctl); /* the AppsToGo editor. */
- TextFont(window->txFont); /* UseCotrolStyle gets it, but it puts */
- TextSize(window->txSize); /* it in the control's port. Therefore */
- TextFace(window->txFace); /* we still need to get it from there and */
- UseControlStyle(nil); /* put it into the offscreen. */
-
- pcpypaddec(pstr, '0', 2, 2, h); /* Format hh:mm:ss. */
- pcatchr(pstr, ':', 1);
- pcatpaddec(pstr, '0', 2, 2, m);
- pcatchr(pstr, ':', 1);
- pcatpaddec(pstr, '0', 2, 2, s);
- r = (*ctl)->contrlRect;
- MoveTo(r.left, r.bottom - 2);
- DrawString(pstr); /* Draw hh:mm:ss. */
-
- CNum2Ctl(window, kMoveDisplay, &ctl); /* The rest of the text uses a different font. */
- UseControlStyle(ctl);
- TextFont(window->txFont);
- TextSize(window->txSize);
- TextFace(window->txFace);
- UseControlStyle(nil);
-
- pcpy(pstr, (*ctl)->contrlTitle); /* Draw the number of moves text. */
- pcatdec(pstr, dcInfo.numMoves);
- r = (*ctl)->contrlRect;
- MoveTo(r.left, r.bottom - 2);
- DrawString(pstr);
-
- if ((dcInfo.numTimeControls > 1) && (dcInfo.numRemaining > 0)) {
- CNum2Ctl(window, kTimeControlDisplay, &ctl);
- pcpy(pstr, (*ctl)->contrlTitle);
- pcatdec(pstr, dcInfo.timeControl);
- r = (*ctl)->contrlRect;
- MoveTo(r.left, r.bottom - 2);
- DrawString(pstr);
- (*ctl)->contrlVis = 255;
- CNum2Ctl(window, kTimeControlDisplay + 50, &ctl);
- (*ctl)->contrlVis = 255;
-
- CNum2Ctl(window, kMovesToMakeDisplay, &ctl);
- pcpy(pstr, (*ctl)->contrlTitle);
- pcatdec(pstr, dcInfo.numRemaining);
- r = (*ctl)->contrlRect;
- MoveTo(r.left, r.bottom - 2);
- DrawString(pstr);
- (*ctl)->contrlVis = 255;
- CNum2Ctl(window, kMovesToMakeDisplay + 50, &ctl);
- (*ctl)->contrlVis = 255;
- }
- else {
- CNum2Ctl(window, kTimeControlDisplay, &ctl);
- (*ctl)->contrlVis = 0;
- CNum2Ctl(window, kTimeControlDisplay + 50, &ctl);
- (*ctl)->contrlVis = 0;
- CNum2Ctl(window, kMovesToMakeDisplay, &ctl);
- (*ctl)->contrlVis = 0;
- CNum2Ctl(window, kMovesToMakeDisplay + 50, &ctl);
- (*ctl)->contrlVis = 0;
- }
-
- rgn = NewRgn();
-
- h = t % 12;
-
- OpenRgn(); /* Draw second hand. */
- r = rct;
- InsetRect(&r, 8, 8);
- FrameOval(&r);
- CloseRgn(rgn);
- SetClip(rgn);
- MoveTo(gArcLocs[s].h, gArcLocs[s].v);
- LineTo(cc.h, cc.v);
-
- OpenRgn(); /* Draw minute hand. */
- r = rct;
- InsetRect(&r, 16, 16);
- FrameOval(&r);
- CloseRgn(rgn);
- SetClip(rgn);
- pp = gArcLocs[m];
- p = gArcLocs[(m + 1) % 60];
- dx = (p.h - pp.h) * s / 60;
- dy = (p.v - pp.v) * s / 60;
- pp.h += dx;
- pp.v += dy;
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h + 1, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h - 1, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v + 1);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v - 1);
-
- OpenRgn(); /* Draw hour hand. */
- r = rct;
- InsetRect(&r, 50, 50);
- FrameOval(&r);
- CloseRgn(rgn);
- SetClip(rgn);
-
- SetRect(&r, cc.h - 2, cc.v - 2, cc.h + 3, cc.v + 3);
- PaintOval(&r);
-
- h *= 5;
- h += m / 12;
- pp = gArcLocs[h];
- p = gArcLocs[(h + 1) % 60];
- dx = (p.h - pp.h) * m / 60;
- dy = (p.v - pp.v) * m / 60;
- pp.h += dx;
- pp.v += dy;
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h + 1, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h - 1, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v + 1);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v - 1);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h + 2, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h - 2, cc.v);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v + 2);
- MoveTo(pp.h, pp.v);
- LineTo(cc.h, cc.v - 2);
-
- ClipRect(&rct);
- DisposeRgn(rgn);
-
- ResetLayerWorld(theLayer);
- break;
-
- default:
- err = DefaultLayerProc(theLayer, message);
- /* Default behavior for everything else. */
- break;
- }
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function does the remaining window initialization.
- **
- ** There may be additional content initialization for the window. At this point,
- ** you have a window, but it is currently invisible. If you return noErr, then
- ** the window will be set to the state indicated for that window. Why this function?
- ** You may wish to add controls to the content of the window. You may have a
- ** TextEdit record in the content. All of these sort of things can't be created
- ** until there is a window to contain them. First a document is read in, and then
- ** if the document creation succeeds, a window is created for that document.
- ** At this point we have a document, and we are on our way to having a window.
- ** All that remains is any additional content initialization. Do it, return
- ** noErr, and everybody's happy. If something goes wrong here, return the error,
- ** and the incomplete window will be disposed of. */
-
- #pragma segment TheDoc
- OSErr InitContent(FileRecHndl frHndl, WindowPtr window)
- {
- OSErr err;
- ControlHandle ctl;
- short i, lr;
- Str15 pstr;
- long t, h, m;
- TreeObjHndl root;
-
- InitButtonsCtl(4960);
- gGetButtonVariant = MyGetButtonVariant;
-
- CNum2Ctl(window, kLeftClock, &ctl);
- /* Check to see if the controls have already been added. This allows us to
- ** call this after the window has been created. */
-
- if (!ctl) { /* If first time here... */
- err = AddControlSet(window, (*frHndl)->fileState.sfType, kwStandardVis, 0, 0, nil);
- if (err) return(err);
- HiliteTabAndReturn(frHndl);
- }
-
- root = (*frHndl)->d.doc.root;
-
- lr = MyGetRadioButtonChoice(window, 0);
- if (lr == 2) lr = 0;
- lr *= 3;
-
- for (i = 0; i < 3; ++i) {
-
- CNum2Ctl(window, kTC1HUpArrow + i * (kTC2HUpArrow - kTC1HUpArrow), &ctl);
- SetTrackControlProc(ctl, TrackArrowProc); /* Set the hour up arrow controls to track. */
-
- CNum2Ctl(window, kTC1HDnArrow + i * (kTC2HDnArrow - kTC1HDnArrow), &ctl);
- SetTrackControlProc(ctl, TrackArrowProc); /* Set the hour down arrow controls to track. */
-
- t = mDerefRoot(root)->timeControl[lr + i];
- h = t / (60L * 60 * 60);
- m = t - (60L * 60 * 60) * h;
- m /= (60 * 60);
-
- CNum2Ctl(window, kTimeControl1Hours + i * (kTimeControl2Hours - kTimeControl1Hours), &ctl);
- CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly);
- /* Filter out non-digits for the hours fields. */
-
- UseControlStyle(ctl);
- pcpypaddec(pstr, '0', 2, 2, h);
- CTEPutPStr(ctl, pstr);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(ctl));
- /* Fill in the field with the hours value. */
-
- CNum2Ctl(window, kTC1MUpArrow + i * (kTC2MUpArrow - kTC1MUpArrow), &ctl);
- SetTrackControlProc(ctl, TrackArrowProc); /* Set the minute down arrow controls to track. */
-
- CNum2Ctl(window, kTC1MDnArrow + i * (kTC2MDnArrow - kTC1MDnArrow), &ctl);
- SetTrackControlProc(ctl, TrackArrowProc); /* Set the minute down arrow controls to track. */
-
- CNum2Ctl(window, kTimeControl1Minutes + i * (kTimeControl2Minutes - kTimeControl1Minutes), &ctl);
- CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly);
- /* Filter out non-digits for the minutes fields. */
-
- pcpypaddec(pstr, '0', 2, 2, m);
- CTEPutPStr(ctl, pstr);
- CTESetSelect(0, 2, (TEHandle)GetControlReference(ctl));
- /* Fill in the field with the minutes value. */
-
- CNum2Ctl(window, kLeftClockRadio + i, &ctl);
- SetTrackControlProc(ctl, TrackRadioProc);
- /* Track the radio buttons (for pre-switch fetch of values). */
- }
-
- for (i = 0; i < 3; ++i) { /* Fill the numMoves fields. */
- CNum2Ctl(window, kTC1NumMoves + i * (kTC2NumMoves - kTC1NumMoves), &ctl);
- CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly); /* Just digits again. */
- m = mDerefRoot(root)->numMovesInTimeControl[i];
- if (m) {
- pcpydec(pstr, m);
- CTEPutPStr(ctl, pstr);
- CTESetSelect(0, 3, (TEHandle)GetControlReference(ctl));
- }
- }
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* The code below assumes that you are using the hierarchical document package.
- ** If you are, the entire hierarchical document is read in with just these two
- ** calls. If you don't use it, you are on your own. See DTS.StyleChat for an
- ** example of an application that uses the DTS.framework without the hierarchical
- ** document package. */
-
- #pragma segment TheDoc
- OSErr ReadDocument(FileRecHndl frHndl)
- {
- OSErr err;
-
- err = DefaultReadDocument(frHndl);
- if (!err)
- DefaultReadDocumentFixup(frHndl);
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Resize application specific content (Called by ResizeWindow).
- **
- ** This gets called when a user does a zoom or window resizing operation.
- ** It is possible that things in the content need to be resized in conjunction
- ** with the resizing of the window. */
-
- #pragma segment TheDoc
- void ResizeContent(WindowPtr window, short oldh, short oldv)
- {
- #ifndef __MWERKS__
- #pragma unused (window, oldh, oldv)
- #endif
-
- /* See DTS.StyleChat for a sample usage of this function. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Scroll application specific frame (Called by DoScrollFrame).
- **
- ** Some applications may need to scroll the "frame" of the document along
- ** with the document contents. This is common for applications with rulers,
- ** or other similar sidebar items. */
-
- #pragma segment TheDoc
- void ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, dh, dv)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Since the hierarchical document package isn't used by DTS.StyleChat,
- ** this function actually never gets called. */
-
- #pragma segment TheDoc
- void UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, contOrg, afterUndo)
- #endif
-
- /* See DTS.Draw for an example of what you might do here. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function is where you adjust the cursor to reflect the location in the
- ** document or window. You have the additional input of gCursorRgn to deal
- ** with. The way that the cursor handling works is as follows:
- ** 1) The application calls DoWindowCursor().
- ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
- ** It looks at the document's windowCursorProc and checks to see if the document
- ** has one. If the document doesn't have one, then it assumes that that window
- ** always wants an arrow. If the cursor is over that window, the cursor is set
- ** to an arrow, and we're done. If the cursor isn't over the window, then the next
- ** window is tried. If all documents don't have a windowCursorProc, then the cursor
- ** is set to an arrow (for the non-document area of the screen).
- ** 3) If a document has a windowCursorProc, then the proc is called. The proc's
- ** job is as follows:
- ** a) If the cursor is over a position that is determined by the window, then
- ** the proc removes other areas from gCursorRgn. Note that it should not
- ** simply set the area to what it "thinks" is the correct area. This window
- ** may not be the front-most. Other windows will have already been subtracted
- ** from gCursorRgn. The resultant gCursorRgn is the correct cursor area,
- ** and should be passed to WaitNextEvent calls in the application (already the case
- ** in EventLoop.c). Also, the cursor should be set to the correct cursor, of course.
- ** You should also return true, as the cursor has been determined.
- ** b) If the cursor is not over a position for this window, then you should
- ** return. You will either pass back true or false. If you don't wish
- ** windows behind this window to have a shot at cursor determination, then
- ** return true. This states that the cursor is "determined". It is, in the
- ** sense that no further determination will occur. If you return false, then
- ** other windows get a shot at determining the cursor.
- **
- ** Setting the cursor to the correct cursor isn't as easy as you would expect.
- ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor. This is
- ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
- ** more of a problem. What you will need to do is to call DoSetResCursor() to make the
- ** resource cursor pointer-based. DoSetResCursor() will set gCursorPtr to nil, and it
- ** also returns the pointer to the permanent copy of the cursor resource. Just set gCursorPtr
- ** to the return result of DoSetResCursor(), and you will be set. */
-
- #pragma segment TheDoc
- Boolean WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
- {
- WindowPtr oldPort;
- RgnHandle contRgn;
- Rect rr, teViewRct, contRct;
- TEHandle teHndl;
- ControlHandle viewCtl;
- Point contOrg;
-
- if (!window) {
- SetCursor(gCursorPtr = &qd.arrow);
- return(true);
- }
-
- oldPort = SetFilePort(frHndl);
- window = (*frHndl)->fileState.window;
-
- GetContentOrigin(window, &contOrg);
- SetOrigin(contOrg.h, contOrg.v); /* Scroll position of window. */
-
- GetContentRect(window, &contRct);
- /* This returns the content portion of the window in local coordinates,
- ** less document scrollbar and sidebar areas. */
-
- contRgn = NewRgn();
- for (viewCtl = nil; ((viewCtl = CTENext(window, &teHndl, viewCtl, 1, false)) != nil);) {
- teViewRct = (*teHndl)->viewRect;
- SectRect(&teViewRct, &contRct, &rr);
- LocalToGlobalRect(&rr);
- if ((*viewCtl)->contrlVis) {
- if (!CTEReadOnly(teHndl)) {
- RectRgn(contRgn, &rr);
- if (PtInRect(globalPt, &rr)) {
- gCursorPtr = DoSetResCursor(iBeamCursorSmall);
- SectRgn(gCursorRgn, contRgn, gCursorRgn);
- DisposeRgn(contRgn);
- SetPort(oldPort);
- return(true);
- }
- DiffRgn(gCursorRgn, contRgn, gCursorRgn);
- }
- }
- }
- SetCursor(gCursorPtr = &qd.arrow);
- DisposeRgn(contRgn);
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* After the DTS.Lib framework disposes of a window, it calls here. This is
- ** to give the application a chance to do any additional tasks related to
- ** a window closing. DTS.StyleChat doesn't have anything else extra to do. */
-
- #pragma segment TheDoc
- void WindowGoneFixup(WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* The reverse function of ReadDocument. */
-
- #pragma segment TheDoc
- OSErr WriteDocument(FileRecHndl frHndl)
- {
- FetchClockValues(frHndl, 0);
- /* Have to make sure that the latest info in the controls will be written out. */
-
- return(DefaultWriteDocument(frHndl));
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does at open-application time. •• */
-
- #pragma segment TheDoc
- OSErr DoOpenApplication(void)
- {
- DisposeLayer(gWorkLayer); /* May be restarted with new clock sizes. */
- DisposeLayer(gBackLayer[0]);
- DisposeLayer(gBackLayer[1]);
- gWorkLayer = nil;
- gBackLayer[0] = nil;
- gBackLayer[1] = nil;
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean AdjustMenuItems(WindowPtr window, short menuID)
- {
- Boolean redrawMenuBar;
- MenuHandle menu;
-
- redrawMenuBar = false;
-
- switch (menuID) {
- case mFile:
- redrawMenuBar = DoAdjustFileMenu(window);
- break;
- case mEdit:
- redrawMenuBar = DoAdjustEditMenu(window);
- break;
- default:
- menu = GetMenuHandle(menuID);
- if (menu)
- (*menu)->enableFlags |= 0xFFFFFFFEL;
- break;
- }
-
- return(redrawMenuBar);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean DoMenuItem(WindowPtr window, short menuID, short menuItem)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- return(DoMenuCommand(menuID, menuItem));
- }
-
-
-
- /*****************************************************************************/
-
-
-
- static short MyGetRadioButtonChoice(WindowPtr window, short famNum)
- {
- ControlHandle nextCtl;
- short firstInFam, cnum, chosen;
-
- nextCtl = ((WindowPeek)window)->controlList;
- for (firstInFam = chosen = 0;;) {
- if (!nextCtl) {
- if (!chosen) return(-1);
- /* If a proper radio button family was passed in, this can't
- ** happen. The -1 is an error that indicates that the
- ** requested family didn't exist, or that there was no selected
- ** radio of the requested family. */
- return(chosen - firstInFam);
- }
- if (IsButtonsCtl(nextCtl)) {
- if (GetControlReference(nextCtl) == famNum) {
- cnum = Ctl2CNum(nextCtl);
- if (!firstInFam)
- firstInFam = cnum;
- else {
- if (firstInFam > cnum)
- firstInFam = cnum;
- }
- if (GetControlValue(nextCtl)) chosen = cnum;
- }
- }
- nextCtl = (*nextCtl)->nextControl;
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- short MyGetButtonVariant(ControlHandle ctl, Boolean *stop)
- {
- if (ctl)
- if (IsButtonsCtl(ctl))
- return(2);
-
- return(-1);
- }
-
-
-
- pascal long xxx(short varCode, ControlHandle ctl, short msg, long parm);
- pascal long xxx(short varCode, ControlHandle ctl, short msg, long parm)
- {
- long retVal;
- Rect rct;
-
-
- retVal = 0;
-
- rct = (*ctl)->contrlRect;
- switch (msg) {
- case drawCntl:
- FrameRect(&rct);
- break;
-
- case calcCRgns:
- case calcCntlRgn:
- case calcThumbRgn:
- if (msg == calcCRgns) parm &= 0x00FFFFFF;
- RectRgn((RgnHandle)parm, &rct);
- if (msg != calcCRgns) retVal = 1;
- break;
- }
-
- return(retVal);
- }
-
-
-
-