00001 // $Id: nodetext.cpp 1478 2006-07-19 14:44:47Z phil $ 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 // This file contains the implementation of all Text object Nodes 00100 // A TextObject is composed of the following nodes 00101 // TextStory ( The root of the text object subtree ) 00102 // NodeAttributes (Many or none) 00103 // NodePath 00104 // TextLine (Many or one) 00105 // NodeAttributes (Many or none) 00106 // TextChar 00107 // See TEXTTLDS.DOC for a description of the structure of the text object data structure 00108 00109 00110 #include "camtypes.h" 00111 #include "nodetext.h" 00112 00113 // Code headers 00114 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 //#include "becomea.h" 00116 #include "blobs.h" 00117 #include "cameleps.h" 00118 #include "cliptype.h" 00119 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 #include "gdraw.h" 00121 #include "grndrgn.h" 00122 #include "lineattr.h" 00123 #include "nodetxtl.h" 00124 #include "nodetxts.h" 00125 #include "snap.h" 00126 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00127 #include "texttool.h" 00128 #include "textops.h" 00129 #include "attrmap.h" 00130 #include "printctl.h" 00131 #include "cxftext.h" 00132 #include "nodepath.h" 00133 #include "swfrndr.h" 00134 00135 // Resource headers 00136 //#include "mario.h" 00137 //#include "peter.h" 00138 //#include "simon.h" 00139 00140 #include "webattr.h" //For the GetClickableRectangle functions 00141 #include "brshattr.h" 00142 00143 #include "ai_epsrr.h" 00144 00145 DECLARE_SOURCE("$Revision: 1478 $") 00146 00147 CC_IMPLEMENT_DYNAMIC(VisibleTextNode, BaseTextClass) 00148 CC_IMPLEMENT_DYNAMIC(CaretNode, VisibleTextNode) 00149 CC_IMPLEMENT_DYNAMIC(AbstractTextChar, VisibleTextNode) 00150 CC_IMPLEMENT_DYNAMIC(EOLNode, AbstractTextChar) 00151 CC_IMPLEMENT_DYNAMIC(TextChar, AbstractTextChar) 00152 CC_IMPLEMENT_DYNAMIC(KernCode, AbstractTextChar) 00153 CC_IMPLEMENT_DYNAMIC(HorizontalTab, AbstractTextChar) 00154 00155 // Declare smart memory handling in Debug builds 00156 #define new CAM_DEBUG_NEW 00157 00158 00159 /******************************************************************************************** 00160 > VisibleTextNode::VisibleTextNode() 00161 00162 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00163 Created: 21/12/94 00164 Purpose: Simple VisibleTextNode constructor, it is required so that SimpleCopy will work. 00165 ********************************************************************************************/ 00166 00167 VisibleTextNode::VisibleTextNode(): BaseTextClass() // Call the base class 00168 { 00169 Init(); 00170 } 00171 00172 00173 /******************************************************************************************** 00174 > VisibleTextNode::VisibleTextNode(Node* ContextNode, AttachNodeDirection Direction) 00175 00176 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00177 Created: 07/02/95 00178 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 00179 00180 Direction: 00181 00182 Specifies the direction in which the node is to be attached to the 00183 ContextNode. The values this variable can take are as follows: 00184 00185 PREV : Attach node as a previous sibling of the context node 00186 NEXT : Attach node as a next sibling of the context node 00187 FIRSTCHILD: Attach node as the first child of the context node 00188 LASTCHILD : Attach node as a last child of the context node 00189 00190 Purpose: The main VisibleTextNode constructor 00191 ********************************************************************************************/ 00192 00193 VisibleTextNode::VisibleTextNode(Node* ContextNode, 00194 AttachNodeDirection Direction): BaseTextClass(ContextNode, Direction) 00195 { 00196 Init(); 00197 } 00198 00199 00200 /******************************************************************************************** 00201 > void VisibleTextNode::Init() 00202 00203 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00204 Created: 14/3/95 00205 Purpose: Initialise the members of a VisibleTextNode. Called by all constructors. 00206 ********************************************************************************************/ 00207 00208 void VisibleTextNode::Init() 00209 { 00210 CharMatrix = Matrix(0,0); 00211 PosInLine = 0; 00212 IsBoundingRectValid = FALSE; 00213 } 00214 00215 00216 /******************************************************************************************** 00217 > VisibleTextNode* VisibleTextNode::FindNextVTNInStory() 00218 00219 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00220 Created: 14/2/95 00221 Returns: A pointer to the next VisibleTextNode in the TextStory 00222 Purpose: Finds the next VisibleTextNode in the TextStory. The routine searches 00223 across TextLines. 00224 Errors: An ERROR3 will be caused if the node is not on a line which is the child 00225 of a TextStory. 00226 ********************************************************************************************/ 00227 00228 VisibleTextNode* VisibleTextNode::FindNextVTNInStory() 00229 { 00230 Node* Line = FindParent(); 00231 00232 // Be cautious 00233 ERROR3IF(Line == NULL, "VisibleTextNode has no parent"); 00234 ERROR3IF(!(IS_A(Line, TextLine)), "Parent of VisibleTextNode is not a TextLine"); 00235 00236 Node* Story = Line->FindParent(); 00237 00238 ERROR3IF(Story == NULL, "TextLine has no parent"); 00239 ERROR3IF(!(IS_A(Story, TextStory)), "Parent of TextLine is not a TextStory"); 00240 00241 Node* n = this; 00242 00243 // Loop until we have found a next VisibleTextNode 00244 // This code is an optimised depth first routine 00245 do 00246 { 00247 if (n->FindNext()) // Has the current node got a next sibling 00248 { 00249 n = n->FindNext(); // Let's visit it 00250 00251 if (IS_A(n,TextLine)) 00252 { 00253 // We have skipped to the next line, let's go to its first child if 00254 // it has one 00255 if (n->FindFirstChild()) 00256 { 00257 n = n->FindFirstChild(); 00258 } 00259 } 00260 00261 if (n->IsAVisibleTextNode()) 00262 { 00263 // Found one ! 00264 return (VisibleTextNode*)n; 00265 } 00266 00267 } 00268 else 00269 { 00270 // The only way is up 00271 n = n->FindParent(); 00272 } 00273 ERROR3IF(n == NULL, "We haven't found the parent TextStory"); 00274 } 00275 while (n != Story); 00276 00277 return NULL; // No more 00278 } 00279 00280 00281 /******************************************************************************************** 00282 > VisibleTextNode* VisibleTextNode::FindPrevVTNInStory() 00283 00284 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00285 Created: 14/2/95 00286 Returns: A pointer to the previous VisibleTextNode in the TextStory 00287 Purpose: Finds the previous VisibleTextNode in the TextStory. The routine searches 00288 across TextLines. 00289 Errors: An ERROR3 will be caused if the node is not on a line which is the child 00290 of a TextStory. 00291 ********************************************************************************************/ 00292 00293 VisibleTextNode* VisibleTextNode::FindPrevVTNInStory() 00294 { 00295 Node* Line = FindParent(); 00296 00297 // Be cautious 00298 ERROR3IF(Line == NULL, "VisibleTextNode has no parent"); 00299 ERROR3IF(!(IS_A(Line, TextLine)), "Parent of VisibleTextNode is not a TextLine"); 00300 00301 Node* Story = Line->FindParent(); 00302 00303 ERROR3IF(Story == NULL, "TextLine has no parent"); 00304 ERROR3IF(!(IS_A(Story, TextStory)), "Parent of TextLine is not a TextStory"); 00305 00306 Node* n = this; 00307 00308 // Loop until we have found a previous VisibleTextNode 00309 // This code is an optimised prev depth first routine 00310 do 00311 { 00312 if (n->FindPrevious()) // Has the current node got a previous sibling 00313 { 00314 n = n->FindPrevious(); // Let's visit it 00315 00316 if (IS_A(n, TextLine)) 00317 { 00318 // Next node to check is the last child of this TextLine 00319 Node* LastChild = n->FindLastChild(); 00320 if (LastChild != NULL) 00321 { 00322 n = LastChild; 00323 } 00324 } 00325 00326 if (n->IsAVisibleTextNode()) 00327 { 00328 // Found one ! 00329 return (VisibleTextNode*)n; 00330 } 00331 00332 } 00333 else 00334 { 00335 // The only way is up 00336 n = n->FindParent(); 00337 } 00338 ERROR3IF(n == NULL, "We haven't found the parent TextStory"); 00339 } 00340 while (n != Story); 00341 00342 return NULL; // No more 00343 } 00344 00345 00346 /******************************************************************************************** 00347 > AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInStory() 00348 00349 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00350 Created: 22/3/95 00351 Returns: A pointer to the next AbstractTextChar in the TextStory 00352 ********************************************************************************************/ 00353 00354 AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInStory() 00355 { 00356 VisibleTextNode* pChar = FindNextVTNInStory(); 00357 while (pChar!=NULL && !pChar->IsAnAbstractTextChar()) 00358 pChar = pChar->FindNextVTNInStory(); 00359 00360 return (AbstractTextChar*)pChar; 00361 } 00362 00363 00364 /******************************************************************************************** 00365 > AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInStory() 00366 00367 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00368 Created: 22/3/95 00369 Returns: A pointer to the previous AbstractTextChar in the TextStory 00370 ********************************************************************************************/ 00371 00372 AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInStory() 00373 { 00374 VisibleTextNode* pChar = FindPrevVTNInStory(); 00375 while (pChar!=NULL && !pChar->IsAnAbstractTextChar()) 00376 pChar = pChar->FindPrevVTNInStory(); 00377 00378 return (AbstractTextChar*)pChar; 00379 } 00380 00381 00382 /******************************************************************************************** 00383 > TextChar* VisibleTextNode::FindNextTextCharInStory() 00384 00385 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00386 Created: 22/3/95 00387 Returns: A pointer to the next TextChar in the TextStory 00388 ********************************************************************************************/ 00389 00390 TextChar* VisibleTextNode::FindNextTextCharInStory() 00391 { 00392 VisibleTextNode* pChar = FindNextVTNInStory(); 00393 while (pChar!=NULL && !IS_A(pChar,TextChar)) 00394 pChar = pChar->FindNextVTNInStory(); 00395 00396 return (TextChar*)pChar; 00397 } 00398 00399 00400 /******************************************************************************************** 00401 > TextChar* VisibleTextNode::FindPrevTextCharInStory() 00402 00403 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00404 Created: 22/3/95 00405 Returns: A pointer to the previous TextChar in the TextStory 00406 ********************************************************************************************/ 00407 00408 TextChar* VisibleTextNode::FindPrevTextCharInStory() 00409 { 00410 VisibleTextNode* pChar = FindPrevVTNInStory(); 00411 while (pChar!=NULL && !IS_A(pChar,TextChar)) 00412 pChar = pChar->FindPrevVTNInStory(); 00413 00414 return (TextChar*)pChar; 00415 } 00416 00417 00418 /******************************************************************************************** 00419 > VisibleTextNode* VisibleTextNode::FindNextVTNInLine() 00420 00421 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00422 Created: 8/1/96 00423 Returns: A pointer to the next VTN in the line 00424 ********************************************************************************************/ 00425 00426 VisibleTextNode* VisibleTextNode::FindNextVTNInLine() 00427 { 00428 Node* pNode = FindNext(); 00429 while (pNode!=NULL && pNode->IsAVisibleTextNode()==FALSE) 00430 pNode = pNode->FindNext(); 00431 00432 return (VisibleTextNode*)pNode; 00433 } 00434 00435 /******************************************************************************************** 00436 > AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInLine() 00437 00438 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 00439 Created: 27/3/97 00440 Returns: A pointer to the next AbstractTextChar in the line 00441 ********************************************************************************************/ 00442 00443 AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInLine() 00444 { 00445 Node* pNode = FindNext(); 00446 while (pNode!=NULL && pNode->IsAnAbstractTextChar()==FALSE) 00447 pNode = pNode->FindNext(); 00448 00449 return (AbstractTextChar*)pNode; 00450 } 00451 00452 00453 00454 /******************************************************************************************** 00455 > VisibleTextNode* VisibleTextNode::FindPrevVTNInLine() 00456 00457 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00458 Created: 8/1/96 00459 Returns: A pointer to the previous VTN in the line 00460 ********************************************************************************************/ 00461 00462 VisibleTextNode* VisibleTextNode::FindPrevVTNInLine() 00463 { 00464 Node* pNode = FindPrevious(); 00465 while (pNode!=NULL && pNode->IsAVisibleTextNode()==FALSE) 00466 pNode = pNode->FindPrevious(); 00467 00468 return (VisibleTextNode*)pNode; 00469 } 00470 00471 /******************************************************************************************** 00472 > AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInLine() 00473 00474 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 00475 Created: 27/3/97 00476 Returns: A pointer to the prev AbstractTextChar in the line 00477 ********************************************************************************************/ 00478 00479 AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInLine() 00480 { 00481 Node* pNode = FindPrevious(); 00482 while (pNode!=NULL && pNode->IsAnAbstractTextChar()==FALSE) 00483 pNode = pNode->FindPrevious(); 00484 00485 return (AbstractTextChar*)pNode; 00486 } 00487 00488 /******************************************************************************************** 00489 > TextLine* VisibleTextNode::FindParentLine() 00490 00491 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00492 Created: 24/7/96 00493 Returns: A pointer to the parent TextLine 00494 ********************************************************************************************/ 00495 00496 TextLine* VisibleTextNode::FindParentLine() 00497 { 00498 return (TextLine*)(this->FindParent(CC_RUNTIME_CLASS(TextLine))); 00499 } 00500 00501 00502 /******************************************************************************************** 00503 > virtual CopyType VisibleTextNode::GetCopyType() 00504 00505 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00506 Created: 3/5/95 00507 Returns: A copy type describing how to copy this object 00508 Purpose: This function returns a type describing how this object is to be copied. 00509 The fuction is called from the low level copy operation CopyObjects. 00510 There are two options at present, these being SIMPLECOPY and COMPLEXCOPY. 00511 SIMPLECOPY indicates that the node can be copied by a call to its virtual 00512 function SimpleCopy(). 00513 COMPLEXCOPY however indicates that the node needs to do its own thing when 00514 copying and must be called via the ComplexCopy() virtual function. This 00515 virtual will likely return a tree of copied objects rather than just a 00516 copy of itself. 00517 ********************************************************************************************/ 00518 00519 CopyType VisibleTextNode::GetCopyType() 00520 { 00521 return COMPLEXCOPY; 00522 } 00523 00524 00525 /******************************************************************************************** 00526 > Node* VisibleTextNode::SimpleCopy() 00527 00528 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00529 Created: 21/12/94 00530 Returns: NULL (See below) 00531 Purpose: It is illegal to copy a VisibleTextNode (it's abstract), therefore this 00532 function will generate an error if called. 00533 ********************************************************************************************/ 00534 00535 Node* VisibleTextNode::SimpleCopy() 00536 { 00537 ERROR2(NULL, "Trying to copy abstract VisibleTextNode !"); 00538 } 00539 00540 00541 /******************************************************************************************** 00542 > virtual INT32 VisibleTextNode::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput) 00543 00544 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00545 Created: 3/5/95 00546 Inputs: Stage - either COPYOBJECT 00547 COPYFINISHED 00548 RangeToCopy - Describes the range which is currently being copied. 00549 pOutput - Depends on the Stage parameter 00550 if Stage= 00551 COPYOBJECT 00552 Then the node pointer pOutput points at NULL. It should be 00553 set on exit to point at the copied object or tree of objects 00554 COPYFINISHED 00555 Then the node pointer pOutput points at the resulting copy 00556 from COPYOBJECT inserted into the destination tree. 00557 Outputs: pOutput 00558 00559 Returns: -1 = The routine failed to make a copy. 00560 0 = No copy has been made. 00561 +1 = pOutput points to the copy. 00562 00563 Purpose: Create a complex copy of this node. This node has overridden GetCopyType() 00564 to return COMPLEXCOPY which means, when copying to the clipboard it must 00565 make a copy of itself and whatever else it needs. The resulting tree will 00566 be attached as the last child of the clipboard root. 00567 The routine will be called twice during a copy. Once when Stage==COPYOBJECT 00568 and once when Stage==COPYFINISHED. It is only necessary to return a copy 00569 during COPYOBJECT. COPYFINISHED can be used to tidy up and flags the node 00570 may set during COPYOBJECT. 00571 00572 Note: 00573 Nodes may well require the use of flags to create a sensible complex copy. 00574 Every selected node will be called to copy itself during a CopyToClipboard 00575 whether they are SIMPLECOPY or COMPLEXCOPY types. Hence if the first call 00576 to a node creates a complete tree of objects including nodes which will 00577 likely be called by the clipboard copy routine further into its range ie 00578 they are selected as well, the node should keep a flag indicating it has 00579 already copied them and return 0 from the routine on subsequent calls. 00580 A concrete example of this is the text object. Any number of characters 00581 can be selected and copied to the clipboard. A character class specifies 00582 it is a COMPLEXCOPY node. Each selected character will then get called 00583 to make a complex copy of itself. To make a copy the character will ask 00584 the parent text story to make a copy of all selected nodes, including 00585 itself and lines. It needs to flag itself at this point as further chars 00586 in the text story will be asked to do the same. This will prevent multiple 00587 text stories from being created, one for every selected character. 00588 ********************************************************************************************/ 00589 00590 INT32 VisibleTextNode::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput) 00591 { 00592 TextStory* pTextStory = FindParentStory(); 00593 ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::ComplexCopy() - pTextStory==NULL"); 00594 return pTextStory->BaseComplexCopy(Stage, RangeToCopy, pOutput); 00595 } 00596 00597 00598 /*********************************************************************************************** 00599 > void VisibleTextNode::CopyNodeContents(VisibleTextNode* NodeCopy) 00600 00601 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00602 Created: 28/4/93 00603 Outputs: A copy of this node 00604 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 00605 Errors: An ERROR3 will occur if NodeCopy is NULL 00606 ***********************************************************************************************/ 00607 00608 void VisibleTextNode::CopyNodeContents(VisibleTextNode* NodeCopy) 00609 { 00610 // Ask the base class to do its bit 00611 Node::CopyNodeContents(NodeCopy); 00612 00613 // copy specifics 00614 NodeCopy->CharMatrix = CharMatrix; 00615 NodeCopy->PosInLine = PosInLine; 00616 } 00617 00618 00619 /******************************************************************************************** 00620 > virtual INT32 VisibleTextNode::ComplexHide(UndoableOperation* pOp, Node* pNextNode) 00621 00622 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00623 Created: 3/5/95 00624 Inputs: pOp - a pointer to an undoable operation 00625 pNextNode - a pointer to the next node in range. 00626 Returns: -1 = The routine failed to hide this node. 00627 0 = Ignored, this object does not support complex hide operations, so 00628 carry on and hide the node as normal. 00629 +1 = The node and possibly various others have been hidden correctly. 00630 Purpose: Override the node level virtual function ComplexHide. This gives us a chance to 00631 get in and hide the various selected members of a text story sensibly. We 00632 hide all necessary nodes when the last member of the text story is called to 00633 complex hide itself, otherwise we may corrupt the range being scanned 00634 ********************************************************************************************/ 00635 00636 INT32 VisibleTextNode::ComplexHide(UndoableOperation* pOp, Node* pNextNode) 00637 { 00638 // if there is no next node in the range then we need to hide all nodes 00639 BOOL CallComplexHide = TRUE; 00640 TextStory* pThisStory = this->FindParentStory(); 00641 ERROR2IF(pThisStory==NULL,FALSE,"VisibleTextNode::ComplexHide() - pThisStory==NULL"); 00642 00643 if (pNextNode) 00644 { 00645 if ( pNextNode->IsAVisibleTextNode() || IS_A(pNextNode,TextLine) ) 00646 { 00647 TextStory* pTextStory = (TextStory*)(pNextNode->FindParent(CC_RUNTIME_CLASS(TextStory))); 00648 ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::ComplexHide() - pTextStory==NULL"); 00649 if (pThisStory==pTextStory) 00650 CallComplexHide=FALSE; 00651 } 00652 } 00653 00654 if (CallComplexHide) 00655 return pThisStory->BaseComplexHide(pOp); 00656 else 00657 return 1; 00658 } 00659 00660 00661 /******************************************************************************************** 00662 > UINT32 VisibleTextNode::GetNodeSize() const 00663 00664 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00665 Created: 21/12/94 00666 Returns: The size of the node in bytes 00667 Purpose: For finding the size of the VisibleTextNode. 00668 ********************************************************************************************/ 00669 00670 UINT32 VisibleTextNode::GetNodeSize() const 00671 { 00672 ERROR3("Tring to find the size of abstract VisibleTextNode"); 00673 return (sizeof(VisibleTextNode)); 00674 } 00675 00676 00677 /******************************************************************************************** 00678 > void VisibleTextNode::GetDebugDetails(StringBase* Str) 00679 00680 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 00681 Created: 1/2/95 00682 Outputs: Str: String giving debug info about the node 00683 Purpose: For obtaining debug information about the Node. 00684 This fn can be deleted before we ship 00685 ********************************************************************************************/ 00686 00687 void VisibleTextNode::GetDebugDetails(StringBase* Str) 00688 { 00689 #if DEBUG_TREE 00690 BaseTextClass::GetDebugDetails(Str); 00691 00692 String_256 TempStr; 00693 String_256 TempStr2; 00694 TCHAR floatStr[20]; 00695 00696 // dump the character matrix 00697 fixed16 abcd[4]; 00698 INT32 ef[2]; 00699 CharMatrix.GetComponents(abcd, ef); 00700 00701 TempStr._MakeMsg( TEXT("\r\nMatrix\r\n")); 00702 (*Str) += TempStr; 00703 camSnprintf( floatStr, 20, _T("%f,%f"), abcd[0].MakeDouble(), abcd[1].MakeDouble()); 00704 TempStr._MakeMsg( TEXT("a, b :\t#1%s\r\n"), floatStr); 00705 (*Str) += TempStr; 00706 camSnprintf( floatStr, 20, _T("%f,%f"), abcd[2].MakeDouble(), abcd[3].MakeDouble()); 00707 TempStr._MakeMsg( TEXT("c, d :\t#1%s\r\n"), floatStr); 00708 (*Str) += TempStr; 00709 TempStr._MakeMsg( TEXT("e, f :\t#1%ld,\t#2%ld\r\n"), ef[0], ef[1]); 00710 (*Str) += TempStr; 00711 #endif 00712 } 00713 00714 00715 /******************************************************************************************** 00716 > BOOL VisibleTextNode::GetStoryAndCharMatrix(Matrix* pMatrix) 00717 00718 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00719 Created: 19/3/95 00720 Outputs: pMatrix - output matrix 00721 Reutrns: FALSE if fails 00722 Purpose: set the given matrix to be the concatenation of the TextStory and VTN matrices 00723 ********************************************************************************************/ 00724 00725 BOOL VisibleTextNode::GetStoryAndCharMatrix(Matrix* pMatrix) 00726 { 00727 ERROR2IF(pMatrix==NULL,FALSE,"VisibleTextNode::GetStoryAndCharMatrix() - pMatrix==NULL"); 00728 00729 // get the VTN matrix, then concatenate the TextStory matrix 00730 *pMatrix=CharMatrix; 00731 TextStory* pTextStory = this->FindParentStory(); 00732 ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::GetStoryAndCharMatrix() - pTextStory==NULL"); 00733 *pMatrix*=*(pTextStory->GetpStoryMatrix()); 00734 00735 return TRUE; 00736 } 00737 00738 00739 /******************************************************************************************** 00740 > BOOL VisibleTextNode::RenderChildAttrs(RenderRegion* pRenderRegion) 00741 00742 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00743 Created: 4/4/95 00744 Inputs: pRenderRegion - 00745 Returns: FALSE if fails 00746 Purpose: Render any first level children attributes into the region 00747 ********************************************************************************************/ 00748 00749 BOOL VisibleTextNode::RenderChildAttrs(RenderRegion* pRenderRegion) 00750 { 00751 ERROR2IF(pRenderRegion==NULL,FALSE,"VisibleTextNode::RenderChildAttrs() - pRenderRegion==NULL"); 00752 00753 Node* pChildNode=FindFirstChild(); 00754 while (pChildNode) 00755 { 00756 if (pChildNode->IsAnAttribute()) 00757 pChildNode->Render(pRenderRegion); 00758 pChildNode=pChildNode->FindNext(); 00759 } 00760 00761 return TRUE; 00762 } 00763 00764 00765 /******************************************************************************************** 00766 > MILLIPOINT VisibleTextNode::CalcCharDistAlongLine(BOOL IncludeThisChar) 00767 00768 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00769 Created: 12/5/95 00770 Inputs: IncludeThisChar - TRUE to include this character in the distance, 00771 FALSE to leave it out 00772 Returns: The distance along the TextLine that this character is at 00773 Purpose: Finds the distance along the text line of this character. 00774 You can optionally include the width of this character in the sum. 00775 ********************************************************************************************/ 00776 00777 MILLIPOINT VisibleTextNode::CalcCharDistAlongLine(BOOL IncludeThisChar) 00778 { 00779 if (IncludeThisChar) 00780 return GetPosInLine()+GetCharAdvance(); 00781 else 00782 return GetPosInLine(); 00783 } 00784 00785 00786 /******************************************************************************************** 00787 > BOOL VisibleTextNode::WrapRestOfLineForward(UndoableOperation* pUndoOp) 00788 00789 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00790 Created: 8/7/96 00791 Inputs: pUndoOp - pointer to undoable op 00792 Returns: FALSE if fails 00793 Purpose: Wrap all nodes from this VTN (inc) to last VTN forward to start of next line 00794 If the line containing this VTN is hard (ends in an EOL) 00795 create a new line to wrap the text onto 00796 ********************************************************************************************/ 00797 00798 BOOL VisibleTextNode::WrapRestOfLineForward(UndoableOperation* pUndoOp) 00799 { 00800 // get info about the source line 00801 TextLine* pSrcLine = this->FindParentLine(); 00802 ERROR2IF(pSrcLine==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - pSrcLine==NULL"); 00803 VisibleTextNode* pLastVTNToMove = pSrcLine->FindLastVTN(); 00804 ERROR2IF(pLastVTNToMove==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - no VTN's on soft line"); 00805 00806 // if SrcLine soft, find next line (localising non-LLA attrs on it) else create a new line 00807 AttrTypeSet* pAttrSet = NULL; // assume creating new line so all attrs need localising 00808 TextLine* pDstLine = NULL; 00809 BOOL ok = TRUE; 00810 if (pLastVTNToMove->IsAnEOLNode()) 00811 { 00812 pDstLine = new TextLine; 00813 if (pDstLine==NULL) 00814 return FALSE; 00815 pSrcLine->CopyNodeContents(pDstLine); // copy cached line level attr info 00816 if (ok) ok = pDstLine->DoInsertNewNode(pUndoOp,pSrcLine,NEXT); 00817 } 00818 else 00819 { 00820 pDstLine = pSrcLine->FindNextLine(); 00821 ERROR2IF(pDstLine==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - no next line after soft line"); 00822 00823 pAttrSet = new AttrTypeSet(); 00824 if (ok) ok = pSrcLine->AddNonLineLevelDescendantAttrsToSet(pAttrSet); 00825 if (ok) ok = pDstLine->AddNonLineLevelDescendantAttrsToSet(pAttrSet); 00826 00827 if (ok) ok = pDstLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,FALSE,pAttrSet); 00828 } 00829 00830 // get context node and attach direction for attaching text as first objects in dest line 00831 Node* pAttachNode = pDstLine; 00832 AttachNodeDirection AttachDir = FIRSTCHILD; 00833 pDstLine->GetAttachNodeAndDirectionToAttachFirstChildObject(&pAttachNode,&AttachDir); 00834 00835 // localise on SrcLine, move text to DstLine, then factor out on both 00836 // Localise/FactorOut not global as attrs on story should never change 00837 if (ok) ok = pSrcLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,FALSE,pAttrSet); 00838 if (ok) ok = this->DoMoveNodes(pUndoOp, pLastVTNToMove, pAttachNode, AttachDir); 00839 if (ok) ok = pSrcLine->DoFactorOutCommonChildAttributes(pUndoOp,FALSE,pAttrSet); 00840 if (ok) ok = pDstLine->DoFactorOutCommonChildAttributes(pUndoOp,FALSE,pAttrSet); 00841 00842 if (pAttrSet!=NULL) 00843 { 00844 pAttrSet->DeleteAll(); 00845 delete pAttrSet; 00846 } 00847 00848 return ok; 00849 } 00850 00851 00852 /******************************************************************************************** 00853 > BOOL VisibleTextNode::WrapFromStartOfLineBack(UndoableOperation* pUndoOp) 00854 00855 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00856 Created: 8/7/96 00857 Inputs: pUndoOp - pointer to undoable operation 00858 Returns: FALSE if fails 00859 Purpose: Wrap all chars upto this VTN (inc) back to the end of the previous line 00860 If this line is then empty, hide it 00861 ********************************************************************************************/ 00862 00863 BOOL VisibleTextNode::WrapFromStartOfLineBack(UndoableOperation* pUndoOp) 00864 { 00865 // get info about this and previous line 00866 TextLine* pThisLine = this->FindParentLine(); 00867 ERROR2IF(pThisLine==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - pThisLine==NULL"); 00868 VisibleTextNode* pFirstVTN = pThisLine->FindFirstVTN(); 00869 ERROR2IF(pFirstVTN==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - no VTN on this line!"); 00870 TextLine* pPrevLine = pThisLine->FindPrevLine(); 00871 ERROR2IF(pPrevLine==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - pPrevLine==NULL"); 00872 ERROR2IF(pPrevLine->FindEOLNode()!=NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - trying to wrap back onto a hard line!"); 00873 00874 // get a set of non line level attrs, which are to be localised to char level 00875 AttrTypeSet NonLineLevelAttrs; 00876 BOOL ok = pThisLine->AddNonLineLevelDescendantAttrsToSet(&NonLineLevelAttrs); 00877 if (ok) ok = pPrevLine->AddNonLineLevelDescendantAttrsToSet(&NonLineLevelAttrs); 00878 00879 // move ALL the nodes from first VTN on line to this VTN back to end of prev line 00880 // if wrapping whole line back, hide the empty line 00881 // since previous line is soft assumes this and prev lines have same line level attrs 00882 // Localise/FactorOut global as Line Level attrs on story may change change 00883 BOOL WholeLine = (this->FindNextVTNInLine()==NULL); 00884 if (ok) ok = pThisLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,TRUE,&NonLineLevelAttrs); 00885 if (ok) ok = pPrevLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,TRUE,&NonLineLevelAttrs); 00886 if (ok) ok = pFirstVTN->DoMoveNodes(pUndoOp, this, pPrevLine, LASTCHILD); 00887 if (ok && WholeLine) ok = pThisLine->DoHideNode(pUndoOp); 00888 if (ok && !WholeLine) ok = pThisLine->DoFactorOutCommonChildAttributes(pUndoOp,TRUE,&NonLineLevelAttrs); 00889 if (ok) ok = pPrevLine->DoFactorOutCommonChildAttributes(pUndoOp,TRUE,&NonLineLevelAttrs); 00890 00891 return ok; 00892 } 00893 00894 00895 /******************************************************************************************** 00896 > BOOL VisibleTextNode::DoMoveNodes(UndoableOperation* pUndoOp, 00897 VisibleTextNode* pLastVTN, 00898 Node* pDestNode, 00899 AttachNodeDirection Direction) 00900 00901 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00902 Created: 7/2/96 00903 Inputs: pUndoOp - pointer to undoable operation (NULL if not undoable) 00904 pLastVTN - pointer to VTN after last node to move (must be on the same line as this) 00905 pDestNode - pointer to node to attach to 00906 Direction - direction to attach in 00907 Returns: FALSE if fails 00908 Purpose: Move ALL nodes from this VTN to LastVTN to pDestNode in the specified direction 00909 Assumes: First and last VTNs are on the same line 00910 Note: only VTN in range are moved so hidden nodes don't cause undo bloat! 00911 ********************************************************************************************/ 00912 00913 BOOL VisibleTextNode::DoMoveNodes(UndoableOperation* pUndoOp, 00914 VisibleTextNode* pLastVTN, 00915 Node* pDestNode, 00916 AttachNodeDirection Direction) 00917 { 00918 ERROR2IF( pLastVTN==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - pLastVTN==NULL"); 00919 ERROR2IF(pDestNode==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - pDestNode==NULL"); 00920 00921 // move all VTN in the range to the specified location 00922 // however, can only move the caret once there are are some cahrs on the new line 00923 Node* pPrevDestNode = pDestNode; 00924 VisibleTextNode* pSrcVTN = this; 00925 while (pPrevDestNode!=pLastVTN) 00926 { 00927 ERROR2IF(pSrcVTN==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - did not find pLastVTN"); 00928 VisibleTextNode* pNextSrcVTN = pSrcVTN->FindNextVTNInLine(); 00929 if (pSrcVTN->DoMoveNode(pUndoOp, pPrevDestNode, Direction)==FALSE) 00930 return FALSE; 00931 Direction = NEXT; // all subsequent VTN moved after previous 00932 pPrevDestNode = pSrcVTN; 00933 pSrcVTN = pNextSrcVTN; 00934 } 00935 00936 return TRUE; 00937 } 00938 00939 00940 /******************************************************************************************** 00941 > BOOL VisibleTextNode::DoMoveNode(UndoableOperation* pUndoOp, 00942 Node* pDestNode, 00943 AttachNodeDirection Direction) 00944 00945 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00946 Created: 7/2/96 00947 Inputs: pUndoOp - pointer to undoable operation (NULL if not undoable) 00948 pDestNode - pointer to node to attach to 00949 Direction - direction to attach in 00950 Returns: FALSE if fails 00951 Purpose: Move this VTN to the specified location, flagging it 'Affected' in 00952 the old and new position 00953 ********************************************************************************************/ 00954 00955 BOOL VisibleTextNode::DoMoveNode(UndoableOperation* pUndoOp, 00956 Node* pDestNode, 00957 AttachNodeDirection Direction) 00958 { 00959 ERROR2IF(pDestNode==NULL,FALSE,"VisibleTextNode::DoMoveNode() - pDestNode==NULL"); 00960 TextStory* pTextStory = this->FindParentStory(); 00961 ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::DoMoveNode() - caret has no parent story!"); 00962 00963 // flag node affected in old position (and parents) 00964 FlagNodeAndDescendantsAffectedAndParentsHaveDescendantAffected(); 00965 00966 // if selected, deselect to maintain 'parent of selected' flag 00967 BOOL selected = IsSelected(); 00968 if (selected) 00969 SetSelected(FALSE); 00970 00971 // if the caret (remember its position if undoable) always move it non-undoably 00972 // else just move the char, non-undoably if required 00973 // Note:must remember caret's old pos as if it is moved onto a new line, 00974 // when it is undone, the caret will be a child of the hidden line 00975 // and PrePostTextAction cannot cope with restoring the caret once hidden 00976 if (this->IsACaret()) 00977 { 00978 #if !defined(EXCLUDE_FROM_RALPH) 00979 if (pUndoOp!=NULL) 00980 if (!PositionCaretAction::DoStoreCaretPosition(pUndoOp,pTextStory)) 00981 return FALSE; 00982 #endif 00983 MoveNode(pDestNode,Direction); 00984 } 00985 else 00986 { 00987 if (pUndoOp==NULL) 00988 MoveNode(pDestNode,Direction); 00989 else 00990 if (pUndoOp->DoMoveNode(this, pDestNode, Direction)==FALSE) 00991 return FALSE; 00992 } 00993 00994 // if was selected, reselect to maintain 'parent of selected' flag 00995 if (selected) 00996 SetSelected(TRUE); 00997 00998 // flag node affected in new position (so parents flagged correctly) 00999 FlagNodeAndDescendantsAffectedAndParentsHaveDescendantAffected(); 01000 01001 return TRUE; 01002 } 01003 01004 01005 /******************************************************************************************** 01006 > void VisibleTextNode::ScrollToShow() 01007 01008 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01009 Created: 24/4/95 01010 Purpose: If this VTN is not fully on the screen then the screen is scrolled so the 01011 VTN is more visible. 01012 ********************************************************************************************/ 01013 01014 void VisibleTextNode::ScrollToShow() 01015 { 01016 #if !defined(EXCLUDE_FROM_RALPH) 01017 DocView* pDocView = DocView::GetSelected(); 01018 Spread* pSpread = FindParentSpread(); 01019 01020 if (pDocView!=NULL && pSpread!=NULL) 01021 { 01022 DocRect ScreenArea = GetBlobBoundingRect(); 01023 01024 // Get the extent of the current view and convert to spread coordinates. 01025 DocRect WorkArea = pDocView->GetDocViewRect(pSpread); 01026 pSpread->DocCoordToSpreadCoord(&WorkArea); 01027 01028 BOOL Scroll = FALSE; 01029 DocCoord WindowTopLeft; 01030 DocCoord Offset(0,0); // Amount to offset current TopLeft by 01031 01032 if (!WorkArea.ContainsRect(ScreenArea)) 01033 { 01034 if (WorkArea.Height() > ScreenArea.Height() && WorkArea.Width() > ScreenArea.Width()) 01035 { 01036 const double Shift = 0.05; 01037 01038 if (ScreenArea.hi.y > WorkArea.hi.y) 01039 Offset.y = ScreenArea.hi.y-WorkArea.hi.y + (INT32)(WorkArea.Height()*Shift); 01040 01041 if (ScreenArea.lo.y < WorkArea.lo.y) 01042 Offset.y = ScreenArea.lo.y-WorkArea.lo.y - (INT32)(WorkArea.Height()*Shift); 01043 01044 if (ScreenArea.hi.x > WorkArea.hi.x) 01045 Offset.x = ScreenArea.hi.x-WorkArea.hi.x + (INT32)(WorkArea.Width()*Shift); 01046 01047 if (ScreenArea.lo.x < WorkArea.lo.x) 01048 Offset.x = ScreenArea.lo.x-WorkArea.lo.x - (INT32)(WorkArea.Width()*Shift); 01049 01050 if (Offset != DocCoord(0,0)) 01051 { 01052 Scroll = TRUE; 01053 WindowTopLeft = DocCoord(WorkArea.lo.x, WorkArea.hi.y) + Offset; 01054 } 01055 } 01056 else 01057 { 01058 // Cannot contain object on screen. Centre it. 01059 Scroll = TRUE; 01060 DocCoord CentreOfObject((ScreenArea.lo.x+ScreenArea.hi.x)/2, (ScreenArea.lo.y+ScreenArea.hi.y)/2); 01061 01062 WindowTopLeft = DocCoord(CentreOfObject.x-WorkArea.Width()/2,CentreOfObject.y+WorkArea.Height()/2); 01063 } 01064 } 01065 01066 // Now scroll to the new position 01067 if (Scroll) 01068 { 01069 // First, ensure that the spread's pasteboard is large enough to include this node 01070 // This is pretty quick if it is big enough. 01071 pSpread->ExpandPasteboardToInclude(GetBoundingRect()); 01072 01073 // Convert the window coordinate from Spread to Document coords... 01074 pSpread->SpreadCoordToDocCoord(&WindowTopLeft); 01075 01076 // ...and thence to Logical coordinates 01077 WorkCoord WTL = WindowTopLeft.ToWork(pSpread, pDocView); 01078 pDocView->SetScrollOffsets(WTL, TRUE); 01079 01080 // New stuff added by Will 29/6/95 01081 // Now we have scrolled the View, we need to invalidate the newly visible areas, 01082 // so that any blob rendering knows that the area has a pending redraw. 01083 // If we wait for the Paint message from the OS, then it will be too late. 01084 01085 // First we get the new extent of the view we just scrolled and convert to spread coordinates. 01086 WorkArea = pDocView->GetDocViewRect(pSpread); 01087 pSpread->DocCoordToSpreadCoord(&WorkArea); 01088 01089 DocRect Invalid; 01090 01091 if (Offset.x != 0) 01092 { 01093 // Get the invalid horizontal scroll rect, by subtracting the x scroll offset 01094 // from the left or right edge of the screen (depending on which way we scrolled) 01095 Invalid.lo.x = Offset.x > 0 ? WorkArea.hi.x - Offset.x : WorkArea.lo.x; 01096 Invalid.lo.y = WorkArea.lo.y; 01097 Invalid.hi.x = Offset.x > 0 ? WorkArea.hi.x : WorkArea.lo.x - Offset.x; 01098 Invalid.hi.y = WorkArea.hi.y; 01099 01100 // and invalidate it 01101 pDocView->ForceRedraw(pSpread, Invalid); 01102 } 01103 01104 if (Offset.y != 0) 01105 { 01106 // Get the invalid vertical scroll rect, by subtracting the y scroll offset 01107 // from the top or bottom edge of the screen (depending on which way we scrolled) 01108 Invalid.lo.x = WorkArea.lo.x; 01109 Invalid.lo.y = Offset.y > 0 ? WorkArea.hi.y - Offset.y : WorkArea.lo.y; 01110 Invalid.hi.x = WorkArea.hi.x; 01111 Invalid.hi.y = Offset.y > 0 ? WorkArea.hi.y : WorkArea.lo.y - Offset.y; 01112 01113 // and invalidate it 01114 pDocView->ForceRedraw(pSpread, Invalid); 01115 } 01116 } 01117 } 01118 #endif 01119 } 01120 01121 01122 /******************************************************************************************** 01123 > virtual BOOL VisibleTextNode::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType) 01124 01125 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01126 Created: 7/6/95 01127 Inputs: AttrType: The type of the attribute. It is a type, rather than an 01128 instance because this function needs to be called from the Localise/Factor out 01129 routines which operate on attribute types. 01130 01131 Returns: TRUE if an attribute of AttrType can be applied to this object, 01132 FALSE otherwise. 01133 01134 Purpose: This fn is not to be confused with RequiresAttrib, it determines if an 01135 attribute of type AttrType can be directly applied to this object. The 01136 object is assumed to Require the attribute. 01137 01138 This function is called by the GetObjectToApplyTo virtual function. 01139 01140 The function returns FALSE if we are trying to apply a line level 01141 attribute to a VisibleTextNode. As a result attributes will get applied 01142 to the parent TextLine object. 01143 ********************************************************************************************/ 01144 01145 BOOL VisibleTextNode::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType) 01146 { 01147 return !TextLine::IsAttrTypeLineLevel(AttrType); 01148 } 01149 01150 01151 /******************************************************************************************** 01152 > virtual BOOL VisibleTextNode::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu) 01153 01154 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01155 Created: 06/10/95 01156 Inputs: pSpread The spread in which things are happening 01157 PointerPos The Location of the mouse pointer at the time of the click 01158 pMenu The menu to which items should be added 01159 Returns: BOOL - TRUE if the node claims the click as its own and FALSE if it is 01160 not interested in the click 01161 Purpose: Allows the VisibleTextNode to respond to pop up menu clicks on itself. 01162 ********************************************************************************************/ 01163 01164 BOOL VisibleTextNode::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu) 01165 { 01166 TextStory* pStory = this->FindParentStory(); 01167 01168 if (pStory!=NULL && pStory->IsSelected()) 01169 return pStory->OnNodePopUp(pSpread, PointerPos, pMenu); 01170 else 01171 return FALSE; 01172 } 01173 01174 01176 // AbstractTextChar methods 01177 01178 /******************************************************************************************** 01179 > void AbstractTextChar::Init() 01180 01181 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01182 Created: 3/2/96 01183 Purpose: common init function for constructors 01184 ********************************************************************************************/ 01185 01186 void AbstractTextChar::Init() 01187 { 01188 mCharWidth = 0; 01189 mCharAdvance = 0; 01190 mFontAscent = 0; 01191 mFontDescent = 0; 01192 mFontSize = 0; 01193 mBaseLineShift = 0; 01194 mAttrdCharBounds = DocRect(0,0,0,0); 01195 } 01196 01197 01198 /******************************************************************************************** 01199 > AbstractTextChar::AbstractTextChar() 01200 01201 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01202 Created: 21/12/94 01203 Purpose: Simple AbstractTextChar constructor, it is required so that SimpleCopy will work. 01204 ********************************************************************************************/ 01205 01206 AbstractTextChar::AbstractTextChar(): VisibleTextNode() // Call the base class 01207 { 01208 Init(); 01209 } 01210 01211 01212 /******************************************************************************************** 01213 > AbstractTextChar::AbstractTextChar(Node* ContextNode, AttachNodeDirection Direction, 01214 WCHAR ChCode) 01215 01216 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01217 Created: 21/12/94 01218 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 01219 01220 Direction: 01221 01222 Specifies the direction in which the node is to be attached to the 01223 ContextNode. The values this variable can take are as follows: 01224 01225 PREV : Attach node as a previous sibling of the context node 01226 NEXT : Attach node as a next sibling of the context node 01227 FIRSTCHILD: Attach node as the first child of the context node 01228 LASTCHILD : Attach node as a last child of the context node 01229 01230 ChCode: The UNICODE character to store in the TextChar node 01231 01232 Purpose: The main TextChar constructor 01233 ********************************************************************************************/ 01234 01235 AbstractTextChar::AbstractTextChar(Node* ContextNode, AttachNodeDirection Direction): 01236 VisibleTextNode(ContextNode, Direction) // call the base class 01237 { 01238 Init(); 01239 } 01240 01241 01242 /******************************************************************************************** 01243 > Node* AbstractTextChar::SimpleCopy() 01244 01245 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01246 Created: 21/12/94 01247 Returns: 01248 Purpose: Because this is an abstract class, the SimpleCopy method simply causes 01249 an ERROR3 to go off. 01250 ********************************************************************************************/ 01251 01252 Node* AbstractTextChar::SimpleCopy() 01253 { 01254 ERROR3("Calling abstract classes SimpleCopy"); 01255 01256 // Well I suppose we should do the copy if the call gets into the retail 01257 AbstractTextChar* NodeCopy = new AbstractTextChar(); 01258 01259 ERROR1IF(NodeCopy==NULL, NULL, _R(IDE_NOMORE_MEMORY)); 01260 01261 if (NodeCopy) 01262 CopyNodeContents(NodeCopy); 01263 01264 return NodeCopy; 01265 } 01266 01267 01268 01269 /*********************************************************************************************** 01270 > void AbstractTextChar::CopyNodeContents(AbstractTextChar* NodeCopy) 01271 01272 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01273 Created: 28/4/93 01274 Outputs: A copy of this node 01275 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 01276 Errors: An assertion failure will occur if NodeCopy is NULL 01277 ***********************************************************************************************/ 01278 01279 void AbstractTextChar::CopyNodeContents(AbstractTextChar* NodeCopy) 01280 { 01281 // Ask the base class to do its bit 01282 VisibleTextNode::CopyNodeContents( NodeCopy ); 01283 01284 // copy specifics 01285 NodeCopy->mCharWidth = mCharWidth; 01286 NodeCopy->mCharAdvance = mCharAdvance; 01287 NodeCopy->mFontAscent = mFontAscent; 01288 NodeCopy->mFontDescent = mFontDescent; 01289 NodeCopy->mFontSize = mFontSize; 01290 NodeCopy->mBaseLineShift = mBaseLineShift; 01291 NodeCopy->mAttrdCharBounds = mAttrdCharBounds; 01292 } 01293 01294 01295 /*********************************************************************************************** 01296 > void AbstractTextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01297 01298 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01299 Created: 18/12/2003 01300 Outputs: - 01301 Purpose: Polymorphically copies the contents of this node to another 01302 Errors: An assertion failure will occur if NodeCopy is NULL 01303 Scope: protected 01304 01305 ***********************************************************************************************/ 01306 01307 void AbstractTextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01308 { 01309 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 01310 ENSURE(IS_A(pNodeCopy, AbstractTextChar), "PolyCopyNodeContents given wrong dest node type"); 01311 01312 if (IS_A(pNodeCopy, AbstractTextChar)) 01313 CopyNodeContents((AbstractTextChar*)pNodeCopy); 01314 } 01315 01316 01317 01318 /******************************************************************************************** 01319 > String AbstractTextChar::Describe(BOOL Plural, BOOL Verbose = TRUE) 01320 01321 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01322 Created: 21/12/94 01323 Inputs: Plural: Singular or plural description 01324 Returns: A string describing the node 01325 Purpose: Gives a description of all character nodes 01326 ********************************************************************************************/ 01327 01328 String AbstractTextChar::Describe(BOOL Plural, BOOL Verbose) 01329 { 01330 if (Plural) 01331 return(String(_R(IDS_DESCRIBE_TEXTCHARP))); 01332 else 01333 return(String(_R(IDS_DESCRIBE_TEXTCHARS))); 01334 } 01335 01336 01337 /******************************************************************************************** 01338 > UINT32 AbstractTextChar::GetNodeSize() const 01339 01340 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01341 Created: 21/12/94 01342 Returns: The size of the node in bytes 01343 Purpose: For finding the size of the node 01344 ********************************************************************************************/ 01345 01346 UINT32 AbstractTextChar::GetNodeSize() const 01347 { 01348 ERROR3("Trying to find the size of an AbstractTextChar ?"); 01349 return (sizeof(AbstractTextChar)); 01350 } 01351 01352 01353 /******************************************************************************************** 01354 > void AbstractTextChar::GetDebugDetails(StringBase* Str) 01355 01356 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01357 Created: 1/2/95 01358 Outputs: Str: String giving debug info about the node 01359 Purpose: For obtaining debug information about the Node. 01360 This fn can be deleted before we ship 01361 ********************************************************************************************/ 01362 01363 void AbstractTextChar::GetDebugDetails(StringBase* Str) 01364 { 01365 VisibleTextNode::GetDebugDetails(Str); 01366 } 01367 01368 01369 /******************************************************************************************** 01370 > virtual DocRect AbstractTextChar::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE) 01371 01372 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01373 Created: 22/3/94 01374 Inputs: DontUseAttrs - indicates that bounds of attributes applied to node should be ignored 01375 Defaults to FALSE 01376 HitTest - TRUE if being called during HitTest 01377 Returns: The characters bounding rect 01378 Purpose: Gets the bounds of the char 01379 if the cached bounds are invalid, they are recalculated 01380 ********************************************************************************************/ 01381 01382 DocRect AbstractTextChar::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest) 01383 { 01384 // if not hit testing, attrs should be included and cache is valid, return cached value 01385 if (HitTest==FALSE && DontUseAttrs==FALSE && IsBoundingRectValid) 01386 return BoundingRectangle; 01387 01388 BOOL ok=TRUE; 01389 DocRect TempBounds; 01390 if (HitTest) 01391 ok=GetMetricsRectBounds(&TempBounds); 01392 else 01393 { 01394 // get the matrix to transform the char to the correct point in the doc 01395 Matrix matrix; 01396 ok=GetStoryAndCharMatrix(&matrix); 01397 01398 // get attr'd-char bounds from node, and transform them 01399 TempBounds=GetAttrdCharBounds(); 01400 if (ok) ok=matrix.TransformBounds(&TempBounds); 01401 01402 // if including attrs, account for line width and recache bounds 01403 NodeAttribute* pAttr; 01404 if (ok && DontUseAttrs==FALSE && FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), &pAttr)) 01405 { 01406 // get width of line and inflate bounds 01407 LineWidthAttribute* pLineWidthAttr=(LineWidthAttribute*)(pAttr->GetAttributeValue()); 01408 TempBounds.Inflate( (MILLIPOINT)(pLineWidthAttr->LineWidth)/2 ); 01409 01410 // update value in cache and flag valid 01411 BoundingRectangle = TempBounds; 01412 IsBoundingRectValid = TRUE; 01413 } 01414 // now we must also account for brush attributes 01415 NodeAttribute* pBrushAttr = NULL; 01416 if (ok && DontUseAttrs == FALSE && FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pBrushAttr)) 01417 { 01418 DocRect BrushRect = ((AttrBrushType*)pBrushAttr)->GetAttrBoundingRect(this); 01419 BoundingRectangle = BoundingRectangle.Union(BrushRect); 01420 IsBoundingRectValid = TRUE; 01421 } 01422 } 01423 01424 // report any errors which occurred, and return the bounding box 01425 if (!ok) InformError(); 01426 return TempBounds; 01427 } 01428 01429 01430 /******************************************************************************************** 01431 > DocRect AbstractTextChar::GetBlobBoundingRect() 01432 01433 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01434 Created: 2/4/95 01435 Returns: DocRect - Returns the bounding rect of the char and its blobs 01436 Purpose: Calculates the blob bounding box of the char based on its metrics 01437 Irrespective of their visibility 01438 ********************************************************************************************/ 01439 01440 DocRect AbstractTextChar::GetBlobBoundingRect() 01441 { 01442 DocRect Bounds(0,0,0,0); 01443 if (GetMetricsRectBounds(&Bounds)==FALSE) 01444 return GetBoundingRect(); 01445 01446 IncludeChildrensBoundingRects(&Bounds); 01447 return Bounds; 01448 } 01449 01450 /******************************************************************************************** 01451 > virtual DocRect AbstractTextChar::GetImagemapClickableRectangle() 01452 01453 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 01454 Created: 27/3/97 01455 Inputs: - 01456 Returns: The bounding rectangle of this character and all adjacent characters 01457 in the same line with the same Web Address attribute 01458 Purpose: Used to get the clickable area of this character for an imagemap. 01459 01460 The clickable area of this character is defined as the bounding 01461 rectangle of all adjacent characters with the same Web Address attribute. 01462 This is so that sequences of characters with the same Web Address attribute 01463 present a single clickable area, rather than a lot of separate areas. 01464 01465 The way it does this is by calling our helper function 01466 GetImagemapRectForAdjacentChars twice: once to get the 01467 clickable rectangle of the characters before this, once 01468 to get the clickable rectangle of the characters after this. 01469 01470 ********************************************************************************************/ 01471 01472 DocRect AbstractTextChar::GetImagemapClickableRectangle() 01473 { 01474 DocRect rectPrevious=GetImagemapRectForAdjacentChars(FALSE); 01475 DocRect rectNext=GetImagemapRectForAdjacentChars(TRUE); 01476 01477 rectPrevious=rectPrevious.Union(rectNext); 01478 01479 return rectPrevious; 01480 } 01481 01482 /******************************************************************************************** 01483 > virtual DocRect AbstractTextChar::GetImagemapRectForAdjacentChars(BOOL fForwards) 01484 01485 Author: Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com> 01486 Created: 27/3/97 01487 Inputs: fForwards TRUE for the characters after this one 01488 FALSE for the character before this one 01489 Returns: The bounding rectangle of this character and all characters 01490 (before/after) this one in this line with the same 01491 Web Address attribute. 01492 01493 Purpose: Called by GetImagemapClickableRectangle to get the clickable rectangle 01494 for this character and all the adjacent characters with the same 01495 WebAddress attribute. 01496 01497 SeeAlso: AbstractTextChar::GetImagemapClickableRectangle() 01498 01499 ********************************************************************************************/ 01500 01501 DocRect AbstractTextChar::GetImagemapRectForAdjacentChars(BOOL fForwards) 01502 { 01503 //First set up a pointer to the node we're currently looking at. 01504 //It will start at this text character 01505 //and scan either forwards or backwards 01506 AbstractTextChar* patcLookNode=this; 01507 01508 //This flag tells us whether we are pointing at a character with 01509 //the same Web Address attribute as this one 01510 BOOL fSameAttribute=TRUE; 01511 01512 //And this is the DocRect we will return 01513 DocRect rectToReturn=GetBoundingRect(FALSE, TRUE); 01514 01515 //And let's find the Web Address attribute applied to this character 01516 AttrWebAddress* pwaThisAttribute=NULL; 01517 01518 FindAppliedAttribute(CC_RUNTIME_CLASS(AttrWebAddress), (NodeAttribute**) &pwaThisAttribute); 01519 01520 //While the node we're looking at exists, and has the same 01521 //Web Address attribute applied to it as this one 01522 while (patcLookNode && fSameAttribute) 01523 { 01524 //Then get the bounding box of that node 01525 DocRect rectLookNode=patcLookNode->GetBoundingRect(FALSE,TRUE); 01526 01527 //Expand our rectangle to return to include that bounding box 01528 rectToReturn=rectToReturn.Union(rectLookNode); 01529 01530 //Then move the pointer either forwards or backwards 01531 if (fForwards) 01532 patcLookNode=patcLookNode->FindNextAbstractTextCharInLine(); 01533 else 01534 patcLookNode=patcLookNode->FindPrevAbstractTextCharInLine(); 01535 01536 //Now, if we are still looking at a node 01537 if (patcLookNode) 01538 { 01539 //Then find the attribute applied to that node 01540 AttrWebAddress* pwaLookAttribute=NULL; 01541 01542 patcLookNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrWebAddress), (NodeAttribute**) &pwaLookAttribute); 01543 ERROR2IF(pwaLookAttribute==NULL, DocRect(0,0,0,0), "AbstractTextChar::GetImagemapRectForAdjacentChars got no applied attribute!"); 01544 01545 //And test whether it's the same as the attribute applied to this node 01546 fSameAttribute=(*pwaLookAttribute==*pwaThisAttribute); 01547 } 01548 } 01549 01550 //Then return the rectangle we've created 01551 return rectToReturn; 01552 } 01553 01554 01555 /******************************************************************************************** 01556 > void AbstractTextChar::RenderObjectBlobs(RenderRegion* pRenderRegion) 01557 01558 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01559 Created: 2/4/95 01560 Inputs: pRenderRegion - region to render the blobs into 01561 Purpose: Renders the selection blobs 01562 ********************************************************************************************/ 01563 01564 void AbstractTextChar::RenderObjectBlobs(RenderRegion* pRenderRegion) 01565 { 01566 #if !defined(EXCLUDE_FROM_RALPH) 01567 Path* pPath=CreateMetricsRectPath(); 01568 if (pPath!=NULL && pRenderRegion!=NULL) 01569 { 01570 DocColour Trans(COLOUR_TRANS); 01571 pRenderRegion->SetLineWidth(0); 01572 pRenderRegion->SetLineColour(Trans); 01573 pRenderRegion->SetFillColour(COLOUR_UNSELECTEDBLOB); 01574 pRenderRegion->DrawPath(pPath); 01575 delete pPath; 01576 } 01577 #endif 01578 } 01579 01580 01581 /******************************************************************************************** 01582 > void AbstractTextChar::RenderTinyBlobs(RenderRegion* pRenderRegion) 01583 01584 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 01585 Created: 3/4/95 01586 Inputs: pRenderRegion - region to render the blobs into 01587 Purpose: Renders the tiny blob, which is an outline selection box 01588 ********************************************************************************************/ 01589 01590 void AbstractTextChar::RenderTinyBlobs(RenderRegion* pRenderRegion) 01591 { 01592 #if !defined(EXCLUDE_FROM_RALPH) 01593 Path* pPath=CreateMetricsRectPath(); 01594 if (pPath!=NULL && pRenderRegion!=NULL) 01595 { 01596 DocColour Trans(COLOUR_TRANS); 01597 pRenderRegion->SetLineColour(COLOUR_UNSELECTEDBLOB); 01598 pRenderRegion->SetFillColour(Trans); 01599 pRenderRegion->DrawPath(pPath); 01600 delete pPath; 01601 } 01602 #endif 01603 } 01604 01605 01606 /******************************************************************************************** 01607 > BOOL AbstractTextChar::GetMetricsRect(DocRect* pRect) 01608 01609 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01610 Created: 3/4/95 01611 Outputs pRect - 01612 Returns: FALSE if fails 01613 Purpose: return the metrics rect of a char 01614 ********************************************************************************************/ 01615 01616 BOOL AbstractTextChar::GetMetricsRect(DocRect* pRect) 01617 { 01618 ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRect() - pRect==NULL"); 01619 01620 TextLine* pTextLine=(TextLine*)FindParent(); 01621 ERROR2IF(pTextLine==NULL,FALSE,"AbstractTextChar::GetMetricsRect - pTextLine==NULL"); 01622 01623 // get a rect (relative to the TextStory) from the bottom left to top right of the char 01624 pRect->lo.y = pTextLine->GetLineDescent(); 01625 pRect->hi.y = pTextLine->GetLineAscent(); 01626 pRect->lo.x = 0; 01627 pRect->hi.x = 0; 01628 MILLIPOINT advance=GetVisibleAdvance(); 01629 if (advance>=0) 01630 pRect->hi.x = advance; 01631 else 01632 pRect->lo.x = advance; 01633 01634 return TRUE; 01635 } 01636 01637 01638 /******************************************************************************************** 01639 > BOOL AbstractTextChar::GetMetricsRectInStory(DocRect* pRect) 01640 01641 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01642 Created: 3/4/95 01643 Outputs pRect - 01644 Returns: FALSE if fails 01645 Purpose: return the metrics rect of a char relative to the TextStory 01646 Note: Not valid for text on a path!! 01647 ********************************************************************************************/ 01648 01649 BOOL AbstractTextChar::GetMetricsRectInStory(DocRect* pRect) 01650 { 01651 ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRectInStory() - pRect==NULL"); 01652 01653 if (GetMetricsRect(pRect)==FALSE) 01654 return FALSE; 01655 01656 // make it relative to the story! 01657 GetpMatrix()->transform((Coord*)&(pRect->lo),2); 01658 01659 return TRUE; 01660 } 01661 01662 01663 /******************************************************************************************** 01664 > BOOL AbstractTextChar::GetMetricsRectBounds(DocRect* pRect) 01665 01666 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01667 Created: 3/4/95 01668 Outputs pRect - 01669 Returns: FALSE if fails 01670 Purpose: return the bounds in the doc of the char's metrics rect 01671 ********************************************************************************************/ 01672 01673 BOOL AbstractTextChar::GetMetricsRectBounds(DocRect* pRect) 01674 { 01675 ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRectInStory() - pRect==NULL"); 01676 01677 Matrix matrix; 01678 if (GetStoryAndCharMatrix(&matrix)==FALSE) 01679 return FALSE; 01680 01681 if (GetMetricsRect(pRect)==FALSE) 01682 return FALSE; 01683 01684 if (matrix.TransformBounds(pRect)==FALSE) 01685 return FALSE; 01686 01687 return TRUE; 01688 } 01689 01690 01691 /******************************************************************************************** 01692 > Path* AbstractTextChar::CreateMetricsRectPath() 01693 01694 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01695 Created: 19/3/95 01696 Returns: pointer to path (or NULL if fails) 01697 Purpose: creates a rectangular path the advance width of a char and 01698 the height of a line transformed to the correct point in the doc 01699 ********************************************************************************************/ 01700 01701 Path* AbstractTextChar::CreateMetricsRectPath() 01702 { 01703 DocRect rect(0,0,0,0); 01704 if (GetMetricsRect(&rect)==FALSE) 01705 return FALSE; 01706 01707 // create the path 01708 Path* pBoundsPath=new Path(); 01709 BOOL ok=(pBoundsPath!=NULL); 01710 if (ok) ok=pBoundsPath->Initialise(6,12); 01711 if (ok) ok=pBoundsPath->AddMoveTo(rect.lo); 01712 if (ok) ok=pBoundsPath->AddLineTo(DocCoord(rect.hi.x,rect.lo.y)); // bottom line 01713 if (ok) ok=pBoundsPath->AddLineTo(rect.hi); // right side 01714 if (ok) ok=pBoundsPath->AddLineTo(DocCoord(rect.lo.x,rect.hi.y)); // top line 01715 if (ok) ok=pBoundsPath->AddLineTo(rect.lo); // left side 01716 if (ok) ok=pBoundsPath->CloseSubPath(); 01717 if (ok) pBoundsPath->IsFilled=TRUE; 01718 01719 // transform path to correct point in doc 01720 Matrix matrix; 01721 if (ok) ok=GetStoryAndCharMatrix(&matrix); 01722 DocCoord* pPathCoords=NULL; 01723 if (ok) pPathCoords=pBoundsPath->GetCoordArray(); 01724 if (ok) ok=(pPathCoords!=NULL); 01725 if (ok) matrix.transform((Coord*)pPathCoords, pBoundsPath->GetNumCoords()); 01726 01727 // if not OK, delete path and set return path pointer to NULL 01728 if (!ok) 01729 { 01730 delete pBoundsPath; 01731 pBoundsPath=NULL; 01732 } 01733 01734 return pBoundsPath; 01735 } 01736 01737 /******************************************************************************************** 01738 > BOOL AbstractTextChar::ReCacheMetrics(FormatRegion* pFormatRegion) 01739 01740 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01741 Created: 2/2/96 01742 Inputs: pFormatRegion - 01743 Returns: FALSE if fails 01744 Purpose: Recache metrics (and AttrdCharBound) in AbstractTextChars 01745 ********************************************************************************************/ 01746 01747 BOOL AbstractTextChar::ReCacheMetrics(FormatRegion* pFormatRegion) 01748 { 01749 #ifndef DISABLE_TEXT_RENDERING 01750 // get metrics for this char with current attribute stack 01751 CharMetrics metrics; 01752 if (pFormatRegion->GetCharMetrics(&metrics,GetUnicodeValue())==FALSE) 01753 return FALSE; 01754 01755 // set font ascent, descent and size 01756 SetFontAscent( metrics.FontAscent); 01757 SetFontDescent(metrics.FontDescent); 01758 SetFontSize(pFormatRegion->GetFontSize()); 01759 SetBaseLineShift(pFormatRegion->GetBaseLineShift()); 01760 01761 // set char width and advance width inc tracking ... 01762 if (IS_A(this,KernCode)) 01763 { 01764 INT32 KernInEmBy1000 = ((KernCode*)this)->GetValue().x; 01765 MILLIPOINT KernInMP = MulDiv(KernInEmBy1000, metrics.FontEmWidth, 1000); 01766 SetCharWidth(KernInMP); 01767 SetCharAdvance(GetCharWidth()); 01768 } 01769 else if (IS_A(this,HorizontalTab)) 01770 { 01771 /* tab widths are not dependent on attributes, so do not do anything */ 01772 } 01773 else if (this->IsAnEOLNode()) 01774 { 01775 SetCharWidth(0); 01776 SetCharAdvance(0); 01777 } 01778 else 01779 { 01780 SetCharWidth(metrics.CharWidth); 01781 MILLIPOINT TrackingInMP = 0; 01782 MILLIPOINT TrackingInEmBy1000 = pFormatRegion->GetTracking(); 01783 if (TrackingInEmBy1000 !=0 ) 01784 TrackingInMP = MulDiv(TrackingInEmBy1000, metrics.FontEmWidth, 1000); 01785 01786 TextStory *story = FindParentStory(); 01787 if (story) 01788 { 01789 if (story->IsAutoKerning()) 01790 SetCharAdvance(GetCharWidth()+TrackingInMP+GetAutoKernSize(pFormatRegion)); 01791 else 01792 SetCharAdvance(GetCharWidth()+TrackingInMP); 01793 } 01794 else 01795 ERROR3("Can't find base story"); 01796 } 01797 01798 // set AttrdCharBounds (if zero size (or kern code), set to sensible size for hit test) 01799 DocRect AttrdCharBounds(0,0,0,0); 01800 if (!IS_A(this,KernCode) && !IS_A(this,HorizontalTab)) 01801 if (pFormatRegion->GetAttrdCharBounds(&AttrdCharBounds,GetUnicodeValue())==FALSE) 01802 return FALSE; 01803 if (AttrdCharBounds.IsEmpty()) 01804 AttrdCharBounds.hi = DocCoord(GetCharAdvance(),pFormatRegion->GetFontSize()/3); 01805 SetAttrdCharBounds(AttrdCharBounds); 01806 #endif 01807 return TRUE; 01808 } 01809 01810 01811 /******************************************************************************************** 01812 > MILLIPOINT AbstractTextChar::GetVisibleAdvance() 01813 01814 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01815 Created: 16/4/95 01816 Returns: pointer to path (or NULL if fails) 01817 Purpose: get the visible advance with of the char 01818 ie advance width less last char tracking if at end of line 01819 ********************************************************************************************/ 01820 01821 MILLIPOINT AbstractTextChar::GetVisibleAdvance() 01822 { 01823 if (IS_A(this,TextChar) && FindNext(CC_RUNTIME_CLASS(AbstractTextChar))==NULL) 01824 return GetCharWidth(); 01825 01826 return GetCharAdvance(); 01827 } 01828 01829 01831 // TextChar methods 01832 01833 /******************************************************************************************** 01834 > TextChar::TextChar() 01835 01836 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01837 Created: 21/12/94 01838 Purpose: Simple TextChar constructor, it is required so that SimpleCopy will work. 01839 You should not normally call this constructor as it does not initialise 01840 the object. 01841 ********************************************************************************************/ 01842 01843 TextChar::TextChar(): AbstractTextChar() 01844 { 01845 Ch = _T('\0'); 01846 } 01847 01848 01849 /******************************************************************************************** 01850 > TextChar::TextChar(Node* ContextNode, AttachNodeDirection Direction) 01851 01852 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01853 Created: 21/12/94 01854 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 01855 01856 Direction: 01857 01858 Specifies the direction in which the node is to be attached to the 01859 ContextNode. The values this variable can take are as follows: 01860 01861 PREV : Attach node as a previous sibling of the context node 01862 NEXT : Attach node as a next sibling of the context node 01863 FIRSTCHILD: Attach node as the first child of the context node 01864 LASTCHILD : Attach node as a last child of the context node 01865 01866 Purpose: The main TextChar constructor 01867 ********************************************************************************************/ 01868 01869 TextChar::TextChar(Node* ContextNode, AttachNodeDirection Direction, 01870 WCHAR ChCode): AbstractTextChar(ContextNode, Direction) 01871 { 01872 Ch = ChCode; 01873 } 01874 01875 01876 /******************************************************************************************** 01877 > Node* TextChar::SimpleCopy() 01878 01879 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01880 Created: 21/12/94 01881 Returns: A copy of the node, or NULL if we are out of memory 01882 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 01883 The function is virtual, and must be defined for all derived classes of Node 01884 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 01885 error and the function returns NULL. 01886 ********************************************************************************************/ 01887 01888 Node* TextChar::SimpleCopy() 01889 { 01890 // Make a new BigChar and then copy things into it 01891 TextChar* NodeCopy = new TextChar(); 01892 01893 ERROR1IF(NodeCopy==NULL, NULL, _R(IDE_NOMORE_MEMORY)); 01894 01895 if (NodeCopy) 01896 CopyNodeContents(NodeCopy); 01897 01898 return NodeCopy; 01899 } 01900 01901 01902 /*********************************************************************************************** 01903 > void TextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01904 01905 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01906 Created: 18/12/2003 01907 Outputs: - 01908 Purpose: Polymorphically copies the contents of this node to another 01909 Errors: An assertion failure will occur if NodeCopy is NULL 01910 Scope: protected 01911 01912 ***********************************************************************************************/ 01913 01914 void TextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01915 { 01916 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 01917 ENSURE(IS_A(pNodeCopy, TextChar), "PolyCopyNodeContents given wrong dest node type"); 01918 01919 if (IS_A(pNodeCopy, TextChar)) 01920 CopyNodeContents((TextChar*)pNodeCopy); 01921 } 01922 01923 01924 01925 /*********************************************************************************************** 01926 > void TextChar::CopyNodeContents(TextChar* NodeCopy) 01927 01928 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01929 Created: 28/4/93 01930 Outputs: A copy of this node 01931 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 01932 Errors: An assertion failure will occur if NodeCopy is NULL 01933 ***********************************************************************************************/ 01934 01935 void TextChar::CopyNodeContents(TextChar* NodeCopy) 01936 { 01937 // Ask the base class to do its bit 01938 AbstractTextChar::CopyNodeContents( NodeCopy ); 01939 // Copy the rest of the data in here 01940 NodeCopy->Ch = Ch; 01941 } 01942 01943 01944 /******************************************************************************************** 01945 > UINT32 TextChar::GetNodeSize() const 01946 01947 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01948 Created: 21/12/94 01949 Returns: The size of the node in bytes 01950 Purpose: For finding the size of the node 01951 ********************************************************************************************/ 01952 01953 UINT32 TextChar::GetNodeSize() const 01954 { 01955 return (sizeof(TextChar)); 01956 } 01957 01958 01959 /******************************************************************************************** 01960 > void TextChar::GetDebugDetails(StringBase* Str) 01961 01962 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 01963 Created: 1/2/95 01964 Outputs: Str: String giving debug info about the node 01965 Purpose: For obtaining debug information about the Node. 01966 This fn can be deleted before we ship 01967 ********************************************************************************************/ 01968 01969 void TextChar::GetDebugDetails(StringBase* Str) 01970 { 01971 #ifdef _DEBUG 01972 AbstractTextChar::GetDebugDetails(Str); 01973 String_256 TempStr; 01974 01975 TempStr._MakeMsg( TEXT( "\r\nUnicode Ch code = #1%u ('#2%c')"),Ch, (Ch<256) ? Ch : ' ' ); 01976 (*Str) += TempStr; 01977 #endif 01978 } 01979 01980 01981 /******************************************************************************************** 01982 > virtual void TextChar::Render(RenderRegion* pRenderRegion) 01983 01984 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01985 Created: 19/3/95 01986 Inputs: pRenderRegion - RenderRegion with current attributes stack 01987 Purpose: render a TextChar with the current attributes specified in the RenderRegion 01988 ********************************************************************************************/ 01989 01990 void TextChar::Render(RenderRegion* pRenderRegion) 01991 { 01992 if (RenderCore(pRenderRegion)==FALSE) 01993 { 01994 // Mike 6/10/95: removed this call as it causes big problems if redraw fails 01995 // InformError(); 01996 } 01997 } 01998 01999 02000 /******************************************************************************************** 02001 > BOOL TextChar::RenderCore(RenderRegion* pRenderRegion) 02002 02003 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02004 Created: 19/3/95 02005 Inputs: pRenderRegion - RenderRegion with current attributes stack 02006 Returns: FALSE if fails 02007 Purpose: render a TextChar with the current attributes specified in the RenderRegion 02008 ********************************************************************************************/ 02009 02010 BOOL TextChar::RenderCore(RenderRegion* pRenderRegion) 02011 { 02012 #ifndef DISABLE_TEXT_RENDERING 02013 ERROR2IF(pRenderRegion == NULL, FALSE, "TextChar::RenderCore() - pRenderRegion == NULL"); 02014 02015 // TRACEUSER("wuerthne", _T("TextChar::RenderCore %04x"), GetUnicodeValue()); 02016 // If the render region is being used for hit detection then render bounds 02017 // BODGE TEXT - should be in the render region RenderChar function 02018 if (pRenderRegion->IsHitDetect() && 02019 pRenderRegion->RRQuality.GetLineQuality() != Quality::BlackLine && 02020 Tool::GetCurrentID() == TOOLID_TEXT) 02021 { 02022 Path* pPath = CreateMetricsRectPath(); 02023 ERROR2IF(pPath == NULL, FALSE, "TextChar::RenderCore() - CreateMetricsRectPath() failed"); 02024 pRenderRegion->SaveContext(); 02025 pRenderRegion->SetFillColour(COLOUR_BLACK); 02026 pRenderRegion->DrawPath(pPath); 02027 pRenderRegion->RestoreContext(); 02028 delete pPath; 02029 return TRUE; 02030 } 02031 02032 Matrix matrix; 02033 if (GetStoryAndCharMatrix(&matrix) == FALSE) return FALSE; 02034 02035 // render the character through the matrix with current attributes in RenderRegion 02036 02037 // If the render region is a printing region then maybe print as shapes. 02038 if (pRenderRegion->IsPrinting()) 02039 { 02040 PrintControl* pCtrl = pRenderRegion->GetRenderView()->GetPrintControl(); 02041 TextStory* pStory = this->FindParentStory(); 02042 if ((pCtrl != NULL && pCtrl->GetTextOptions() == PRINTTEXTOPTIONS_ALLTEXTASSHAPES) || 02043 (pStory != NULL && pStory->IsPrintingAsShapes())) 02044 { 02045 return pRenderRegion->RenderRegion::RenderChar(GetUnicodeValue(), &matrix); 02046 } 02047 } 02048 02049 // if we're exporting to illustrator, make the text position relative to 02050 // the page. 02051 if (pRenderRegion->IsKindOf (CC_RUNTIME_CLASS(AIEPSRenderRegion))) 02052 { 02053 // (ChrisG 14/12/00) - Only transform if we're not exporting text as shapes, as this 02054 // will be done in CreateCharPath - in AIEPSRenderRegion::RenderChar 02055 if (((AIEPSRenderRegion *) pRenderRegion)->GetTextAsShapes () == FALSE) 02056 { 02057 DocCoord pos; 02058 matrix.GetTranslation(pos); 02059 02060 Spread* pCurSpread = FindParentSpread(); 02061 if (pCurSpread) 02062 { 02063 DocCoord result; 02064 pCurSpread->SpreadCoordToPagesCoord(&result, pos); 02065 matrix.SetTranslation(result); 02066 } 02067 } 02068 } 02069 02070 // Render into the given region region as characters 02071 BOOL Result = pRenderRegion->RenderChar(GetUnicodeValue(), &matrix); 02072 02073 #if EXPORT_TEXT 02074 02075 // Graeme (27/4/00) - This piece of code is here to fix a problem with the export of 02076 // paragraph text to an EPS varient file. Basically, because only the last line in a 02077 // paragraph is terminated by a line feed, the export filter isn't recognising that 02078 // there is a break, and so all the text appears on one line. This new piece of code 02079 // fixes the problem. 02080 02081 // This goes horribly wrong if it's printing to distiller, which picks up the paragraph 02082 // width anyway, making this only relevant for exporting eps files... 02083 if (pRenderRegion->IsPrinting () == FALSE) 02084 { 02085 // Determine whether this is the last node in a text line. 02086 if ( FindNextVTNInLine () == NULL ) 02087 { 02088 // Manually output a newline token. 02089 Result = pRenderRegion->WriteNewLine (); 02090 } 02091 } // if not printing (i.e. doing export) 02092 02093 #endif // EXPORT_TEXT 02094 02095 return Result; 02096 #else 02097 return FALSE; 02098 #endif 02099 } 02100 02101 02102 /******************************************************************************************** 02103 > void TextChar::RenderEorDrag(RenderRegion* pRenderRegion) 02104 02105 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02106 Created: 27/03/95 02107 Inputs: pRenderRegion - region to render the blobs into 02108 Purpose: Renders the selection blobs for this TextChar 02109 ********************************************************************************************/ 02110 02111 void TextChar::RenderEorDrag(RenderRegion* pRenderRegion) 02112 { 02113 #if !defined(EXCLUDE_FROM_RALPH) && !defined(DISABLE_TEXT_RENDERING) 02114 // Before rendering the character we need to render its applied *TEXT* attributes 02115 // into the render region as EOR drag render regions don't maintain an attribute stack 02116 CCAttrMap* pAttribMap = new CCAttrMap(30); 02117 BOOL FoundAttributes = FALSE; 02118 if (pAttribMap) 02119 FoundAttributes = FindAppliedAttributes(pAttribMap); 02120 02121 if (FoundAttributes) 02122 { 02123 pRenderRegion->SaveContext(); 02124 // Render the text attributes 02125 CCAttrMap::iterator pos = pAttribMap->GetStartPosition(); 02126 CCAttrMap::iterator end = pAttribMap->GetEndPosition(); 02127 02128 while (pos != end) 02129 { 02130 CCRuntimeClass *pKey; 02131 void *pVal; 02132 pAttribMap->GetNextAssoc(pos, pKey, pVal); 02133 02134 if (((NodeAttribute*)pVal)->IsKindOfTextAttribute()) 02135 ((NodeAttribute*)pVal)->Render(pRenderRegion); 02136 } 02137 } 02138 02139 // Render the character 02140 if (RenderCore(pRenderRegion)==FALSE) 02141 InformError(); 02142 02143 if (FoundAttributes) 02144 pRenderRegion->RestoreContext(); 02145 02146 if (pAttribMap!=NULL) delete pAttribMap; 02147 #endif 02148 } 02149 02150 /******************************************************************************************** 02151 02152 > virtual BOOL TextChar::ExportRender ( RenderRegion *pRegion ) 02153 02154 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 02155 Created: 13/10/99 02156 Inputs: pRegion - A pointer to a RenderRegion. 02157 Outputs: - 02158 Returns: TRUE if the RenderRegion is a FlashRenderRegion, otherwise FALSE. 02159 Purpose: If pRenderRegion points to a FlashRenderRegion, the character will be 02160 processed as a Flash character, and ultimately stored in the export file 02161 in the appropriate manner. (As a set of three records: One referring to 02162 the paths, one mapping the paths onto characters, and one detailling the 02163 text string itself. 02164 02165 ********************************************************************************************/ 02166 02167 BOOL TextChar::ExportRender ( RenderRegion *pRegion ) 02168 { 02169 BOOL bResult = FALSE; 02170 02171 // If the RenderRegion is a FlashRenderRegion, use custom Flash export code. 02172 if ( pRegion->IsKindOf ( CC_RUNTIME_CLASS ( FlashRenderRegion ) ) ) 02173 { 02174 // Step 1: Cast the pRegion pointer to be a FlashRenderRegion pointer, so that 02175 // it can access the custom Flash export methods. 02176 FlashRenderRegion *pFlash = ( FlashRenderRegion* ) pRegion; 02177 02178 // Step 1a: If the character supports fill or line types that are unsupported by 02179 // Flash, return FALSE, and export them as paths. 02180 // (Option, may add later.) 02181 02182 // Step 2: Pass the character into the appropriate method to export the character. 02183 // This is where all the hard work is done. 02184 bResult = pFlash->ExportCharacter ( this ); 02185 } 02186 02187 // Step 3: The export has been done successfully. Return TRUE to prevent Camelot 02188 // from rendering the character out as paths as well as text. (If there's 02189 // been an error, bResult will have been set to FALSE.) 02190 return bResult; 02191 } 02192 02193 /******************************************************************************************** 02194 > BOOL TextChar::CreateNodePath(NodePath** ppNodePath, FormatRegion* pFormatRegion) 02195 02196 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02197 Created: 30/3/95 02198 Inputs: pFormatRegion - format region with current attr stack 02199 Outputs: ppNodePath - pointer to NodePath (may be NULL if none - eg a space!) 02200 Returns: FALSE if fails 02201 Purpose: Transforms the TextChar into a NodePath 02202 ********************************************************************************************/ 02203 02204 BOOL TextChar::CreateNodePath(NodePath** ppNodePath, FormatRegion* pFormatRegion) 02205 { 02206 #ifndef DISABLE_TEXT_RENDERING 02207 ERROR2IF(pFormatRegion==NULL,FALSE,"TextChar::CreateNodePath() - pFormatRegion==NULL"); 02208 ERROR2IF( ppNodePath==NULL,FALSE,"TextChar::CreateNodePath() - ppNodePath==NULL"); 02209 02210 // get the char's path transformed to the correct place inthe doc 02211 Matrix matrix; 02212 if (GetStoryAndCharMatrix(&matrix)==FALSE) 02213 return FALSE; 02214 Path* pPath=pFormatRegion->CreateCharPath(GetUnicodeValue(), &matrix); 02215 if (pPath==NULL) 02216 return FALSE; 02217 pPath->InitialiseFlags(); 02218 02219 // Allocate a new NodePath node and copy path data into it 02220 BOOL ok=TRUE; 02221 NodePath* pNodePath=NULL; 02222 if (pPath->GetNumCoords()!=0) 02223 { 02224 pNodePath=new NodePath; 02225 ok=(pNodePath!=NULL); 02226 if (ok) ok=pNodePath->InkPath.Initialise(pPath->GetNumCoords(),1); 02227 if (ok) ok=pNodePath->InkPath.CopyPathDataFrom(pPath); 02228 if (!ok) 02229 { 02230 delete pNodePath; 02231 pNodePath=NULL; 02232 } 02233 } 02234 02235 delete pPath; 02236 02237 *ppNodePath=pNodePath; 02238 return ok; 02239 #else 02240 return FALSE; 02241 #endif 02242 } 02243 02244 02245 02246 /*********************************************************************************************** 02247 > virtual BOOL TextChar::Snap(DocCoord* pDocCoord) 02248 02249 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02250 Created: 19/10/95 02251 Inputs: pDocCoord = a coord in Spread coords 02252 Outputs: If the point is snapped then pDocCoord will contain the point of attraction. 02253 Returns: TRUE - the DocCoord has been snapped to the character's path. 02254 FALSE - the DocCoord has not been processed. 02255 Purpose: Snaps to given coord to the nearest point on the characters render path. If 02256 it is not appropriate to snap the coord to the shape (at the moment this means 02257 the coord is too far awawy), then FALSE is returned. 02258 **********************************************************************************************/ 02259 02260 BOOL TextChar::Snap(DocCoord* pDocCoord) 02261 { 02262 BOOL Snapped = FALSE; 02263 02264 #if !defined(EXCLUDE_FROM_RALPH) 02265 // MILLIPOINT SnapDist = CSnap::GetSnapDist(); 02266 // MILLIPOINT SqrSnapDist = SnapDist*SnapDist; 02267 02268 // create a format region with an attribute stack 02269 FormatRegion FRegion; 02270 FormatRegion* pFormatRegion=&FRegion; 02271 BOOL ok = pFormatRegion->Init(this); 02272 pFormatRegion->SaveContext(); 02273 02274 // Get the path for this character 02275 NodePath* pPath = NULL; 02276 if (ok) 02277 ok = CreateNodePath(&pPath, pFormatRegion); 02278 02279 if (ok && (pPath!= NULL) && (pPath->InkPath.GetNumCoords() > 0)) 02280 { 02281 Snapped = CSnap::SnapCoordToPath(pDocCoord, &(pPath->InkPath)); 02282 delete pPath; 02283 } 02284 02285 pFormatRegion->RestoreContext(); 02286 #endif 02287 return Snapped; 02288 } 02289 02290 02291 /******************************************************************************************** 02292 > virtual BOOL TextChar::SupportsClipboardFormat(InternalClipboardFormat *Format) const 02293 02294 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 02295 Created: 26/4/95 02296 Returns: TRUE = This node supports the given format 02297 FALSE = This node does not support the format (or the format is unknown) 02298 02299 Purpose: Determine if a node supports a given internal data type. This is used 02300 by the clipboard when exporting to other applications in order to 02301 determine if certain data types can be supplied. 02302 02303 e.g. The basic formats include: 02304 Vector - this is ALWAYS assumed to be available (Vector format 02305 includes every Node, e.g. export in Camelot .art format) 02306 02307 Text - As well as paths, some objects can provide text chars 02308 02309 Bitmap - Bitmap fills can render a filled object or supply the 02310 bitmap used for filling with. 02311 02312 See InternalClipboardFormat (kernel\cliptype.h) for more details 02313 02314 Notes: TextChars can be exported as either "vector" or "text" data 02315 SeeAlso: InternalClipboardFormat; Node::SupportsClipboardFormat 02316 ********************************************************************************************/ 02317 02318 BOOL TextChar::SupportsClipboardFormat(InternalClipboardFormat *Format) const 02319 { 02320 #if !defined(EXCLUDE_FROM_RALPH) 02321 // TextChars can be exported as either "vector" or "text" data 02322 InternalClipboardFormat textformat(CLIPTYPE_TEXT); 02323 return(Format->IsSameFormat(textformat)); 02324 #else 02325 return FALSE; 02326 #endif 02327 } 02328 02329 /******************************************************************************************** 02330 02331 > BOOL TextChar::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 02332 BOOL TextChar::WritePreChildrenNative(BaseCamelotFilter *pFilter) 02333 02334 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 02335 Created: 10/07/96 02336 Inputs: pFilter - new file format filter to write record to 02337 Returns: TRUE if successful, FALSE otherwise 02338 Purpose: Writes a text char record to the new file format filter 02339 02340 ********************************************************************************************/ 02341 02342 BOOL TextChar::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 02343 { 02344 #ifdef DO_EXPORT 02345 return CXaraFileTxtChar::WritePreChildrenWeb(pFilter, this); 02346 #else 02347 return FALSE; 02348 #endif 02349 } 02350 02351 BOOL TextChar::WritePreChildrenNative(BaseCamelotFilter *pFilter) 02352 { 02353 #ifdef DO_EXPORT 02354 return CXaraFileTxtChar::WritePreChildrenNative(pFilter, this); 02355 #else 02356 return FALSE; 02357 #endif 02358 } 02359 02360 /******************************************************************************************** 02361 02362 > BOOL TextChar::WritePostChildrenWeb(BaseCamelotFilter* pFilter) 02363 02364 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02365 Created: 14/8/96 02366 Inputs: pFilter - new file format filter to write record to 02367 Returns: TRUE if successful, FALSE otherwise 02368 Purpose: Tells the text node that all it's children have been exported (or skipped if 02369 CanWriteChildrenWeb() returned FALSE) 02370 02371 Chars use this to reset their AlreadyWritten flag, because this can only be reset 02372 after it's children have been skipped 02373 02374 ********************************************************************************************/ 02375 02376 BOOL TextChar::WritePostChildrenWeb(BaseCamelotFilter* pFilter) 02377 { 02378 SetAlreadyWritten(FALSE); 02379 return TRUE; 02380 } 02381 02382 //------------------------------------------------------------------------------ 02383 // See TextChar::WritePostChildrenWeb(BaseCamelotFilter *pFilter) for more details 02384 02385 BOOL TextChar::WritePostChildrenNative(BaseCamelotFilter* pFilter) 02386 { 02387 SetAlreadyWritten(FALSE); 02388 return TRUE; 02389 } 02390 02391 /******************************************************************************************** 02392 02393 > BOOL TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) 02394 02395 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 02396 Created: 14/8/96 02397 Inputs: pFilter - new file format filter to write record to 02398 Returns: TRUE if successful, FALSE otherwise 02399 Purpose: Asks if it's alright to write out the char's children 02400 02401 Chars will only say no if they've already been written out (checks the AlreayWritten flag) 02402 02403 ********************************************************************************************/ 02404 02405 BOOL TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) 02406 { 02407 return !AlreadyWritten(); 02408 } 02409 02410 //------------------------------------------------------------------------------ 02411 // See TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) for more details 02412 02413 BOOL TextChar::CanWriteChildrenNative(BaseCamelotFilter *pFilter) 02414 { 02415 return !AlreadyWritten(); 02416 } 02417 02418 /******************************************************************************************** 02419 02420 > MILLIPOINT TextChar::GetAutoKernSize(FormatRegion* pFormatRegion) 02421 02422 Author: Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com> 02423 Created: 17/10/2000 02424 Inputs: FormatRegion 02425 Returns: Kern between char and next char 02426 Purpose: Find auto kern between two TextChar and next TextChar in the story 02427 02428 ********************************************************************************************/ 02429 MILLIPOINT TextChar::GetAutoKernSize(FormatRegion* pFormatRegion) 02430 { 02431 TextChar* pNextTC = FindNextTextCharInStory(); 02432 02433 if (pNextTC) 02434 { 02435 // If we get here, we know there is a TextChar (this) and a following textchar (pNextTC) 02436 // that might have a kern between them. Before asking for that kerning value, we have 02437 // to check that both 'this' and 'pNextTC' are of the same font and have the same bold/ 02438 // italic attribs. If we did not do this, GetCharsKerning would use the font currently 02439 // selected into pFormatRegion which is just the font the TextChar 'this'. 02440 02441 // The basic method I am using to do this is to look at the child attribs of 'this' 02442 // (don't care about attribs higher up the tree as they will apply to both 'this' and 02443 // 'pNextTC') and check that pNextTC also has child attribs of the same type. 02444 02445 // Well it should work... 02446 02447 // Hopefully... 02448 02449 Node *Child; // used to point to child attribs of 'this' 02450 Node *CompareChild; // used to point to child attribs of 'pNextTC' 02451 02452 Child = FindFirstChild(); 02453 while (Child) 02454 { 02455 if (IS_A(Child,AttrTxtFontTypeface) || 02456 IS_A(Child,AttrTxtItalic) || 02457 IS_A(Child,AttrTxtBold) || 02458 IS_A(Child,AttrTxtFontSize) || 02459 IS_A(Child,AttrTxtScript)) 02460 { 02461 // 'this' has a child node that could mean it has a difference between 02462 // it 'pNextTC' that could be important to us. Now we have to find out firstly 02463 // 'pNextTC' has this child node and if so if it has the same value. 02464 CompareChild = pNextTC->FindFirstChild(); 02465 while (CompareChild && Child->GetRuntimeClass() != CompareChild->GetRuntimeClass()) 02466 CompareChild = CompareChild->FindNext(); 02467 02468 if (CompareChild) 02469 { 02470 // If we get here we have found an attrib that is shared by 'this' and 'pNextTC' 02471 // with 'Child' pointing to the attrib of 'this' and 'CompareChild' pointing to the 02472 // attrib of 'pNextTC'. 02473 if (Child->IsDifferent(CompareChild)) 02474 return 0; // No kern 02475 } 02476 else 02477 { 02478 // We found an attrib on 'this' but not on 'pNextTC' so they must be different. 02479 // That means that we don't kern. 02480 return 0; // No kern 02481 } 02482 } 02483 02484 Child = Child->FindNext(); 02485 } 02486 02487 // If we get here, we know that 'this' has no attribs that are different from 'pNextTC'. 02488 // What we don't know is if 'pNextTC' has an attrib that 'this' does not have. This case 02489 // is made a little simpler as the mere existence of an attrib should be enough to make the 02490 // two different so there is no need to compare the attrib values. 02491 CompareChild = pNextTC->FindFirstChild(); 02492 while (CompareChild) 02493 { 02494 if (IS_A(CompareChild,AttrTxtFontTypeface) || 02495 IS_A(CompareChild,AttrTxtItalic) || 02496 IS_A(CompareChild,AttrTxtBold) || 02497 IS_A(CompareChild,AttrTxtFontSize) || 02498 IS_A(CompareChild,AttrTxtScript)) 02499 { 02500 // Found an attrib of 'pNextTC'. Just need to check that 'this' has this attrib as well 02501 // (if it does have that attrib, we will have checked they are the same in the IsDifferent() 02502 // call, above). 02503 Child = FindFirstChild(); 02504 while (Child && Child->GetRuntimeClass() != CompareChild->GetRuntimeClass()) 02505 Child = Child->FindNext(); 02506 02507 if (!Child) 02508 return 0; // No kern 02509 } 02510 02511 CompareChild = CompareChild->FindNext(); 02512 } 02513 02514 // Wow, we got through all the tests so I guess we might as well check for a kern now 02515 // (at last). Possible optimisation - we could do this at the top of the function and 02516 // then do all the all the checking afterwards - not sure if this would be faster or not. 02517 return pFormatRegion->GetCharsKerning(GetUnicodeValue(), pNextTC->GetUnicodeValue()); 02518 } 02519 else 02520 return 0; // No kern 02521 } 02522 02524 // CaretNode methods 02525 02526 /******************************************************************************************** 02527 > CaretNode::CaretNode() 02528 02529 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02530 Created: 21/12/94 02531 Purpose: Simple CaretNode constructor, it is required so that SimpleCopy will work. 02532 ********************************************************************************************/ 02533 02534 CaretNode::CaretNode(): VisibleTextNode() // Call the base class 02535 { 02536 } 02537 02538 02539 /******************************************************************************************** 02540 > CaretNode::CaretNode(Node* ContextNode, AttachNodeDirection Direction) 02541 02542 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02543 Created: 07/02/95 02544 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 02545 02546 Direction: 02547 02548 Specifies the direction in which the node is to be attached to the 02549 ContextNode. The values this variable can take are as follows: 02550 02551 PREV : Attach node as a previous sibling of the context node 02552 NEXT : Attach node as a next sibling of the context node 02553 FIRSTCHILD: Attach node as the first child of the context node 02554 LASTCHILD : Attach node as a last child of the context node 02555 02556 Purpose: The main CaretNode constructor 02557 ********************************************************************************************/ 02558 02559 CaretNode::CaretNode(Node* ContextNode, 02560 AttachNodeDirection Direction): VisibleTextNode(ContextNode, Direction) 02561 { 02562 } 02563 02564 /******************************************************************************************** 02565 > Node* CaretNode::SimpleCopy() 02566 02567 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02568 Created: 21/12/94 02569 Returns: NULL (See below) 02570 Purpose: It is illegal to copy a CaretNode, therefore this function will generate an error 02571 if called. 02572 But blends, moulds etc. call this function so I (Peter) have implemented it 02573 Fix after the show 02574 ********************************************************************************************/ 02575 02576 Node* CaretNode::SimpleCopy() 02577 { 02578 // Make a new CaretNode and then copy things into it 02579 CaretNode* NodeCopy = new CaretNode(); 02580 02581 ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 02582 02583 if (NodeCopy != NULL) 02584 CopyNodeContents(NodeCopy); 02585 02586 return NodeCopy; 02587 } 02588 02589 02590 /******************************************************************************************** 02591 > UINT32 CaretNode::GetNodeSize() const 02592 02593 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02594 Created: 21/12/94 02595 Returns: The size of the node in bytes 02596 Purpose: For finding the size of the CaretNode. 02597 ********************************************************************************************/ 02598 02599 UINT32 CaretNode::GetNodeSize() const 02600 { 02601 return (sizeof(CaretNode)); 02602 } 02603 02604 02605 /******************************************************************************************** 02606 > void CaretNode::GetDebugDetails(StringBase* Str) 02607 02608 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02609 Created: 1/2/95 02610 Outputs: Str: String giving debug info about the node 02611 Purpose: For obtaining debug information about the Node. 02612 This fn can be deleted before we ship 02613 ********************************************************************************************/ 02614 02615 void CaretNode::GetDebugDetails(StringBase* Str) 02616 { 02617 #if DEBUG_TREE 02618 VisibleTextNode::GetDebugDetails(Str); 02619 #endif 02620 } 02621 02622 02623 /******************************************************************************************** 02624 > Path* CaretNode::CreatePath(Matrix* pMatrix) 02625 02626 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02627 Created: 21/395 02628 Inputs: pMatrix - transform to be applied to the caret 02629 Returns: pointer to new path (or NULL if fails) 02630 Purpose: Create a caret path 02631 ********************************************************************************************/ 02632 02633 Path* CaretNode::CreatePath(Matrix* pMatrix) 02634 { 02635 ERROR2IF(pMatrix==NULL,NULL,"CaretNode::CreatePath() - pMatrix==NULL"); 02636 02637 TextLine* pTextLine=(TextLine*)FindParent(); 02638 ERROR2IF(pTextLine==NULL,FALSE,"CaretNode::CreatePath() - pTextLine==NULL"); 02639 02640 // find italic status on caret 02641 NodeAttribute* pAttr; 02642 BOOL Italic=FALSE; 02643 if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtItalic), &pAttr)) 02644 Italic=((TxtItalicAttribute*)(pAttr->GetAttributeValue()))->ItalicOn; 02645 02646 // find script offest 02647 FIXED16 ScriptOffset=0; 02648 if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtScript), &pAttr)) 02649 ScriptOffset=((TxtScriptAttribute*)(pAttr->GetAttributeValue()))->Offset; 02650 02651 // find caret height 02652 MILLIPOINT LineSize = pTextLine->GetLineSize(); 02653 MILLIPOINT CaretSize = LineSize; 02654 if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtFontSize), &pAttr)) 02655 CaretSize=((TxtFontSizeAttribute*)(pAttr->GetAttributeValue()))->FontSize; 02656 02657 // find baseline shift 02658 // MILLIPOINT BaseLineShift=0; 02659 // if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtBaseLine), &pAttr)) 02660 // BaseLineShift=((TxtBaseLineAttribute*)(pAttr->GetAttributeValue()))->Value; 02661 02662 // calc caret top and bottom points accounting for italic and baseline shift 02663 FIXED16 CaretRatio=(LineSize!=0) ? Div32By32(CaretSize,LineSize) : 1; 02664 DocCoord CaretTop(0, XLONG(pTextLine->GetLineDescent()) * CaretRatio ); 02665 DocCoord CaretBot(0, XLONG(pTextLine->GetLineAscent()) * CaretRatio ); 02666 if (Italic && ScriptOffset==0) 02667 { 02668 const double SlantRatio = tan(15.0*PI/180); 02669 CaretTop.x = (INT32) ((double)CaretTop.y * SlantRatio); 02670 CaretBot.x = (INT32) ((double)CaretBot.y * SlantRatio); 02671 } 02672 02673 // get caret path 02674 Path* pCaretPath=new Path(); 02675 BOOL ok=(pCaretPath!=NULL); 02676 if (ok) ok=pCaretPath->Initialise(2,12); 02677 if (ok) ok=pCaretPath->AddMoveTo(CaretTop); 02678 if (ok) ok=pCaretPath->AddLineTo(CaretBot); 02679 02680 // apply transform to caret path 02681 DocCoord* pPathCoords=NULL; 02682 if (ok) pPathCoords=pCaretPath->GetCoordArray(); 02683 if (ok) ok=(pPathCoords!=NULL); 02684 if (ok) pMatrix->transform((Coord*)pPathCoords, pCaretPath->GetNumCoords()); 02685 02686 // if not OK, delete caret path and set return path pointer to NULL 02687 if (!ok) 02688 { 02689 delete pCaretPath; 02690 pCaretPath=NULL; 02691 } 02692 02693 return pCaretPath; 02694 } 02695 02696 02697 /******************************************************************************************** 02698 > void CaretNode::RenderObjectBlobs(RenderRegion* pRenderRegion) 02699 02700 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02701 Created: 14/2/95 02702 Inputs: pRender - The region to render into 02703 Returns: FALSE if fails 02704 Purpose: Renders the caret's path into the pRender render region 02705 ********************************************************************************************/ 02706 02707 void CaretNode::RenderObjectBlobs(RenderRegion* pRenderRegion) 02708 { 02709 if (RenderObjectBlobsCore(pRenderRegion)==FALSE) 02710 InformError(); 02711 } 02712 02713 02714 /******************************************************************************************** 02715 > BOOL CaretNode::RenderObjectBlobsCore(RenderRegion* pRenderRegion) 02716 02717 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02718 Created: 14/2/95 02719 Inputs: pRender: The region to render into 02720 Returns: FALSE if fails 02721 Purpose: Renders the caret's path into the pRender render region 02722 ********************************************************************************************/ 02723 02724 BOOL CaretNode::RenderObjectBlobsCore(RenderRegion* pRenderRegion) 02725 { 02726 #if !defined(EXCLUDE_FROM_RALPH) 02727 ERROR2IF(pRenderRegion==NULL,FALSE,"CaretNode::RenderObjectBlobsCore() - pRenderRegion==NULL"); 02728 02729 TextStory* pTextStory = this->FindParentStory(); 02730 ERROR2IF(pTextStory==NULL,FALSE,"CaretNode::RenderObjectBlobsCore() - pTextStory==NULL"); 02731 02732 // get the caret path transformed to the correct place in the doc 02733 Matrix matrix; 02734 if (GetStoryAndCharMatrix(&matrix)==FALSE) 02735 return FALSE; 02736 Path* pCaretPath=CreatePath(&matrix); 02737 BOOL ok=(pCaretPath!=NULL); 02738 02739 // draw the caret path in red (line width?) 02740 if (ok) 02741 { 02742 pRenderRegion->SaveContext(); 02743 pRenderRegion->SetLineColour(RED); 02744 pRenderRegion->DrawPath(pCaretPath); 02745 pRenderRegion->RestoreContext(); 02746 } 02747 02748 // delete the caret path 02749 delete pCaretPath; 02750 02751 return ok; 02752 #else 02753 return TRUE; 02754 #endif 02755 } 02756 02757 02758 /******************************************************************************************* 02759 > virtual BOOL CaretNode::ExportRender(RenderRegion* pRegion) 02760 02761 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02762 Created: 14/4/95 02763 Inputs: pRegion - points to the export render region 02764 Returns: TRUE if rendered OK (FALSE=>use normal rendering) 02765 Purpose: This function is called when the render function passes through this node 02766 It outputs the Text Object start and end tokens 02767 ********************************************************************************************/ 02768 02769 BOOL CaretNode::ExportRender(RenderRegion* pRegion) 02770 { 02771 #if EXPORT_TEXT 02772 // BODGE TEXT - need to export caret in a comment! 02773 if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion))) 02774 { 02775 /*EPSExportDC *pDC=*/(EPSExportDC*)pRegion->GetRenderDC(); 02776 // pDC->OutputToken("ctk"); 02777 // pDC->OutputNewLine(); 02778 return TRUE; 02779 } 02780 #endif 02781 return FALSE; 02782 } 02783 02784 02785 /******************************************************************************************** 02786 > virtual void CaretNode::Describe(BOOL Plural, BOOL Verbose = TRUE) 02787 02788 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 02789 Created: 15/03/95 02790 Inputs: Plural - FALSE to describe a single caret 02791 TRUE to describe many 02792 Returns: String describing what the node is 02793 Purpose: For obtaining a desciption about the node to use in the status line 02794 ********************************************************************************************/ 02795 02796 String CaretNode::Describe(BOOL Plural, BOOL Verbose) 02797 { 02798 if (Plural) 02799 return(String(_R(IDS_CARETSDESCRIPTION))); 02800 else 02801 return(String(_R(IDS_CARETDESCRIPTION))); 02802 } 02803 02804 02805 /******************************************************************************************** 02806 > virtual DocRect CaretNode::GetBlobBoundingRect() 02807 02808 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02809 Created: 21/3/95 02810 Returns: the caret's bounds 02811 Purpose: get the caret's blob bounds 02812 Note: Abuse of bounding box cache should really be for renderable bounds 02813 but the caret has none! 02814 ********************************************************************************************/ 02815 02816 DocRect CaretNode::GetBlobBoundingRect() 02817 { 02818 if (IsBoundingRectValid==FALSE) 02819 if (ValidateBoundingRect()==FALSE) 02820 InformError(); 02821 02822 return BlobBounds; 02823 } 02824 02825 02826 /******************************************************************************************** 02827 > virtual DocRect CaretNode::GetBoundingRect(BOOL DontUseAttr=FALSE, BOOL HitTest=FALSE) 02828 02829 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02830 Created: 21/3/95 02831 Inputs: DontUseAttr - not used 02832 HitTest - not used 02833 Returns: the caret's renderable bounds 02834 ********************************************************************************************/ 02835 02836 DocRect CaretNode::GetBoundingRect(BOOL DontUseAttr, BOOL HitTest) 02837 { 02838 if (IsBoundingRectValid==FALSE) 02839 if (ValidateBoundingRect()==FALSE) 02840 InformError(); 02841 02842 return BoundingRectangle; 02843 } 02844 02845 02846 /******************************************************************************************** 02847 > BOOL CaretNode::ValidateBoundingRect(FormatRegion* pFormatRegion=NULL) 02848 02849 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02850 Created: 21/3/95 02851 Inputs: pFormatRegion - not used 02852 Returns: FALSE if fails 02853 Purpose: recache the caret's renderable and blob bounding rects 02854 ********************************************************************************************/ 02855 02856 BOOL CaretNode::ValidateBoundingRect(FormatRegion* pFormatRegion) 02857 { 02858 #if !defined(EXCLUDE_FROM_RALPH) 02859 BOOL ok=TRUE; 02860 02861 // get the overall matrix to apply to the caret 02862 Matrix matrix; 02863 if (GetStoryAndCharMatrix(&matrix)==FALSE) 02864 return FALSE; 02865 02866 // get a zero size rect at the correct position in the doc 02867 // for the renderable bounds of the caret (uses by ScrollToShow) 02868 DocCoord temp(0,0); 02869 matrix.transform((Coord*)&temp,1); 02870 DocRect RendRect(temp,temp); 02871 02872 // get the bounds of the caret path for the blob bounds 02873 Path* pCaretPath=CreatePath(&matrix); 02874 DocRect BlobRect(0,0,0,0); 02875 ok=(pCaretPath!=NULL); 02876 if (ok) 02877 { 02878 DocCoord* pCoords=pCaretPath->GetCoordArray(); 02879 PathVerb* pVerbs=pCaretPath->GetVerbArray(); 02880 ok=(pVerbs!=NULL && pCoords!=NULL); 02881 if (ok) 02882 { 02883 GDrawContext *GD = GRenderRegion::GetStaticDrawContext(); 02884 02885 if (GD != NULL) 02886 { 02887 ok=!(GD->CalcStrokeBBox((POINT*)pCoords, pVerbs, pCaretPath->GetNumCoords(), 02888 (LPRECT)(&BlobRect), 0, 2, CAPS_ROUND, JOIN_ROUND, NULL)); 02889 } 02890 02891 if (!ok) ERROR2RAW("CaretNode::ValidateBoundingRect() - GDraw_CalcStrokeBBox() failed"); 02892 } 02893 delete pCaretPath; 02894 } 02895 02896 // Inflate the blob bounds, so that the Caret is at least a pixel wide 02897 if (View::GetCurrent() != NULL) 02898 { 02899 INT32 PixWidth = (View::GetCurrent()->GetScaledPixelWidth()).MakeLong(); 02900 BlobRect.Inflate(PixWidth/2); 02901 } 02902 02903 // update the cached values 02904 BoundingRectangle = RendRect; 02905 BlobBounds = BlobRect; 02906 IsBoundingRectValid = TRUE; 02907 return ok; 02908 #else 02909 return TRUE; 02910 #endif 02911 } 02912 02913 02914 /******************************************************************************************** 02915 > BOOL CaretNode::HasMoved(); 02916 02917 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02918 Created: 17/3/95 02919 Returns: FALSE if fails 02920 Purpose: reposition the caret after it has moved 02921 If possible to the right of the previous char as the caret takes its attributes 02922 from this char so the caret's position reflects it's baseline shift correctly 02923 ********************************************************************************************/ 02924 02925 BOOL CaretNode::HasMoved() 02926 { 02927 #if !defined(EXCLUDE_FROM_RALPH) 02928 AbstractTextChar* pPrevATC=(AbstractTextChar*)(this->FindPrevious(CC_RUNTIME_CLASS(AbstractTextChar))); 02929 BOOL AfterPrevChar = (pPrevATC!=NULL); 02930 02931 // if positioning the caret after the previous char and its a kern code 02932 // and its on a path and a silly size, position the caret before the next char 02933 if (AfterPrevChar && IS_A(pPrevATC,KernCode)) 02934 { 02935 TextStory* pTextStory = this->FindParentStory(); 02936 ERROR2IF(pTextStory==NULL,FALSE,"CaretNode::HasMoved() - could not find caret's parent story!"); 02937 if ( pTextStory->GetTextPath()!=NULL && ((KernCode*)pPrevATC)->GetValue().x>1000 ) 02938 AfterPrevChar = FALSE; 02939 } 02940 02941 // if positioning caret after last char, use prev char's info plus advance 02942 // else just use next char's info 02943 Matrix matrix; 02944 MILLIPOINT pos=0; 02945 if (AfterPrevChar) 02946 { 02947 const MILLIPOINT advance=pPrevATC->GetVisibleAdvance(); 02948 matrix = Matrix(advance,0); 02949 matrix *= pPrevATC->GetMatrix(); 02950 pos = pPrevATC->GetPosInLine()+advance; 02951 } 02952 else 02953 { 02954 AbstractTextChar* pNextATC=(AbstractTextChar*)(this->FindNext(CC_RUNTIME_CLASS(AbstractTextChar))); 02955 ERROR2IF(pNextATC==NULL,FALSE,"CaretNode::HasMoved() - no AbstractTextChar before or after caret!"); 02956 matrix = pNextATC->GetMatrix(); 02957 pos = pNextATC->GetPosInLine(); 02958 } 02959 02960 SetMatrix(matrix); 02961 SetPosInLine(pos); 02962 InvalidateBoundingRect(); 02963 #endif 02964 return TRUE; 02965 } 02966 02967 02968 /******************************************************************************************** 02969 > virtual BOOL CaretNode::DiscardsAttributeChildren() 02970 02971 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 02972 Created: 4/5/95 02973 Returns: TRUE 02974 Purpose: When attributes are applied to the caret, we cannot generate undo info 02975 as children of the CaretNode are thrown away in a non-undoable way. 02976 02977 Notes: Phil, 24/09/2005 02978 The usage of this function has changed subtly today. It used to prevent 02979 both attribute optimisation and undo recording on Caret nodes. 02980 As of today it just prevents undo recording - attribute optimisation 02981 goes ahead like normal on Caret nodes so that they behave more consistently. 02982 02983 ********************************************************************************************/ 02984 02985 BOOL CaretNode::DiscardsAttributeChildren() const 02986 { 02987 return TRUE; 02988 } 02989 02990 02991 /******************************************************************************************** 02992 > BOOL CaretNode::DoApplyAttrsTo(UndoableOperation* pUndoOp, VisibleTextNode* pDstVTN, BOOL bDeleteDups) 02993 02994 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 02995 Created: 9/7/96 02996 Inputs: pDstVTN - VisibleTextNode to apply caret attrs to 02997 Returns: FALSE if fails 02998 Purpose: Apply attrs on caret to given VTN (on same line) ensuring tree left optimal 02999 ********************************************************************************************/ 03000 03001 BOOL CaretNode::DoApplyAttrsTo(UndoableOperation* pUndoOp, VisibleTextNode* pDstVTN, BOOL bDeleteDups) 03002 { 03003 ERROR2IF(pUndoOp==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - pUndoOp==NULL"); 03004 ERROR2IF(pDstVTN==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - pDstVTN==NULL"); 03005 03006 TextLine* pCaretLine = this->FindParentLine(); 03007 ERROR2IF(pCaretLine==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - caret has no TextLine parent"); 03008 TextLine* pDstVTNLine = pDstVTN->FindParentLine(); 03009 ERROR2IF(pDstVTNLine==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - dest VTN has no TextLine parent"); 03010 if (bDeleteDups) 03011 { 03012 ERROR2IF(pDstVTNLine!=pCaretLine,FALSE,"CaretNode::DoApplyAttrsTo() - caret and pDstVTN not on same line"); 03013 } 03014 03015 // determine if attr types on caret are already localised 03016 AbstractTextChar* pATC = (AbstractTextChar*)(pCaretLine->FindFirstChild(CC_RUNTIME_CLASS(AbstractTextChar))); 03017 ERROR2IF(pATC==NULL,FALSE,"OpTextFormat::DoInsertCharHelper() - caret line has no AbstaractTextChars"); 03018 BOOL CommonAttrsAffected = !pATC->HasAttrTypesOn(this); 03019 03020 // if attr types on the caret are not localised, localise them 03021 AttrTypeSet CaretsAttrTypes; 03022 this->AddChildAttrTypesToSet(&CaretsAttrTypes); 03023 if (CommonAttrsAffected) 03024 if (!pUndoOp->DoLocaliseForAttrChange(pDstVTN,&CaretsAttrTypes,NULL)) 03025 return FALSE; 03026 03027 // BODGE WORDWRAP - causes dup attrs if applying defalut attr on caret to new char in line of non-default 03028 03029 // now copy carets attrs to new char, deleting any duplicates 03030 NodeAttribute* pCaretAttr = (NodeAttribute*)(this->FindFirstChild(CC_RUNTIME_CLASS(NodeAttribute))); 03031 while (pCaretAttr!=NULL) 03032 { 03033 NodeAttribute* pDupAttr = pDstVTN->GetChildAttrOfType(pCaretAttr->GetAttributeType()); 03034 03035 // If we have found a duplicate and we are allowed to delete it, do so 03036 if (pDupAttr!=NULL && bDeleteDups) 03037 { 03038 pDupAttr->CascadeDelete(); 03039 delete pDupAttr; 03040 } 03041 03042 // If we didn't find a duplicate or we did and we deleted it then 03043 // copy the caret's attribute 03044 if (pDupAttr==NULL || bDeleteDups) 03045 { 03046 Node* pAttrCopy; 03047 if (!pCaretAttr->NodeCopy(&pAttrCopy)) 03048 return FALSE; 03049 pAttrCopy->AttachNode(pDstVTN, LASTCHILD); 03050 } 03051 03052 pCaretAttr = (NodeAttribute*)(pCaretAttr->FindNext(CC_RUNTIME_CLASS(NodeAttribute))); 03053 } 03054 03055 // if attr types on caret were localised, factor them out 03056 if (CommonAttrsAffected) 03057 if (!pUndoOp->DoFactorOutAfterAttrChange(pDstVTN, &CaretsAttrTypes)) 03058 return FALSE; 03059 03060 return TRUE; 03061 } 03062 03063 03064 /******************************************************************************************** 03065 > virtual void CaretNode::SetSelected(BOOL Status) 03066 03067 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03068 Created: 11/5/95 03069 Inputs: Status - TRUE to select the caret 03070 FALSE to deselect it 03071 Purpose: Overides the normal SetSelected call so we can ensure that the caret is not 03072 selected outside the TextTool. 03073 ********************************************************************************************/ 03074 03075 void CaretNode::SetSelected(BOOL Status) 03076 { 03077 #if !defined(EXCLUDE_FROM_RALPH) 03078 if (!TextTool::IsCurrentTool()) 03079 { 03080 TextStory* pStory = this->FindParentStory(); 03081 if (pStory != NULL) 03082 pStory->SetSelected(Status); 03083 } 03084 else 03085 BaseTextClass::SetSelected(Status); 03086 #endif 03087 } 03088 03089 03090 /******************************************************************************************** 03091 > BOOL CaretNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03092 BOOL CaretNode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03093 03094 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 03095 Created: 10/07/96 03096 Inputs: pFilter - new file format filter to write record to 03097 Returns: TRUE if successful, FALSE otherwise 03098 Purpose: Writes a caret node record to the new file format filter 03099 ********************************************************************************************/ 03100 03101 BOOL CaretNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03102 { 03103 //#ifdef DO_EXPORT 03104 // return CXaraFileTxtCaret::WritePreChildrenWeb(pFilter, this); 03105 //#else 03106 return FALSE; 03107 //#endif 03108 } 03109 03110 BOOL CaretNode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03111 { 03112 //#ifdef DO_EXPORT 03113 // return CXaraFileTxtCaret::WritePreChildrenNative(pFilter, this); 03114 //#else 03115 return FALSE; 03116 //#endif 03117 } 03118 03119 BOOL CaretNode::CanWriteChildrenWeb(BaseCamelotFilter* pFilter) 03120 { 03121 return FALSE; 03122 } 03123 03124 BOOL CaretNode::CanWriteChildrenNative(BaseCamelotFilter* pFilter) 03125 { 03126 return FALSE; 03127 } 03128 03130 // EOLNode methods 03131 03132 /******************************************************************************************** 03133 > EOLNode::EOLNode() 03134 03135 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03136 Created: 21/12/94 03137 Purpose: Simple EOLNode constructor, it is required so that SimpleCopy will work. 03138 ********************************************************************************************/ 03139 03140 EOLNode::EOLNode(): AbstractTextChar() // Call the base class 03141 { 03142 Virtual = FALSE; 03143 } 03144 03145 03146 /******************************************************************************************** 03147 > EOLNode::EOLNode(Node* ContextNode, AttachNodeDirection Direction) 03148 03149 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03150 Created: 07/02/95 03151 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 03152 03153 Direction: 03154 03155 Specifies the direction in which the node is to be attached to the 03156 ContextNode. The values this variable can take are as follows: 03157 03158 PREV : Attach node as a previous sibling of the context node 03159 NEXT : Attach node as a next sibling of the context node 03160 FIRSTCHILD: Attach node as the first child of the context node 03161 LASTCHILD : Attach node as a last child of the context node 03162 03163 Purpose: The main EOLNode constructor 03164 ********************************************************************************************/ 03165 03166 EOLNode::EOLNode(Node* ContextNode, 03167 AttachNodeDirection Direction): AbstractTextChar(ContextNode, Direction) 03168 { 03169 Virtual = FALSE; 03170 } 03171 03172 03173 /******************************************************************************************** 03174 > Node* EOLNode::SimpleCopy() 03175 03176 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03177 Created: 21/12/94 03178 Returns: A copy of the node, or NULL if we are out of memory 03179 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 03180 The function is virtual, and must be defined for all derived classes of Node 03181 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 03182 error and the function returns NULL. 03183 ********************************************************************************************/ 03184 03185 Node* EOLNode::SimpleCopy() 03186 { 03187 // Make a new TextChar and then copy things into it 03188 EOLNode* NodeCopy = new EOLNode(); 03189 03190 if (NodeCopy) 03191 CopyNodeContents(NodeCopy); 03192 03193 return NodeCopy; 03194 03195 } 03196 03197 03198 /******************************************************************************************** 03199 > virtual void EOLNode::Describe(BOOL Plural, BOOL Verbose = TRUE) 03200 03201 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03202 Created: 15/03/95 03203 Inputs: Plural - FALSE to describe a single EOLNode 03204 TRUE to describe many 03205 Returns: String describing what the node is 03206 Purpose: For obtaining a desciption about the node to use in the status line 03207 ********************************************************************************************/ 03208 03209 String EOLNode::Describe(BOOL Plural, BOOL Verbose) 03210 { 03211 if (Plural) 03212 return(String(_R(IDS_EOLNODES))); 03213 else 03214 return(String(_R(IDS_EOLNODE))); 03215 } 03216 03217 03218 /*********************************************************************************************** 03219 > void EOLNode::CopyNodeContents(EOLNode* NodeCopy) 03220 03221 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03222 Created: 28/4/93 03223 Inputs: 03224 Outputs: A copy of this node 03225 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 03226 Errors: An assertion failure will occur if NodeCopy is NULL 03227 ***********************************************************************************************/ 03228 03229 void EOLNode::CopyNodeContents(EOLNode* NodeCopy) 03230 { 03231 // Ask the base class to do its bit 03232 AbstractTextChar::CopyNodeContents( NodeCopy ); 03233 03234 // Copy the rest of the data in here 03235 NodeCopy->Virtual = Virtual; 03236 } 03237 03238 03239 /*********************************************************************************************** 03240 > void EOLNode::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 03241 03242 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03243 Created: 18/12/2003 03244 Outputs: - 03245 Purpose: Polymorphically copies the contents of this node to another 03246 Errors: An assertion failure will occur if NodeCopy is NULL 03247 Scope: protected 03248 03249 ***********************************************************************************************/ 03250 03251 void EOLNode::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 03252 { 03253 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 03254 ENSURE(IS_A(pNodeCopy, EOLNode), "PolyCopyNodeContents given wrong dest node type"); 03255 03256 if (IS_A(pNodeCopy, EOLNode)) 03257 CopyNodeContents((EOLNode*)pNodeCopy); 03258 } 03259 03260 03261 03262 /******************************************************************************************** 03263 > UINT32 EOLNode::GetNodeSize() const 03264 03265 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03266 Created: 21/12/94 03267 Returns: The size of the node in bytes 03268 Purpose: For finding the size of the node 03269 ********************************************************************************************/ 03270 03271 UINT32 EOLNode::GetNodeSize() const 03272 { 03273 return (sizeof(EOLNode)); 03274 } 03275 03276 03277 /******************************************************************************************** 03278 > void EOLNode::GetDebugDetails(StringBase* Str) 03279 03280 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03281 Created: 1/2/95 03282 Outputs: Str: String giving debug info about the node 03283 Purpose: For obtaining debug information about the Node. 03284 This fn can be deleted before we ship 03285 ********************************************************************************************/ 03286 03287 void EOLNode::GetDebugDetails(StringBase* pStr) 03288 { 03289 #if DEBUG_TREE 03290 AbstractTextChar::GetDebugDetails(pStr); 03291 03292 String_256 TempStr; 03293 03294 switch (IsVirtual()) 03295 { 03296 case TRUE: TempStr._MakeMsg(TEXT("\r\nIs virtual")); break; 03297 case FALSE: TempStr._MakeMsg(TEXT("\r\nIs physical")); break; 03298 } 03299 *pStr += TempStr; 03300 #endif 03301 } 03302 03303 03304 /******************************************************************************************** 03305 > virtual DocRect EOLNode::GetBoundingRect(BOOL DontUseAttr=FALSE, BOOL HitTest=FALSE) 03306 03307 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03308 Created: 21/3/95 03309 Inputs: DontUseAttr - not used (EOL is not rendered) 03310 HitTest - TRUE if being called during HitTest 03311 Returns: the EOL bounds (zero size but in correct position 03312 Purpose: Get the EOL's bounds 03313 If the cached bounds are invalid, recalculate them 03314 ********************************************************************************************/ 03315 03316 DocRect EOLNode::GetBoundingRect(BOOL DontUseAttr, BOOL HitTest) 03317 { 03318 if (IsBoundingRectValid==FALSE) 03319 if (ValidateBoundingRect()==FALSE) 03320 InformError(); 03321 03322 return BoundingRectangle; 03323 } 03324 03325 03326 /******************************************************************************************** 03327 > BOOL EOLNode::ValidateBoundingRect(FormatRegion* pFormatRegion=NULL) 03328 03329 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03330 Created: 21/3/95 03331 Inputs: pFormatRegion - not used 03332 Returns: FALSE if fails 03333 Purpose: calculate the EOL bounds in the document 03334 ********************************************************************************************/ 03335 03336 BOOL EOLNode::ValidateBoundingRect(FormatRegion* pFormatRegion) 03337 { 03338 Matrix matrix; 03339 if (GetStoryAndCharMatrix(&matrix)==FALSE) 03340 return FALSE; 03341 03342 // get a zero size rect at correct place in the doc for the renderable bounds of the EOL 03343 DocCoord temp(0,0); 03344 matrix.transform(&temp); 03345 BoundingRectangle = DocRect(temp,temp); 03346 IsBoundingRectValid = TRUE; 03347 return TRUE; 03348 } 03349 03350 03351 /******************************************************************************************** 03352 > virtual DocRect EOLNode::GetBlobBoundingRect() 03353 03354 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03355 Created: 11/5/95 03356 Returns: the EOLNode's blob bounds 03357 Purpose: get the EOLNode's blob bounds 03358 ********************************************************************************************/ 03359 03360 DocRect EOLNode::GetBlobBoundingRect() 03361 { 03362 Path RenderPath; 03363 DocRect Bounds(0,0,1,1); 03364 if (GetBlobPath(&RenderPath)) 03365 Bounds = RenderPath.GetBoundingRect(); 03366 03367 return Bounds; 03368 } 03369 03370 03371 /******************************************************************************************** 03372 > void EOLNode::RenderObjectBlobs(RenderRegion* pRenderRegion) 03373 03374 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03375 Created: 11/5/95 03376 Inputs: pRenderRegion - region to render the blobs into 03377 Purpose: Renders the selection blobs for an EOLNode 03378 ********************************************************************************************/ 03379 03380 void EOLNode::RenderObjectBlobs(RenderRegion* pRenderRegion) 03381 { 03382 #if !defined(EXCLUDE_FROM_RALPH) 03383 Path RenderPath; 03384 if (GetBlobPath(&RenderPath)) 03385 { 03386 DocColour Trans(COLOUR_TRANS); 03387 pRenderRegion->SetLineWidth(0); 03388 pRenderRegion->SetLineColour(Trans); 03389 pRenderRegion->SetFillColour(COLOUR_UNSELECTEDBLOB); 03390 pRenderRegion->DrawPath(&RenderPath); 03391 } 03392 else 03393 InformError(); 03394 #endif 03395 } 03396 03397 03398 /******************************************************************************************** 03399 > void EOLNode::RenderTinyBlobs(RenderRegion* pRenderRegion) 03400 03401 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03402 Created: 11/5/95 03403 Inputs: pRenderRegion - region to render the blobs into 03404 Purpose: Renders the selection blobs for an EOLNode 03405 ********************************************************************************************/ 03406 03407 void EOLNode::RenderTinyBlobs(RenderRegion* pRenderRegion) 03408 { 03409 #if !defined(EXCLUDE_FROM_RALPH) 03410 RenderObjectBlobs(pRenderRegion); 03411 #endif 03412 } 03413 03414 03415 /******************************************************************************************** 03416 > BOOL EOLNode::GetBlobPath(Path*) 03417 03418 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 03419 Created: 11/5/95 03420 Inputs: Pointer to a path 03421 Returns: TRUE/FALSE for success/failure 03422 Purpose: Builds a path for rendering the blobs for an EOLNode 03423 ********************************************************************************************/ 03424 03425 BOOL EOLNode::GetBlobPath(Path* pPath) 03426 { 03427 #if !defined(EXCLUDE_FROM_RALPH) 03428 ERROR2IF(pPath==NULL, FALSE, "Path pointer was NULL"); 03429 TextLine* pParentLine = this->FindParentLine(); 03430 ERROR2IF(pParentLine==NULL, FALSE, "EOLNode didn't have a parent TextLine"); 03431 const MILLIPOINT LineAscent = pParentLine->GetLineAscent(); 03432 const MILLIPOINT HalfLA = LineAscent/2; 03433 const MILLIPOINT QuarterLA = LineAscent/4; 03434 BOOL ok = TRUE; 03435 if (ok) ok = pPath->Initialise(4,1); 03436 if (ok) ok = pPath->AddMoveTo(DocCoord(QuarterLA,0)); 03437 if (ok) ok = pPath->AddLineTo(DocCoord(QuarterLA, HalfLA)); 03438 if (ok) ok = pPath->AddLineTo(DocCoord(HalfLA+QuarterLA, QuarterLA)); 03439 if (ok) ok = pPath->AddLineTo(DocCoord(QuarterLA,0)); 03440 if (ok) 03441 { 03442 ok = pPath->CloseSubPath(); 03443 pPath->IsFilled = TRUE; 03444 } 03445 03446 // Transform the path 03447 if (ok) 03448 { 03449 Matrix matrix; 03450 if (ok) ok = GetStoryAndCharMatrix(&matrix); 03451 if (ok) matrix.transform((Coord*)(pPath->GetCoordArray()), pPath->GetNumCoords()); 03452 } 03453 03454 return ok; 03455 #else 03456 return FALSE; 03457 #endif 03458 } 03459 /******************************************************************************************** 03460 03461 > BOOL EOLNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03462 BOOL EOLNode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03463 03464 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 03465 Created: 10/07/96 03466 Inputs: pFilter - new file format filter to write record to 03467 Returns: TRUE if successful, FALSE otherwise 03468 Purpose: Writes an end of line record to the new file format filter 03469 03470 ********************************************************************************************/ 03471 03472 BOOL EOLNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03473 { 03474 #ifdef DO_EXPORT 03475 return CXaraFileTxtEOL::WritePreChildrenWeb(pFilter, this); 03476 #else 03477 return FALSE; 03478 #endif 03479 } 03480 03481 BOOL EOLNode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03482 { 03483 #ifdef DO_EXPORT 03484 return CXaraFileTxtEOL::WritePreChildrenNative(pFilter, this); 03485 #else 03486 return FALSE; 03487 #endif 03488 } 03489 03490 /******************************************************************************************** 03491 03492 > BOOL EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) 03493 03494 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 03495 Created: 30/8/96 03496 Inputs: pFilter - new file format filter to write record to 03497 Returns: TRUE if successful, FALSE otherwise 03498 Purpose: Asks if it's alright to write out the EOL's children 03499 03500 EOLs always say yes. EOL nodes can't be female then. 03501 03502 ********************************************************************************************/ 03503 03504 BOOL EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) 03505 { 03506 return TRUE; 03507 } 03508 03509 //------------------------------------------------------------------------------ 03510 // See EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) for more details 03511 03512 BOOL EOLNode::CanWriteChildrenNative(BaseCamelotFilter *pFilter) 03513 { 03514 return TRUE; 03515 } 03516 03517 /******************************************************************************************* 03518 > virtual BOOL EOLNode::ExportRender(RenderRegion* pRegion) 03519 03520 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03521 Created: 14/4/95 03522 Inputs: pRegion - points to the export render region 03523 Returns: TRUE if rendered OK (FALSE=>use normal rendering) 03524 Purpose: This function is called when the render function passes through this node 03525 It outputs the Text Object start and end tokens 03526 ********************************************************************************************/ 03527 03528 BOOL EOLNode::ExportRender(RenderRegion* pRegion) 03529 { 03530 #if EXPORT_TEXT 03531 03532 // (ChrisG - 3/11/00) 03533 if (pRegion->IsKindOf(CC_RUNTIME_CLASS(AIEPSRenderRegion))) 03534 { 03535 // if we were exporting the overflow data (i.e. we were exporting a path), then 03536 // finish off exporting this 03537 if (((AIEPSRenderRegion *) pRegion)->ExportingOnPath ()) 03538 ((AIEPSRenderRegion *) pRegion)->OverflowTextFinish (); 03539 } 03540 03541 return pRegion->WriteNewLine (); 03542 #else 03543 return FALSE; 03544 #endif 03545 } 03546 03547 03549 // KernCode methods 03550 03551 /******************************************************************************************** 03552 > KernCode::KernCode() 03553 03554 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03555 Created: 21/12/94 03556 Purpose: Simple KernCode constructor, it is required so that SimpleCopy will work. 03557 You should not normally call this constructor as it does not initialise 03558 the object. 03559 ********************************************************************************************/ 03560 03561 KernCode::KernCode(): AbstractTextChar() 03562 { 03563 } 03564 03565 /******************************************************************************************** 03566 > KernCode::KernCode(DocCoord& KernValue) 03567 03568 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03569 Created: 21/12/94 03570 Inputs: KernValue: Horizontal/Vertical kern value 03571 Purpose: KernCode constructor 03572 ********************************************************************************************/ 03573 03574 KernCode::KernCode(DocCoord& KernValue): AbstractTextChar() 03575 { 03576 Value = KernValue; 03577 } 03578 03579 03580 /******************************************************************************************** 03581 > KernCode::KernCode(Node* ContextNode, AttachNodeDirection Direction, DocCoord& KernValue) 03582 03583 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03584 Created: 21/12/94 03585 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 03586 03587 Direction: 03588 03589 Specifies the direction in which the node is to be attached to the 03590 ContextNode. The values this variable can take are as follows: 03591 03592 PREV : Attach node as a previous sibling of the context node 03593 NEXT : Attach node as a next sibling of the context node 03594 FIRSTCHILD: Attach node as the first child of the context node 03595 LASTCHILD : Attach node as a last child of the context node 03596 03597 Value: Horizontal/Vertical kern value 03598 03599 Purpose: The main KernCode constructor 03600 ********************************************************************************************/ 03601 03602 KernCode::KernCode(Node* ContextNode, AttachNodeDirection Direction, 03603 DocCoord& KernValue): AbstractTextChar(ContextNode, Direction) 03604 { 03605 Value = KernValue; 03606 } 03607 03608 03609 /******************************************************************************************* 03610 > virtual BOOL KernCode::ExportRender(RenderRegion* pRegion) 03611 03612 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 03613 Created: 14/4/95 03614 Inputs: pRegion - points to the export render region 03615 Returns: TRUE if rendered OK (FALSE=>use normal rendering) 03616 Purpose: This function is called when the render function passes through this node 03617 It outputs the Text Object start and end tokens 03618 ********************************************************************************************/ 03619 03620 BOOL KernCode::ExportRender(RenderRegion* pRegion) 03621 { 03622 #if EXPORT_TEXT 03623 if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion))) 03624 { 03625 // Output any valid text attributes necessary 03626 ((EPSRenderRegion*)pRegion)->GetValidPathAttributes(); 03627 ((EPSRenderRegion*)pRegion)->GetValidTextAttributes(); 03628 03629 EPSExportDC *pDC=(EPSExportDC*)pRegion->GetRenderDC(); 03630 03631 // Use illustrator 3.0 compatible token. 03632 // Any vertical movement is done by BaselineShift 03633 INT32 autokern = 0; 03634 pDC->OutputValue(autokern); 03635 pDC->OutputValue(-(Value.x)); 03636 pDC->OutputToken(_T("Tk")); 03637 pDC->OutputNewLine(); 03638 return TRUE; 03639 } 03640 #endif 03641 return FALSE; 03642 } 03643 03644 03645 /******************************************************************************************** 03646 > Node* KernCode::SimpleCopy() 03647 03648 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03649 Created: 21/12/94 03650 Returns: A copy of the node, or NULL if we are out of memory 03651 Purpose: This method returns a shallow copy of the node with all Node pointers NULL. 03652 The function is virtual, and must be defined for all derived classes of Node 03653 Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory 03654 error and the function returns NULL. 03655 ********************************************************************************************/ 03656 03657 Node* KernCode::SimpleCopy() 03658 { 03659 // Make a new BigChar and then copy things into it 03660 KernCode* NodeCopy = new KernCode(); 03661 03662 ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 03663 03664 if (NodeCopy) 03665 CopyNodeContents(NodeCopy); 03666 03667 return NodeCopy; 03668 } 03669 03670 03671 /*********************************************************************************************** 03672 > void KernCode::CopyNodeContents(KernCode* NodeCopy) 03673 03674 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03675 Created: 28/4/93 03676 Outputs: A copy of this node 03677 Purpose: This method copies the node's contents to the node pointed to by NodeCopy. 03678 Errors: An assertion failure will occur if NodeCopy is NULL 03679 ***********************************************************************************************/ 03680 03681 void KernCode::CopyNodeContents(KernCode* NodeCopy) 03682 { 03683 // Ask the base class to do its bit 03684 AbstractTextChar::CopyNodeContents( NodeCopy ); 03685 // Copy the rest of the data in here 03686 NodeCopy->Value = Value; 03687 } 03688 03689 03690 /*********************************************************************************************** 03691 > void KernCode::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 03692 03693 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 03694 Created: 18/12/2003 03695 Outputs: - 03696 Purpose: Polymorphically copies the contents of this node to another 03697 Errors: An assertion failure will occur if NodeCopy is NULL 03698 Scope: protected 03699 03700 ***********************************************************************************************/ 03701 03702 void KernCode::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 03703 { 03704 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 03705 ENSURE(IS_A(pNodeCopy, KernCode), "PolyCopyNodeContents given wrong dest node type"); 03706 03707 if (IS_A(pNodeCopy, KernCode)) 03708 CopyNodeContents((KernCode*)pNodeCopy); 03709 } 03710 03711 03712 03713 /******************************************************************************************** 03714 > UINT32 KernCode::GetNodeSize() const 03715 03716 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03717 Created: 21/12/94 03718 Returns: The size of the node in bytes 03719 Purpose: For finding the size of the node 03720 ********************************************************************************************/ 03721 03722 UINT32 KernCode::GetNodeSize() const 03723 { 03724 return (sizeof(KernCode)); 03725 } 03726 03727 03728 /******************************************************************************************** 03729 > void KernCode::GetDebugDetails(StringBase* Str) 03730 03731 Author: Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> 03732 Created: 1/2/95 03733 Outputs: Str: String giving debug info about the node 03734 Purpose: For obtaining debug information about the Node. 03735 This fn can be deleted before we ship 03736 ********************************************************************************************/ 03737 03738 void KernCode::GetDebugDetails(StringBase* Str) 03739 { 03740 #if DEBUG_TREE 03741 AbstractTextChar::GetDebugDetails(Str); 03742 String_256 TempStr; 03743 03744 TempStr._MakeMsg( TEXT( "\r\nKernValue = (#1%u, #2%u)"), Value.x, Value.y); 03745 (*Str) += TempStr; 03746 #endif 03747 } 03748 03749 /******************************************************************************************** 03750 03751 > BOOL KernCode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03752 BOOL KernCode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03753 03754 Author: Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com> 03755 Created: 10/07/96 03756 Inputs: pFilter - new file format filter to write record to 03757 Returns: TRUE if successful, FALSE otherwise 03758 Purpose: Writes a kern code record to the new file format filter 03759 03760 ********************************************************************************************/ 03761 03762 BOOL KernCode::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03763 { 03764 #ifdef DO_EXPORT 03765 return CXaraFileTxtKern::WritePreChildrenWeb(pFilter, this); 03766 #else 03767 return FALSE; 03768 #endif 03769 } 03770 03771 BOOL KernCode::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03772 { 03773 #ifdef DO_EXPORT 03774 return CXaraFileTxtKern::WritePreChildrenNative(pFilter, this); 03775 #else 03776 return FALSE; 03777 #endif 03778 } 03779 03780 /******************************************************************************************** 03781 > HorizontalTab::HorizontalTab(Node* ContextNode, AttachNodeDirection Direction) 03782 03783 Author: Martin Wuerthner (xara@mw-software.com) 03784 Created: 07/05/06 03785 Inputs: ContextNode: Pointer to a node which this node is to be attached to. 03786 03787 Direction: 03788 03789 Specifies the direction in which the node is to be attached to the 03790 ContextNode. The values this variable can take are as follows: 03791 03792 PREV : Attach node as a previous sibling of the context node 03793 NEXT : Attach node as a next sibling of the context node 03794 FIRSTCHILD: Attach node as the first child of the context node 03795 LASTCHILD : Attach node as a last child of the context node 03796 03797 Purpose: The main HorizontalTab constructor 03798 ********************************************************************************************/ 03799 03800 HorizontalTab::HorizontalTab(Node* ContextNode, AttachNodeDirection Direction) 03801 :AbstractTextChar(ContextNode, Direction) 03802 { 03803 } 03804 03805 /******************************************************************************************** 03806 03807 > BOOL HorizontalTab::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03808 BOOL HorizontalTab::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03809 03810 Author: Martin Wuerthner <xara@mw-software.com> 03811 Created: 29/06/06 03812 Inputs: pFilter - new file format filter to write record to 03813 Returns: TRUE if successful, FALSE otherwise 03814 Purpose: Writes a tab record to the new file format filter 03815 03816 ********************************************************************************************/ 03817 03818 BOOL HorizontalTab::WritePreChildrenWeb(BaseCamelotFilter *pFilter) 03819 { 03820 #ifdef DO_EXPORT 03821 return CXaraFileTxtTab::WritePreChildrenWeb(pFilter, this); 03822 #else 03823 return FALSE; 03824 #endif 03825 } 03826 03827 BOOL HorizontalTab::WritePreChildrenNative(BaseCamelotFilter *pFilter) 03828 { 03829 #ifdef DO_EXPORT 03830 return CXaraFileTxtTab::WritePreChildrenNative(pFilter, this); 03831 #else 03832 return FALSE; 03833 #endif 03834 } 03835 03836 /******************************************************************************************** 03837 > UINT32 HorizontalTab::GetNodeSize() const 03838 03839 Author: Martin Wuerthner <xara@mw-software.com> 03840 Created: 29/06/06 03841 Returns: The size of the node in bytes 03842 Purpose: For finding the size of the node 03843 ********************************************************************************************/ 03844 03845 UINT32 HorizontalTab::GetNodeSize() const 03846 { 03847 return (sizeof(HorizontalTab)); 03848 } 03849 03850 void HorizontalTab::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 03851 { 03852 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 03853 ENSURE(IS_A(pNodeCopy, HorizontalTab), "PolyCopyNodeContents given wrong dest node type"); 03854 03855 if (IS_A(pNodeCopy, HorizontalTab)) 03856 CopyNodeContents((HorizontalTab*)pNodeCopy); 03857 } 03858 03859 Node* HorizontalTab::SimpleCopy() 03860 { 03861 // Make a new HorizontalTab and then copy things into it 03862 HorizontalTab* NodeCopy = new HorizontalTab(); 03863 03864 ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 03865 03866 if (NodeCopy) CopyNodeContents( NodeCopy ); 03867 03868 return NodeCopy; 03869 } 03870 03871 /******************************************************************************************* 03872 > BOOL HorizontalTab::ExportRender(RenderRegion* pRegion) 03873 03874 Author: Martin Wuerthner <xara@mw-software.com> 03875 Created: 18/07/06 03876 Inputs: pRegion - points to the export render region 03877 Returns: TRUE if rendered OK (FALSE=>use normal rendering) 03878 Purpose: This function is called when the render function passes through this node 03879 It outputs the Text Object start and end tokens 03880 See also: KernCode::ExportRender, on which this routine is based 03881 ********************************************************************************************/ 03882 BOOL HorizontalTab::ExportRender(RenderRegion* pRegion) 03883 { 03884 // a tab is exported as a horizontal kern code 03885 #if EXPORT_TEXT 03886 if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion))) 03887 { 03888 // Output any valid text attributes necessary 03889 ((EPSRenderRegion*)pRegion)->GetValidPathAttributes(); 03890 ((EPSRenderRegion*)pRegion)->GetValidTextAttributes(); 03891 03892 EPSExportDC *pDC=(EPSExportDC*)pRegion->GetRenderDC(); 03893 03894 // Use illustrator 3.0 compatible token. 03895 INT32 autokern = 0; 03896 pDC->OutputValue(autokern); 03897 pDC->OutputValue(GetCharWidth()); 03898 pDC->OutputToken(_T("Tk")); 03899 pDC->OutputNewLine(); 03900 return TRUE; 03901 } 03902 #endif 03903 return FALSE; 03904 }