home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** File: TRectObj.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1992-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. */
-
- /* See the files "=How to write your app" and "=Using TreeObj.c" for information
- ** on this function. */
-
- /* This file implements the messages for the rect object. */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "App.h" /* Get the application includes/typedefs, etc. */
- #include "App.protos.h" /* Get the prototypes for the application. */
-
- #ifndef __OSEVENTS__
- #include <OSEvents.h>
- #endif
-
- #ifndef __OSUTILS__
- #include <OSUtils.h>
- #endif
-
- #ifndef __QUICKDRAW__
- #include <Quickdraw.h>
- #endif
-
- #ifndef __STRING__
- #include <String.h>
- #endif
-
- #ifndef __TREEOBJ2__
- #include "TreeObj2.h"
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- /**********************************************************************/
-
-
-
- RGBColor gBorderColor = {0, 0, 0};
- RGBColor gContentColor = {0xFFFF, 0xFFFF, 0xFFFF};
- short gPenHeight = 1;
- short gPenWidth = 1;
-
-
-
- /**********************************************************************/
-
-
-
- #pragma segment DrawObjects
- long TRectObj(TreeObjHndl hndl, short message, long data)
- {
- TreeObjHndl root, shndl;
- Rect rct, oldRct, *rptr, grabber;
- short hit, fileRefNum, dx1, dx2, dy1, dy2, h, v, ptype;
- short fv, fh, flip, noDraw, w;
- Point where, begMouse, curMouse, offset;
- Boolean selected;
- EventRecord option;
- ClickInfo *click;
- RgnHandle rgn, accumRgn;
- OSErr err;
- RGBColor rgb, rgb2;
- #if VH_VERSION
- char *cptr;
- #endif
-
- switch (message) {
- case INITMESSAGE:
- /* This is called either with a sub-message of CREATEINIT or WINDOWINIT.
- ** The sub-message CREATEINIT is sent in when the object is initially created.
- ** The sub-message WINDOWINIT is sent in when the object belongs to a document
- ** that was just assigned to a window. Note that the object could be created
- ** into a document that already has a window. In this case, only the
- ** CREATEINIT sub-message will be received. It is the object's responsibility
- ** to determine if the document has a window when CREATEINIT is called.
- ** An additional possible sub-message is NOWINDOWINIT. In this case, the
- ** document is being disconnected from a window, and therefore objects have
- ** to convert back to their non-window state. Both the WINDOWINIT and
- ** NOWINDOWINIT sub-messages would be application-specific, and sending
- ** the sub-messages to the objects would be the application's responsibility. */
- mDerefCommon(hndl)->penHeight = gPenHeight;
- mDerefCommon(hndl)->penWidth = gPenWidth;
- mDerefCommon(hndl)->borderColor = gBorderColor;
- mDerefCommon(hndl)->content = true;
- mDerefCommon(hndl)->contentColor = gContentColor;
- break;
-
- case FREEMESSAGE:
- if (mDerefCommon(hndl)->selected) {
- root = GetRootHndl(hndl);
- if ((*root)->type == ROOTOBJ)
- mDerefRoot(root)->numSelected--;
- /* Here the root object can be either the document root
- ** or the undo root. The FREEOBJMESSAGE is due to the
- ** object being disposed of. It may be being disposed of
- ** from either the document or undo side. If it is being
- ** disposed of out of the undo side, we don't care about
- ** the selection status. If it is being disposed of out
- ** of the document side, then we do care, as we will have
- ** one less selected object. The numSelected count needs
- ** to reflect this. */
- }
- break;
-
- case COPYMESSAGE:
- /* CopyOneChild was called (indirectly) and an object has been
- ** cloned. At this point the data area has already been copied.
- ** If the data area holds references to other handles, these
- ** handles need to be copied so that the object has its own copies.
- ** Since the data was copied from the original child, the fields
- ** holding references to handles actually contain the same reference
- ** that the original child contains. To create unique handles for
- ** the copy, this object should pass itself an INITOBJMESSAGE to
- ** initially create unique handles for the copy.
- ** The data parameter for this message is the handle of the object
- ** that was copied. It is possible that the copy won't be an exact
- ** copy, and that there should be some differences between the
- ** original and the copy. By having a reference to the original,
- ** these situations can be resolved. */
- break;
-
- case UNDOMESSAGE:
- root = GetRootHndl(hndl);
- if ((*root)->type == ROOTOBJ) {
- ptype = (*((*hndl)->parent))->type;
- switch (data) {
- case UNDOFROMDOC:
- if (mDerefCommon(hndl)->selected == true) {
- mDerefCommon(hndl)->selected = false;
- mDerefRoot(root)->numSelected--;
- } /* If a selected object is moving from the document into the */
- break; /* undo, reflect this in the numSelected count in the root. */
-
- case UNDOTODOC:
- mDerefCommon(hndl)->selected = false;
- if (ptype != GROUPOBJ) {
- mDerefCommon(hndl)->selected = true;
- mDerefRoot(root)->numSelected++;
- } /* An object moving into the document needs to be selected
- ** so the user can see what changed. The select status while
- ** in the undo doesn't matter, as the user can't see what is in
- ** the undo. */
- break;
- }
- }
- break;
-
- case CONVERTMESSAGE:
- /* This is called to convert any data that loses meaning when saved.
- ** It is called with a TOFILE or a FROMFILE sub-message.
- **
- ** For the CONVERTTOID sub-message:
- **
- ** If this object has any references to handles elsewhere in the document,
- ** these references lose meaning when saved to disk. When the file is
- ** read in, the handle references will not coorelate to what is currently
- ** in ram.
- ** Prior to starting a file save, all of the objects in the tree are
- ** assigned sequential id numbers. You can replace handle references
- ** with the 4-byte treeID. To convert the handle to a treeID, just
- ** do something like the following:
- ** Hndl2ID(&DerefMyObject(hndl)->thingToConvert);
- **
- ** For the CONVERTTOHNDL sub-message:
- **
- ** Once the file is opened and completely loaded into ram, there may be
- ** objects that have references to elsewhere in the file that were stored
- ** as treeID's. These need to be converted back to handle references.
- ** To do this, do something like the below:
- ** ID2Hndl(hndl, &DerefMyObject(hndl)->thingToConvert);
- */
- break;
-
- case FREADMESSAGE:
- fileRefNum = data;
- err = ReadTreeObjData(hndl, fileRefNum);
- if (!err)
- mDerefCommon(hndl)->selected = false;
- return(err);
- break;
-
- case FWRITEMESSAGE:
- fileRefNum = data;
- return(WriteTreeObjData(hndl, fileRefNum));
- break;
-
- case HREADMESSAGE:
- err = HReadTreeObjData(hndl, (Handle)data);
- if (!err)
- mDerefCtl(hndl)->selected = false;
- return(err);
- break;
-
- case HWRITEMESSAGE:
- return(HWriteTreeObjData(hndl, (Handle)data));
- break;
-
- case HITTESTMESSAGE:
- click = (ClickInfo *)data;
- where = click->localEvent.where;
- hit = 0;
- switch (click->message) {
- case HITTESTOBJ:
- DoTreeObjMethod(hndl, GETBBOXMESSAGE, (long)&rct);
- if (PtInRect(where, &rct)) {
- rgn = (RgnHandle)DoTreeObjMethod(hndl, GETRGNMESSAGE, 0);
- if (PtInRgn(where, rgn))
- hit = -1;
- DisposeRgn(rgn);
- }
- break;
- case HITTESTGRABBER:
- rct = mDerefCommon(hndl)->rect;
- if (mDerefCommon(hndl)->selected) {
- grabber = rct;
- InsetRect(&grabber, -4, -4);
- if (PtInRect(where, &grabber)) {
- GetMouse(&curMouse);
- for (;;) {
- if (where.v < (rct.top + 4)) {
- if (where.h < (rct.left + 4) ) {
- hit = 1;
- flip = (VFLIPOBJ | HFLIPOBJ);
- where.h = rct.right;
- where.v = rct.bottom;
- offset.h = rct.left - curMouse.h;
- offset.v = rct.top - curMouse.v;
- break;
- }
- if (where.h >= (rct.right - 4)) {
- hit = 2;
- flip = VFLIPOBJ;
- where.h = rct.left;
- where.v = rct.bottom;
- offset.h = rct.right - curMouse.h;
- offset.v = rct.top - curMouse.v;
- break;
- }
- }
- if (where.v >= (rct.bottom - 4)) {
- if (where.h < (rct.left + 4) ) {
- hit = 3;
- flip = HFLIPOBJ;
- where.h = rct.right;
- where.v = rct.top;
- offset.h = rct.left - curMouse.h;
- offset.v = rct.bottom - curMouse.v;
- break;
- }
- if (where.h >= (rct.right - 4)) {
- hit = 4;
- flip = 0;
- where.h = rct.left;
- where.v = rct.top;
- offset.h = rct.right - curMouse.h;
- offset.v = rct.bottom - curMouse.v;
- break;
- }
- }
- break;
- }
- }
- }
- break;
- case CANBETARGET:
- return(false);
- break;
- case CANTAKEKEYS:
- return(false);
- break;
- }
- if (hit) {
- for (; (*(root = (*hndl)->parent))->type != ROOTOBJ; hndl = root) {};
- /* Group objects can not be hit directly. Only the base
- ** objects can be hit. However, if a base object is hit,
- ** we want to return the top-most group object that
- ** contains it. Walk the tree up until the root object
- ** is hit. The object below this is top-most group object,
- ** or the base object doesn't belong to a group. */
- if (click->message == HITTESTGRABBER) {
- if (mDerefRoot(root)->numSelected == 1) {
- click->localEvent.where = where;
- click->offset = offset;
- click->oldFlip = click->newFlip = flip;
- }
- else hit = 0;
- }
- }
- if (!hit)
- hndl = nil;
- click->grabber = hit;
- return((long)hndl);
- break;
-
- case GETRGNMESSAGE:
- rgn = NewRgn();
- accumRgn = (RgnHandle)data;
- if (accumRgn)
- if (GetHandleSize((Handle)accumRgn) > 10000)
- return((long)rgn);
- rct = mDerefCommon(hndl)->rect;
- RectRgn(rgn, &rct);
- if (accumRgn)
- UnionRgn(rgn, accumRgn, accumRgn);
- return((long)rgn);
- break;
-
- case GETOBJRECTMESSAGE:
- case GETBBOXMESSAGE:
- rptr = (Rect *)data;
- *rptr = mDerefCommon(hndl)->rect;
- break;
-
- case SETOBJRECTMESSAGE:
- rptr = (Rect *)data;
- mDerefCommon(hndl)->rect = *rptr;
- break;
-
- case SECTOBJRECTMESSAGE:
- rptr = (Rect *)data;
- SectRect(rptr, &(mDerefCommon(hndl)->rect), &rct);
- if (!EmptyRect(&rct)) return(true);
- break;
-
- case DRAWMESSAGE:
- rct = mDerefCommon(hndl)->rect;
- h = mDerefCommon(hndl)->penHeight;
- w = mDerefCommon(hndl)->penWidth;
- PenSize(w, h);
- switch (data) {
- case DRAWOBJ:
- if (gQDVersion)
- GetForeColor(&rgb);
- ForeColor(whiteColor);
- if (gQDVersion) {
- rgb2 = mDerefRect(hndl)->contentColor;
- RGBForeColor(&rgb2);
- }
- PaintRect(&rct);
- ForeColor(blackColor);
- if (gQDVersion) {
- rgb2 = mDerefRect(hndl)->borderColor;
- RGBForeColor(&rgb2);
- }
- FrameRect(&rct);
- if (gQDVersion)
- RGBForeColor(&rgb);
- break;
- case ERASEOBJ:
- EraseRect(&rct);
- break;
- case DRAWSELECT:
- if (mDerefCommon(hndl)->selected) {
- for (h = v = 1; (h > -1); h -= (v ^= 1)) {
- grabber.top = v ? rct.top : rct.bottom;
- grabber.left = h ? rct.left : rct.right;
- grabber.bottom = (grabber.top -= 3) + 6;
- grabber.right = (grabber.left -= 3) + 6;
- InvertRect(&grabber);
- }
- }
- break;
- case DRAWGHOST:
- PenMode(patXor);
- FrameRect(&rct);
- break;
- case DRAWMASK:
- FillRect(&rct, (ConstPatternParam)&qd.black);
- break;
- }
- PenNormal();
- break;
-
- case PRINTMESSAGE:
- DoTreeObjMethod(hndl, DRAWMESSAGE, DRAWOBJ);
- break;
-
- #if VH_VERSION
- case VHMESSAGE:
- cptr = ((VHFormatDataPtr)data)->data;
- ccatchr(cptr, 13, 2);
- ccat (cptr, "$10: TRectObj:");
- ccatchr(cptr, 13, 1);
- ccat (cptr, " $00: selected = ");
- ccatdec(cptr, mDerefRect(hndl)->selected);
- ccatchr(cptr, 13, 1);
-
- rct = mDerefRect(hndl)->rect;
- ccat (cptr, " $02: rect = ($");
- ccatpadhex(cptr, 0, 4, 4, rct.top);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, rct.left);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, rct.bottom);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, rct.right);
- ccat (cptr, ")");
- ccatchr (cptr, 13, 1);
- ccat (cptr, " $0A: penHeight = ");
- ccatdec (cptr, mDerefRect(hndl)->penHeight);
- ccatchr (cptr, 13, 1);
- ccat (cptr, " $0C: penWidth = ");
- ccatdec (cptr, mDerefRect(hndl)->penWidth);
- ccatchr (cptr, 13, 1);
- ccat (cptr, " $0E: borderColor = ($");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->borderColor.red);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->borderColor.green);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->borderColor.blue);
- ccat (cptr, ")");
- ccatchr (cptr, 13, 1);
- ccat (cptr, " $1$: content = ($");
- ccatdec (cptr, mDerefRect(hndl)->content);
- ccatchr (cptr, 13, 1);
- ccat (cptr, " $16: contentColor = ($");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->contentColor.red);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->contentColor.green);
- ccat (cptr, ",$");
- ccatpadhex(cptr, 0, 4, 4, mDerefRect(hndl)->contentColor.blue);
- ccat (cptr, ")");
- return(true);
- break;
- #endif
-
- case COMPAREMESSAGE:
- return(DefaultEqualTreeObjData(hndl, (TreeObjHndl)data));
- break;
-
- /* End of standard messages. Start of object-specific messages. */
-
- case CLICKMESSAGE:
- click = (ClickInfo *)data;
- switch (click->message) {
- case CLICKSELECT:
- for (shndl = hndl; (*(root = (*shndl)->parent))->type != ROOTOBJ; shndl = root) {};
- selected = mDerefCommon(shndl)->selected;
- if ((!selected) || (click->localEvent.modifiers & shiftKey)) {
- if (shndl == hndl)
- DoTreeObjMethod(hndl, SETSELECTMESSAGE, SELECTTOGGLE);
- /* If the object doesn't belong to a group, then we want to change
- ** the select status. If it belongs to a group, the group object
- ** is responsible for maintaining the select status. */
- }
- break;
- case CLICKDRAG:
- OffsetRect(&(mDerefCommon(hndl)->rect), click->offset.h, click->offset.v);
- break;
- }
- break;
-
- case KEYMESSAGE:
- break;
-
- case SETSELECTMESSAGE:
- noDraw = (data & SELECTNODRAW);
- data ^= noDraw;
-
- selected = mDerefCommon(hndl)->selected;
- if (selected != data) { /* The select status is other than desired. */
- if (!noDraw) {
- mDerefCommon(hndl)->selected = true;
- DoTreeObjMethod(hndl, DRAWMESSAGE, DRAWSELECT);
- /* Force a draw-toggle of the selection grabbers. */
- }
- mDerefCommon(hndl)->selected = (selected ^= true);
- root = GetRootHndl(hndl);
- if (selected)
- mDerefRoot(root)->numSelected++;
- else
- mDerefRoot(root)->numSelected--;
- /* Change the global numSelected value to reflect the new
- ** number of selected objects. */
- }
- break;
-
- case GETSELECTMESSAGE:
- return(mDerefCommon(hndl)->selected);
- break;
-
- case SIZEMESSAGE:
- DoTreeObjMethod(hndl, GETOBJRECTMESSAGE, (long)&oldRct);
- click = (ClickInfo *)data;
- begMouse = click->localEvent.where;
- GetMouse(&curMouse);
- curMouse.h += click->offset.h;
- curMouse.v += click->offset.v;
- dx1 = dx2 = (curMouse.h - begMouse.h);
- dy1 = dy2 = (curMouse.v - begMouse.v);
- if (dx2 < 0)
- dx2 = -dx2;
- if (dy2 < 0)
- dy2 = -dy2;
- OSEventAvail(nullEvent, &option);
- if ((*hndl)->type == EXTSELECTOBJ) option.modifiers = 0;
- if (option.modifiers & shiftKey) {
- if (dx2 > dy2)
- dx2 = dy2;
- else
- dy2 = dx2;
- }
- if (dx1 < 0)
- dx2 = -dx2;
- if (dy1 < 0)
- dy2 = -dy2;
- curMouse.h = begMouse.h + dx2;
- curMouse.v = begMouse.v + dy2;
- fv = (curMouse.v < begMouse.v) ? VFLIPOBJ : 0x00;
- fh = (curMouse.h < begMouse.h) ? HFLIPOBJ : 0x00;
- rct.top = (fv) ? curMouse.v : begMouse.v;
- rct.bottom = (fv) ? begMouse.v : curMouse.v;
- rct.left = (fh) ? curMouse.h : begMouse.h;
- rct.right = (fh) ? begMouse.h : curMouse.h;
- mDerefCommon(hndl)->rect = rct;
- click->oldFlip = click->newFlip;
- click->newFlip = (fv | fh);
- return(!EqualRect(&rct, &oldRct));
- break;
-
- }
-
- return(noErr);
- }
-
-
-
-