#include <sgdrag.h>
Inheritance diagram for SGListDragTarget:
Public Member Functions | |
SGListDragTarget (DialogOp *TheDialog, CGadgetID TheGadget=NULL) | |
Constructor. | |
virtual UINT32 | GetCursorID () |
Base Method to set cursor over this target. | |
virtual BOOL | GetStatusLineText (String_256 *TheText) |
Provide status line text for this target. | |
Protected Member Functions | |
virtual BOOL | ProcessEvent (DragEventType Event, DragInformation *pDragInfo, OilCoord *pMousePos, KeyPress *pKeyPress) |
Event Handler for SuperGallery listitem drag events. | |
SGDragInsertType | GetDragInsertType (SuperGallery *ParentGallery, SGDisplayNode *DraggedNode, OilCoord *pMousePos, SGDisplayNode *DestNode) |
Determines whether we will want to drop an item 'above' or 'below' the item under the current pointer position (used to work out which pointer shape to use to indicate the action which will be taken when a drag ends). | |
void | HandleDragCompleted (SuperGallery *ParentGallery, SGDisplayNode *DraggedNode, OilCoord *pMousePos, BOOL DragThisItemOnly=FALSE) |
Moves/copies gallery items as appropriate when a drag completes. | |
virtual BOOL | DetermineCursorShape (SuperGallery *ParentGallery, SGDisplayNode *DraggedNode, OilCoord *pMousePos) |
Determines what mouse pointer shape should be used during a drag while the mouse is over a gallery listbox target area. This sets the member variable CurrentCursorID, and if you then return the return value of this function from your ProcessEvent handler, this will result in the cursor shape beng updated correctly. | |
BOOL | OwnsEntireLine (SGDisplayNode *TheNode) |
Determines if the given display node has siblings to its left/right or if it fills an entire 'line' of the display list. This is used to determine whether to treat the top/bottom or left/right sides of the item as insert-before/after dropzones. | |
Protected Attributes | |
UINT32 | CurrentCursorID |
Friends | |
class | DragManagerOp |
Definition at line 265 of file sgdrag.h.
|
Constructor.
Definition at line 580 of file sgdrag.cpp. 00581 : KernelDragTarget(TheDialog, TheGadget) 00582 { 00583 CurrentCursorID = _R(IDC_SGDRAGCURSOR); 00584 00585 ERROR3IF(!TheDialog->IsKindOf(CC_RUNTIME_CLASS(SuperGallery)), 00586 "You can only use SGListDragTargets with SuperGallery dialogues!"); 00587 }
|
|
Determines what mouse pointer shape should be used during a drag while the mouse is over a gallery listbox target area. This sets the member variable CurrentCursorID, and if you then return the return value of this function from your ProcessEvent handler, this will result in the cursor shape beng updated correctly.
Definition at line 1017 of file sgdrag.cpp. 01020 { 01021 // By default, we want a simple pointer cursor 01022 CurrentCursorID = _R(IDC_SGDRAGCURSOR); 01023 01024 if (ParentGallery == NULL) 01025 return(FALSE); 01026 01027 // Convert the OilCoords into DocCoords 01028 DocCoord MousePos(pMousePos->x, pMousePos->y); 01029 01030 // Make the gallery scroll the list if we're dragging near the top/bottom 01031 ParentGallery->AutoScrollForDrag(&MousePos); 01032 01033 SGDisplayNode *DestNode = ParentGallery->FindNodeUnderPointer(&MousePos); 01034 if (DestNode == NULL) 01035 return(FALSE); // No valid target area, so return now 01036 01037 switch (GetDragInsertType(ParentGallery, DraggedNode, pMousePos, DestNode)) 01038 { 01039 case SGDRAGINSERT_NONE: 01040 CurrentCursorID = _R(IDC_DRAGGING_COLOUR); // No-can-drop cursor shape 01041 break; 01042 01043 case SGDRAGINSERT_ADD: 01044 CurrentCursorID = _R(IDC_SGDRAGCURSOR); // Can drop here 01045 break; 01046 01047 case SGDRAGINSERT_BEFORE: 01048 CurrentCursorID = _R(IDC_SGABOVECURSOR); // Will insert above 01049 break; 01050 01051 case SGDRAGINSERT_AFTER: 01052 CurrentCursorID = _R(IDC_SGBELOWCURSOR); // Will insert below 01053 break; 01054 } 01055 01056 // We claim all mouse movements, so that the manager uses our drag pointer 01057 // while the mouse is over our target area 01058 return(TRUE); 01059 }
|
|
Base Method to set cursor over this target.
Reimplemented from DragTarget. Definition at line 1126 of file sgdrag.cpp. 01127 { 01128 return(CurrentCursorID); 01129 }
|
|
Determines whether we will want to drop an item 'above' or 'below' the item under the current pointer position (used to work out which pointer shape to use to indicate the action which will be taken when a drag ends).
MousePos - The end-drag position, as passed into DragTarget::ProcessEvent DestNode - the DisplayTree node in which the drag completed
Definition at line 670 of file sgdrag.cpp. 00674 { 00675 ERROR3IF(DraggedNode == NULL || pMousePos == NULL || 00676 ParentGallery == NULL || DestNode == NULL, 00677 "Illegal NULL params"); 00678 00679 if (DestNode == DraggedNode || DestNode == DraggedNode->GetParent()) 00680 return(SGDRAGINSERT_NONE); 00681 00682 // If dragging a group over an item, then we will insert the group below the item's 00683 // parent group, so we always insert below. 00684 if (DraggedNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup)) && 00685 DestNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayItem))) 00686 { 00687 // Dragging a group over an item 00688 SGDisplayNode *DestParent = DestNode->GetParent(); 00689 00690 // It's an item in the group which is being dragged, so no point in dropping here 00691 if (DestParent == DraggedNode) 00692 return(SGDRAGINSERT_NONE); 00693 00694 // It's an item in the previous group, so we would insert back where we came from 00695 if (DestParent == DraggedNode->GetPrevious()) 00696 return(SGDRAGINSERT_NONE); 00697 00698 // It's a different group, so we will insert after that group 00699 return(SGDRAGINSERT_AFTER); 00700 } 00701 00702 00703 // If dragging an item over a group, then we'll ADD to the group 00704 if ((DraggedNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayItem))) && 00705 (DestNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup))) ) 00706 { 00707 // You can't drop an item into a read-only group (but we still allow moving of items 00708 // within a read-only group) 00709 if (DestNode != DraggedNode->GetParent() && DestNode->Flags.ReadOnly) 00710 return(SGDRAGINSERT_NONE); 00711 00712 return(SGDRAGINSERT_ADD); 00713 } 00714 00715 00716 // If we're dragging an item, check that the destination is legal (not read-only) 00717 if (DraggedNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayItem))) 00718 { 00719 SGDisplayNode *DestParent = DestNode->GetParent(); 00720 00721 // You can't drop an item into a read-only group (but we still allow moving of items 00722 // within a read-only group) 00723 if (DestParent != NULL && DestParent != DraggedNode->GetParent() && DestParent->Flags.ReadOnly) 00724 return(SGDRAGINSERT_NONE); 00725 } 00726 00727 00728 SGMiscInfo MiscInfo; 00729 ParentGallery->FillInMiscInfo(&MiscInfo); 00730 00731 // Determine where within the display item the drag was dropped 00732 DocCoord ListMouseCoord(pMousePos->x, pMousePos->y); 00733 ParentGallery->ConvertToVirtualCoords(&MiscInfo, &ListMouseCoord); 00734 00735 DocRect DestRect; 00736 DestNode->GetFormatRect(&DestRect); 00737 00738 BOOL IsInsertBefore = FALSE; 00739 00740 if (OwnsEntireLine(DestNode)) 00741 { 00742 // This item is full-width, so use top/bottom half as dropzones 00743 if (ListMouseCoord.y > (DestRect.lo.y + DestRect.hi.y) / 2) 00744 IsInsertBefore = TRUE; 00745 } 00746 else 00747 { 00748 // This item is not full width, so use left/right half as dropzones 00749 if (ListMouseCoord.x < (DestRect.lo.x + DestRect.hi.x) / 2) 00750 IsInsertBefore = TRUE; 00751 } 00752 00753 // Finally, one last check to see if we're still trying to drop the item back 00754 // into the same place. 00755 if (IsInsertBefore) 00756 { 00757 if (DestNode->GetPrevious() == DraggedNode) 00758 return(SGDRAGINSERT_NONE); 00759 } 00760 else 00761 { 00762 if (DestNode->GetNext() == DraggedNode) 00763 return(SGDRAGINSERT_NONE); 00764 } 00765 00766 return(IsInsertBefore ? SGDRAGINSERT_BEFORE : SGDRAGINSERT_AFTER); 00767 }
|
|
Provide status line text for this target.
Reimplemented from DragTarget. Definition at line 1149 of file sgdrag.cpp. 01150 { 01151 ERROR3IF(TheText == NULL, "Illegal NULL param"); 01152 01153 if (CurrentCursorID == _R(IDC_SGABOVECURSOR)) 01154 { 01155 TheText->MakeMsg(_R(IDS_SGDRAG_INSABOVE)); 01156 } 01157 else if (CurrentCursorID == _R(IDC_SGBELOWCURSOR)) 01158 { 01159 TheText->MakeMsg(_R(IDS_SGDRAG_INSBELOW)); 01160 } 01161 else 01162 { 01163 TheText->MakeMsg(_R(IDS_SGDRAG_LISTITEM)); 01164 } 01165 01166 return(TRUE); 01167 }
|
|
Moves/copies gallery items as appropriate when a drag completes. DraggedNode - The node being dragged MousePos - The end-drag position, as passed into DragTarget::ProcessEvent DragThisItemOnly - if TRUE, indicates that only the 'DragggedNode' should be dragged. If FALSE, then all items in the current gallery selection, plus DraggedNode, will be treated as if they were dragged. Definition at line 793 of file sgdrag.cpp. 00797 { 00798 TRACEUSER("amb", _T("SGListDragTarget::HandleDragCompleted")); 00799 ERROR3IF(DraggedNode == NULL || pMousePos == NULL || ParentGallery == NULL, 00800 "Illegal NULL params"); 00801 00802 if (ParentGallery == NULL) 00803 return; 00804 00805 // Convert the OilCoords into DocCoords 00806 DocCoord MousePos(pMousePos->x, pMousePos->y); 00807 SGDisplayNode *DestNode = ParentGallery->FindNodeUnderPointer(&MousePos); 00808 00809 if (DestNode == NULL || // No valid target 00810 DestNode == DraggedNode || // Dropped back where we started 00811 (DragThisItemOnly && DestNode == DraggedNode->GetParent())) // Dropped into own parent group 00812 { 00813 return; 00814 } 00815 00816 00817 BOOL InsertBefore = FALSE; // TRUE if should insert-before the DestNode 00818 switch (GetDragInsertType(ParentGallery, DraggedNode, pMousePos, DestNode)) 00819 { 00820 case SGDRAGINSERT_NONE: 00821 // The drag has no effect, so we exit now 00822 return; 00823 00824 case SGDRAGINSERT_ADD: 00825 case SGDRAGINSERT_AFTER: 00826 // We need take no specific action here 00827 break; 00828 00829 case SGDRAGINSERT_BEFORE: 00830 InsertBefore = TRUE; 00831 break; 00832 00833 default: 00834 ERROR3("Illegal return value from GetDragInsertType"); 00835 return; 00836 } 00837 00838 // TRUE if dragged a group, FALSE if dragged an item 00839 BOOL GroupBeingDragged = DraggedNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup)); 00840 00841 // Determine if we need to insert multiple nodes, and compile a list of 00842 // all the nodes to affect, if necessary. This list is then used to apply 00843 // the drag-finish to all selected items (done this way, as the movements 00844 // may well affect the selection in nasty ways, so we must cache it before 00845 // we move stuff around) 00846 INT32 ItemCount = 1; 00847 INT32 ItemIndex; 00848 if (!DragThisItemOnly) 00849 { 00850 if (GroupBeingDragged) 00851 ItemCount = ParentGallery->GetSelectedGroupCount(); 00852 else 00853 ItemCount = ParentGallery->GetSelectedItemCount(NULL, NULL); 00854 00855 if (ItemCount < 1) // Just in case DraggedNode is not selected! 00856 ItemCount = 1; 00857 } 00858 00859 SGDisplayNode **DraggedArray = NULL; 00860 SGDisplayRoot *DisplayTree = ParentGallery->GetDisplayTree(); 00861 00862 if (ItemCount > 1 && DisplayTree != NULL) 00863 { 00864 DraggedArray = (SGDisplayNode **) CCMalloc(ItemCount * sizeof(SGDisplayNode *)); 00865 00866 if (DraggedArray != NULL) 00867 { 00868 SGDisplayNode *Ptr = NULL; 00869 for (ItemIndex =0; ItemIndex < ItemCount; ItemIndex++) 00870 { 00871 if (GroupBeingDragged) 00872 Ptr = DisplayTree->FindNextSelectedGroup(Ptr); 00873 else 00874 Ptr = DisplayTree->FindNextSelectedItem(Ptr); 00875 DraggedArray[ItemIndex] = Ptr; 00876 00877 ERROR3IF(Ptr == NULL, "Gallery selection ran out before selection count did"); 00878 } 00879 } 00880 } 00881 00882 if (DraggedArray == NULL) // Just ensure we're safe 00883 ItemCount = 1; 00884 00885 // OK, For each item we must move, apply the appropriate action. 00886 // If there is only one item, DraggedArray will be NULL, and ItemCount will be 1, in 00887 // which case, we'll only do the loop once, using DraggedNode as the dropped thing. 00888 00889 // Determine if the DestNode is a group or an item, and determine the group affected (TargetGroup) 00890 BOOL TargetIsGroup = DestNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup)); 00891 SGDisplayGroup *TargetGroup = (SGDisplayGroup *) ((TargetIsGroup) ? DestNode : DestNode->GetParent()); 00892 ERROR3IF(TargetGroup == NULL, "Drag target display group is NULL!?"); 00893 00894 SGDisplayNode *NewItem = NULL; 00895 00896 for (ItemIndex = 0; ItemIndex < ItemCount; ItemIndex++) 00897 { 00898 if (DraggedArray != NULL) 00899 DraggedNode = DraggedArray[ItemIndex]; 00900 00901 NewItem = DraggedNode; 00902 00903 if (DraggedNode->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup))) 00904 { 00905 // Dragged node is a group, so move before/after the target group 00906 if (InsertBefore) 00907 TargetGroup->MoveBefore(DraggedNode); 00908 else 00909 TargetGroup->MoveAfter(DraggedNode); 00910 } 00911 else 00912 { 00913 // Dragged node is an item 00914 if (TargetIsGroup) 00915 { 00916 // Item was dropped on a group title, so copy into that group 00917 if (TargetGroup != DraggedNode->GetParent()) 00918 NewItem = ParentGallery->CopyDisplayItem((SGDisplayItem *)DraggedNode, TargetGroup); 00919 // else it's being moved into its own group - do nothing 00920 } 00921 else 00922 { 00923 // Item was dropped on another item, so use that item as the target position 00924 if (TargetGroup != DraggedNode->GetParent()) 00925 { 00926 // But it's in another group, so we must copy the item across 00927 if (InsertBefore) 00928 { 00929 NewItem = ParentGallery->CopyDisplayItem((SGDisplayItem *)DraggedNode, TargetGroup, 00930 (SGDisplayItem *)DestNode); 00931 } 00932 else 00933 { 00934 // We want to insert *after* the DestNode, so we make the target node the NEXT node 00935 // after DestNode (as this routine alwyas does an InsertBefore operation) 00936 NewItem = ParentGallery->CopyDisplayItem((SGDisplayItem *)DraggedNode, TargetGroup, 00937 (SGDisplayItem *) (DestNode->GetNext())); 00938 } 00939 } 00940 else 00941 { 00942 // We're just moving it within its own group 00943 if (InsertBefore) 00944 DestNode->MoveBefore(DraggedNode); 00945 else 00946 { 00947 // We have to be careful with MoveAfter to retain the correct order 00948 if (ItemIndex == 0 || DraggedArray[ItemIndex-1] == NULL) 00949 DestNode->MoveAfter(DraggedNode); 00950 else 00951 DraggedArray[ItemIndex-1]->MoveAfter(DraggedNode); 00952 } 00953 } 00954 } 00955 } 00956 00957 // Update the selection state for copied items 00958 if (DraggedNode != NewItem) 00959 { 00960 if (DraggedNode != NULL) 00961 DraggedNode->SetSelected(FALSE); 00962 00963 if (NewItem != NULL) 00964 { 00965 // Poke the flags directly to avoid an attempt to redraw, as at this point 00966 // the item's formatrect will be uninitialised (well, (0,0,0,0)) 00967 NewItem->Flags.Selected = TRUE; 00968 } 00969 } 00970 00971 // Update the last item in the array to point at the copy rather than the source 00972 if (ItemIndex > 0) 00973 DraggedArray[ItemIndex] = NewItem; 00974 } // end for 00975 00976 if (DraggedArray != NULL) // Free up our temporary memory allocation 00977 CCFree(DraggedArray); 00978 00979 ParentGallery->InvalidateCachedFormat(); // Redraw any changed areas of the list 00980 ParentGallery->ReformatAndRedrawIfNecessary(); 00981 00982 ParentGallery->AllItemsCopied(TargetGroup); // Inform gallery this group has changed 00983 00984 ParentGallery->SelectionHasChanged(); // And ensure it updates button shading state 00985 }
|
|
Determines if the given display node has siblings to its left/right or if it fills an entire 'line' of the display list. This is used to determine whether to treat the top/bottom or left/right sides of the item as insert-before/after dropzones.
Definition at line 609 of file sgdrag.cpp. 00610 { 00611 DocRect TheRect; 00612 TheNode->GetFormatRect(&TheRect); 00613 00614 SGDisplayNode *Ptr = TheNode->GetPrevious(); 00615 if (Ptr != NULL) 00616 { 00617 DocRect TempRect; 00618 Ptr->GetFormatRect(&TempRect); 00619 00620 // If overlap in the Y axis, then we are on the same line 00621 if (TempRect.lo.y <= TheRect.hi.y && TempRect.hi.y >= TheRect.lo.y) 00622 return(FALSE); 00623 } 00624 00625 Ptr = TheNode->GetNext(); 00626 if (Ptr != NULL) 00627 { 00628 DocRect TempRect; 00629 Ptr->GetFormatRect(&TempRect); 00630 00631 // If overlap in the Y axis, then we are on the same line 00632 if (TempRect.lo.y <= TheRect.hi.y && TempRect.hi.y >= TheRect.lo.y) 00633 return(FALSE); 00634 } 00635 00636 return(TRUE); 00637 }
|
|
Event Handler for SuperGallery listitem drag events.
Reimplemented from KernelDragTarget. Reimplemented in SGNameDragTarget, SGBitmapDragTarget, SGColourDragTarget, SGClipartDragTarget, SGFillsDragTarget, SGNameDragTarget, SGFontsDragTarget, and SGLineDragTarget. Definition at line 1083 of file sgdrag.cpp. 01085 { 01086 if (!pDragInfo->IsKindOf(CC_RUNTIME_CLASS(SGListDragInfo))) 01087 return(FALSE); 01088 01089 SGListDragInfo *Info = (SGListDragInfo *)pDragInfo; 01090 01091 switch(Event) 01092 { 01093 case DRAGEVENT_COMPLETED: 01094 HandleDragCompleted((SuperGallery *) TargetDialog, 01095 Info->GetDraggedNode(), pMousePos); 01096 return(TRUE); 01097 01098 01099 case DRAGEVENT_MOUSESTOPPED: 01100 case DRAGEVENT_MOUSEMOVED: 01101 case DRAGEVENT_MOUSEIDLE: 01102 // Call a subroutine to work out and set our current cursor shape 01103 return(DetermineCursorShape((SuperGallery *) TargetDialog, 01104 Info->GetDraggedNode(), pMousePos)); 01105 default: 01106 break; 01107 } 01108 01109 // Otherwise, we aren't interested in the event, so we don't claim it 01110 return(FALSE); 01111 }
|
|
Reimplemented from KernelDragTarget. Reimplemented in SGBitmapDragTarget, SGColourDragTarget, SGClipartDragTarget, SGFillsDragTarget, SGFontsDragTarget, and SGLineDragTarget. |
|
|