home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-02 | 25.8 KB | 985 lines | [TEXT/MPCC] |
- // { WASTE PROJECT }
- // { Mouse Clicks and support for Drag and Drop }
-
- // { Copyright © 1993-1994 Marco Piovanelli }
- // { All Rights Reserved }
-
- #include "WASTEIntf.h"
- #include <Folders.h>
-
- static DragSendDataUPP WESendFlavorUPP = NULL;
-
- pascal OSErr _WEExtractFlavor(DragReference theDrag, ItemReference theItem,
- FlavorType theType, Handle *hFlavor)
- {
- Size theSize;
- OSErr err;
-
- *hFlavor = nil;
-
- // { get size of flavor data }
- err = GetFlavorDataSize(theDrag, theItem, theType, &theSize);
- if (err != noErr) return err;
-
- // { allocate a block that size }
- err = _WEAllocate(theSize, kAllocClear + kAllocTemp, hFlavor);
- if (err != noErr) return err;
-
- // { get the flavor }
- HLock(*hFlavor);
- err = GetFlavorData(theDrag, theItem, theType, *hFlavor, &theSize, 0);
- HUnlock(*hFlavor);
-
- return err;
- } // { _WEExtractFlavor }
-
- pascal Boolean _WEDragTastesGood(DragReference theDrag)
- {
- unsigned short dragItemIndex, numDragItems;
- ItemReference theItem;
- FlavorFlags theFlags;
- short objectIndex;
- OSType objectType;
- OSErr err;
-
- // { count items in this theDrag }
- err = CountDragItems(theDrag, &numDragItems);
- if (err != noErr) return false;
-
- for (dragItemIndex = 1; dragItemIndex <= numDragItems; dragItemIndex++)
- {
- // { get item reference number for current drag item }
- err = GetDragItemReferenceNumber(theDrag, dragItemIndex, &theItem);
- if (err != noErr) return false;
-
- // { see if this drag item contains a text flavor }
- err = GetFlavorFlags(theDrag, theItem, kTypeText, &theFlags);
- if (err == badDragFlavorErr)
- {
- // { see if this drag item contains a flavor matching one of the registered object types }
- objectIndex = 0;
- while (_WEGetIndObjectType(objectIndex, &objectType) == noErr)
- {
- err = GetFlavorFlags(theDrag, theItem, objectType, &theFlags);
- if (err != badDragFlavorErr)
- break; // { enclosing while }
- objectIndex = objectIndex + 1;
- } // { while }
- }
-
- if (err != noErr)
- return false;
- } // { for }
-
- return true;
-
- } // { _WEDragTastesGood }
-
- pascal void _WEUpdateDragCaret(long offset, WEHandle hWE)
- {
- long ticks;
- WEPtr pWE;
-
- // { the WE record must be already locked }
- pWE = *hWE;
-
- // { get current time }
- ticks = TickCount();
-
- if (offset == pWE->dragCaretOffset)
- {
-
- // { drag caret offset didn't change; blink the caret }
- if ((GetCaretTime() < ticks - pWE->caretTime) &&
- (offset != kInvalidOffset))
- {
- _WEDrawCaret(pWE->dragCaretOffset, hWE);
- pWE->flags = pWE->flags ^ BSL(1, weFDragCaretVisible);
- pWE->caretTime = ticks;
- }
- }
- else
- {
-
- // { drag caret offset did change }
- // { hide old caret, if it's showing }
- if (BTST(pWE->flags, weFDragCaretVisible))
- _WEDrawCaret(pWE->dragCaretOffset, hWE);
-
- // { show new caret (unless offset is kInvalidOffset) }
- if (offset != kInvalidOffset)
- {
- _WEDrawCaret(offset, hWE);
- BSET(pWE->flags, weFDragCaretVisible);
- pWE->caretTime = ticks;
- }
- else
- {
- BCLR(pWE->flags, weFDragCaretVisible);
- }
-
- // { remember drag caret offset }
- pWE->dragCaretOffset = offset;
- }
- } // { _WEUpdateDragCaret }
-
- pascal OSErr WETrackDrag(DragTrackingMessage theMessage,DragReference theDrag,
- WEHandle hWE)
- {
- WEPtr pWE;
- DragAttributes attributes;
- Point mouse;
- RgnHandle tmpRgn;
- LongPt thePoint;
- long offset, ticks;
- char edge;
- Boolean saveWELock;
- OSErr err;
- Point zeroPoint = {0, 0};
-
- // { lock the WE record }
- saveWELock = _WESetHandleLock((Handle)hWE, true);
- pWE = *hWE;
-
- // { dispatch on theMessage }
- switch(theMessage)
- {
- case dragTrackingEnterWindow:
- // { determine whether we can accept this drag }
- if (_WEDragTastesGood(theDrag))
- BSET(pWE->flags, weFCanAcceptDrag);
- else
- BCLR(pWE->flags, weFCanAcceptDrag);
-
- // { reset clickTime }
- pWE->clickTime = 0;
- break;
-
- case dragTrackingInWindow:
- if (BTST(pWE->flags, weFCanAcceptDrag))
- {
-
- // { get drag attributes }
- err = GetDragAttributes(theDrag, &attributes);
- if (err != noErr)
- goto cleanup;
-
- // { get current mouse location in local coordinates }
- err = GetDragMouse(theDrag, &mouse, &zeroPoint);
- if (err != noErr)
- goto cleanup;
- GlobalToLocal(&mouse);
-
- if (PtInRgn(mouse, pWE->viewRgn))
- {
- // { mouse is in text area }
- // { hilite the text rectangle, if we haven't already }
- // { and if the drag has left sender window since drag tracking started }
- if ((!BTST(pWE->flags, weFHilited)) &&
- (attributes & dragHasLeftSenderWindow) != 0)
- {
- tmpRgn = NewRgn();
- CopyRgn(pWE->viewRgn, tmpRgn);
- InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
- ShowDragHilite(theDrag, tmpRgn, true);
- DisposeRgn(tmpRgn);
- BSET(pWE->flags, weFHilited);
- }
-
- // { hide the caret }
- if (BTST(pWE->flags, weFCaretVisible))
- _WEBlinkCaret(hWE);
-
- // { get text offset corresponding to mouse location }
- WEPointToLongPoint(mouse, &thePoint);
- offset = WEGetOffset(&thePoint, &edge, hWE);
-
- // { if offset is within the original selection range, don't display drag feedback }
- if (theDrag == pWE->currentDrag)
- if (_WEOffsetInRange(offset, edge, pWE->selStart, pWE->selEnd))
- offset = kInvalidOffset;
-
- // { provide a drag feedback in the form of a blinking caret }
- _WEUpdateDragCaret(offset, hWE);
-
- // { clear clickTime }
- pWE->clickTime = 0;
- }
- else
- {
-
- // { mouse is outside text area }
- // { dehilite the text rectangle, if it's hilited }
- if (BTST(pWE->flags, weFHilited))
- {
- HideDragHilite(theDrag);
- BCLR(pWE->flags, weFHilited);
- }
-
- // { hide the drag caret, if it's showing }
- _WEUpdateDragCaret(kInvalidOffset, hWE);
-
- // { if the mouse has been remaining outside the view region for 10 ticks or more }
- // { and this drag was created by this WE instance, call the click loop routine }
- if (theDrag == pWE->currentDrag)
- {
- ticks = TickCount();
- if (pWE->clickTime == 0)
- pWE->clickTime = ticks;
- else if (ticks > pWE->clickTime + kAutoScrollDelay)
- if (pWE->clickLoop != nil)
- (*(WEClickLoopProcPtr)pWE->clickLoop)(hWE);
- }
- }
- }
- break; // { case dragTrackingInWindow }
-
- case dragTrackingLeaveWindow:
-
- // { drag has left this window }
- // { dehilite the text area if necessary }
- if (BTST(pWE->flags, weFHilited))
- {
- HideDragHilite(theDrag);
- BCLR(pWE->flags, weFHilited);
- }
-
- // { hide the drag caret, if it's showing }
- _WEUpdateDragCaret(kInvalidOffset, hWE);
-
- break;
-
- default:
- ;
- } // { case theMessage }
-
- // { clear result code }
- err = noErr;
-
- cleanup:
- // { unlock the WE record }
- _WESetHandleLock((Handle)hWE, saveWELock);
-
- // { return result code }
- return err;
-
- } // { WETrackDrag }
-
- pascal OSErr WEReceiveDrag(DragReference theDrag, WEHandle hWE)
- {
- WEPtr pWE;
- WEActionHandle hAction;
- Point mouse;
- short downModifiers, upModifiers;
- LongPt dropLocation;
- long insertionOffset, insertionLength;
- long sourceStart, sourceEnd;
- long destStart, destEnd;
- long delta;
- unsigned short dragItemIndex, numDragItems;
- ItemReference theItem;
- Handle hText, hStyles, hSoup, hObjectData;
- short objectIndex;
- OSType objectType;
- GrafPtr savePort;
- short intPasteAction;
- short saveUndoSupport, saveInhibitRecal;
- char dropEdge, space;
- Boolean isMove, isBackwards;
- Boolean saveWELock;
- OSErr err;
- short zero = 0;
- Point zeroPoint = {0, 0};
-
- isMove = false;
- hText = nil;
- hStyles = nil;
- hSoup = nil;
- hObjectData = nil;
-
- // { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- // { lock the WE record }
- saveWELock = _WESetHandleLock((Handle)hWE, true);
- pWE = *hWE;
-
- // { set up the port }
- GetPort(&savePort);
- SetPort(pWE->port);
-
- // { hide the drag caret }
- _WEUpdateDragCaret(kInvalidOffset, hWE);
-
- // { refuse this drag if we don't like its flavors :-) }
- err = badDragFlavorErr;
- if (_WEDragTastesGood(theDrag) == false)
- goto cleanup;
-
- // { get drag modifiers }
- err = GetDragModifiers(theDrag, &zero, &downModifiers, &upModifiers);
- if (err != noErr)
- goto cleanup;
-
- // { get drop location in local coordinates }
- err = GetDragMouse(theDrag, &mouse, &zeroPoint);
- if (err != noErr)
- goto cleanup;
- GlobalToLocal(&mouse);
-
- // { for the drag to be accepted, the drop location must be within the view region }
- err = dragNotAcceptedErr;
- if (PtInRgn(mouse, pWE->viewRgn) == false)
- goto cleanup;
-
- // { get drop offset into the text }
- WEPointToLongPoint(mouse, &dropLocation);
- insertionOffset = WEGetOffset(&dropLocation, &dropEdge, hWE);
-
- // { destStart/destEnd define the range to highlight at the end of the drag }
- destStart = insertionOffset;
-
- // { drag originated from this same window? }
- if (theDrag == pWE->currentDrag)
- {
-
- // { sourceStart/sourceEnd define the range to delete at the end of the move }
- sourceStart = pWE->selStart;
- sourceEnd = pWE->selEnd;
-
- // { remember text length before insertion }
- delta = pWE->textLength;
-
- // { if insertion offset is within the original selection range, abort the drag }
- // (*err = dragNotAcceptedErr;*)
- if (_WEOffsetInRange(insertionOffset, dropEdge, sourceStart, sourceEnd))
- goto cleanup;
-
- // { if the drag originated from this window, a move, }
- // { rather than a copy, should be performed }
- // { Exception: the option key may be held down at mouse-down }
- // { or mouse-up time to force a copy operation. }
-
- isMove = (((downModifiers | upModifiers) & optionKey) == 0);
- isBackwards = (insertionOffset <= sourceStart);
- } // { if intra-window drag }
-
- // { clear null style }
- BCLR(pWE->flags, weFUseNullStyle);
-
- // { hide selection highlighting }
- _WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
-
- // { if undo support is enabled, create a new action so we'll be able to undo the insertion }
- if (BTST(pWE->flags, weFUndoSupport))
- {
- WEClearUndo(hWE);
- if (WENewAction(insertionOffset, insertionOffset, 0, weAKDrag, 0, hWE, &hAction) == noErr)
- if (WEPushAction(hAction) != noErr)
- { ; }
- }
-
- // { count items in this drag }
- err = CountDragItems(theDrag, &numDragItems);
- if (err != noErr)
- goto cleanup;
-
- for (dragItemIndex = 1; dragItemIndex<=numDragItems; dragItemIndex++)
- {
- // { get item reference number for current drag item }
- err = GetDragItemReferenceNumber(theDrag, dragItemIndex, &theItem);
- if (err != noErr)
- goto cleanup;
-
- // { see if this drag item contains a text flavor }
- err = _WEExtractFlavor(theDrag, theItem, kTypeText, &hText);
- if (err == noErr)
- {
- // { extract accompanying styles and soup, if any }
- err = _WEExtractFlavor(theDrag, theItem, kTypeStyles, &hStyles);
- if (err != noErr && err != badDragFlavorErr)
- goto cleanup;
- err = _WEExtractFlavor(theDrag, theItem, kTypeSoup, &hSoup);
- if (err != noErr && err != badDragFlavorErr)
- goto cleanup;
-
- // { any extra space added because of intelligent cut-and-paste rules will use the }
- // { style attributes set at the insertion point }
- if (dragItemIndex == 1)
- {
- pWE->selStart = insertionOffset;
- pWE->selEnd = insertionOffset;
- _WESynchNullStyle(hWE);
- }
-
- // { get text length }
- insertionLength = GetHandleSize(hText);
- destEnd = insertionOffset + insertionLength;
-
- // { insert the new text at the insertion point }
- HLock(hText);
- err = _WEInsertText(insertionOffset, *hText, insertionLength, hWE);
- _WEForgetHandle(&hText);
- if (err != noErr)
- goto cleanup;
-
- // { adjust deletion range length in undo buffer }
- _WEAdjustUndoRange(insertionLength, hWE);
-
- // { apply the accompanying styles, if any }
- if (hStyles != nil)
- {
- err = _WEApplyStyleScrap(insertionOffset, destEnd,
- (StScrpHandle)hStyles, hWE);
- if (err != noErr)
- goto cleanup;
- _WEForgetHandle(&hStyles);
- }
-
- // { apply the accompanying soup, if any }
- if (hSoup != nil)
- {
- err = _WEApplySoup(insertionOffset, hSoup, hWE);
- if (err != noErr)
- goto cleanup;
- _WEForgetHandle(&hSoup);
- }
-
- // { determine whether an extra space should be added before or after the inserted text }
- intPasteAction = _WEIntelligentPaste(insertionOffset, destEnd, hWE);
-
- // { add the extra space, if necessary }
- if (intPasteAction != weDontAddSpaces)
- {
- space = 32;
- if (intPasteAction == weAddSpaceOnLeftSide)
- {
- err = _WEInsertText(insertionOffset, &space, 1, hWE);
- if (err != noErr)
- goto cleanup;
-
- destEnd = destEnd + 1;
-
- // { if an extra space is inserted in front of all dropped items, }
- // { don't count it when eventually highlighting the destination range }
- if (dragItemIndex == 1)
- destStart = destStart + 1;
- }
- else
- {
- err = _WEInsertText(destEnd, &space, 1, hWE);
- if (err != noErr)
- goto cleanup;
- }
-
- insertionLength = insertionLength + 1;
- _WEAdjustUndoRange(1, hWE);
- } // { if extra space }
-
- }
- else if (err == badDragFlavorErr)
- {
-
- // { no text flavor: there must be a flavor matching one of the registered object types }
- objectIndex = 0;
- while (_WEGetIndObjectType(objectIndex, &objectType) == noErr)
- {
- err = _WEExtractFlavor(theDrag, theItem, objectType, &hObjectData);
- if (err == noErr)
- break; // { enclosing while }
- if (err != badDragFlavorErr)
- goto cleanup;
- objectIndex = objectIndex + 1;
- } // { while }
-
- if (err != noErr)
- goto cleanup;
-
- // { set insertion point on first iteration (*after* extracting flavors, in case we are }
- // { doing an intra-window move, otherwise our send proc would be confused) }
- if (dragItemIndex == 1)
- {
- pWE->selStart = insertionOffset;
- pWE->selEnd = insertionOffset;
- }
-
- // { insert the object, but without touching undo or redrawing the text }
- saveUndoSupport = WEFeatureFlag(weFUndoSupport, weBitClear, hWE);
- saveInhibitRecal = WEFeatureFlag(weFInhibitRecal, weBitSet, hWE);
- err = WEInsertObject(objectType, hObjectData, zeroPoint, hWE);
- WEFeatureFlag(weFUndoSupport, saveUndoSupport, hWE);
- WEFeatureFlag(weFInhibitRecal, saveInhibitRecal, hWE);
- if (err != noErr)
- goto cleanup;
-
- insertionLength = 1;
- destEnd = insertionOffset + 1;
- _WEAdjustUndoRange(1, hWE);
- }
- else
- goto cleanup;
-
- // { advance insertion offset for subsequent drag items, if any }
- insertionOffset = insertionOffset + insertionLength;
-
- } // { for }
-
- if (isMove)
- {
- // { adjust source range }
- if (isBackwards)
- {
- delta = delta - pWE->textLength;
- sourceStart = sourceStart - delta;
- sourceEnd = sourceEnd - delta;
- }
-
- // { extend range according to intelligent cut-and-paste rules }
- _WEIntelligentCut(&sourceStart, &sourceEnd, hWE);
-
- // { if undo support is enabled, create a new action so we'll be able to undo the deletion }
- if (BTST(pWE->flags, weFUndoSupport))
- if (WENewAction(sourceStart, sourceEnd, 0, weAKDrag, 0, hWE, &hAction) == noErr)
- if (WEPushAction(hAction) != noErr)
- { ; }
-
- // { delete source range }
- delta = pWE->textLength;
- err = _WEDeleteRange(sourceStart, sourceEnd, hWE);
- if (err != noErr)
- goto cleanup;
-
- // { adjust destination range }
- if (isBackwards == false)
- {
- delta = delta - pWE->textLength;
- destStart = destStart - delta;
- destEnd = destEnd - delta;
- }
-
- } // { if isMove }
-
- // { select the range encompassing all items dropped }
- pWE->selStart = destStart;
- pWE->selEnd = destEnd;
-
- // { redraw the text }
- if (isMove)
- if (sourceStart < destStart)
- err = _WERedraw(sourceStart, destEnd, hWE);
- else
- err = _WERedraw(destStart, sourceEnd, hWE);
- else
- err = _WERedraw(destStart, destEnd, hWE);
-
- cleanup:
- // { dispose of temporary handles }
- _WEForgetHandle(&hText);
- _WEForgetHandle(&hStyles);
- _WEForgetHandle(&hSoup);
-
- // { restore the port }
- SetPort(savePort);
-
- // { unlock the WE record }
- _WESetHandleLock((Handle)hWE, saveWELock);
-
- // { return result code }
- return err;
-
- } // { WEReceiveDrag }
-
- pascal OSErr _WESendFlavor(FlavorType theType, void *dragSendRefCon, Handle hWE,
- DragReference theDrag)
- {
- WEPtr pWE;
- long selStart, selEnd;
- WEObjectDescHandle hObjectDesc;
- Handle hItem;
- Boolean disposeItem;
- OSErr err;
-
- pWE = *(WEHandle)hWE;
- selStart = pWE->selStart;
- selEnd = pWE->selEnd;
- disposeItem = false;
- hItem = nil;
-
- // { see if the selection contains an embedded object whose type matches the flavortype }
- if ((selEnd - selStart == 1) && _WEIsEmbeddedObject(selStart, &hObjectDesc, (WEHandle)hWE)
- && ((*hObjectDesc)->objectType == theType))
- hItem = (*hObjectDesc)->objectDataHandle;
- else
- {
-
- // { allocate a temporary handle to hold a copy of the requested flavor }
- err = _WEAllocate(0, kAllocTemp, &hItem);
- if (err != noErr)
- goto cleanup;
- disposeItem = true; // { dispose of hItem when done }
-
- // { identify the requested flavor type as either 'TEXT', 'styl' or 'SOUP' }
- if (theType == kTypeText)
- err = WECopyRange(selStart, selEnd, hItem, nil, nil, (WEHandle)hWE);
- else if (theType == kTypeStyles)
- err = WECopyRange(selStart, selEnd, nil, hItem, nil, (WEHandle)hWE);
- else if (theType == kTypeSoup)
- err = WECopyRange(selStart, selEnd, nil, nil, hItem,(WEHandle)hWE);
- else
- err = badDragFlavorErr;
-
- if (err != noErr)
- goto cleanup;
-
- }
-
- // { set the drag flavor data }
- HLock(hItem);
- err = SetDragItemFlavorData(theDrag, (ItemReference)hWE, theType, *hItem,
- GetHandleSize(hItem), 0);
- HUnlock(hItem);
-
- cleanup:
-
- // { clean up }
- if (disposeItem)
- _WEForgetHandle(&hItem);
-
- // { return result code }
- return err;
-
- } // { _WESendFlavor }
-
- pascal Boolean _WEDraggedToTrash(DragReference theDrag)
- {
-
- // { return TRUE if the drop location of the specified drag is the trash }
-
- const short bDirectoryAttr = 4;
-
- AEDesc dropLocation, coercedDropLocation;
- CInfoPBRec pb;
- FSSpecPtr pSpec;
- short trashVRefNum;
- long trashDirID;
- Boolean draggedToTrash;
-
- draggedToTrash = false;
- dropLocation.dataHandle = nil;
- coercedDropLocation.dataHandle = nil;
-
- // { get drop location }
- if (GetDropLocation(theDrag, &dropLocation) != noErr)
- goto cleanup;
-
- // { do nothing if dropLocation is a null descriptor }
- if (dropLocation.descriptorType == typeNull)
- goto cleanup;
-
- // { try to coerce the descriptor to a file system specification record }
- if (AECoerceDesc(&dropLocation, typeFSS, &coercedDropLocation) != noErr)
- goto cleanup;
-
- // { lock the data handle of the coerced descriptor }
- HLock(coercedDropLocation.dataHandle);
- pSpec = *(FSSpecHandle)coercedDropLocation.dataHandle;
-
- // { determine the directory ID of the drop location (assuming it's a folder!) }
- _WEBlockClr((Ptr)&pb, sizeof(pb));
- pb.hFileInfo.ioVRefNum = pSpec->vRefNum;
- pb.hFileInfo.ioDirID = pSpec->parID;
- pb.hFileInfo.ioNamePtr = pSpec->name;
- if (PBGetCatInfoSync(&pb) != noErr)
- goto cleanup;
-
- // { make sure the specified file system object is really a directory }
- if (!BTST(pb.hFileInfo.ioFlAttrib, bDirectoryAttr))
- goto cleanup;
-
- // { find the directory ID of the trash folder }
- if (FindFolder(pSpec->vRefNum, kTrashFolderType, kDontCreateFolder, &trashVRefNum, &trashDirID)
- != noErr)
- goto cleanup;
-
- // { compare the two directory IDs: if they're the same, the drop location is the trash }
- if (pb.dirInfo.ioDrDirID == trashDirID)
- draggedToTrash = true;
-
- cleanup:
- // { clean up }
- AEDisposeDesc(&dropLocation);
- AEDisposeDesc(&coercedDropLocation);
-
- return draggedToTrash;
- } // { _WEDraggedToTrash }
-
- pascal OSErr _WEDrag(Point mouseLoc, short modifiers, long clickTime, WEHandle hWE)
- {
- WEPtr pWE;
- WEObjectDescHandle hObjectDesc;
- EventRecord theEvent;
- RgnHandle dragRgn, tmpRgn;
- Rect dragBounds;
- Point portDelta;
- GrafPtr savePort;
- OSErr err;
-
- dragRgn = nil;
- tmpRgn = nil;
- pWE = *hWE;
- pWE->currentDrag = kNullDrag;
-
- // { set up the port }
- GetPort(&savePort);
- SetPort(pWE->port);
-
- // { fabricate an EventRecord for TrackDrag }
- theEvent.what = mouseDown;
- theEvent.message = 0;
- theEvent.when = clickTime;
- theEvent.where = mouseLoc;
- LocalToGlobal(&theEvent.where);
- theEvent.modifiers = modifiers;
-
- // { before seeing the dotted outline, the user must move the mouse a certain }
- // { distance away from the initial mouse location; this allows a short click in the selection }
- // { area to set the insertion point instead of starting a drag-and-drop sequence }
- err = noDragErr;
- if (WaitMouseMoved(theEvent.where) == false)
- goto cleanup;
-
- // { create a drag object }
- err = NewDrag(&pWE->currentDrag);
- if (err != noErr)
- goto cleanup;
-
- // {$IFC WASTE_DEBUG}
- // _WEAssert(pWE->currentDrag != kNullDrag, 'Zero is a valid drag reference (??)');
- // {$ENDC}
-
- // { if the selection range contains only an embedded object, }
- // { use its object kind as flavor type }
- if ((pWE->selEnd - pWE->selStart == 1) && _WEIsEmbeddedObject(pWE->selStart, &hObjectDesc, hWE))
- {
- err = AddDragItemFlavor(pWE->currentDrag, (ItemReference)hWE, (*hObjectDesc)->objectType,
- nil, 0, 0);
- if (err != noErr)
- goto cleanup;
- }
- else
- {
-
- // { add a 'TEXT' flavor to the drag }
- err = AddDragItemFlavor(pWE->currentDrag, (ItemReference)hWE, kTypeText, nil, 0, 0);
- if (err != noErr)
- goto cleanup;
-
- // { add a 'styl' flavor to the drag }
- err = AddDragItemFlavor(pWE->currentDrag, (ItemReference)hWE, kTypeStyles, nil, 0, 0);
- if (err != noErr)
- goto cleanup;
-
- // { add a 'SOUP' flavor to the drag }
- err = AddDragItemFlavor(pWE->currentDrag, (ItemReference)hWE, kTypeSoup, nil, 0, 0);
- if (err != noErr)
- goto cleanup;
-
- }
-
- // { since we didn't provide the flavor data for any of the above flavors, }
- // { we need supply a data send callback }
- if (WESendFlavorUPP == NULL) WESendFlavorUPP = NewDragSendDataProc(_WESendFlavor);
- err = SetDragSendProc(pWE->currentDrag, WESendFlavorUPP, 0);
- if (err != noErr)
- goto cleanup;
-
- // { get hilite region }
- dragRgn = WEGetHiliteRgn(pWE->selStart, pWE->selEnd, hWE);
-
- // { we need just the outline of this region }
- tmpRgn = NewRgn();
- CopyRgn(dragRgn, tmpRgn);
- InsetRgn(tmpRgn, 1, 1);
- DiffRgn(dragRgn, tmpRgn, dragRgn);
- DisposeRgn(tmpRgn);
-
- // { and we need it in global coordinates }
- portDelta.v = 0;
- portDelta.h = 0;
- LocalToGlobal(&portDelta);
- OffsetRgn(dragRgn, portDelta.h, portDelta.v);
-
- // { set the bounds of the drag }
- dragBounds = (*dragRgn)->rgnBBox;
- err = SetDragItemBounds(pWE->currentDrag, (ItemReference)hWE, &dragBounds);
- if (err != noErr)
- goto cleanup;
-
- // { track the drag }
- err = TrackDrag(pWE->currentDrag, &theEvent, dragRgn);
- if (err != noErr)
- goto cleanup;
-
- // { if the selection was dragged to the trash, delete it }
- if (_WEDraggedToTrash(pWE->currentDrag))
- {
- err = WEDelete(hWE);
- if (err != noErr)
- goto cleanup;
- }
-
- // { clear result code }
- err = noErr;
-
- cleanup:
- // { dispose of the drag }
- if (pWE->currentDrag != kNullDrag)
- {
- DisposeDrag(pWE->currentDrag);
- pWE->currentDrag = kNullDrag;
- }
-
- // { dispose of the drag region }
- if (dragRgn != nil)
- DisposeRgn(dragRgn);
-
- // { restore the port }
- SetPort(savePort);
-
- // { return result code }
- return err;
- } // { _WEDrag }
-
- pascal void WEClick(Point mouseLoc, short modifiers, long clickTime, WEHandle hWE)
- {
- WEPtr pWE;
- LongPt thePoint;
- long offset, anchor;
- long rangeStart, rangeEnd;
- char edge;
- Boolean isMultipleClick;
- Boolean saveWELock;
-
- // { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- // { lock the WE record }
- saveWELock = _WESetHandleLock((Handle)hWE, true);
- pWE = *hWE;
-
- // { hide the caret if it's showing }
- if (BTST(pWE->flags, weFCaretVisible))
- _WEBlinkCaret(hWE);
-
- // { find click offset }
- WEPointToLongPoint(mouseLoc, &thePoint);
- offset = WEGetOffset(&thePoint, &edge, hWE);
-
- // { determine whether this click is part of a sequence }
- isMultipleClick = ((clickTime < pWE->clickTime + GetDblTime()) && (offset == pWE->clickLoc));
-
- // { remember click time, click offset and edge value }
- pWE->clickTime = clickTime;
- pWE->clickLoc = offset;
- pWE->clickEdge = edge;
-
- if ((modifiers & shiftKey) == 0)
- {
-
- // { is this click part of a sequence or is it a single click? }
- if (isMultipleClick)
- {
- pWE->clickCount = pWE->clickCount + 1;
-
- // { a double (triple) click creates an anchor-word (anchor-line) }
- if (pWE->clickCount > 1)
- WEFindLine(offset, edge, &pWE->anchorStart, &pWE->anchorEnd, hWE);
- else
- WEFindWord(offset, edge, &pWE->anchorStart, &pWE->anchorEnd, hWE);
-
- offset = pWE->anchorStart;
-
- }
- else
- {
-
- // { single-click }
- // { if the Drag Manager is available and the click went in the selection range, }
- // { this click may be the beginning of a drag gesture }
- if (BTST(pWE->flags, weFDragAndDrop))
- if (_WEOffsetInRange(offset, edge, pWE->selStart, pWE->selEnd))
- if (_WEDrag(mouseLoc, modifiers, clickTime, hWE) != noDragErr)
- goto cleanup;
-
- pWE->clickCount = 0;
- anchor = offset;
- }
- }
- else
- {
-
- // { if the shift key was down, use the old anchor offset found with the previous click }
- if (BTST(pWE->flags, weFAnchorIsEnd))
- anchor = pWE->selEnd;
- else
- anchor = pWE->selStart;
- }
-
- // { set the weFMouseTracking bit while we track the mouse }
- BSET(pWE->flags, weFMouseTracking);
-
- // { MOUSE TRACKING LOOP }
- do
- {
-
- // { get text offset corresponding to mouse position }
- WEPointToLongPoint(mouseLoc, &thePoint);
- offset = WEGetOffset(&thePoint, &edge, hWE);
-
- // { if we're selecting words or lines, pin offset to a word or line boundary }
- if (pWE->clickCount > 0)
- {
- if (pWE->clickCount > 1)
- WEFindLine(offset, edge, &rangeStart, &rangeEnd, hWE);
- else
- WEFindWord(offset, edge, &rangeStart, &rangeEnd, hWE);
-
- // { choose the word/line boundary and the anchor that are farthest away from each other }
- if (offset > pWE->anchorStart)
- {
- anchor = pWE->anchorStart;
- offset = rangeEnd;
- }
- else
- {
- offset = rangeStart;
- anchor = pWE->anchorEnd;
- }
- }
-
- // { set the selection range from anchor point to current offset }
- WESetSelection(anchor, offset, hWE);
-
- // { call the click loop callback, if any }
- if (pWE->clickLoop != nil)
- if ((*(WEClickLoopProcPtr)pWE->clickLoop)(hWE) == false)
- break;
-
- // { update mouse position }
- GetMouse(&mouseLoc);
-
- } while(WaitMouseUp());
-
- // { clear the weFMouseTracking bit }
- BCLR(pWE->flags, weFMouseTracking);
-
- // { redraw the caret immediately if the selection range is empty }
- if (anchor == offset)
- _WEBlinkCaret(hWE);
-
- cleanup:
- // { unlock the WE record }
- _WESetHandleLock((Handle)hWE, saveWELock);
-
- } // { WEClick }
-