00001 // $Id: sgtree.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 00099 // SGTree.cpp - super gallery DisplayTree classes 00100 00101 00102 #include "camtypes.h" 00103 00104 #include "dlgmgr.h" 00105 //#include "document.h" // For Document->GetTitle() - in camtypes.h [AUTOMATICALLY REMOVED] 00106 #include "dragmgr.h" // Drag manager (DragManagerOp::StartDrag, RedrawStarting etc) 00107 //#include "galres.h" // Gallery bitmap resources 00108 //#include "galstr.h" // Gallery string resources 00109 //#include "scroller.h" // For scroll bar width 00110 //#include "sgallery.h" // SuperGallery definitions - in camtypes.h [AUTOMATICALLY REMOVED] 00111 #include "sgdrag.h" // Scroll bar drag target/info 00112 //#include "sgtree.h" // This file's associated header - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "sglib.h" // For virtualising static switch 00114 //#include "sglcart.h" 00115 00116 #include "ccdc.h" // For render-into-dialogue support 00117 //#include "sglfills.h" 00118 #include "dlgcol.h" 00119 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 //#include "grnddib.h" 00121 00122 //#include "richard3.h" // For _R(IDS_GALLERY_PREPARE_FOR_UNFOLD) 00123 #include "progress.h" 00124 // Webster stuff 00125 //#include "webster.h" 00126 //#include "inetop.h" 00127 00128 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00129 00130 // Implement the dynamic class bits... 00131 CC_IMPLEMENT_DYNAMIC(SGDisplayNode, CCObject) 00132 CC_IMPLEMENT_DYNAMIC(SGDisplayRoot, SGDisplayNode) 00133 CC_IMPLEMENT_DYNAMIC(SGDisplayRootScroll, SGDisplayRoot) 00134 CC_IMPLEMENT_DYNAMIC(SGDisplayGroup, SGDisplayNode) 00135 CC_IMPLEMENT_DYNAMIC(SGDisplayItem, SGDisplayNode) 00136 00137 00138 // This line mustn't go before any CC_IMPLEMENT_... macros 00139 #define new CAM_DEBUG_NEW 00140 00141 00142 static INT32 ScrollBarWidth = 10; // Width (PIXELS) of an SGDisplayRootScroll 00143 // provided gallery list scrollbar. MUST be even! 00144 00145 00146 SGDisplayNode *SGDisplayNode::CurrentBGRenderNode = NULL; 00147 BOOL SGDisplayNode::BGRenderClaimed= FALSE; 00148 BOOL SGDisplayNode::BkgEraseMode = TRUE; 00149 00150 00151 /*********************************************************************************************** 00152 00153 > SGDisplayNode::SGDisplayNode() 00154 00155 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00156 Created: 20/10/94 00157 Purpose: SGDisplayNode constructor 00158 SeeAlso: SuperGallery; SGDisplayGroup; SGDisplayItem 00159 00160 ***********************************************************************************************/ 00161 00162 SGDisplayNode::SGDisplayNode() 00163 { 00164 Parent = Next = Previous = NULL; 00165 00166 Flags.Invisible = Flags.ReadOnly = Flags.Modified = FALSE; 00167 Flags.CanSelect = Flags.Selected = FALSE; 00168 Flags.Folded = Flags.RedrawPending = FALSE; 00169 Flags.Virtualised = FALSE; 00170 00171 Flags.HandleEventCount = 0; 00172 00173 Flags.Reserved = 0; 00174 00175 FormatRect = DocRect(0,0,0,0); 00176 } 00177 00178 00179 00180 /*********************************************************************************************** 00181 00182 > SGDisplayNode::~SGDisplayNode() 00183 00184 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00185 Created: 20/10/94 00186 Purpose: SGDisplayNode destructor 00187 SeeAlso: SuperGallery; SGDisplayGroup; SGDisplayItem 00188 00189 ***********************************************************************************************/ 00190 00191 SGDisplayNode::~SGDisplayNode() 00192 { 00193 ERROR3IF(Flags.HandleEventCount > 0, "AWOOGA! SGDisplayNode deleted while in its own HandleEvent method - Alert Jason!"); 00194 ERROR3IF(Flags.HandleEventCount != 0, "Deleted SGDisplayNode had a corrupted HandleEventCount"); 00195 00196 if (Parent != NULL || GetChild() != NULL || Next != NULL || Previous != NULL) 00197 { 00198 ERROR3("Destructing SGDisplayNode which is still linked into a tree! I'll try to delink it first\n"); 00199 RemoveFromTree(); 00200 } 00201 } 00202 00203 00204 00205 /*********************************************************************************************** 00206 00207 > virtual SGDisplayNode *SGDisplayNode::GetChild(void) const 00208 00209 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00210 Created: 20/10/94 (Made virtual on 13/5/95) 00211 00212 Returns: A pointer to the first child of this SGDisplayNode object, or NULL 00213 00214 Purpose: Finds the child of this DisplayTree Node. 00215 Returns NULL if you have reached the boundary of the tree 00216 00217 Notes: This base-class method returns NULL - base nodes and items do not have 00218 children (to reduce memory usage). SGDisplayRoot and SGDisplayGroup override 00219 this method to provide child pointers. 00220 00221 SeeAlso: SGDisplayNode::SetChild; SuperGallery; SGDisplayNode::GetParent; 00222 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 00223 00224 ***********************************************************************************************/ 00225 00226 SGDisplayNode *SGDisplayNode::GetChild(void) const 00227 { 00228 return NULL; 00229 } 00230 00231 00232 00233 /*********************************************************************************************** 00234 00235 > void SGDisplayNode::SetChild(SGDisplayNode *NewChild) 00236 00237 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00238 Created: 20/10/94 00239 00240 Inputs: A pointer to the new first-child of this SGDisplayNode object 00241 00242 Purpose: Sets the child of this DisplayTree Node. 00243 00244 Notes: This base-class method gives an ERROR3 - base nodes and items do not have 00245 children (to reduce memory usage). SGDisplayRoot and SGDisplayGroup override 00246 this method to provide child pointers. 00247 00248 SeeAlso: SuperGallery; SGDisplayNode::GetParent; 00249 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 00250 00251 ***********************************************************************************************/ 00252 00253 void SGDisplayNode::SetChild(SGDisplayNode *NewChild) 00254 { 00255 ERROR3("This is a childless SGDisplayNode - You cannot set it's child!"); 00256 } 00257 00258 00259 00260 /*********************************************************************************************** 00261 00262 > virtual void SGDisplayNode::InsertInternal(SGDisplayNode *NodeToInsert, 00263 SGDisplayNode *PrevNode, SGDisplayNode *NextNode) 00264 00265 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00266 Created: 20/10/94 00267 00268 Inputs: NodeToInsert - the node to insert 00269 PrevNode - NULL, or the node to insert after 00270 NextNode - NULL, or the node to insert before 00271 00272 Purpose: Inserts the given node/subtree into this subtree, between PrevNode and 00273 NextNode. One of these two nodes may be NULL if you are trying to insert 00274 at the head/tail of a sibling list. 00275 00276 Errors: ERROR3s will be reported in debug builds for NULL NodeToInsert, or if 00277 NodeToInsert is linked into another tree (has non-null parent/next/previous 00278 pointers). It is perfectly legal for it to have a child subtree, though. 00279 00280 Errors will also occur if BOTH Next/PrevNode are NULL, or if PrevNode is 00281 not currently the Previous Node of NextNode. (i.e. you must insert between 00282 two valid adjacent nodes, or at the head/tail of the sibling list) 00283 00284 SeeAlso: SuperGallery; SGDisplayNode::AddItem; 00285 SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 00286 00287 ***********************************************************************************************/ 00288 00289 void SGDisplayNode::InsertInternal(SGDisplayNode *NodeToInsert, 00290 SGDisplayNode *PrevNode, SGDisplayNode *NextNode) 00291 { 00292 if (NodeToInsert == NULL) 00293 { 00294 ERROR3("Attempt to insert a NULL node into a tree was ignored"); 00295 return; 00296 } 00297 00298 // The node cannot be inserted after/before *itself*! 00299 ERROR3IF(NodeToInsert == PrevNode || NodeToInsert == NextNode, 00300 "Illegal attempt to link a node before/after ITSELF!"); 00301 00302 // The node cannot have parent, next, prev, but can have children 00303 ERROR3IF(NodeToInsert->Parent != NULL || 00304 NodeToInsert->Next != NULL || NodeToInsert->Previous != NULL, 00305 "Illegal attempt to link an already-linked node into a tree"); 00306 00307 ERROR3IF(PrevNode == NULL && NextNode == NULL, 00308 "SGDisplayNode::InsertInternal - can't insert between TWO NULL nodes!"); 00309 00310 ERROR3IF((PrevNode != NULL && PrevNode->Next != NextNode) || 00311 (NextNode != NULL && NextNode->Previous != PrevNode), 00312 "SGDisplayNode::InsertInternal - Prev/Next nodes are not adjacent!"); 00313 00314 NodeToInsert->Previous = PrevNode; 00315 if (PrevNode != NULL) 00316 { 00317 // Linking in the middle of the sibling list 00318 PrevNode->Next = NodeToInsert; 00319 NodeToInsert->Parent = PrevNode->Parent; 00320 } 00321 else 00322 { 00323 // Must be trying to insert at the head of the sibling list, so becomes 1st child 00324 if (NextNode != NULL) 00325 { 00326 ERROR3IF(NextNode->Parent->GetChild() != NextNode, 00327 "Attempt to Insert node as first child has gone awry!"); 00328 00329 NextNode->Parent->SetChild(NodeToInsert); 00330 } 00331 } 00332 00333 NodeToInsert->Next = NextNode; 00334 if (NextNode != NULL) 00335 { 00336 NextNode->Previous = NodeToInsert; 00337 NodeToInsert->Parent = NextNode->Parent; 00338 } 00339 00340 // Because we have recreated part of the tree, we must inform the gallery that the 00341 // cached format is incorrect and needs to be recalculated. 00342 SuperGallery *ParentGallery = GetParentGallery(); 00343 if (ParentGallery != NULL) 00344 ParentGallery->InvalidateCachedFormat(); 00345 } 00346 00347 00348 00349 /*********************************************************************************************** 00350 00351 > virtual void SGDisplayNode::AddItem(SGDisplayNode *NodeToInsert, 00352 SGSortKey *SortInfo = NULL) 00353 00354 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00355 Created: 20/10/94 00356 00357 Inputs: NodeToInsert - the node/subtree to be inserted 00358 SortInfo - NULL, or an array of MaxSGSortKeys sort key structures which 00359 describe how the item should be inserted. [NOTE that this parameter is 00360 only used for insertion of SGDisplayItem and derived classes] 00361 00362 Purpose: Inserts the given node/subtree into this subtree. If SortInfo == NULL or 00363 NodeToInsert is not an SGDisplayItem, it is added as the last child of 00364 this node. Otherwise, it is inserted into the subtree of SGDisplayItems 00365 at the point 'specified' by SortInfo (By asking each DisplayItem in turn 00366 to compare itself to the one being added, until one is found which is 00367 considered "greater than" this one according to the sort mode) 00368 00369 Errors: ERROR3s will be reported in debug builds for NULL NodeToInsert, or if 00370 NodeToInsert is linked into another tree (has non-null parent/next/previous 00371 pointers). It is perfectly legal for it to have a child subtree, though. 00372 00373 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 00374 00375 ***********************************************************************************************/ 00376 00377 void SGDisplayNode::AddItem(SGDisplayNode *NodeToInsert, SGSortKey *SortInfo) 00378 { 00379 if (NodeToInsert == NULL) 00380 { 00381 ERROR3("Attempt to add a NULL node to a tree was ignored"); 00382 return; 00383 } 00384 00385 // The node cannot have parent, next, prev, but can have children 00386 ERROR3IF(NodeToInsert->Parent != NULL || 00387 NodeToInsert->Next != NULL || NodeToInsert->Previous != NULL, 00388 "Illegal attempt to link an already-linked node into a tree"); 00389 00390 if (GetChild() == NULL) // We have no children, so there is only one place for this node! 00391 { 00392 SetChild(NodeToInsert); // Add it as our first child and return 00393 NodeToInsert->Parent = this; 00394 00395 // Because we have recreated part of the tree, we must inform the gallery that the 00396 // cached format is incorrect and needs to be recalculated. 00397 SuperGallery *ParentGallery = GetParentGallery(); 00398 if (ParentGallery != NULL) 00399 ParentGallery->InvalidateCachedFormat(); 00400 return; 00401 } 00402 00403 SGDisplayNode *Ptr = GetChild(); 00404 SGDisplayNode *Last = NULL; 00405 00406 if (SortInfo == NULL || SortInfo[0].SortKey == 0 || 00407 !NodeToInsert->IsKindOf(CC_RUNTIME_CLASS(SGDisplayItem)) || 00408 !IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup))) 00409 { 00410 // There is no requested sort mode, or it is sort-by-none, or the node being inserted 00411 // is not a DisplayItem, or I am not a DisplayGroup, so I just add the item to the end 00412 // of my child list 00413 00414 while (Ptr != NULL) // Find the end of the sibling list 00415 { 00416 Last = Ptr; 00417 Ptr = Ptr->Next; 00418 } 00419 00420 // This ENSURE should never occur, as we checked for no-children above 00421 ERROR3IF(Last == NULL, "Something screwy has happened in SGDisplayNode:AddItem!"); 00422 InsertInternal(NodeToInsert, Last, NULL); // Insert it as the last child 00423 } 00424 else 00425 { 00426 // While searching givvus a parent! (bodge so libraries can sort whilst adding) 00427 NodeToInsert->Parent = this; 00428 00429 // We can add with sorting, so add the item at an appropriate position based upon 00430 // the provided sort mode 00431 INT32 Result; 00432 while (Ptr != NULL) // Search the sibling list for the first appropriate insertion point 00433 { 00434 Last = Ptr; 00435 00436 // Compare using sort key 1 00437 Result = Ptr->CompareTo(NodeToInsert, SortInfo[0].SortKey); 00438 if (SortInfo[0].Reversed) 00439 Result = -Result; 00440 00441 // If they are equal, and we have multi-key sort, use key 2 00442 if (Result == 0 && SortInfo[1].SortKey != 0) 00443 { 00444 Result = Ptr->CompareTo(NodeToInsert, SortInfo[1].SortKey); 00445 if (SortInfo[1].Reversed) 00446 Result = -Result; 00447 } 00448 00449 // We have compared - if the current item is "greater" than the one being 00450 // inserted, then we can stop and insert it before that item 00451 if (Result > 0) 00452 break; 00453 00454 Ptr = Ptr->Next; 00455 } 00456 00457 // Delink the parent since it shouldn't really be connected yet 00458 NodeToInsert->Parent = NULL; 00459 00460 if (Ptr == NULL) 00461 { 00462 // We must have run off the end of the list - insert at the end 00463 ERROR3IF(Last == NULL, "Something screwy has happened in SGDisplayNode:AddItem!"); 00464 InsertInternal(NodeToInsert, Last, NULL); 00465 } 00466 else 00467 { 00468 // We found an item to insert before, so insert before it 00469 InsertInternal(NodeToInsert, Ptr->GetPrevious(), Ptr); 00470 } 00471 } 00472 } 00473 00474 00475 00476 /*********************************************************************************************** 00477 00478 > virtual void SGDisplayNode::InsertAfter(SGDisplayNode *NodeToInsert) 00479 00480 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00481 Created: 20/10/94 00482 00483 Inputs: NodeToInsert - the node to, ... erm... insert. 00484 00485 Purpose: Inserts the given node into the DisplayTree as the next (right) sibling 00486 of this node. 00487 00488 Notes: The derived SGDisplayRoot node overrides this with a call to AddItem() 00489 00490 Errors: ERROR3 and quiet exit if NodeToInsert == NULL 00491 00492 SeeAlso: SuperGallery; SGDisplayNode::InsertBefore; SGDisplayNode::AddItem 00493 00494 ***********************************************************************************************/ 00495 00496 void SGDisplayNode::InsertAfter(SGDisplayNode *NodeToInsert) 00497 { 00498 // Set the parent to modified to signify that one of it's children has been 00499 SGDisplayNode *Parent = GetParent(); 00500 if(Parent != NULL) 00501 Parent->Flags.Modified = TRUE; 00502 00503 InsertInternal(NodeToInsert, this, Next); 00504 } 00505 00506 00507 00508 /*********************************************************************************************** 00509 00510 > virtual void SGDisplayNode::InsertBefore(SGDisplayNode *NodeToInsert) 00511 00512 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00513 Created: 20/10/94 00514 00515 Inputs: NodeToInsert - the node to, ... erm... insert. 00516 00517 Purpose: Inserts the given node into the DisplayTree as the previous (left) sibling 00518 of this node. 00519 00520 Notes: The derived SGDisplayRoot node overrides this with a call to AddItem() 00521 00522 Errors: ERROR3 and quiet exit if NodeToInsert == NULL 00523 00524 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::AddItem 00525 00526 ***********************************************************************************************/ 00527 00528 void SGDisplayNode::InsertBefore(SGDisplayNode *NodeToInsert) 00529 { 00530 // Set the parent to modified to signify that one of it's children has been 00531 SGDisplayNode *Parent = GetParent(); 00532 if(Parent != NULL) 00533 Parent->Flags.Modified = TRUE; 00534 00535 InsertInternal(NodeToInsert, Previous, this); 00536 } 00537 00538 00539 00540 /*********************************************************************************************** 00541 00542 > virtual void SGDisplayNode::MoveAfter(SGDisplayNode *NodeToMove) 00543 00544 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00545 Created: 14/3/95 00546 00547 Inputs: NodeToMove - the node to move 00548 00549 Purpose: MOVES the given node (to a different position in the DisplayTree) as the 00550 previous (left) sibling of this node. If the node is not linked into 00551 a tree, it is effectively just inserted. 00552 00553 Notes: This base class method simply delinks the item and relinks it elsewhere 00554 in the display tree. However, derived classes will override this method 00555 so that moving display items can have a further effect of also rearranging 00556 the displayed "real" items. Before/After moving the real item, the 00557 derived class can then call this baseclass method to complete the action. 00558 00559 Take care when moving items between groups (e.g. if an item is "moved" 00560 from one docuemnt to another, it could be a bad thing, so be very 00561 careful in derived classes to take appropriate action) 00562 00563 Any attempt to move an item after *itself* is queitly ignored 00564 00565 Errors: ERROR3 and quiet exit if NodeToMove == NULL 00566 00567 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::AddItem 00568 00569 ***********************************************************************************************/ 00570 00571 void SGDisplayNode::MoveAfter(SGDisplayNode *NodeToMove) 00572 { 00573 ERROR3IF(NodeToMove == NULL, "Illegal NULL param"); 00574 00575 if (NodeToMove == this) 00576 return; 00577 00578 NodeToMove->RemoveFromTree(); 00579 InsertAfter(NodeToMove); 00580 } 00581 00582 00583 00584 /*********************************************************************************************** 00585 00586 > virtual void SGDisplayNode::MoveBefore(SGDisplayNode *NodeToMove) 00587 00588 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00589 Created: 14/3/95 00590 00591 Inputs: NodeToMove - the node to move 00592 00593 Purpose: MOVES the given node (to a different position in the DisplayTree) as the 00594 previous (left) sibling of this node. If the node is not linked into 00595 a tree, it is effectively just inserted. 00596 00597 Notes: This base class method simply delinks the item and relinks it elsewhere 00598 in the display tree. However, derived classes will override this method 00599 so that moving display items can have a further effect of also rearranging 00600 the displayed "real" items. Before/After moving the real item, the 00601 derived class can then call this baseclass method to complete the action. 00602 00603 Take care when moving items between groups (e.g. if an item is "moved" 00604 from one docuemnt to another, it could be a bad thing, so be very 00605 careful in derived classes to take appropriate action) 00606 00607 Any attempt to move an item before *itself* is queitly ignored 00608 00609 Errors: ERROR3 and quiet exit if NodeToMove == NULL 00610 00611 SeeAlso: SuperGallery; SGDisplayNode::InsertBefore; SGDisplayNode::AddItem 00612 00613 ***********************************************************************************************/ 00614 00615 void SGDisplayNode::MoveBefore(SGDisplayNode *NodeToMove) 00616 { 00617 ERROR3IF(NodeToMove == NULL, "Illegal NULL param"); 00618 00619 if (NodeToMove == this) 00620 return; 00621 00622 NodeToMove->RemoveFromTree(); 00623 InsertBefore(NodeToMove); 00624 } 00625 00626 00627 00628 /*********************************************************************************************** 00629 00630 > virtual void SGDisplayNode::RemoveFromTree(void) 00631 00632 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00633 Created: 20/10/94 00634 00635 Purpose: De-links this node/subtree from the DisplayTree. This DOES NOT DELETE the 00636 node, just unlinks it in preparation for being deleted. 00637 00638 Notes: This does NOT delink children of this node from this node. To do that, you 00639 must call RemoveFromTree from each child node in turn. To delete a subtree 00640 you are better off calling DestroySubtree 00641 00642 Errors: ERROR3s will be reported in debug builds if certain corrupted tree 00643 structures are detected, indicating tree generation/maintenance code 00644 has gone wrong 00645 00646 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; 00647 SGDisplayNode::InsertBefore; SGDisplayNode::AddItem; 00648 SGDisplayNode::DestroySubtree 00649 00650 ***********************************************************************************************/ 00651 00652 void SGDisplayNode::RemoveFromTree(void) 00653 { 00654 // Because we have changed part of the tree, we must inform the gallery that the 00655 // cached format is incorrect and needs to be recalculated. We must also make sure 00656 // that this item is not pending a background redraw. 00657 SuperGallery *ParentGallery = GetParentGallery(); 00658 if (ParentGallery != NULL) 00659 { 00660 // Ensure that the ParentGallery doesn't dereference this pointer on the next background 00661 // rendering pass (if we happen to be removed just after redrawing in the BG) 00662 if (this == ParentGallery->GetLastBackgroundNode()) 00663 ParentGallery->SetLastBackgroundNode(NULL); 00664 00665 if (Flags.RedrawPending) 00666 ParentGallery->DecrementPendingRedraws(); 00667 00668 ParentGallery->InvalidateCachedFormat(); 00669 } 00670 00671 Flags.RedrawPending = FALSE; // We are NOT pending a redraw! 00672 00673 if (Next == NULL) 00674 { 00675 // If the next sibling ptr is NULL, then we are at the end of a group or the list 00676 // so we 'touch' the previous node (or parent) FormatRect so that the next reformat 00677 // realises that a change has occurred around here and redraws where we were. 00678 SGDisplayNode *ToTouch = Previous; 00679 if (ToTouch == NULL) 00680 ToTouch = Parent; 00681 00682 if (ToTouch != NULL) 00683 ToTouch->FormatRect.MakeEmpty(); 00684 } 00685 00686 // Delink our Parent from ourself 00687 if (Parent != NULL) 00688 { 00689 if (Parent->GetChild() == this) // If we are first child, make Next child the first 00690 { 00691 // I must be the first child, so should not have a Previous node 00692 ERROR3IF(Previous != NULL, "Tree linking failure detected in SGDisplayNode::RemoveFromTree"); 00693 Parent->SetChild(Next); 00694 } 00695 else 00696 { 00697 // I am not the parent's first child, so I must have a Previous node 00698 ERROR3IF(Previous == NULL, "Tree linking failure detected in SGDisplayNode::RemoveFromTree"); 00699 } 00700 } 00701 00702 00703 // Delink our Previous/Next siblings (if any) from ourself 00704 if (Previous != NULL) 00705 Previous->Next = Next; 00706 00707 if (Next != NULL) 00708 Next->Previous = Previous; 00709 00710 00711 // And finally, destroy our own backward links to parent, next, previous. 00712 // Done last to avoid 'losing' pointers before we have finished using them for delinking! 00713 Parent = NULL; 00714 Previous = NULL; 00715 Next = NULL; 00716 } 00717 00718 00719 00720 /*********************************************************************************************** 00721 00722 > virtual void SGDisplayNode::DestroySubtree(BOOL IncludingThisNode = TRUE) 00723 00724 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00725 Created: 21/10/94 00726 00727 Inputs: IncludingThisNode - TRUE (The default) to delete this node (the root of 00728 the subtree) as well as all its children. 00729 FALSE to delete its children only (This leaves this node untouched, but 00730 vapes all child nodes) 00731 00732 Purpose: DESTROYS the subtree starting at (and including, if IncludingThisNode is 00733 TRUE) this node. 00734 This does a depth-first recursive scan of the subtree, delinking each item, 00735 and then CALLING EACH ITEMS DESTRUCTOR. 00736 00737 Notes: If you destroy at the root node, the entire tree is destroyed. The root node 00738 will be deleted, but note that the reference(s) to the root node (e.g. in 00739 the parent SuperGallery) will NOT be de-linked, so be *very* careful! 00740 00741 However, if the root node is a derived SGDisplayRoot node, it will refuse 00742 to delete itself in this case, 00743 00744 Errors: May be generated by the RemoveFromTree and destructor calls if the subtree 00745 is in some way corrupt - see these calls for details. 00746 00747 An ERROR3 may be caused by the destructor if you are trying to delete 00748 a tree item from within that item's event handler! 00749 00750 SeeAlso: SuperGallery; SGDisplayNode::RemoveFromTree; SGDisplayNode::~SGDisplayNode 00751 00752 ***********************************************************************************************/ 00753 00754 void SGDisplayNode::DestroySubtree(BOOL IncludingThisNode) 00755 { 00756 while (GetChild() != NULL) // Recurse depth-first down the subtree, destroying it 00757 GetChild()->DestroySubtree(); // Destroy child. Child now points at the next child 00758 00759 if (IncludingThisNode) // If this node is included in the destruction... 00760 { 00761 RemoveFromTree(); // Delink ourself from the tree 00762 delete this; // and invoke our own destructor 00763 } 00764 } 00765 00766 00767 00768 /*********************************************************************************************** 00769 00770 > virtual SuperGallery *SGDisplayNode::GetParentGallery(void) const 00771 00772 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00773 Created: 17/1/95 00774 00775 Returns: NULL if a cataclysmic event occurs 00776 Otherwise,a pointer to the SuperGallery that 'owns' the tree this node is in 00777 00778 Purpose: Recursively scans up the tree asking each parent node in turn for the parent 00779 gallery. It is expected that a node (eg SGDisplayRoot or SGDisplayGroup) 00780 will be found somewhere on this path which will know who our parent gallery 00781 is. (If not, there is a serious tree problem!) 00782 00783 Nodes which directly know their parent gallery must override this method 00784 to ensure that they return the correct result instead of asking their parent! 00785 00786 SeeAlso: SGDisplayRoot::GetParentGallery; SGDisplayGroup::GetParentGallery 00787 00788 ***********************************************************************************************/ 00789 00790 SuperGallery *SGDisplayNode::GetParentGallery() const 00791 { 00792 if (GetParent() != NULL) return GetParent()->GetParentGallery(); 00793 00794 return NULL; 00795 } 00796 00797 00798 00799 /*********************************************************************************************** 00800 00801 > virtual BOOL SGDisplayNode::GiveEventToMyChildren(SGEventType EventType, 00802 void *EventInfo, 00803 SGMiscInfo *MiscInfo) 00804 00805 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00806 Created: 20/10/94 00807 00808 Inputs: EventType - An enumerated value describing what type of event is to be processed 00809 00810 EventInfo - A structure describing the event (may be NULL). The exact thing 00811 pointed at by this pointer depends upon the event type: 00812 00813 MonoOn 00814 Event Thing EventInfo points at 00815 SGEVENT_FORMAT (SGFormatInfo *) 00816 SGEVENT_REDRAW (SGRedrawInfo *) 00817 SGEVENT_MOUSECLICK (SGMouseInfo *) 00818 MonoOff 00819 00820 Use the SGDisplayNode::Get[Format]Info() inlines to retrieve 00821 this information for you (it does helpful ERROR3 checking for you) 00822 00823 MiscInfo - A structure containing any other relevant information. 00824 This will always be non-NULL, and contain valid information. 00825 00826 Outputs: FormatInfo is updated as appropriate 00827 00828 Returns: TRUE if the event was handled successfully 00829 FALSE if it was not 00830 00831 Purpose: Causes the entire subtree below this node to check their formatting, and 00832 handle the given event. Once a node returns TRUE from its HandleEvent method, 00833 the event will NOT be passed on. 00834 00835 Notes: This is used by derived classes to save them the work of 00836 having to scan the tree in their own event code - each node just 00837 redraws itself, and then passes the event along by calling this 00838 function. 00839 00840 If this node is folded, then it is treated as having no children (as they 00841 do not appear in the displayed list. 00842 00843 The traversal loops in this code can handle any nodes being deleted around 00844 them, except for the "current node". However, in debug builds the "current 00845 node" should refuse to be deleted while it is handling an event. 00846 The traversal loops increment the "HandleEventCount" during calls to all the 00847 node HandleEvent methods in order to be able to detect this situation (It's 00848 done here to save doing it in all derived HandleEvent methods). 00849 00850 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayRoot::HandleEvent; 00851 SGDisplayGroup::HandleEvent; SGDisplayItem::HandleEvent 00852 00853 ***********************************************************************************************/ 00854 00855 BOOL SGDisplayNode::GiveEventToMyChildren(SGEventType EventType, void *EventInfo, 00856 SGMiscInfo *MiscInfo) 00857 { 00858 BOOL Handled = FALSE; 00859 SGDisplayNode *Ptr = GetChild(); 00860 // SGDisplayNode *NextPtr = NULL; 00861 00862 if (EventType == SGEVENT_FORMAT) 00863 { 00864 // We're formatting, so update FormatInfo as we go 00865 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 00866 00867 NewLine(FormatInfo, MiscInfo); // When going down the tree, go to a new line 00868 00869 if (Flags.Folded || Ptr == NULL) // If folded, or no children, return 00870 return(FALSE); 00871 00872 if (!Flags.Invisible) 00873 FormatInfo->IndentLevel++; // Increment the indent level 00874 00875 while (Ptr != NULL && !Handled) 00876 { 00877 // Call each child's handler in turn. We can cope with any child being deleted except 00878 // for the current one. To detect this, we increment HandleEventCOunt across the 00879 // call, which will trigger ERROR3's in the destructor if we attempt suicide! 00880 Ptr->Flags.HandleEventCount++; 00881 ERROR3IF(Ptr->Flags.HandleEventCount > 100, 00882 "Rampant recursion or node corruption in GiveEventToMyChildren"); 00883 if (Ptr->HandleEvent(EventType, EventInfo, MiscInfo)) 00884 Handled = TRUE; 00885 Ptr->Flags.HandleEventCount--; 00886 00887 Ptr = Ptr->Next; 00888 } 00889 00890 if (!Flags.Invisible) 00891 FormatInfo->IndentLevel--; // Restore the indent level 00892 00893 NewLine(FormatInfo, MiscInfo); // When ascending back up the tree, go to a new line 00894 00895 FormatInfo->LineHeight = UpTreeGap; 00896 NewLine(FormatInfo, MiscInfo); // ... and add a small gap 00897 } 00898 else 00899 { 00900 if (Ptr == NULL) // We have no children, so return 00901 return(FALSE); 00902 00903 if (EventType != SGEVENT_BGFLUSH && Flags.Folded) 00904 { 00905 // If folded, return (but not if this is a FLUSH, which MUST go to ALL) 00906 return(FALSE); 00907 } 00908 00909 while (Ptr != NULL && !Handled) 00910 { 00911 // Call each child's handler in turn. We can cope with any child being deleted except 00912 // for the current one. To detect this, we increment HandleEventCOunt across the 00913 // call, which will trigger ERROR3's in the destructor if we attempt suicide! 00914 Ptr->Flags.HandleEventCount++; 00915 ERROR3IF(Ptr->Flags.HandleEventCount > 100, 00916 "Rampant recursion or node corruption in GiveEventToMyChildren"); 00917 if (Ptr->HandleEvent(EventType, EventInfo, MiscInfo)) 00918 Handled = TRUE; 00919 Ptr->Flags.HandleEventCount--; 00920 00921 Ptr = Ptr->Next; 00922 } 00923 } 00924 00925 return(Handled); 00926 } 00927 00928 00929 00930 /*********************************************************************************************** 00931 00932 > virtual void SGDisplayNode::NewLine(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo) 00933 00934 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00935 Created: 24/10/94 00936 00937 Inputs: FormatInfo - A structure containing all relevant information for items to 00938 calculate their formatted positions in the display list 00939 00940 Outputs: FormatInfo is updated as appropriate 00941 00942 Purpose: Resets the formatting info structure to default values for the start of 00943 the next 'line'. 00944 00945 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayRoot::HandleEvent; 00946 SGDisplayGroup::HandleEvent; SGDisplayItem::HandleEvent 00947 00948 ***********************************************************************************************/ 00949 00950 void SGDisplayNode::NewLine(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo) 00951 { 00952 if (FormatInfo->LineHeight > 0) 00953 { 00954 FormatInfo->LineHeight = GridLock(MiscInfo, FormatInfo->LineHeight) + 00955 GridLock(MiscInfo, InterLineGap); 00956 FormatInfo->LinePos -= FormatInfo->LineHeight; 00957 } 00958 00959 FormatInfo->LineHeight = 0; 00960 FormatInfo->AvailableWidth = MiscInfo->MaxWidth - (FormatInfo->IndentLevel * IndentWidth); 00961 FormatInfo->AvailableWidth = GridLock(MiscInfo, FormatInfo->AvailableWidth); 00962 } 00963 00964 00965 00966 /*********************************************************************************************** 00967 00968 > void SGDisplayNode::GridLockRect(SGMiscInfo *MiscInfo, DocRect *Rect) 00969 00970 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00971 Created: 28/10/94 00972 00973 Inputs: FormatInfo - A structure containing all relevant information for items to 00974 calculate their formatted positions in the display list. NOTE this is also 00975 an output! 00976 00977 Rect - A rectangle which needs to be locked to the pixel grid 00978 00979 Outputs: FormatInfo - updated as appropriate 00980 Rect - modified as necessary to lock its points to the pixel grid 00981 00982 Purpose: Given a rectangle and the normal FormatInfo, this ensures that all points 00983 of the rectangle are snapped onto a grid of the destination device pixels. 00984 This ensures that aliasing effects, due to rounding errors when mapping 00985 to the output pixel coordinates, do not occur. 00986 00987 SeeAlso: SGDisplayNode::GridLock; SGDisplayNode::DevicePixels 00988 00989 ***********************************************************************************************/ 00990 00991 void SGDisplayNode::GridLockRect(SGMiscInfo *MiscInfo, DocRect *Rect) 00992 { 00993 Rect->lo.x = GridLock(MiscInfo, Rect->lo.x); 00994 Rect->lo.y = GridLock(MiscInfo, Rect->lo.y); 00995 Rect->hi.x = GridLock(MiscInfo, Rect->hi.x); 00996 Rect->hi.y = GridLock(MiscInfo, Rect->hi.y); 00997 } 00998 00999 01000 01001 /*********************************************************************************************** 01002 01003 > virtual void SGDisplayNode::CalculateFormatRect(SGFormatInfo *FormatInfo, 01004 SGMiscInfo *MiscInfo, 01005 INT32 ItemWidth, INT32 ItemHeight) 01006 01007 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01008 Created: 24/10/94 01009 01010 Inputs: FormatInfo - A structure containing all relevant information for items to 01011 calculate their formatted positions in the display list. NOTE this is also 01012 an output! (As passed into HandleEvent for SGEVENT_FORMAT events) 01013 01014 MiscInfo - Miscellaneous information needed for formatting; as passed 01015 into all HandleEvent calls 01016 01017 ItemWidth - The width of this item in millipoints, or 0 if this item 01018 is 'infinite' width (fills the entire line). If there is not enough space left 01019 on this line for the item, a new line is started. 01020 01021 ItemHeight - The height of this item in millipoints. Sibling items are 01022 currently expected to have equal heights; although line formatting will cope 01023 with different heights, redraw may miss strips below items for the time 01024 being. 01025 01026 Outputs: FormatInfo - updated as appropriate 01027 Member variable FormatRect now contains the format rectangle 01028 01029 Returns: TRUE if the resulting rectangle overlaps RedrawInfo->Bounds (i.e. if the 01030 node would need to redraw itself if handling a redraw request) 01031 else FALSE if the node need not be redrawn 01032 01033 Purpose: Given current formatting information, generates the rectangle within which 01034 this node and its subtree should be redrawn. 01035 01036 Notes: This relies upon the cached formatting information in this node being 01037 correct - this function can only be called once per node during a pass 01038 through the tree... the second call would give a different result. 01039 01040 If you do not use this function to do all the formatting work for you, then 01041 you must remember to either updaet the 'FormatRect' member variable, or 01042 override the 'GetFormatRect' member function to supply this information 01043 to the caller properly. 01044 01045 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayRoot::HandleEvent; 01046 SGDisplayGroup::HandleEvent; SGDisplayItem::HandleEvent 01047 01048 ***********************************************************************************************/ 01049 01050 void SGDisplayNode::CalculateFormatRect(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo, 01051 INT32 ItemWidth, INT32 ItemHeight) 01052 { 01053 ERROR3IF(FormatInfo == NULL || MiscInfo == NULL, 01054 "NULL parameter(s) passed to SGDisplayNode::CalculateFormatRect"); 01055 01056 if (Previous == NULL || // Is first child node, so go to a new line 01057 FormatInfo->AvailableWidth <= 0 || // No room left at all on this line 01058 FormatInfo->AvailableWidth < ItemWidth || // Not enough room on the line for this item 01059 ItemWidth == 0) // This item is infinitely wide 01060 { 01061 NewLine(FormatInfo, MiscInfo); 01062 } 01063 01064 // If items do not fill the entire width, add a 2-pixel gap at the right edge, so that 01065 // adjacent items have a small gap between them. (see below) 01066 if (ItemWidth != 0) 01067 ItemWidth += MiscInfo->PixelSize * 2; 01068 01069 ItemWidth = GridLock(MiscInfo, ItemWidth); 01070 ItemHeight = GridLock(MiscInfo, ItemHeight); 01071 01072 // We must now have enough room for this item across the current line, so plonk it in! 01073 // Update the height of the current line 01074 if (FormatInfo->LineHeight < ItemHeight) 01075 { 01076 // if (LineHeight != 0) AWOOGA! Line height has increased! Must go back and fill in 01077 // the background colour below the previous items on this line, to ensure the entire 01078 // line is fully redrawn. 01079 01080 ERROR3IF(FormatInfo->LineHeight != 0, 01081 "Sibling Display Item heights are not equal! Jason must upgrade the redraw code"); 01082 01083 FormatInfo->LineHeight = ItemHeight; 01084 } 01085 01086 // Generate the position rectangle. Note that this may be wider than MaxWidth - it is the 01087 // actual rectangle the item has (so scaling into the returned rect will always work, 01088 // even if part of the rectangle is clipped out of view). However, if the item was 01089 // requested as infinite width, it is returned as MaxWidth. 01090 INT32 ActualWidth = (ItemWidth == 0) ? FormatInfo->AvailableWidth : ItemWidth; 01091 01092 // Ensure it is clipped within the available window space 01093 if (ActualWidth > FormatInfo->AvailableWidth) 01094 ActualWidth = FormatInfo->AvailableWidth; 01095 01096 DocRect OldFormatRect(FormatRect); 01097 FormatRect.lo.x = MiscInfo->MaxWidth - FormatInfo->AvailableWidth; 01098 FormatRect.hi.x = FormatRect.lo.x + ActualWidth; 01099 FormatRect.lo.y = FormatInfo->LinePos - FormatInfo->LineHeight; 01100 FormatRect.hi.y = FormatInfo->LinePos; 01101 01102 // If items do not fill the entire width, add a 2-pixel gap at the right edge, so that 01103 // adjacent items have a small gap between them. (see above) 01104 if (ActualWidth < FormatInfo->AvailableWidth) 01105 FormatRect.hi.x -= MiscInfo->PixelSize * 2; 01106 01107 GridLockRect(MiscInfo, &FormatRect); // And ensure it is locked onto the grid 01108 01109 // If this node is no longer in the same position as it was last time we formatted, 01110 // then accumulate its Y bounds into the 'InvalidBounds' rect, to allow the gallery 01111 // to redraw only those regions of the list which are invalid 01112 if (FormatInfo->AccumulateBounds) 01113 { 01114 if (OldFormatRect != FormatRect) 01115 { 01116 FormatInfo->LastInvalidNode = this; // We are the last node found to have invalid bounds 01117 01118 if (FormatInfo->InvalidBounds.hi.y > 0) // If we haven't found an invalid item before 01119 FormatInfo->InvalidBounds.hi.y = FormatRect.hi.y; 01120 01121 if (FormatInfo->InvalidBounds.lo.y > FormatRect.lo.y) 01122 FormatInfo->InvalidBounds.lo.y = FormatRect.lo.y; 01123 } 01124 else 01125 { 01126 if (FormatInfo->LastInvalidNode != NULL) 01127 { 01128 // The immediately previous node had invalid bounds. If we lie below the current 01129 // invalid bounds, then we extend them to touch the top of us, to include any gap 01130 // between them and us. 01131 01132 ERROR3IF(FormatInfo->InvalidBounds.hi.y > 0, 01133 "Gallery display formatting error - LastInvalidNode should be NULL " 01134 "if there haven't been any invalid nodes yet"); 01135 01136 if (FormatInfo->InvalidBounds.lo.y > FormatRect.hi.y) 01137 FormatInfo->InvalidBounds.lo.y = FormatRect.hi.y; 01138 01139 FormatInfo->LastInvalidNode = NULL; // Reset LastInvalid node so that the next node doesn't extend! 01140 } 01141 } 01142 } 01143 01144 // if (Flags.Invisible) 01145 // { 01146 // FormatRect.hi.x = FormatRect.lo.x; 01147 // FormatRect.hi.y = FormatRect.lo.y; 01148 // } 01149 01150 // Update the free width on the end of this line. Note that this may now be 0 or -ve, 01151 // but this will be sorted out on the next call to this method, in the clauses above. 01152 // if (!Flags.Invisible) 01153 // { 01154 FormatInfo->AvailableWidth -= ActualWidth; 01155 GridLock(MiscInfo, FormatInfo->AvailableWidth); 01156 // } 01157 } 01158 01159 01160 01161 /*********************************************************************************************** 01162 01163 > virtual BOOL SGDisplayNode::SetFoldedState(BOOL NewState, BOOL ForceRedraw = TRUE) 01164 01165 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01166 Created: 15/4/95 01167 01168 Inputs: NewState - TRUE to fold, FALSE to unfold 01169 01170 Returns: TRUE if the new state is different from the old state (if anything has changed) 01171 01172 Purpose: Folds or unfolds a display node 01173 01174 Notes: This base-class implementation gives an ERROR3 - use folding only on groups 01175 01176 ***********************************************************************************************/ 01177 01178 BOOL SGDisplayNode::SetFoldedState(BOOL NewState, BOOL ForceRedraw) 01179 { 01180 ERROR3("Folding can only be applied to groups!"); 01181 return(FALSE); 01182 } 01183 01184 01185 01186 /*********************************************************************************************** 01187 01188 > void SGDisplayNode::SetSelected(BOOL IsSelected = TRUE) 01189 01190 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01191 Created: 28/10/94 01192 01193 Inputs: IsSelected - TRUE to select, FALSE to deselect this item 01194 01195 Purpose: Sets the selection state of a SuperGallery Display Item tree node. 01196 Note that this does not cause a redraw of the gallery list box or anything. 01197 After setting the state(s) of item(s) you must therefore redraw them. 01198 01199 Notes: An ENSURE will be generated by any node which cannot be selected. 01200 (Derived classes wishing to allow selection state changes should set 01201 Flags.CanSelect) 01202 01203 SeeAlso: SGDisplayItem::SetSelected; SGDisplayNode::IsSelected 01204 01205 ***********************************************************************************************/ 01206 01207 void SGDisplayNode::SetSelected(BOOL IsSelected) 01208 { 01209 ERROR3IF(!Flags.CanSelect, "Base class SGDisplayNode::SetSelected called! I'm not a selectable ITEM!"); 01210 01211 if (Flags.CanSelect && Flags.Selected != (UINT32)IsSelected) 01212 { 01213 Flags.Selected = (UINT32) IsSelected; 01214 ForceRedrawOfMyself(); 01215 } 01216 } 01217 01218 01219 01220 /*********************************************************************************************** 01221 01222 > virtual BOOL SGDisplayNode::HandleEvent(SGEventType EventType, void *EventInfo, 01223 SGMiscInfo *MiscInfo); 01224 01225 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01226 Created: 1/4/95 (was pure virtual before then) 01227 01228 Inputs: EventType - Indicates the event type to be handled (see SGEventType) 01229 01230 EventInfo - NULL, or points at a structure containing useful info 01231 for processing this specific event. (See SGEventInfo) 01232 01233 MiscInfo - Always supplied. Points at an SGMiscInfo struct which 01234 contains miscellanous useful information. 01235 01236 Purpose: Handles a generic display tree event. Events of interest trigger 01237 specific actions. 01238 01239 Generally overridden to provide redraw, mouse click, etc functionality. 01240 Overridden methos should call the base class for any event types 01241 which are unknown or which they do not specifically want to handle. 01242 01243 For a description of how to use this, see the documentation, or 01244 take a look at other SGDisplay* types and galleries for example code. 01245 01246 The base class doesn't do much, but does handle background redraw, and 01247 will pass all unhandled events on to its children (if any) 01248 01249 Documentation: docs\howtouse\sgallery.doc 01250 01251 ***********************************************************************************************/ 01252 01253 BOOL SGDisplayNode::HandleEvent(SGEventType EventType, void *EventInfo, SGMiscInfo *MiscInfo) 01254 { 01255 switch(EventType) 01256 { 01257 // Now handled by recursive DoBGRedrawPass method 01258 // case SGEVENT_BGREDRAW: 01259 // // Redraw in the background if necessary. This will return TRUE if it claims 01260 // // the event (the first one that successfully background renders will claim 01261 // // the event) 01262 // if (DoBGRedraw(MiscInfo)) 01263 // return(TRUE); 01264 // break; 01265 01266 case SGEVENT_BGFLUSH: 01267 DeregisterForBGRedraw(); 01268 break; // And drop through to flush all children 01269 default: 01270 break; 01271 } 01272 01273 // And pass all events on to my children 01274 return(GiveEventToMyChildren(EventType, EventInfo, MiscInfo)); 01275 } 01276 01277 01278 01279 /*********************************************************************************************** 01280 01281 > virtual void SGDisplayNode::DragWasReallyAClick(SGMouseInfo *MouseInfo, 01282 SGMiscInfo *MiscInfo) 01283 01284 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01285 Created: 15/3/95 01286 01287 Inputs: MouseInfo - The mouse info passed to the original click handler 01288 MiscInfo - The misc info passed to the original click handler 01289 01290 Purpose: Handles a mouse click event. This is a callback function - drags of 01291 items from galleries will call this function back if the drag turns 01292 out to just be a click. 01293 01294 Notes: The base class method takes no action whatsoever. Derived classes 01295 should override this method to do something useful. 01296 01297 For a description of how to use this, see the documentation, or 01298 take a look at other galleries for example code. 01299 01300 Documentation: docs\howtouse\sgallery.doc 01301 01302 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayNode::DefaultDragHandler 01303 01304 ***********************************************************************************************/ 01305 01306 void SGDisplayNode::DragWasReallyAClick(SGMouseInfo *MouseInfo, SGMiscInfo *MiscInfo) 01307 { 01308 // The base class does nothing 01309 } 01310 01311 01312 01313 /*********************************************************************************************** 01314 01315 > virtual void SGDisplayNode::GetFormatRect(DocRect *FormatRect) 01316 01317 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01318 Created: 16/1/95 01319 01320 Outputs: FormatRect - Returned containing the format rectangle where this item last 01321 positioned itself - make sure a formatting event has gone around before 01322 calling this method, so that you get a meaningful result 01323 01324 Purpose: Determines where this item wants to redraw itself within the logical window 01325 DocCoord coordinates. If this is not a visible node type, or if someone 01326 neglected to cache the value in overridden methods, returns (0,0,0,0) 01327 01328 ***********************************************************************************************/ 01329 01330 void SGDisplayNode::GetFormatRect(DocRect *ResultFormatRect) 01331 { 01332 if (ResultFormatRect != NULL) 01333 *ResultFormatRect = FormatRect; 01334 } 01335 01336 01337 01338 /*********************************************************************************************** 01339 01340 > BOOL SGDisplayNode::IMustRedraw(SGRedrawInfo *RedrawInfo) 01341 01342 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01343 Created: 31/10/94 01344 01345 Inputs: RedrawInfo - The redraw information indicating the redraw Bounds 01346 01347 Returns: TRUE if this item should redraw itself. FALSE if it need not bother 01348 01349 Purpose: To determine if a given item needs to be redrawn. This is done by 01350 determining if its bounding rectangle ('FormatRect') overlaps the 01351 bounding rectangle of the area to be redrawn as specified by 01352 RedrawInfo->Bounds. 01353 01354 Notes: Obviously, if FormatRect has not been correctly calculated/cached, 01355 this method will give spurious results! 01356 01357 SeeAlso: SGDisplayNode::CalculateFormatRect 01358 01359 ***********************************************************************************************/ 01360 01361 BOOL SGDisplayNode::IMustRedraw(SGRedrawInfo *RedrawInfo) 01362 { 01363 // No redraw info?! 01364 if (RedrawInfo == NULL) 01365 return(TRUE); 01366 01367 // Determine if the rect overlaps RedrawInfo->Bounds, returning TRUE if it does 01368 return (FormatRect.lo.y <= RedrawInfo->Bounds.hi.y && 01369 FormatRect.hi.y >= RedrawInfo->Bounds.lo.y && 01370 FormatRect.lo.x <= RedrawInfo->Bounds.hi.x && 01371 FormatRect.hi.x >= RedrawInfo->Bounds.lo.x); 01372 } 01373 01374 01375 01376 /*********************************************************************************************** 01377 01378 > virtual void SGDisplayNode::ForceRedrawOfMyself(void) 01379 01380 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01381 Created: 17/1/95 01382 01383 Purpose: Uses the cached FormatRect to force-redraw the appropriate part of the 01384 SuperGallery display window to cause myself (only) to be redrawn. 01385 01386 Notes: Before redrawing, this scans up the tree to see if any parent is Folded. 01387 If this is the case, it returns without doing anything, as this item must 01388 therefore be hidden in the fold. 01389 By default, the background is erased. If bEraseBkg is FALSE, the backgound 01390 will not be altered before redrawing. (Adrian 10/05/97) 01391 01392 01393 SeeAlso: SuperGallery::ForceRedrawOfArea 01394 01395 ***********************************************************************************************/ 01396 01397 void SGDisplayNode::ForceRedrawOfMyself(BOOL bEraseBkg) 01398 { 01399 // if (!Flags.Invisible) 01400 // { 01401 SuperGallery *ParentGallery = GetParentGallery(); 01402 if (ParentGallery != NULL) 01403 { 01404 // Before redrawing, search up the tree for any nodes which are folded - if there 01405 // are any, then I cannot be visible, so should not redraw! 01406 01407 SGDisplayNode *Ptr = GetParent(); 01408 while (Ptr != NULL) 01409 { 01410 if (Ptr->Flags.Folded) 01411 return; 01412 01413 Ptr = Ptr->GetParent(); 01414 } 01415 01416 // Not hidden in a fold, so redraw my rectangle and set the redraw mode 01417 BkgEraseMode = bEraseBkg ? TRUE : FALSE; 01418 ParentGallery->ForceRedrawOfArea(&FormatRect); 01419 } 01420 // } 01421 } 01422 01423 01424 01425 /*********************************************************************************************** 01426 01427 > virtual void SGDisplayNode::ForceRedrawOfMyselfAndChildren(void) 01428 01429 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01430 Created: 17/1/95 01431 01432 Purpose: Uses the cached FormatRect to force-redraw the appropriate part of the 01433 SuperGallery display window to cause myself to be redrawn - derived 01434 classes may override this to also redraw their children (SGDisplayNode) 01435 01436 ***********************************************************************************************/ 01437 01438 void SGDisplayNode::ForceRedrawOfMyselfAndChildren(void) 01439 { 01440 // if (!Flags.Invisible) 01441 // { 01442 ForceRedrawOfMyself(); 01443 // } 01444 } 01445 01446 01447 01448 /*********************************************************************************************** 01449 01450 > virtual void SGDisplayNode::RegisterForBGRedraw(void); 01451 01452 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01453 Created: 1/4/95 01454 01455 Purpose: Called by derived classes to register themselves for background redraw. 01456 01457 Must be called every time you want a background redraw to occur. May be 01458 called multiple times before the redraw occurs (it ignores repeated 01459 calls) 01460 01461 DO NOT call this method directly - see ShouldIDrawForeground() 01462 01463 Notes: DO NOT TOUCH the Flags.RedrawPending member variable directly! 01464 01465 SeeAlso: SGDisplayNode::DoBGRedraw; SGDisplayNode::ShouldIDrawForeground 01466 01467 ***********************************************************************************************/ 01468 01469 void SGDisplayNode::RegisterForBGRedraw(void) 01470 { 01471 if (!Flags.RedrawPending) 01472 { 01473 SuperGallery *ParentGallery = GetParentGallery(); 01474 01475 if (ParentGallery != NULL) 01476 { 01477 Flags.RedrawPending = TRUE; 01478 ParentGallery->IncrementPendingRedraws(); 01479 } 01480 } 01481 } 01482 01483 01484 01485 /*********************************************************************************************** 01486 01487 > virtual BOOL SGDisplayNode::DoBGRedraw(SGMiscInfo *MiscInfo); 01488 01489 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01490 Created: 1/4/95 01491 01492 Inputs: MiscInfo - the usual 01493 01494 Returns: TRUE to claim the redraw event, FALSE to not claim it 01495 01496 Purpose: Forces an immediate redraw of a given node, if it is pending for 01497 background redraw. 01498 01499 This is used by the base-class system to render items waiting for 01500 BG redraw, but can also be used by derived classes to force a given 01501 item to be visible immediately. e.g. This might be done if your item is 01502 clicked while waiting to be redrawn. 01503 01504 DO NOT call this method directly - see ShouldIDrawForeground() 01505 01506 Notes: DO NOT TOUCH the Flags.RedrawPending member variable directly! 01507 01508 SeeAlso: SGDisplayNode::RegisterForBGRedraw; SGDisplayNode::ShouldIDrawForeground 01509 01510 ***********************************************************************************************/ 01511 01512 BOOL SGDisplayNode::DoBGRedraw(SGMiscInfo *MiscInfo) 01513 { 01514 BGRenderClaimed = FALSE; 01515 01516 if (Flags.RedrawPending /*&& !Flags.Invisible*/) 01517 { 01518 SuperGallery *ParentGallery = GetParentGallery(); 01519 01520 if (ParentGallery != NULL) 01521 { 01522 // Interlock the redraw with the drag manager to make sure the screen isn't 01523 // screwed up by us redrawing over a solid drag 01524 DocRect KernelRect(FormatRect); 01525 BOOL NeedInterlock = ParentGallery->ConvertFromVirtualCoords(MiscInfo, &KernelRect); 01526 01527 if (NeedInterlock) 01528 { 01529 DragManagerOp::RedrawStarting(ParentGallery->WindowID, 01530 ParentGallery->GetListGadgetID(), 01531 &KernelRect); 01532 } 01533 01534 CurrentBGRenderNode = this; 01535 ForceRedrawOfMyself(); // Invalidate myself 01536 ParentGallery->PaintListNow(); // And immediately redraw 01537 CurrentBGRenderNode = NULL; 01538 01539 if (NeedInterlock) 01540 DragManagerOp::RedrawFinished(); 01541 01542 } 01543 } 01544 01545 return(BGRenderClaimed); 01546 } 01547 01548 01549 01550 /*********************************************************************************************** 01551 01552 > BOOL SGDisplayNode::ShouldIDrawForeground(BOOL ForceForeground) 01553 01554 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01555 Created: 6/5/95 01556 01557 Inputs: ForceForeground - TRUE if you want to force foreground redrawing (e.g. if you 01558 know your thumbnail is cached you are better off just drawing it immediately), 01559 or FALSE to allow the operation to be backgrounded. 01560 01561 Returns: TRUE if you should draw in the foreground (i.e. draw the item to completion), 01562 FALSE if you should draw the background stuff (i.e. draw a grey box instead 01563 of a thumbnail) - if FALSE, you'll be called back to complete the redraw later. 01564 01565 Purpose: Call this method in derived class redraw methods. Your code should go like 01566 this: 01567 MonoOn 01568 if (ShouldIDrawForeground(ByGollyIveGotAThumbnailCachedAlready) 01569 DrawTheItemFully(); 01570 else 01571 DrawAGreyBox(); 01572 MonoOff 01573 01574 This system is full automatic, and is all you have to do to get BG redraw 01575 to work. Note that foreground redraw will be expected when (a) ForceForeground 01576 is TRUE, (b) the item is selected, or (c) we are doing the second BG redraw pass. 01577 Background redraw will generally be used in all other circumstances. 01578 01579 SeeAlso: SGDisplayNode::RegisterForBGRedraw 01580 01581 ***********************************************************************************************/ 01582 01583 BOOL SGDisplayNode::ShouldIDrawForeground(BOOL ForceForeground) 01584 { 01585 BOOL FG = FALSE; 01586 01587 if (ForceForeground || Flags.Selected) 01588 FG = TRUE; 01589 else 01590 { 01591 if (CurrentBGRenderNode == this) 01592 FG = TRUE; 01593 } 01594 01595 // And make sure our current idea of the state is up to date 01596 if (FG) 01597 { 01598 DeregisterForBGRedraw(); 01599 BGRenderClaimed = TRUE; // Flag the fact that someone has FG rendered 01600 } 01601 else 01602 RegisterForBGRedraw(); 01603 01604 return(FG); 01605 } 01606 01607 01608 01609 /*********************************************************************************************** 01610 01611 > virtual void SGDisplayNode::DeregisterForBGRedraw(void); 01612 01613 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01614 Created: 1/4/95 01615 01616 Purpose: Ensures that this node is not pending background redraw (resets it) 01617 This is called in response to SGEVENT_BGFLUSH, when flushing BG redraws 01618 01619 DO NOT call this method directly - see ShouldIDrawForeground() 01620 01621 Notes: DO NOT TOUCH the Flags.RedrawPending member variable directly! 01622 01623 SeeAlso: SGDisplayNode::RegisterForBGRedraw; SGDisplayNode::ShouldIDrawForeground 01624 01625 ***********************************************************************************************/ 01626 01627 void SGDisplayNode::DeregisterForBGRedraw(void) 01628 { 01629 if (Flags.RedrawPending /*&& !Flags.Invisible*/) 01630 { 01631 SuperGallery *ParentGallery = GetParentGallery(); 01632 01633 if (ParentGallery != NULL) 01634 ParentGallery->DecrementPendingRedraws(); 01635 01636 Flags.RedrawPending = FALSE; // And finally, turn off pending flag 01637 } 01638 } 01639 01640 01641 01642 /*********************************************************************************************** 01643 01644 > SGDisplayNode *SGDisplayNode::DoBGRedrawPass(SGMiscInfo *MiscInfo) 01645 01646 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01647 Created: 16/5/95 01648 01649 Inputs: MiscInfo - The usual gallery MiscInfo struct 01650 01651 Returns: NULL, or a pointer to the last rendered node. 01652 01653 Purpose: Applies a background rendering pass to the display tree. This will scan the 01654 tree from this node onwards looking for a node to background render. 01655 01656 Once a node has been background rendered, this method will return the node 01657 which was rendered - SuperGalleries store this in LastBackgroundNode, and will 01658 call this method again, using that pointer as a point to start scanning from. 01659 01660 This makes scanning for background rendering nodes generally very much more 01661 efficient than searching the entire tree each time, as usually bg render nodes 01662 occur in sequential runs in the tree. 01663 01664 Notes: The SGDisplayNode RemoveFromTree method ensures that the parent gallery does 01665 not use this pointer after the node is deleted, by calling 01666 SuperGallery::SetLastBackgroundNode(NULL) if necessary - if the system is 01667 changed, make sure that it is updated to ensure that the pointer is not called 01668 upon after the item it references has been deleted. 01669 01670 ONLY LEAF NODES are guaranteed to background render with this scheme 01671 01672 SeeAlso: SGDisplayNode::RegisterForBGRedraw; SGDisplayNode::ShouldIDrawForeground; 01673 SuperGallery::SetLastBackgroundNode; SGDisplayNode::RemoveFromTree 01674 01675 ***********************************************************************************************/ 01676 01677 SGDisplayNode *SGDisplayNode::DoBGRedrawPass(SGMiscInfo *MiscInfo) 01678 { 01679 // If I'm not a leaf node, scan down the tree until the first leaf child is found 01680 if (GetChild() != NULL) 01681 return(GetChild()->DoBGRedrawPass(MiscInfo)); 01682 01683 // This is a bit nasty... The trouble is, if a group is virtualised, GetChild() will 01684 // return NULL and we won't go any further. In such situations we now execute this 01685 // bit of code here which will pass the rendering onto the next group... 01686 if (this->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup))) 01687 { 01688 if(GetNext() != NULL) 01689 return(GetNext()->DoBGRedrawPass(MiscInfo)); 01690 } 01691 01692 // Search (including ourself in the search) for the next node which needs to render 01693 // If we find one, we render it and return immediately, returning the pointer to that 01694 // node as the place to start the next BG rendering pass. 01695 SGDisplayNode *Ptr = this; 01696 while (Ptr != NULL) 01697 { 01698 if (Ptr->DoBGRedraw(MiscInfo)) 01699 return(Ptr); 01700 01701 Ptr = Ptr->GetNext(); 01702 } 01703 01704 // We failed to find a sibling that needs to redraw, so go skip on to the next group 01705 // To save the stack, we search until we find a likely candidate (a group with kids) 01706 Ptr = Parent; 01707 while (Ptr != NULL) 01708 { 01709 // Go on to the next sibling of our parent 01710 Ptr = Ptr->GetNext(); 01711 01712 if (Ptr != NULL && (Ptr->Flags.RedrawPending || Ptr->GetChild() != NULL)) 01713 return(Ptr->DoBGRedrawPass(MiscInfo)); 01714 } 01715 01716 // We didn't find anything to draw. On the next pass, we'll start from the root of 01717 // the tree again (we pass back NULL, and the SuperGallery starts from scratch) 01718 return(NULL); 01719 } 01720 01721 01722 01723 /*********************************************************************************************** 01724 01725 > virtual SGDisplayNode *SGDisplayNode::FindSubtree(SuperGallery *ParentGal, 01726 Document *ParentDoc, Library *ParentLib); 01727 01728 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01729 Created: 26/10/94 01730 01731 Inputs: ParentGal - The parent gallery of the node to find 01732 ParentDoc - The parent document of the node to find 01733 ParentLib - The parent library of the node to find 01734 01735 Returns: NULL, or the found node 01736 01737 Purpose: Searches this node and its subtree for any SGDisplayGroup nodes which 01738 have parent pointers which exactly match the input parameters. This is used 01739 to find the subtree for a given document or library. 01740 01741 SeeAlso: SGDisplayGroup::SGDisplayGroup 01742 01743 ***********************************************************************************************/ 01744 01745 SGDisplayGroup *SGDisplayNode::FindSubtree(SuperGallery *ParentGal, 01746 Document *ParentDoc, Library *ParentLib) 01747 { 01748 SGDisplayNode *Ptr = GetChild(); 01749 SGDisplayGroup *Result; 01750 01751 while (Ptr != NULL) 01752 { 01753 if (Ptr->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup))) // Search immediate children 01754 { 01755 Result = (SGDisplayGroup *) Ptr; 01756 if (Result->GetParentGallery() == ParentGal && 01757 Result->GetParentDocument() == ParentDoc && 01758 Result->GetParentLibrary() == ParentLib) 01759 return(Result); 01760 } 01761 01762 // Recurse down subtrees 01763 Result = Ptr->FindSubtree(ParentGal, ParentDoc, ParentLib); 01764 if (Result != NULL) 01765 return(Result); 01766 01767 Ptr = Ptr->GetNext(); // No luck - try the next child 01768 } 01769 01770 return(NULL); 01771 } 01772 01773 01774 01775 /*********************************************************************************************** 01776 01777 > virtual INT32 SGDisplayNode::CompareTo(SGDisplayNode *Other, INT32 SortKey) 01778 01779 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01780 Created: 26/10/94 01781 01782 Inputs: Other - the node to compare this node to 01783 SortKey - An integer identifying how to compare the items 01784 0 = No sorting (always returns 0) 01785 1 = Sort-by-name 01786 Other values will return 0, unless the derived class overrides this 01787 method in order to provide other sort modes. 01788 01789 Returns: negative (I am lesser), 0 (we are equal), or positive (I am greater) 01790 01791 Purpose: Compares this node to the 'other' node, to determine their relative positions 01792 in the display tree. Returns a value which usually indicates that the other 01793 node should be inserted before (-1, or 0) or after (+1) this item. 01794 01795 SeeAlso: SGDisplayNode::AddItem 01796 01797 ***********************************************************************************************/ 01798 01799 INT32 SGDisplayNode::CompareTo(SGDisplayNode *Other, INT32 SortKey) 01800 { 01801 ERROR3IF(Other == NULL, "Illegal NULL parameter"); 01802 01803 switch (SortKey) 01804 { 01805 case SGSORTKEY_BYNAME: 01806 { 01807 String_256 MyName; 01808 String_256 ItsName; 01809 01810 GetNameText(&MyName); 01811 Other->GetNameText(&ItsName); 01812 01813 return(MyName.CompareTo(ItsName)); 01814 } 01815 break; 01816 } 01817 01818 // No sorting (SGSORTKEY_NONE - 0), or 01819 return(0); 01820 } 01821 01822 01823 01824 /******************************************************************************************** 01825 01826 > virtual void SGDisplayNode::GetNameText(String_256 *Result) 01827 01828 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01829 Created: 9/3/95 01830 01831 Outputs: On exit, the string pointed at by Result will contain either a blank 01832 string, or the name text associated with this item (if any) 01833 01834 Purpose: To determine a name string for this node. Generally, this is used for 01835 a simple mechanism which searches for display items whose names match 01836 given search parameters in some way. It is also used in libraries to 01837 provide default redraw methods. 01838 01839 Notes: The base class returns a blank string. 01840 If you can provide a better name string, then override the base class 01841 method to do so. 01842 01843 SeeAlso: SGDisplayNode::GetFullInfoText 01844 01845 ********************************************************************************************/ 01846 01847 void SGDisplayNode::GetNameText(String_256 *Result) 01848 { 01849 ERROR3IF(Result == NULL, "Illegal NULL param"); 01850 if(Result == NULL) return; 01851 01852 *Result = TEXT(""); 01853 } 01854 01855 01856 01857 /******************************************************************************************** 01858 01859 > virtual void SGDisplayNode::GetFullInfoText(String_256 *Result) 01860 01861 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01862 Created: 9/3/95 01863 01864 Outputs: On exit, the string pointed at by Result will contain either a blank 01865 string, or the full-information text associated with this item (if any) 01866 (NOTE that the FullInfo string does NOT include the name!) 01867 01868 Purpose: To determine a full-info string for this node. Generally, this is used for 01869 a simple mechanism which searches for display items whose info matches 01870 given search parameters in some way. It is also used in libraries to 01871 provide default redraw methods. 01872 01873 Notes: The base class returns a blank string 01874 01875 If you can provide a better full-info string, then override the base class 01876 method to do so. 01877 01878 SeeAlso: SGDisplayNode::GetNameText 01879 01880 ********************************************************************************************/ 01881 01882 void SGDisplayNode::GetFullInfoText(String_256 *Result) 01883 { 01884 ERROR3IF(Result == NULL, "Illegal NULL param"); 01885 if(Result == NULL) return; 01886 01887 *Result = TEXT(""); 01888 } 01889 01890 01891 /******************************************************************************************** 01892 01893 > virtual void SGDisplayNode::GetKeyWords(String_256 *Result) 01894 01895 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 01896 Created: 30/3/95 01897 01898 Outputs: On exit, the string pointed at by Result will contain either a blank 01899 string, or a list of | seperated keywords associated with the item 01900 01901 Purpose: To determine the keywords for this node. Generally, this is used for 01902 a simple searching mechanism. 01903 01904 Notes: The base class returns a blank string. 01905 If you can provide a better name string, then override the base class 01906 method to do so. 01907 01908 SeeAlso: SGDisplayNode::GetFullInfoText 01909 01910 ********************************************************************************************/ 01911 01912 void SGDisplayNode::GetKeyWords(String_256 *Result) 01913 { 01914 ERROR3IF(Result == NULL, "Illegal NULL param"); 01915 if(Result == NULL) return; 01916 01917 *Result = TEXT(""); 01918 } 01919 01920 01921 01922 /******************************************************************************************** 01923 01924 > virtual BOOL SGDisplayNode::GetBubbleHelp(DocCoord *MousePos, String_256 *Result) 01925 01926 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01927 Created: 16/4/95 01928 01929 Inputs: MousePos - The current mouse position. This will generally be expected 01930 to lie inside this item's FormatRect. With it, this item can provide 01931 help on specific areas of an item. 01932 01933 Outputs: On exit, if the return value is TRUE, the string pointed at by Result 01934 will contain a bubble help string for this item 01935 01936 Returns: TRUE if it filled in the string, FALSE if it did not 01937 01938 Purpose: Called by the parent gallery when bubble help is needed. The parent 01939 gallery will do a hit test to determine which node contains the pointer, 01940 and will then ask that node to supply bubble/status-line help. 01941 01942 Notes: The base class returns FALSE (i.e. provides no help) 01943 If you can provide help, then override the base class method to do so. 01944 01945 SeeAlso: SGDisplayNode::GetStatusLineHelp 01946 01947 ********************************************************************************************/ 01948 01949 BOOL SGDisplayNode::GetBubbleHelp(DocCoord *MousePos, String_256 *Result) 01950 { 01951 ERROR3IF(MousePos == NULL || Result == NULL, "Invalid NULL params"); 01952 return(FALSE); 01953 } 01954 01955 01956 01957 /******************************************************************************************** 01958 01959 > virtual BOOL SGDisplayNode::GetStatusLineHelp(DocCoord *MousePos, String_256 *Result) 01960 01961 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01962 Created: 16/4/95 01963 01964 Inputs: MousePos - The current mouse position. This will generally be expected 01965 to lie inside this item's FormatRect. With it, this item can provide 01966 help on specific areas of an item. 01967 01968 Outputs: On exit, if the return value is TRUE, the string pointed at by Result 01969 will contain a status line help string for this item 01970 01971 Returns: TRUE if it filled in the string, FALSE if it did not 01972 01973 Purpose: Called by the parent gallery when status line help is needed. The parent 01974 gallery will do a hit test to determine which node contains the pointer, 01975 and will then ask that node to supply bubble/status-line help. 01976 01977 Notes: The base class returns FALSE (i.e. provides no help) 01978 If you can provide help, then override the base class method to do so. 01979 01980 SeeAlso: SGDisplayNode::GetBubbleHelp 01981 01982 ********************************************************************************************/ 01983 01984 BOOL SGDisplayNode::GetStatusLineHelp(DocCoord *MousePos, String_256 *Result) 01985 { 01986 ERROR3IF(MousePos == NULL || Result == NULL, "Invalid NULL params"); 01987 return(FALSE); 01988 } 01989 01990 01991 01992 /******************************************************************************************** 01993 01994 > virtual void SGDisplayNode::SelectItems(BOOL SelectThem, BOOL Exclusive = FALSE, 01995 Document *ParentDocument = NULL, Library *ParentLibrary = NULL) 01996 01997 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 01998 Created: 20/1/95 01999 02000 Inputs: SelectThem - TRUE to select the given items, FALSE to deselect them 02001 02002 Exclusive - TRUE to apply this action to all items *outside* the given 02003 range, FALSE to apply it to all items *inside* the range. 02004 02005 Document - NULL, or the document which defines the range of items to affect 02006 02007 Library - NULL, or the library which defines the range of items to affect 02008 02009 Purpose: To select/deselect groups of display items in this Gallery display. 02010 All items whose state changes will force redraw themselves 02011 02012 If selecting items, all groups will be deselected 02013 02014 Do not call this method - use the SuperGallery version 02015 02016 Notes: To select all items in a range, and deselect all items outside the range, 02017 you need to use 2 calls to this method. 02018 02019 To select/deselect all items in the display, pass FALSE, NULL, NULL to 02020 the last 3 parameters. (If Doc/Lib are both NULL, 'Exclusive' has no effect) 02021 02022 This base-class method does a simple thing: If this node is selectable 02023 (not invisible) then it sets its own selection state according to the 02024 'SelectThem' flag, and then passes the request on to its children. 02025 Any node type which understands how to cope with the last 3 parameters MUST 02026 override this method to provide the appropriate handling. 02027 (This default handling suffices, however, for root and leaf nodes) 02028 02029 SeeAlso: SuperGallery::SelectItems; SGDisplayGroup::SelectItems 02030 02031 ********************************************************************************************/ 02032 02033 void SGDisplayNode::SelectItems(BOOL SelectThem, BOOL Exclusive, 02034 Document *ParentDocument, Library *ParentLibrary) 02035 { 02036 // First, if I'm a selectable node, {de}select myself as appropriate to the request 02037 if (!Flags.Invisible && Flags.CanSelect) 02038 SetSelected(SelectThem); 02039 02040 // Now, pass the selection request on to my children 02041 SGDisplayNode *Ptr = GetChild(); 02042 02043 while (Ptr != NULL) 02044 { 02045 Ptr->SelectItems(SelectThem, Exclusive, ParentDocument, ParentLibrary); 02046 Ptr = Ptr->GetNext(); 02047 } 02048 } 02049 02050 02051 02052 /******************************************************************************************** 02053 02054 > virtual void SGDisplayNode::SelectGroups(BOOL SelectThem, BOOL Exclusive = FALSE, 02055 Document *ParentDocument = NULL, Library *ParentLibrary = NULL) 02056 02057 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02058 Created: 14/5/95 02059 02060 Inputs: SelectThem - TRUE to select the given groups, FALSE to deselect them 02061 02062 Exclusive - TRUE to apply this action to all groups *outside* the given 02063 range, FALSE to apply it to all groups *inside* the range. 02064 02065 Document - NULL, or the document which defines the range of groups to affect 02066 02067 Library - NULL, or the library which defines the range of groups to affect 02068 02069 Purpose: To select/deselect sets of display groups in this Gallery display. 02070 All groups whose state changes will force redraw themselves 02071 02072 If selecting, all items in the tree will be deselected 02073 02074 Do not call this method - use the SuperGallery version 02075 02076 Notes: To select all groups in a range, and deselect all groups outside the range, 02077 you need to use 2 calls to this method. 02078 02079 To select/deselect all groups in the display, pass FALSE, NULL, NULL to 02080 the last 3 parameters. (If Doc/Lib are both NULL, 'Exclusive' has no effect) 02081 02082 SeeAlso: SuperGallery::SelectGroups; SGDisplayGroup::SelectGroups 02083 02084 ********************************************************************************************/ 02085 02086 void SGDisplayNode::SelectGroups(BOOL SelectThem, BOOL Exclusive, 02087 Document *ParentDocument, Library *ParentLibrary) 02088 { 02089 // First, if selecting, then we need to ensure that all base-class nodes are deselected. 02090 // The group class overrides this behaviour to correctly select groups. 02091 if (SelectThem && !Flags.Invisible && Flags.CanSelect) 02092 SetSelected(FALSE); 02093 02094 // Now, pass the selection request on to my children 02095 SGDisplayNode *Ptr = GetChild(); 02096 while (Ptr != NULL) 02097 { 02098 Ptr->SelectGroups(SelectThem, Exclusive, ParentDocument, ParentLibrary); 02099 Ptr = Ptr->GetNext(); 02100 } 02101 } 02102 02103 /******************************************************************************************** 02104 02105 > virtual void SGDisplayNode::SelectRangeGroups(SGDisplayGroup *PrimeNode, SGDisplayGroup *AnchorNode); 02106 02107 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02108 Created: 10/2/95 02109 02110 Inputs: PrimeNode - The group which MUST be selected. May NOT be NULL. 02111 02112 AnchorNode - The other group, specifying a range of sibling groups to 02113 be selected. May be NULL, in which case only PrimeNode is selected 02114 02115 Purpose: Selects the PrimeNode, and if possible, all sibling items between it and 02116 the Anchor node. If Anchor == NULL or is not found, only PrimeNode is 02117 selected. Does not deselect any items - you should call SelectItems first 02118 to clear the seln. 02119 02120 ********************************************************************************************/ 02121 02122 void SGDisplayNode::SelectRangeGroups(SGDisplayGroup *PrimeNode, SGDisplayGroup *AnchorNode) 02123 { 02124 ERROR3IF(PrimeNode == NULL, "SGDisplayNode::SelectRangeGroup - PrimeNode must be non-NULL"); 02125 02126 BOOL AnchorIsHere = FALSE; 02127 SGDisplayGroup *First = PrimeNode; 02128 02129 SuperGallery *ParentGallery = GetParentGallery(); 02130 ERROR3IF(ParentGallery == NULL, "NULL Parent gallery?!"); 02131 02132 if (AnchorNode != NULL) 02133 { 02134 SGDisplayNode *Ptr = PrimeNode->GetParent(); 02135 ERROR3IF(Ptr == NULL, "SGDisplayNode::SelectRangeGroup - Tree linkage corrupt, or PrimeNode is the root!"); 02136 02137 // Find which of the two nodes comes first 02138 Ptr = Ptr->GetChild(); 02139 while (Ptr != NULL && Ptr != PrimeNode) 02140 { 02141 if (Ptr == AnchorNode) 02142 { 02143 First = (SGDisplayGroup *)AnchorNode; // Ooops - the Anchor node occurs first! 02144 AnchorIsHere = TRUE; // And remember we've found the Anchor 02145 break; 02146 } 02147 02148 Ptr = Ptr->GetNext(); 02149 } 02150 02151 // Continue scanning until we can be sure that the Anchor Node is in the sibling list 02152 while (Ptr != NULL && !AnchorIsHere) 02153 { 02154 AnchorIsHere = (Ptr == AnchorNode); 02155 Ptr = Ptr->GetNext(); 02156 } 02157 } 02158 02159 if (!AnchorIsHere) // Only one item in the range! 02160 { 02161 PrimeNode->SetSelected(TRUE); 02162 PrimeNode->ForceRedrawOfMyself(); 02163 02164 // And inform the parent gallery of the selection change 02165 ParentGallery->SetLastSelectedNode(PrimeNode); 02166 ParentGallery->SelectionHasChanged(); 02167 return; 02168 } 02169 02170 // We have a valid range. Scan from First to Last, selecting everything in our path 02171 SGDisplayGroup *Last = (First == PrimeNode) ? AnchorNode : PrimeNode; 02172 while (First != NULL && First != Last) 02173 { 02174 First->SetSelected(TRUE); 02175 First->ForceRedrawOfMyself(); 02176 02177 First = (SGDisplayGroup *) First->GetNext(); 02178 } 02179 02180 // And set the last one 02181 Last->SetSelected(TRUE); 02182 Last->ForceRedrawOfMyself(); 02183 02184 // And inform the parent gallery of the selection change 02185 ParentGallery->SetLastSelectedNode(Last); 02186 ParentGallery->SelectionHasChanged(); 02187 } 02188 02189 /******************************************************************************************** 02190 02191 > virtual void SGDisplayNode::SelectRangeItems(SGDisplayItem *PrimeNode, SGDisplayItem *AnchorNode); 02192 02193 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02194 Created: 10/2/95 02195 02196 Inputs: PrimeNode - The item which MUST be selected. May NOT be NULL. 02197 02198 AnchorNode - The other item, specifying a range of sibling items to 02199 be selected. May be NULL, in which case only PrimeNode is selected 02200 02201 Purpose: Selects the PrimeNode, and if possible, all sibling items between it and 02202 the Anchor node. If Anchor == NULL or is not found, only PrimeNode is 02203 selected. Does not deselect any items - you should call SelectItems first 02204 to clear the seln. 02205 02206 ********************************************************************************************/ 02207 02208 void SGDisplayNode::SelectRangeItems(SGDisplayItem *PrimeNode, SGDisplayItem *AnchorNode) 02209 { 02210 ERROR3IF(PrimeNode == NULL, "SGDisplayItem::SelectRangeItem - PrimeNode must be non-NULL"); 02211 02212 BOOL AnchorIsHere = FALSE; 02213 SGDisplayItem *First = PrimeNode; 02214 02215 SuperGallery *ParentGallery = GetParentGallery(); 02216 ERROR3IF(ParentGallery == NULL, "NULL Parent gallery?!"); 02217 02218 if (AnchorNode != NULL) 02219 { 02220 SGDisplayNode *Ptr = PrimeNode->GetParent(); 02221 ERROR3IF(Ptr == NULL, "SGDisplayItem::SelectRangeItem - Tree linkage corrupt, or PrimeNode is the root!"); 02222 02223 // Find which of the two nodes comes first 02224 Ptr = Ptr->GetChild(); 02225 while (Ptr != NULL && Ptr != PrimeNode) 02226 { 02227 if (Ptr == AnchorNode) 02228 { 02229 First = (SGDisplayItem *)AnchorNode; // Ooops - the Anchor node occurs first! 02230 AnchorIsHere = TRUE; // And remember we've found the Anchor 02231 break; 02232 } 02233 02234 Ptr = Ptr->GetNext(); 02235 } 02236 02237 // Continue scanning until we can be sure that the Anchor Node is in the sibling list 02238 while (Ptr != NULL && !AnchorIsHere) 02239 { 02240 AnchorIsHere = (Ptr == AnchorNode); 02241 Ptr = Ptr->GetNext(); 02242 } 02243 } 02244 02245 if (!AnchorIsHere) // Only one item in the range! 02246 { 02247 PrimeNode->SetSelected(TRUE); 02248 PrimeNode->ForceRedrawOfMyself(); 02249 02250 // And inform the parent gallery of the selection change 02251 ParentGallery->SetLastSelectedNode(PrimeNode); 02252 ParentGallery->SelectionHasChanged(); 02253 return; 02254 } 02255 02256 // We have a valid range. Scan from First to Last, selecting everything in our path 02257 SGDisplayItem *Last = (First == PrimeNode) ? AnchorNode : PrimeNode; 02258 while (First != NULL && First != Last) 02259 { 02260 First->SetSelected(TRUE); 02261 First->ForceRedrawOfMyself(); 02262 02263 First = (SGDisplayItem *) First->GetNext(); 02264 } 02265 02266 // And set the last one 02267 Last->SetSelected(TRUE); 02268 Last->ForceRedrawOfMyself(); 02269 02270 // And inform the parent gallery of the selection change 02271 ParentGallery->SetLastSelectedNode(Last); 02272 ParentGallery->SelectionHasChanged(); 02273 } 02274 02275 02276 /*********************************************************************************************** 02277 02278 > void SGDisplayNode::DrawPlinth(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo, 02279 DialogColourInfo *RedrawColours, 02280 DocRect *ButtonRect, 02281 BOOL Indented = FALSE, 02282 UINT32 GlyphResourceID = 0) 02283 02284 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02285 Created: 24/1/95 02286 02287 Inputs: RedrawInfo - The redraw info, as normal with all this redraw stuff 02288 MiscInfo - The MiscInfo, as normal for a SG Event 02289 RedrawColours - The object what knows about them thar plotting colours 02290 ButtonRect - The rectangle inside which to draw the plinth 02291 Indented - TRUE for indented button, FALSE for raised button 02292 GlyphResourceID - 0 (for no glyph, in which case the plinth 'face' is flat- 02293 filled with the appropriate colour), else the resource ID of a bitmap 02294 to be drawn in the center of the plinth/button. 02295 02296 Purpose: Draws a plinth (2 white lines and 2 dark grey lines) around the inside edge 02297 of the given rectangle, in order to give a Windows 95 like button plinth. 02298 It can include a button glyph bitmap. It's static so anybody can 02299 call it if they so desire. 02300 02301 Notes: It would be advantageous if the provided button rectangle is aligned 02302 to the device pixel grid if you want its appearance to be correct 02303 02304 The area within the plinth is filled with colour, so all pixels within 02305 the given rectangle are guaranteed to be painted - i.e. you do not need 02306 to clear the background region before calling this routine (indeed you 02307 should not, if you wish to avoid flicker) 02308 02309 ***********************************************************************************************/ 02310 02311 void SGDisplayNode::DrawPlinth(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo, 02312 DialogColourInfo *RedrawColours, 02313 DocRect *ButtonRect, BOOL Indented, 02314 UINT32 GlyphResourceID) 02315 { 02316 ERROR3IF(RedrawInfo == NULL || RedrawColours == NULL || ButtonRect == NULL, 02317 "SGDisplayNode::DrawPlinth - NULL parameters aer illegal"); 02318 // if (!Flags.Invisible) 02319 // { 02320 RenderRegion *pRender = RedrawInfo->Renderer; 02321 pRender->SaveContext(); 02322 02323 pRender->SetLineWidth(0); 02324 02325 // Fill inside the plinth with Button Face grey 02326 DocRect InsideRect(*ButtonRect); 02327 InsideRect.Inflate(-MiscInfo->PixelSize); 02328 02329 // Fill inside the plinth with button-face (grey), and optionally with the glyph bitmap 02330 // (We always fill behind the bitmap first in case the bitmap isn't big enough to 02331 // fill the entire area) 02332 DocColour trans(COLOUR_TRANS); 02333 pRender->SetLineColour(trans); 02334 pRender->SetFillColour(RedrawColours->ButtonFace()); 02335 pRender->DrawRect(&InsideRect); 02336 02337 if (GlyphResourceID != 0) 02338 { 02339 // Quick v1.5 release bodge to center the up & down scroll arrow glyphs in the plinth 02340 if (GlyphResourceID == _R(IDB_GALLERY_SCROLLUP) || GlyphResourceID == _R(IDB_GALLERY_SCROLLDOWN)) 02341 { 02342 DocRect CenterRect(InsideRect); 02343 CenterRect.Inflate(((7*MiscInfo->PixelSize) - CenterRect.Width())/2); // Shrink to 7 pixels, centered 02344 DrawBitmap(pRender, &CenterRect, GlyphResourceID); 02345 } 02346 else 02347 DrawBitmap(pRender, &InsideRect, GlyphResourceID); 02348 } 02349 02350 // Draw the plinth border 02351 DocColour LineCol; 02352 02353 if (Indented) 02354 LineCol = RedrawColours->ButtonShadow(); 02355 else 02356 LineCol = RedrawColours->ButtonHighlight(); 02357 02358 pRender->SetFillColour(LineCol); 02359 02360 DocRect TempRect(*ButtonRect); // Left 02361 TempRect.hi.x = TempRect.lo.x + MiscInfo->PixelSize; 02362 pRender->DrawRect(&TempRect); 02363 02364 TempRect = *ButtonRect; // Top 02365 TempRect.lo.y = TempRect.hi.y - MiscInfo->PixelSize; 02366 pRender->DrawRect(&TempRect); 02367 02368 if (Indented) 02369 LineCol = RedrawColours->ButtonHighlight(); 02370 else 02371 LineCol = RedrawColours->ButtonShadow(); 02372 02373 pRender->SetFillColour(LineCol); 02374 TempRect = *ButtonRect; // Right 02375 TempRect.lo.x = TempRect.hi.x - MiscInfo->PixelSize; 02376 pRender->DrawRect(&TempRect); 02377 02378 TempRect = *ButtonRect; // Bottom 02379 TempRect.hi.y = TempRect.lo.y + MiscInfo->PixelSize; 02380 pRender->DrawRect(&TempRect); 02381 02382 pRender->RestoreContext(); 02383 // } 02384 } 02385 02386 02387 02388 /*********************************************************************************************** 02389 02390 > void SGDisplayNode::DrawSelectionOutline(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo, 02391 DocRect *BoundsRect, INT32 Width = 0) 02392 02393 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02394 Created: 9/3/95 02395 02396 Inputs: RedrawInfo - The info passed in to HandleEvent for redraws 02397 MiscInfo - Standard miscinfo struct 02398 BoundsRect - The rectangle to draw the border into 02399 Width - 0 for a default (2-pixel-wide) border, else the width of the 02400 lines, in pixels. The outside of the frame will always touch the edge 02401 of the given rectangle, so essentially, this is used as a 'defalate' 02402 value to find the inside edge of the lines. 02403 02404 Purpose: Draws a black 2-pixel-thick frame-rectangle just inside the given Rect. 02405 This is the normal selection-rectangle outline which should go outside 02406 an icon or thumbnail when an item is selected. 02407 02408 Notes: If you wish to draw inside the rectangle, use 02409 TheRect.Inflate(DevicePixels(MiscInfo, 2)); 02410 02411 This draws 4 filled rectangles around the border of the rectangle. The 02412 area inside the rectangle is left unpainted - this will reduce flicker 02413 on large items as compared to blatting a single rectangle behind the 02414 icon/thumbnail. 02415 02416 ***********************************************************************************************/ 02417 02418 void SGDisplayNode::DrawSelectionOutline(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo, 02419 DocRect *BoundsRect, INT32 Width) 02420 { 02421 ERROR3IF(RedrawInfo == NULL || MiscInfo == NULL || BoundsRect == NULL, 02422 "SGDisplayNode::DrawSelectionOutline - NULL parameters aer illegal"); 02423 02424 // if (!Flags.Invisible) 02425 // { 02426 RenderRegion *pRender = RedrawInfo->Renderer; 02427 02428 if (Width == 0) // Default value of zero means a 2-pixel border 02429 Width = DevicePixels(MiscInfo, 2); 02430 02431 pRender->SaveContext(); 02432 02433 pRender->SetLineWidth(0); 02434 DocColour trans(COLOUR_TRANS); 02435 pRender->SetLineColour(trans); 02436 DocColour black(COLOUR_BLACK); 02437 pRender->SetFillColour(black); 02438 02439 DocRect TempRect(*BoundsRect); // Left 02440 TempRect.hi.x = TempRect.lo.x + Width; 02441 pRender->DrawRect(&TempRect); 02442 02443 TempRect = *BoundsRect; // Top 02444 TempRect.lo.y = TempRect.hi.y - Width; 02445 pRender->DrawRect(&TempRect); 02446 02447 TempRect = *BoundsRect; // Right 02448 TempRect.lo.x = TempRect.hi.x - Width; 02449 pRender->DrawRect(&TempRect); 02450 02451 TempRect = *BoundsRect; // Bottom 02452 TempRect.hi.y = TempRect.lo.y + Width; 02453 pRender->DrawRect(&TempRect); 02454 02455 pRender->RestoreContext(); 02456 // } 02457 } 02458 02459 02460 02461 /*********************************************************************************************** 02462 02463 > void SGDisplayNode::DrawBitmap(RenderRegion *Renderer, DocRect *BoundsRect, UINT32 ResID) 02464 02465 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02466 Created: 6/2/95 02467 02468 Inputs: Renderer - The render region to render with 02469 BoundsRect - The rectangle to draw the bitmap into 02470 ResID - A non-zero bitmap-resource identifier (the bitmap to draw) 02471 02472 Purpose: Draws the given bitmap to screen in the given DocRect of the supergallery 02473 display list. (Used to be necessary before RR:DrawBitmap came along) 02474 02475 SeeAlso: RenderRegion::DrawBitmap 02476 02477 ***********************************************************************************************/ 02478 02479 void SGDisplayNode::DrawBitmap(RenderRegion *Renderer, DocRect *BoundsRect, UINT32 ResID) 02480 { 02481 ERROR3IF(Renderer == NULL || BoundsRect == NULL || ResID == 0, 02482 "SGDisplayNode::DrawBitmap - NULL Parameter(s) are illegal"); 02483 02484 // if (!Flags.Invisible) 02485 // { 02486 Renderer->DrawBitmap(BoundsRect->lo, ResID); 02487 // } 02488 } 02489 02490 02491 02492 /*********************************************************************************************** 02493 02494 > virtual void SGDisplayNode::StartRendering(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo) 02495 02496 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02497 Created: 1/2/95 02498 02499 Inputs: RedrawInfo - The RedrawInfo passed to your HandleEvent function 02500 for SGEVENT_REDRAWs 02501 MiscInfo - The MiscInfo passed in to your HandleEvent function 02502 02503 Purpose: MUST be called by all derived node types when they are about to start 02504 rendering. This allows us to do things like using GRenderRegions to small 02505 bitmaps (a region for each item rather than one region for the whole window) 02506 and other fabby things. 02507 02508 SeeAlso: SGDisplayNode::StopRendering 02509 02510 ***********************************************************************************************/ 02511 02512 void SGDisplayNode::StartRendering(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo) 02513 { 02514 // Does nothing, for now 02515 } 02516 02517 02518 02519 /*********************************************************************************************** 02520 02521 > virtual void SGDisplayNode::StopRendering(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo) 02522 02523 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02524 Created: 1/2/95 02525 02526 Inputs: RedrawInfo - The RedrawInfo passed to your HandleEvent function 02527 for SGEVENT_REDRAWs 02528 MiscInfo - The MiscInfo passed in to your HandleEvent function 02529 02530 Purpose: MUST be called by all derived node types when they have finished 02531 rendering. This allows us to do things like using GRenderRegions to small 02532 bitmaps (a region for each item rather than one region for the whole window) 02533 and other fabby things. 02534 02535 SeeAlso: SGDisplayNode::StopRendering 02536 02537 ***********************************************************************************************/ 02538 02539 void SGDisplayNode::StopRendering(SGRedrawInfo *RedrawInfo, SGMiscInfo *MiscInfo) 02540 { 02541 // Does nothing, for now 02542 } 02543 02544 02545 /*********************************************************************************************** 02546 02547 > virtual BOOL SGDisplayNode::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 02548 02549 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02550 Created: 16/4/95 02551 02552 Inputs: Mouse - Information on the mouse state for this click 02553 MiscInfo - the normal info as passed to event handlers 02554 02555 Returns: TRUE if the click caused any action to be taken (selection state to change) 02556 FALSE if the click was ignored for whatever reason 02557 02558 Purpose: Provides part 1 of the default selection model for clicks on gallery display 02559 nodes. Should be called by all derived gallery DisplayItems to handle clicks 02560 upon them, when multiple-selection support is desired. 02561 02562 You should call this method immediately prior to starting a drag as a result 02563 of a click event. Note that it is paired with DefaultClickHandler (which 02564 should be called when the drag you start turns out to be a click, if you 02565 want multiple-selection capability). 02566 02567 See the SGDisplayColour (kernel\sgcolour.cpp) for an example of use 02568 02569 SeeAlso: SGDisplayItem::DefaultClickHandler; SGDisplayColour::HandleEvent 02570 02571 ***********************************************************************************************/ 02572 02573 BOOL SGDisplayNode::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 02574 { 02575 if (Mouse->Adjust) // Drags cannot be started with adjust 02576 return(FALSE); 02577 02578 SuperGallery *ParentGallery = GetParentGallery(); 02579 02580 if (Mouse->Extend) 02581 { 02582 BOOL Handled = TRUE; 02583 02584 // This was a click to extend the selection to the clicked item 02585 #if FALSE 02586 /* I was led to believe that this was how shift-select worked, but it isn't (thank God) 02587 so I have removed this case again - Jason 02588 02589 if (IsSelected()) 02590 { 02591 // If this item is selected, then shift-clicking it acts to leave it 02592 // selected, and deselect every other item. 02593 02594 ParentGallery->SelectItems(FALSE); // Deselect everything else 02595 ParentGallery->SelectGroups(FALSE); // Deselect all groups 02596 02597 // Repaint the list box now. This is because if there is a large 02598 // distance between the old selection and the new one, we get a huge 02599 // redraw cliprect, so get a (slow) complete redraw, instead of two 02600 // small redraws. It is thus better to break the redraw into 2 steps 02601 // so that we are more likely to get 2 fast redraws than one slow one. 02602 ParentGallery->PaintListNow(); 02603 02604 // And select myself, with immediate redraw 02605 SetSelected(TRUE); 02606 ParentGallery->PaintListNow(); 02607 02608 // Update the ParentGallery to know that we are the new multi-selection anchor 02609 ParentGallery->SetLastSelectedNode(this); 02610 02611 // And inform the parent gallery that the selection may have changed 02612 ParentGallery->SelectionHasChanged(); 02613 02614 return(TRUE); 02615 } 02616 else 02617 */ 02618 #endif 02619 { 02620 if (ParentGallery->GetSelectedItemCount() == 0 && ParentGallery->GetSelectedGroupCount() == 0) 02621 Handled = FALSE; // No selection - treat extend-click as a normal click 02622 else 02623 { 02624 ParentGallery->SelectItems(FALSE); // Deselect all items 02625 ParentGallery->SelectGroups(FALSE); // Deselect all groups 02626 02627 ParentGallery->SelectRange(this, ParentGallery->GetLastSelectedNode()); 02628 } 02629 } 02630 02631 if (Handled) 02632 return(TRUE); 02633 } 02634 02635 02636 if (!Flags.Selected) 02637 { 02638 if (!Mouse->Adjust) 02639 { 02640 // If it's not an adjust-click, deselect all other items and groups 02641 ParentGallery->SelectItems(FALSE); 02642 ParentGallery->SelectGroups(FALSE); 02643 02644 // Repaint the list box now. This is because if there is a large 02645 // distance between the old selection and the new one, we get a huge 02646 // redraw cliprect, so get a (slow) complete redraw, instead of two 02647 // small redraws. It is thus better to break the redraw into 2 steps 02648 // so that we are more likely to get 2 fast redraws than one slow one. 02649 ParentGallery->PaintListNow(); 02650 } 02651 else 02652 { 02653 // Mutual exclusion stuff... If we're a group, deselect all items, etc... 02654 if(this->IS_KIND_OF(SGDisplayGroup)) 02655 ParentGallery->SelectItems(FALSE); 02656 else if(this->IS_KIND_OF(SGDisplayItem)) 02657 ParentGallery->SelectGroups(FALSE); 02658 else 02659 ERROR3("What are we if we're not a group or an item ?"); 02660 } 02661 02662 // And select myself, and do an immediate redraw 02663 SetSelected(TRUE); 02664 ParentGallery->PaintListNow(); 02665 02666 // Update the ParentGallery to know that we are the new multi-selection anchor 02667 ParentGallery->SetLastSelectedNode(this); 02668 02669 // And inform the parent gallery that the selection may have changed 02670 ParentGallery->SelectionHasChanged(); 02671 02672 return(TRUE); 02673 } 02674 02675 return(FALSE); 02676 } 02677 02678 02679 02680 /*********************************************************************************************** 02681 02682 > virtual BOOL SGDisplayNode::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 02683 BOOL AfterDrag = FALSE, 02684 BOOL AdjustDoubleClick = TRUE) 02685 02686 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02687 Created: 9/2/94 02688 02689 Inputs: Mouse - Information on the mouse state for this click 02690 MiscInfo - the normal info as passed to event handlers 02691 02692 AfterDrag - TRUE if this is being called when a drag turns into a click, and 02693 you called DefaultPreDragHandler before the drag started 02694 02695 AdjustDoubleClick - TRUE to do normal adjust-double-click handling (which 02696 closes the gallery after applying the item) 02697 FALSE to not close the gallery (used by the colour gallery to stop the 02698 gallery closing when applying with adjust as it applies line colour, so 02699 overrides the default behaviour) 02700 02701 Returns: TRUE if the click caused any action to be taken (selection state to change) 02702 FALSE if the click was ignored for whatever reason 02703 02704 Purpose: Provides the default selection model for clicks on gallery display nodes. 02705 Should be called by all derived gallery DisplayItems to handle clicks 02706 upon them, when multiple-selection support is desired. 02707 02708 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 02709 02710 ***********************************************************************************************/ 02711 02712 BOOL SGDisplayNode::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 02713 BOOL AfterDrag, BOOL AdjustDoubleClick) 02714 { 02715 TRACEUSER( "Matt", _T("SGDisplyaNode::DefaultClickHandler called\n")); 02716 SuperGallery *ParentGallery = GetParentGallery(); 02717 02718 if (!AfterDrag) 02719 { 02720 // This was not called after having previously called DefaultPreDragHandler, 02721 // so we have to do both halves of the processing. If PreDrag deals with it, 02722 // we don't need to do anything further. 02723 if (DefaultPreDragHandler(Mouse, MiscInfo)) 02724 return(TRUE); 02725 } 02726 02727 if (Mouse->DoubleClick && !Flags.Invisible) 02728 { 02729 // On double-click, this item becomes the only selected item, and 02730 // it is applied (if that action is supported by the parent gallery) 02731 02732 ParentGallery->SelectItems(FALSE); // Deselect everything else 02733 ParentGallery->SelectGroups(FALSE); // Deselect all groups 02734 02735 // Repaint the list box now. This is because if there is a large 02736 // distance between the old selection and the new one, we get a huge 02737 // redraw cliprect, so get a (slow) complete redraw, instead of two 02738 // small redraws. It is thus better to break the redraw into 2 steps 02739 // so that we are more likely to get 2 fast redraws than one slow one. 02740 ParentGallery->PaintListNow(); 02741 02742 // And select myself, and do an immediate redraw 02743 SetSelected(TRUE); 02744 ParentGallery->PaintListNow(); 02745 02746 // Update the ParentGallery to know that we are the new multi-selection anchor 02747 ParentGallery->SetLastSelectedNode(this); 02748 02749 // And inform the parent gallery that the selection may have changed 02750 ParentGallery->SelectionHasChanged(); 02751 02752 if (Mouse->Adjust) 02753 { 02754 BOOL ActionApplied = ParentGallery->ApplyAction(SGACTION_APPLYADJUST); 02755 if (!ActionApplied) 02756 ActionApplied = ParentGallery->ApplyAction(SGACTION_APPLY); 02757 02758 if (ActionApplied && AdjustDoubleClick) 02759 { 02760 // Adjust/Ctrl double click of an item. This applies the item and then 02761 // auto closes the gallery (just like RISC OS and Win95) 02762 ParentGallery->SetVisibility(FALSE); 02763 02764 DialogBarOp::SetSystemStateChanged(); // Ensure toolbar button pops out again 02765 } 02766 } 02767 PORTNOTE("galleries", "Disabled clipart gallery") 02768 #ifndef EXCLUDE_FROM_XARALX 02769 else if (ParentGallery->IsKindOf(CC_RUNTIME_CLASS(LibFillsSGallery))) 02770 LibClipartSGallery::ImportClipart(TRUE, (LibraryGallery*) ParentGallery); 02771 #endif 02772 else 02773 ParentGallery->ApplyAction(SGACTION_APPLY); 02774 02775 return(TRUE); 02776 } 02777 02778 // If this was an adjust click, it should toggle the selection state 02779 if (Mouse->Adjust) 02780 { 02781 BOOL AreWeSelected = IsSelected(); 02782 02783 // Mutual exclusion stuff... If we're a group, deselect all items, etc... 02784 if(this->IS_KIND_OF(SGDisplayGroup)) 02785 ParentGallery->SelectItems(FALSE); 02786 else if(this->IS_KIND_OF(SGDisplayItem)) 02787 ParentGallery->SelectGroups(FALSE); 02788 else 02789 ERROR3("What are we if we're not a group or an item ?"); 02790 02791 // Invert my selection state, and do an immediate redraw 02792 SetSelected(!AreWeSelected); 02793 ParentGallery->PaintListNow(); 02794 02795 // Update the ParentGallery to know that we are the new multi-selection anchor 02796 ParentGallery->SetLastSelectedNode(this); 02797 02798 // And inform the parent gallery that the selection may have changed 02799 ParentGallery->SelectionHasChanged(); 02800 02801 return(TRUE); 02802 } 02803 return(FALSE); 02804 } 02805 02806 02807 /*********************************************************************************************** 02808 02809 > CWindowID SGDisplayNode::GetListWindow(void) 02810 02811 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 02812 Created: 18/05/2006 02813 02814 Purpose: Returns the window id of the list box window of the parent gallery 02815 02816 SeeAlso: - 02817 02818 ***********************************************************************************************/ 02819 02820 CWindowID SGDisplayNode::GetListWindow(void) 02821 { 02822 return(DialogManager::GetGadget(GetParentGallery()->GetReadWriteWindowID(), GetParentGallery()->GetListGadgetID())); 02823 } 02824 02825 02826 02827 /*********************************************************************************************** 02828 02829 > virtual void SGDisplayNode::DumpSubtree(INT32 TreeLevel = 1) 02830 02831 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02832 Created: 26/10/94 02833 Purpose: Dumps TRACE output to the debugger showing the layout of the tree 02834 THIS FUNCTION IS ONLY PRESENT IN DEBUG BUILDS (#ifdef _DEBUG) 02835 It will also only produce debug output if your UserName is "Jason" 02836 02837 ***********************************************************************************************/ 02838 02839 #ifdef _DEBUG 02840 void SGDisplayNode::DumpSubtree(INT32 TreeLevel) 02841 { 02842 PORTNOTETRACE("galleries", "Disabled debug dump"); 02843 #ifndef EXCLUDE_FROM_XARALX 02844 if (IsUserName("Matt"/*Jason*/)) 02845 { 02846 // First, dump out myself... 02847 TCHAR Temp[200]; 02848 TCHAR Msg[200]; 02849 INT32 i; 02850 for (i = 0; i < (TreeLevel * 2) && i < 50; i++) 02851 Msg[i] = ' '; 02852 02853 Msg[i] = '\0'; 02854 02855 wsprintf(Temp, "%s (%x)\n", GetRuntimeClass()->m_lpszClassName, (INT32)this); 02856 camStrcat(Msg, Temp); 02857 OutputDebugString(Msg); 02858 02859 02860 // Now recursively dump all my children... 02861 SGDisplayNode *Ptr = GetChild(); 02862 while (Ptr != NULL) 02863 { 02864 Ptr->DumpSubtree(TreeLevel+1); 02865 Ptr = Ptr->Next; 02866 } 02867 } 02868 #endif 02869 } 02870 #endif 02871 02872 02873 02874 02875 02876 02877 02878 02879 02880 02881 02882 02883 /*********************************************************************************************** 02884 02885 > SGDisplayRoot::SGDisplayRoot() 02886 02887 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02888 Created: 26/10/94 02889 02890 Purpose: SGDisplayRoot constructor (makes root nodes invisible by default) 02891 02892 SeeAlso: SGDisplayNode::SGDisplayNode 02893 02894 ***********************************************************************************************/ 02895 02896 SGDisplayRoot::SGDisplayRoot() 02897 { 02898 Child = NULL; 02899 02900 Flags.Invisible = TRUE; // The root node is always invisible 02901 ParentGallery = NULL; 02902 ScrollExtent = 0; 02903 02904 ERROR3("SGDisplayRoot constructed in an illegal manner"); 02905 } 02906 02907 02908 02909 /*********************************************************************************************** 02910 02911 > SGDisplayRoot::SGDisplayRoot(SuperGallery *ParentGal) 02912 02913 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02914 Created: 26/10/94 02915 02916 Inputs: ParentGal - A pointer to the parent gallery of this node/tree 02917 02918 Purpose: SGDisplayRoot constructor (makes root nodes invisible by default) 02919 02920 SeeAlso: SGDisplayNode::SGDisplayNode 02921 02922 ***********************************************************************************************/ 02923 02924 SGDisplayRoot::SGDisplayRoot(SuperGallery *ParentGal) 02925 { 02926 Child = NULL; 02927 02928 Flags.Invisible = TRUE; // The root node is always invisible 02929 ParentGallery = ParentGal; 02930 ScrollExtent = 0; 02931 } 02932 02933 02934 02935 /*********************************************************************************************** 02936 02937 > virtual SGDisplayNode *SGDisplayRoot::GetChild(void) const 02938 02939 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02940 Created: 20/10/94 (Made virtual 13/5/95) 02941 Returns: A pointer to the first child of this SGDisplayNode object, or NULL 02942 02943 Purpose: Finds the child of this DisplayTree Node. 02944 Returns NULL if you have reached the boundary of the tree 02945 02946 SeeAlso: SuperGallery; SGDisplayNode::GetParent; 02947 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 02948 02949 ***********************************************************************************************/ 02950 02951 SGDisplayNode *SGDisplayRoot::GetChild(void) const 02952 { 02953 return(Child); 02954 } 02955 02956 02957 02958 /*********************************************************************************************** 02959 02960 > void SGDisplayRoot::SetChild(SGDisplayNode *NewChild) 02961 02962 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02963 Created: 20/10/94 02964 02965 Inputs: A pointer to the new first-child of this SGDisplayNode object 02966 02967 Purpose: Sets the child of this DisplayTree Node. Overrides to base class method 02968 to allow the child to be set. 02969 02970 SeeAlso: SuperGallery; SGDisplayNode::GetParent; 02971 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 02972 02973 ***********************************************************************************************/ 02974 02975 void SGDisplayRoot::SetChild(SGDisplayNode *NewChild) 02976 { 02977 Child = NewChild; 02978 } 02979 02980 02981 02982 /*********************************************************************************************** 02983 02984 > virtual SuperGallery *SGDisplayRoot::GetParentGallery(void) const 02985 02986 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02987 Created: 28/10/94 02988 02989 Returns: The parent SuperGallery, or NULL 02990 02991 Purpose: Returns the SuperGallery which 'owns' this node (and its subtree) 02992 02993 SeeAlso: SGDisplayNode::GetParentGallery 02994 02995 ***********************************************************************************************/ 02996 02997 SuperGallery *SGDisplayRoot::GetParentGallery(void) const 02998 { 02999 ERROR3IF(ParentGallery == NULL, "I have no parent gallery! This is not right!"); 03000 03001 return(ParentGallery); 03002 } 03003 03004 03005 03006 /*********************************************************************************************** 03007 03008 > virtual void SGDisplayRoot::InsertAfter(SGDisplayNode *NodeToInsert) 03009 03010 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03011 Created: 21/10/94 03012 03013 Inputs: NodeToInsert - the new node to insert into the tree 03014 03015 Purpose: OVERRIDES SGDisplayNode::InsertAfter 03016 03017 Insertions at the root node are always converted to AddItem() calls, 03018 to insert the item as the last child of the root node. The root cannot 03019 have siblings! 03020 03021 SeeAlso: SGDisplayNode::AddItem 03022 03023 ***********************************************************************************************/ 03024 03025 void SGDisplayRoot::InsertAfter(SGDisplayNode *NodeToInsert) 03026 { 03027 AddItem(NodeToInsert); 03028 } 03029 03030 03031 03032 /*********************************************************************************************** 03033 03034 > virtual void SGDisplayRoot::InsertBefore(SGDisplayNode *NodeToInsert) 03035 03036 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03037 Created: 21/10/94 03038 03039 Inputs: NodeToInsert - the new node to insert into the tree 03040 03041 Purpose: OVERRIDES SGDisplayNode::InsertBefore 03042 03043 Insertions at the root node are always converted to AddItem() calls, 03044 to insert the item as the last child of the root node. The root cannot 03045 have siblings! 03046 03047 SeeAlso: SGDisplayNode::AddItem 03048 03049 ***********************************************************************************************/ 03050 03051 void SGDisplayRoot::InsertBefore(SGDisplayNode *NodeToInsert) 03052 { 03053 AddItem(NodeToInsert); 03054 } 03055 03056 03057 03058 /*********************************************************************************************** 03059 03060 > virtual void SGDisplayRoot::RemoveFromTree(void) 03061 03062 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03063 Created: 21/10/94 03064 03065 Purpose: OVERRIDES SGDisplayNode::RemoveFromTree 03066 The root node cannot be removed from the tree - it returns quietly, taking 03067 no action (this allows the generic treatment of DestroyTree to work without 03068 having to take special action for delinking the root node) 03069 03070 SeeAlso: SGDisplayNode::RemoveFromTree; SGDisplayNode::DestroySubtree 03071 03072 ***********************************************************************************************/ 03073 03074 void SGDisplayRoot::RemoveFromTree(void) 03075 { 03076 // do nothing 03077 } 03078 03079 03080 03081 /*********************************************************************************************** 03082 03083 > virtual void SGDisplayRoot::DestroySubtree(BOOL IncludingThisNode = TRUE) 03084 03085 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03086 Created: 21/10/94 03087 03088 Inputs: IncludingThisNode - TRUE (The default) to delete this node (the root of 03089 the subtree) as well as all its children. 03090 FALSE to delete its children only (This leaves this node untouched, but 03091 vapes all child nodes) 03092 NOTE - This parameter is ignored, and always treated as FALSE 03093 03094 Purpose: DESTROYS the subtree starting at this root node. 03095 This does a depth-first recursive scan of the subtree, delinking each item, 03096 and then CALLING EACH ITEMS DESTRUCTOR. 03097 03098 IT DOES NOT destruct the root node, however (i.e. it destroys the tree down 03099 to the point where only the root is left alive). 03100 03101 Errors: May be generated by the RemoveFromTree and destructor calls if the subtree 03102 is in some way corrupt - see these calls for details. 03103 03104 SeeAlso: SuperGallery; SGDisplayNode::RemoveFromTree; SGDisplayNode::DestroySubtree 03105 03106 ***********************************************************************************************/ 03107 03108 void SGDisplayRoot::DestroySubtree(BOOL IncludingThisNode) 03109 { 03110 // Destroy all our children, but DO NOT delete 'this' node! 03111 SGDisplayNode::DestroySubtree(FALSE); 03112 } 03113 03114 03115 03116 /*********************************************************************************************** 03117 03118 > virtual void SGDisplayRoot::InitFormatInfo(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo) 03119 03120 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03121 Created: 24/10/94 03122 03123 Inputs: FormatInfo - Points at the format information to be initialised 03124 MiscInfo - Points at a structure containing standard 'MiscInfo' 03125 03126 Outputs: FormatInfo is initialised as appropriate 03127 MiscInfo->MaxWidth is gridlocked to the pixel grid 03128 03129 Purpose: Resets the formatting info structure to default values for the start of a 03130 formatting pass. Must be called before SGDisplayRoot::Redraw 03131 03132 SeeAlso: SGDisplayRoot::Redraw 03133 03134 ***********************************************************************************************/ 03135 03136 void SGDisplayRoot::InitFormatInfo(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo) 03137 { 03138 MiscInfo->MaxWidth = GridLock(MiscInfo, MiscInfo->MaxWidth); // Maximum width of formatting lines 03139 03140 FormatInfo->LinePos = 0; // Start at the top of the list 03141 FormatInfo->LineHeight = 0; // The current line is 0 height so far 03142 FormatInfo->AvailableWidth = MiscInfo->MaxWidth; // The full line is left to allocate 03143 FormatInfo->IndentLevel = 0; // Initially we are not indented 03144 03145 FormatInfo->AccumulateBounds = FALSE; // By default, don't accumulate bounds 03146 FormatInfo->LastInvalidNode = NULL; // For the group dragging redraw fix 03147 FormatInfo->InvalidBounds = DocRect(0, 1, MiscInfo->MaxWidth, 2); 03148 } 03149 03150 03151 03152 /*********************************************************************************************** 03153 03154 > virtual BOOL SGDisplayRoot::HandleEvent(SGEventType EventType, void *EventInfo, 03155 SGMiscInfo *MiscInfo) 03156 03157 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03158 Created: 20/10/94 03159 03160 Inputs: See SGDisplayNode::HandleEvent 03161 03162 Returns: TRUE if the event was handled successfully 03163 FALSE if it was not 03164 03165 Purpose: Handles a SuperGallery DisplayTree event 03166 03167 Notes: This overrides the pure virtual SGDisplayNode::HandleEvent method 03168 03169 A node need not handle a specific event - if it does not handle it, it 03170 should return FALSE. 03171 03172 Redraw and Formatting handlers should never return TRUE, as this will 03173 prevent the event from continuing through the tree. 03174 03175 Non-leaf-nodes must call SGDisplayNode::GiveEventToMyChildren in order 03176 to pass the event down the tree. 03177 03178 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayGroup::HandleEvent; 03179 SGDisplayItem::HandleEvent; SGDisplayRoot::InitFormatInfo; 03180 SGDisplayRoot::CalculateListExtent; 03181 SGDisplayNode::GiveEventToMyChildren 03182 03183 ***********************************************************************************************/ 03184 03185 BOOL SGDisplayRoot::HandleEvent(SGEventType EventType, void *EventInfo, 03186 SGMiscInfo *MiscInfo) 03187 { 03188 switch (EventType) 03189 { 03190 case SGEVENT_FORMAT: 03191 // Do nothing, but ensure we don't use the 'default:' case. 03192 break; 03193 03194 case SGEVENT_REDRAW: 03195 { 03196 SGRedrawInfo *RedrawInfo = GetRedrawInfo(EventType, EventInfo); 03197 03198 // This line is to stop the white flicker when backgrounding the items 03199 // Hmmm... There are a few problems which need sorting out though ! 03200 if (BkgEraseMode == TRUE) 03201 { 03202 StartRendering(RedrawInfo, MiscInfo); 03203 03204 RenderRegion *pRender = RedrawInfo->Renderer; 03205 03206 // Set default background colour 03207 pRender->SetFillColour(RedrawInfo->Background); 03208 pRender->SetLineColour(COLOUR_TRANS); //RedrawInfo->Background); 03209 03210 // Work out height first to avoid ENSURE in DocRect ctor 03211 INT32 height=ScrollExtent; 03212 // Extend the rect if necessary to ensure entire window bg is filled 03213 if (ScrollExtent < MiscInfo->WindowHeight) 03214 height = MiscInfo->WindowHeight; 03215 03216 if ((height>=0) && (MiscInfo->MaxWidth>=0)) 03217 { 03218 // Fill entire display window background with bg colour 03219 DocRect WindowBG(0, -height, MiscInfo->MaxWidth, 0); 03220 pRender->DrawRect(&WindowBG); 03221 } 03222 03223 StopRendering(RedrawInfo, MiscInfo); 03224 } 03225 else 03226 BkgEraseMode = TRUE; 03227 03228 if (GetChild() == NULL) // We have no children (empty tree) 03229 { 03230 // Redraw ourself as 'No Items' indicator 03231 // ERROR3("SGDisplayRoot::Redraw - I have no children to draw"); 03232 return(TRUE); // Might as well return TRUE - there is nobody else! 03233 } 03234 } 03235 break; 03236 03237 03238 default: 03239 return(SGDisplayNode::HandleEvent(EventType, EventInfo, MiscInfo)); 03240 } 03241 03242 // We have children, so recursively call them all with this event 03243 BOOL result = GiveEventToMyChildren(EventType, EventInfo, MiscInfo); 03244 03245 // If we've just reformatted the tree, remember the new list extent 03246 if (EventType == SGEVENT_FORMAT) 03247 { 03248 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 03249 03250 ScrollExtent = (ABS(FormatInfo->LinePos)); 03251 SetScrollOffset(GetScrollOffset(), MiscInfo); // Ensure not scrolled off end! 03252 03253 if (FormatInfo->LastInvalidNode != NULL) 03254 { 03255 // The immediately previous (final) node had invalid bounds. 03256 // We'd better include the blank part of the list below it in the 03257 // invalid bounds, to ensure we don't leave little bits of stuff past the end 03258 // of the list if it has got smaller. 03259 03260 ERROR3IF(FormatInfo->InvalidBounds.hi.y > 0, 03261 "Gallery display formatting error - LastInvalidNode should be NULL " 03262 "if there haven't been any invalid nodes yet"); 03263 03264 FormatInfo->InvalidBounds.lo.y = FormatInfo->LinePos - MiscInfo->WindowHeight; 03265 } 03266 } 03267 03268 return(result); 03269 } 03270 03271 03272 03273 /*********************************************************************************************** 03274 03275 > virtual INT32 SGDisplayRoot::CalculateListExtent(SGFormatInfo *FormatInfo, 03276 SGMiscInfo *MiscInfo) 03277 03278 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03279 Created: 26/10/94 03280 03281 Inputs: FormatInfo - should have been initialised with InitFormatInfo 03282 MiscInfo - Miscellanous info needed for formatting 03283 03284 Outputs: FormatInfo is updated as appropriate 03285 03286 Returns: The needed (window scroll) extent to contain the entire list if it were to 03287 be redrawn right now. NOTE that this is a positive value; if you wish to 03288 use this to find the bottom of the virtual space coordinates, you must 03289 negate it (as Virtual space runs from 0 to -Extent) 03290 03291 Purpose: Causes the entire subtree from this node to format themselves, and 03292 returns the 'height' of the entire list display, in millipoints 03293 03294 SeeAlso: SGDisplayRoot::InitFormatInfo; SGDisplayRoot::GetCachedListExtent 03295 03296 ***********************************************************************************************/ 03297 03298 INT32 SGDisplayRoot::CalculateListExtent(SGFormatInfo *FormatInfo, SGMiscInfo *MiscInfo) 03299 { 03300 if (GetChild() == NULL) 03301 return(0); 03302 03303 // Ask ourself to handle a FORMAT event. This recursively formats the tree, and returns 03304 // with FormatInfo indicating the state at the end of formatting (FormatInfo->LinePos 03305 // is at the end position of the list, and hence gives us the extent) 03306 HandleEvent(SGEVENT_FORMAT, FormatInfo, MiscInfo); 03307 return(ScrollExtent); 03308 } 03309 03310 03311 03312 /*********************************************************************************************** 03313 03314 > virtual INT32 SGDisplayRoot::GetCachedListExtent(void) 03315 03316 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03317 Created: 1/3/95 03318 03319 Returns: The currently cached value for the scroll extent 03320 03321 Purpose: Returns the 'height' of the entire list display, in millipoints. 03322 This return value is only valid after the tree has been formatted (including 03323 a previous call to CalculateListExtent), so long as the cached tree format 03324 is still valid. Use with care. 03325 03326 SeeAlso: SGDisplayRoot::CalculateListExtent 03327 03328 ***********************************************************************************************/ 03329 03330 INT32 SGDisplayRoot::GetCachedListExtent(void) 03331 { 03332 return(ScrollExtent); 03333 } 03334 03335 03336 03337 /*********************************************************************************************** 03338 03339 > virtual void SGDisplayRoot::SetScrollOffset(INT32 NewOffset, SGMiscInfo *MiscInfo) 03340 03341 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03342 Created: 21/1/95 03343 03344 Inputs: NewOffset - The new scroll offset. 03345 This is a number between 0 and LengthOfList, in MILLIPOINTs 03346 03347 MiscInfo - the usual 03348 03349 Purpose: Changes the scroll offset, and if necessary, redraws the scroll bar 03350 03351 In the base class, no scrollbar is supplied; this method does nothing 03352 03353 SeeAlso: SGDisplayRoot::GetScrollOffset; SGDisplayRootScroll::SetScrollOffset 03354 03355 ***********************************************************************************************/ 03356 03357 void SGDisplayRoot::SetScrollOffset(INT32 NewOffset, SGMiscInfo *MiscInfo) 03358 { 03359 // Base class does nothing 03360 } 03361 03362 03363 03364 /*********************************************************************************************** 03365 03366 > virtual INT32 SGDisplayRoot::GetScrollOffset(void) 03367 03368 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03369 Created: 21/1/95 03370 03371 Returns: In the base class, always returns 0 03372 03373 Returns: The current Scroll offset. This is a positive MLLIPOINT value. Note that 03374 virtual coordinates go from 0 to -Extent, so the point of VirtualSpace which 03375 maps to the top left displayed pixel on screen is at (-ScrollOffset). 03376 03377 In the base class, no scrollbar is supplied; this method does nothing 03378 03379 SeeAlso: SGDisplayRoot::SetScrollOffset; SGDisplayRootScroll::GetScrollOffset 03380 03381 ***********************************************************************************************/ 03382 03383 INT32 SGDisplayRoot::GetScrollOffset(void) 03384 { 03385 // Base class does nothing - There is no scroll offset 03386 return(0); 03387 } 03388 03389 03390 03391 /*********************************************************************************************** 03392 03393 > void SGDisplayRoot::RedrawScrollBar(SGMiscInfo *MiscInfo) 03394 03395 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03396 Created: 3/2/95 03397 03398 Inputs: MiscInfo - The normal MiscInfo for SGDisplayNode events 03399 03400 Purpose: Causes the scroll bar, if any, to be redrawn. 03401 In the base class, this method does nothing 03402 03403 SeeAlso: SGDisplayRootScroll::RedrawScrollBar 03404 03405 ***********************************************************************************************/ 03406 03407 void SGDisplayRoot::RedrawScrollBar(SGMiscInfo *MiscInfo) 03408 { 03409 // The base class has no scrollbar, so does nothing 03410 } 03411 03412 03413 03414 /*********************************************************************************************** 03415 03416 > virtual SGDisplayItem *SGDisplayRoot::FindNextSelectedItem( 03417 SGDisplayNode *CurrentItem = NULL, 03418 BOOL *SkipGroup = NULL) 03419 03420 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03421 Created: 10/2/95 03422 03423 Inputs: CurrentItem - NULL to find the first selected item, else 03424 An SGDisplayItem (node) indicating the 'position' to search from for the next 03425 selected item 03426 03427 Outputs: if Non-NULL, SkipGroup will be filled in with TRUE if the scan has just 03428 skipped onto a new document/library group within the tree, or FALSE if the 03429 scan remains in the same group as the last selected node was in. If CurrentItem 03430 was NULL on entry, this returned value will be TRUE. 03431 03432 Returns: NULL (if no selection), or 03433 A pointer to the first selected leaf of this tree which occurs after 03434 the 'CurrentItem'. If CurrentItem is NULL, then the first selected 03435 leaf node is returned. 03436 03437 Purpose: Scanning the selection within a Display Tree - this will scan over 03438 multiple documents/libraries without blinking an eyelid. 03439 03440 Use to scan through multiple-group selections, or to find the 03441 first selected item without having to know which document/library group 03442 it belongs to. 03443 03444 Notes: This method relies heavily on the flat (root/group/item) structure of 03445 current display trees - it will fail horribly if this simple layout is 03446 changed. 03447 03448 Warning: It may be possible for groups AND items to be selected at one 03449 time. This essentially filters Groups out of the selection scan. 03450 03451 SeeAlso: SGDisplayNode::FindSubtree; SGDisplayGroup::FindNextSelectedItem; 03452 SGDisplayRoot::GetSelectedItemCount; SGDisplayGroup::GetSelectedItemCount; 03453 SGDisplayRoot::FindNextSelectedGroup 03454 03455 ***********************************************************************************************/ 03456 03457 SGDisplayItem *SGDisplayRoot::FindNextSelectedItem(SGDisplayNode *CurrentItem, 03458 BOOL *SkipGroup) 03459 { 03460 BOOL ReturnSkip = (CurrentItem == NULL); 03461 SGDisplayItem *ReturnItem = NULL; 03462 03463 // Find the current group node - my first child, or the the current item's parent. 03464 SGDisplayGroup *CurrentGroup; 03465 if (CurrentItem != NULL) 03466 CurrentGroup = (SGDisplayGroup *) CurrentItem->GetParent(); 03467 else 03468 CurrentGroup = (SGDisplayGroup *) GetChild(); 03469 03470 ERROR3IF(CurrentGroup != NULL && !CurrentGroup->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup)), 03471 "The gallery displaytree seems to have mutated- " 03472 "where have my lovely groups gone?"); 03473 03474 // Search each sibling group in turn until we find another selected leaf item 03475 while (CurrentGroup != NULL && ReturnItem == NULL) 03476 { 03477 ReturnItem = CurrentGroup->FindNextSelectedItem((SGDisplayItem *)CurrentItem); 03478 if (ReturnItem == NULL) 03479 { 03480 // No more selected items in this group - skip onto the next group, and flag 03481 // the fact that we had to skip to a different group 03482 ReturnSkip = TRUE; 03483 CurrentGroup = (SGDisplayGroup *) CurrentGroup->GetNext(); 03484 CurrentItem = NULL; 03485 } 03486 } 03487 03488 // Return the SkipGroup output 03489 if (SkipGroup != NULL) 03490 *SkipGroup = ReturnSkip; 03491 03492 03493 // And return NULL or the next selected node 03494 return(ReturnItem); 03495 } 03496 03497 03498 03499 /*********************************************************************************************** 03500 03501 > virtual INT32 SGDisplayRoot::GetSelectedItemCount(void) 03502 03503 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03504 Created: 10/2/95 03505 03506 Returns: The number of items in this display tree which are selected (may return 0) 03507 03508 Purpose: To determine how many eaf items of this tree are selected 03509 03510 Notes: This scans the selection (is not cached), so calling it multiple times 03511 should be avoided where possible 03512 03513 This method relies heavily on the flat (root/group/item) structure of 03514 current display trees - it will fail horribly if this simple layout is 03515 changed. 03516 03517 SeeAlso: SGDisplayRoot::FindNextSelectedItem; SGDisplayGroup::GetSelectedItemCount; 03518 SGDisplayRoot::GetSelectedGroupCount 03519 03520 ***********************************************************************************************/ 03521 03522 INT32 SGDisplayRoot::GetSelectedItemCount(void) 03523 { 03524 INT32 Count = 0; 03525 03526 SGDisplayGroup *Ptr = (SGDisplayGroup *) GetChild(); 03527 while (Ptr != NULL) 03528 { 03529 Count += Ptr->GetSelectedItemCount(); 03530 Ptr = (SGDisplayGroup *) Ptr->GetNext(); 03531 } 03532 03533 return(Count); 03534 } 03535 03536 03537 /******************************************************************************************** 03538 03539 > virtual void SGDisplayRoot::SelectRange(SGDisplayNode *PrimeNode, SGDisplayNode *AnchorNode); 03540 03541 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 03542 Created: 26/5/95 03543 03544 Inputs: PrimeNode - The node which MUST be selected. May NOT be NULL. 03545 03546 AnchorNode - The other node, specifying a range of sibling nodes to 03547 be selected. May be NULL, in which case only PrimeNode is selected 03548 03549 Purpose: Selects the PrimeNode, and if possible, all sibling nodes between it and 03550 the Anchor node. If Anchor == NULL or is not found, only PrimeNode is 03551 selected. Does not deselect any nodes - you should call SelectItems first 03552 to clear the seln. 03553 03554 Note: The code to do the selection is now sub-contracted out to SelectRangeGroups 03555 and SelectRangeItems, depending on the type of the two given nodes. 03556 03557 If prime node is an item and the other a group, nothing will be selected... 03558 If prime node is an item and the null, the item will be selected... 03559 03560 ********************************************************************************************/ 03561 03562 void SGDisplayRoot::SelectRange(SGDisplayNode *PrimeNode, SGDisplayNode *AnchorNode) 03563 { 03564 ERROR3IF(PrimeNode == NULL, "SGDisplayRoot::SelectRange - PrimeNode must be non-NULL"); 03565 03566 if (AnchorNode == NULL || PrimeNode->GetParent() != AnchorNode->GetParent()) 03567 { 03568 // There is no anchor, or the prime/anchor nodes are not siblings, so 03569 // we cannot select a range - select PrimeNode, deselect all others 03570 ParentGallery->SelectItems(FALSE); 03571 ParentGallery->SelectGroups(FALSE); 03572 03573 // Paint the list now to reduce the chance of large redraws if the 03574 // old/new selections are far apart. 03575 ParentGallery->PaintListNow(); 03576 03577 PrimeNode->SetSelected(TRUE); 03578 ParentGallery->PaintListNow(); 03579 } 03580 else if (PrimeNode->IS_KIND_OF(SGDisplayItem) && (AnchorNode == NULL || AnchorNode->IS_KIND_OF(SGDisplayItem))) 03581 { 03582 // We are selecting a range of items so deselect all groups first 03583 ParentGallery->SelectGroups(FALSE); // Deselect all groups 03584 SelectRangeItems((SGDisplayItem *)PrimeNode, (SGDisplayItem *)AnchorNode); 03585 } 03586 else if (PrimeNode->IS_KIND_OF(SGDisplayGroup) && (AnchorNode == NULL || AnchorNode->IS_KIND_OF(SGDisplayGroup))) 03587 { 03588 // We are selecting a range of groups so deselect all items first 03589 ParentGallery->SelectItems(FALSE); // Deselect all items 03590 SelectRangeGroups((SGDisplayGroup *)PrimeNode, (SGDisplayGroup *)AnchorNode); 03591 } 03592 03593 // And ensure the gallery updates itself appropriately 03594 ParentGallery->SelectionHasChanged(); 03595 } 03596 03597 03598 03599 /*********************************************************************************************** 03600 03601 > virtual SGDisplayGroup *SGDisplayRoot::FindNextSelectedGroup( 03602 SGDisplayNode *CurrentGroup = NULL) 03603 03604 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03605 Created: 10/2/95 03606 03607 Inputs: CurrentGroup - NULL to find the first selected Group, else 03608 An SGDisplayGroup indicating the 'position' to search from for the next 03609 selected Group 03610 03611 Returns: NULL (if no selection), or 03612 A pointer to the first selected leaf of this tree which occurs after 03613 the 'CurrentGroup'. If CurrentGroup is NULL, then the first selected 03614 leaf node is returned. 03615 03616 Purpose: Scanning the group-selection within a Display Tree. 03617 03618 Notes: This method relies heavily on the flat (root/group/Group) structure of 03619 current display trees - it will fail horribly if this simple layout is 03620 changed. 03621 03622 Warning: It may be possible for groups AND items to be selected at one 03623 time. This essentially filters Items out of the selection scan. 03624 03625 SeeAlso: SGDisplayRoot::FindNextSelectedItem; SGDisplayRoot::GetSelectedGroupCount 03626 03627 ***********************************************************************************************/ 03628 03629 SGDisplayGroup *SGDisplayRoot::FindNextSelectedGroup(SGDisplayNode *CurrentGroup) 03630 { 03631 // Find the current group node - my first child, or the the current Group's parent. 03632 if (CurrentGroup != NULL) 03633 CurrentGroup = ((SGDisplayGroup *) CurrentGroup)->GetNext(); 03634 else 03635 CurrentGroup = (SGDisplayGroup *) GetChild(); 03636 03637 ERROR3IF(CurrentGroup != NULL && !CurrentGroup->IsKindOf(CC_RUNTIME_CLASS(SGDisplayGroup)), 03638 "The gallery displaytree seems to have mutated- " 03639 "where have my lovely groups gone?"); 03640 03641 // Search each sibling group in turn until we find another selected leaf Group 03642 while (CurrentGroup != NULL) 03643 { 03644 if (CurrentGroup->IsSelected()) // Found a selected group - return it 03645 return((SGDisplayGroup *)CurrentGroup); 03646 03647 CurrentGroup = ((SGDisplayGroup *) CurrentGroup)->GetNext(); 03648 } 03649 03650 // No more selected groups 03651 return(NULL); 03652 } 03653 03654 03655 03656 /*********************************************************************************************** 03657 03658 > virtual INT32 SGDisplayRoot::GetSelectedGroupCount(void) 03659 03660 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03661 Created: 10/2/95 03662 03663 Returns: The number of Groups in this display tree which are selected (may return 0) 03664 03665 Purpose: To determine how many eaf Groups of this tree are selected 03666 03667 Notes: This scans the selection (is not cached), so calling it multiple times 03668 should be avoided where possible 03669 03670 This method relies heavily on the flat (root/group/Group) structure of 03671 current display trees - it will fail horribly if this simple layout is 03672 changed. 03673 03674 SeeAlso: SGDisplayRoot::FindNextSelectedGroup; SGDisplayGroup::GetSelectedGroupCount 03675 03676 ***********************************************************************************************/ 03677 03678 INT32 SGDisplayRoot::GetSelectedGroupCount(void) 03679 { 03680 INT32 Count = 0; 03681 03682 SGDisplayGroup *Ptr = (SGDisplayGroup *) GetChild(); 03683 while (Ptr != NULL) 03684 { 03685 if (Ptr->IsSelected()) 03686 Count++; 03687 03688 Ptr = (SGDisplayGroup *) Ptr->GetNext(); 03689 } 03690 03691 return(Count); 03692 } 03693 03694 03695 03696 03697 03698 /*********************************************************************************************** 03699 03700 > static SGDisplayNode *SGDisplayRoot::FindNextItemInTree(SGDisplayNode *StartItem) 03701 03702 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 03703 Created: 15/04/96 03704 03705 Inputs: StartItem - Item from which to start looking for next item 03706 03707 Returns: The next item, or NULL if no further items found 03708 03709 Purpose: Given an item in the tree, find the next one. 03710 03711 Notes: This function will skip virtualised groups, so if you need to do something 03712 globally, don't call this... 03713 03714 SeeAlso: SGDisplayRoot::GetSelectedItemCount; 03715 03716 ***********************************************************************************************/ 03717 03718 SGDisplayNode *SGDisplayRoot::FindNextItemInTree(SGDisplayNode *StartItem) 03719 { 03720 ERROR3IF(StartItem == NULL, "SGDisplayRoot::FindNextItemInTree given a NULL StartItem - bad"); 03721 if(StartItem == NULL) return NULL; 03722 03723 SGDisplayNode *Item = StartItem; 03724 03725 // If this is the last item in the group, skip to the next group 03726 if (Item->GetNext() == NULL) 03727 { 03728 ERROR3IF(Item->GetParent() == NULL, "Tree linkage corruption"); 03729 03730 // Check if we're the last group 03731 if (Item->GetParent()->GetNext() != NULL) 03732 { 03733 SGDisplayNode *TmpItem = Item->GetParent()->GetNext(); 03734 03735 // Jump over any virtualised groups 03736 while(TmpItem != NULL && TmpItem->GetChild() == NULL) 03737 TmpItem = TmpItem->GetNext(); 03738 03739 // Check if gone over last group 03740 if(TmpItem == NULL) 03741 Item = NULL; 03742 else 03743 Item = TmpItem->GetChild(); 03744 } 03745 else 03746 Item = NULL; 03747 } 03748 else 03749 Item = Item->GetNext(); // Get next sibling item 03750 03751 return Item; 03752 } 03753 03754 03755 03756 03757 03758 03759 03760 03761 03762 03763 03764 /*********************************************************************************************** 03765 03766 > SGDisplayRootScroll::SGDisplayRootScroll(SuperGallery *ParentGal) 03767 03768 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03769 Created: 26/10/94 03770 03771 Inputs: ParentGal - A pointer to the parent gallery of this node/tree 03772 03773 Purpose: SGDisplayRootScroll constructor (makes root nodes invisible by default) 03774 03775 SeeAlso: SGDisplayNode::SGDisplayNode 03776 03777 ***********************************************************************************************/ 03778 03779 SGDisplayRootScroll::SGDisplayRootScroll(SuperGallery *ParentGal) : SGDisplayRoot(ParentGal) 03780 { 03781 ScrollOffset = 0; 03782 IndentedButton = IBUTTON_NONE; 03783 03784 // Read the scroll bar width - use half of the normal scroll bar width (and is an even number) 03785 PORTNOTE("galleries", "hard wired scrollbar width"); 03786 ScrollBarWidth = 12; 03787 // ScrollBarWidth = (CScroller::GetScrollerSize() / 2) & 0xFE; 03788 03789 if (ScrollBarWidth < 10) // But make sure it lies within a sensible range 03790 ScrollBarWidth = 10; 03791 if (ScrollBarWidth > 100) 03792 ScrollBarWidth = 100; 03793 } 03794 03795 03796 03797 /*********************************************************************************************** 03798 03799 > virtual void SGDisplayRootScroll::SetScrollOffset(INT32 NewOffset, SGMiscInfo *MiscInfo) 03800 03801 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03802 Created: 21/1/95 03803 03804 Inputs: NewOffset - The new scroll offset. 03805 This is a number between 0 and LengthOfList, in MILLIPOINTs 03806 03807 MiscInfo - the usual 03808 03809 Purpose: Changes the scroll offset, and if necessary, redraws the scroll bar 03810 03811 Notes: To ensure that the current scroll offset is within bounds, call 03812 SetScrollOffset(GetScrollOffset(), MiscInfo); 03813 03814 SeeAlso: SGDisplayRootScroll::GetScrollOffset; SGDisplayRoot::SetScrollOffset 03815 03816 ***********************************************************************************************/ 03817 03818 void SGDisplayRootScroll::SetScrollOffset(INT32 NewOffset, SGMiscInfo *MiscInfo) 03819 { 03820 // Ensure we don't scroll out of bounds 03821 if (NewOffset > ScrollExtent - MiscInfo->WindowHeight) 03822 NewOffset = ScrollExtent - MiscInfo->WindowHeight; 03823 03824 if (NewOffset < 0) 03825 NewOffset = 0; 03826 03827 // Make sure the scroll offset is aligned tidily with the output pixel grid 03828 GridLock(MiscInfo, NewOffset); 03829 03830 // And if it has changed, set the new scroll offset, and scroll the window 03831 if (NewOffset != ScrollOffset) 03832 { 03833 DocCoord ScrollBy(0, NewOffset - ScrollOffset); 03834 03835 if (!GetParentGallery()->AreYouRedrawingNow()) 03836 { 03837 // A normal scroll - we are not inside the redraw code, so we can safely 03838 // assume that the screen display is up to date (and therefore can be scrolled 03839 // with 'ScrollArea') and that it is safe to invoke redraw. 03840 03841 DocRect ScrollRect(0, 0, MiscInfo->MaxWidth - DevicePixels(MiscInfo, ScrollBarWidth), 03842 MiscInfo->WindowHeight); 03843 03844 // Scroll the window. During the scroll, we make sure that the drag manager 03845 // has removed any eor or solid drag blobs from screen, so we don't copy 03846 // them as part of the scroll! 03847 DragManagerOp::RedrawStarting(GetParentGallery()->WindowID, 03848 GetParentGallery()->GetListGadgetID()); 03849 03850 // And scroll 03851 GetParentGallery()->ScrollArea(&ScrollRect, &ScrollBy); 03852 03853 // Set the new scroll offset, using the gridlocked value returned from ScrollArea 03854 ScrollOffset += ScrollBy.y; 03855 03856 // Redraw immediately. If we scroll only a little bit, and do not redraw 03857 // immediately, we get a small horizontal strip, plus the vertical scroll bar 03858 // region, and so the redraw bounds is the entire window, so we redraw heaps 03859 // more than actually changes, thus making scrolling dead slow. 03860 GetParentGallery()->PaintListNow(); 03861 03862 // And redraw the proportional scrollbar 03863 DocRect ScrollBarRect(MiscInfo->MaxWidth - DevicePixels(MiscInfo, ScrollBarWidth), 03864 -ScrollExtent, 03865 MiscInfo->MaxWidth, 0); 03866 GetParentGallery()->ForceRedrawOfArea(&ScrollBarRect); 03867 03868 // And finally, force another immediate repaint of the list gadget 03869 GetParentGallery()->PaintListNow(); 03870 03871 DragManagerOp::RedrawFinished(); 03872 } 03873 else 03874 { 03875 // Awooga! We have been forced to fix the scroll offset during a redraw (probably 03876 // because the window size has changed). We thus change the scroll offset, but 03877 // do not try to redraw or anything - hopefully the pending redraw will handle 03878 // everything. 03879 03880 // Set the new scroll offset, using the gridlocked value returned from ScrollArea 03881 ScrollOffset += ScrollBy.y; 03882 } 03883 } 03884 } 03885 03886 03887 03888 /*********************************************************************************************** 03889 03890 > INT32 SGDisplayRootScroll::GetScrollOffset(void) 03891 03892 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03893 Created: 21/1/95 03894 03895 Returns: The current Scroll offset. This is a positive MLLIPOINT value. Note that 03896 virtual coordinates go from 0 to -Extent, so the point of VirtualSpace which 03897 maps to the top left displayed pixel on screen is at (-ScrollOffset). 03898 03899 Purpose: Returns the current scroll offset for the gallery display list represented in 03900 the tree. 03901 03902 SeeAlso: SGDisplayRootScroll::SetScrollOffset; SGDisplayRoot::GetScrollOffset 03903 03904 ***********************************************************************************************/ 03905 03906 INT32 SGDisplayRootScroll::GetScrollOffset(void) 03907 { 03908 return(ScrollOffset); 03909 } 03910 03911 03912 03913 /*********************************************************************************************** 03914 03915 > virtual BOOL SGDisplayRootScroll::CalculateScrollRects(SGMiscInfo *MiscInfo, 03916 BOOL Translate, 03917 DocRect *UpButton, DocRect *DownButton, 03918 DocRect *Sausage, DocRect *PageUp = NULL, 03919 DocRect *PageDown = NULL, DocRect *ScrollRect = NULL) 03920 03921 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 03922 Created: 28/2/95 03923 03924 Inputs: MiscInfo - The misc info, as passed to all event handlers 03925 Translate - TRUE to translate the returned rectangles to give Display-list 03926 coordinates, FALSE to give the coordinates as offsets within the visible 03927 display area on screen. 03928 03929 Outputs: The rects - Rectangles in millipoint offsets within the list gadget 03930 of the various bits of the scrollbar: up/down buttons, plus the 03931 sausage, and the page-up/down areas above/below the sausage. ScrollRect 03932 is the all-inclusive rectangle containing all the others. 03933 03934 PageUp, PageDown, and ScrollRect may be NULL. All others may not be NULL 03935 03936 Returns: TRUE if the scroll rects are valid, FALSE if there is not enough room 03937 for a scrollbar. If FALSE is returned, none of the outputs are valid, though 03938 some of them may have been changed/corrupted. 03939 03940 Purpose: Determines where in the gadget the scroll bar rectangles are. Used by 03941 the SGScrollDragTarget in order to determine if the mouse pointer still 03942 lies over a given rectangle. 03943 03944 ***********************************************************************************************/ 03945 03946 BOOL SGDisplayRootScroll::CalculateScrollRects(SGMiscInfo *MiscInfo, 03947 BOOL Translate, 03948 DocRect *UpButton, DocRect *DownButton, 03949 DocRect *Sausage, DocRect *PageUp, 03950 DocRect *PageDown, DocRect *pScrollRect) 03951 { 03952 ERROR3IF(MiscInfo == NULL || UpButton == NULL || DownButton == NULL || Sausage == NULL, 03953 "SGDispayRootScroll::CalculateScrollRects - NULL params are illegal"); 03954 03955 // Calculate the strip into which the scrollbar must fit... 03956 INT32 ScrollWidth = DevicePixels(MiscInfo, ScrollBarWidth); 03957 03958 #ifdef _DEBUG 03959 if (((MiscInfo->MaxWidth - ScrollWidth) > MiscInfo->MaxWidth) || (0 > MiscInfo->WindowHeight)) 03960 { 03961 TRACE( _T("Bad MiscInfo in SGDispayRootScroll::CalculateScrollRects\n")); 03962 TRACE( _T(" MaxWidth = %d\n"), MiscInfo->MaxWidth); 03963 TRACE( _T(" WindowHeight = %d\n"), MiscInfo->WindowHeight); 03964 TRACE( _T(" DisplayMode = %d\n"), MiscInfo->DisplayMode); 03965 TRACE( _T(" PixelSize = %d\n"), MiscInfo->PixelSize); 03966 TRACE( _T("ScrollBarWidth = %d\n"), ScrollBarWidth); 03967 TRACE( _T("ScrollWidth = %d\n"), ScrollWidth); 03968 } 03969 #endif 03970 03971 DocRect ScrollRect(MiscInfo->MaxWidth - ScrollWidth, 0, 03972 MiscInfo->MaxWidth, MiscInfo->WindowHeight); 03973 03974 // Convert, if necessary, the position, into display-list offsets 03975 if (Translate) 03976 ScrollRect.Translate(0, -(ScrollOffset + MiscInfo->WindowHeight)); 03977 03978 GridLockRect(MiscInfo, &ScrollRect); 03979 03980 if (!ScrollRect.IsValid()) 03981 return(FALSE); 03982 03983 // Calculate the squares for the up/down scroll buttons 03984 *UpButton =ScrollRect; 03985 UpButton->lo.x += DevicePixels(MiscInfo, 1); 03986 UpButton->lo.y = (UpButton->hi.y - ScrollWidth) + DevicePixels(MiscInfo, 1); 03987 03988 *DownButton = *UpButton; 03989 DownButton->Translate(0, -(MiscInfo->WindowHeight - 03990 (ScrollWidth - DevicePixels(MiscInfo, 1)) )); 03991 03992 // And make the scroll rect include only the central strip 03993 ScrollRect.Inflate(0, -(ScrollWidth - DevicePixels(MiscInfo, 1))); 03994 03995 BOOL Result = CalculateSausageRect(MiscInfo, &ScrollRect, Sausage); 03996 03997 if (PageUp != NULL) 03998 { 03999 *PageUp = ScrollRect; 04000 PageUp->lo.y = Sausage->hi.y; 04001 } 04002 04003 if (PageDown != NULL) 04004 { 04005 *PageDown = ScrollRect; 04006 PageDown->hi.y = Sausage->lo.y; 04007 } 04008 04009 if (pScrollRect != NULL) 04010 *pScrollRect = ScrollRect; 04011 04012 return(Result); 04013 } 04014 04015 04016 04017 /*********************************************************************************************** 04018 04019 > BOOL SGDisplayRootScroll::CalculateSausageRect(SGMiscInfo *MiscInfo, 04020 DocRect *ScrollBarRect, DocRect *Result) 04021 04022 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04023 Created: 21/1/95 04024 04025 Inputs: MiscInfo - The misc info, as passed to all event handlers 04026 ScrollBarRect - The bounds in which the scroll sausage can slide 04027 04028 Outputs: Result - Either unchanged (return == FALSE) or the rectangle to use 04029 for the scroll sausage (return == TRUE) 04030 04031 Returns: TRUE if it succeeds; FALSE if it did nothing 04032 (FALSE is returned when there is no room for a scroll sausage etc) 04033 04034 Purpose: Determines where within the given scroller the scroll 'sausage' (thumb) 04035 should be positioned to give the correct display 04036 04037 SeeAlso: SGDisplayRootScroll::SetScrollOffset; SGDisplayRoot::GetScrollOffset 04038 04039 ***********************************************************************************************/ 04040 04041 BOOL SGDisplayRootScroll::CalculateSausageRect(SGMiscInfo *MiscInfo, 04042 DocRect *ScrollBarRect, DocRect *Result) 04043 { 04044 INT32 PixelSize = MiscInfo->PixelSize; 04045 04046 // If the scroll bar hasn't got enough room to exist, it does not appear 04047 if (ScrollBarRect->hi.y - ScrollBarRect->lo.y < 5*PixelSize) 04048 return(FALSE); 04049 04050 *Result = *ScrollBarRect; 04051 Result->Inflate(-PixelSize); // Scroll sausage sits just inside the scroll rect 04052 Result->hi.x += PixelSize; // But the window border already does the 1-pixel black 04053 // line on the right, so we actually touch the scroll 04054 // rect on this edge. 04055 GridLockRect(MiscInfo, Result); 04056 04057 // If the sausage does not entirely fill the available space (we can scroll), then 04058 // scale and translate the sausage rect appropriately 04059 if (ScrollExtent > MiscInfo->WindowHeight) 04060 { 04061 // It is necessary to calculate the center of the sausage and grow it outwards 04062 // from that, so that we can ensure it never gets shorter that being a small square. 04063 04064 // Calculate the size of the proportional scroll sausage 04065 INT32 SausageHeight = (INT32) (((double)Result->Height()) * 04066 (((double)MiscInfo->WindowHeight) / (double)ScrollExtent)); 04067 04068 // Don't allow sausage to become smaller than a square 04069 if (SausageHeight < (ScrollBarWidth-2) * PixelSize) 04070 SausageHeight = (ScrollBarWidth-2) * PixelSize; 04071 04072 // BarTravel is the range in which the *center* of the scroll sausage can move - 04073 // this is limited by the overall bar height and the size of the scroll sausage 04074 INT32 BarTravel = Result->Height() - SausageHeight; 04075 04076 // Range in which the ScrollOffset is limited 04077 INT32 ScrollTravel = ScrollExtent - MiscInfo->WindowHeight; 04078 04079 // From which we calculate how far down the bar the sausage center appears 04080 double MidOffset = ((double)BarTravel * 04081 (((double)ScrollOffset) / (double)ScrollTravel)); 04082 04083 // Convert this into a position within the scroll rectangle (subtract from the top, 04084 // taking into account the gap at the top of the travel to contain half the sausage) 04085 MidOffset = (double) Result->hi.y - (((double)SausageHeight)/2 + MidOffset); 04086 04087 // Finally, shift and resize the scroll rectangle to generate the sausage rect 04088 Result->hi.y = (INT32) (-0.5 + MidOffset + SausageHeight/2); 04089 Result->lo.y = (INT32) (-0.5 + MidOffset - SausageHeight/2); 04090 GridLockRect(MiscInfo, Result); 04091 } 04092 04093 return(TRUE); 04094 } 04095 04096 04097 04098 /*********************************************************************************************** 04099 04100 > virtual BOOL SGDisplayRootScroll::HandleEvent(SGEventType EventType, void *EventInfo, 04101 SGMiscInfo *MiscInfo) 04102 04103 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04104 Created: 20/10/94 04105 04106 Inputs: See SGDisplayNode::HandleEvent 04107 04108 Returns: TRUE if the event was handled successfully 04109 FALSE if it was not 04110 04111 Purpose: Handles a SuperGallery DisplayTree event 04112 For this Scrollbar-providing version of the DisplayRoot node, adds a 04113 scrollbar at the right side of the window, and updates the event info 04114 appropriately to make the rest of the tree format to the left of that 04115 scroll bar. The scrollbar is 100% automated - any attempt to change the 04116 tree will result in the scrollbar updating as appropriate. 04117 04118 Notes: This overrides the pure virtual SGDisplayNode::HandleEvent method 04119 04120 A node need not handle a specific event - if it does not handle it, it 04121 should return FALSE. 04122 04123 Redraw and Formatting handlers should never return TRUE, as this will 04124 prevent the event from continuing through the tree. 04125 04126 Non-leaf-nodes must call SGDisplayNode::GiveEventToMyChildren in order 04127 to pass the event down the tree. 04128 04129 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayGroup::HandleEvent; 04130 SGDisplayItem::HandleEvent; SGDisplayRoot::InitFormatInfo; 04131 SGDisplayRoot::CalculateListExtent; 04132 SGDisplayNode::GiveEventToMyChildren 04133 04134 ***********************************************************************************************/ 04135 04136 BOOL SGDisplayRootScroll::HandleEvent(SGEventType EventType, void *EventInfo, 04137 SGMiscInfo *MiscInfo) 04138 { 04139 // THUMBMSG and BGFLUSH can be broadcast with MiscInfo == NULL. We ignore these msgs 04140 // so we just pass them on to the base class immediately. 04141 if (MiscInfo == NULL) 04142 return(SGDisplayRoot::HandleEvent(EventType, EventInfo, MiscInfo)); 04143 04144 SGMiscInfo NewMiscInfo(*MiscInfo); // Ensure we don't corrupt the one passed in 04145 04146 // Calculate the strip into which the scrollbar must fit... 04147 INT32 ScrollWidth = DevicePixels(MiscInfo, ScrollBarWidth); 04148 04149 DocRect ScrollRect; 04150 DocRect UpButton; 04151 DocRect DownButton; 04152 DocRect PageUp; 04153 DocRect PageDown; 04154 DocRect SausageRect; 04155 BOOL HasScrollBar = CalculateScrollRects(MiscInfo, TRUE, 04156 &UpButton, &DownButton, &SausageRect, 04157 &PageUp, &PageDown, &ScrollRect); 04158 04159 // Convince the DisplayTree the scroll area is outside the region they can use 04160 // We add 1 pixel to put a 1-pixel white gap between the scrollbar and the right end of all items 04161 NewMiscInfo.MaxWidth -= ScrollWidth; 04162 04163 // Remember what the scroll extent used to be. If formatting causes a chnage to the extent, 04164 // we'll redraw ourself to make sure that our display is up to date. 04165 INT32 OldScrollExtent = ScrollExtent; 04166 04167 switch (EventType) 04168 { 04169 case SGEVENT_FORMAT: 04170 if (HasScrollBar) 04171 { 04172 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 04173 04174 // Reset AvailableWidth so the first line doesn't overwrite the scrollbar! 04175 FormatInfo->AvailableWidth = NewMiscInfo.MaxWidth; 04176 } 04177 break; 04178 04179 04180 case SGEVENT_REDRAW: 04181 // Does nothing here - redraw is now delayed until after we have called all our 04182 // children, so that rampant clipping problems in the font gallery do not cause 04183 // the scrollbar to be left in an overwritten state. 04184 break; 04185 04186 04187 case SGEVENT_MOUSECLICK: 04188 if (HasScrollBar && ScrollExtent > 0) 04189 { 04190 SGMouseInfo *MouseInfo = GetMouseInfo(EventType, EventInfo); 04191 SGDragType DragType = SGDRAG_NONE; 04192 04193 if (ScrollRect.ContainsCoord(MouseInfo->Position)) 04194 { 04195 if (SausageRect.ContainsCoord(MouseInfo->Position)) 04196 DragType = SGDRAG_SAUSAGE; 04197 else if (SausageRect.hi.y < MouseInfo->Position.y) 04198 DragType = SGDRAG_PAGEUP; 04199 else if (SausageRect.lo.y > MouseInfo->Position.y) 04200 DragType = SGDRAG_PAGEDOWN; 04201 else 04202 return(TRUE); 04203 } 04204 04205 if (DragType == SGDRAG_NONE && UpButton.ContainsCoord(MouseInfo->Position)) 04206 DragType = SGDRAG_SCROLLUP; 04207 04208 if (DragType == SGDRAG_NONE && DownButton.ContainsCoord(MouseInfo->Position)) 04209 DragType = SGDRAG_SCROLLDOWN; 04210 04211 if (DragType != SGDRAG_NONE) 04212 { 04213 SGScrollDragInfo *DragInfo = 04214 new SGScrollDragInfo(this, DragType, MiscInfo, 04215 SausageRect.hi.y - MouseInfo->Position.y, 04216 MouseInfo->MenuClick); 04217 04218 if (DragInfo != NULL) 04219 DragManagerOp::StartDrag(DragInfo, GetListWindow()); 04220 } 04221 } 04222 break; 04223 04224 04225 case SGEVENT_DRAGSTARTED: 04226 { 04227 DragMessage *Msg = GetDragInfo(EventType, EventInfo); 04228 04229 // Is it a Drag Started message? 04230 if (Msg->State == DragMessage::DRAGSTARTED) 04231 { 04232 // Is it a SuperGallery scroll drag? 04233 // And is it a scroll drag for THIS display tree? 04234 if (Msg->pInfo->IsKindOf(CC_RUNTIME_CLASS(SGScrollDragInfo)) && 04235 ((SGScrollDragInfo *)(Msg->pInfo))->GetDragRootNode() == this) 04236 { 04237 SuperGallery *ParentGallery = GetParentGallery(); 04238 04239 // AMB comment out assignment to variable as variable is unused. Can this be right? 04240 /* SGScrollDragTarget *DragTarget = */ 04241 new SGScrollDragTarget(ParentGallery, 04242 ParentGallery->GetListGadgetID()); 04243 } 04244 } 04245 } 04246 break; 04247 04248 default: 04249 break; 04250 } 04251 04252 // And pass the event on to the tree via our base class handler 04253 BOOL Result = SGDisplayRoot::HandleEvent(EventType, EventInfo, 04254 (HasScrollBar) ? &NewMiscInfo : MiscInfo); 04255 04256 if (EventType == SGEVENT_FORMAT && ScrollExtent != OldScrollExtent && HasScrollBar) 04257 { 04258 // The scroll extent has changed as a result of this reformat. 04259 // We'd better invalidate the scrollbar rectangle to make sure it's up to date 04260 SuperGallery *ParentGal = GetParentGallery(); 04261 04262 04263 // We modify the scrollbar rectangle before invalidating it - if the extent has changed, 04264 // the scrollbar may have been scrolled off the visible area!! 04265 // The easiest way to redraw it is to just redraw everything down the right side of the extent 04266 ScrollRect.hi.y = 0; 04267 ScrollRect.lo.y = -(ScrollExtent + MiscInfo->WindowHeight); 04268 ParentGal->ForceRedrawOfArea(&ScrollRect); 04269 04270 // If the extent has got smaller, ensure the invalid redraw region includes 04271 // everything to the very bottom of the list 04272 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 04273 if (FormatInfo->AccumulateBounds) 04274 FormatInfo->InvalidBounds.lo.y = min(-OldScrollExtent, -ScrollExtent); 04275 } 04276 04277 if (EventType == SGEVENT_REDRAW && HasScrollBar) // If room for a scrollbar, draw it 04278 { 04279 // Redraw is now left until after all children have been redrawn, as the font gallery 04280 // has a clipping problem where it was overwriting the scrollbar area. By drawing last 04281 // we at least end up in the correct screen display state. 04282 INT32 PixelSize = DevicePixels(MiscInfo, 1); 04283 04284 SGRedrawInfo *RedrawInfo = GetRedrawInfo(EventType, EventInfo); 04285 RenderRegion *Renderer = RedrawInfo->Renderer; 04286 04287 StartRendering(RedrawInfo, MiscInfo); 04288 04289 // Note that we call the base class, so we can rely on it to clear the 04290 // background of the area outside the scrollbar 04291 04292 // If we don't need to redraw anything, then we, er... don't redraw anything 04293 if (ScrollRect.IsIntersectedWith(RedrawInfo->Bounds) || 04294 UpButton.IsIntersectedWith(RedrawInfo->Bounds) || 04295 DownButton.IsIntersectedWith(RedrawInfo->Bounds)) 04296 { 04297 DialogColourInfo RedrawColours; 04298 04299 // Fill the page-up and down rectangles with background colour. 04300 // We move the left and top/bottom edges by 1 pixel to accomodate 04301 // the black border lines that we draw around these areas. 04302 Renderer->SetLineWidth(0); 04303 DocColour trans(COLOUR_TRANS); 04304 Renderer->SetLineColour(trans); 04305 Renderer->SetFillColour(RedrawColours.ButtonFace()); 04306 04307 PageUp.lo.x += PixelSize; 04308 PageUp.hi.y -= PixelSize; 04309 if (PageUp.IsValid()) 04310 Renderer->DrawRect(&PageUp); 04311 04312 PageDown.lo.x += PixelSize; 04313 PageDown.lo.y += PixelSize; 04314 if (PageDown.IsValid()) 04315 Renderer->DrawRect(&PageDown); 04316 04317 // Draw a 1-pixel black border around the region 04318 // (down left edge and between scroll bar and arrows) 04319 // We draw these lines as filled rectangles to avoid the fact that lines 04320 // draw in different blimming places in different render regions 04321 DocColour black(COLOUR_BLACK); 04322 Renderer->SetFillColour(black); 04323 04324 Renderer->DrawPixelLine(DocCoord(ScrollRect.lo.x, DownButton.lo.y), 04325 DocCoord(ScrollRect.lo.x, UpButton.hi.y)); 04326 Renderer->DrawPixelLine(DocCoord(ScrollRect.lo.x, ScrollRect.hi.y - PixelSize), 04327 DocCoord(ScrollRect.hi.x, ScrollRect.hi.y - PixelSize)); 04328 Renderer->DrawPixelLine(DocCoord(ScrollRect.lo.x, ScrollRect.lo.y), 04329 DocCoord(ScrollRect.hi.x, ScrollRect.lo.y)); 04330 04331 // Draw the scroll sausage 04332 DrawPlinth(RedrawInfo, MiscInfo, &RedrawColours, &SausageRect, FALSE); 04333 04334 Renderer->DrawPixelLine(DocCoord(ScrollRect.lo.x, SausageRect.hi.y), 04335 DocCoord(ScrollRect.hi.x, SausageRect.hi.y)); 04336 Renderer->DrawPixelLine(DocCoord(ScrollRect.lo.x, SausageRect.lo.y - PixelSize), 04337 DocCoord(ScrollRect.hi.x, SausageRect.lo.y - PixelSize)); 04338 04339 // Draw the scroll-up and scroll-down buttons 04340 DrawPlinth(RedrawInfo, MiscInfo, &RedrawColours, 04341 &UpButton, (IndentedButton == IBUTTON_UP), 04342 _R(IDB_GALLERY_SCROLLUP)); 04343 04344 DrawPlinth(RedrawInfo, MiscInfo, &RedrawColours, 04345 &DownButton, (IndentedButton == IBUTTON_DOWN), 04346 _R(IDB_GALLERY_SCROLLDOWN)); 04347 } 04348 04349 StopRendering(RedrawInfo, MiscInfo); 04350 } 04351 04352 return(Result); 04353 } 04354 04355 04356 04357 /*********************************************************************************************** 04358 04359 > void SGDisplayRootScroll::RedrawScrollBar(SGMiscInfo *MiscInfo) 04360 04361 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04362 Created: 3/2/95 04363 04364 Inputs: MiscInfo - The normal MiscInfo for SGDisplayNode events 04365 04366 Purpose: Causes the scroll bar, if any, to be redrawn, ensuring that it shows the 04367 correct information for the current format of the display list 04368 04369 SeeAlso: SGDisplayRootScroll::RedrawScrollBar 04370 04371 ***********************************************************************************************/ 04372 04373 void SGDisplayRootScroll::RedrawScrollBar(SGMiscInfo *MiscInfo) 04374 { 04375 // Calculate the strip into which the scrollbar must fit... 04376 INT32 ScrollWidth = DevicePixels(MiscInfo, ScrollBarWidth); 04377 04378 DocRect ScrollRect(MiscInfo->MaxWidth - ScrollWidth, -MiscInfo->WindowHeight, 04379 MiscInfo->MaxWidth, 0); 04380 ScrollRect.Translate(0, -ScrollOffset); 04381 GridLockRect(MiscInfo, &ScrollRect); 04382 04383 GetParentGallery()->ForceRedrawOfArea(&ScrollRect); 04384 } 04385 04386 04387 04388 04389 04390 04391 04392 04393 04394 04395 04396 04397 04398 04399 /*********************************************************************************************** 04400 04401 > SGDisplayGroup::SGDisplayGroup() 04402 04403 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04404 Created: 31/10/94 04405 04406 Purpose: SGDisplayGroup constructor. NOTE that to initialise the parent gallery, 04407 document, and library pointers, you should use the other constructor. 04408 04409 ***********************************************************************************************/ 04410 04411 SGDisplayGroup::SGDisplayGroup() 04412 { 04413 Child = NULL; 04414 04415 ParentGallery = NULL; 04416 ParentDocument = NULL; 04417 ParentLibrary = NULL; 04418 04419 ChildArea.MakeEmpty(); 04420 04421 TRACE( _T("Warning: Using default constructor for SGDisplayGroup is silly\n")); 04422 } 04423 04424 04425 04426 /*********************************************************************************************** 04427 04428 > SGDisplayGroup::SGDisplayGroup(SuperGallery *ParentGal, 04429 Document *ParentDoc = NULL, Library *ParentLib = NULL) 04430 04431 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04432 Created: 31/10/94 04433 04434 Inputs: ParentGal - points to the SuperGallery object which 'owns' this node 04435 ParentDoc - NULL, or a pointer to the document this group references 04436 ParentLib - NULL, or a pointer to the library this group references 04437 04438 Purpose: SGDisplayGroup constructor. Initialises the Group's parent pointers to 04439 point at its parent(s). Note that generally speaking, one of ParentDoc, 04440 ParentLib will be NULL, and the other will be non-NULL. (This is not the 04441 case, however, for the Font gallery!) 04442 04443 ***********************************************************************************************/ 04444 04445 SGDisplayGroup::SGDisplayGroup(SuperGallery *ParentGal, 04446 Document *ParentDoc, Library *ParentLib) 04447 { 04448 // Sanity checks 04449 ERROR3IF(ParentGal == NULL, "SGDisplayGroup needs a parent gallery!"); 04450 ERROR3IF(ParentDoc != NULL && ParentLib != NULL, 04451 "SGDisplayGroup cannot have BOTH a doc and lib for parents!"); 04452 04453 Child = NULL; 04454 04455 ParentGallery = ParentGal; 04456 ParentDocument = ParentDoc; 04457 ParentLibrary = ParentLib; 04458 04459 if (ParentLibrary != NULL) // Library groups (which come off disc) default to folded 04460 Flags.Folded = TRUE; 04461 04462 ChildArea.MakeEmpty(); 04463 04464 ReadGroupTitle(); 04465 } 04466 04467 04468 04469 /*********************************************************************************************** 04470 04471 > virtual SGDisplayNode *SGDisplayGroup::GetChild(void) const 04472 04473 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04474 Created: 20/10/94 (Made virtual 13/5/95) 04475 Returns: A pointer to the first child of this SGDisplayNode object, or NULL 04476 04477 Purpose: Finds the child of this DisplayTree Node. 04478 Returns NULL if you have reached the boundary of the tree 04479 04480 SeeAlso: SuperGallery; SGDisplayNode::GetParent; 04481 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 04482 04483 ***********************************************************************************************/ 04484 04485 SGDisplayNode *SGDisplayGroup::GetChild(void) const 04486 { 04487 return(Child); 04488 } 04489 04490 04491 04492 /*********************************************************************************************** 04493 04494 > void SGDisplayGroup::SetChild(SGDisplayNode *NewChild) 04495 04496 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04497 Created: 13/5/95 04498 04499 Inputs: A pointer to the new first-child of this SGDisplayNode object 04500 04501 Purpose: Sets the child of this DisplayTree Node. Overrides to base class method 04502 to allow the child to be set. 04503 04504 SeeAlso: SuperGallery; SGDisplayNode::GetParent; 04505 SGDisplayNode::GetNext; SGDisplayNode::GetPrevious 04506 04507 ***********************************************************************************************/ 04508 04509 void SGDisplayGroup::SetChild(SGDisplayNode *NewChild) 04510 { 04511 Child = NewChild; 04512 } 04513 04514 04515 04516 /*********************************************************************************************** 04517 04518 > virtual BOOL SGDisplayGroup::SetFoldedState(BOOL NewState, BOOL ForceRedraw = TRUE) 04519 04520 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04521 Created: 15/4/95 04522 04523 Inputs: NewState - TRUE to fold, FALSE to unfold 04524 04525 ForceRedraw - TRUE to force a reformat-and-redraw of the group, or FALSE 04526 to mark the tree format invalid but not bother actually reformatting and 04527 redrawing just yet (usually only set to FALSE when constructing the 04528 DisplayTree before the gallery window is opened, for AutoFolding) 04529 04530 Returns: TRUE if the new state is different from the old state (if anything has changed) 04531 04532 Purpose: Folds or unfolds a display group 04533 04534 Notes: If changed, forces an immediate reformat and redraw of the Display list 04535 04536 ***********************************************************************************************/ 04537 04538 BOOL SGDisplayGroup::SetFoldedState(BOOL NewState, BOOL ForceRedraw) 04539 { 04540 if ((BOOL)Flags.Folded != NewState) 04541 { 04542 SuperGallery *ParentGal = GetParentGallery(); 04543 04544 // Devirtualise the group. If there were problems, keep it folded... 04545 if (!NewState && IsVirtualised()) 04546 { 04547 // For library galleries we need to set the Quiet button status ready to un-supress errors 04548 ParentGal->SetQuietStatus(FALSE); 04549 04550 // On older machines this can take a couple of seconds, so we need some feedback... 04551 Progress ProgMsg(_R(IDS_GALLERY_PREPARE_FOR_UNFOLD), -1, FALSE); 04552 04553 if(!DeVirtualise()) 04554 return FALSE; 04555 } 04556 04557 Flags.Folded = NewState; 04558 ChildArea.MakeEmpty(); 04559 04560 ParentGal->InvalidateCachedFormat(); 04561 04562 if (ForceRedraw) 04563 ParentGal->ReformatAndRedrawIfNecessary(); 04564 04565 return(TRUE); 04566 } 04567 04568 return(FALSE); 04569 } 04570 04571 04572 04573 /*********************************************************************************************** 04574 04575 > virtual void SGDisplayGroup::ForceRedrawOfMyselfAndChildren(void) 04576 04577 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04578 Created: 17/1/95 04579 04580 Purpose: Uses the cached FormatRect to force-redraw the appropriate part of the 04581 SuperGallery display window to cause myself to be redrawn. Also redraws 04582 the entire area that my children will occupy, thus redrawing this entire 04583 category. 04584 04585 SeeAlso: SuperGallery::RedrawArea 04586 04587 ***********************************************************************************************/ 04588 04589 void SGDisplayGroup::ForceRedrawOfMyselfAndChildren(void) 04590 { 04591 SuperGallery *ParentGallery = GetParentGallery(); 04592 if (ParentGallery != NULL) 04593 { 04594 DocRect WholeRect(FormatRect); // My own rectangle 04595 04596 if (!Flags.Folded && GetChild() != NULL && !ChildArea.IsEmpty()) 04597 { 04598 // Union with child bounds rect, if any 04599 WholeRect.Union(ChildArea); 04600 } 04601 04602 ParentGallery->ForceRedrawOfArea(&WholeRect); 04603 } 04604 } 04605 04606 04607 04608 /*********************************************************************************************** 04609 04610 > virtual SuperGallery *SGDisplayGroup::GetParentGallery(void) const 04611 04612 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04613 Created: 28/10/94 04614 04615 Returns: The parent SuperGallery, or NULL 04616 04617 Purpose: Returns the SuperGallery which 'owns' this node (and its subtree) 04618 04619 SeeAlso: SGDisplayGroup::GetParentLibrary; SGDisplayGroup::GetParentDocument; 04620 SGDisplayNode::GetParentGallery 04621 04622 ***********************************************************************************************/ 04623 04624 SuperGallery *SGDisplayGroup::GetParentGallery(void) const 04625 { 04626 return(ParentGallery); 04627 } 04628 04629 04630 04631 /*********************************************************************************************** 04632 04633 > virtual SGDisplayItem *SGDisplayGroup::FindNextSelectedItem( 04634 SGDisplayItem *CurrentItem = NULL) 04635 04636 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04637 Created: 18/1/95 04638 04639 Inputs: CurrentItem - NULL to find the first selected item, else 04640 An item indicating the 'position' to search from for the next selected item 04641 04642 Returns: NULL (if no selection), or 04643 A pointer to the first selected child of this node which occurs after 04644 the 'CurrentItem'. If CurrentItem is NULL, then the first selected 04645 child node is returned. 04646 04647 Purpose: Scanning the selection within a Group (document/library). 04648 Use after finding the subtree for a given doc/lib with FindSubtree, to 04649 scan through items in the selection. 04650 04651 SeeAlso: SGDisplayNode::FindSubtree; SGDisplayGroup::GetSelectedItemCount() 04652 04653 ***********************************************************************************************/ 04654 04655 SGDisplayItem *SGDisplayGroup::FindNextSelectedItem(SGDisplayItem *CurrentItem) 04656 { 04657 if (CurrentItem == NULL) 04658 CurrentItem = (SGDisplayItem *) GetChild(); 04659 else 04660 { 04661 if (CurrentItem->GetParent() != this) // Sanity check 04662 { 04663 ERROR3("Asking for next selected when previous was not in this group! Starting from first child"); 04664 CurrentItem = (SGDisplayItem *) GetChild(); 04665 } 04666 else 04667 CurrentItem = (SGDisplayItem *) CurrentItem->GetNext(); 04668 } 04669 04670 while (CurrentItem != NULL && !CurrentItem->IsSelected()) 04671 CurrentItem = (SGDisplayItem *) CurrentItem->GetNext(); 04672 04673 return(CurrentItem); 04674 } 04675 04676 04677 04678 /*********************************************************************************************** 04679 04680 > virtual INT32 SGDisplayGroup::GetSelectedItemCount(void) 04681 04682 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04683 Created: 18/1/95 04684 04685 04686 Returns: The number of items in this group which are selected (may return 0) 04687 04688 Purpose: To determine how many child items of this group are selected 04689 04690 Notes: This scans the selection (is not cached), so calling it multiple times 04691 should be avoided where possible 04692 04693 SeeAlso: SGDisplayNode::FindSubtree; SGDisplayGroup::FindNextSelectedItem 04694 04695 ***********************************************************************************************/ 04696 04697 INT32 SGDisplayGroup::GetSelectedItemCount(void) 04698 { 04699 INT32 Count = 0; 04700 SGDisplayItem *Item = FindNextSelectedItem(NULL); 04701 04702 while (Item != NULL) 04703 { 04704 if (Item->IsSelected()) 04705 Count++; 04706 04707 Item = FindNextSelectedItem(Item); 04708 } 04709 04710 return(Count); 04711 } 04712 04713 04714 04715 /******************************************************************************************** 04716 04717 > virtual void SGDisplayGroup::SelectItems(BOOL SelectThem, BOOL Exclusive = FALSE, 04718 Document *ParentDocument = NULL, Library *ParentLibrary = NULL) 04719 04720 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04721 Created: 20/1/95 04722 04723 Inputs: SelectThem - TRUE to select the given items, FALSE to deselect them 04724 04725 Exclusive - TRUE to apply this action to all items *outside* the given 04726 range, FALSE to apply it to all items *inside* the range. 04727 04728 Document - NULL, or the document which defines the range of items to affect 04729 04730 Library - NULL, or the library which defines the range of items to affect 04731 04732 Purpose: To select/deselect groups of display items in this Gallery display. 04733 Do not call this method - use the SuperGallery version 04734 04735 Notes: To select all items in a range, and deselect all items outside the range, 04736 you need to use 2 calls to this method. 04737 04738 To select/deselect all items in the display, pass FALSE, NULL, NULL to 04739 the last 3 parameters. (If Doc/Lib are both NULL, 'Exclusive' has no effect) 04740 04741 OVERRIDES the base SGDisplayNode method to handle the last 3 paramters 04742 properly. Firstly, groups won't select themselves; secondly, the call is 04743 only passed on to my children if they are in the requested range. 04744 04745 SeeAlso: SuperGallery::SelectItems; SGDisplayNode::SelectItems 04746 04747 ********************************************************************************************/ 04748 04749 void SGDisplayGroup::SelectItems(BOOL SelectThem, BOOL Exclusive, 04750 Document *ParentDoc, Library *ParentLib) 04751 { 04752 BOOL InRange = TRUE; 04753 04754 // If we are selecting items, make sure we (a group) are deselected 04755 if (SelectThem && Flags.CanSelect) 04756 SetSelected(FALSE); 04757 04758 // If anythign other than entire-display-tree was requested, then check if it includes 04759 // our children... 04760 if (ParentDoc != NULL || ParentLib != NULL) 04761 { 04762 // First, do we contain display stuff for the requested Doc/Lib? 04763 InRange = (ParentDocument == ParentDoc) || (ParentLibrary == ParentLib); 04764 04765 // Next, was the range inclusive (everything in doc/lib) or 04766 // exclusive (everything outside doc/lib)? 04767 if (Exclusive) 04768 InRange = !InRange; 04769 } 04770 04771 if (!InRange) // My children are not included in the range specified - return 04772 return; 04773 04774 // Now, pass the selection request on to my children 04775 SGDisplayNode *Ptr = GetChild(); 04776 while (Ptr != NULL) 04777 { 04778 Ptr->SelectItems(SelectThem, Exclusive, ParentDocument, ParentLibrary); 04779 Ptr = Ptr->GetNext(); 04780 } 04781 } 04782 04783 04784 04785 /******************************************************************************************** 04786 04787 > virtual void SGDisplayGroup::SelectGroups(BOOL SelectThem, BOOL Exclusive = FALSE, 04788 Document *ParentDocument = NULL, Library *ParentLibrary = NULL) 04789 04790 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04791 Created: 14/5/95 04792 04793 Inputs: SelectThem - TRUE to select the given groups, FALSE to deselect them 04794 04795 Exclusive - TRUE to apply this action to all groups *outside* the given 04796 range, FALSE to apply it to all groups *inside* the range. 04797 04798 Document - NULL, or the document which defines the range of groups to affect 04799 04800 Library - NULL, or the library which defines the range of groups to affect 04801 04802 Purpose: To select/deselect sets of display groups in this Gallery display. 04803 All groups whose state changes will force redraw themselves 04804 04805 If selecting, all non-group nodes in the tree will be deselected 04806 04807 Do not call this method - use the SuperGallery version 04808 04809 Notes: To select all groups in a range, and deselect all groups outside the range, 04810 you need to use 2 calls to this method. 04811 04812 To select/deselect all groups in the display, pass FALSE, NULL, NULL to 04813 the last 3 parameters. (If Doc/Lib are both NULL, 'Exclusive' has no effect) 04814 04815 SeeAlso: SuperGallery::SelectGroups; SGDisplayGroup::SelectGroups 04816 04817 ********************************************************************************************/ 04818 04819 void SGDisplayGroup::SelectGroups(BOOL SelectThem, BOOL Exclusive, 04820 Document *ParentDoc, Library *ParentLib) 04821 { 04822 BOOL InRange = TRUE; 04823 04824 // If anything other than entire-display-tree was requested, then check if it includes us 04825 if (ParentDoc != NULL || ParentLib != NULL) 04826 { 04827 // First, do we contain display stuff for the requested Doc/Lib? 04828 InRange = (ParentDocument == ParentDoc) || (ParentLibrary == ParentLib); 04829 04830 // Next, was the range inclusive (everything in doc/lib) or 04831 // exclusive (everything outside doc/lib)? 04832 if (Exclusive) 04833 InRange = !InRange; 04834 } 04835 04836 // Select myself if I am withint the specified range 04837 if (InRange && Flags.CanSelect /*&& !Flags.Invisible*/) 04838 SetSelected(SelectThem); 04839 04840 // Now, pass the selection request on to my children, so the items will be 04841 // deselected if necessary 04842 SGDisplayNode *Ptr = GetChild(); 04843 while (Ptr != NULL) 04844 { 04845 Ptr->SelectGroups(SelectThem, Exclusive, ParentDocument, ParentLibrary); 04846 Ptr = Ptr->GetNext(); 04847 } 04848 } 04849 04850 04851 /*********************************************************************************************** 04852 04853 > void SGDisplayGroup::ReadGroupTitle(void) 04854 04855 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04856 Created: 31/10/94 04857 04858 Purpose: Reads the title text for this Group from its parent document/library 04859 This information is cached, but at present it is re-read on each 04860 redraw request to ensure it is kept up to date 04861 04862 ***********************************************************************************************/ 04863 04864 void SGDisplayGroup::ReadGroupTitle(void) 04865 { 04866 // Generate the text to be displayed in this group heading 04867 if (ParentDocument != NULL) 04868 { 04869 String_256 NewTitle; 04870 const String_256 DocTitle = ParentDocument->GetTitle(); 04871 NewTitle.MakeMsg(_R(IDS_GALGROUPDOCUMENT), (const TCHAR *) DocTitle); 04872 04873 // Truncate the name into our 64-char buffer 04874 NewTitle.Left(&TitleText, 63); 04875 } 04876 PORTNOTE("galleries", "disabled folder updated stuff") 04877 #ifndef EXCLUDE_FROM_XARALX 04878 else if (ParentLibrary != NULL) 04879 { 04880 ParentLibrary->GetLibraryTitle(&TitleText); 04881 //>> webster (Adrian 02/01/97) 04882 UINT32 nModified = ParentLibrary->GetModified(); 04883 if (nModified == FOLDER_UPDATED) 04884 { 04885 String_256 strUpdated(_R(IDS_FOLDERUPDATED)); 04886 TitleText += strUpdated; 04887 } 04888 if (nModified == FOLDER_NEW) 04889 { 04890 String_256 strNew(_R(IDS_FOLDERNEW)); 04891 TitleText += _T(" "); 04892 TitleText += strNew; 04893 } 04894 //<< webster 04895 } 04896 #endif 04897 } 04898 04899 04900 04901 /*********************************************************************************************** 04902 04903 > virtual void SGDisplayNode::DragWasReallyAClick(SGMouseInfo *MouseInfo, 04904 SGMiscInfo *MiscInfo) 04905 04906 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04907 Created: 15/3/95 04908 04909 Inputs: MouseInfo - The mouse info passed to the original click handler 04910 MiscInfo - The misc info passed to the original click handler 04911 04912 Purpose: Handles a mouse click event. This is a callback function - drags of 04913 items from galleries will call this function back if the drag turns 04914 out to just be a click. 04915 04916 Notes: SELECTABLE groups override this method to call DefaultClickHandler when 04917 drags on them turn into clicks 04918 04919 Documentation: docs\howtouse\sgallery.doc 04920 04921 SeeAlso: SGDisplayGroup::HandleEvent; SGDisplayNode::DefaultClickHandler 04922 04923 ***********************************************************************************************/ 04924 04925 void SGDisplayGroup::DragWasReallyAClick(SGMouseInfo *MouseInfo, SGMiscInfo *MiscInfo) 04926 { 04927 // Just get default selection action to be applied for this click. 04928 // The TRUE indicates that this is a drag-click, and we previously called 04929 // the DefaultPreDragHandler - we don't want it to do those same actions twice! 04930 04931 // But we only do anything at all if we're a selectable group 04932 if (Flags.CanSelect) 04933 DefaultClickHandler(MouseInfo, MiscInfo, TRUE); 04934 } 04935 04936 04937 04938 /*********************************************************************************************** 04939 04940 > virtual BOOL SGDisplayGroup::HandleEvent(SGEventType EventType, void *EventInfo, 04941 SGMiscInfo *MiscInfo) 04942 04943 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 04944 Created: 20/10/94 04945 04946 Inputs: See SGDisplayNode::HandleEvent 04947 04948 Returns: TRUE if the event was handled successfully 04949 FALSE if it was not 04950 04951 Purpose: Handles a SuperGallery DisplayTree event 04952 04953 Notes: This overrides the pure virtual SGDisplayNode::HandleEvent method 04954 04955 A node need not handle a specific event - if it does not handle it, it 04956 should return FALSE. 04957 04958 Redraw and Formatting handlers should never return TRUE, as this will 04959 prevent the event from continuing through the tree. 04960 04961 Non-leaf-nodes must call SGDisplayNode::GiveEventToMyChildren in order 04962 to pass the event dow the tree. 04963 04964 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayNode::GiveEventToMyChildren 04965 04966 ***********************************************************************************************/ 04967 04968 BOOL SGDisplayGroup::HandleEvent(SGEventType EventType, void *EventInfo, 04969 SGMiscInfo *MiscInfo) 04970 { 04971 TRACEUSER( "Matt", _T("SGDisplayGroup::HandleEvent called\n")); 04972 // And handle the specific event 04973 switch (EventType) 04974 { 04975 case SGEVENT_FORMAT: 04976 { 04977 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 04978 04979 // If we've recently folded or unfolded (ChildArea is Empty) then change the 04980 // format rectangle to ensure everything below this point is redrawn 04981 if (ChildArea.IsEmpty()) 04982 FormatRect = DocRect(0,0,0,0); 04983 04984 if (!Flags.Invisible) 04985 { 04986 CalculateFormatRect(FormatInfo, MiscInfo, DefaultGroupWidth, DefaultGroupHeight); 04987 } 04988 else 04989 { 04990 CalculateFormatRect(FormatInfo, MiscInfo, DefaultGroupWidth, 0); 04991 } 04992 } 04993 break; 04994 04995 case SGEVENT_REDRAW: 04996 { 04997 DocRect MyRect = FormatRect; // Rely on cached format info being correct 04998 04999 SGRedrawInfo *RedrawInfo = GetRedrawInfo(EventType, EventInfo); 05000 05001 if (IMustRedraw(RedrawInfo) && !Flags.Invisible && Flags.CanSelect) 05002 { 05003 StartRendering(RedrawInfo, MiscInfo); 05004 05005 DocColour Col(192, 192, 192); //128, 128, 128); 05006 Col.SetSeparable(FALSE); // Do not colour correct or separate this colour! 05007 05008 RedrawInfo->Renderer->SetLineWidth(0); 05009 RedrawInfo->Renderer->SetLineColour(RedrawInfo->Transparent); 05010 RedrawInfo->Renderer->SetFillColour(Col); 05011 RedrawInfo->Renderer->DrawRect(&MyRect); 05012 05013 ReadGroupTitle(); // (Re)Cache the title text 05014 05015 // Plot the folder glyph (an 18x14 bitmap) 05016 DocRect GlyphRect(MyRect); 05017 GlyphRect.lo.x += DevicePixels(MiscInfo, 2); 05018 GlyphRect.hi.x = GlyphRect.lo.x + DevicePixels(MiscInfo, 18); 05019 05020 // Center the bitmap's 14 pixels of height in our strip 05021 INT32 Excess = GlyphRect.Height() - DevicePixels(MiscInfo, 14); 05022 Excess = GridLock(MiscInfo, Excess / 2); 05023 GlyphRect.lo.y += Excess; 05024 GlyphRect.hi.y = GlyphRect.lo.y + DevicePixels(MiscInfo, 14); 05025 MyRect.lo.x = GlyphRect.hi.x; 05026 05027 #ifdef _DEBUG 05028 if(IsVirtualised()) 05029 { 05030 // in debug builds we get a green rectangle to denote virtualised-ness... 05031 DrawBitmap(RedrawInfo->Renderer, &GlyphRect, 05032 (Flags.Folded) ? _R(IDB_GALLERY_FOLD2) : _R(IDB_GALLERY_FOLD0)); 05033 } else { 05034 DrawBitmap(RedrawInfo->Renderer, &GlyphRect, 05035 (Flags.Folded) ? _R(IDB_GALLERY_FOLD1) : _R(IDB_GALLERY_FOLD0)); 05036 } 05037 #else 05038 DrawBitmap(RedrawInfo->Renderer, &GlyphRect, 05039 (Flags.Folded) ? _R(IDB_GALLERY_FOLD1) : _R(IDB_GALLERY_FOLD0)); 05040 #endif 05041 05042 // Mode selection rectangle one pixel to the right so it looks a bit better 05043 MyRect.lo.x += DevicePixels(MiscInfo, 1); 05044 05045 if (MyRect.lo.x < MyRect.hi.x) // If still room left, draw title 05046 { 05047 // Space between text and glyph 05048 MyRect.lo.x += DevicePixels(MiscInfo, 3); 05049 05050 if (Flags.Selected) 05051 { 05052 // Fill the entire text background with the 'selected' colour 05053 RedrawInfo->Renderer->SetFillColour(RedrawInfo->SelBackground); 05054 RedrawInfo->Renderer->DrawRect(&MyRect); 05055 05056 RedrawInfo->Renderer->SetFixedSystemTextColours(&RedrawInfo->SelForeground, &RedrawInfo->SelBackground); 05057 } 05058 else 05059 RedrawInfo->Renderer->SetFixedSystemTextColours(&RedrawInfo->Foreground, &Col); 05060 05061 // Space between text and glyph 05062 MyRect.lo.x += DevicePixels(MiscInfo, 3); 05063 05064 if (MyRect.lo.x < MyRect.hi.x) // If still room left, draw text 05065 RedrawInfo->Renderer->DrawFixedSystemText(&TitleText, MyRect); 05066 } 05067 05068 StopRendering(RedrawInfo, MiscInfo); 05069 } 05070 05071 // Check if the cliprect overlaps any of our children - if not, then we 05072 // can return now, passing the event on quickly without bothering to give 05073 // it to our children. 05074 05075 if (Flags.Folded || GetChild() == NULL || 05076 !ChildArea.IsIntersectedWith(RedrawInfo->Bounds)) 05077 { 05078 return(FALSE); 05079 } 05080 } 05081 break; 05082 05083 05084 case SGEVENT_MOUSECLICK: 05085 { 05086 if (!Flags.Invisible) 05087 { 05088 SGMouseInfo *Mouse = GetMouseInfo(EventType, EventInfo); 05089 05090 // If the click hit us, we will always claim it to save the event going 05091 // on through the tree unnecessarily 05092 if (FormatRect.ContainsCoord(Mouse->Position)) 05093 { 05094 DocRect FolderRect(FormatRect); 05095 FolderRect.hi.x = FolderRect.lo.x + DevicePixels(MiscInfo, 24); 05096 05097 // Single clicks on the folder icon will fold/unfold the category 05098 if (FolderRect.ContainsCoord(Mouse->Position)) 05099 { 05100 if (!Mouse->DoubleClick) // We ignore double-clicks, though 05101 { 05102 // Toggle the folded state of this group and force a redraw 05103 SetFoldedState((Flags.Folded) ? FALSE : TRUE); 05104 } 05105 } 05106 else 05107 { 05108 if (Mouse->DoubleClick) // It was a double-click, so {un}fold instead 05109 { 05110 // Toggle the folded state of this group and force a redraw 05111 SetFoldedState((Flags.Folded) ? FALSE : TRUE); 05112 } 05113 else 05114 { 05115 // Not a click on the folder or a general double-click, so assume it's a 05116 // drag of the group 05117 // This starts the drag. We will be called back, either with: 05118 // a) SGDisplayNode::DragWasReallyAClick(), or 05119 // b) Some variant of MoveBefore, MoveAfter, or AddItem 05120 // (possibly via SuperGallery::CopyItem) to rearrange this 05121 // item in the tree 05122 05123 if (Flags.CanSelect) 05124 DefaultPreDragHandler(Mouse, MiscInfo); 05125 05126 SGListDragInfo *DragGroup; 05127 DragGroup = new SGListDragInfo(GetParentGallery(), this, 05128 Mouse, Mouse->MenuClick); 05129 if (DragGroup != NULL) 05130 DragManagerOp::StartDrag(DragGroup, GetListWindow()); 05131 // The DragWasReallyAClick handler will take care of clicks 05132 } 05133 } 05134 05135 // Claim this event - nobody else can own this click 05136 return(TRUE); 05137 } 05138 05139 // Next, if the click cannot hit any of our children, pass the event on 05140 // without passing it to any of the children, to save time 05141 if (Flags.Folded || GetChild() == NULL || 05142 !ChildArea.ContainsCoord(Mouse->Position)) 05143 { 05144 return(FALSE); 05145 } 05146 } 05147 } 05148 break; 05149 05150 05151 case SGEVENT_CLAIMPOINT: 05152 { 05153 if (!Flags.Invisible) 05154 { 05155 SGClaimPointInfo *PointInfo = GetClaimPointInfo(EventType, EventInfo); 05156 05157 // If the point hit us, we must claim the event so that the caller 05158 // knows which tree item contains the point. 05159 if (FormatRect.ContainsCoord(PointInfo->Position)) 05160 { 05161 PointInfo->ClosestSoFar = 0; 05162 PointInfo->Claimant = this; // Let 'em know it was me! 05163 return(TRUE); 05164 } 05165 05166 // OK, we don't OWN the point, but are we closer to it than anyone else 05167 // checked so far? If so, we update ClosestSoFar and Claimant, but we 05168 // do not claim the event (so others can check if they are closer) 05169 05170 // Find the distance to the 2 closest edges of the rectangle. Then 05171 // the approx. distance to the rectangle is the larger of the two. 05172 INT32 XDist = 0; 05173 if (FormatRect.lo.x > PointInfo->Position.x) 05174 XDist = FormatRect.lo.x - PointInfo->Position.x; 05175 else if (FormatRect.hi.x < PointInfo->Position.x) 05176 XDist = PointInfo->Position.x - FormatRect.lo.x; 05177 05178 INT32 YDist = 0; 05179 if (FormatRect.lo.y > PointInfo->Position.y) 05180 YDist = FormatRect.lo.y - PointInfo->Position.y; 05181 else if (FormatRect.hi.y < PointInfo->Position.y) 05182 YDist = PointInfo->Position.y - FormatRect.lo.y; 05183 05184 XDist = max(XDist, YDist); // XDist is now approx the dist to the point 05185 05186 if (XDist < PointInfo->ClosestSoFar) 05187 { 05188 PointInfo->Claimant = this; 05189 PointInfo->ClosestSoFar = XDist; 05190 // drop through to pass the event on... 05191 } 05192 05193 // Next, if the point cannot hit any of our children, pass the event on 05194 // without passing it to any of the children, to save time 05195 if (Flags.Folded || GetChild() == NULL || 05196 !ChildArea.ContainsCoord(PointInfo->Position)) 05197 { 05198 return(FALSE); 05199 } 05200 } 05201 } 05202 break; 05203 05204 default: 05205 return(SGDisplayNode::HandleEvent(EventType, EventInfo, MiscInfo)); 05206 } 05207 05208 // Pass the event on to my children, as appropriate (but not if it's a thumbmsg) 05209 BOOL Result = GiveEventToMyChildren(EventType, EventInfo, MiscInfo); 05210 05211 if (EventType == SGEVENT_FORMAT) 05212 { 05213 SGFormatInfo *FormatInfo = GetFormatInfo(EventType, EventInfo); 05214 05215 // After they have formatted themselves, calculate the area they fill, so we can 05216 // quickly determine if events (clicks/redraws) fall over any of our children. 05217 ChildArea = FormatRect; // We are 'infinite' width, so copy our rect to get width 05218 // and the top of the rectangle. 05219 05220 // And then move the bottom down to include my children, and not myself 05221 ChildArea.hi.y = ChildArea.lo.y; 05222 ChildArea.lo.y = FormatInfo->LinePos; 05223 } 05224 05225 // And return... 05226 return(Result); 05227 } 05228 05229 05230 05231 /*********************************************************************************************** 05232 05233 > void SGDisplayGroup::GetChildArea(DocRect *Result) 05234 05235 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05236 Created: 13/5/95 05237 05238 Outputs: Result - Filled in with a rectangle (may be 'Empty') 05239 05240 Purpose: Retrieves the display list rectangle of this group's children. This is a 05241 bounding rectangle which entirely contains the children of this group. 05242 05243 Notes: This rectangle may be Empty (if the group is folded, or if it has not 05244 yet been reformatted after being unfolded) 05245 05246 The rectangle does NOT include the group's ("titlebar") FormatRect - to 05247 include the group title and all children, you must union with FormatRect 05248 05249 ***********************************************************************************************/ 05250 05251 void SGDisplayGroup::GetChildArea(DocRect *Result) 05252 { 05253 ERROR3IF(Result == NULL, "Illegal NULL param"); 05254 05255 *Result = ChildArea; 05256 } 05257 05258 05259 /*********************************************************************************************** 05260 05261 > virtual BOOL SGDisplayGroup::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 05262 05263 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05264 Created: 16/4/95 05265 05266 Inputs: Mouse - Information on the mouse state for this click 05267 MiscInfo - the normal info as passed to event handlers 05268 05269 Returns: TRUE if the click caused any action to be taken (selection state to change) 05270 FALSE if the click was ignored for whatever reason 05271 05272 Purpose: Provides part 1 of the default selection model for clicks on gallery display 05273 items. Should be called by all derived gallery DisplayItems to handle clicks 05274 upon them, when multiple-selection support is desired. 05275 05276 You should call this method immediately prior to starting a drag as a result 05277 of a click event. Note that it is paired with DefaultClickHandler (which 05278 should be called when the drag you start turns out to be a click, if you 05279 want multiple-selection capability). 05280 05281 See the SGDisplayColour (kernel\sgcolour.cpp) for an example of use 05282 05283 Notes: The code for this has now been moved into the SGDisplayNode base class since 05284 group selection is now also required. 05285 05286 SeeAlso: SGDisplayItem::DefaultClickHandler; SGDisplayColour::HandleEvent 05287 05288 ***********************************************************************************************/ 05289 05290 BOOL SGDisplayGroup::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 05291 { 05292 return(SGDisplayNode::DefaultPreDragHandler(Mouse, MiscInfo)); 05293 } 05294 05295 05296 05297 /*********************************************************************************************** 05298 05299 > virtual BOOL SGDisplayGroup::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 05300 BOOL AfterDrag = FALSE) 05301 05302 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05303 Created: 9/2/94 05304 05305 Inputs: Mouse - Information on the mouse state for this click 05306 MiscInfo - the normal info as passed to event handlers 05307 AfterDrag - TRUE if this is being called when a drag turns into a click, and 05308 you called DefaultPreDragHandler before the drag started 05309 05310 Returns: TRUE if the click caused any action to be taken (selection state to change) 05311 FALSE if the click was ignored for whatever reason 05312 05313 Purpose: Provides the default selection model for clicks on gallery display items. 05314 Should be called by all derived gallery DisplayItems to handle clicks 05315 upon them, when multiple-selection support is desired. 05316 05317 Notes: The code for this has now been moved into the SGDisplayNode base class since 05318 group selection is now also required. 05319 05320 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 05321 05322 ***********************************************************************************************/ 05323 05324 BOOL SGDisplayGroup::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 05325 BOOL AfterDrag) 05326 { 05327 return(SGDisplayNode::DefaultClickHandler(Mouse, MiscInfo, AfterDrag)); 05328 } 05329 05330 05331 /******************************************************************************************** 05332 05333 > virtual BOOL SGDisplayGroup::CanVirtualise(void); 05334 05335 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 05336 Created: 4/1/95 05337 05338 Returns: TRUE if it can 05339 05340 Purpose: Most groups shouldn't need to be virtualised out. Really it's just library 05341 groups - SGLibGroup - that should be. 05342 05343 ********************************************************************************************/ 05344 05345 BOOL SGDisplayGroup::CanVirtualise(void) 05346 { 05347 return FALSE; 05348 } 05349 05350 /******************************************************************************************** 05351 05352 > virtual BOOL SGDisplayGroup::Virtualise(void); 05353 05354 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 05355 Created: 4/1/95 05356 05357 Returns: TRUE if it virtualised out OK (or already was) 05358 05359 Purpose: Virtualise a group out of memory, or rather, vape the items and entire tree 05360 associcated with the group, leaving a memory-minimal shell. 05361 05362 ********************************************************************************************/ 05363 05364 BOOL SGDisplayGroup::Virtualise(void) 05365 { 05366 // Group is already virtualised 05367 if(IsVirtualised()) 05368 return TRUE; 05369 05370 PORTNOTE("galleries", "Disabled virtualising switch") 05371 #ifndef EXCLUDE_FROM_XARALX 05372 // Virtualisation disabled... 05373 if(!SGLibGroup::LibraryVirtualisingEnabled) 05374 return FALSE; 05375 #endif 05376 05377 DestroySubtree(FALSE); // Delete all items in the group (but not this one obviously) 05378 SetVirtualisedState(TRUE); 05379 05380 #ifdef _DEBUG 05381 ForceRedrawOfMyselfAndChildren(); 05382 #endif 05383 05384 return TRUE; 05385 } 05386 05387 /******************************************************************************************** 05388 05389 > virtual BOOL SGDisplayGroup::DeVirtualise(void); 05390 05391 Author: Richard_Millican (Xara Group Ltd) <camelotdev@xara.com> 05392 Created: 4/1/95 05393 05394 Returns: TRUE if it devirtualised back in OK (or already had) 05395 05396 Purpose: Virtualise a group back into memory, or rather, add the items associated with 05397 the group to the group so we can display them, etc. 05398 05399 ********************************************************************************************/ 05400 05401 BOOL SGDisplayGroup::DeVirtualise(void) 05402 { 05403 if(!IsVirtualised()) 05404 return TRUE; 05405 05406 #ifdef _DEBUG 05407 ForceRedrawOfMyselfAndChildren(); 05408 #endif 05409 05410 // Might need some help with this one - override and implement 05411 05412 return FALSE; 05413 } 05414 05415 05416 05417 05418 05419 05420 05421 05422 05423 /*********************************************************************************************** 05424 05425 > SGDisplayItem::SGDisplayItem() 05426 05427 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05428 Created: 13/5/95 05429 05430 Purpose: DisplayItem constructor 05431 05432 ***********************************************************************************************/ 05433 05434 SGDisplayItem::SGDisplayItem() 05435 { 05436 // Items can be selected 05437 Flags.CanSelect = TRUE; 05438 } 05439 05440 05441 05442 /*********************************************************************************************** 05443 05444 > virtual BOOL SGDisplayItem::HandleEvent(SGEventType EventType, void *EventInfo, 05445 SGMiscInfo *MiscInfo) 05446 05447 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05448 Created: 20/10/94 05449 05450 Inputs: See SGDisplayNode::HandleEvent 05451 05452 Returns: TRUE if the event was handled successfully 05453 FALSE if it was not 05454 05455 Purpose: Handles a SuperGallery DisplayTree event 05456 05457 Notes: This overrides the pure virtual SGDisplayNode::HandleEvent method 05458 05459 A node need not handle a specific event - if it does not handle it, it 05460 should return FALSE. 05461 05462 Redraw and Formatting handlers should never return TRUE, as this will 05463 prevent the event from continuing through the tree. 05464 05465 ClaimPoint handlers should always return FALSE, unless they contain 05466 the given point, in which case they should return TRUE. 05467 05468 Non-leaf-nodes must call SGDisplayNode::GiveEventToMyChildren in order 05469 to pass the event dow the tree. THIS node is a leaf-node, so it doesn't. 05470 05471 Derived DisplayItem classes should call this base class method if they 05472 wish to handle CLAIMPOINT broadcasts to provide drag-target detection. 05473 05474 SeeAlso: SGDisplayNode::HandleEvent; SGDisplayRoot::HandleEvent; 05475 SGDisplayGroup::HandleEvent 05476 05477 ***********************************************************************************************/ 05478 05479 BOOL SGDisplayItem::HandleEvent(SGEventType EventType, void *EventInfo, 05480 SGMiscInfo *MiscInfo) 05481 { 05482 switch(EventType) 05483 { 05484 case SGEVENT_CLAIMPOINT: 05485 { 05486 SGClaimPointInfo *PointInfo = GetClaimPointInfo(EventType, EventInfo); 05487 05488 // If the point hit us, we must claim the event so that the caller 05489 // knows which tree item contains the point. 05490 if (FormatRect.ContainsCoord(PointInfo->Position)) 05491 { 05492 PointInfo->ClosestSoFar = 0; 05493 PointInfo->Claimant = this; // Let 'em know it was me! 05494 return(TRUE); 05495 } 05496 05497 // OK, we don't OWN the point, but are we closer to it than anyone else 05498 // checked so far? If so, we update ClosestSoFar and Claimant, but we 05499 // do not claim the event (so others can check if they are closer) 05500 05501 // Find the distance to the 2 closest edges of the rectangle. Then 05502 // the approx. distance to the rectangle is the larger of the two. 05503 INT32 XDist = 0; 05504 if (FormatRect.lo.x > PointInfo->Position.x) 05505 XDist = FormatRect.lo.x - PointInfo->Position.x; 05506 else if (FormatRect.hi.x < PointInfo->Position.x) 05507 XDist = PointInfo->Position.x - FormatRect.lo.x; 05508 05509 INT32 YDist = 0; 05510 if (FormatRect.lo.y > PointInfo->Position.y) 05511 YDist = FormatRect.lo.y - PointInfo->Position.y; 05512 else if (FormatRect.hi.y < PointInfo->Position.y) 05513 YDist = PointInfo->Position.y - FormatRect.lo.y; 05514 05515 XDist = max(XDist, YDist); // XDist is now approx the dist to the point 05516 05517 if (XDist < PointInfo->ClosestSoFar) 05518 { 05519 PointInfo->Claimant = this; 05520 PointInfo->ClosestSoFar = XDist; 05521 // drop through to pass the event on... 05522 } 05523 } 05524 break; 05525 05526 05527 default: 05528 return(SGDisplayNode::HandleEvent(EventType, EventInfo, MiscInfo)); 05529 } 05530 05531 return(FALSE); 05532 } 05533 05534 05535 05536 /*********************************************************************************************** 05537 05538 > virtual void SGDisplayItem::AddItem(SGDisplayNode *NodeToInsert, 05539 SGSortKey *SortInfo = NULL) 05540 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05541 Created: 20/10/94 05542 05543 Inputs: NodeToInsert - the node/subtree to be inserted 05544 SortInfo - NULL, or an array of MaxSGSortKeys sort key structures, which 05545 describes the sort mode to be used for determining the position of the 05546 insertion. 05547 05548 Purpose: OVERRIDES the DisplayNode action, and gives an ERROR3 - 05549 DisplayItems are only allowed to be leaf-nodes, and hence you cannot 05550 insert items as children of them. 05551 05552 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 05553 05554 ***********************************************************************************************/ 05555 05556 void SGDisplayItem::AddItem(SGDisplayNode *NodeToInsert, SGSortKey *SortInfo) 05557 { 05558 ERROR3("You can't SGDisplayItem::AddItem() - DisplayItems are supposed to be leaf nodes"); 05559 } 05560 05561 05562 05563 /*********************************************************************************************** 05564 05565 > virtual void SGDisplayItem::RemoveFromTree(void) 05566 05567 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05568 Created: 10/2/95 05569 05570 Purpose: De-links this node/subtree from the DisplayTree. This DOES NOT DELETE the node, 05571 just unlinks it in preparation for being deleted. 05572 05573 Notes: This method calls SGDisplayNode::RemoveFromTree to do all the work. 05574 It is overridden simply so that display items can deselect themselves and 05575 inform the parent gallery if they were the selected node, so that pointers 05576 to removed nodes are not kept lying around. 05577 05578 SeeAlso: SGDisplayNode::RemoveFromTree 05579 05580 ***********************************************************************************************/ 05581 05582 void SGDisplayItem::RemoveFromTree(void) 05583 { 05584 // SetSelected(FALSE); 05585 SGDisplayNode::RemoveFromTree(); 05586 } 05587 05588 05589 05590 /*********************************************************************************************** 05591 05592 > virtual BOOL SGDisplayItem::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 05593 05594 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05595 Created: 16/4/95 05596 05597 Inputs: Mouse - Information on the mouse state for this click 05598 MiscInfo - the normal info as passed to event handlers 05599 05600 Returns: TRUE if the click caused any action to be taken (selection state to change) 05601 FALSE if the click was ignored for whatever reason 05602 05603 Purpose: Provides part 1 of the default selection model for clicks on gallery display 05604 items. Should be called by all derived gallery DisplayItems to handle clicks 05605 upon them, when multiple-selection support is desired. 05606 05607 You should call this method immediately prior to starting a drag as a result 05608 of a click event. Note that it is paired with DefaultClickHandler (which 05609 should be called when the drag you start turns out to be a click, if you 05610 want multiple-selection capability). 05611 05612 See the SGDisplayColour (kernel\sgcolour.cpp) for an example of use 05613 05614 Notes: The code for this has now been moved into the SGDisplayNode base class since 05615 group selection is now also required. 05616 05617 SeeAlso: SGDisplayItem::DefaultClickHandler; SGDisplayColour::HandleEvent 05618 05619 ***********************************************************************************************/ 05620 05621 BOOL SGDisplayItem::DefaultPreDragHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo) 05622 { 05623 return(SGDisplayNode::DefaultPreDragHandler(Mouse, MiscInfo)); 05624 } 05625 05626 05627 05628 /*********************************************************************************************** 05629 05630 > virtual BOOL SGDisplayItem::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 05631 BOOL AfterDrag = FALSE, 05632 BOOL AdjustDoubleClick = TRUE) 05633 05634 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 05635 Created: 9/2/94 05636 05637 Inputs: Mouse - Information on the mouse state for this click 05638 MiscInfo - the normal info as passed to event handlers 05639 AfterDrag - TRUE if this is being called when a drag turns into a click, and 05640 you called DefaultPreDragHandler before the drag started 05641 05642 AdjustDoubleClick - Override for derived classes to enable/disable the 05643 default adjust-double-click action (which closes the gallery after apply). 05644 The colour gallery has a special meaning for adjust-double-click, so overrides 05645 this variable to pass in FALSE and disable default action. 05646 05647 Returns: TRUE if the click caused any action to be taken (selection state to change) 05648 FALSE if the click was ignored for whatever reason 05649 05650 Purpose: Provides the default selection model for clicks on gallery display items. 05651 Should be called by all derived gallery DisplayItems to handle clicks 05652 upon them, when multiple-selection support is desired. 05653 05654 Notes: The code for this has now been moved into the SGDisplayNode base class since 05655 group selection is now also required. 05656 05657 SeeAlso: SuperGallery; SGDisplayNode::InsertAfter; SGDisplayNode::InsertBefore 05658 05659 ***********************************************************************************************/ 05660 05661 BOOL SGDisplayItem::DefaultClickHandler(SGMouseInfo *Mouse, SGMiscInfo *MiscInfo, 05662 BOOL AfterDrag, BOOL AdjustDoubleClick) 05663 { 05664 return(SGDisplayNode::DefaultClickHandler(Mouse, MiscInfo, AfterDrag, AdjustDoubleClick)); 05665 } 05666 05667