00001 // $Id: sgdrag.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // sgdrag.cpp - Drag Manager classes (information, targets) for supergallery scollbars 00099 // and generic supergallery item dragging (for rearrangement only) 00100 00101 00102 /* 00103 */ 00104 00105 00106 #include "camtypes.h" 00107 00108 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "galres.h" 00110 //#include "galstr.h" 00111 //#include "resource.h" 00112 //#include "sgallery.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "sgdrag.h" 00114 //#include "sgtree.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 //#include "oilcoord.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00116 00117 00118 DECLARE_SOURCE("$Revision: 1282 $"); 00119 00120 00121 CC_IMPLEMENT_DYNAMIC(SGScrollDragTarget, KernelDragTarget) 00122 CC_IMPLEMENT_DYNCREATE(SGScrollDragInfo, DragInformation) 00123 00124 CC_IMPLEMENT_DYNAMIC(SGListDragTarget, KernelDragTarget) 00125 CC_IMPLEMENT_DYNCREATE(SGListDragInfo, DragInformation) 00126 00127 00128 00129 #define new CAM_DEBUG_NEW 00130 00131 00132 00133 const INT32 AUTOREPEATTIME = 150; // Auto-repeat a maximum of ~7 times per second 00134 // (This is the delay, in milliseconds) 00135 00136 00137 /******************************************************************************************** 00138 00139 > SGScrollDragTarget::SGScrollDragTarget(DialogOp *TheDialog, CGadgetID TheGadget = NULL) 00140 00141 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00142 Created: 27/2/95 00143 Inputs: TheDialog - The kernel dialog in which the target exists 00144 TheGadget - The gadget within that dialogue which is the target 00145 00146 Purpose: Constructor 00147 00148 ********************************************************************************************/ 00149 00150 SGScrollDragTarget::SGScrollDragTarget(DialogOp *TheDialog, CGadgetID TheGadget) 00151 : KernelDragTarget(TheDialog, TheGadget) 00152 { 00153 Timer.Sample(); // Remember the time at which we were created, for autorepeat 00154 00155 IWantAllEvents = TRUE; // Ask for all events to be given to us, even if the pointer 00156 // strays out of our target window area. 00157 } 00158 00159 00160 00161 /******************************************************************************************** 00162 00163 BOOL SGScrollDragTarget::ProcessEvent(DragEventType Event, DragInformation *pDragInfo, 00164 OilCoord *pMousePos, KeyPress* pKeyPress) 00165 00166 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00167 Created: 27/2/95 00168 Inputs: Event - Indicates what has happened 00169 pDragInfo - points to drag information describing this drag. This 00170 should be an SGScrollDragInfo or something has gone seriously wrong. 00171 pMousePos - points to information on the current mouse position, in OIL coords 00172 pKeyPress - NULL, or if for a keypress event, keypress information 00173 00174 Returns: TRUE to claim the event, FALSE to let it through to other targets 00175 This particular handler always returns TRUE 00176 00177 Purpose: Event Handler for SuperGallery scrollbar drag events 00178 00179 ********************************************************************************************/ 00180 00181 BOOL SGScrollDragTarget::ProcessEvent(DragEventType Event, DragInformation *pDragInfo, 00182 OilCoord *pMousePos, KeyPress* pKeyPress) 00183 { 00184 // Weed out events that we are not interested in 00185 switch(Event) 00186 { 00187 case DRAGEVENT_ABORT: 00188 case DRAGEVENT_COMPLETED: 00189 // Just claim the event as ours. 00190 // We don't get these events unless the pointer is over us, so we don't do 00191 // anything here - see the deinitialise handler 00192 return(TRUE); 00193 00194 case DRAGEVENT_INITIALISE: 00195 case DRAGEVENT_DEINITIALISE: 00196 case DRAGEVENT_MOUSEMOVED: 00197 case DRAGEVENT_MOUSESTOPPED: 00198 case DRAGEVENT_MOUSEIDLE: 00199 // We want these events, so break to drop through and process them 00200 break; 00201 00202 default: 00203 // An unknown/unwanted event type - it could be dangerous to do something on 00204 // an unknown event, so we won't! 00205 return(TRUE); 00206 } 00207 00208 // Cast the draginfo into the correct type 00209 SGScrollDragInfo *DragInfo = (SGScrollDragInfo *) pDragInfo; 00210 00211 // FALSE if we aren't dragging, but just handling auto-repeat 00212 BOOL NotAutoRepeat = (DragInfo->GetDragType() == SGDRAG_SAUSAGE); 00213 00214 SGDisplayRootScroll *Root = DragInfo->GetDragRootNode(); 00215 SGMiscInfo *MiscInfo = DragInfo->GetDragMiscInfo(); 00216 SuperGallery *ParentGallery = Root->GetParentGallery(); 00217 00218 // Convert the OilCoord into a DocCoord, and convert into displaylist coords 00219 DocCoord MousePos(pMousePos->x, pMousePos->y); 00220 ParentGallery->ConvertToVirtualCoords(MiscInfo, &MousePos); 00221 00222 // And calculate the relevant rectangles... 00223 DocRect UpButton; 00224 DocRect DownButton; 00225 DocRect SausageRect; 00226 DocRect PageUp; 00227 DocRect PageDown; 00228 DocRect ScrollRect; 00229 Root->CalculateScrollRects(MiscInfo, TRUE, 00230 &UpButton, &DownButton, &SausageRect, 00231 &PageUp, &PageDown, &ScrollRect); 00232 00233 if (Event == DRAGEVENT_MOUSEMOVED && NotAutoRepeat) 00234 { 00235 // Dragging the scroll sausage 00236 00237 // Get the offset - the scroll sausage should try to move this point of the 00238 // sausage (measured in millipoints from the top of the sausage) to lie under 00239 // the mouse pointer position if possible. 00240 INT32 AnchorOffset = DragInfo->GetDragAnchorOffset(); 00241 00242 INT32 ScrollWindowTo; 00243 00244 if (SausageRect.Height() <= SausageRect.Width()) 00245 { 00246 // The sausage is a minimum-size square, so now does not proportionally represent 00247 // the displayed area of the window. Thus, we need to use the top position of the 00248 // bar in (barheight - sausageheight) as a fractional scroll between 0 and 00249 // (ScrollExtent - WindowHeight) 00250 ScrollWindowTo = (INT32) ( 00251 ( ((double) (ScrollRect.hi.y - (MousePos.y + AnchorOffset))) / 00252 (double) (ScrollRect.Height() - SausageRect.Height()) ) * 00253 (double) (Root->GetCachedListExtent() - MiscInfo->WindowHeight) 00254 ); 00255 } 00256 else 00257 { 00258 // The bar represents the fraction of visible area to extent, so we work out the 00259 // fractional position of the top of the bar, and that gives the position to scroll 00260 // the top of the displayed area to. 00261 ScrollWindowTo = (INT32) ( 00262 ( ((double) (ScrollRect.hi.y - (MousePos.y + AnchorOffset))) / 00263 (double) ScrollRect.Height() ) * 00264 (double) Root->GetCachedListExtent() 00265 ); 00266 } 00267 00268 Root->SetScrollOffset(ScrollWindowTo, MiscInfo); 00269 return(TRUE); 00270 } 00271 00272 00273 // The drag must therefore be to implement simple AutoRepeat on a button or page-scroll. 00274 // We only bother scrolling if: 00275 // 1) Event is 'initialise' (so it scrolls immediately the button goes down) 00276 // 2) Event is 'deinitialise' (so we must ensure all buttons are popped up) 00277 // 3) Or if it is time for another autorepeat 00278 if (Event != DRAGEVENT_INITIALISE && 00279 Event != DRAGEVENT_DEINITIALISE && 00280 !Timer.Elapsed(AUTOREPEATTIME)) 00281 { 00282 // No need to update just now. Return, claiming this event 00283 return(TRUE); 00284 } 00285 00286 const INT32 ClickScroll = 12000; // Millipoint distance to scroll for a button click 00287 INT32 ScrollBy = 0; // Set this to the amount by which to scroll 00288 00289 Timer.Sample(); // Update the autorepeat timer 00290 00291 switch (DragInfo->GetDragType()) 00292 { 00293 case SGDRAG_SCROLLUP: 00294 if (Event == DRAGEVENT_DEINITIALISE) 00295 { 00296 // Drag completed: Unindent the scroll button 00297 Root->IndentedButton = IBUTTON_NONE; 00298 ParentGallery->ForceRedrawOfArea(&UpButton); 00299 ParentGallery->PaintListNow(); 00300 } 00301 else if (UpButton.ContainsCoord(MousePos)) 00302 { 00303 ScrollBy = -ClickScroll; 00304 00305 // Indent the scroll button 00306 Root->IndentedButton = IBUTTON_UP; 00307 ParentGallery->ForceRedrawOfArea(&UpButton); 00308 ParentGallery->PaintListNow(); 00309 } 00310 break; 00311 00312 00313 case SGDRAG_SCROLLDOWN: 00314 if (Event == DRAGEVENT_DEINITIALISE) 00315 { 00316 // Drag completed: Unindent the scroll button 00317 Root->IndentedButton = IBUTTON_NONE; 00318 ParentGallery->ForceRedrawOfArea(&DownButton); 00319 ParentGallery->PaintListNow(); 00320 } 00321 else if (DownButton.ContainsCoord(MousePos)) 00322 { 00323 ScrollBy = ClickScroll; 00324 00325 // Indent the scroll button 00326 Root->IndentedButton = IBUTTON_DOWN; 00327 ParentGallery->ForceRedrawOfArea(&DownButton); 00328 ParentGallery->PaintListNow(); 00329 } 00330 break; 00331 00332 00333 case SGDRAG_PAGEUP: 00334 if (PageUp.IsValid() && PageUp.ContainsCoord(MousePos)) 00335 { 00336 ScrollBy = MiscInfo->WindowHeight - ClickScroll; 00337 if (ScrollBy < 0) 00338 ScrollBy = ClickScroll; 00339 00340 ScrollBy = -ScrollBy; 00341 } 00342 break; 00343 00344 00345 case SGDRAG_PAGEDOWN: 00346 if (PageDown.IsValid() && PageDown.ContainsCoord(MousePos)) 00347 { 00348 ScrollBy = MiscInfo->WindowHeight - ClickScroll; 00349 if (ScrollBy < 0) 00350 ScrollBy = ClickScroll; 00351 } 00352 break; 00353 00354 default: 00355 break; 00356 } 00357 00358 if (Event != DRAGEVENT_DEINITIALISE && ScrollBy != 0) 00359 { 00360 if (DragInfo->IsAdjustDrag()) // If adjust-drag, reverse scroll direction 00361 ScrollBy = -ScrollBy; 00362 00363 Root->SetScrollOffset(Root->GetScrollOffset() + ScrollBy, MiscInfo); 00364 } 00365 00366 // We always claim all events during this drag (it is not a drag to a particular place 00367 // to move an object - really we're using the drag system to "capture" the mouse) 00368 return(TRUE); 00369 } 00370 00371 00372 00373 /******************************************************************************************** 00374 00375 > void SGScrollDragTarget::GetCursorID() 00376 00377 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00378 Created: 27/2/95 00379 00380 Purpose: Base Method to set cursor over this target 00381 00382 ********************************************************************************************/ 00383 00384 UINT32 SGScrollDragTarget::GetCursorID() 00385 { 00386 return(0); 00387 } 00388 00389 00390 00391 /******************************************************************************************** 00392 00393 > virtual BOOL SGScrollDragTarget::GetStatusLineText(String_256 * TheText) 00394 00395 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00396 Created: 27/2/95 00397 00398 Returns: FALSE - we never provide any status line help for scroll-drags 00399 00400 Purpose: Provide status line text for this target 00401 00402 ********************************************************************************************/ 00403 00404 BOOL SGScrollDragTarget::GetStatusLineText(String_256 * TheText) 00405 { 00406 return FALSE; 00407 } 00408 00409 00410 00411 00412 00413 00414 00415 00416 00417 00418 00419 00420 00421 00422 00423 00424 /******************************************************************************************** 00425 00426 > void SGScrollDragInfo::SGScrollDragInfo() 00427 00428 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00429 Created: 27/2/95 00430 00431 Purpose: Default constructor. DO NOT CALL THIS CONSTRUCTOR 00432 00433 ********************************************************************************************/ 00434 SGScrollDragInfo::SGScrollDragInfo() 00435 { 00436 ERROR3("Default SGScrollDragInfo constructor called"); 00437 } 00438 00439 00440 00441 /******************************************************************************************** 00442 00443 > SGScrollDragInfo::SGScrollDragInfo(SGDisplayRootScroll *ParentRootNode, 00444 SGDragType TheDragType, 00445 SGMiscInfo *MiscInfo, 00446 INT32 DragAnchorOffset, 00447 BOOL IsAdjust = FALSE) 00448 00449 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00450 Created: 27/2/95 00451 00452 Inputs: ParentRootNode - The SGDisplayRootScroll for the DisplayTree for which 00453 the drag is occurring 00454 00455 TheDragType - The SGDragType indicating what is being dragged 00456 00457 MiscInfo - The normal SGMiscInfo as recieved by display tree event handlers 00458 00459 DragAnchorOffset - The offset, in millipoints, from the top of the scroll 00460 sausage to the point where the drag started (used only when dragging the 00461 sausage, to "lock" the sausage to the mouse pointer) 00462 00463 IsAdjust - TRUE if it is an "adjust" drag [NOTE - Adjust drags are legal 00464 when dragging scrollbars, and are not turned into clicks like normal drags] 00465 00466 Purpose: Constructor 00467 00468 ********************************************************************************************/ 00469 00470 SGScrollDragInfo::SGScrollDragInfo(SGDisplayRootScroll *ParentRootNode, 00471 SGDragType TheDragType, 00472 SGMiscInfo *MiscInfo, 00473 INT32 DragAnchorOffset, 00474 BOOL IsAdjust) 00475 : DragInformation(FALSE) 00476 { 00477 DragRootNode = ParentRootNode; 00478 DragType = TheDragType; 00479 DragAnchor = DragAnchorOffset; 00480 DragAdjust = IsAdjust; 00481 00482 DragMiscInfo = *MiscInfo; // Copy the MiscInfo structure for ourselves 00483 00484 // Set up a few things about this drag - it does not do solid drag 00485 DoesSolidDrag = FALSE; 00486 SolidDragOffset.x = SolidDragOffset.y = 0; // Set up defaults just in case 00487 SolidDragSize.Set(1,1); 00488 } 00489 00490 00491 00492 /******************************************************************************************** 00493 00494 > virtual UINT32 SGScrollDragInfo::GetCursorID() 00495 00496 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00497 Created: 27/2/95 00498 00499 Returns: a cursor ID to set during this drag 00500 00501 Purpose: To provide the resource ID of the cursor to use during this drag. 00502 For scrollbar drags, the cursor should remain the normal arrow shape. 00503 00504 ********************************************************************************************/ 00505 00506 UINT32 SGScrollDragInfo::GetCursorID() 00507 { 00508 return(0); 00509 } 00510 00511 00512 00513 /******************************************************************************************** 00514 00515 > virtual BOOL SGScrollDragInfo::GetStatusLineText(String_256 * TheText) 00516 00517 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00518 Created: 27/2/95 00519 00520 Returns: FALSE - The string has not been filled in 00521 Purpose: Provide status line text for this drag - While dragging scrollbars no help 00522 is required/given, so this always returns FALSE 00523 00524 ********************************************************************************************/ 00525 00526 BOOL SGScrollDragInfo::GetStatusLineText(String_256 * TheText) 00527 { 00528 return(FALSE); 00529 } 00530 00531 00532 00533 /******************************************************************************************** 00534 00535 > void SGScrollDragInfo::OnClick(INT32 Flags,POINT Point) 00536 00537 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00538 Created: 27/2/95 00539 Inputs: Flags - Some flags 00540 Point - the point which was clicked 00541 00542 Purpose: This is called if a drag was attempted but never started because it was a 00543 click all along 00544 00545 ********************************************************************************************/ 00546 00547 void SGScrollDragInfo::OnClick(INT32 Flags, POINT Point) 00548 { 00549 // Do nothing. As the thing is scrolled once immediately on SGEVENT_INITIALISE, we 00550 // have already applied the correct click action. 00551 } 00552 00553 00554 00555 00556 00557 00558 00559 00560 00561 00562 00563 00564 00565 00566 00567 /******************************************************************************************** 00568 00569 > SGListDragTarget::SGListDragTarget(DialogOp *TheDialog, CGadgetID TheGadget = NULL) 00570 00571 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00572 Created: 14/3/95 00573 Inputs: TheDialog - The kernel dialog in which the target exists 00574 TheGadget - The gadget within that dialogue which is the target 00575 00576 Purpose: Constructor 00577 00578 ********************************************************************************************/ 00579 00580 SGListDragTarget::SGListDragTarget(DialogOp *TheDialog, CGadgetID TheGadget) 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 } 00588 00589 00590 00591 /******************************************************************************************** 00592 00593 > BOOL SGListDragTarget::OwnsEntireLine(SGDisplayNode *TheNode) 00594 00595 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00596 Created: 17/3/95 00597 00598 Inputs: TheNode - the node to check 00599 00600 Returns: TRUE if the item fills the entire width of the display list 00601 00602 Purpose: Determines if the given display node has siblings to its left/right 00603 or if it fills an entire 'line' of the display list. This is used to 00604 determine whether to treat the top/bottom or left/right sides of the 00605 item as insert-before/after dropzones. 00606 00607 ********************************************************************************************/ 00608 00609 BOOL SGListDragTarget::OwnsEntireLine(SGDisplayNode *TheNode) 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 } 00638 00639 00640 00641 /******************************************************************************************** 00642 00643 > SGDragInsertType SGListDragTarget::GetDragInsertType(SuperGallery *ParentGallery, 00644 SGDisplayNode *DraggedNode, 00645 OilCoord *pMousePos, 00646 SGDisplayNode *DestNode) 00647 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00648 Created: 14/3/95 00649 00650 Inputs: ParentGallery - The gallery in which the drag completed 00651 00652 DraggedNode - The node being dragged 00653 00654 MousePos - The end-drag position, as passed into DragTarget::ProcessEvent 00655 00656 DestNode - the DisplayTree node in which the drag completed 00657 00658 Returns: An enumerated type indicating whether the node will be added to a group, 00659 or inserted above or below another node. 00660 00661 Purpose: Determines whether we will want to drop an item 'above' or 'below' 00662 the item under the current pointer position (used to work out which 00663 pointer shape to use to indicate the action which will be taken when a 00664 drag ends) 00665 00666 SeeAlso: SGListDragTarget::HandleDragCompleted 00667 00668 ********************************************************************************************/ 00669 00670 SGDragInsertType SGListDragTarget::GetDragInsertType(SuperGallery *ParentGallery, 00671 SGDisplayNode *DraggedNode, 00672 OilCoord *pMousePos, 00673 SGDisplayNode *DestNode) 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 } 00768 00769 00770 00771 /******************************************************************************************** 00772 00773 > void SGListDragTarget::HandleDragCompleted(SuperGallery *ParentGallery, 00774 SGDisplayNode *DraggedNode, 00775 OilCoord *pMousePos, 00776 BOOL DragThisItemOnly = FALSE) 00777 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00778 Created: 14/3/95 00779 Inputs: ParentGallery - The gallery in which the drag completed 00780 00781 DraggedNode - The node being dragged 00782 00783 MousePos - The end-drag position, as passed into DragTarget::ProcessEvent 00784 00785 DragThisItemOnly - if TRUE, indicates that only the 'DragggedNode' 00786 should be dragged. If FALSE, then all items in the current gallery 00787 selection, plus DraggedNode, will be treated as if they were dragged. 00788 00789 Purpose: Moves/copies gallery items as appropriate when a drag completes 00790 00791 ********************************************************************************************/ 00792 00793 void SGListDragTarget::HandleDragCompleted(SuperGallery *ParentGallery, 00794 SGDisplayNode *DraggedNode, 00795 OilCoord *pMousePos, 00796 BOOL DragThisItemOnly) 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 } 00986 00987 00988 00989 /******************************************************************************************** 00990 00991 > BOOL SGListDragTarget::DetermineCursorShape(SuperGallery *ParentGallery, 00992 SGDisplayNode *DraggedNode, 00993 OilCoord *pMousePos) 00994 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00995 Created: 15/3/95 00996 00997 Inputs: ParentGallery - The gallery in which the drag completed 00998 DraggedNode - The node which is being dragged 00999 pMousePos - The end-drag position, as passed into DragTarget::ProcessEvent 01000 01001 Returns: TRUE if we should change the cursor shape (return this value 01002 from mouse events in ProcessEvent to have the drag manager use 01003 or not-use our pointer as appropriate) 01004 01005 Purpose: Determines what mouse pointer shape should be used during a drag 01006 while the mouse is over a gallery listbox target area. This sets 01007 the member variable CurrentCursorID, and if you then return the 01008 return value of this function from your ProcessEvent handler, this 01009 will result in the cursor shape beng updated correctly. 01010 01011 Notes: This is a subroutine to minimise the amount of work involved in 01012 deriving classes from SGListDragTarget for recieving drags of 01013 specific things (e.g. colours, bitmaps, etc) in gallery listboxes 01014 01015 ********************************************************************************************/ 01016 01017 BOOL SGListDragTarget::DetermineCursorShape(SuperGallery *ParentGallery, 01018 SGDisplayNode *DraggedNode, 01019 OilCoord *pMousePos) 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 } 01060 01061 01062 01063 /******************************************************************************************** 01064 01065 > virtual BOOL SGListDragTarget::ProcessEvent(DragEventType Event, 01066 DragInformation *pDragInfo, 01067 OilCoord *pMousePos, KeyPress* pKeyPress) 01068 01069 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01070 Created: 14/3/95 01071 Inputs: Event - Indicates what has happened 01072 pDragInfo - points to drag information describing this drag. This 01073 should be an SGListDragInfo or something has gone seriously wrong. 01074 pMousePos - points to information on the current mouse position, in OIL coords 01075 pKeyPress - NULL, or if for a keypress event, keypress information 01076 01077 Returns: TRUE to claim the event, FALSE to let it through to other targets 01078 01079 Purpose: Event Handler for SuperGallery listitem drag events 01080 01081 ********************************************************************************************/ 01082 01083 BOOL SGListDragTarget::ProcessEvent(DragEventType Event, DragInformation *pDragInfo, 01084 OilCoord *pMousePos, KeyPress* pKeyPress) 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 } 01112 01113 01114 01115 /******************************************************************************************** 01116 01117 > void SGListDragTarget::GetCursorID() 01118 01119 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01120 Created: 14/3/95 01121 01122 Purpose: Base Method to set cursor over this target 01123 01124 ********************************************************************************************/ 01125 01126 UINT32 SGListDragTarget::GetCursorID() 01127 { 01128 return(CurrentCursorID); 01129 } 01130 01131 01132 01133 /******************************************************************************************** 01134 01135 > virtual BOOL SGListDragTarget::GetStatusLineText(String_256 * TheText) 01136 01137 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01138 Created: 14/3/95 01139 01140 Returns: FALSE - we never provide any status line help for scroll-drags 01141 01142 Purpose: Provide status line text for this target 01143 01144 Notes: Bases the text on the current value of the member var CurrentCursorID. 01145 If this is an unknown value, defaults to _R(IDS_SGDRAG_LISTITEM) 01146 01147 ********************************************************************************************/ 01148 01149 BOOL SGListDragTarget::GetStatusLineText(String_256 * TheText) 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 } 01168 01169 01170 01171 01172 01173 01174 01175 01176 01177 01178 01179 01180 01181 01182 01183 01184 /******************************************************************************************** 01185 01186 > void SGListDragInfo::SGListDragInfo() 01187 01188 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01189 Created: 14/3/95 01190 01191 Purpose: Default constructor. DO NOT CALL THIS CONSTRUCTOR 01192 01193 ********************************************************************************************/ 01194 SGListDragInfo::SGListDragInfo() 01195 { 01196 ERROR3("Default SGListDragInfo constructor called"); 01197 } 01198 01199 01200 01201 /******************************************************************************************** 01202 01203 > SGListDragInfo::SGListDragInfo(SuperGallery *ParentGal, SGDisplayNode *DraggedNode, 01204 SGMouseInfo *TheMouseInfo, BOOL IsAdjust = FALSE) 01205 01206 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01207 Created: 14/3/95 01208 01209 Inputs: ParentGal - The gallery from which the drag originated 01210 01211 DraggedNode - the SGDisplayNode that is being dragged 01212 01213 TheMouseInfo -The MouseInfo which was passed into your HandleEvent 01214 method for the click which started this drag. (Passed back into the 01215 SGDisplayNode::DragWasReallyAClick handler if the drag becomes a click) 01216 01217 IsAdjust - TRUE if it is an "adjust" drag [NOTE - Adjust drags are legal 01218 when dragging scrollbars, and are not turned into clicks like normal drags] 01219 01220 Purpose: Constructor 01221 01222 ********************************************************************************************/ 01223 01224 SGListDragInfo::SGListDragInfo(SuperGallery *ParentGal, SGDisplayNode *DraggedNode, 01225 SGMouseInfo *TheMouseInfo, BOOL IsAdjust) 01226 : DragInformation(IsAdjust) 01227 { 01228 ParentGallery = ParentGal; 01229 DragNode = DraggedNode; 01230 MouseInfo = *TheMouseInfo; // COPY the MouseInfo structure 01231 01232 // Set up a few things about this drag - it does not do solid drag 01233 DoesSolidDrag = FALSE; 01234 SolidDragOffset.x = SolidDragOffset.y = 0; // Set up defaults just in case 01235 SolidDragSize.Set(1,1); 01236 } 01237 01238 01239 01240 /******************************************************************************************** 01241 01242 > virtual UINT32 SGListDragInfo::GetCursorID() 01243 01244 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01245 Created: 14/3/95 01246 01247 Returns: a cursor ID to set during this drag 01248 01249 Purpose: To provide the resource ID of the cursor to use during this drag. 01250 For scrollbar drags, the cursor should remain the normal arrow shape. 01251 01252 ********************************************************************************************/ 01253 01254 UINT32 SGListDragInfo::GetCursorID() 01255 { 01256 return(_R(IDC_DRAGGING_COLOUR)); // No-can-drop cursor shape 01257 } 01258 01259 01260 01261 /******************************************************************************************** 01262 01263 > virtual BOOL SGListDragInfo::GetStatusLineText(String_256 * TheText) 01264 01265 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01266 Created: 14/3/95 01267 01268 Returns: FALSE - The string has not been filled in 01269 Purpose: Provide status line text for this drag - While dragging scrollbars no help 01270 is required/given, so this always returns FALSE 01271 01272 ********************************************************************************************/ 01273 01274 BOOL SGListDragInfo::GetStatusLineText(String_256 * TheText) 01275 { 01276 ERROR3IF(TheText == NULL, "Illegal NULL param"); 01277 TheText->MakeMsg(_R(IDS_SGDRAG_LISTITEM)); 01278 01279 return(TRUE); 01280 } 01281 01282 01283 01284 /******************************************************************************************** 01285 01286 > void SGListDragInfo::OnClick(INT32 Flags,POINT Point) 01287 01288 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01289 Created: 14/3/95 01290 Inputs: Flags - Some flags 01291 Point - the point which was clicked 01292 01293 Purpose: This is called if a drag was attempted but never started because it was a 01294 click all along. It passes the original Click information back to the 01295 SGDisplayNode which started the drag by calling its DragWasReallyAClick 01296 method 01297 01298 SeeAlso: SGDisplayNode::DragWasReallyAClick 01299 01300 ********************************************************************************************/ 01301 01302 void SGListDragInfo::OnClick(INT32 Flags, POINT Point) 01303 { 01304 if (DragNode != NULL) 01305 { 01306 SGMiscInfo MiscInfo; 01307 ParentGallery->FillInMiscInfo(&MiscInfo); 01308 01309 DragNode->DragWasReallyAClick(&MouseInfo, &MiscInfo); 01310 } 01311 } 01312 01313