00001 // $Id: nodeshap.cpp 1361 2006-06-25 16:43:38Z 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 // NodeSimpleShape class. This provides a base class for all simple primitve shapes 00099 // eg, Rectangles and Ellipses. 00100 00101 /* 00102 */ 00103 00104 00105 #include "camtypes.h" 00106 #include "nodeshap.h" 00107 //#include "osrndrgn.h" 00108 #include "nodepath.h" 00109 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 #include "snap.h" 00112 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "blobs.h" 00114 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 #include "extender.h" 00116 00117 #include "ophist.h" 00118 00119 // Put my version Number into the About box 00120 DECLARE_SOURCE( "$Revision: 1361 $" ); 00121 00122 00123 CC_IMPLEMENT_DYNCREATE(NodeSimpleShape, NodeRenderableInk) 00124 00125 // Declare smart memory handling in Debug builds 00126 #define new CAM_DEBUG_NEW 00127 00128 00129 00130 /*********************************************************************************************** 00131 00132 > NodeSimpleShape::NodeSimpleShape(Node* ContextNode, 00133 AttachNodeDirection Direction, 00134 const DocRect& BoundingRect, 00135 BOOL Locked = FALSE, 00136 BOOL Mangled = FALSE, 00137 BOOL Marked = FALSE, 00138 BOOL Selected = FALSE, 00139 BOOL Renderable = FALSE 00140 ) 00141 00142 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00143 Created: 22/9/93 00144 00145 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00146 MonoOn Direction: MonoOff 00147 Specifies the direction in which the node is to be attached to the 00148 ContextNode. The values this variable can take are as follows: 00149 00150 PREV : Attach node as a previous sibling of the context node 00151 NEXT : Attach node as a next sibling of the context node 00152 FIRSTCHILD: Attach node as the first child of the context node 00153 LASTCHILD : Attach node as a last child of the context node 00154 00155 BoundingRect: Bounding rectangle 00156 00157 The remaining inputs specify the status of the node: 00158 00159 Locked: Is node locked ? 00160 Mangled: Is node mangled ? 00161 Marked: Is node marked ? 00162 Selected: Is node selected ? 00163 00164 Purpose: This constructor initialises the nodes flags and links it to ContextNode in the 00165 direction specified by Direction. All neccesary tree links are updated. 00166 Note: SetUpPath() must be called before the NodeSimpleShape is in a state in which it can be used. 00167 00168 SeeAlso: SetUpPath 00169 Errors: An assertion error will occur if ContextNode is NULL 00170 00171 ***********************************************************************************************/ 00172 00173 NodeSimpleShape::NodeSimpleShape(Node* ContextNode, 00174 AttachNodeDirection Direction, 00175 BOOL Locked, 00176 BOOL Mangled, 00177 BOOL Marked, 00178 BOOL Selected 00179 ):NodeRenderableInk(ContextNode, Direction, Locked, Mangled, Marked, Selected ) 00180 { 00181 } 00182 00183 /********************************************************************************************* 00184 00185 > NodeSimpleShape::NodeSimpleShape() 00186 00187 Author: Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com> 00188 Created: 22/9/93 00189 Purpose: This constructor creates a NodeSimpleShape linked to no other with all status 00190 flags false and an uninitialized bounding rectangle. 00191 Note: SetUpPath() must be called before the NodeSimpleShape is in a state in which it can be 00192 used. 00193 SeeAlso: SetUpPath 00194 00195 **********************************************************************************************/ 00196 /* Technical Notes: 00197 The default constructor is required so that SimpleCopy will work 00198 */ 00199 00200 NodeSimpleShape::NodeSimpleShape(): NodeRenderableInk() 00201 { 00202 } 00203 00204 /*********************************************************************************************** 00205 00206 > virtual Node* NodeSimpleShape::SimpleCopy() 00207 00208 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00209 Created: 26/5/93 00210 Returns: Pointer to a Node 00211 Purpose: Makes a copy of all the data in the node 00212 00213 ***********************************************************************************************/ 00214 00215 Node* NodeSimpleShape::SimpleCopy() 00216 { 00217 // Make a new NodeSimpleShape and then copy things into it 00218 TRACE( _T("NodeSimpleShape::SimpleCopy() - Should not be called\n")); 00219 NodeSimpleShape* NodeCopy = new NodeSimpleShape(); 00220 if (NodeCopy) 00221 CopyNodeContents(NodeCopy); 00222 00223 return NodeCopy; 00224 } 00225 00226 00227 /*********************************************************************************************** 00228 00229 > void NodeSimpleShape::CopyNodeContents(NodeSimpleShape* NodeCopy) 00230 00231 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00232 Created: 26/5/93 00233 Inputs: NodeCopy - The node to copy 00234 Purpose: Copies the data in the node by first calling the base class to get it to 00235 copy its stuff, and then copying its own stuff 00236 Scope: protected 00237 SeeAlso: NodeRenderableInk::CopyNodeContents 00238 00239 ***********************************************************************************************/ 00240 00241 void NodeSimpleShape::CopyNodeContents(NodeSimpleShape* NodeCopy) 00242 { 00243 NodeRenderableInk::CopyNodeContents(NodeCopy); 00244 00245 //Copy contents specific to derived class here 00246 if (NodeCopy->InkPath.Initialise(InkPath.GetNumCoords(),12)) 00247 { 00248 // Copy the path data 00249 NodeCopy->InkPath.CopyPathDataFrom(&InkPath); 00250 00251 // copy the parralleogram data 00252 NodeCopy->Parallel[0] = Parallel[0]; 00253 NodeCopy->Parallel[1] = Parallel[1]; 00254 NodeCopy->Parallel[2] = Parallel[2]; 00255 NodeCopy->Parallel[3] = Parallel[3]; 00256 } 00257 } 00258 00259 00260 00261 /*********************************************************************************************** 00262 > void NodeSimpleShape::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00263 00264 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00265 Created: 18/12/2003 00266 Outputs: - 00267 Purpose: Polymorphically copies the contents of this node to another 00268 Errors: An assertion failure will occur if NodeCopy is NULL 00269 Scope: protected 00270 00271 ***********************************************************************************************/ 00272 00273 void NodeSimpleShape::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 00274 { 00275 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 00276 ENSURE(IS_A(pNodeCopy, NodeSimpleShape), "PolyCopyNodeContents given wrong dest node type"); 00277 00278 if (IS_A(pNodeCopy, NodeSimpleShape)) 00279 CopyNodeContents((NodeSimpleShape*)pNodeCopy); 00280 } 00281 00282 00283 00284 /*********************************************************************************************** 00285 00286 > void NodeSimpleShape::ShowDebugTreeDetails() const 00287 00288 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00289 Created: 26/5/93 00290 Purpose: Displays debugging info of the tree 00291 SeeAlso: NodeRenderableInk::ShowDebugTreeDetails 00292 00293 ***********************************************************************************************/ 00294 #ifdef _DEBUG 00295 void NodeSimpleShape::ShowDebugTreeDetails() const 00296 { 00297 TRACE( _T("SimpleShape ")); 00298 // Display a bit of debugging info 00299 // For now, we will just call the base class version 00300 NodeRenderableInk::ShowDebugTreeDetails(); 00301 } 00302 #endif 00303 00304 /******************************************************************************************** 00305 00306 > void NodeSimpleShape::GetDebugDetails( StringBase* Str ) 00307 00308 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00309 Created: 21/9/93 00310 Outputs: Str: String giving debug info about the node 00311 Purpose: For obtaining debug information about the Node 00312 00313 ********************************************************************************************/ 00314 00315 void NodeSimpleShape::GetDebugDetails( StringBase* Str ) 00316 { 00317 #ifdef _DEBUG 00318 // Call base class 00319 NodeRenderableInk::GetDebugDetails( Str ); 00320 00321 InkPath.FindStartOfPath(); 00322 String_256 TempStr; 00323 00324 (*Str) += TEXT( "\r\nEllipse Path Data Dump\r\n" ); 00325 00326 TempStr._MakeMsg( TEXT( "Parallelogram :-\r\n\t#1%ld,\t#2%ld\r\n") 00327 TEXT("\t#3%ld,\t#4%ld\r\n") 00328 TEXT("\t#5%ld,\t#6%ld\r\n") 00329 TEXT("\t#7%ld,\t#8%ld\r\n"), 00330 Parallel[0].x, Parallel[0].y, 00331 Parallel[1].x, Parallel[1].y, 00332 Parallel[2].x, Parallel[2].y, 00333 Parallel[3].x, Parallel[3].y ); 00334 (*Str) += TempStr; 00335 00336 DocRect BlobRect = GetBlobBoundingRect(); 00337 TempStr._MakeMsg( TEXT("Blob Bounding Rect :-\r\n\t#1%ld,\t#2%ld\r\n\t#3%ld,\t#4%ld\r\n"), 00338 BlobRect.lo.x, BlobRect.lo.y, BlobRect.hi.x, BlobRect.hi.y ); 00339 (*Str) += TempStr; 00340 00341 if ( InkPath.IsFilled ) 00342 (*Str) += TEXT( "The Path is Filled\r\n" ); 00343 00344 (*Str) += TEXT( "\r\nNum\tType\tX Coord\tY Coord\r\n" ); 00345 PathVerb* Verbs = InkPath.GetVerbArray(); 00346 DocCoord* Coords = InkPath.GetCoordArray(); 00347 // PathFlags* Flags = InkPath.GetFlagArray(); 00348 for (INT32 i=0; i<InkPath.GetNumCoords(); i++) 00349 { 00350 // Add the info to the string 00351 TempStr._MakeMsg( TEXT("#1%d.\t#2%d\t#3%ld,\t#4%ld\r\n"), 00352 i, Verbs[i], Coords[i].x, Coords[i].y ); 00353 (*Str) += TempStr; 00354 } 00355 #endif 00356 } 00357 00358 00359 00360 /*********************************************************************************************** 00361 00362 > BOOL NodeSimpleShape::SetUpPath(INT32 RequiredSize=12, INT32 BlockSize=12) 00363 00364 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00365 Created: 04/5/93 00366 Inputs: RequiredSize - The size of the initial block of memory to be allocated to the 00367 path. 00368 BlockSize - The size of the block asked for by the path object when it 00369 runs out of space. 00370 Returns: TRUE if the path was init'ed ok, FALSE otherwise 00371 Purpose: To initialise the path used by the shape into a state that can be used, 00372 by allocating memory, setting up member variables properly. 00373 00374 ***********************************************************************************************/ 00375 00376 BOOL NodeSimpleShape::SetUpPath(INT32 RequiredSize, INT32 BlockSize) 00377 { 00378 return (InkPath.Initialise(RequiredSize, BlockSize)); 00379 } 00380 00381 00382 00383 /******************************************************************************************** 00384 00385 > virtual void NodeSimpleShape::Transform( TransformBase& Trans ) 00386 00387 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00388 Created: 20/10/93 00389 Inputs: Trans - The transform Object 00390 Purpose: Transforms the shapes parallelogram and then re-builds the shape to fit it. 00391 SeeAlso: NodeRenderableInk::Transform() 00392 00393 ********************************************************************************************/ 00394 00395 void NodeSimpleShape::Transform( TransformBase& Trans ) 00396 { 00397 // Transform the Shape 00398 Trans.Transform((DocCoord*)Parallel, 4); 00399 00400 // re-create the path and update its bounding rectangle 00401 UpdateShape(); 00402 00403 // Mark the bounding rect as invalid 00404 InvalidateBoundingRect(); 00405 00406 // Transform all the children... 00407 TransformChildren(Trans); 00408 } 00409 00410 00411 00412 00413 /*********************************************************************************************** 00414 00415 > void NodeSimpleShape::CreateShape(DocRect ARect) 00416 00417 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00418 Created: 22/9/93 00419 Inputs: DocRect - representing the rectangle to be created. 00420 Purpose: Should create a the shape to fit the current parallelogram. This version does 00421 nothing as there should always be a derived class version. 00422 00423 ***********************************************************************************************/ 00424 00425 void NodeSimpleShape::CreateShape(DocRect NewRect) 00426 { 00427 // You are not supposed to be calling this. You should have called a 00428 // derived classes version of this function 00429 ENSURE(FALSE, "NodeSimpleShape::CreateShape - You called the base class version"); 00430 } 00431 00432 /*********************************************************************************************** 00433 00434 > void NodeSimpleShape::UpdateShape(DocRect ARect) 00435 00436 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00437 Created: 22/9/93 00438 Inputs: DocRect - representing the rectangle to be created. 00439 Purpose: Should update the the shape to the current parallelogram. This version does 00440 nothing as there should always be a derived class version. 00441 00442 ***********************************************************************************************/ 00443 00444 void NodeSimpleShape::UpdateShape() 00445 { 00446 // You are not supposed to be calling this. You should have called a 00447 // derived classes version of this function 00448 ENSURE(FALSE, "NodeSimpleShape::UpdateShape - You called the base class version"); 00449 } 00450 00451 00452 00453 00454 /*********************************************************************************************** 00455 00456 > void NodeSimpleShape::Render(RenderRegion* pRender) 00457 00458 Author: Jim_Lynn (Xara Group Ltd) <camelotdev@xara.com> 00459 Created: 31/5/93 00460 Inputs: Pointer to a render region 00461 Purpose: Will render the path contained within the object to the given render region 00462 00463 ***********************************************************************************************/ 00464 00465 void NodeSimpleShape::Render(RenderRegion* pRender) 00466 { 00467 // render the path 00468 pRender->DrawPath(&InkPath); 00469 } 00470 00471 00472 00473 /******************************************************************************************** 00474 00475 > void NodeSimpleShape::RenderEorDrag( RenderRegion* pRender ) 00476 00477 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00478 Created: 22/10/93 00479 Inputs: pRender - A Pointer to the current RenderRegion 00480 Purpose: Renders a version of the path for EORed dragging of shapes. 00481 SeeAlso: NodePath::Render; NodeRenderableInk::RenderEorDrag 00482 00483 ********************************************************************************************/ 00484 00485 void NodeSimpleShape::RenderEorDrag( RenderRegion* pRender ) 00486 { 00487 // Render an EORed version of the shape. For a simple object such 00488 // as this we can render it as normal 00489 pRender->DrawPath(&InkPath); 00490 } 00491 00492 00493 00494 00495 /******************************************************************************************** 00496 00497 > void NodeSimpleShape::RenderObjectBlobs(RenderRegion* pRender) 00498 00499 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00500 Created: 23/6/94 00501 Inputs: pRender - the region to render the blobs to 00502 Purpose: Renders the Object blobs for a Node Shape 00503 SeeAlso: BlobManager 00504 00505 ********************************************************************************************/ 00506 00507 void NodeSimpleShape::RenderObjectBlobs(RenderRegion* pRender) 00508 { 00509 #if !defined(EXCLUDE_FROM_RALPH) 00510 // Set the line colours etc as we need them 00511 pRender->SetLineColour(COLOUR_NONE); 00512 pRender->SetFillColour(COLOUR_UNSELECTEDBLOB); 00513 00514 // Render the blobs on the path 00515 pRender->DrawBlob(Parallel[0], BT_UNSELECTED); 00516 pRender->DrawBlob(Parallel[1], BT_UNSELECTED); 00517 pRender->DrawBlob(Parallel[2], BT_UNSELECTED); 00518 pRender->DrawBlob(Parallel[3], BT_UNSELECTED); 00519 #endif 00520 } 00521 00522 00523 00524 /******************************************************************************************** 00525 00526 > void NodeSimpleShape::RenderTinyBlobs(RenderRegion* pRender) 00527 00528 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00529 Created: 23/6/94 00530 Inputs: pRender - the region to render the blobs to 00531 Purpose: Renders the Tiny blobs for a Node Shape 00532 SeeAlso: BlobManager 00533 00534 ********************************************************************************************/ 00535 00536 void NodeSimpleShape::RenderTinyBlobs(RenderRegion* pRender) 00537 { 00538 #if !defined(EXCLUDE_FROM_RALPH) 00539 // Set the line colours etc as we need them 00540 pRender->SetLineColour(COLOUR_NONE); 00541 pRender->SetFillColour(COLOUR_UNSELECTEDBLOB); 00542 00543 // Find out about the path that the shape is made from 00544 DocCoord* Coords = InkPath.GetCoordArray(); 00545 00546 // Render the blobs on the path 00547 if (InkPath.GetNumCoords()>0) 00548 pRender->DrawBlob(Coords[0], BT_UNSELECTED); 00549 #endif 00550 } 00551 00552 00553 00554 /******************************************************************************************** 00555 00556 > DocRect NodeSimpleShape::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE) 00557 00558 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00559 Created: 17/02/94 00560 Inputs: DontUseAttrs - TRUE if we should ignore the nodes attributes. 00561 Defaults to FALSE 00562 HitTest - TRUE if being called during HitTest 00563 Returns: The nodes bounding rect 00564 Purpose: if the bounding rect is valid it is returned, if not, it is recalculated 00565 and then returned. 00566 SeeAlso: NodeSimpleShape::GetBlobBoundingRect 00567 00568 ********************************************************************************************/ 00569 00570 DocRect NodeSimpleShape::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest) 00571 { 00572 if (!IsBoundingRectValid || DontUseAttrs) 00573 { 00574 // Something to put the new bounding rectangle in 00575 DocRect NewBoundingRect; 00576 00577 // Find out what the paths bounding rect is now 00578 if (!CalculatePathBoundingRect(InkPath, DontUseAttrs, &NewBoundingRect)) 00579 { 00580 // GDraw failed to find out how big the bounding rect 00581 // we will have to make do with the bounding rect of the coords 00582 NewBoundingRect = InkPath.GetBoundingRect(); 00583 } 00584 00585 // we have a new bounding rect - decide what to do with it 00586 if (DontUseAttrs) 00587 { 00588 // but it is not the real bounding rect, so just return it 00589 return NewBoundingRect; 00590 } 00591 00592 // Update the Nodes bounding rectangle 00593 BoundingRectangle = NewBoundingRect; 00594 00595 // Mark the rect as valid 00596 IsBoundingRectValid = TRUE; 00597 } 00598 00599 // return the current state of the bounding rect 00600 return BoundingRectangle; 00601 } 00602 00603 00604 /******************************************************************************************** 00605 00606 > DocRect NodeSimpleShape::GetBlobBoundingRect() 00607 00608 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00609 Created: 17/02/94 00610 Returns: DocRect - Returns the bounding rect of the path and its blobs 00611 Purpose: This calculates the bounding box of the path and adds in the influence of 00612 the selection blobs. It does not consider if the blobs are visible or not, 00613 it just gives the bounding box that they would occupy if they were visible 00614 00615 ********************************************************************************************/ 00616 00617 DocRect NodeSimpleShape::GetBlobBoundingRect() 00618 { 00619 #if !defined(EXCLUDE_FROM_RALPH) 00620 // Find the Shapes bounding rectangle 00621 DocRect Rect = GetBoundingRect(); 00622 00623 // Find the blob manager 00624 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00625 00626 // And if we can find the current view, add on the size of a selection blob 00627 if (pBlobMgr!= NULL) 00628 { 00629 // Wee need to add in each of the blobs. there is a blob on each corner 00630 // of the parallelogram 00631 DocRect BlobSize; 00632 pBlobMgr->GetBlobRect(Parallel[0], &BlobSize); 00633 Rect = Rect.Union(BlobSize); 00634 00635 // Next corner of the parallelogram 00636 pBlobMgr->GetBlobRect(Parallel[1], &BlobSize); 00637 Rect = Rect.Union(BlobSize); 00638 00639 // and the next 00640 pBlobMgr->GetBlobRect(Parallel[2], &BlobSize); 00641 Rect = Rect.Union(BlobSize); 00642 00643 // and the last one 00644 pBlobMgr->GetBlobRect(Parallel[3], &BlobSize); 00645 Rect = Rect.Union(BlobSize); 00646 } 00647 00648 // Make sure we include the Bounds of our children 00649 IncludeChildrensBoundingRects(&Rect); 00650 00651 // return the rectangle with the blobs included 00652 return Rect; 00653 #else 00654 return DocRect(0,0,0,0); 00655 #endif 00656 } 00657 00658 00659 00660 00661 /******************************************************************************************** 00662 00663 > virtual UINT32 NodeSimpleShape::GetNodeSize() const 00664 00665 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00666 Created: 6/10/93 00667 Returns: The size of the node in bytes 00668 Purpose: For finding the size of the node 00669 SeeAlso: Node::GetSubtreeSize 00670 00671 ********************************************************************************************/ 00672 00673 UINT32 NodeSimpleShape::GetNodeSize() const 00674 { 00675 return (sizeof(NodeSimpleShape)); 00676 } 00677 00678 00679 00680 /******************************************************************************************** 00681 00682 > BOOL NodeSimpleShape::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00683 Spread* pSpread ) 00684 00685 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00686 Created: 2/6/94 00687 Inputs: PointerPos - The Location of the mouse pointer at the time of the click 00688 Click - The type of click received (single, double, drag etc) 00689 ClickMods - The modifiers to the click (eg shift, control etc ) 00690 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 00691 not interested in the click 00692 Purpose: Allows the Node to respond to clicks by selecting its blobs or starting 00693 drags etc. 00694 This functions should be overridden in the all the NodeRenderableInk classes 00695 so that this version never gets called. Eg the NodePath class might claim 00696 the click if it happened over one of its unselected blobs. 00697 00698 ********************************************************************************************/ 00699 00700 BOOL NodeSimpleShape::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods, 00701 Spread* pSpread ) 00702 { 00703 PORTNOTETRACE("other","NodeSimpleShape::OnClick - do nothing"); 00704 00705 #if !defined(EXCLUDE_FROM_RALPH) 00706 // we only handle the click if we can confirm that object blobs are being displayed. 00707 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00708 if (pBlobMgr == NULL) 00709 return FALSE; 00710 if (!pBlobMgr->GetCurrentInterest().Object) 00711 return FALSE; 00712 00713 INT32 ClickCorner; 00714 00715 if (IsNearControlHandle(PointerPos, &ClickCorner)) 00716 { 00717 // The click was over a control point, so start the drag and tell it the opposite corner 00718 if (Click==CLICKTYPE_DRAG) 00719 HandleBlobDrag(Parallel[ClickCorner], pSpread, (ClickCorner+2)%4 ); 00720 00721 // we have used that click up, so tell the world 00722 return TRUE; 00723 } 00724 #endif 00725 // did not use the click 00726 return FALSE; 00727 } 00728 00729 00730 00731 /******************************************************************************************** 00732 00733 > BOOL NodeSimpleShape::IsNearControlHandle(DocCoord Coord, INT32* CoordNum) 00734 00735 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00736 Created: 9/11/94 00737 Inputs: Coord - The Coordinate that we want to test 00738 Outputs: CoordNum - The number of the control point that the coord was close to. 00739 This parameter is only changed it the function returns TRUE. 00740 Returns: TRUE if the Coord was close to one of the control points, FALSE otherwise 00741 Purpose: This function tests to see if the Coord passed in is close to any of the 00742 control points in the Ellipse. If it is, the number of the control point 00743 is set in CoordNum and TRUE is returned. If not, the value of CoordNum 00744 is left unchanged and FALSE is returned. 00745 00746 ********************************************************************************************/ 00747 00748 BOOL NodeSimpleShape::IsNearControlHandle(DocCoord Coord, INT32* CoordNum) 00749 { 00750 #if !defined(EXCLUDE_FROM_RALPH) 00751 // Find the blob manager 00752 BlobManager* pBlobMgr = GetApplication()->GetBlobManager(); 00753 if (pBlobMgr==NULL) 00754 return FALSE; 00755 00756 // Find out about the size of a blob 00757 DocRect BlobRect; 00758 pBlobMgr->GetBlobRect(Coord, &BlobRect); 00759 00760 // Check to see if it is near any of the blobs 00761 for (INT32 i=0; i<4; i++) 00762 { 00763 // Check for collision with the control points 00764 if (BlobRect.ContainsCoord(Parallel[i])) 00765 { 00766 // Tell them which control point it waas over 00767 *CoordNum = i; 00768 00769 // we have used that click up, so tell the world 00770 return TRUE; 00771 } 00772 } 00773 #endif 00774 // was not over any of the control points 00775 return FALSE; 00776 } 00777 00778 00779 /******************************************************************************************** 00780 00781 > void NodeSimpleShape::HandleBlobDrag(DocCoord& PointerPos, Spread* pSpread, INT32 FixedCorner) 00782 00783 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00784 Created: 2/6/94 00785 Inputs: PointerPos - The position the mouse pointer clicked 00786 pSpread - the spread that the click was on 00787 FixedCorner - The corner of the parallelogram that will stay fixed during 00788 the drag 00789 Purpose: This is the base class version of this function, which does nothing. All the 00790 work should be done in the derived classes. These should do as follows. 00791 When a drag is started on one of the paths blobs this is called. It tries to 00792 fire up an operation that will perform a drag of all the selected points, 00793 including all the EORing of the relavent parts of the curve. If it fails it 00794 will inform the user and not bother. 00795 00796 ********************************************************************************************/ 00797 00798 void NodeSimpleShape::HandleBlobDrag(DocCoord& PointerPos, Spread* pSpread, INT32 FixedCorner) 00799 { 00800 ENSURE( FALSE, "NodeSimpleShape::HandleBlobDrag() called. Derived class should have been used"); 00801 } 00802 00803 00804 00805 00806 00807 /******************************************************************************************** 00808 00809 > virtual BOOL NodeSimpleShape::CanBecomeA(BecomeA* pBecomeA) 00810 00811 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00812 Created: 29/4/94 00813 Inputs: InkClass: The class of object 00814 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL). 00815 *pNumObects in undefined on entry 00816 Returns: TRUE if the node, or any of its children can transmogrify themselves to become 00817 an InkClass object 00818 Purpose: This function is used by the convert to shapes operation. It determines if 00819 the node or any of its children can convert themselves into an InkClass object. 00820 00821 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number 00822 of pClass objects you create. It should NOT contain any additional objects you may produce 00823 such as group objects for containing the pClass object, or attributes. 00824 00825 Also, the entry value of *pNumObjects cannot be assumed to be 0. 00826 ********************************************************************************************/ 00827 00828 BOOL NodeSimpleShape::CanBecomeA(BecomeA* pBecomeA) 00829 { 00830 // The NodeSimpleShape can become a NodePath 00831 if (pBecomeA->BAPath()) 00832 { 00833 pBecomeA->AddCount(1); 00834 00835 return TRUE; 00836 } 00837 00838 return FALSE; 00839 } 00840 00841 00842 /******************************************************************************************** 00843 00844 > virtual BOOL NodeSimpleShape::DoBecomeA(CCRuntimeClass* InkClass, UndoableOperation* pOp) 00845 00846 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00847 Created: 29/4/94 00848 Inputs: pBecomeA = ptr to a class that contains all the info needed to become a new 00849 type of node. 00850 Outputs: - 00851 Returns: TRUE if the object has been transformed, FALSE if we run out of memory 00852 00853 Purpose: Transforms the object into another type of object. 00854 Note: changed 7/10/94 by MarkN to take the pBecomeA param, so that more data could be passed 00855 to these functions in the future without causing massive rebuilds due to the editing of 00856 node.h 00857 SeeAlso: NodeSimpleShape::CanBecomeA 00858 00859 ********************************************************************************************/ 00860 00861 BOOL NodeSimpleShape::DoBecomeA(BecomeA* pBecomeA) 00862 { 00863 // Check for a NULL entry param 00864 ERROR2IF_PF(pBecomeA == NULL,FALSE,("pBecomeA is NULL")); 00865 00866 // This lump checks that the Reason is one that we understand 00867 // It also makes sure that we don't have a NULL UndoOp ptr 00868 BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK); 00869 ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason())); 00870 00871 // pBecomeA->Reason is one that we understand. 00872 00873 BOOL Success = TRUE; // Our success flag (Important that this defaults to TRUE) 00874 NodePath* pNewNodePath = NULL; // Ptr to a new NodePath, if we get to make one. 00875 00876 if (pBecomeA->BAPath()) 00877 { 00878 // We need to create a new NodePath, no matter what the reason. 00879 00880 // Allocate a new NodePath node 00881 ALLOC_WITH_FAIL(pNewNodePath, (new NodePath), pBecomeA->GetUndoOp()); 00882 Success = (pNewNodePath != NULL); 00883 00884 // Initialise the path 00885 if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.Initialise(InkPath.GetNumCoords(),12), pBecomeA->GetUndoOp(), Success); 00886 if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.CopyPathDataFrom(&InkPath), pBecomeA->GetUndoOp(), Success); 00887 00888 // If Success is TRUE, then we now have a new NodePath object that contains this shape's path 00889 00890 if (Success) 00891 { 00892 switch (pBecomeA->GetReason()) 00893 { 00894 case BECOMEA_REPLACE : 00895 { 00896 // It's a BECOMEA_REPLACE, so replace this node with the new NodePath in an undoable way 00897 00898 // Can't do it in an undoable way without an Undo Op 00899 ERROR2IF_PF(pBecomeA->GetUndoOp() == NULL,FALSE,("GetUndoOp() returned NULL")); 00900 00901 // Firstly, hide this node 00902 NodeHidden* pNodeHidden; 00903 Success = pBecomeA->GetUndoOp()->DoHideNode(this, TRUE, &pNodeHidden); 00904 00905 if (Success) 00906 { 00907 // Insert the new NodePath into the tree, next to the hidden node 00908 pNewNodePath->AttachNode(pNodeHidden,NEXT); 00909 00910 // Copy the node's attributes 00911 CALL_WITH_FAIL(CopyChildrenTo(pNewNodePath), pBecomeA->GetUndoOp(), Success); 00912 00913 if (Success) 00914 { 00915 // Set the bounds 00916 pNewNodePath->InvalidateBoundingRect(); 00917 pNewNodePath->SetSelected(IsSelected()); 00918 00919 // Create a hide node action to hide the node when we undo 00920 HideNodeAction* UndoHideNodeAction; 00921 Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(), 00922 pBecomeA->GetUndoOp()->GetUndoActionList(), 00923 pNewNodePath, 00924 TRUE, // Include subtree size 00925 ( Action**)(&UndoHideNodeAction)) 00926 != AC_FAIL); 00927 } 00928 } 00929 00930 if (Success) 00931 pBecomeA->PassBack(pNewNodePath, this); 00932 } 00933 break; 00934 00935 case BECOMEA_PASSBACK : 00936 Success = pBecomeA->PassBack(pNewNodePath,this); 00937 break; 00938 00939 default: 00940 break; 00941 } 00942 } 00943 } 00944 00945 if (!Success) 00946 { 00947 if (pNewNodePath != NULL) 00948 { 00949 // Delete all the NodePath's children (if it has any) and unlink it from the tree (if it's linked) 00950 // This is all done by CascadeDelete() 00951 pNewNodePath->CascadeDelete(); 00952 delete pNewNodePath; 00953 pNewNodePath = NULL; 00954 } 00955 } 00956 00957 return Success; 00958 } 00959 00960 00961 00962 /*********************************************************************************************** 00963 00964 > BOOL NodeSimpleShape::Snap(DocCoord* pDocCoord) 00965 00966 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00967 Created: 20/9/94 00968 Inputs: pDocCoord = a coord in Spread coords 00969 Outputs: 00970 Returns: TRUE - the DocCoord has been snapped to the path. 00971 FALSE - the DocCoord has not been processed. 00972 00973 Purpose: Snaps to given coord to the nearest point on the path. If it is not appropriate to snap 00974 the coord to the path (at the moment this means the coord is too far awawy), then FALSE is returned. 00975 Errors: 00976 Scope: public 00977 00978 **********************************************************************************************/ 00979 00980 BOOL NodeSimpleShape::Snap(DocCoord* pDocCoord) 00981 { 00982 #if !defined(EXCLUDE_FROM_RALPH) 00983 BOOL Snapped = FALSE; 00984 00985 MILLIPOINT SnapDist = CSnap::GetSnapDist(); 00986 MILLIPOINT SqrSnapDist = SnapDist*SnapDist; 00987 00988 INT32 NearEl; 00989 double mu; 00990 double SqrDist = InkPath.SqrDistanceToPoint(*pDocCoord,&NearEl,&mu); 00991 00992 if (SqrDist <= SqrSnapDist) 00993 { 00994 *pDocCoord = InkPath.ClosestPointTo(mu,NearEl); 00995 Snapped = TRUE; 00996 } 00997 00998 return (Snapped); 00999 #else 01000 return FALSE; 01001 #endif 01002 } 01003 01004 /*********************************************************************************************** 01005 01006 > BOOL NodeSimpleShape::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord) 01007 01008 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 01009 Created: 21/9/94 01010 Inputs: pDocCoord - the rectangle to snap 01011 StartDrag - Start coord of drag 01012 EndDrag - End coord of drag 01013 Outputs: 01014 Returns: TRUE - the DocRect been snapped to the grid. 01015 FALSE - the DocRect has not been processed. 01016 01017 Purpose: Snaps the given rect to the nearest position on the grid, preserving its width 01018 and height. 01019 The coords of the rect used for the snapping are determined by the PrevCoord and 01020 CurCoord coords supplied. This is done to allow the user to control how a 01021 selection rectangle is snapped to the grid by the direction of his/her last mouse 01022 movement. 01023 To force the bottom left hand corner of the rect to be snapped, 01024 supply PrevCoord=(0,0) and CurCoord(-1,-1). 01025 Scope: public 01026 01027 **********************************************************************************************/ 01028 01029 BOOL NodeSimpleShape::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord) 01030 { 01031 #if !defined(EXCLUDE_FROM_RALPH) 01032 TRACEUSER( "MarkN", _T("NodeSimpleShape::Snap(DocRect)\n") ); 01033 #endif 01034 return FALSE; 01035 } 01036 01037 01038 01039 /******************************************************************************************** 01040 01041 > BOOL NodeSimpleShape::SnapToCoords(DocCoord* pDocCoord) 01042 01043 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01044 Created: 21/11/94 01045 Inputs: pDocCoord - The Coord to try and snap 01046 Outputs: pDocCoord - The snapped verison of the coord 01047 Returns: TRUE if the input coord was snapped, FALSE if not 01048 Purpose: This function tries to magnetically snap the supplied coord to the shape. 01049 This version of the function tries to snap to coords at the centre of the 01050 shape and in the middle of each of the edges. 01051 SeeAlso: NodeRenderableBounded::SnapToCoords 01052 01053 ********************************************************************************************/ 01054 01055 BOOL NodeSimpleShape::SnapToCoords(DocCoord* pDocCoord) 01056 { 01057 #if !defined(EXCLUDE_FROM_RALPH) 01058 // Work out the coords to snap to 01059 DocCoord TestPoint; 01060 01061 // Snap to the Centre of the Shape 01062 TestPoint.x = (Parallel[0].x + Parallel[2].x) / 2; 01063 TestPoint.y = (Parallel[0].y + Parallel[2].y) / 2; 01064 01065 // Test to see if the points are close together, and update pDocCoord if they are 01066 if (IsMagneticallyClose(&TestPoint, pDocCoord)) 01067 return TRUE; 01068 01069 // Try and snap to the middle of each of the edges 01070 for (INT32 i=0; i<4; i++) 01071 { 01072 // Find test coord 01073 INT32 NextPoint = (i+1) % 4; 01074 TestPoint.x = (Parallel[i].x + Parallel[NextPoint].x) / 2; 01075 TestPoint.y = (Parallel[i].y + Parallel[NextPoint].y) / 2; 01076 01077 // Test to see if the points are close together, and update pDocCoord if they are 01078 if (IsMagneticallyClose(&TestPoint, pDocCoord)) 01079 return TRUE; 01080 } 01081 #endif 01082 // Did not snap to anything. 01083 return FALSE; 01084 } 01085 01086 01087 01088 /******************************************************************************************** 01089 01090 > double NodeSimpleShape::GetRotationAngle() 01091 01092 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01093 Created: 24/1/95 01094 Inputs: - 01095 Outputs: - 01096 Returns: The rotation angle of this simple shape NodeRenderableInk 01097 Purpose: Returns the current angle of rotation of the simple shape. This is calculated 01098 as the angle from the midpoint of the upper paralleogram line to the positive 01099 x-axis. 01100 SeeAlso: NodeRenderableBounded::GetRotationAngle 01101 01102 ********************************************************************************************/ 01103 01104 double NodeSimpleShape::GetRotationAngle() 01105 { 01106 DocCoord MidPoint((Parallel[0].x + Parallel[1].x)/2, (Parallel[0].y + Parallel[1].y)/2); 01107 01108 DocRect Bounds(Parallel[0],Parallel[0]); 01109 Bounds.IncludePoint(Parallel[1]); 01110 Bounds.IncludePoint(Parallel[2]); 01111 Bounds.IncludePoint(Parallel[3]); 01112 DocCoord Centre((Bounds.LowCorner().x+Bounds.HighCorner().x)/2, 01113 (Bounds.LowCorner().y+Bounds.HighCorner().y)/2); 01114 01115 DocCoord Offset = MidPoint - Centre; 01116 01117 double Angle = atan2((double)Offset.y, (double)Offset.x); 01118 if (Angle == HUGE_VAL) 01119 Angle = 0.0; 01120 01121 return Angle; 01122 } 01123 01124 01125 01126 /******************************************************************************************** 01127 01128 > DocRect NodeSimpleShape::ValidateExtend(const ExtendParams& ExtParams) 01129 01130 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01131 Created: 25/11/1999 01132 Inputs: ExtParams parameters describing the extension. 01133 Outputs: 01134 Returns: TRUE if this simple shape can be validly extended, 01135 FALSE otherwise. 01136 Purpose: Tests to see whether this shape's centre-point is positioned so as to make 01137 an extend operation irreversible. 01138 Errors: 01139 See also: 01140 01141 ********************************************************************************************/ 01142 DocRect NodeSimpleShape::ValidateExtend(const ExtendParams& ExtParams) 01143 { 01144 DocCoord doccArray[1] = { FindExtendCentre() }; 01145 DocRect drMinExtend = Extender::ValidateControlPoints(1, doccArray, ExtParams); 01146 01147 // if we didn't invalidate the extension, we must call the base class 01148 // implementation, which will validate our children. 01149 if (drMinExtend.lo.x == INT32_MAX && 01150 drMinExtend.lo.y == INT32_MAX && 01151 drMinExtend.hi.x == INT32_MAX && 01152 drMinExtend.hi.y == INT32_MAX) 01153 drMinExtend = Node::ValidateExtend(ExtParams); 01154 01155 return drMinExtend; 01156 } 01157 01158 01159 01160 /******************************************************************************************** 01161 01162 > void NodeSimpleShape::Extend(const ExtendParams& ExtParams) 01163 01164 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01165 Created: 25/11/1999 01166 Inputs: ExtParams parameters describing the extension. 01167 Outputs: this NodeSimpleShape will be extended in accordance with ExtParams. 01168 Returns: 01169 Purpose: Perform an Extend operation on this shape. Behaviour is as follows: 01170 01171 * the shape extends separately along each axis. 01172 * if the shape is asked to stretch, it scales along the corresponding axes. 01173 * if the shape is asked to extend, it is translated as a whole, as described 01174 by ExtParams. 01175 Errors: 01176 See also: class Extender 01177 01178 ********************************************************************************************/ 01179 void NodeSimpleShape::Extend(const ExtendParams& ExtParams) 01180 { 01181 // do the extension operations on ourself. 01182 TransformStretchObject(ExtParams); 01183 TransformTranslateObject(ExtParams); 01184 01185 // do the base-class implementation to extend our children. 01186 Node::Extend(ExtParams); 01187 }