Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Windows.c
/*------------------------------------------------------------------------------ |
* |
* Apple Developer Technical Support |
* |
* |
* |
* Program: AEObject-Edition Sample |
* File: Windows.c -C Source |
* |
* by: C.K. Haun <TR> |
* |
* Copyright © 1990-1992 Apple Computer, Inc. |
* All rights reserved. |
* |
*------------------------------------------------------------------------------ |
* This file contains some of our window handling routines. |
* It also contains the clipboard handlers |
*----------------------------------------------------------------------------*/ |
#define __MYWINDOWS__ |
#include "Sampdefines.h" |
#pragma segment MyWindows |
static void DragPictOrObject(Point *where, windowCHandle tempWC); |
/* AddNewWindow creates and initializes a new document window. */ |
/* It returns false in this example if there are already 10 windows open. */ |
WindowPtr AddNewWindow(Boolean showIt) |
{ |
windowCHandle setControls; |
WindowPtr tempWP; |
Handle tempHand; |
short cnt = 0; |
Str31 wtitle; |
tempWP = GetNewWindow(kDocWindow, 0, (WindowPtr)-1); /* get a new window */ |
((WindowPeek)tempWP)->windowKind = kDocumentWindow; /* mark it as a document window */ |
tempHand = NewHandleClear(sizeof(windowControl)); /* add our control structure to it */ |
((WindowPeek)tempWP)->refCon = tempHand; /* and attach the controller to the window */ |
setControls = (windowCHandle)((WindowPeek)tempWP)->refCon; /* and put it where we can use it */ |
HLock((Handle)setControls); /* lock it down while we fill it*/ |
/* add pointers to our procedures for drawing, saving, and closing */ |
/* This way, all I need is one dispatch point for drawing, closing */ |
/* or whatever, I don't have to case off the window kind to go to the */ |
/* correct routine. Kinda like object-oriented programming, but I won't */ |
/* admit that. */ |
(*setControls)->drawMe = (ProcPtr)DrawFull; |
(*setControls)->saveMe = (ProcPtr)SaveMe; |
(*setControls)->closeMe = (ProcPtr)CloseMyWindow; |
(*setControls)->clickMe = (ProcPtr)DoDocumentClick; |
(*setControls)->sizeMe = (ProcPtr)NilProc; |
/* now initialize all our required handles */ |
(*setControls)->pubs = NewHandle(0); |
(*setControls)->pubRects = NewHandle(0); |
(*setControls)->numPubs = 0; |
(*setControls)->subs = NewHandle(0); |
(*setControls)->subRects = NewHandle(0); |
(*setControls)->subDataHandle = NewHandle(0); |
(*setControls)->numSubs = 0; |
(*setControls)->pictHandle = NewHandle(0); |
(*setControls)->pictRects = NewHandle(0); |
(*setControls)->numPicts = 0; |
/* init shapes */ |
(*setControls)->theShapes = nil; |
(*setControls)->numShapes = 0; |
/* initialize our control codes and counts */ |
(*setControls)->currentAction = 0; |
(*setControls)->undoAction = 0; |
(*setControls)->hasSelection = false; |
(*setControls)->windowDirty = false; |
/* I am using this window ID to identify the sections (publishers and subscribers) */ |
/* that are associated with this window */ |
(*setControls)->windowID = gMasterWindowID; |
gMasterWindowID += 10000; /* update for next window */ |
/* clear the file spec for the file this document will be saved to */ |
/* since the handle is nil, I know this window hasn't been saved yet. */ |
(*setControls)->fileAliasHandle = (AliasHandle)NewHandle(0); |
(*setControls)->boxHandle = nil; /* no textedit field */ |
(*setControls)->textSections = nil; |
/* if there already is a window (or more) add a count to this title */ |
if (showIt) { |
short docWCount = 0; |
WindowPtr ourWindows = (WindowPtr)LMGetWindowList(); /* grab the first window from the global WindowList */ |
Str32 numOfW; |
GetWTitle(tempWP, wtitle); /* get our current title (untitled) */ |
while (ourWindows) { /* count 'em up */ |
if (((WindowPeek)ourWindows)->windowKind == kDocumentWindow) |
docWCount++; /* only count doc windows o' course */ |
ourWindows = (WindowPtr)((WindowPeek)ourWindows)->nextWindow; |
} /* end ourWindows while */ |
/* change the number to text, and append it */ |
NumToString((long)docWCount, numOfW); |
AppendString(wtitle, numOfW); |
SetWTitle(tempWP, wtitle); |
ShowWindow(tempWP); /* show it */ |
} |
HUnlock((Handle)setControls); |
SetPort(tempWP); |
SetUndo(0, false); /* since it is the current window, set all the actions to default */ |
SetCurAction(0); /* initialize the environment for a new window in front */ |
SetMyCursor(0); |
SwitchChecks(0); |
SetWMenus(true); |
if (showIt) { |
/* add it's name to our window menu */ |
AddToWindowMenu(tempWP, nil); |
ChangePlane(tempWP); |
} |
return(tempWP); |
} |
/* end AddNewWindow */ |
/* CloseMyWindow closes the window and disposes of all the memory |
* associated with it. It also calls HandleSections (sic) to UnRegister |
* all the editions associated with this window |
*/ |
void CloseMyWindow(WindowPtr theClose) |
{ |
windowCHandle theWind; |
short alBack; |
register qq; |
OSErr myErr; |
PicHandle *tempPicHandPtr; |
NMRec myNotification; |
Str255 nmWords; |
myNotification.qType =nmType ; |
myNotification.nmMark = nil; |
myNotification.nmIcon = nil; |
myNotification.nmSound = (Handle)-1; |
myNotification.nmStr =&nmWords ; |
myNotification.nmResp =nil ; |
theWind = (windowCHandle)GetWRefCon(theClose); |
GetIndString(&nmWords,kGeneralStrings,kBringForward); |
HLock((Handle)theWind); |
/* First see if we need to ask the user if they want to save this window or not */ |
if ((*theWind)->windowDirty) { |
ModalFilterUPP upp; |
Str255 windName; |
GetWTitle(theClose, windName); |
ParamText(windName, "", "", ""); |
/* No before we can do this, we have to be the frontmost application. It is */ |
/* not proper to put up a ModalDialog if you are not frontmost! */ |
/* But we cannot bully ourselves forward, we have got to */ |
/* ask the AppleEvent Manager if we can come forward. */ |
/* ¥¥¥¥ YOU MUST ASK TO COME FORWARD!!!!! */ |
/* NEVER force yourself forward. Bad thing will happen if you do, you will */ |
/* be messing up scripting systems if you change layers */ |
/* at will. So, we do this.... */ |
myErr = AEInteractWithUser(kAEDefaultTimeout, &myNotification, gCommonIdleFunctionUPP); |
/* now we've got to check the error. It is possible that there is NO way that */ |
/* we can come forward and bring up a dialog (imagine if this machine were running in another */ |
/* room, or late at night, and there was no-one to respond to the dialog) */ |
/* So we check like so.... */ |
if(myErr == errAENoUserInteraction){ |
return; /* we're blowing away the save because we can't talk about it */ |
} |
InitCursor(); |
upp = NewModalFilterProc(standardAlertFilter); |
alBack = Alert(kDirtyAlert, upp); /* Ask 'em */ |
DisposeRoutineDescriptor(upp); |
if (alBack == ok) /* they said yes, dispatch to the save handler */ |
(ProcPtr)(*(theWind))->saveMe(theWind, theClose); |
if (alBack == cancel) { |
/* if they said Cancel, this also tells us that the user does not want to */ |
/* quit the application if they were in the midst of shutdown ops. So, */ |
/* reset the stopping flag. Even if they weren't, this doesn't do any harm */ |
gStop = false; |
return; |
} |
} |
/* Save all our subscribers and publishers */ |
HandleSectionSave(theWind, false, true, nil); |
/* get rid of all our memory associated with this window */ |
DisposeHandle((*theWind)->pubs); |
DisposeHandle((*theWind)->pubRects); |
DisposeHandle((*theWind)->subs); |
DisposeHandle((*theWind)->subRects); |
DisposeHandle((Handle)(*theWind)->fileAliasHandle); |
/* Was there a TextEdit handle??? */ |
if ((*theWind)->boxHandle != nil) |
TEDispose((*theWind)->boxHandle); |
/* if there are any pictures, kill them too */ |
if ((*theWind)->numPicts) { |
HLock((*theWind)->pictHandle); |
tempPicHandPtr = (PicHandle *)*(*theWind)->pictHandle; |
for (qq = 0; qq < (*theWind)->numPicts; qq++) { /* rectangles are handled in the HandleSectionSave */ |
KillPicture(*tempPicHandPtr); |
tempPicHandPtr += 1; |
} |
} |
DisposeHandle((*theWind)->pictHandle); |
DisposeHandle((*theWind)->pictRects); |
DisposeHandle((Handle)theWind); |
DeleteFromWindowMenu(theClose); |
/* and finally actually close the window */ |
CloseWindow(theClose); |
if (FrontWindow()) { |
gShowingSecHandle = nil; |
gShowPub = false; |
gShowSub = false; |
if (((WindowPeek)FrontWindow())->windowKind == kDocumentWindow) |
SetWMenus(true); |
} else { |
SetWMenus(false); |
gShowingSecHandle = nil; |
gShowPub = false; |
gShowSub = false; |
} |
EnableItem(gFileMenuHandle, kOpenItem); |
EnableItem(gFileMenuHandle, kNewItem); |
} /* end CloseMyWindow */ |
/* DrawFull draws the contents of our document windows */ |
void DrawFull(windowCHandle theWind, WindowPtr theWindPtr) |
{ |
register qq; |
Rect scratchRect; |
RgnHandle tempRgn; |
RGBColor black = {0,0,0}; |
Rect grabRect; |
ShapesHandle theShape; |
/* Are there any shapes in this window? */ |
if ((*theWind)->numShapes) { |
theShape = (*theWind)->theShapes; |
/* walk through all the shapes */ |
do { |
HLock((Handle)theShape); |
switch ((*theShape)->type) { |
/* Draw whatever type of shape this is */ |
case kLineShape: |
if(gHasColor) |
RGBForeColor(&(*theShape)->theColor); |
MoveTo((*theShape)->theRect.left, (*theShape)->theRect.top); |
LineTo((*theShape)->theRect.right, (*theShape)->theRect.bottom); |
break; |
case kRectShape: |
if(gHasColor) |
RGBForeColor(&(*theShape)->theColor); |
FrameRect(&(*theShape)->theRect); |
break; |
case kOvalShape: |
if(gHasColor) |
RGBForeColor(&(*theShape)->theColor); |
FrameOval(&(*theShape)->theRect); |
break; |
} |
HUnlock((Handle)theShape); |
theShape = (*theShape)->nextShape; |
}while (theShape); /* end of shape list */ |
} |
if(gHasColor) |
RGBForeColor(&black); |
/* Is there a TextEdit field in this window? */ |
if ((*theWind)->boxHandle != nil) { |
/* If there is a textedit field, there may also be bordered text sections, */ |
/* so check for them also */ |
Rect framer; |
mySectionDataHandle tempTS = (*theWind)->textSections; |
TEUpdate(&(*theWind)->textBox, (*theWind)->boxHandle); |
framer = (*theWind)->textBox; |
InsetRect(&framer, -3, -2); |
FrameRect(&framer); |
/* step through any possible sections, and border them as needful */ |
while (tempTS) { |
if ((*tempTS)->bordered) |
BorderTextSection(tempTS); |
tempTS = (*tempTS)->nextSection; |
} /* end of text section list check */ |
} |
if ((*theWind)->numSubs) { /* are we subscribed to anything? */ |
PicHandle *tempHand; |
Handle *tempRHand; |
Rect *tempRect; |
HLock((*theWind)->subDataHandle); /* lock down and get the rectangles and */ |
HLock((*theWind)->subRects); /* current picture data for the subscribers this */ |
tempHand = (PicHandle *)*(*theWind)->subDataHandle; /* window has */ |
tempRHand = (Handle *)*(*theWind)->subRects; |
/* cast them into a handy form, and step through the list, drawing each */ |
for (qq = 0; qq < (*theWind)->numSubs; qq++) { |
PicHandle tempPic; |
tempPic = *tempHand; |
/* ¥¥¥¥This following check is important!¥¥¥¥ */ |
/* No matter what data type you are subscribing to, the data MAY NOT */ |
/* be in your application at the time you get an update. */ |
/* Updates have a higher event priority than AppleEvents, and you usually */ |
/* will get an update event after you show the 'Subscribe' dialog box and the */ |
/* user has subscribed to something. */ |
/* What that means is that you may not have yet gotten the first Section Read */ |
/* event for this subscription, you have no data to display. */ |
if (GetHandleSize((Handle)tempPic) != nil) { |
HLock(*tempRHand); |
tempRect = (Rect *)*(*tempRHand); |
DrawPicture(tempPic, tempRect); |
HUnlock(*tempRHand); |
} |
tempHand += 1; |
tempRHand += 1; |
} |
HUnlock((*theWind)->subDataHandle); |
HUnlock((*theWind)->subRects); |
} |
if ((*theWind)->numPicts) { |
/* see if we have any pictures. Pictures will be residual if the user */ |
/* used to have a subscriber, and canceled it. We get rid of the subscription */ |
/* but keep the data */ |
Handle *tempPicPtr; |
Handle *tempPicRect; |
HLock((*theWind)->pictHandle); |
HLock((*theWind)->pictRects); |
tempPicPtr = (Handle *)*((*theWind)->pictHandle); |
tempPicRect = (Handle *)*((*theWind)->pictRects); |
for (qq = 0; qq < (*theWind)->numPicts; qq++) { |
HLock(*tempPicRect); |
DrawPicture((PicHandle)*tempPicPtr, (Rect *)(*(*tempPicRect))); |
tempPicPtr += 1; |
tempPicRect += 1; |
} |
} |
/* Show publisher in this window if it's been clicked on lately */ |
if (theWindPtr == FrontWindow()) { |
if (gShowPub) { |
PenPat(&qd.gray); /* 50% gray for publishers */ |
PenSize(3, 3); |
FrameRect(&gShowPubRect); |
PenPat(&qd.black); |
PenSize(1, 1); |
grabRect = gShowPubRect; |
grabRect.top = grabRect.bottom - 7; |
grabRect.left = grabRect.right - 7; |
PaintRect(&grabRect); |
/* ¥¥¥¥ NOTE: I've taken the invert out of these areas because it got confusing for what */ |
/* I was publishing and subscribing. Since we're dealing basically with bitmaps NOT */ |
/* with object-style graphiocs, the invert can be confusing. */ |
/* InsetRect(&gShowPubRect, 4, 4); */ |
/* invert the selection */ |
/*InvertRect(&gShowPubRect);*/ |
/*InsetRect(&gShowPubRect, -4, -4); */ |
} |
if (gShowSub) { |
PenPat(&qd.dkGray); /* 75% gray for subscriptions */ |
PenSize(3, 3); |
InsetRect(&gShowSubRect, -4, -4); |
FrameRect(&gShowSubRect); |
PenPat(&qd.black); |
PenSize(1, 1); |
/* same as NOTE above */ |
/*InsetRect(&gShowSubRect, 4, 4); */ |
/*InvertRect(&gShowSubRect); */ |
/*InsetRect(&gShowSubRect, -4, -4); */ |
/* add a resizing grabber */ |
if (gResizeSub) { |
/* If they can resize subscriptions, draw the grab box. */ |
/* see the extra check box I added to the Subscriber Options dialog */ |
grabRect = gShowSubRect; |
grabRect.top = grabRect.bottom - 7; |
grabRect.left = grabRect.right - 7; |
PenPat(&qd.black); |
/* if this is not the front window, just outline the grabber */ |
/* if it is frontmost, draw it in solid black */ |
if (theWindPtr != FrontWindow()) { |
EraseRect(&grabRect); |
FrameRect(&grabRect); |
} else { |
EraseRect(&grabRect); |
PaintRect(&grabRect); |
} |
} |
InsetRect(&gShowSubRect, 4, 4); |
} |
/* see if border showing is happening */ |
/* They optionally may have the 'Show All Borders' menu item checked, if so show */ |
/* the location of all the sections in this window */ |
if (gShowingAll) { |
Rect borderRect; |
/* show all pubs */ |
if ((*theWind)->numPubs) { |
Rect *tempRectPtr; |
HLock((*theWind)->pubRects); |
tempRectPtr = (Rect *)*(*theWind)->pubRects; |
PenPat(&qd.gray); /* 50% gray for publishers */ |
PenSize(3, 3); |
for (qq = 0; qq < (*theWind)->numPubs; qq++) { |
borderRect = *tempRectPtr; |
FrameRect(&borderRect); |
tempRectPtr += 1; |
} |
HUnlock((*theWind)->pubRects); |
} |
/* show all subs */ |
if ((*theWind)->numSubs) { |
Handle *theRectsHandle; |
HLock((*theWind)->subRects); /* lock down the rect handle */ |
/* cast it as a pointer to handles for reading ease */ |
theRectsHandle = (Handle *)*(*theWind)->subRects; |
PenPat(&qd.dkGray); /* 75% gray for subscriptions */ |
PenSize(3, 3); |
for (qq = 0; qq < (*theWind)->numSubs; qq++) { |
HLock(*theRectsHandle); |
borderRect = *((Rect *)*(*theRectsHandle)); |
InsetRect(&borderRect, -4, -4); |
FrameRect(&borderRect); |
HUnlock(*theRectsHandle); |
theRectsHandle += 1; |
} |
HUnlock((*theWind)->subRects); |
} |
/* and show all text sections */ |
if ((*theWind)->textSections) { |
mySectionDataHandle tempTS = (*theWind)->textSections; |
do { |
BorderTextSection(tempTS); |
tempTS = (*tempTS)->nextSection; |
}while (tempTS); |
} |
PenSize(1, 1); |
PenPat(&qd.black); |
} |
} |
/* and the grow box */ |
scratchRect = theWindPtr->portRect; |
scratchRect.top = scratchRect.bottom - 15; |
scratchRect.left = scratchRect.right - 15; |
tempRgn = NewRgn(); |
GetClip(tempRgn); |
ClipRect(&scratchRect); |
DrawGrowIcon(theWindPtr); |
SetClip(tempRgn); |
DisposeRgn(tempRgn); |
} |
/* end DrawFull */ |
/* DoDocumentClick handles clicking in the content region of our */ |
/* document windows. */ |
void DoDocumentClick(WindowPtr twindow) |
{ |
/* if the window already was frontmost, take the right */ |
/* action for this window */ |
/* ¥¥¥ NOTE: Normally, this is also the place where you would */ |
/* update the modification date (mdDate) of publishers */ |
/* If the user takes an action across a published area, you */ |
/* should update the modification time to flag yourself that this */ |
/* edition needs to be sent. This date/time will also show up in the */ |
/* Options dialog for that publisher. But for the sake of clarity in this */ |
/* sample, I am only changing the mod date on edition write (in files.c) */ |
Point endPoint; |
Point oldendPoint; |
Rect startRect; |
Boolean wasInTB; |
windowCHandle shortname; |
short tempAct; |
Rect testRect; |
shortname = (windowCHandle)GetWRefCon(twindow); |
/* This handle is already locked on entry, from the dispatcher that got us here */ |
tempAct = (*shortname)->currentAction; /* what are they doing? */ |
SetPort(twindow); /* make sure the port is good, I'm paranoid */ |
GlobalToLocal(&gERecord.where); /* everything will be in local coordinate to this window */ |
/* I don't want users to draw objects across my text box, so see if this click is in that thang */ |
testRect.left = testRect.right = gERecord.where.h; |
testRect.right++; |
testRect.top = testRect.bottom = gERecord.where.v; |
testRect.bottom++; |
wasInTB = InTextBox(shortname, &testRect); |
if (!wasInTB || tempAct == kTextBox || tempAct == kNoAction) { |
switch (tempAct) { /* switch off the action code */ |
myLine tempLine; |
case kNoAction: |
/* no menu items checked. See if they clicked in a */ |
/* publisher or subcriber */ |
/* border a publisher or subscriber if they clicked in one */ |
if (!SearchPubs(gERecord.where) && !SearchSubs(gERecord.where)) { |
/* if they didn't click in one, then erase the current selection */ |
/* Check to see if they're clicking in the TERecord. This takes precidence over */ |
/* any other click */ |
/* You'll want to change this depending on your app */ |
if (wasInTB) { |
/* treat this like a random click to de-border any PICT subscriptions that */ |
/* may be selected */ |
KillSelection(shortname); |
DeBorderSelection(); |
/* check publisher stuff here */ |
TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*shortname)->boxHandle); |
if (!gShowingAll) { |
mySectionDataHandle tempTS = (*shortname)->textSections; |
Boolean anyOn = false; /* for our invalidate check */ |
/* step through text sections and turn off flags */ |
//while (tempTS) { |
///* also check here to see if anything was bordered. If it was, invalidate */ |
///* the TE rectangle so the old borders will be erased. If there */ |
///* were NOT any, don't invalidate, so we don't strobe the user to */ |
///* blindness */ |
//anyOn = anyOn | (*tempTS)->bordered; |
//(*tempTS)->bordered = false; |
//tempTS = (*tempTS)->nextSection; |
//} |
//if (anyOn) |
//InvalRect(&(*(*shortname)->boxHandle)->viewRect); |
} /* see if the click was inside a subscriber */ |
CheckSectionHit(); |
} else { |
/* if it was a random click, dehilite the text selection if there is one */ |
if ((*shortname)->boxHandle != nil) { |
TESetSelect((*(*shortname)->boxHandle)->selStart, (*(*shortname)->boxHandle)->selStart, |
(*shortname)->boxHandle); |
/* Also, check to see if any borders are on in the TE box. If so, turn them off. */ |
/* That is, unless gSHowingAll is on.... */ |
/* and it's easiest just to invlaidate the terect */ |
InvalRect(&(*(*shortname)->boxHandle)->viewRect); |
if (!gShowingAll) { |
mySectionDataHandle tempTS = (*shortname)->textSections; |
/* step through text sections and turn off flags */ |
while (tempTS) { |
(*tempTS)->bordered = false; |
tempTS = (*tempTS)->nextSection; |
} /* tempTS while end */ |
} |
} |
KillSelection(shortname); |
DeBorderSelection(); |
/* and drag around a picture or an object if they want */ |
DragPictOrObject(&gERecord.where, shortname); |
} |
break; |
case kDrawLine: |
/* they want to draw a line in this window */ |
/* start and end points of the line set to the same val */ |
oldendPoint = endPoint = gERecord.where; |
PenMode(srcXor); /* Xor so we can rubberband the line */ |
while (StillDown()) { /* Keep doing this as long as the */ |
/* user keeps the mouse down */ |
GetMouse(&endPoint); /* Current mouse position in local */ |
MakeRect(&gERecord.where, &endPoint, &testRect); |
if (!InTextBox(shortname, &testRect)) { |
/* coordinates */ |
if (endPoint != oldendPoint) { /* only do this if the mouse moved so the line doesn't flicker */ |
/* erase the old line (redraw in Xor mode ) */ |
MoveTo(gERecord.where.h, gERecord.where.v); |
LineTo(oldendPoint.h, oldendPoint.v); |
/* draw the new line */ |
MoveTo(gERecord.where.h, gERecord.where.v); |
LineTo(endPoint.h, endPoint.v); |
oldendPoint = endPoint; |
} |
} else { |
endPoint = oldendPoint; |
} |
} /* StillDown while end */ |
PenMode(srcCopy); |
/* They released the mouse. Add the line they drew */ |
/* to our record */ |
tempLine.start = gERecord.where; |
tempLine.end = endPoint; |
/* see this function later in this file */ |
AddLine((windowCHandle)((WindowPeek)twindow)->refCon, &tempLine); |
/* changes the Undo menu item text */ |
SetUndo(kDrawLine, false); |
break; /* end line case */ |
/* they want to draw a rectangle in this window */ |
case kDrawRect: |
/* start and end of rectangle set to the same val */ |
PullRect(shortname, &startRect, false, false, true); |
/* Add it to our window */ |
AddRect((windowCHandle)((WindowPeek)twindow)->refCon, &startRect); |
SetUndo(kDrawRect, false); /* Set undo menu item text to */ |
/* Undo Rectangle */ |
break; /* end rectangle case */ |
case kDrawOval: |
/* start and end of oval set to the same val */ |
PullRect(shortname, &startRect, true, false, true); |
/* Add the oval to our window struct */ |
AddOval((windowCHandle)((WindowPeek)twindow)->refCon, &startRect); |
/* Set undo menu item text to Undo Oval */ |
SetUndo(kDrawOval, false); |
break; |
case kTextBox: |
/* start and end of rectangle set to the same val */ |
PullRect(shortname, &startRect, false, false, true); |
/* Add it to our window */ |
AddTextBox((windowCHandle)((WindowPeek)twindow)->refCon, &startRect); |
SetUndo(kCantUndo, false); /* can't undo a text box */ |
SwitchChecks(kTextBox); |
InitCursor(); |
/* Undo Rectangle */ |
break; |
case kSelectStuff: |
/* pretty much like drawrect, but */ |
/* the resulting rect can be published */ |
/* get rid of the old one */ |
if ((*shortname)->hasSelection) |
KillSelection((windowCHandle)GetWRefCon(twindow)); |
PullRect(shortname, &startRect, false, false, true); |
PenPat(&qd.gray); |
FrameRect(&startRect); |
PenPat(&qd.black); |
PenSize(1, 1); |
AddSelection((windowCHandle)((WindowPeek)twindow)->refCon, &startRect); |
/* they can only select one rectangle, so clear the check */ |
/* and change the cursor back to an arrow */ |
SwitchChecks(kSelectStuff); |
InitCursor(); |
(*shortname)->hasSelection = true; |
SetUndo(kSelectItem - 1, false); /* since the item on the menu is one more than our use, because of the divider */ |
/* before the MenuSelect call above to see how it's used */ |
break; |
break; |
} else { |
unsigned long timeNow; |
/* they did click in one, see if it is/was a double click please */ |
/* A double-click in a section should be treated the same */ |
/* as if the user had selected Pub/Sub options for that section */ |
KillSelection(shortname); |
if ((gShowingSecHandle == gLastSection) && (gShowingSecHandle != nil)) { |
timeNow = TickCount(); |
if ((timeNow - gLastSecClickTick) < GetDblTime()) { |
/* it is a double click. treat the same way as the menu selection for */ |
/* Options UNLESS they had the option key down, then do a gotopublisher*/ |
if (gERecord.modifiers & optionKey) |
MyGoToPublisher(gLastSection); |
else |
DoOptions(gShowingSecHandle); /* in Subscribe.c. */ |
} else { |
/* not a double click. Set up for the next pass */ |
/* de-border the old one please */ |
gLastSecClickTick = timeNow; |
gLastSection = gShowingSecHandle; |
} |
} else { |
gLastSecClickTick = timeNow; |
gLastSection = gShowingSecHandle; |
} |
} |
} |
} else { |
/* no matter which tool is selected, you can select in the TB */ |
TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*shortname)->boxHandle); |
} |
} |
/* end DoDocumentClick */ |
/* DragPictOrObject drags a shape or picture. Stores last position in */ |
/* window structure for Undo */ |
void DragPictOrObject(Point *where, windowCHandle tempWC) |
{ |
Handle *tempPicRect; |
ShapesHandle theShapes; |
register qq; |
Rect origRect; |
Boolean hadIt = false; |
Point thePoint; |
/* See if the hit was in a Pict, search all picts */ |
if ((*tempWC)->numPicts) { |
HLock((*tempWC)->pictRects); |
tempPicRect = (Handle *)*((*tempWC)->pictRects); |
/* run through all of them */ |
for (qq = 0; qq < (*tempWC)->numPicts; qq++) { |
/* Did we hit this one? */ |
if (PtInRect(*where, (Rect *)(*(*tempPicRect)))) { |
/* Yes, drag it around */ |
Rect dragger = *((Rect *)(*(*tempPicRect))); |
thePoint = *where; |
origRect = dragger; |
hadIt = true; |
PullRect(tempWC, &dragger, false, true, false); |
if(!EqualRect(&origRect,&dragger)){ |
/* if it really moved, update the dirty flag <ckh 1.0.2>*/ |
(*tempWC)->windowDirty = kMyTrue; |
} |
*((Rect *)(*(*tempPicRect)))=dragger; |
InvalRect(&dragger); |
InvalRect(&origRect); |
if ((*tempWC)->hasSelection) |
InvalRect(&(*tempWC)->selectionRect); |
(*tempWC)->hasSelection = true; |
(*tempWC)->selectionRect = dragger; |
/* make this one pixel bigger, so if the user wants to publish a Pict */ |
/* they get the whole thing */ |
InsetRect(&(*tempWC)->selectionRect,-1,-1); |
break; |
} |
tempPicRect += 1; |
} |
HUnlock((*tempWC)->pictRects); |
} |
if (!hadIt) { |
/* check all my shapes */ |
if ((*tempWC)->numShapes) { |
Boolean offsetIt = false; |
theShapes = (*tempWC)->theShapes; |
do { |
Rect dragger; |
HLock((Handle)theShapes); |
dragger = (*theShapes)->theRect; |
if ((*theShapes)->type == kLineShape) { |
short temp; |
if (dragger.top > dragger.bottom) { |
offsetIt = true; |
temp = dragger.top; |
dragger.top = dragger.bottom; |
dragger.bottom = temp; |
} |
if (dragger.left > dragger.right) { |
offsetIt = true; |
temp = dragger.left; |
dragger.left = dragger.right; |
dragger.right = temp; |
} |
} |
if (PtInRect(*where, &dragger)) { |
thePoint = *where; |
/* have to see if this was a line, since that rect may be reversed */ |
origRect = dragger; |
InsetRect(&dragger, -1, -1); |
hadIt = true; |
PullRect(tempWC, &dragger, false, true, false); |
InsetRect(&dragger, 1, 1); |
if(!EqualRect(&origRect,&dragger))(*tempWC)->windowDirty = kMyTrue; |
if (offsetIt) { |
OffsetRect(&(*theShapes)->theRect, dragger.left - origRect.left, dragger.top - origRect.top); |
} else { |
(*theShapes)->theRect = dragger; |
} |
InvalRect(&dragger); |
InvalRect(&origRect); |
(*tempWC)->hasSelection = true; |
if ((*tempWC)->hasSelection) |
InvalRect(&(*tempWC)->selectionRect); |
(*tempWC)->hasSelection = true; |
(*tempWC)->selectionRect = dragger; |
/* make this one pixel bigger, so if the user wants to publish an object */ |
/* they get the whole thing */ |
InsetRect(&(*tempWC)->selectionRect,-1,-1); |
break; |
} |
HUnlock((Handle)theShapes); |
theShapes = (*theShapes)->nextShape; |
}while (theShapes); /* end of shapes */ |
} |
} |
} /* end DragPictOrObject */ |
/* KillSelection removes any selection from the current window */ |
void KillSelection(windowCHandle tempWC) |
{ |
Rect nulRect = { |
0, 0, 0, 0 |
}; |
InvalRect(&(*tempWC)->selectionRect); |
(*tempWC)->selectionRect = nulRect; |
(*tempWC)->hasSelection = false; |
} /* end KillSelection */ |
/* UndoLast undoes the last drawing action that happened in the current |
* window. Each window has it's own record of the last action, so |
* Undo is always valid for the current window, and will not act on a |
* window the user doesn't expect. */ |
void UndoLast(void) |
{ |
windowCHandle temp; |
WindowPtr tempPort; |
ShapesHandle tempSH, beforeLast; |
GetPort(&tempPort); /* not really necessary, but I'm paranoid */ |
SetPort(FrontWindow()); |
temp = (windowCHandle)GetWRefCon(FrontWindow()); |
HLock((Handle)temp); /* memory may move when handles are resized */ |
switch ((*temp)->undoAction) { /* last action that happened in this window */ |
/* For the graphic objects, we need to erase the last thing draw and update |
* the window record's handles and counts */ |
case kDrawLine: |
case kDrawRect: |
case kDrawOval: |
/* unlink and dispose of the last shape handle please */ |
/* find the last shape */ |
beforeLast = (*temp)->theShapes; |
tempSH = (*temp)->theShapes; |
if ((*temp)->numShapes == 1) { |
(*temp)->numShapes = 0; |
DisposeHandle((Handle)(*temp)->theShapes); |
(*temp)->theShapes = nil; |
} else { |
register qq; |
for (qq = 0; qq < (*temp)->numShapes - 2; qq++) { |
tempSH = (*tempSH)->nextShape; |
} |
DisposeHandle((Handle)(*tempSH)->nextShape); |
(*tempSH)->nextShape = nil; |
(*temp)->numShapes--; |
} |
break; |
case kTextBox: |
TEDispose((*temp)->boxHandle); |
(*temp)->boxHandle = nil; |
InsetRect(&(*temp)->textBox, -3, -2); /* just don't ask */ |
InvalRect(&(*temp)->textBox); |
break; |
case kSelectStuff: |
KillSelection(temp); |
break; |
case kMoveObject: |
break; |
} |
HUnlock((Handle)temp); |
/* now make sure things get refreshed */ |
InvalRect(&(FrontWindow()->portRect)); |
EraseRect(&(FrontWindow()->portRect)); |
SetUndo(0, false); |
SetPort(tempPort); |
} /* end UndoLast */ |
/* AddLine adds a line to our window data structure */ |
/* nowHandle is the window data structure handle */ |
/* inLine is the line to add */ |
void AddLine(windowCHandle nowHandle, myLine *inline) |
{Rect tempRect; |
short temp; |
ShapesHandle newShape = NewShape(nowHandle); |
(*newShape)->type=kLineShape; |
(*newShape)->aeType = cGraphicLine; |
(*newShape)->theRect.top = inline->start.v; |
(*newShape)->theRect.left = inline->start.h; |
(*newShape)->theRect.bottom = inline->end.v; |
(*newShape)->theRect.right = inline->end.h; |
tempRect = (*newShape)->theRect; |
if (tempRect.top > tempRect.bottom) { |
temp = tempRect.top; |
tempRect.top = tempRect.bottom; |
tempRect.bottom = temp; |
} |
if (tempRect.left > tempRect.right) { |
temp = tempRect.left; |
tempRect.left = tempRect.right; |
tempRect.right = temp; |
} |
InvalRect(&tempRect); |
} |
/* end AddLine */ |
/* AddRect adds a rectangle to our window data structure */ |
/* nowHandle is the window data structure handle */ |
/* inRect is the rect to add */ |
void AddRect(windowCHandle nowHandle, Rect *inrect) |
{ShapesHandle tempShape = NewShape(nowHandle); |
(*tempShape)->type=kRectShape; |
(*tempShape)->aeType = cRectangle; |
(*tempShape)->theRect=*inrect; |
InvalRect(inrect); |
} |
/* end AddRect */ |
/* AddTextBox adds a text editing box to our window data structure */ |
/* nowHandle is the window data structure handle */ |
/* inRect is the position to put the box in to add */ |
void AddTextBox(windowCHandle nowHandle, Rect *inrect) |
{ |
Rect framer; |
HLock((Handle)nowHandle); |
(*nowHandle)->textBox = *inrect; |
(*nowHandle)->windowDirty = kMyTrue; |
/* Create a TERecord to go here */ |
InsetRect(&(*nowHandle)->textBox, -3, -3); |
(*nowHandle)->boxHandle = TENew(inrect, &(*nowHandle)->textBox); |
TEActivate((*nowHandle)->boxHandle); |
framer = (*nowHandle)->textBox; |
InsetRect(&framer, -3, -2); |
InvalRect(&framer); |
HUnlock((Handle)nowHandle); |
} |
/* end AddTextBox */ |
/* AddOval adds a oval to our window data structure */ |
/* nowHandle is the window data structure handle */ |
/* inOval is the oval to add */ |
void AddOval(windowCHandle nowHandle, Rect *inoval) |
{ShapesHandle tempShape = NewShape(nowHandle); |
(*tempShape)->type=kOvalShape; |
(*tempShape)->aeType = cOval; |
(*tempShape)->theRect=*inoval; |
InvalRect(inoval); |
} /* end AddOval */ |
/* AddSelection adds a selection rectangle to our window data structure */ |
/* nowHandle is the window data structure handle */ |
/* inRect is the rect to add */ |
void AddSelection(windowCHandle nowHandle, Rect *inrect) |
{ |
HLock((Handle)nowHandle); |
(*nowHandle)->selectionRect = *inrect; |
(*nowHandle)->hasSelection = true; |
HUnlock((Handle)nowHandle); |
} /* end AddSelection */ |
/* NewShape adds a new shape to our window structure */ |
ShapesHandle NewShape(windowCHandle theWindow) |
{ |
ShapesHandle newShape = (ShapesHandle)NewHandle(sizeof(Shapes)); |
ShapesHandle tempShapes=(*theWindow)->theShapes; |
(*newShape)->theColor = gColorArray[gCurrentColor]; |
if(tempShapes){ /* if there is already a shape defined */ |
/* find the end and store this handle there */ |
while((*tempShapes)->nextShape){ |
tempShapes=(*tempShapes)->nextShape; |
} |
(*tempShapes)->nextShape=newShape; |
} else { |
/* first shape */ |
(*theWindow)->theShapes=newShape; |
} |
/* increase our count of shapes */ |
(*theWindow)->numShapes++; |
(*theWindow)->windowDirty = kMyTrue; |
(*newShape)->nextShape=nil; |
return(newShape); |
} |
/* end NewShape */ |
/* ChangePlane does the housekeeping we need to do when a window comes to */ |
/* the front, swapping menu checks, setting the cursor, and so on */ |
/* And by the way, this routine has caused me more problems than any other, I will */ |
/* be completely rewriting it in the next release, it is _not_ optimal. */ |
void ChangePlane(WindowPtr twindow) |
{ |
short temp; |
Rect scratchRect; |
WindowPtr oldWindow = FrontWindow(); |
windowCHandle shortname; |
/* Before the swap kill any current borders */ |
DeBorderSelection(); |
/* deactivate the textedit record of the old window, if there is one */ |
if (oldWindow != nil && oldWindow != twindow && IsMyWindow(oldWindow)) { |
windowCHandle tempCH = (windowCHandle)GetWRefCon(oldWindow); |
if ((*tempCH)->boxHandle != nil) |
TEDeactivate((*tempCH)->boxHandle); |
SetPort(oldWindow); |
scratchRect = twindow->portRect; |
scratchRect.top = scratchRect.bottom - 15; |
scratchRect.left = scratchRect.right - 15; |
InvalRect(&scratchRect); |
} |
/* if the window coming forward isn't a doc window, dim the tools menu */ |
if (((WindowPeek)twindow)->windowKind != kDocumentWindow) { |
SetWMenus(false); |
} else { |
SetWMenus(true); |
} |
SetUndo(0, true); /* tell SetUndo to pull the undo item value out of the current record */ |
shortname = (windowCHandle)GetWRefCon(twindow); /* was oldwindow */ |
HLock((Handle)shortname); |
temp = (*shortname)->currentAction; /* pull the last action the */ |
HUnlock((Handle)shortname); /* user was performing out of the */ |
SetCurAction(temp); /* window record */ |
SetMyCursor(actsToIDs[temp]); /* set the right cursor */ |
SwitchChecks(actsToIDs[temp]); /* check the right menu item */ |
gShowPub = gShowSub = false; /* selections go away when windows */ |
gShowingSecHandle = nil; |
if ((*shortname)->boxHandle != nil) |
TEActivate((*shortname)->boxHandle); |
SelectWindow(twindow); /* select the window */ |
SetPort(twindow); |
scratchRect = twindow->portRect; |
scratchRect.top = scratchRect.bottom - 15; |
scratchRect.left = scratchRect.right - 15; |
InvalRect(&scratchRect); |
/* and re-do our window indexes */ |
/* ¥¥¥¥ NOTE: I am not including the AEStatus window in this */ |
/* window index or check! The AEStatus window is a special diagnostic |
/* only type window that is _not_ anything a 'real' application would have */ |
/* It can change planes in the middle of an AppleEvent if there is information */ |
/* to display, and if I included it in my real window list that */ |
/* would violate 'state freezing' for the space of an event, which */ |
/* is A Bad Thing */ |
/* So I'm looking at everything but the AES window */ |
temp = 1; |
oldWindow = FrontWindow(); |
while(oldWindow){ |
shortname = (windowCHandle)GetWRefCon(oldWindow); |
if((((WindowPeek)oldWindow)->visible) && (((WindowPeek)oldWindow)->windowKind != kAEStatusWindow && IsMyWindow(oldWindow))) |
{(*shortname)->windowIndex = temp; |
temp++;} |
oldWindow = (WindowPtr)((WindowPeek)oldWindow)->nextWindow; |
} |
/* now any invisible windows, since their index will be after the visible ones */ |
oldWindow = (WindowPtr)LMGetWindowList(); |
while(oldWindow){ |
shortname = (windowCHandle)GetWRefCon(oldWindow); |
if((!((WindowPeek)oldWindow)->visible) && (((WindowPeek)oldWindow)->windowKind != kAEStatusWindow) && IsMyWindow(oldWindow)) |
{(*shortname)->windowIndex = temp; |
temp++;} |
oldWindow = (WindowPtr)((WindowPeek)oldWindow)->nextWindow; |
} |
AdjustCursor(gERecord.where, mousergn); |
} |
/* end ChangePlane */ |
/* may be a shape ,PICT, or a selection range */ |
/* so if it's a shape, I cut the shape definition, pict, same thing. */ |
/* if it's a selection range, I dunno what I'm gonna do. */ |
/* no, actually I'll just cut all the components of the range */ |
void CutGraphic(windowCHandle tempWC) |
{Rect localSelection = (*tempWC)->selectionRect; |
} |
void CopyGraphic(windowCHandle tempWC) |
{ |
#pragma unused (tempWC) |
} |
void ClearGraphic(windowCHandle tempWC) |
{ |
#pragma unused (tempWC) |
} |
/* This sets window properties, it's passed one of our property tokens */ |
OSErr SetWindowProperty(PropertyTHdl propertyBack, AEDesc *theData) |
{ |
OSErr myErr = noErr; |
AEDesc convertedDesc; |
Size dataSize; |
switch ((*propertyBack)->theProperty) { |
case pName: |
/* setting name. Let's see if the data is typeChar */ |
if (theData->descriptorType != typeChar) { |
/* problem. See if it'll coerce */ |
myErr = AECoerceDesc(theData, typeChar, &convertedDesc); |
if (!myErr) { |
/* it converted. swap descs (kinda) */ |
myErr = AEDisposeDesc(theData); |
myErr = AEDuplicateDesc(&convertedDesc, theData); |
myErr = AEDisposeDesc(&convertedDesc); |
} |
} |
if (!myErr) { |
Str63 newName,oldName; |
/* the data in the handle is text. Make it into a string for us */ |
dataSize = GetHandleSize(theData->dataHandle); |
if (dataSize > 63) |
dataSize = 63; /* Truncating the name because I want to */ |
HLock(theData->dataHandle); |
BlockMove((Ptr)*(theData->dataHandle), (Ptr)&newName[1], dataSize); |
HUnlock(theData->dataHandle); |
newName[0] = dataSize; |
/* set the title. We have the window pointer in the property token */ |
GetWTitle((*propertyBack)->token.window,&oldName); |
SetWTitle((*propertyBack)->token.window, &newName); |
/* v 1.0.1 revise old name in window menu please */ |
AddToWindowMenu((*propertyBack)->token.window,&oldName); |
/* all done! */ |
} |
break; |
case pBounds: |
/* we have been passed a new rectangle, in global coords */ |
/* so pull the rectangle out */ |
/* again, make sure the data is in a rect type */ |
if (theData->descriptorType != typeQDRectangle) { |
/* problem. See if it'll coerce */ |
myErr = AECoerceDesc(theData, typeQDRectangle, &convertedDesc); |
if (!myErr) { |
/* it converted. swap descs (kinda) */ |
myErr = AEDisposeDesc(theData); |
myErr = AEDuplicateDesc(&convertedDesc, theData); |
myErr = AEDisposeDesc(&convertedDesc); |
} |
} |
if (!myErr) { |
Rect newRect; |
/* OK, the data handle contains a rect. I'll move it so it's easier to read */ |
newRect = *((Rect *)*(theData->dataHandle)); |
/* Move the window. Pass a false as BringToFront since we don't want window shuffling */ |
/* check the rect for validity */ |
if( newRect.top < newRect.bottom && newRect.left < newRect.right){ |
MoveWindow((*propertyBack)->token.window, newRect.left, newRect.top, false); |
/* set the new dimensions. And generate an update as needed */ |
SizeWindow((*propertyBack)->token.window, (newRect.right - newRect.left), (newRect.bottom - newRect.top), true); |
/* Done! */ |
} else { |
myErr = errAEEventNotHandled; |
AddToReply("\pBad Window Size",kWeirdSizeErr); |
} |
} |
break; |
case pHasTitleBar: |
case pIsModal: |
case pIsModified: |
case pIsResizable: |
case pIsStationeryPad: |
case pIsZoomed: |
/* add new Winter '92 registry error code <ckh 1.0.2>*/ |
myErr = errAENotModifiable; /* I am not allowing these properties to be modified */ |
AddToReply("\p Attempted to modify a read-only parameter",errAENotModifiable); |
break; |
case pVisible: |
/* value is true oder false */ |
if(**(theData->dataHandle)){ |
ShowWindow((*propertyBack)->token.window); |
AddToWindowMenu((*propertyBack)->token.window,nil); |
} |
else { |
DeleteFromWindowMenu((*propertyBack)->token.window); |
HideWindow((*propertyBack)->token.window); |
} |
break; |
} |
return(myErr); |
} /* end SetWindowProperty */ |
OSErr SetShapeProperty(PropertyTHdl propertyBack, AEDesc *theData) |
{ |
OSErr myErr = noErr; |
AEDesc convertedDesc; |
WindowPtr tempWindow; |
ShapesHandle theShape =(*propertyBack)->token.shapeHandle; |
switch ((*propertyBack)->theProperty) { |
case pBounds: |
case pDefinitionRect: |
/* we have been passed a new rectangle */ |
/* so pull the rectangle out */ |
/* again, make sure the data is in a rect type */ |
if (theData->descriptorType != typeQDRectangle) { |
/* problem. See if it'll coerce */ |
myErr = AECoerceDesc(theData, typeQDRectangle, &convertedDesc); |
if (!myErr) { |
/* it converted. swap descs (kinda) */ |
myErr = AEDisposeDesc(theData); |
myErr = AEDuplicateDesc(&convertedDesc, theData); |
myErr = AEDisposeDesc(&convertedDesc); |
} |
} |
if (!myErr) { |
/* we have a rect. Set the shape to it */ |
HLock((Handle)theShape); |
/* invalidate the old rect so the user sees the change */ |
/* ¥ NOTE: I'm getting current port and setting the one in the */ |
/* token. Remember, there is NO reason for an event to have to */ |
/* occur in the frontmost or current port */ |
GetPort(&tempWindow); |
SetPort((*propertyBack)->inWindow); |
InvalRect(&(*theShape)->theRect); |
/* i dont want the rect set to zero, please */ |
if(!EmptyRect(((Rect *)*(theData->dataHandle)))){ |
(*theShape)->theRect = *((Rect *)*(theData->dataHandle)); |
InvalRect(&(*theShape)->theRect);} |
SetPort(tempWindow); |
} |
break; |
case pPenColor: |
/* pretty much the same for colors */ |
if (theData->descriptorType != typeRGBColor) { |
/* problem. See if it'll coerce */ |
myErr = AECoerceDesc(theData, typeRGBColor, &convertedDesc); |
if (!myErr) { |
/* it converted. swap descs (kinda) */ |
myErr = AEDisposeDesc(theData); |
myErr |= AEDuplicateDesc(&convertedDesc, theData); |
myErr |= AEDisposeDesc(&convertedDesc); |
} |
} |
if (!myErr) { |
/* we have a rect. Set the shape to it */ |
HLock((Handle)theShape); |
/* invalidate the old rect so the user sees the change */ |
/* ¥ NOTE: I'm getting current port and setting the one in the */ |
/* token. Remember, there is NO reason for an event to have to */ |
/* occur in the frontmost or current port */ |
GetPort(&tempWindow); |
SetPort((*propertyBack)->inWindow); |
InvalRect(&(*theShape)->theRect); |
(*theShape)->theColor = *((RGBColor *)*(theData->dataHandle)); |
SetPort(tempWindow); |
} |
break; |
/* I'm not handling any other properties right now, check again later */ |
default: |
/* add new Winter '92 registry error code <ckh 1.0.2>*/ |
myErr = errAENotModifiable; /* I am not allowing these properties to be modified */ |
AddToReply("\p Attempted to modify a read-only parameter",errAENotModifiable); |
break; |
} |
return(myErr); |
} |
/* Check to see if a window belongs to a desk accessory. */ |
/* This is _almost_ unnecessary in System 7. Since DAs have their own layer now, and */ |
/* it's _almost_ impossible to force a DA into an applications space, this should */ |
/* rarely be true */ |
/* HOWEVER, there are INITs out there that will stick windows in your window list. */ |
/* BallooonWriter does, for example */ |
Boolean IsDAWindow(WindowPtr window) |
{ |
if (window == nil) |
return false; |
else /* DA windows have negative windowKinds */ |
return((WindowPeek)window)->windowKind < 0; |
} |
/* end IsDAWindow*/ |
/* DrawClip draws the current contents of the clipboard */ |
void DrawClip(windowCHandle theWind, WindowPtr windowIn) |
{ |
#pragma unused(theWind) |
RgnHandle tempRgn; |
Rect theRect; |
Str63 clipString; |
UpdateScrap(false); /* no neverending updateas */ |
MoveTo(10, 10); |
/* Get the basic clipboard text */ |
GetIndString(clipString, kClipBoardStrings, 1); |
DrawString(clipString); |
/* get the string that says what type of thing is on the clipboard */ |
GetIndString(clipString, kClipBoardStrings, gClipHasContents); |
DrawString(clipString); |
MoveTo(0, 13); |
/* underline those words */ |
LineTo(FindClipWindow()->portRect.right, 13); |
HLock(gScrapData); |
/* I make all my clipboard data into a picture, so we can use DrawPicture to display it */ |
if ((GetHandleSize(gScrapData) != 0) && gScrapData) { |
Rect picRect; |
picRect = ((*(PicHandle)gScrapData))->picFrame; |
OffsetRect(&picRect, 0, 15); |
DrawPicture((PicHandle)gScrapData, &picRect); |
} |
HUnlock(gScrapData); |
/* Add our grow box, clip out the rect so we don't get the */ |
/* spurious scroll area lines */ |
theRect = windowIn->portRect; |
theRect.top = theRect.bottom - 15; |
theRect.left = theRect.right - 15; |
tempRgn = NewRgn(); |
GetClip(tempRgn); |
ClipRect(&theRect); |
DrawGrowIcon(windowIn); |
SetClip(tempRgn); |
DisposeRgn(tempRgn); |
} /* end DrawClip */ |
void ClipClick(WindowPtr twindow) |
{ /* nothing happens on a clipboard click, it's in here for whenever I put scroll bars in */ |
#pragma unused (twindow) |
} /* end ClipClick */ |
/* Closes the clipboard window and takes it off the window menu */ |
/* Remember, however, it isn't dead. If there is a section on the */ |
/* clipboard it can still get updated */ |
void CloseClip(WindowPtr inWind) |
{ |
#pragma unused (inWind) |
WindowPtr clipWind = FindClipWindow(); |
Str63 menuText; |
if (((WindowPeek)clipWind)->visible) { |
HideWindow(clipWind); |
DeleteFromWindowMenu(clipWind); |
if (FrontWindow() != nil) |
ChangePlane(FrontWindow()); |
/* change the menu string to read 'Show Clipboard' */ |
GetIndString(menuText, kGeneralStrings, kShowClipString); |
SetMenuItemText(gEditMenuHandle, kClapNum, menuText); |
} |
} /* end CloseClip */ |
void SizeClip(WindowPtr windowIn) |
{ |
#pragma unused (windowIn) |
} /* end SizeClip */ |
/* UpdateScrap reads in the current scrap, and makes a picture from it */ |
/* It will also cause the clipboard window to redraw if it's visible */ |
void UpdateScrap(Boolean refreshIt) |
{ |
/* The 'refreshIt' variable is there to indicate if the window should be */ |
/* invalidated or not. I added this so this routine can safely */ |
/* be called from the drawing procedure without fear of nverending updates */ |
Handle textData; |
long myOffset; |
long length; |
textData = NewHandle(0); |
if (gClipHasContents == kClipHasSub) { |
} else { |
/* show standard scrap types, prefering pictures */ |
length = GetScrap(gScrapData, 'PICT', &myOffset); |
if (length < 0) { |
if (length == noTypeErr) { |
length = GetScrap(textData, kGenericTEXTWord, &myOffset); |
/* if it's text, I'm going to make it into a picture for my clipboard display, makes things */ |
/* easier in my draw proc */ |
if (length > 0) { |
DisposeHandle(gScrapData); /* kill the old one */ |
gScrapData = (Handle)OpenPicture(&FindClipWindow()->portRect); |
HLock(textData); |
TETextBox(*textData, length, &(FindClipWindow())->portRect, teJustLeft); |
HUnlock(textData); |
ClosePicture(); |
gClipHasContents = kClipHasText; |
} |
} else { /* another type of error, like nothing available at all */ |
MySetHandleSize(gScrapData, 0); |
gClipHasContents = kClipEmpty; |
} |
} else { |
/* set the pict rect so it's in the upper left of our clipboard */ |
gClipHasContents = kClipHasPict; |
OffsetRect(&((*(PicHandle)gScrapData))->picFrame, (((*(PicHandle)gScrapData))->picFrame.left * -1), |
(((*(PicHandle)gScrapData))->picFrame.top * -1) + 11); |
} |
} |
DisposeHandle(textData); |
if (refreshIt && ((WindowPeek)FindClipWindow())->visible) { |
/* if we want it refreshed, force an update */ |
WindowPtr temp; |
GetPort(&temp); |
SetPort(FindClipWindow()); |
InvalRect(&(FindClipWindow())->portRect); |
SetPort(temp); |
} |
} |
/* end updatescrap */ |
/* SpitClip spits our private subscription out to the general clipboard as a PICT type scrap */ |
/* when we go in the background. Does nothing if it's not a subscription, since it'll already */ |
/* be right. */ |
void SpitClip(void) |
{ |
if (gClipHasContents == kClipHasSub) { |
ZeroScrap(); |
HLock(gScrapData); |
PutScrap(GetHandleSize(gScrapData), 'PICT', *gScrapData); |
} |
} /* end spitclip */ |
/* Handy little routine to find and return a pointer to the clipboard, visible or not */ |
WindowPtr FindClipWindow(void) |
{ |
WindowPtr twindow = (WindowPtr)LMGetWindowList(); |
while (twindow) { |
if (((WindowPeek)twindow)->windowKind == kClipboardWindow) |
return(twindow); |
twindow = (WindowPtr)((WindowPeek)twindow)->nextWindow; |
} /* end of windows while */ |
return(nil); /* should never reach here */ |
} /* end FindClipWindow */ |
/* AppleEvent Status Window routines */ |
/* Changes the visiblility state of the AEStatus window */ |
void ToggleAEWindow(void) |
{ |
WindowPtr oldFront = FrontWindow(); |
Str63 menuText; |
short tempShort; |
if(!IsModalFront()){ |
WindowPtr AEWind = FindAEWindow(); /* find it */ |
if (((WindowPeek)AEWind)->visible) { /* if it's visiblem hide it */ |
HideWindow(AEWind); |
DeleteFromWindowMenu(AEWind); /* and remive it from the menu */ |
tempShort = kShowAEString; |
} else { |
ShowWindow(AEWind); /* show the thing */ |
AddToWindowMenu(AEWind, nil); /* add it's name to the window menu */ |
if(oldFront)ChangePlane(AEWind); /* bring it forward */ |
tempShort = kHideAEString; |
} |
/* get the correct text for the 'Show/Hide AEWindow' menu item */ |
GetIndString(menuText, kGeneralStrings, tempShort); |
SetMenuItemText(gAppleEventMenuHandle, kShowAEWind, menuText); |
} |
} /* end ToggleAEWindow */ |
/* Handy little routine for finding the AEStatus window, visible or not */ |
WindowPtr FindAEWindow(void) |
{ |
WindowPtr twindow = (WindowPtr)LMGetWindowList(); |
while (twindow) { |
if (((WindowPeek)twindow)->windowKind == kAEStatusWindow) |
return(twindow); |
twindow = (WindowPtr)((WindowPeek)twindow)->nextWindow; |
} |
return(nil); /* should never reach here */ |
} /* end FindAEWindow */ |
/* Draws the AEStatus window */ |
void DrawAES(windowCHandle theWind, WindowPtr windowIn) |
{ |
Rect theRect; |
RgnHandle tempRgn; |
theRect = windowIn->portRect; |
TEUpdate(&theRect, (*theWind)->boxHandle); |
theRect.top = theRect.bottom - 15; |
theRect.left = theRect.right - 15; |
tempRgn = NewRgn(); |
GetClip(tempRgn); |
ClipRect(&theRect); |
DrawGrowIcon(windowIn); |
SetClip(tempRgn); |
DisposeRgn(tempRgn); |
} /* end DrawAES */ |
/* Handles a click in the AEStatus window, by doing a TEClick */ |
void ClickAES(WindowPtr twindow) |
{ |
windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow); |
Rect theRect = twindow->portRect; |
SetPort(twindow); |
GlobalToLocal(&gERecord.where); |
TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*tempWCH)->boxHandle); |
} /* end ClickAES */ |
/* CloseAES doesn't close the window, just makes it invisible */ |
void CloseAES(WindowPtr inWind) |
{ |
#pragma unused (inWind) |
WindowPtr aeWind = FindAEWindow(); |
Str32 menuText; |
if (((WindowPeek)aeWind)->visible) { |
HideWindow(aeWind); |
DeleteFromWindowMenu(aeWind); |
if (FrontWindow() != nil) |
ChangePlane(FrontWindow()); |
/* and change the menu text */ |
GetIndString(menuText, kGeneralStrings, kShowAEString); |
SetMenuItemText(gAppleEventMenuHandle, kShowAEWind, menuText); |
} |
} /* end CloseAES */ |
void AESKey(char theKey, windowCHandle tempWC) |
{ |
TEKey(theKey, (*tempWC)->boxHandle); |
} /* end AESKey */ |
/* Resize the AES window */ |
/* When resizing TextEdit records, I always destroy and recreate them in */ |
/* their new size, instead of mucking around with the rects. Simpler and safer */ |
void SizeAES(WindowPtr windowIn) |
{ |
Handle theText; |
Rect newRect; |
short selStart, selEnd; |
windowCHandle tempWCH = (windowCHandle)GetWRefCon(windowIn); |
/* recalculate the TE rectangle */ |
newRect = windowIn->portRect; |
newRect.right -= 16; |
/* Get the old text */ |
theText = (Handle)TEGetText((*tempWCH)->boxHandle); |
/* get the old selection range */ |
selStart = (*(*tempWCH)->boxHandle)->selStart; |
selEnd = (*(*tempWCH)->boxHandle)->selEnd; |
/* copy the old text */ |
HandToHand(&theText); |
/* kill the TERecord */ |
TEDeactivate((*tempWCH)->boxHandle); |
TEDispose((*tempWCH)->boxHandle); |
/* recreate it in it's new size */ |
(*tempWCH)->boxHandle = TENew(&newRect, &newRect); |
/* and do all the housekeeping associated with a new TERecord */ |
TEAutoView(true, (*tempWCH)->boxHandle); |
HLock((Handle)theText); |
TESetText((Ptr)*theText, GetHandleSize((Handle)theText), (*tempWCH)->boxHandle); |
TECalText((*tempWCH)->boxHandle); |
DisposeHandle((Handle)theText); |
TEActivate((*tempWCH)->boxHandle); |
TESetSelect(selStart, selEnd, (*tempWCH)->boxHandle); |
TEUpdate(&newRect, (*tempWCH)->boxHandle); |
} /* end SizeAES */ |
/* The next few routines add text to the AEStatus window, in various ways */ |
void AddToAEWindow(Ptr text, long count) |
{ |
WindowPtr tempW = FindAEWindow(); |
WindowPtr temp; |
windowCHandle tempWCH = (windowCHandle)GetWRefCon(tempW); |
GetPort(&temp); |
/* No matter what, if we're adding text we want the window to be visible, even if */ |
/* it's not frontmost */ |
if (!((WindowPeek)tempW)->visible) { |
ToggleAEWindow(); |
} |
/* if it's your preference to see the window any time something happens, it comes forward here */ |
if (gPreferences.bringAEUp && FrontWindow() != tempW && !IsModalFront()) |
ChangePlane(tempW); /* bring it forward if you want */ |
SetPort(tempW); |
/* move to the end of the record */ |
TESetSelect(32000, 32000, (*tempWCH)->boxHandle); |
/* add the text */ |
TEInsert(text, count, (*tempWCH)->boxHandle); |
SetPort(temp); |
} /* end AddToAEWindow */ |
/* routine to add a number easily */ |
void AddAENum(long theNum) |
{ |
Str31 theString; |
NumToString(theNum, theString); |
AddToAEWindow(&theString[1], theString[0]); |
} /* end AddAENum */ |
/* routine to add a PString easily */ |
void AddAEText(ConstStr255Param theText) |
{ |
AddToAEWindow(&theText[1], theText[0]); |
} /* end AddAEText */ |
/* This routine is called when the user selects a window from the Windows menu */ |
/* it gets the item text, then finds the window that matches it and */ |
/* makes it frontmost */ |
void WindowToFront(short which,Str63 name) |
{ |
Str63 tempTitle; |
Str63 otherName; |
WindowPtr frontW = FrontWindow(); |
if (!frontW) |
return; |
if(name == nil){name = &otherName; |
GetMenuItemText(gWindowMenuHandle, which, name); |
} |
do { |
GetWTitle(frontW, tempTitle); |
if (EqualString(name, tempTitle, false, false)) { |
break; |
} else { |
frontW = (WindowPtr)((WindowPeek)frontW)->nextWindow; |
} |
} |
while (frontW); |
if (frontW) |
ChangePlane(frontW); |
} /* end WindowToFront */ |
/* Adds the input window title to the window list. If it was there */ |
/* in an old incarnation, it replaces the old text with the new name */ |
/* (like when a user saves the file, or does a 'save as' */ |
void AddToWindowMenu(WindowPtr theWindow, const Str255 oldName) |
{ |
short count = CountMItems(gWindowMenuHandle); |
Str255 wTitle; |
Str255 theItem; |
short iCount = 0; |
GetWTitle(theWindow, wTitle); |
/* if the window already existed, change an existing menu item */ |
if (oldName) { |
do { |
iCount++; |
GetMenuItemText(gWindowMenuHandle, iCount, theItem); |
if (EqualString(theItem, oldName, false, false)) |
break; |
} |
while (true); |
SetMenuItemText(gWindowMenuHandle, iCount, wTitle); |
} else { |
count++; |
InsertMenuItem(gWindowMenuHandle, wTitle, count); |
} |
} /* end AddToWindowMenu */ |
/* take this window off the window menu, for whatever reason */ |
void DeleteFromWindowMenu(WindowPtr theWindow) |
{ |
register qq; |
Str63 item, name; |
short count = CountMItems(gWindowMenuHandle); |
GetWTitle(theWindow, name); |
for (qq = 1; qq < count + 1; qq++) { |
GetMenuItemText(gWindowMenuHandle, qq, &item); |
if (EqualString(item, name, false, false)) { |
DeleteMenuItem(gWindowMenuHandle, qq); |
} |
} |
} /* end DeleteFromWindowMenu */ |
/* CheckExisting is called from our file opener to see if this file */ |
/* is already open */ |
Boolean CheckExisting(FSSpecPtr newSpec) |
{ |
Boolean openNow = false; |
/* check against all the open windows */ |
WindowPtr tempWindow = FrontWindow(); |
FSSpec tempSpec; |
Boolean wasCh; |
windowCHandle tempWC; |
while(tempWindow){ |
if(((WindowPeek)tempWindow)->windowKind == kDocumentWindow){ |
tempWC = (windowCHandle)GetWRefCon(tempWindow); |
if(GetHandleSize((Handle)(*tempWC)->fileAliasHandle)){ |
ResolveAlias(nil,(*tempWC)->fileAliasHandle,&tempSpec,&wasCh); |
openNow = CompareFSSpecs(&tempSpec,newSpec); |
if(openNow)break; |
} |
} |
tempWindow = (WindowPtr)((WindowPeek)tempWindow)->nextWindow; |
} |
return(openNow); |
} /* end CheckExisting */ |
#undef __MYWINDOWS__ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14