home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-13 | 30.8 KB | 1,140 lines | [TEXT/PJMM] |
- unit WEMouse;
-
- { WASTE PROJECT }
- { Mouse Clicks and support for Drag and Drop }
-
- { Copyright © 1993-1994 Marco Piovanelli }
- { All Rights Reserved }
-
- interface
- uses
- Drag, WEHighLevelEditing;
-
- procedure WEClick (mouseLoc: Point;
- modifiers: Integer;
- clickTime: LongInt;
- hWE: WEHandle);
- function WETrackDrag (theMessage: DragTrackingMessage;
- theDrag: DragReference;
- hWE: WEHandle): OSErr;
- function WEReceiveDrag (theDrag: DragReference;
- hWE: WEHandle): OSErr;
-
- function WECanAcceptDrag (theDrag: DragReference;
- hWE: WEHandle): Boolean;
- function WEDraggedToTrash (theDrag: DragReference): Boolean;
-
- implementation
- uses
- AppleEvents, Folders, WEScraps;
-
- const
-
- noDragErr = 128;
- kTextMargin = 3; { width of border area surrounding the text (in pixels) }
- kAutoScrollDelay = 10; { delay before auto-scroll starts (in ticks) }
-
- function CallClickLoop (hWE: WEHandle;
- clickProc: ProcPtr): Boolean;
- inline
- $205F, { movea.l (sp)+, a0 }
- $4E90; { jsr (a0) }
-
- function CallTranslateDrag (theDrag: DragReference;
- theItem: ItemReference;
- requestedType: FlavorType;
- putDataHere: Handle;
- translateProc: ProcPtr): OSErr;
- inline
- $205F, { movea.l (sp)+, a0 }
- $4E90; { jsr (a0) }
-
- {$IFC WASTE_SEGMENT}
- {$S WASTE_DRAG}
- {$ENDC}
-
- function _WEGetFlavor (theDrag: DragReference;
- theItem: ItemReference;
- requestedType: FlavorType;
- hFlavor: Handle;
- translateDragHook: ProcPtr): OSErr;
-
- { get the requested flavor out of the specified drag reference and put it into }
- { the given handle, if any -- if hFlavor is NIL, just check whether the specified flavor }
- { is there or can be obtained by invoking a user-defined translation routine }
-
- label
- 1;
- var
- theFlags: FlavorFlags;
- theSize: Size;
- saveFlavorLock: Boolean;
- err: OSErr;
- begin
-
- { see if the drag item has the requested flavor type, }
- { without forcing the actual data to be sent and/or translated }
- err := GetFlavorFlags(theDrag, theItem, requestedType, theFlags);
- if (err = badDragFlavorErr) then
- begin
-
- { requested flavor is not available: our client may try a custom translation }
- { this is especially handy to translate HFS objects like TEXT and PICT files }
- if (translateDragHook <> nil) then
- err := CallTranslateDrag(theDrag, theItem, requestedType, hFlavor, translateDragHook);
- end
- else if (err = noErr) then
- begin
-
- { requested flavor is available: get it if hFlavor is not NIL }
- if (hFlavor = nil) then
- goto 1;
-
- { get size of flavor data }
- err := GetFlavorDataSize(theDrag, theItem, requestedType, theSize);
- if (err <> noErr) then
- goto 1;
-
- { resize the handle }
- err := %_SetHandleSize(hFlavor, theSize);
- if (err <> noErr) then
- goto 1;
-
- { get flavor data }
- saveFlavorLock := _WESetHandleLock(hFlavor, true);
- err := GetFlavorData(theDrag, theItem, requestedType, hFlavor^, theSize, 0);
- IgnoreBoolean(_WESetHandleLock(hFlavor, saveFlavorLock));
- end;
-
- 1:
- { return result code }
- _WEGetFlavor := err;
-
- end; { _WEGetFlavor }
-
- function _WEExtractFlavor (theDrag: DragReference;
- theItem: ItemReference;
- theType: FlavorType;
- var hFlavor: Handle;
- translateDragHook: ProcPtr): OSErr;
-
- { _WEExtractFlavor creates a new handle and calls _WEGetFlavor on it }
-
- var
- err: OSErr;
- begin
-
- { allocate a new handle }
- err := _WEAllocate(0, kAllocTemp, hFlavor);
- if (err = noErr) then
- begin
-
- { put the requested flavor into this handle }
- err := _WEGetFlavor(theDrag, theItem, theType, hFlavor, translateDragHook);
-
- { if an error occurred, forget the handle }
- if (err <> noErr) then
- _WEForgetHandle(hFlavor);
- end;
-
- _WEExtractFlavor := err;
- end; { _WEExtractFlavor }
-
- function WECanAcceptDrag (theDrag: DragReference;
- hWE: WEHandle): Boolean;
- var
- dragItemIndex, numDragItems: Integer;
- theItem: ItemReference;
- theFlags: FlavorFlags;
- objectIndex: Integer;
- objectType: OSType;
- translateDragHook: ProcPtr;
- err: OSErr;
- begin
- WECanAcceptDrag := false;
- translateDragHook := hWE^^.translateDragHook;
-
- { count items in this theDrag }
- err := CountDragItems(theDrag, numDragItems);
- if (err <> noErr) then
- Exit(WECanAcceptDrag);
-
- for dragItemIndex := 1 to numDragItems do
- begin
-
- { get item reference number for current drag item }
- err := GetDragItemReferenceNumber(theDrag, dragItemIndex, theItem);
- if (err <> noErr) then
- Exit(WECanAcceptDrag);
-
- { see if this drag item contains a text flavor }
- err := _WEGetFlavor(theDrag, theItem, kTypeText, nil, translateDragHook);
- if (err = badDragFlavorErr) then
- begin
-
- { see if this drag item contains a flavor matching one of the registered object types }
- objectIndex := 0;
- while (_WEGetIndObjectType(objectIndex, objectType) = noErr) do
- begin
- err := _WEGetFlavor(theDrag, theItem, objectType, nil, translateDragHook);
- if (err <> badDragFlavorErr) then
- Leave; { enclosing while }
- objectIndex := objectIndex + 1;
- end; { while }
- end;
-
- if (err <> noErr) then
- Exit(WECanAcceptDrag);
-
- end; { for }
-
- WECanAcceptDrag := true;
-
- end; { WECanAcceptDrag }
-
- procedure _WEUpdateDragCaret (offset: LongInt;
- hWE: WEHandle);
- var
- ticks: LongInt;
- pWE: WEPtr;
- begin
-
- { the WE record must be already locked }
- pWE := hWE^;
-
- { get current time }
- ticks := TickCount;
-
- if (offset = pWE^.dragCaretOffset) then
- begin
-
- { drag caret offset didn't change; blink the caret }
- if (GetCaretTime < ticks - pWE^.caretTime) and (offset <> kInvalidOffset) then
- begin
- _WEDrawCaret(pWE^.dragCaretOffset, hWE);
- pWE^.flags := BitXor(pWE^.flags, BSL(1, weFDragCaretVisible));
- pWE^.caretTime := ticks;
- end;
- end
- else
- begin
-
- { drag caret offset did change }
- { hide old caret, if it's showing }
- if BTST(pWE^.flags, weFDragCaretVisible) then
- _WEDrawCaret(pWE^.dragCaretOffset, hWE);
-
- { show new caret (unless offset is kInvalidOffset) }
- if (offset <> kInvalidOffset) then
- begin
- _WEDrawCaret(offset, hWE);
- BSET(pWE^.flags, weFDragCaretVisible);
- pWE^.caretTime := ticks;
- end
- else
- BCLR(pWE^.flags, weFDragCaretVisible);
-
- { remember drag caret offset }
- pWE^.dragCaretOffset := offset;
- end;
- end; { _WEUpdateDragCaret }
-
- function WETrackDrag (theMessage: DragTrackingMessage;
- theDrag: DragReference;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- attributes: DragAttributes;
- mouse: Point;
- tmpRgn: RgnHandle;
- thePoint: LongPoint;
- offset, ticks: LongInt;
- edge: SignedByte;
- saveWELock: Boolean;
- err: OSErr;
- begin
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { dispatch on theMessage }
- case theMessage of
-
- dragTrackingEnterWindow:
- begin
-
- { determine whether we can accept this drag }
- if (WECanAcceptDrag(theDrag, hWE)) then
- BSET(pWE^.flags, weFCanAcceptDrag)
- else
- BCLR(pWE^.flags, weFCanAcceptDrag);
-
- { reset clickTime }
- pWE^.clickTime := 0;
-
- end;
-
- dragTrackingInWindow:
- if BTST(pWE^.flags, weFCanAcceptDrag) then
- begin
-
- { get drag attributes }
- err := GetDragAttributes(theDrag, attributes);
- if (err <> noErr) then
- goto 1;
-
- { get current mouse location in local coordinates }
- err := GetDragMouse(theDrag, mouse, PointPtr(0)^);
- if (err <> noErr) then
- goto 1;
- GlobalToLocal(mouse);
-
- if (PtInRgn(mouse, pWE^.viewRgn)) then
- begin
-
- { 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 ((not BTST(pWE^.flags, weFHilited)) and (BitAnd(attributes, dragHasLeftSenderWindow) <> 0)) then
- begin
- tmpRgn := NewRgn;
- CopyRgn(pWE^.viewRgn, tmpRgn);
- InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
- IgnoreShort(ShowDragHilite(theDrag, tmpRgn, true));
- DisposeRgn(tmpRgn);
- BSET(pWE^.flags, weFHilited);
- end;
-
- { hide the caret }
- if BTST(pWE^.flags, weFCaretVisible) then
- _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) then
- if (_WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd)) then
- offset := kInvalidOffset;
-
- { provide a drag feedback in the form of a blinking caret }
- _WEUpdateDragCaret(offset, hWE);
-
- { clear clickTime }
- pWE^.clickTime := 0;
-
- end
- else
- begin
-
- { mouse is outside text area }
- { dehilite the text rectangle, if it's hilited }
- if (BTST(pWE^.flags, weFHilited)) then
- begin
- IgnoreShort(HideDragHilite(theDrag));
- BCLR(pWE^.flags, weFHilited);
- end;
-
- { 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) then
- begin
- ticks := TickCount;
- if (pWE^.clickTime = 0) then
- pWE^.clickTime := ticks
- else if (ticks > pWE^.clickTime + kAutoScrollDelay) then
- if (pWE^.clickLoop <> nil) then
- IgnoreBoolean(CallClickLoop(hWE, pWE^.clickLoop));
- end;
- end;
- end; { case dragTrackingInWindow }
-
- dragTrackingLeaveWindow:
- begin
-
- { drag has left this window }
- { dehilite the text area if necessary }
- if (BTST(pWE^.flags, weFHilited)) then
- begin
- IgnoreShort(HideDragHilite(theDrag));
- BCLR(pWE^.flags, weFHilited);
- end;
-
- { hide the drag caret, if it's showing }
- _WEUpdateDragCaret(kInvalidOffset, hWE);
-
- end;
-
- otherwise
- ;
- end; { case theMessage }
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- WETrackDrag := err;
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WETrackDrag }
-
- function WEReceiveDrag (theDrag: DragReference;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- hAction: WEActionHandle;
- mouse: Point;
- downModifiers, upModifiers: Integer;
- dropLocation: LongPoint;
- insertionOffset, insertionLength: LongInt;
- sourceStart, sourceEnd: LongInt;
- destStart, destEnd: LongInt;
- delta: LongInt;
- dragItemIndex, numDragItems: Integer;
- theItem: ItemReference;
- hText, hStyles, hSoup, hObjectData: Handle;
- objectIndex: Integer;
- objectType: OSType;
- savePort: GrafPtr;
- intPasteAction: Integer;
- saveUndoSupport, saveInhibitRecal: Integer;
- dropEdge, space: SignedByte;
- isMove, isBackwards: Boolean;
- saveWELock: Boolean;
- err: OSErr;
- begin
- isMove := false;
- hText := nil;
- hStyles := nil;
- hSoup := nil;
- hObjectData := nil;
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { set up the port }
- GetPort(savePort);
- SetPort(pWE^.port);
-
- { hide the drag caret }
- _WEUpdateDragCaret(kInvalidOffset, hWE);
-
- { refuse this drag if it doesn't taste good }
- err := badDragFlavorErr;
- if (WECanAcceptDrag(theDrag, hWE) = false) then
- goto 1;
-
- { get drag modifiers }
- err := GetDragModifiers(theDrag, IntegerPtr(0)^, downModifiers, upModifiers);
- if (err <> noErr) then
- goto 1;
-
- { get drop location in local coordinates }
- err := GetDragMouse(theDrag, mouse, PointPtr(0)^);
- if (err <> noErr) then
- goto 1;
- 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) then
- goto 1;
-
- { 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) then
- begin
-
- { 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)) then
- goto 1;
-
- { 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 := (BitAnd(BitOr(downModifiers, upModifiers), optionKey) = 0);
- isBackwards := (insertionOffset <= sourceStart);
- end; { if intra-window drag }
-
- { clear null style }
- BCLR(pWE^.flags, weFUseNullStyle);
-
- { hide selection highlighting }
- _WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
-
- { increment modification count }
- pWE^.modCount := pWE^.modCount + 1;
-
- { if undo support is enabled, create a new action so we'll be able to undo the insertion }
- if (BTST(pWE^.flags, weFUndoSupport)) then
- begin
- WEClearUndo(hWE);
- if (WENewAction(insertionOffset, insertionOffset, 0, weAKDrag, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
- end;
-
- { count items in this drag }
- err := CountDragItems(theDrag, numDragItems);
- if (err <> noErr) then
- goto 1;
-
- for dragItemIndex := 1 to numDragItems do
- begin
-
- { get item reference number for current drag item }
- err := GetDragItemReferenceNumber(theDrag, dragItemIndex, theItem);
- if (err <> noErr) then
- goto 1;
-
- { see if this drag item contains a text flavor }
- err := _WEExtractFlavor(theDrag, theItem, kTypeText, hText, pWE^.translateDragHook);
- if (err = noErr) then
- begin
-
- { extract accompanying styles and soup, if any }
- err := _WEExtractFlavor(theDrag, theItem, kTypeStyles, hStyles, pWE^.translateDragHook);
- if (err <> noErr) and (err <> badDragFlavorErr) then
- goto 1;
- err := _WEExtractFlavor(theDrag, theItem, kTypeSoup, hSoup, pWE^.translateDragHook);
- if (err <> noErr) and (err <> badDragFlavorErr) then
- goto 1;
-
- { any extra space added because of intelligent cut-and-paste rules will use the }
- { style attributes set at the insertion point }
- if (dragItemIndex = 1) then
- begin
- pWE^.selStart := insertionOffset;
- pWE^.selEnd := insertionOffset;
- _WESynchNullStyle(hWE);
- end;
-
- { 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) then
- goto 1;
-
- { adjust deletion range length in undo buffer }
- _WEAdjustUndoRange(insertionLength, hWE);
-
- { apply the accompanying styles, if any }
- if (hStyles <> nil) then
- begin
- err := _WEApplyStyleScrap(insertionOffset, destEnd, StScrpHandle(hStyles), hWE);
- if (err <> noErr) then
- goto 1;
- _WEForgetHandle(hStyles);
- end;
-
- { apply the accompanying soup, if any }
- if (hSoup <> nil) then
- begin
- err := _WEApplySoup(insertionOffset, hSoup, hWE);
- if (err <> noErr) then
- goto 1;
- _WEForgetHandle(hSoup);
- end;
-
- { 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) then
- begin
-
- space := 32;
- if (intPasteAction = weAddSpaceOnLeftSide) then
- begin
- err := _WEInsertText(insertionOffset, @space, 1, hWE);
- if (err <> noErr) then
- goto 1;
-
- 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) then
- destStart := destStart + 1;
-
- end
- else
- begin
- err := _WEInsertText(destEnd, @space, 1, hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- insertionLength := insertionLength + 1;
- _WEAdjustUndoRange(1, hWE);
- end; { if extra space }
-
- end
- else if (err = badDragFlavorErr) then
- begin
-
- { no text flavor: there must be a flavor matching one of the registered object types }
- objectIndex := 0;
- while (_WEGetIndObjectType(objectIndex, objectType) = noErr) do
- begin
- err := _WEExtractFlavor(theDrag, theItem, objectType, hObjectData, pWE^.translateDragHook);
- if (err = noErr) then
- Leave; { enclosing while }
- if (err <> badDragFlavorErr) then
- goto 1;
- objectIndex := objectIndex + 1;
- end; { while }
-
- if (err <> noErr) then
- goto 1;
-
- { 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) then
- begin
- pWE^.selStart := insertionOffset;
- pWE^.selEnd := insertionOffset;
- end;
-
- { 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, Point(0), hWE);
- IgnoreShort(WEFeatureFlag(weFUndoSupport, saveUndoSupport, hWE));
- IgnoreShort(WEFeatureFlag(weFInhibitRecal, saveInhibitRecal, hWE));
- if (err <> noErr) then
- goto 1;
-
- insertionLength := 1;
- destEnd := insertionOffset + 1;
- _WEAdjustUndoRange(1, hWE);
- end
- else
- goto 1;
-
- { advance insertion offset for subsequent drag items, if any }
- insertionOffset := insertionOffset + insertionLength;
-
- end; { for }
-
- if (isMove) then
- begin
-
- { adjust source range }
- if (isBackwards) then
- begin
- delta := delta - pWE^.textLength;
- sourceStart := sourceStart - delta;
- sourceEnd := sourceEnd - delta;
- end;
-
- { 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)) then
- if (WENewAction(sourceStart, sourceEnd, 0, weAKDrag, 0, hWE, hAction) = noErr) then
- if (WEPushAction(hAction) <> noErr) then
- ;
-
- { delete source range }
- delta := pWE^.textLength;
- err := _WEDeleteRange(sourceStart, sourceEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { adjust destination range }
- if (isBackwards = false) then
- begin
- delta := delta - pWE^.textLength;
- destStart := destStart - delta;
- destEnd := destEnd - delta;
- end;
-
- end; { if isMove }
-
- { select the range encompassing all items dropped }
- pWE^.selStart := destStart;
- pWE^.selEnd := destEnd;
-
- { redraw the text }
- if (isMove) then
- if (sourceStart < destStart) then
- err := _WERedraw(sourceStart, destEnd, hWE)
- else
- err := _WERedraw(destStart, sourceEnd, hWE)
- else
- err := _WERedraw(destStart, destEnd, hWE);
-
- 1:
- { return result code }
- WEReceiveDrag := err;
-
- { dispose of temporary handles }
- _WEForgetHandle(hText);
- _WEForgetHandle(hStyles);
- _WEForgetHandle(hSoup);
-
- { restore the port }
- SetPort(savePort);
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEReceiveDrag }
-
- function _WESendFlavor (theType: FlavorType;
- dragSendRefCon: Ptr;
- hWE: WEHandle;
- theDrag: DragReference): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- selStart, selEnd: LongInt;
- hObjectDesc: WEObjectDescHandle;
- hItem: Handle;
- disposeItem: Boolean;
- err: OSErr;
- begin
- pWE := hWE^;
- selStart := pWE^.selStart;
- selEnd := pWE^.selEnd;
- disposeItem := false;
- hItem := nil;
-
- { see if the selection contains an embedded object whose type matches the flavor type }
- if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) & (hObjectDesc^^.objectType = theType) then
- hItem := hObjectDesc^^.objectDataHandle
- else
- begin
-
- { allocate a temporary handle to hold a copy of the requested flavor }
- err := _WEAllocate(0, kAllocTemp, hItem);
- if (err <> noErr) then
- goto 1;
- disposeItem := true; { dispose of hItem when done }
-
- { identify the requested flavor type as either 'TEXT', 'styl' or 'SOUP' }
- if (theType = kTypeText) then
- err := WECopyRange(selStart, selEnd, hItem, nil, nil, hWE)
- else if (theType = kTypeStyles) then
- err := WECopyRange(selStart, selEnd, nil, hItem, nil, hWE)
- else if (theType = kTypeSoup) then
- err := WECopyRange(selStart, selEnd, nil, nil, hItem, hWE)
- else
- err := badDragFlavorErr;
-
- if (err <> noErr) then
- goto 1;
-
- end;
-
- { set the drag flavor data }
- HLock(hItem);
- err := SetDragItemFlavorData(theDrag, ItemReference(hWE), theType, hItem^, %_GetHandleSize(hItem), 0);
- HUnlock(hItem);
-
- 1:
- { return result code }
- _WESendFlavor := err;
-
- { clean up }
- if (disposeItem) then
- _WEForgetHandle(hItem);
-
- end; { _WESendFlavor }
-
- function WEDraggedToTrash (theDrag: DragReference): Boolean;
-
- { return TRUE if the drop location of the specified drag is the trash }
-
- label
- 1;
- const
- bDirectoryAttr = 4;
- var
- dropLocation, coercedDropLocation: AEDesc;
- pb: CInfoPBRec;
- pSpec: FSSpecPtr;
- trashVRefNum: Integer;
- trashDirID: LongInt;
- begin
- WEDraggedToTrash := false;
- dropLocation.dataHandle := nil;
- coercedDropLocation.dataHandle := nil;
-
- { get drop location }
- if (GetDropLocation(theDrag, dropLocation) <> noErr) then
- goto 1;
-
- { do nothing if dropLocation is a null descriptor }
- if (dropLocation.descriptorType = typeNull) then
- goto 1;
-
- { try to coerce the descriptor to a file system specification record }
- if (AECoerceDesc(dropLocation, typeFSS, coercedDropLocation) <> noErr) then
- goto 1;
-
- { 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(@pb, SizeOf(pb));
- pb.ioVRefNum := pSpec^.vRefNum;
- pb.ioDirID := pSpec^.parID;
- pb.ioNamePtr := @pSpec^.name;
- if (PBGetCatInfoSync(@pb) <> noErr) then
- goto 1;
-
- { make sure the specified file system object is really a directory }
- if (not BTST(pb.ioFlAttrib, bDirectoryAttr)) then
- goto 1;
-
- { find the directory ID of the trash folder }
- if (FindFolder(pSpec^.vRefNum, kTrashFolderType, kDontCreateFolder, trashVRefNum, trashDirID) <> noErr) then
- goto 1;
-
- { compare the two directory IDs: if they're the same, the drop location is the trash }
- if (pb.ioDrDirID = trashDirID) then
- WEDraggedToTrash := true;
-
- 1:
- { clean up }
- IgnoreShort(AEDisposeDesc(dropLocation));
- IgnoreShort(AEDisposeDesc(coercedDropLocation));
-
- end; { WEDraggedToTrash }
-
- function _WEDrag (mouseLoc: Point;
- modifiers: Integer;
- clickTime: LongInt;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pWE: WEPtr;
- hObjectDesc: WEObjectDescHandle;
- theEvent: EventRecord;
- dragRgn, tmpRgn: RgnHandle;
- dragBounds: Rect;
- portDelta: Point;
- savePort: GrafPtr;
- err: OSErr;
- begin
- 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) then
- goto 1;
-
- { create a drag object }
- err := NewDrag(pWE^.currentDrag);
- if (err <> noErr) then
- goto 1;
-
- {$IFC WASTE_DEBUG}
- _WEAssert(pWE^.currentDrag <> kNullDrag, 'Zero is a valid drag reference (??)');
- {$ENDC}
-
- { if the selection range consists of an embedded object, }
- { then use its object type as flavor type }
- if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
- begin
- err := AddDragItemFlavor(pWE^.currentDrag, ItemReference(hWE), hObjectDesc^^.objectType, nil, 0, 0);
- if (err <> noErr) then
- goto 1;
- end
- else
- begin
-
- { add a 'TEXT' flavor to the drag }
- err := AddDragItemFlavor(pWE^.currentDrag, ItemReference(hWE), kTypeText, nil, 0, 0);
- if (err <> noErr) then
- goto 1;
-
- { add a 'styl' flavor to the drag }
- err := AddDragItemFlavor(pWE^.currentDrag, ItemReference(hWE), kTypeStyles, nil, 0, 0);
- if (err <> noErr) then
- goto 1;
-
- { add a 'SOUP' flavor to the drag }
- err := AddDragItemFlavor(pWE^.currentDrag, ItemReference(hWE), kTypeSoup, nil, 0, 0);
- if (err <> noErr) then
- goto 1;
-
- end;
-
- { since we didn't provide the flavor data for any of the above flavors, }
- { we need supply a data send callback }
- err := SetDragSendProc(pWE^.currentDrag, @_WESendFlavor, 0);
- if (err <> noErr) then
- goto 1;
-
- { 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 := Point(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) then
- goto 1;
-
- { track the drag }
- err := TrackDrag(pWE^.currentDrag, theEvent, dragRgn);
- if (err <> noErr) then
- goto 1;
-
- { if the selection was dragged to the trash, delete it }
- if (WEDraggedToTrash(pWE^.currentDrag)) then
- begin
- err := WEDelete(hWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEDrag := err;
-
- { dispose of the drag }
- if (pWE^.currentDrag <> kNullDrag) then
- begin
- IgnoreShort(DisposeDrag(pWE^.currentDrag));
- pWE^.currentDrag := kNullDrag;
- end;
-
- { dispose of the drag region }
- if (dragRgn <> nil) then
- DisposeRgn(dragRgn);
-
- { restore the port }
- SetPort(savePort);
-
- end; { _WEDrag }
-
- {$IFC WASTE_SEGMENT}
- {$S}
- {$ENDC}
-
- procedure WEClick (mouseLoc: Point;
- modifiers: Integer;
- clickTime: LongInt;
- hWE: WEHandle);
- label
- 1;
- var
- pWE: WEPtr;
- hObjectDesc: WEObjectDescHandle;
- thePoint: LongPoint;
- offset, anchor: LongInt;
- rangeStart, rangeEnd: LongInt;
- edge: SignedByte;
- isMultipleClick: Boolean;
- saveWELock: Boolean;
- begin
-
- { stop any ongoing inline input session }
- WEStopInlineSession(hWE);
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
- pWE := hWE^;
-
- { hide the caret if it's showing }
- if BTST(pWE^.flags, weFCaretVisible) then
- _WEBlinkCaret(hWE);
-
- { find click offset }
- WEPointToLongPoint(mouseLoc, thePoint);
- offset := WEGetOffset(thePoint, edge, hWE);
-
- { determine whether this click is part of a sequence }
- { a single click inside an object selects it, so it's like a double click in a word }
- isMultipleClick := ((clickTime < pWE^.clickTime + GetDblTime) and (offset = pWE^.clickLoc));
-
- { remember click time, click offset and edge value }
- pWE^.clickTime := clickTime;
- pWE^.clickLoc := offset;
- pWE^.clickEdge := edge;
-
- { when selected, embedded objects can intercept mouse clicks }
- if (WEGetSelectedObject(hObjectDesc, hWE) = noErr) then
- if _WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd) then
- if (_WEClickObject(mouseLoc, modifiers + ORD(isMultipleClick), clickTime, hObjectDesc)) then
- goto 1;
-
- if (BitAnd(modifiers, shiftKey) = 0) then
- begin
-
- { is this click part of a sequence or is it a single click? }
- if (isMultipleClick) then
- begin
- pWE^.clickCount := pWE^.clickCount + 1;
-
- { a double (triple) click creates an anchor-word (anchor-line) }
- if (pWE^.clickCount > 1) then
- WEFindLine(offset, edge, pWE^.anchorStart, pWE^.anchorEnd, hWE)
- else
- WEFindWord(offset, edge, pWE^.anchorStart, pWE^.anchorEnd, hWE);
-
- offset := pWE^.anchorStart;
-
- end
- else
- begin
-
- { 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) then
- if _WEOffsetInRange(offset, edge, pWE^.selStart, pWE^.selEnd) then
- if (_WEDrag(mouseLoc, modifiers, clickTime, hWE) <> noDragErr) then
- goto 1;
-
- pWE^.clickCount := 0;
- anchor := offset;
- end
- end
- else
-
- { if the shift key was down, use the old anchor offset found with the previous click }
- if BTST(pWE^.flags, weFAnchorIsEnd) then
- anchor := pWE^.selEnd
- else
- anchor := pWE^.selStart;
-
- { set the weFMouseTracking bit while we track the mouse }
- BSET(pWE^.flags, weFMouseTracking);
-
- { MOUSE TRACKING LOOP }
- repeat
-
- { 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) then
- begin
- if (pWE^.clickCount > 1) then
- 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) then
- begin
- anchor := pWE^.anchorStart;
- offset := rangeEnd;
- end
- else
- begin
- offset := rangeStart;
- anchor := pWE^.anchorEnd;
- end;
- end
- else
-
- { if the point is in the middle of an object, the selection should include it }
- if (edge = kObjectEdge) then
- offset := offset + 1;
-
- { 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) then
- if (CallClickLoop(hWE, pWE^.clickLoop) = false) then
- Leave;
-
- { update mouse position }
- GetMouse(mouseLoc);
-
- until (not WaitMouseUp);
-
- { clear the weFMouseTracking bit }
- BCLR(pWE^.flags, weFMouseTracking);
-
- { redraw the caret immediately if the selection range is empty }
- if (anchor = offset) then
- _WEBlinkCaret(hWE);
-
- 1:
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { WEClick }
-
- end.