// $Id: nodebrsh.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // implementation of the NodeBrush class #include "camtypes.h" #include "nodebrsh.h" //#include "group.h" //#include "rndrgn.h" //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "blobs.h" //#include "nodershp.h" #include "ndbrshpt.h" #include "ndbrshmk.h" //#include "progress.h" //#include "objchge.h" //#include "markn.h" //#include "opdrbrsh.h" #include "opshadow.h" //#include "opbevel.h" #include "objchge.h" class BlendRef; CC_IMPLEMENT_DYNCREATE(NodeBrush, NodeGroup); // Declare smart memory handling in Debug builds #define new CAM_DEBUG_NEW #define BRUSH_MIN_SPACING 100 #define BRUSH_MAX_SPACING 10000000 #define BRUSH_DEFAULT_SPACING 10000 /********************************************************************************************* > NodeBrush::NodeBrush() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: Purpose: This constructor creates a NodeBrush linked to no other Errors: **********************************************************************************************/ NodeBrush::NodeBrush(): NodeGroup() { } /*********************************************************************************************** > void NodeBrush::NodeBrush ( Node* ContextNode, AttachNodeDirection Direction, BOOL Locked = FALSE, BOOL Mangled = FALSE, BOOL Marked = FALSE, BOOL Selected = FALSE, ) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: ContextNode: Pointer to a node which this node is to be attached to. Direction: Specifies the direction in which this node is to be attached to the ContextNode. The values this variable can take are as follows: PREV : Attach node as a previous sibling of the context node NEXT : Attach node as a next sibling of the context node FIRSTCHILD: Attach node as the first child of the context node LASTCHILD : Attach node as a last child of the context node The remaining inputs specify the status of the node: Locked: Is node locked ? Mangled: Is node mangled ? Marked: Is node marked ? Selected: Is node selected ? Outputs: - Returns: - Purpose: This method initialises the node and links it to ContextNode in the direction specified by Direction. All necessary tree links are updated. Errors: An assertion error will occur if ContextNode is NULL ***********************************************************************************************/ NodeBrush::NodeBrush(Node* ContextNode, AttachNodeDirection Direction, BOOL Locked, BOOL Mangled, BOOL Marked, BOOL Selected ):NodeGroup(ContextNode, Direction, Locked, Mangled, Marked, Selected) { } /********************************************************************************************* > NodeBrush::~NodeBrush() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: Purpose: Destructor Errors: **********************************************************************************************/ NodeBrush::~NodeBrush() { } /******************************************************************************************** > DocRect NodeBrush::GetBlobBoundingRect() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Returns: DocRect - The bounding rect of the node and its blobs Purpose: This calls the base classes GetBlobBoundingRect(), and inflates the result by the width of a blob ********************************************************************************************/ DocRect NodeBrush::GetBlobBoundingRect() { #if !defined(EXCLUDE_FROM_RALPH) // Find the base class blob bounding rectangle DocRect Rect = NodeGroup::GetBlobBoundingRect(); // inflate it by the width of a blob (plus a bit) DocRect TempRect; GetApplication()->GetBlobManager()->GetBlobRect(Rect.lo,&TempRect); INT32 Delta = ((TempRect.hi.x - TempRect.lo.x)*1)/1; Rect.Inflate(Delta); return Rect; #else return DocRect(0,0,0,0); #endif } /******************************************************************************************** > DocRect NodeBrusher::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 11/10/94 Inputs: DontUseAttrs - TRUE if we should ignore the nodes attributes. Defaults to FALSE HitTest - TRUE if being called during HitTest Returns: The nodes bounding rect Purpose: if the bounding rect is valid it is returned, if not, it is recalculated and then returned. SeeAlso: NodeBrusher::GetBlobBoundingRect ********************************************************************************************/ DocRect NodeBrush::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest) { /* // first get the bounding rect of the path DocRect Rect = m_pNodeBrushPath->GetBoundingRect(); // inflate by half the size of the brush ink object. NodeRenderableInk* pInk = m_pNodeBrushMaker->GetInkNode(); if (pInk != NULL) { DocRect InkRect = pInk->GetBoundingRect(); INT32 dx = InkRect.Width() / 2; INT32 dy = InkRect.Height() / 2; Rect.Inflate(dx, dy); } return Rect; */ // default docrect constructor makes empty rect DocRect Rect; if (m_pNodeBrushMaker != NULL) Rect = m_pNodeBrushMaker->GetBoundingRect(); return Rect; } /******************************************************************************************** > void NodeBrush::Render (RenderRegion* pRender) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: pRender - The region to draw the blobs in Purpose: Renders the nodebrushpath, if selected, otherwise nothing. The main rendering is performed by the nodebrushmaker ********************************************************************************************/ void NodeBrush::Render(RenderRegion* pRender) { if (this->IsSelected()) { if (m_pNodeBrushPath != NULL) m_pNodeBrushPath->RenderObjectBlobs(pRender); } if (m_pNodeBrushMaker != NULL) m_pNodeBrushMaker->Render(pRender); } /******************************************************************************************** > virtual SubtreeRenderState NodeBrush::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip = TRUE) Author: Phil_Martin (Xara Group Ltd) Created: 22/06/2004 Inputs: A Render Region to Render into. Returns: PRE_FAILED for something went wrong, PRE_RENDER_CHILDREN for continue to render children, PRE_NO_RENDER_CHILDREN for DO NOT Render any of my children!!!! Purpose: Enables Nodes to be able to Do Pre Print time alterations or even take over the control of the current Printing of their children. ********************************************************************************************/ SubtreeRenderState NodeBrush::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip) { return SUBTREE_ROOTONLY; } /******************************************************************************************** > void NodeBrush::RenderObjectBlobs(RenderRegion* pRender) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: pRender - The region to draw the blobs in Purpose: Renders the object blobs ********************************************************************************************/ void NodeBrush::RenderObjectBlobs(RenderRegion* pRegion) { #if !defined(EXCLUDE_FROM_RALPH) // Find out about the groups bounding rect DocRect BoundingRect = GetBoundingRect(); // Inflate the bounds by the width of a blob DocRect TempRect; GetApplication()->GetBlobManager()->GetBlobRect(BoundingRect.lo,&TempRect); INT32 Delta = ((TempRect.hi.x - TempRect.lo.x)*3)/4; BoundingRect.Inflate(Delta); // Find out where to draw the blobs DocCoord Low = BoundingRect.LowCorner(); DocCoord High = BoundingRect.HighCorner(); // Set the colours of the blobs pRegion->SetFillColour(COLOUR_UNSELECTEDBLOB); pRegion->SetLineColour(COLOUR_NONE); // Draw all the blobs pRegion->DrawBlob(Low, BT_UNSELECTED); pRegion->DrawBlob(High, BT_UNSELECTED); pRegion->DrawBlob(DocCoord(Low.x, High.y), BT_UNSELECTED); pRegion->DrawBlob(DocCoord(High.x, Low.y), BT_UNSELECTED); // for some reason the NBP is never called, there is probably a // proper fix for this but I don't have time right now, so render // the nodeblend path here m_pNodeBrushPath->RenderObjectBlobs(pRegion); #endif } /******************************************************************************************** > void NodeBrush::RenderTinyBlobs(RenderRegion* pRender) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: pRender - The region to draw the blobs in Purpose: Renders the object blobs ********************************************************************************************/ void NodeBrush::RenderTinyBlobs(RenderRegion* pRegion) { // for some reason the NBP is never called, there is probably a // proper fix for this but I don't have time right now, so render // the nodeblend path here m_pNodeBrushPath->RenderTinyBlobs(pRegion); } /******************************************************************************************** > void NodeBrush::Transform(TransformBase& Trans) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/10/99 Inputs: Trans - the transformation to perform Purpose: transforms the brush ********************************************************************************************/ void NodeBrush::Transform(TransformBase& Trans) { // The groups bounding rect is no longer valid InvalidateBoundingRect(); // Transform all the children // See GroupCanTransformCached() NodeGroup::Transform(Trans); } /******************************************************************************************** > virtual BOOL NodeBrush::WritePreChildrenWeb(BaseCamelotFilter* pFilter) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/20/99 Inputs: pFilter = ptr to the filter Returns: TRUE if record is written, FALSE if not Purpose: Writes the brush record to the filter SeeAlso: - ********************************************************************************************/ BOOL NodeBrush::WritePreChildrenWeb(BaseCamelotFilter* pFilter) { return TRUE; } /******************************************************************************************** > virtual BOOL NodeBrush::WritePreChildrenNative(BaseCamelotFilter* pFilter) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 7/20/99 Inputs: pFilter = ptr to the filter Returns: TRUE if record is written, FALSE if not Purpose: Writes the brush record to the filter SeeAlso: - ********************************************************************************************/ BOOL NodeBrush::WritePreChildrenNative(BaseCamelotFilter* pFilter) { return TRUE; } /*********************************************************************************************** > Node* NodeBrush::SimpleCopy() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: - Outputs: - Returns: A copy of the node, or NULL if memory has run out Purpose: This method returns a shallow copy of the node with all Node pointers NULL. The function is virtual, and must be defined for all derived classes. Errors: If memory runs out when trying to copy, then ERROR is called with an out of memory error and the function returns NULL. **********************************************************************************************/ Node* NodeBrush::SimpleCopy() { NodeBrush* pCopyOfNode = new NodeBrush(); if (pCopyOfNode != NULL) CopyNodeContents(pCopyOfNode); return (pCopyOfNode); } /*********************************************************************************************** > void NodeBrush::CopyNodeContents(Node* pCopyOfNode) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: pCopyOfNode - The node to copy data to Outputs: - Returns: - Purpose: Copies the data from this node to pCopyOfNode by first calling the base class to get it to copy its stuff, and then copying its own stuff Scope: protected SeeAlso: NodeGroup::CopyNodeContents ***********************************************************************************************/ void NodeBrush::CopyNodeContents(NodeBrush* pCopyOfNode) { NodeGroup::CopyNodeContents(pCopyOfNode); // Copy member vars here } /*********************************************************************************************** > void NodeBrush::PolyCopyNodeContents(NodeRenderable* pNodeCopy) Author: Phil_Martin (Xara Group Ltd) Created: 18/12/2003 Outputs: - Purpose: Polymorphically copies the contents of this node to another Errors: An assertion failure will occur if NodeCopy is NULL Scope: protected ***********************************************************************************************/ void NodeBrush::PolyCopyNodeContents(NodeRenderable* pNodeCopy) { ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); ENSURE(IS_A(pNodeCopy, NodeBrush), "PolyCopyNodeContents given wrong dest node type"); if (IS_A(pNodeCopy, NodeBrush)) CopyNodeContents((NodeBrush*)pNodeCopy); } /******************************************************************************************** > virtual String NodeBrush::Describe(BOOL Plural, BOOL Verbose = TRUE) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Plural: Flag indicating if the string description should be plural or singular. Outputs: - Retuns: Description of the blend node Purpose: To return a description of the Brush object in either the singular or the plural. This method is called by the DescribeRange method. The description will always begin with a lower case letter. Errors: - SeeAlso: - ********************************************************************************************/ String NodeBrush::Describe(BOOL Plural, BOOL Verbose) { return m_BrushName; } /********************************************************************************************* > NodeBrushPath* NodeBrush::GetNodeBtushPath() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: the nodebrushpath used by this brush Purpose: as above **********************************************************************************************/ NodeBrushPath* NodeBrush::GetNodeBrushPath() { return m_pNodeBrushPath; } /********************************************************************************************* > void NodeBrush: SetNodeBrushPath() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: the nodebrushpath used by this brush Purpose: as above **********************************************************************************************/ void NodeBrush::SetNodeBrushPath(NodeBrushPath* pPath) { m_pNodeBrushPath = pPath; } /********************************************************************************************* > NodeBrushMaker* NodeBrush::GetNodeBtushMaker() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: the nodebrushMaker used by this brush Purpose: as above **********************************************************************************************/ NodeBrushMaker* NodeBrush::GetNodeBrushMaker() { return m_pNodeBrushMaker; } /********************************************************************************************* > void NodeBrush: SetNodeBrushMaker() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: Outputs: Returns: the nodebrushMaker used by this brush Purpose: as above **********************************************************************************************/ void NodeBrush::SetNodeBrushMaker(NodeBrushMaker* pMaker) { m_pNodeBrushMaker = pMaker; } /********************************************************************************************* > MILLIPOINT NodeBrush: GetBrushSpacing() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 19/11/99 Inputs: Outputs: Returns: the spacing between objects of this brush Purpose: as above **********************************************************************************************/ MILLIPOINT NodeBrush::GetBrushSpacing() { if (m_pNodeBrushMaker != NULL) return m_pNodeBrushMaker->GetBrushSpacing(); else { ERROR3("NodeBrushMaker is NULL"); return 0; } } /********************************************************************************************* > void NodeBrush: SetBrushSpacing(MILLIPOINT Spacing) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 18/11/99 Inputs: Spacing to set Outputs: Returns: - Purpose: Sets the distance between brush objects used buy the nodebrushmaker **********************************************************************************************/ void NodeBrush::SetBrushSpacing(MILLIPOINT Spacing) { if (Spacing >= BRUSH_MIN_SPACING && Spacing >= BRUSH_MAX_SPACING) { ERROR3("Invalid spacing got passed to NodeBrush::SetBrushSpacing"); Spacing = BRUSH_DEFAULT_SPACING; } if (m_pNodeBrushMaker != NULL) { m_pNodeBrushMaker->SetBrushSpacing(Spacing); } else ERROR3("NodeBrushMaker is NULL"); } /******************************************************************************************** > BOOL NodeBrush::ResetBrushPath() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: - Outputs: - Returns: TRUE if successful, FALSE otherwise Purpose: Asks the nodebrushmaker to recalculate its number of steps, for use when the nodebrushpath has been edited ********************************************************************************************/ BOOL NodeBrush::ResetBrushPath() { // get the brushmaker to recalculate how many steps it needs if (m_pNodeBrushMaker != NULL) { m_pNodeBrushMaker->RecalculateMaxStep(); m_pNodeBrushMaker->ClearListOfPointsToRender(); } else { ERROR3("NodeBrushMaker is NULL"); return FALSE; } return TRUE; } /******************************************************************************************** > BOOL NodeBrush::ReInitialiseInk() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: - Outputs: - Returns: TRUE if successful, FALSE otherwise Purpose: Asks the nodebrushmaker to reinitialise itself, for use when the ink node has been altered, e.g. attribute changes. Note that this must be called AFTER the attribute change in order to work. ********************************************************************************************/ BOOL NodeBrush::ReInitialiseInk() { if (m_pNodeBrushMaker!= NULL) { NodeRenderableInk* pInk = m_pNodeBrushMaker->GetInkNode(); if (pInk != NULL) { //if (!m_pNodeBrushMaker->InitialiseInk(pInk)) // return FALSE; //else { // clear the cache in case we have any points left to render m_pNodeBrushMaker->ClearListOfPointsToRender(); return TRUE; } } } ERROR3("NodeBrushMaker is NULL"); return FALSE; } /******************************************************************************************** > void NodeBrush::ChangeNodeBrushPath(NodeBrushPath * pNewPath) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/10/99 Inputs: pNewPath - the new path to set Outputs: - Returns: TRUE if successful, FALSE otherwise Purpose: Changes the nodebrushpath used by the brush ********************************************************************************************/ /* IMPLEMENTATION NOTE: This function was written for use when the path was modified using the freehand or bezier tool. These operations take care of hiding the old nodebrushpath for you, so it is not performed here. If you wish to use this function for some other purpose then make sure you do something with the original nodebrushpath before swapping in a new one */ BOOL NodeBrush::ChangeNodeBrushPath(NodeBrushPath* pNewPath) { if (pNewPath == NULL) { ERROR3("NodeBrushPath is NULL"); return FALSE;; } m_pNodeBrushPath = pNewPath; if (m_pNodeBrushMaker != NULL) m_pNodeBrushMaker->InitialisePath(pNewPath); else { ERROR3("NodeBrushMaker is NULL"); return FALSE;; } return TRUE; } /********************************************************************************************* > Node* NodeBrush::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 19/11/99 Inputs: ChildClass = the runtime class of the editable object pPreviousChild = a pointer to the previous editable child returned by 'this' node, NULL if this is the first call to this node. Outputs: - Returns: A node pointer, to an object which forms part of the editable surface of its parent (this node). Purpose: This function returns our edit node (the NodeBrushPath) **********************************************************************************************/ Node* NodeBrush::HasEditableChild(CCRuntimeClass* ChildClass, Node* pPreviousChild) { if (ChildClass != CC_RUNTIME_CLASS(NodePath)) return NULL; NodeBrushPath* pNodeBrushPath = GetNodeBrushPath(); // check to see if this has already been asked for once if (((Node*)pNodeBrushPath) == pPreviousChild) return NULL; return pNodeBrushPath; } /********************************************************************************************* > NodeRenderableInk* NodeBrush: GetInkNode() Author: Diccon_Yamanaka (Xara Group Ltd) Created: 19/11/99 Inputs: Outputs: Returns: the ink node used by the nodebrushmaker to generate the blendpaths Purpose: as above **********************************************************************************************/ NodeRenderableInk* NodeBrush::GetInkNode() { if (m_pNodeBrushMaker != NULL) { return m_pNodeBrushMaker->GetInkNode(); } return NULL; } /******************************************************************************************** > virtual BOOL NodeBrush::AllowOp(ObjChangeParam* pParam,BOOL SetOpPermissionState = TRUE) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/12/99 Inputs: pParam = describes the way an op wants to change the node SetOpPermissionState = if TRUE the Op permission state of this node will be set according to the outcome of the call Outputs: - Returns: TRUE means the node and all its parents are happy with this op, FALSE means don't do it Purpose: In this instance, the func gives the brush a chance to stop an op from happening to one of its children. Currently the only permitted ops on children are those that change their appearance, .eg. change fill, line width etc. This must be called *before* the op is performed. SeeAlso: Node::AllowOp(),GetOpPermission(),SetOpPermission(); ********************************************************************************************/ BOOL NodeBrush::AllowOp(ObjChangeParam* pParam, BOOL SetOpPermissionState) { ERROR2IF(pParam==NULL,FALSE,"NodeBlend::AllowOp() - pParam==NULL"); // clean out the calling-child ptr, so it doesn't get passed around unintentionally. pParam->SetCallingChild(NULL); // decide if we allow it ... (and if we'll still exist after the op) BOOL allowed=TRUE; ObjChangeFlags Flags=pParam->GetChangeFlags(); if (pParam->GetDirection()==OBJCHANGE_CALLEDBYCHILD) { if (Flags.DeleteNode || Flags.MultiReplaceNode || Flags.MoveNode) { pParam->SetReasonForDenial(_R(IDS_BLEND_CANT_OP_ON_CHILDREN)); allowed=FALSE; } } // if we allow it, (and our parents weren't calling us) see if our parents do ... if (allowed && pParam->GetDirection()!=OBJCHANGE_CALLEDBYPARENT && Parent!=NULL) { ObjChangeDirection OldDirection=pParam->GetDirection(); pParam->SetCallingChild(this); pParam->SetDirection(OBJCHANGE_CALLEDBYCHILD); allowed=Parent->AllowOp(pParam,SetOpPermissionState); pParam->SetDirection(OldDirection); } if (allowed && pParam->GetDirection() == OBJCHANGE_CALLEDBYCHILD) { if (pParam->GetOpPointer()) { if (pParam->GetOpPointer()->IS_KIND_OF(OpApplyShadow)) { allowed = FALSE; } PORTNOTE("other", "Removed use of OpCreateBevel from NodeBrush::AllowOp") #if !defined(EXCLUDE_FROM_XARALX) if (pParam->GetOpPointer()->IS_KIND_OF(OpCreateBevel)) { allowed = FALSE; } #endif } } // if setting permisions ... (and possibly cause post-op code to be called) if (SetOpPermissionState) { if (allowed) { if (Parent!=NULL) Parent->SetOpPermission(PERMISSION_ALLOWED); // if post process required, ensure our OnChildChange is called (by setting permission on ourself), // insert an inverse action in the undo if (pParam->GetDirection()==OBJCHANGE_CALLEDBYCHILD || Flags.Attribute) { SetOpPermission(PERMISSION_ALLOWED); PORTNOTE("other", "Removed use of ChangeBrushOpParam from NodeBrush::AllowOp") #if !defined(EXCLUDE_FROM_XARALX) UndoableOperation* pOp=pParam->GetOpPointer(); if (pOp!=NULL) { ChangeBrushOpParam BrushParam; BrushParam.ChangeType = CHANGEBRUSH_REGEN; ChangeBrushAction* pNewAction; if (allowed) allowed=(ChangeBrushAction::Init(pOp, pOp->GetUndoActionList(), this, &BrushParam, &pNewAction) != AC_FAIL); if (allowed) allowed=pOp->DoInvalidateNodeRegion(this,TRUE); } #endif } } else SetOpPermission(PERMISSION_DENIED,TRUE); } // if the op was allowed, inform our children by calling their AllowOp()s // this must be done after we've inserted our undo actions so that any child undo actions will be undone first! if (allowed && pParam->GetDirection()!=OBJCHANGE_CALLEDBYCHILD) AllowOp_AccountForCompound(pParam, SetOpPermissionState); // return result (directly, or indirectly via a child AllowOp()) to op return allowed; } /******************************************************************************************** > virtual ChangeCode NodeBlend::OnChildChange(ObjChangeParam* pParam) Author: Diccon_Yamanaka (Xara Group Ltd) Created: 6/12/99 Inputs: pParam = pointer to a object change parameter class Returns: CC_OK if we have successfully processed the change. CC_FAIL if we cannot handle this particular change and must prevent the child from continuing Purpose: This function should be overridden in derived object classes. Composite objects can use this function to respond to one of their children undergoing a change. They should return CC_FAIL whenever they are unable to cope with the change. Brushes simply regenerate themselves at the moment. SeeAlso: WarnParentOfChange(),AllowOp(); ********************************************************************************************/ ChangeCode NodeBrush::OnChildChange(ObjChangeParam* pParam) { PORTNOTE("other","NodeBrush::OnChildChange - ChangeBrushAction ChangeBrushOpParam") #ifndef EXCLUDE_FROM_XARALX ERROR2IF(pParam == NULL,CC_FAIL,"pParam == NULL"); ObjChangeType cType = pParam->GetChangeType(); ObjChangeFlags Flags = pParam->GetChangeFlags(); if (cType == OBJCHANGE_FINISHED) { UndoableOperation* pUndoOp = pParam->GetOpPointer(); if (pUndoOp == NULL) { ERROR3("Couldn't get undo op"); return CC_FAIL; } ChangeBrushAction* pAction; ChangeBrushOpParam OpParam; OpParam.ChangeType = CHANGEBRUSH_REGEN; BOOL ok = (ChangeBrushAction::Init(pUndoOp, pUndoOp->GetUndoActionList(), this, &OpParam, &pAction) != AC_FAIL); if (ok) ok = pUndoOp->DoInvalidateNodeRegion(this,TRUE); if (ok) return CC_OK; else return CC_FAIL; } #endif return CC_OK; }