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.
Subscribe.c
/*------------------------------------------------------------------------------ |
* |
* Apple Developer Technical Support |
* |
* Edition subscribing routines |
* |
* Program: AEObject-Edition Sample |
* File: Subscribe.c - C Source |
* |
* by: C.K. Haun <TR> |
* |
* Copyright © 1990-1992 Apple Computer, Inc. |
* All rights reserved. |
* |
*------------------------------------------------------------------------------ |
* This file handles the Subscribe section of the program. It also handles some of |
* the common use routines, like the section options dialog. |
*----------------------------------------------------------------------------*/ |
#define __SUBSCRIBE__ |
#pragma segment Subscribe |
#include "Sampdefines.h" |
/* this point tells EM to center our expanded box, if we're using that feature */ |
Point expPoint = |
{ |
-1, -1 |
}; |
/* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */ |
/* subscribe to a PICT type edition, anywhere, anytime. It also stores the */ |
/* section handle returned in the window data structure for the current window */ |
/* You can only subscribe to TEXT if you have a text box open in the current window. */ |
/* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */ |
/* subscribe to that as such, same as you would with clipboard types. */ |
void DoSubscribe(void) |
{ |
OSErr myErr; |
SectionHandle secHandle; |
windowCHandle shortName; |
NewSubscriberReply GetSub; |
shortName = (windowCHandle)GetWRefCon(FrontWindow()); /* get our struct */ |
GetSub.formatsMask = kPICTformatMask; /* tell the dialog we only want PICT type editions */ |
if ((*shortName)->boxHandle != nil) /* is there a text box already? */ |
GetSub.formatsMask += kTEXTformatMask; |
/* GetLastEditionContainerUsed gives you either the last edition container used */ |
/* (either pub or sub, since they are the same to the Edition Manager) or if there */ |
/* was not a previous container, it fills it with a default container. */ |
GetLastEditionContainerUsed(&GetSub.container); |
/* Now ask the user to select an edition to subscribe to */ |
if (!gExpanded) |
myErr = NewSubscriberDialog(&GetSub); |
else |
{ |
ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook); |
ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter); |
myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, dhUPP, mfUPP, nil); |
DisposeRoutineDescriptor(mfUPP); |
DisposeRoutineDescriptor(dhUPP); |
} |
if (myErr != noErr) { /* bail on fail */ |
ShowMe("\pNewSubscriberDialog", myErr, __LINE__); |
return; |
} |
if (GetSub.canceled) /* did they cancel the dialog? */ |
return; |
HLock((Handle)shortName); |
/* Now create a new section record for the container the user picked. In other words, the */ |
/* Edition manager keeps track of things by the container, and will give you a section */ |
/* record that refers to it for you to keep track with. */ |
/* ¥¥¥ NOTE: Whenever the Edition Manager gives you memory (like the section handle) */ |
/* it came out of your heap, and YOU are responsible for disposing of it when you are */ |
/* completely done (and have UnRegistered) the section. If you're not careful about this */ |
/* then you'll get creeping memory loss. */ |
/* Now see if the window has ever been saved. If so, we can store a reference to */ |
/* the file in the section */ |
if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) { |
myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle); |
} else { |
/* if the file has been saved once, then we can store a reference to the 'parent' file */ |
/* in the edition */ |
FSSpec tempSpec; |
Boolean myWasChanged; |
myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged); |
myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, |
&secHandle); |
} |
if (myErr != noErr) { |
ShowMe("\pNewSection", myErr, __LINE__); |
return; |
} |
/* section successfully gotten. Add it to the current window section list please */ |
/* Handle this in whatever way is appropriate for your application, of course. */ |
/* The main point to remember is that you _must_ keep track of the section handles, */ |
/* they are your method (only method) for comunication between your application */ |
/* and the Edition Manager, you will be passing sections to the EM, and it will be */ |
/* passing them back to you. */ |
gSectionID++; /* increment our unique ID */ |
StoreSubscriber(shortName, secHandle, nil, nil); |
HUnlock((Handle)shortName); |
} |
/* end DoSubscribe */ |
/* DoOptions handles the SectionOptions menu selection. The handle passed */ |
/* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */ |
/* out what dialog to display by looking at the section record */ |
/* ¥¥¥ BE CAREFUL with the section handle you pass to the options dialog (or anywhere, for that matter) */ |
/* A section that has not been registered, or a section containing a bad alias handle, will */ |
/* cause the options dialog to blow up in unusual and fun ways */ |
/* This call also includes the expanded section options dialog box with one */ |
/* extra item, to show how it's used. */ |
void DoOptions(SectionHandle inSection) |
{ |
OSErr myErr; |
SectionOptionsReply oreply; |
Boolean subExpansion; |
oreply.sectionH = inSection; /* put the section passed in the reply record */ |
if ((*inSection)->kind == stSubscriber) |
subExpansion = true; |
else |
subExpansion = false; |
myErr = IsRegisteredSection(inSection); |
if (myErr != noErr) { |
ShowMe("\p Bad Section ", myErr, __LINE__); |
return; |
} |
if (subExpansion) { |
ExpDlgHookUPP dhUPP = NewExpDlgHookProc(SubExpOptHook); |
ExpModalFilterUPP mfUPP = NewExpModalFilterProc(SubExpOptFilter); |
myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, dhUPP, mfUPP, nil); |
DisposeRoutineDescriptor(dhUPP); |
DisposeRoutineDescriptor(mfUPP); |
} else { |
if (!gExpanded) |
myErr = SectionOptionsDialog(&oreply); /* run the dialog */ |
else |
{ |
ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook); |
ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter); |
myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, dhUPP, mfUPP, nil); |
DisposeRoutineDescriptor(dhUPP); |
DisposeRoutineDescriptor(mfUPP); |
} |
} |
if (myErr != noErr) { |
ShowMe("\pSection Options", myErr, __LINE__); |
return; |
} |
if (oreply.canceled) /* if user canceled */ |
return; |
if (oreply.action == sectionReadMsgID) { |
/* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */ |
/* one that gets called on a sect read AppleEvent */ |
MyReadSection(inSection); |
} else { |
if (oreply.action == sectionWriteMsgID) { |
/* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */ |
/* one that gets called on a sect writ AppleEvent */ |
MyUpdateEdition(inSection); |
} else { |
if (oreply.action == 'goto') { /* why isn't there a constant fo this? */ |
/* this is the sect scrl (section scroll) event from the dialog */ |
/* the dialog has already taken the action for you, that's it's job */ |
} else { |
if (oreply.action == emCancelSectionDialogRefCon) { |
/* This is for canceling a section, either pub or sub, you have to make the */ |
/* choice based on what the section is */ |
SectionType tempST; |
HLock((Handle)inSection); |
tempST = (*inSection)->kind; /* what kinda thing is this? */ |
HUnlock((Handle)inSection); |
MyCancelSection(inSection, FindSection(inSection)); |
} |
} |
} |
} |
} |
/* end DoOptions */ |
/* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */ |
/* AppleEvents of the type 'sect' 'read'. What this means is that whenever I get a */ |
/* high level event of the type 'sect' 'read' this routine will be dispatched to when I */ |
/* call AEProcessAppleEvent (in AppleEventM.c). This is where the actual section data */ |
/* gets read in, when the Edition Manager tells you the edition is ready to read */ |
pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (reply,refIn) |
SectionHandle theSection; |
OSErr myErr; |
myErr = GetSectionHandleFromEvent(messagein, &theSection); /* in AppleEventM.c */ |
if (myErr) { |
ShowMe("\pGetSectionHandleFromEvent", myErr, __LINE__); |
return(myErr); |
} |
/* This next step is very important. Unexpected things can happen to you, */ |
/* a section could disappear between the time an event gets posted and when it */ |
/* finally gets to your application (particularly since AppleEvents are the lowest in */ |
/* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */ |
/* whatever. You must make a current check with the EM to see if the section that */ |
/* you are supposed to read. */ |
myErr = IsRegisteredSection((SectionHandle)theSection); |
if (myErr) { |
ShowMe("\pRead IsRegisteredSection", myErr, __LINE__); |
return(myErr); |
} |
/* It is a valid section. Jump to my routine that opens and reads it */ |
MyReadSection(theSection); |
} |
/* end AEReadSectionHandler */ |
/* MyReadSection opens and reads the edition data into my window data structure. */ |
OSErr MyReadSection(SectionHandle theSection) |
{ |
OSErr myErr; |
EditionRefNum sRefNum=0; |
Size dataSize; |
Boolean existed = false; /* for setting the display rect */ |
/* open the edition and get a ref number */ |
SpinCursor(); |
myErr = OpenEdition(theSection, &sRefNum); |
if (myErr) { |
if(sRefNum)CloseEdition(sRefNum,true); |
ShowMe("\pOpenEdition", myErr, __LINE__); |
return(myErr); |
} |
/* Here we are double-checking the edition. I'm first checking for PICT data, */ |
/* and as a handy side effect, it gives us the size of the data (returned in my */ |
/* variable dataSize) for us to use when we read it later */ |
if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))) { |
/* It does have a pict, read it in */ |
register jj; /* loop vars for window search */ |
long subIDtofind; |
/* There is already a handle allocated for this picture in the window structure. |
* Find it, resize it (since the edition size could have changed) and fill it. |
* Keep in mind that the section read may happen for a window which is not |
* frontmost, so we need to search all the windows to find the ID */ |
WindowPtr tempPort; |
Boolean secFound = false; |
SectionHandle *tempPtr; |
SectionRecord *tempRecord; |
Handle tempHandle; |
WindowPtr tempNextWindow; |
Rect *tempRect; |
Rect holdRect; |
SpinCursor(); |
HLock((Handle)theSection); |
subIDtofind = (*theSection)->sectionID; /* what ID are we reading? */ |
/* check to see if this is the clipboard's section. If so, let the clipboard */ |
/* handle it */ |
if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil)){ |
return(ReadClipSection(dataSize, sRefNum)); |
} |
GetPort(&tempPort); /* save the current port */ |
/* search window list now */ |
tempNextWindow = (WindowPtr)LMGetWindowList(); /* start at the beginning of the chain */ |
while (tempNextWindow) { |
SpinCursor(); |
if (((WindowPeek)tempNextWindow)->windowKind == kDocumentWindow) { |
windowCHandle tempWC; |
/* do housekeeping to get to the section handle list */ |
tempWC = (windowCHandle)GetWRefCon(tempNextWindow); |
HLock((Handle)tempWC); |
tempHandle = (*tempWC)->subs; /* handle containing SectionHandles */ |
HLock(tempHandle); |
tempPtr = (SectionHandle *)*tempHandle; |
/* Loop through all our sections until we find this edition */ |
for (jj = 0; jj < (*tempWC)->numSubs; jj++) { |
Handle *newTemp; |
SpinCursor(); |
HLock((Handle)*tempPtr); |
tempRecord = *(*tempPtr); |
if (tempRecord->sectionID == subIDtofind) { |
/* found the section belonging to this read. */ |
/* can't break, since it is conceiveable that the user has more that one subscription in this document */ |
SetPort(tempNextWindow); /* set the port to the window we found the section in */ |
HLock((*tempWC)->subDataHandle); |
newTemp = (Handle *)*((*tempWC)->subDataHandle); |
newTemp += jj; |
/* if the dataSize returned was -1 then the size was unknown when opened. */ |
/* in this case, this should only happen with our special opener. */ |
/* So, if it is -1, then we'll have to handle the read */ |
/* in a series of steps to get the right amount of data */ |
/* For now, I'll leave that out until I put in a custom */ |
/* opener. Watch this space */ |
if (dataSize != -1) { |
HUnlock(*newTemp); |
MySetHandleSize(*newTemp, dataSize); |
HLock(*newTemp); |
} |
SpinCursor(); |
/* read the pict in */ |
myErr = MyReadEditionData(**newTemp, kGenericPICTWord, sRefNum, &dataSize); |
/* ¥¥¥¥¥ NOTE: After much discussion with our Human Interface folks and the */ |
/* Edition Manager engineer, we've decided that the interface guidelines */ |
/* for editions will say that reading a subscription does _not_ dirty */ |
/* a document. A lot of soul-searching went on to make this decision, and */ |
/* we decided this way primarily to keep the user from getting confused. */ |
/* Editions should be as transparent and automatic as possible, and reminding */ |
/* the user that an edition is a 'special' thing that they have to do */ |
/* unusual things with to make work right will remove some of that */ |
/* automation. Of course, the 'cached' version of the subscription that */ |
/* you save with the document should be updated when the subscription changes */ |
/* So, the following line was commented out. */ |
/* (*tempWC)->windowDirty = true; */ |
/* mark window dirty on every read */ |
holdRect = (*(PicHandle)(*newTemp))->picFrame; |
HUnlock(*newTemp); |
/* put the picture in the corner, if it didn't exist. If it did, adjust the rect as |
* required */ |
HLock((*tempWC)->subRects); |
newTemp = (Handle *)*((*tempWC)->subRects); |
newTemp += jj; |
/* if the handle is the size of a rect, I've seen this edition before */ |
if (GetHandleSize(*newTemp) == sizeof(Rect)) { |
existed = true; /* it's already been made */ |
} else { |
HUnlock(*newTemp); |
MySetHandleSize(*newTemp, sizeof(Rect)); /* new subscription */ |
} |
HLock(*newTemp); |
tempRect = (Rect *)*(*newTemp); |
if (!existed) { |
tempRect->top = tempRect->left = 0; |
tempRect->bottom = holdRect.bottom - holdRect.top; |
tempRect->right = holdRect.right - holdRect.left; |
} else { |
InvalRect(tempRect); /* refresh the old image if the thing was resized */ |
/* tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top); |
tempRect->right = tempRect->left + (holdRect.right - holdRect.left); |
*/ |
} |
InvalRect(tempRect); |
HUnlock(*newTemp); |
HUnlock((Handle)*tempPtr); |
} else { |
HUnlock((Handle)*tempPtr); |
tempPtr += 1; |
} |
} /* section handle loop jj */ |
HUnlock(tempHandle); |
HUnlock((Handle)tempWC); |
/* ¥¥¥ NOTE: You'll notice that there is no break or exit from this section searching loop */ |
/* Why? Because there may be many subscribers to the same edition. The user may */ |
/* have multiple subscribtions in the same window, or in any of his or her windows. */ |
/* Don't assume that there is only one subscriber (unless you require it, which may be */ |
/* reasonable for a single document but _not_ for a multi-document application), run */ |
/* your whole list each time to be certain everything gets refreshed */ |
} /* if document */ |
SpinCursor(); |
tempNextWindow = (WindowPtr)((WindowPeek)tempNextWindow)->nextWindow; |
} /* window loop qq */ |
SetPort(tempPort); /* reset the port to what it was when we entered */ |
} else { |
if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericTEXTWord, &dataSize))) { |
WindowPtr theWindow; |
windowCHandle tempWC; |
TEHandle tempTEH; |
mySectionDataHandle theTES; |
long tempStart, tempEnd; |
SpinCursor(); |
/* it's a text subscription. That means we search in the text path, and also need */ |
/* to update the TEHandle for the window this goes with */ |
theWindow = FindSection(theSection); |
theTES = TextSectionFromSecHandle(theSection); |
HLock((Handle)theTES); |
tempWC = (windowCHandle)GetWRefCon(theWindow); |
tempTEH = (*tempWC)->boxHandle; |
/* save the current TE selection range so that the user is returned to the */ |
/* place he or she was before we did the reading, so the text doesn't jump */ |
/* around all loony on them */ |
tempStart = (*tempTEH)->selStart; |
tempEnd = (*tempTEH)->selEnd; |
/* first thing we need to do is remove whatever the current sub data in our */ |
/* TE Record is. if there is any, o'course */ |
if ((*theTES)->startChar != (*theTES)->endChar) { |
TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH); |
TEDelete(tempTEH); |
} |
SetHandleSize((*theTES)->additionalData, dataSize); |
HLock((*theTES)->additionalData); |
MyReadEditionData(*(*theTES)->additionalData, kGenericTEXTWord, sRefNum, &dataSize); |
SpinCursor(); |
/* that gives us the text. Now we need to adjust our endpoint */ |
(*theTES)->endChar = ((*theTES)->startChar) + dataSize; |
/* set insertion point to where we want to be */ |
TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH); |
TEInsert(*(*theTES)->additionalData, dataSize, tempTEH); |
HUnlock((*theTES)->additionalData); |
HUnlock((Handle)theTES); |
/* reset insertion point to what it once was */ |
TESetSelect(tempStart, tempEnd, tempTEH); |
} |
} |
} |
/* end MyReadSection */ |
OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch) |
{ |
OSErr myErr; |
if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch)) |
CloseEdition(readRef, false); |
else |
CloseEdition(readRef, true); |
if(myErr)ShowMe("\p reading error",myErr,0); |
return(myErr); |
} |
/* HandleSectionSave handles saving and closing of subscribers for */ |
/* a document. The Boolean flags tell this function wheither to write */ |
/* ouut the data [on save or save/close] and weither to UnRegister */ |
/* the sections [on close]. */ |
/* The resource fork is open on entry. */ |
/* theWind is locked on entry */ |
void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec) |
{ |
SectionHandle *theSections; |
Handle *newTemp; |
SectionRecord secRec; |
Handle tempHandle; |
Rect *tempRectPtr; |
register qq; |
OSErr myErr; |
if ((*theWind)->numSubs) { |
Handle *tempPictPtr; |
HLock((*theWind)->subs); |
theSections = (SectionHandle *)*(*theWind)->subs; |
/* and display rectangles */ |
HLock((*theWind)->subRects); |
HLock((*theWind)->subDataHandle); |
newTemp = (Handle *)*((*theWind)->subRects); |
tempPictPtr = (Handle *)*((*theWind)->subDataHandle); |
/* loop through the sections */ |
for (qq = 0; qq < (*theWind)->numSubs; qq++) { |
SpinCursor(); |
/* first update (or create, if needed, the Ed Manger will know) the alias */ |
myErr = AssociateSection(*theSections, theSpec); |
if (myErr) |
ShowMe("\p Assocate", myErr, __LINE__); |
/* write the section handle out... */ |
if (writeEm) { |
tempHandle = (Handle)*theSections; |
HandToHand(&tempHandle); |
HLock((Handle)*theSections); /* lock down the original section so we can work with it */ |
secRec = *(*(*theSections)); /* just for easier display below */ |
AddResource(tempHandle, rSectionType, secRec.sectionID, ""); |
/* now do the same with the alias record please */ |
tempHandle = (Handle)secRec.alias; |
HandToHand(&tempHandle); |
AddResource(tempHandle, rAliasType, secRec.sectionID, ""); |
HUnlock((Handle)*theSections); |
/* save off the display rect for this sub */ |
tempHandle = *newTemp; |
HandToHand(&tempHandle); |
AddResource(tempHandle, kRECTType, secRec.sectionID, ""); |
/* and save out the picture data, so we don't need to immediatly do a */ |
/* section read when the file is opened */ |
tempHandle = *tempPictPtr; |
HandToHand(&tempHandle); |
AddResource(tempHandle, kGenericPICTWord, secRec.sectionID, ""); |
} /* writeEm if */ |
if (dereg) { |
UnRegisterSection(*theSections); |
/* and dispose of the alias handle */ |
DisposeHandle((Handle)*(*(*theSections))->alias); |
/* and the section handle */ |
DisposeHandle((Handle)*theSections); |
/* and the rectangle handle */ |
DisposeHandle((Handle)*newTemp); |
/* picture handle disposed in closewindow */ |
} |
theSections += 1; /* go to next section handle please */ |
newTemp += 1; /* and next rectangle */ |
} |
HUnlock((*theWind)->subRects); |
HUnlock((*theWind)->subs); |
} /* end subscriber save section */ |
/* now do the same thing for our publishers please */ |
/* Of course, here you'll also write the data if pumAutomatic is set */ |
if ((*theWind)->numPubs) { |
SpinCursor(); |
HLock((*theWind)->pubs); |
theSections = (SectionHandle *)*(*theWind)->pubs; |
/* and display rectangles */ |
HLock((*theWind)->pubRects); |
tempRectPtr = (Rect *)*((*theWind)->pubRects); |
/* loop through the sections */ |
for (qq = 0; qq < (*theWind)->numPubs; qq++) { |
SpinCursor(); |
/* first update (or create, if needed, the Ed Manger will know) the alias */ |
AssociateSection(*theSections, theSpec); |
/* write the section handle out... */ |
if (writeEm) { |
tempHandle = (Handle)*theSections; |
HandToHand(&tempHandle); |
HLock((Handle)*theSections); /* lock down the original section so we can work with it */ |
secRec = *(*(*theSections)); /* just for easier display below */ |
AddResource(tempHandle, rSectionType, secRec.sectionID, ""); |
SpinCursor(); |
/* now do the same with the alias record please */ |
tempHandle = (Handle)secRec.alias; |
HandToHand(&tempHandle); |
AddResource(tempHandle, rAliasType, secRec.sectionID, ""); |
SpinCursor(); |
HUnlock((Handle)*theSections); |
/* save off the display rect for this pub */ |
tempHandle = NewHandle(sizeof(Rect)); |
PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect)); |
HandToHand(&tempHandle); |
AddResource(tempHandle, kRECTType, secRec.sectionID, ""); |
SpinCursor(); |
if (secRec.mode == pumOnSave) { |
MyUpdateEdition(*theSections); |
/* and indicate that this was saved with a document */ |
(*(*theSections))->refCon |= kSavedOnce; /* OR in our saved flag with type */ |
} |
} /* writeEm if for pubs */ |
if (dereg) { |
UnRegisterSection(*theSections); |
/* first see if this publisher has ever been saved with a document. If it hasn't */ |
/* then we'll delete it. */ |
if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) { |
OSErr myErr; |
FSSpec deleteSpec; |
Boolean myWasChanged; |
ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged); |
SpinCursor(); |
if (myErr = DeleteEditionContainerFile(&deleteSpec)) { |
ShowMe("\pDelete Editon", myErr, __LINE__); |
} |
} |
/* and dispose of the alias handle */ |
DisposeHandle((Handle)*(*(*theSections))->alias); |
/* and the section handle */ |
DisposeHandle((Handle)*theSections); |
} |
theSections += 1; /* go to next section handle please */ |
tempRectPtr += 1; /* and next rectangle */ |
} |
HUnlock((*theWind)->pubRects); |
HUnlock((*theWind)->pubs); |
} |
/* now save off any text sections in this document */ |
if ((*theWind)->textSections) { |
mySectionDataHandle tempTS = (*theWind)->textSections; |
do { |
SpinCursor(); |
tempHandle = (Handle)(*tempTS)->theSection; |
/* make sure the text is the latest */ |
RePackText(tempTS, (*theWind)->boxHandle); |
AssociateSection((SectionHandle)tempHandle, theSpec); |
if (writeEm) { |
HandToHand(&tempHandle); |
myErr = MemError(); |
if (myErr) |
ShowMe("\p memerr", myErr, __LINE__); |
HLock(tempHandle); /* lock down the original section so we can work with it */ |
secRec = *(*(SectionHandle)tempHandle); /* just for easier display below */ |
AddResource(tempHandle, rSectionType, secRec.sectionID, ""); |
SpinCursor(); |
/* save the alias */ |
tempHandle = (Handle)secRec.alias; |
HandToHand(&tempHandle); |
AddResource(tempHandle, rAliasType, secRec.sectionID, ""); |
SpinCursor(); |
/* now save a copy of my whole text record */ |
tempHandle = (Handle)tempTS; |
HandToHand(&tempHandle); |
/* use the same ID number as the section, make things easy */ |
/* zap any forward link in this, so StoreSection doesn't get */ |
/* confused when the section is read back in */ |
(*(mySectionDataHandle)tempHandle)->nextSection = nil; |
(*(mySectionDataHandle)tempHandle)->additionalData = nil; |
(*(mySectionDataHandle)tempHandle)->theSection = nil; |
AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, ""); |
/* and finally, the associated text */ |
tempHandle = (*tempTS)->additionalData; |
HandToHand(&tempHandle); |
AddResource(tempHandle, rMyTextBlock, secRec.sectionID, ""); |
SpinCursor(); |
if (secRec.kind == stPublisher && secRec.mode == pumOnSave) { |
MyUpdateEdition((*tempTS)->theSection); |
/* and indicate that this was saved with a document */ |
(*(*tempTS)->theSection)->refCon |= kSavedOnce; /* OR in our saved flag with type */ |
} |
} /* text writeem if */ |
if (dereg) { |
UnRegisterSection((SectionHandle)tempHandle); |
/* first see if this publisher has ever been saved with a document. If it hasn't */ |
/* then we'll delete it. */ |
if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) { |
OSErr myErr; |
FSSpec deleteSpec; |
Boolean myWasChanged; |
ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged); |
if (myErr = DeleteEditionContainerFile(&deleteSpec)) { |
ShowMe("\pSection Save Delete Editon", myErr, __LINE__); |
} |
} |
/* and dispose of the alias handle */ |
DisposeHandle((Handle)(*(SectionHandle)tempHandle)->alias); |
/* and the section handle */ |
DisposeHandle((Handle)tempHandle); |
} |
tempTS = (*tempTS)->nextSection; |
} |
while (tempTS); |
} |
} |
/* MyCancelSection cancels this section. It removes */ |
/* the section info from our window structure, and also de-registers the */ |
/* section with (from) the Edition Manager. If it's a publisher, it also */ |
/* deletes the edition file */ |
void MyCancelSection(SectionHandle inSection, WindowPtr theWindow) |
{ |
OSErr myErr; |
windowCHandle shortName; |
SectionHandle *tempPtr; |
Rect *tempRectPtr; |
register qq; |
FSSpec deleteSpec; |
Boolean myWasChanged; |
shortName = (windowCHandle)GetWRefCon(theWindow); |
HLock((Handle)shortName); |
/* first thing to do is deregister the thing */ |
UnRegisterSection(inSection); |
if ((*inSection)->kind == stPublisher) { /* only delete publishers */ |
ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged); |
if (myErr = DeleteEditionContainerFile(&deleteSpec)) { |
ShowMe("\pCancel Delete Editon", myErr, __LINE__); |
} |
} |
/* get rid of the alias handle for it */ |
DisposeHandle((Handle)(*inSection)->alias); |
if ((*inSection)->kind == stPublisher) { |
HLock((*shortName)->pubs); /* lock down my list of section handles */ |
tempPtr = (SectionHandle *)*(*shortName)->pubs; |
for (qq = 0; qq < (*shortName)->numPubs; qq++) { |
HLock((Handle)*tempPtr); |
if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) { |
DisposeHandle((Handle)inSection); |
DisposeHandle((Handle)(*(*tempPtr))->alias); |
DisposeHandle((Handle)*tempPtr); |
HLock((*shortName)->pubRects); |
tempRectPtr = (Rect *)*((*shortName)->pubRects); |
tempRectPtr += qq; |
if (qq != (*shortName)->numPubs) { |
register ii; /* need to move information down */ |
for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) { |
*tempPtr = *(tempPtr + 1); |
*tempRectPtr = *(tempRectPtr + 1); |
tempPtr += 1; |
tempRectPtr += 1; |
} |
} |
(*shortName)->numPubs--; |
HUnlock((*shortName)->pubs); |
MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle)); |
HUnlock((*shortName)->pubRects); |
MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect))); |
} |
} |
} else { /* it's a subscriber */ |
HLock((*shortName)->subs); /* lock down my list of section handles */ |
tempPtr = (SectionHandle *)*(*shortName)->subs; |
for (qq = 0; qq < (*shortName)->numSubs; qq++) { |
HLock((Handle)*tempPtr); |
if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) { |
SectionHandle removeSection; |
Handle *tempRectHand; |
Handle *tempPicHand; |
Handle *tempPicHand2; |
removeSection = (*tempPtr); |
HLock((Handle)removeSection); |
/* When the user cancels a subscription, you do NOT want to delete the */ |
/* current subscription data (the picture) at this time. Since the data should be */ |
/* selectable in the document they are working on (text in a text doc, pic in a */ |
/* pic doc, etc) they keep the last subscription data, and delete it */ |
/* seperatly if they'd like */ |
HLock((*shortName)->subRects); |
HLock((*shortName)->subDataHandle); |
tempRectHand = (Handle *)*((*shortName)->subRects); |
tempPicHand = (Handle *)*((*shortName)->subDataHandle); |
tempRectHand += qq; |
tempPicHand += qq; |
/* move the picture over, increase the handle by 1 */ |
(*shortName)->numPicts++; |
HUnlock((*shortName)->pictHandle); |
MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle))); |
HLock((*shortName)->pictHandle); |
tempPicHand2 = (Handle *)*(*shortName)->pictHandle; |
tempPicHand2 += ((*shortName)->numPicts) - 1; |
*tempPicHand2 = *tempPicHand; |
/* move the rect over also */ |
HUnlock((*shortName)->pictRects); |
MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle))); |
HLock((*shortName)->pictRects); |
tempPicHand2 = (Handle *)*(*shortName)->pictRects; |
tempPicHand2 += ((*shortName)->numPicts) - 1; |
*tempPicHand2 = *tempRectHand; |
HUnlock((*shortName)->pictRects); |
HUnlock((*shortName)->pictHandle); |
if ((qq + 1) != (*shortName)->numSubs) { |
register ii; /* need to move information down */ |
for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) { |
*tempPtr = *(tempPtr + 1); |
*tempRectHand = *(tempRectHand + 1); |
*tempPicHand = *(tempPicHand + 1); |
tempPtr += 1; |
tempRectHand += 1; |
tempPicHand += 1; |
} |
} |
(*shortName)->numSubs--; |
HUnlock((*shortName)->subs); |
MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle)); |
HUnlock((*shortName)->subRects); |
MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle))); |
} |
} |
} |
HUnlock((Handle)shortName); |
/* and clear the highlight */ |
if (gShowPub || gShowSub) { |
extern Rect gShowPubRect; |
extern Rect gShowSubRect; |
extern SectionHandle gShowingSecHandle; |
gShowPub = gShowSub = false; |
gShowingSecHandle = nil; |
InvalRect(&gShowPubRect); |
InvalRect(&gShowSubRect); |
} |
} |
/* end MyCancelSection */ |
void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn) |
{ |
OSErr myErr; |
SectionHandle *tempPtr; |
Handle *tempPicHand; |
Size dataSize; |
EditionRefNum sRefNum; |
/* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */ |
/* them differently for drill. */ |
myErr = OpenEdition(secHandle, &sRefNum); |
if (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize)) |
(*secHandle)->refCon |= kTextType; |
else |
(*secHandle)->refCon |= kPictType; |
/* Now that little mechanism could screw up, if the formats of the section have been */ |
/* changed since the subscription was originally created. But it'll work here */ |
CloseEdition(sRefNum, true); |
/* increase our section handle holding handle by the size of a handle */ |
if (((*secHandle)->refCon & 0xf) == kPictType) { |
HUnlock((*shortName)->subs); |
MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle)); |
HLock((*shortName)->subs); |
/* dereference the handle to our section handles in our window structure */ |
/* and cast it to a pointer to section handles, since that's what it contains */ |
tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs))); |
/* and store our subscriber section */ |
*tempPtr = (SectionHandle)secHandle; |
HUnlock((*shortName)->subs); /* let it float again */ |
/* Here I'm setting up a handle for the picture data contained in the edition we just */ |
/* subscribed to, in an array of handles held in the handle subDataHandle */ |
HUnlock((*shortName)->subDataHandle); |
MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle)); /* allocate */ |
HLock((*shortName)->subDataHandle); |
/* deref it */ |
tempPicHand = (Handle *)*((*shortName)->subDataHandle); |
tempPicHand += ((*shortName)->numSubs); |
if (pictIn == nil) |
*tempPicHand = NewHandle(0); /* set up a nil handleo */ |
else |
*tempPicHand = pictIn; |
/* ¥¥¥ NOTE: You do _NOT_ read the data contained in this section yet! */ |
/* All you have done is subscribed to it, the Edition Manager has not told you */ |
/* that you can read it! Wait for the section read event (see below) to get the */ |
/* data. SO I store an empty handle here as a placeholder */ |
MoveHHi(*tempPicHand); |
HUnlock((*shortName)->subRects); |
MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle))); /* allocate a new re*/ |
myErr = MemError(); |
if (myErr) |
ShowMe("\pMemory error ", myErr, __LINE__); |
HLock((*shortName)->subRects); |
/* generate an empty display rectangle handle also */ |
tempPicHand = (Handle *)*((*shortName)->subRects); |
tempPicHand += ((*shortName)->numSubs); |
if (inRect == nil) |
*tempPicHand = NewHandle(0); /* set up a nil handleo */ |
else |
*tempPicHand = inRect; |
MoveHHi(*tempPicHand); |
(*shortName)->numSubs++; /* increment our count of subscribers */ |
HUnlock((*shortName)->subRects); |
HUnlock((*shortName)->subDataHandle); |
} else { |
if (((*secHandle)->refCon & 0xf) == kTextType) { /* double checking here */ |
mySectionDataHandle newSection; |
/* get a new text section record */ |
if (inRect == nil) { |
/* this means that it is being created fresh, so we have to get a */ |
/* text section record from my routine */ |
newSection = GetTextSection(shortName, stSubscriber); |
/* fill it with stuff relating to the section we just created */ |
(*newSection)->publishing = false; |
(*newSection)->theID = (*secHandle)->sectionID; |
(*newSection)->theSection = secHandle; |
} else { |
newSection = (mySectionDataHandle)inRect; |
} |
/* store it in our window structure */ |
if ((*shortName)->textSections) { |
mySectionDataHandle tempSection = (*shortName)->textSections; |
if ((*shortName)->textSections) { |
while ((*tempSection)->nextSection) |
tempSection = (*tempSection)->nextSection; |
} |
(*tempSection)->nextSection = newSection; |
} else { |
/* first one */ |
(*shortName)->textSections = newSection; |
} |
} |
} |
} |
pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr) |
{ |
#pragma unused (yourDataPtr) |
short myHit; |
short itemType; |
ControlHandle theButton; |
Rect theRect; |
/* first make sure that a sub-dialog is not frontmost */ |
/* so we don't filter keys or hits to a sub-dialog */ |
if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) { |
/* first see if it's the 'first call' item (see the Standard File chapter). If it is, then */ |
/* we preset our check box */ |
if (itemHit == -1) { |
/* this gets the handle to our check box, since we know it's one past the last standard item */ |
GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect); |
SetControlValue(theButton, gResizeSub); /* and set our current value */ |
} else { |
/* only have one item in this expansion, but we'll check the range anyway to be safe */ |
myHit = itemHit - itemOffset; /* since our item numbers are relative to the total number */ |
/* of items in the dialog, and the system may change. Always do your item numbering based */ |
/* on the offset, this will prevent incompatability when the system dialog grows or shrinks */ |
if (myHit == 1) { /* I only added one item, so this be the one */ |
/* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */ |
/* additive dialog. It is counting from the actual start of the DITL, not the start of */ |
/* your custom items */ |
GetDialogItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect); |
if (GetControlValue(theButton)) |
gResizeSub = false; |
else |
gResizeSub = true; |
SetControlValue(theButton, gResizeSub); |
} |
} |
} |
return(itemHit); /* the return value must be absolute */ |
} |
pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr) |
{ |
#pragma unused (itemHit,yourDataPtr) |
short itemType; |
ControlHandle theButton; |
Rect theRect; |
/* first make sure that a sub-dialog is not frontmost */ |
/* so we don't filter keys or hits to a sub-dialog */ |
if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) { |
/* standard filter proc kinda stuff here */ |
if ((theEvent->what) == keyDown) { |
char tempChar; |
tempChar = theEvent->message & charCodeMask; |
if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) { |
/* they pressed an A with the command key down, we get to handle it. */ |
GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect); |
if (GetControlValue(theButton)) |
gResizeSub = false; |
else |
gResizeSub = true; |
SetControlValue(theButton, gResizeSub); |
return(true); /* tell folks we handled it */ |
} |
} |
} |
return(false); /* was not a keystroke we wanted */ |
} |
/* DeleteSubscriber is called by a menu command 'Clear' */ |
void DeleteSubscriber(void) |
{ |
ModalFilterUPP upp = NewModalFilterProc(standardAlertFilter); |
if (StopAlert(kCanxSub, upp) == 2) { |
MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle)); |
} |
DisposeRoutineDescriptor(upp); |
} |
/* end DeleteSubscriber */ |
/* PasteSubscription pastes the section (a subscriber) from the clipboard into the */ |
/* frontmost window (as you would expect) */ |
void PasteSubscription(void) |
{ |
windowCHandle tempWC; |
SectionHandle tempHandle; |
AliasHandle tempHandle2; |
FSSpec newFileSpec; |
Boolean myWasChanged; |
Rect tempPRect = { |
0, 0, 40, 40 |
}; |
long myOffset; |
long fred; |
Handle tempRectHand = NewHandle(sizeof(Rect)); |
/* first see if there is a section handle on the clipboard */ |
/* kill the current section on the clipboard, if there is one */ |
/* ¥¥¥¥ NEW, we're looking for section handles and aliases on the clipboard. */ |
/* set up a dummy picture for this incoming section.... */ |
if (!gScrapData) |
gScrapData = NewHandle(0); |
fred = GetScrap(gScrapData, rSectionType, &myOffset); |
if (fred > 0) { /* if there is a section on the clipboard */ |
myOffset = 0; |
/* read in the rect also */ |
fred = GetScrap(tempRectHand, kRECTType, &myOffset); |
if (fred > 0) { |
short offH, offV; |
/* move the rect to the upper left */ |
offH = (*(Rect *)*tempRectHand).right - (*(Rect *)*tempRectHand).left; |
offV = (*(Rect *)*tempRectHand).bottom - (*(Rect *)*tempRectHand).top; |
(*(Rect *)*tempRectHand).left = 0; |
(*(Rect *)*tempRectHand).top = 0; |
(*(Rect *)*tempRectHand).right = offH; |
(*(Rect *)*tempRectHand).bottom = offV; |
/* and read in the pict */ |
myOffset = 0; |
GetScrap((Handle)gClipPict, kGenericPICTWord, &myOffset); |
} else { |
*(Rect *)*tempRectHand = tempPRect; /* default it */ |
} |
} |
HLock(tempRectHand); |
tempWC = (windowCHandle)GetWRefCon(FrontWindow()); |
HLock((Handle)tempWC); |
if (gClipPict && GetHandleSize((Handle)gClipPict)) { |
InvalRect((Rect *)*tempRectHand); |
} else { |
*(Rect *)(*tempRectHand) = tempPRect; |
} |
/* update the ID of the section to include the master ID of the window yer pasting into */ |
(*gClipSection)->sectionID += (*tempWC)->windowID; |
StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict); |
HUnlock((Handle)tempWC); |
/* Now, after you paste the subscription, you have to change the subscription on the clipboard. */ |
/* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */ |
/* you could have two subscriptions with the same ID, which would not be nice. So we do this... */ |
tempHandle = gClipSection; |
tempHandle2 = (*gClipSection)->alias; |
HandToHand((Handle *)&tempHandle); |
HandToHand((Handle *)&tempHandle2); |
(*tempHandle)->sectionID = gSectionID; |
(*tempHandle)->alias = tempHandle2; |
gSectionID++; |
/* now register the section so the edition manager knows to send you updates */ |
ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged); |
if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr) |
gClipSection = tempHandle; |
gClipHasContents = kClipHasSub; |
MyReadSection(tempHandle); |
} |
/* CutSubscription and CopySubscription move the current selection in the active window to the */ |
/* ClipBoard. The main difference here from standard scrap handling is that the scrap you now */ |
/* have is dynamic. The contents of the clipboard can change if the publisher of this subscription */ |
/* changes, so you must treat this section as you would any other subscriber */ |
/* frontmost window (as you would expect) */ |
void CutSubscription(void) |
{ |
CopySubscription(); |
DeleteSubscriber(); /* even though they said cut, I want to make sure that they really mean it */ |
} |
/* CopySubscriber moves the current display subscriber to the clipboard, making a new */ |
/* subscription in the process, since we don't want to have two copies of the same thing */ |
void CopySubscription(void) |
{ |
SectionHandle tempHandle; |
AliasHandle tempHandle2; |
FSSpec newFileSpec; |
Boolean myWasChanged; |
/* First check to see if there is already a section to remove */ |
if (gClipHasContents == kClipHasSub) { |
KillClipSub(); |
} |
tempHandle = gShowingSecHandle; |
/* copy the alias also */ |
tempHandle2 = (*gShowingSecHandle)->alias; |
HandToHand((Handle *)&tempHandle); |
HandToHand((Handle *)&tempHandle2); |
/* create a unique ID for this section. I'll just use the next section ID */ |
(*tempHandle)->sectionID = gSectionID; |
(*tempHandle)->alias = tempHandle2; |
gSectionID++; |
/* now register the section so the edition manager knows to send you updates */ |
ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged); |
if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr) |
gClipSection = tempHandle; |
gClipPict = (PicHandle)NewHandle(0); /* allocate an empty handle for this picture data */ |
gClipHasContents = kClipHasSub; |
/* write the section handle out to the cipboard */ |
ZeroScrap(); |
PutScrap(sizeof(Handle), rSectionType, (Ptr)&tempHandle); |
PutScrap(sizeof(Rect), kRECTType, (Ptr)&gShowSubRect); |
MyReadSection(tempHandle); |
InitCursor(); /* set to watch by MyReadSection, would normally be reset next pass */ |
/* through the event loop, but NOT if it's being called by Cut, */ |
/* so I'll reset it just to be safe */ |
} |
OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum) |
{OSErr myErr = noErr; |
extern Handle gScrapData; |
MySetHandleSize((Handle)gClipPict, readIn); |
HLock((Handle)gClipPict); |
/* read the pict in */ |
myErr = MyReadEditionData((Ptr)*gClipPict, kGenericPICTWord, sRefNum, &readIn); |
HUnlock((Handle)gClipPict); |
gScrapData = (Handle)gClipPict; |
if (((WindowPeek)FindClipWindow())->visible) { |
WindowPtr temp; |
GetPort(&temp); |
SetPort(FindClipWindow()); |
InvalRect(&FindClipWindow()->portRect); |
SetPort(temp); |
} |
return(myErr); |
} |
/* This kills the current section on the clipboard, since it's being replaced */ |
/* and you don't want to receive events for it anymore */ |
void KillClipSub(void) |
{ |
UnRegisterSection(gClipSection); |
DisposeHandle((Handle)(*gClipSection)->alias); |
DisposeHandle((Handle)gClipSection); |
gClipSection = nil; |
gClipHasContents = kClipEmpty; |
if (GetHandleSize((Handle)gClipPict) != nil) |
KillPicture(gClipPict); |
} |
/* MyGoToPublisher is used if the user was holding down the Option key during a */ |
/* double click, to send them to the publisher without seeing the dialog box */ |
OSErr MyGoToPublisher(SectionHandle theSection) |
{ |
EditionInfoRecord theEdInfo; |
GetEditionInfo(theSection, &theEdInfo); |
return(GoToPublisherSection(&theEdInfo.container)); |
} |
/* Searches the subcriber list, hilites the selection, and drags it */ |
/* This is very similar to the publisher check, but has added functionality */ |
/* for dragging the subscriber around the window */ |
Boolean SearchSubs(Point thePoint) |
{ |
register qq; |
Str63 pubString; |
Handle *theRectsHandle; |
Boolean subGotIt = false; |
windowCHandle shortname = (windowCHandle)GetWRefCon(FrontWindow()); |
HLock((Handle)shortname); |
if ((*shortname)->numSubs) { /* does it have any subscribers? */ |
HLock((*shortname)->subRects); /* lock down the rect handle */ |
/* cast it as a pointer to handles for reading ease */ |
theRectsHandle = (Handle *)*(*shortname)->subRects; |
for (qq = 0; qq < (*shortname)->numSubs; qq++) { /* step through the subscribers */ |
SectionHandle *tempPtr; |
Rect *checkRect; |
Rect cornerRect; |
HLock(*theRectsHandle); |
checkRect = (Rect *)**theRectsHandle; |
/* did they click in this rect? */ |
InsetRect(checkRect, kNegFour, kNegFour); /* include the possible borders */ |
if (PtInRect(thePoint, checkRect)) { /* yes */ |
/* erase the old display rectangles, if there are any */ |
if (gShowSub){ |
InsetRect(&gShowSubRect, kNegFour, kNegFour); |
InvalRect(&gShowSubRect); |
InsetRect(&gShowSubRect, kFour, kFour); |
} |
gShowSub = true; |
if (gShowPub) { |
InvalRect(&gShowPubRect); |
gShowPub = false; |
} |
/* get the section handle for this section */ |
HLock((*shortname)->subs); |
tempPtr = (SectionHandle *)*(*shortname)->subs; |
tempPtr += qq; |
gShowingSecHandle = *tempPtr; |
HUnlock((*shortname)->subs); |
/* change the menu item name now */ |
GetIndString(pubString, kGeneralStrings, kSubOptString); |
SetMenuItemText(gEditMenuHandle, kSoptionsItem,pubString); |
InvalRect(checkRect); /* make sure it gets redrawn */ |
/* now I want the actual rect values so I can drag it around */ |
/* in response to the user */ |
gShowSubRect = *checkRect; |
PenPat(&qd.dkGray); |
PenSize(3, 3); |
FrameRect(&gShowSubRect); |
PenSize(1, 1); |
/* Here you drag the thing around to where the user wants it, updating the |
* window record as you do it. */ |
GetMouse(&thePoint); |
InvalRect(&gShowSubRect); |
/* two choices here. They could be dragging the whole thing, or resizing it. */ |
/* The resize box is in the lower right ten pixels, I'll say, so if the original */ |
/* click is there I'll go to the resize routine */ |
cornerRect = gShowSubRect; |
cornerRect.top = cornerRect.bottom - 7; |
cornerRect.left = cornerRect.right - 7; |
if (PtInRect(thePoint, &cornerRect) && gResizeSub) { |
PullRect(shortname, &gShowSubRect, false, true,true); |
} else { |
while (StillDown()) { /* keep doing it until they release the mouse */ |
Point tempPoint; |
PenMode(patXor); |
FrameRect(&gShowSubRect); /* nasty way to put up a flashing border for the drag */ |
FrameRect(&gShowSubRect); |
GetMouse(&tempPoint); |
/* keep inside the window please, don't let them drag the */ |
/* rectangle outside the window bounds */ |
if (PtInRect(tempPoint, &(FrontWindow()->portRect))) { |
if (tempPoint != thePoint) { |
OffsetRect(&gShowSubRect, tempPoint.h - thePoint.h, tempPoint.v - thePoint.v); |
thePoint = tempPoint; |
} |
} |
} |
PenMode(normal); |
} |
InvalRect(&gShowSubRect); |
InsetRect(checkRect, kFour, kFour); /* remember that ShowingRect is kFour bigger */ |
InsetRect(&gShowSubRect, kFour, kFour); /* remember that ShowingRect is kFour bigger */ |
if (gShowSubRect != *checkRect) { /* don't update if they didn't end up moving it */ |
*checkRect = gShowSubRect; /* update our record of things */ |
} |
subGotIt = true; |
} else { |
/* shrink it back agin */ |
InsetRect(checkRect, kFour, kFour); /* remember that ShowingRect is kFour bigger */ |
} |
HUnlock(*theRectsHandle); |
theRectsHandle += 1; /* increase by one Rect to check next */ |
if (subGotIt) |
break; |
} |
HUnlock((*shortname)->subRects); |
} |
HUnlock((Handle)shortname); |
return(subGotIt); |
} |
/* end SearchSubs */ |
#undef __SUBSCRIBE__ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14