OpBlendNodes Class Reference

#include <blndtool.h>

Inheritance diagram for OpBlendNodes:

SelOperation UndoableOperation Operation MessageHandler ListItem CCObject SimpleCCObject List of all members.

Public Member Functions

 OpBlendNodes ()
 Constructor.
 ~OpBlendNodes ()
 Destructor.
BOOL DoDrag (BlendTool *pBlendTool)
 This starts a drag that may lead to a blend. The DragFinished() method will do the hard work of blending if it can be done.
virtual BOOL SnappingDrag ()
virtual void DragPointerMove (DocCoord PointerPos, ClickModifiers ClickMods, Spread *, BOOL bSolidDrag)
 Pure virtual function which tells the operation that the mouse has moved.
virtual void DragFinished (DocCoord PointerPos, ClickModifiers ClickMods, Spread *, BOOL Success, BOOL bSolidDrag)
 Ends the drag. Either creates a new grid or resizes GridClicked depending on the state of affairs when the drag started.
void RenderMyDragBlobs ()
 Draws an EORed rectangle defined by AnchorPoint and DragPoint.
void RenderDragBlobs (DocRect Rect, Spread *pSpread, BOOL bSolidDrag)
 Draws an EORed rectangle defined by AnchorPoint and DragPoint.
void GetOpName (String_256 *OpName)
 The GetOpName fn is overridden so that we return back a description appropriate to the type of attribute that the operation applies.
virtual BOOL Undo ()
 Gets called whenever this operation is undone.
virtual BOOL Redo ()
 Gets called whenever this operation is Redone.
BOOL RecordBlenderInfo (List &BlenderList, NodeBlend *pNodeBlend)
 This scans the blenders in the given blend node, creating a BlenderInfoItem for each NodeBlender. Each BlenderInfoItem is placed on BlenderList.
void DeinitBlenders (List &BlenderList)
 This scans the blenders, calling the Deinit() method for each of them.
BOOL ReinitBlenders (List &BlenderList)
 This scans the blenders, calling the Reinit() method for each of them. It uses the start and end node pointers gathered by RecordBlenderInfo() when calling Reinit().
BOOL GetNodeClosestToPoint (NodeRenderableInk **ppInk, BOOL StartBlend)
 when blending from two blends, this retrieves the node closest to the actual point where the blend began or ended

Static Public Member Functions

static BOOL Declare ()
 Adds the operation to the list of all known operations.
static OpState GetState (String_256 *Description, OpDescriptor *)
 Find out the state of the operation at the specific time.

Private Member Functions

 CC_DECLARE_DYNCREATE (OpBlendNodes)
BOOL DoBlendObjects ()
 This blends two objects together to form a new blend object in the tree. All the data that's required is stored in pRefStart (for the start object) and pRefEnd (for the end object). It assumes that neither the start or end objects are blends, so no clever merging of blend objects will take place here.
BOOL DoCreateBlender (NodeRenderableInk *pNodeStart, INT32 IndexStart, NodeRenderableInk *pNodeEnd, INT32 IndexEnd, Node *pContextNode, AttachNodeDirection AttachDir)
 This forms a blender object in the tree that can blend pRefStart->pNode to pRefEnd->pNode.
BOOL DoRemapBlend ()
 This tries to remap a blend using the data held in pRefStart && pRefEnd. It asks the pNodeBlend object to try and remap the two paths by rotating the path elements so that the element at Index is the first element in the path.
BOOL DoBlendBlendAndObject ()
 This blends a blend object with another non-blend object. This is like a concatination of the the two nodes, resulting a single blend with an extra blend stage. E.g. blending a blend containing two paths (i.e. a single blend of two objects) with another path. The result will be a single blend object, blending the first path to the second, and the second to the third.
BOOL DoBlendBlendAndBlend ()
 This merges to blend nodes together, so that the last object in the first blend is blended with the first of the second blend.
BOOL DoDeinitBlenders (List &BlenderList)
 This calls DeinitBlenders() on the given list, and creates an action that will call ReinitBlenders() on undo, and DeinitBlenders() on redo.
BOOL DoReinitBlenders (List &BlenderList)
 This calls ReinitBlenders() on the given list, and creates an action that will call DeinitBlenders() on undo, and ReinitBlenders() on redo.
BOOL DeterminBlendObjectsProcessorHit ()
 This function provides a quick (and rough) estimate on the amount of work that will have to be done to create the blend. This estimate is based upon the total length of all paths that exist within the start and end nodes. An attempt is also made at altering the 'threshold' based upon the CPU type.
BOOL RemoveCompoundNodes (CompoundNodeTreeFactoryList *pList)
 Removes all compound nodes.
BOOL RemoveCompoundNodesFromNode (Node *pNode, Node **pRetnNode, CompoundNodeTreeFactoryList *pList)
 Removes all compound nodes from the given node (i.e. unshadows and unbevels nodes).
BOOL DoContourNode (Node *pNode, DocCoord PointerPos, UINT32 Steps)
 Applies a contour to the given node.

Private Attributes

BlendToolRefpRefStart
BlendToolRefpRefEnd
OpBlendOpType OpType
NodeBlendpNodeBlend
NodeBlendpNodeBlendStart
NodeBlendpNodeBlendEnd
BlendToolm_pBlendTool

Detailed Description

Definition at line 475 of file blndtool.h.


Constructor & Destructor Documentation

OpBlendNodes::OpBlendNodes  ) 
 

Constructor.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/10/94

Definition at line 3081 of file blndtool.cpp.

03082 {
03083     pRefStart = NULL;
03084     pRefEnd   = NULL;
03085     OpType    = BLENDOPTYPE_NONE;
03086 
03087     pNodeBlend      = NULL;
03088     pNodeBlendStart = NULL;
03089     pNodeBlendEnd   = NULL;
03090 }

OpBlendNodes::~OpBlendNodes  ) 
 

Destructor.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/10/94

Definition at line 3102 of file blndtool.cpp.

03103 {
03104 }


Member Function Documentation

OpBlendNodes::CC_DECLARE_DYNCREATE OpBlendNodes   )  [private]
 

BOOL OpBlendNodes::Declare  )  [static]
 

Adds the operation to the list of all known operations.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/10/94
Returns:
TRUE if all went OK, FALSE otherwise

Definition at line 4561 of file blndtool.cpp.

04562 {
04563     return (RegisterOpDescriptor(
04564                                 0, 
04565                                 _R(IDS_BLEND_TOOL),
04566                                 CC_RUNTIME_CLASS(OpBlendNodes), 
04567                                 OPTOKEN_BLENDNODES,
04568                                 OpBlendNodes::GetState,
04569                                 0,          /* help ID */
04570                                 _R(IDBBL_NOOP), /* bubble ID */
04571                                 0           /* bitmap ID */
04572                                 ));
04573 }

void OpBlendNodes::DeinitBlenders List BlenderList  ) 
 

This scans the blenders, calling the Deinit() method for each of them.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/11/94
Parameters:
BlenderList = reference to a list of blender info items [INPUTS]
- [OUTPUTS]
Returns:
-

Definition at line 3819 of file blndtool.cpp.

03820 {
03821     BlenderInfoItem* pItem = (BlenderInfoItem*) BlenderList.GetHead();
03822 
03823     while (pItem != NULL)
03824     {
03825         pItem->pNodeBlender->Deinit();
03826         pItem = (BlenderInfoItem*) BlenderList.GetNext(pItem);
03827     }
03828 }

BOOL OpBlendNodes::DeterminBlendObjectsProcessorHit  )  [private]
 

This function provides a quick (and rough) estimate on the amount of work that will have to be done to create the blend. This estimate is based upon the total length of all paths that exist within the start and end nodes. An attempt is also made at altering the 'threshold' based upon the CPU type.

Author:
Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
Date:
6/9/2000
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
TRUE if should continue, FALSE otherwise
This system could probably be enhanced - but for now it seems to work fine.

Definition at line 4338 of file blndtool.cpp.

04339 {
04340     Node* pStart = pRefStart->pNode;
04341     Node* pEnd = pRefEnd->pNode;
04342 
04343     INT32 complexityEstimate1 = pStart->EstimateNodeComplexity (NULL);
04344     INT32 complexityEstimate2 = pEnd->EstimateNodeComplexity (NULL);
04345 
04346     INT32 generatedPathsEstimate = 3*complexityEstimate1 + 2*complexityEstimate2;
04347 
04348     static BOOL foundCPU = FALSE;
04349     static INT32 pathsBeforeAsk = 0;
04350 
04351     if (!foundCPU)
04352     {
04353 /*      SYSTEM_INFO systemInfo;
04354         GetSystemInfo (&systemInfo);
04355 
04356         if (systemInfo.dwProcessorType == PROCESSOR_INTEL_386)
04357         {
04358             pathsBeforeAsk = 6000;
04359         }
04360         else if (systemInfo.dwProcessorType == PROCESSOR_INTEL_486)
04361         {
04362             pathsBeforeAsk = 12000;
04363         }
04364         else if (systemInfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM)
04365         {
04366             pathsBeforeAsk = 20000;
04367         }
04368         else */
04369         {
04370             // assume its faster than a pentium .... (in 2005 this will alwys be the case!)
04371             pathsBeforeAsk = 24000;
04372         }
04373         foundCPU = TRUE;
04374     }
04375 
04376     if (generatedPathsEstimate > pathsBeforeAsk)
04377     {
04378         // Load and build the question text.
04379         String_256 QueryString(_R(IDS_ASKLONGJOB));
04380                         
04381         // The only way of bringing up a box with a string in it
04382         Error::SetError(0, QueryString, 0);
04383         INT32 DlgResult = InformMessage(0, _R(IDS_YES), _R(IDS_NO));
04384         Error::ClearError();
04385 
04386         switch (DlgResult)
04387         {
04388             case 1:     // YES
04389                 return (TRUE);
04390             break;
04391             case 2:     // NO
04392                 return (FALSE);         // break out of this stuff!
04393         }
04394     }
04395 
04396     return (TRUE);
04397 }

BOOL OpBlendNodes::DoBlendBlendAndBlend  )  [private]
 

This merges to blend nodes together, so that the last object in the first blend is blended with the first of the second blend.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
18/11/94
Parameters:
- (data is taken from pRefStart and pRefEnd member vars) [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise

Definition at line 3498 of file blndtool.cpp.

03499 {
03500     // Get ptr to the NodeBlends in question, and put them in the member vars pNodeBlendStart & pNodeBlendEnd
03501     pNodeBlendStart = (NodeBlend*)pRefStart->pNode;
03502     pNodeBlendEnd   = (NodeBlend*)pRefEnd  ->pNode;
03503 
03504     // DY changed to allow for new blending to and from a blend on a path
03505     if (pNodeBlendStart->IsOnACurve() || pNodeBlendEnd->IsOnACurve())
03506     {
03507         OpType = BLENDOPTYPE_BLENDBLENDONPATH;
03508         pNodeBlendStart->SetBlendedOnCurve(TRUE);
03509     }
03510     else
03511         OpType = BLENDOPTYPE_BLENDANDBLEND;
03512 
03513 
03514     if (pNodeBlendStart == NULL || pNodeBlendEnd == NULL || pNodeBlendStart == pNodeBlendEnd) return FALSE;
03515 
03516     ERROR3IF(!IS_A(pNodeBlendStart,NodeBlend) || !IS_A(pNodeBlendEnd,NodeBlend),"Either start or end is not a NodeBlend");
03517     if (!IS_A(pNodeBlendStart,NodeBlend) || !IS_A(pNodeBlendEnd,NodeBlend)) return FALSE;
03518 
03519     // Get a record of all the blenders in the blend nodes
03520     List BlenderListStart,BlenderListEnd;
03521     if (!RecordBlenderInfo(BlenderListStart,pNodeBlendStart) || !RecordBlenderInfo(BlenderListEnd,pNodeBlendEnd))
03522     {
03523         // Tidy up if we fail to get blender info on the two blend nodes
03524         BlenderListStart.DeleteAll();
03525         BlenderListEnd  .DeleteAll();
03526         return FALSE;
03527     }
03528 
03529     //BlenderInfoItem*   pItemStart = (BlenderInfoItem*)BlenderListStart.GetTail();
03530     //BlenderInfoItem*   pItemEnd   = (BlenderInfoItem*)BlenderListEnd  .GetHead();
03531     NodeRenderableInk* pNodeStart = NULL;  //pItemStart->pNodeEnd;
03532     NodeRenderableInk* pNodeEnd   = NULL;  //pItemEnd  ->pNodeStart;
03533 
03534     BOOL ok = GetNodeClosestToPoint(&pNodeStart, TRUE);
03535     if (ok) ok = GetNodeClosestToPoint(&pNodeEnd, FALSE);
03536     ERROR3IF(pNodeStart == NULL,"The start node ptr is NULL");
03537     ERROR3IF(pNodeEnd   == NULL,"The end node ptr is NULL");
03538     if (pNodeStart == NULL || pNodeEnd == NULL) return FALSE;
03539 
03540     BlobManager* pBlobManager = GetApplication()->GetBlobManager();
03541     ENSURE(pBlobManager, "Can't get BlobManager");
03542 
03543     ok = DeterminBlendObjectsProcessorHit ();
03544 
03545     // Now we are ready to do the actual blend
03546 
03547     // Firstly, record the selection state
03548     if (ok) ok = DoStartSelOp(TRUE,TRUE);
03549 
03550     if (ok) ok = (Tool::GetCurrent() != NULL);
03551     if (ok) pBlobManager->RenderToolBlobsOff(Tool::GetCurrent(), pRefStart->pSpread,NULL);
03552     if (ok) NodeRenderableInk::DeselectAll(FALSE);
03553 
03554     // Select the start blend node
03555     if (ok) pNodeBlendStart->SetSelected(TRUE);
03556 
03557     // Deinit all the blenders in the end blend.
03558     if (ok) ok = DoDeinitBlenders(BlenderListEnd);
03559 
03560     // Localise the attributes in the start blend
03561     if (ok) ok = DoLocaliseCommonAttributes(pNodeBlendStart);
03562 
03563     // Localise the attributes in the end blend
03564     if (ok) ok = DoLocaliseCommonAttributes(pNodeBlendEnd);
03565 
03566     // Hide the end blend node
03567     NodeHidden* pNodeHidden;
03568     if (ok) ok = DoHideNode(pNodeBlendEnd,TRUE,&pNodeHidden);
03569 
03570     if (ok)
03571     {
03572         // DY update blendpath indexes in existing blenders before we
03573         // move them
03574         INT32 FirstBlendNumPaths = pNodeBlendStart->GetNumNodeBlendPaths();
03575         NodeBlender* pBlender = pNodeBlendEnd->FindFirstBlender();
03576         while (pBlender != NULL)
03577         {
03578             INT32 CurrentIndex = pBlender->GetNodeBlendPathIndex();
03579             if (CurrentIndex > -1)
03580             {
03581                 ChangeBlenderOpParam Param;
03582                 Param.m_NewNodeBlendPathIndex = (CurrentIndex + FirstBlendNumPaths);
03583                 Param.m_ChangeType = CHANGEBLENDER_NBPINDEX;
03584                 ok = ChangeBlenderAction::Init(this, &UndoActions, pBlender, Param);
03585             }
03586             pBlender =  pNodeBlendEnd->FindNextBlender(pBlender);
03587         }
03588     }
03589 
03590     // Now move all the end blend's children (except hidden nodes) into the start blend.
03591     if (ok)
03592     {
03593         Node* pNode = pNodeBlendEnd->FindFirstChild();
03594         while (pNode != NULL && ok)
03595         {
03596             Node* pNext = pNode->FindNext();
03597             if (!pNode->IS_KIND_OF(NodeHidden))
03598                 ok = DoMoveNode(pNode,pNodeBlendStart,LASTCHILD);
03599             
03600             // DY keep track of which nodeblendpath this is
03601             //if (pNode->IS_KIND_OF(NodeBlendPath))
03602             //  ((NodeBlendPath*)pNode)->SetPathIndex();
03603             pNode = pNext;
03604         }
03605     }
03606 
03607     // Create a blender node to blend the two nodes
03608     if (ok) ok = DoCreateBlender(pNodeStart,-1,pNodeEnd,-1,pNodeStart,NEXT);
03609 
03610     // Reinit the end blenders using the same start and end pointers they were using before the blend
03611     if (ok) ok = DoReinitBlenders(BlenderListEnd);
03612 
03613     // Factor out any common attrs that might have been copied during the blend
03614     if (ok) ok = DoFactorOutCommonChildAttributes(pNodeBlendStart);
03615 
03616     // Invalid the whole of the start blend
03617     if (ok) ok = DoInvalidateNodeRegion(pNodeBlendStart,TRUE);
03618 
03619     // Clear out the lists (we don't want memory leaks, do we).
03620     BlenderListStart.DeleteAll();
03621     BlenderListEnd  .DeleteAll();
03622 
03623     // Throw away the selection cache
03624     GetApplication()->UpdateSelection();
03625 
03626     return (ok);
03627 }

BOOL OpBlendNodes::DoBlendBlendAndObject  )  [private]
 

This blends a blend object with another non-blend object. This is like a concatination of the the two nodes, resulting a single blend with an extra blend stage. E.g. blending a blend containing two paths (i.e. a single blend of two objects) with another path. The result will be a single blend object, blending the first path to the second, and the second to the third.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/11/94
Parameters:
- (data is taken from pRefStart and pRefEnd member vars) [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise
The order in which the two objects are concatinated depends on which is is the start of the blend and which is the end.

Definition at line 3649 of file blndtool.cpp.

03650 {
03651     ERROR3IF(!IS_A(pRefStart->pNode,NodeBlend) && !IS_A(pRefEnd->pNode,NodeBlend),"Neither start or end are NodeBlends");
03652     if (!IS_A(pRefStart->pNode,NodeBlend) && !IS_A(pRefEnd->pNode,NodeBlend)) return FALSE;
03653 
03654     OpType = BLENDOPTYPE_BLENDANDOBJECT;
03655     // BlendIsStart == TRUE if the blend node was the start of the blend and not the end
03656     BOOL BlendIsStart = IS_A(pRefStart->pNode,NodeBlend);
03657 
03658     // Get ptr to the NodeBlend in question, and put it in the member var pNodeBlend
03659     pNodeBlend = NULL;
03660     if (BlendIsStart) 
03661         pNodeBlend = (NodeBlend*)pRefStart->pNode; 
03662     else
03663         pNodeBlend = (NodeBlend*)pRefEnd->pNode; 
03664 
03665     if (pNodeBlend == NULL) return FALSE;
03666 
03667     // Get a record of all the blenders in the blend node
03668     List BlenderList;
03669     if (!RecordBlenderInfo(BlenderList,pNodeBlend))
03670         return FALSE;
03671 
03672     NodeRenderableInk* pNodeStart = NULL;
03673     NodeRenderableInk* pNodeEnd = NULL;
03674     Node* pContextNode;
03675     AttachNodeDirection AttachDir;
03676     BOOL ok = FALSE;
03677     if (BlendIsStart)
03678     {
03679 //      BlenderInfoItem* pItem = (BlenderInfoItem*)BlenderList.GetTail();
03680         pNodeBlendStart = pNodeBlend;
03681         ok              = GetNodeClosestToPoint(&pNodeStart, TRUE);
03682         pNodeEnd        = pRefEnd->pNode;
03683         pContextNode    = pNodeEnd;
03684         AttachDir       = PREV;
03685     }
03686     else
03687     {
03688 //      BlenderInfoItem* pItem = (BlenderInfoItem*)BlenderList.GetHead();
03689         pNodeStart      = pRefStart->pNode;
03690         pNodeBlendEnd   = pNodeBlend;
03691         ok              = GetNodeClosestToPoint(&pNodeEnd, FALSE);
03692         pContextNode    = pNodeStart;
03693         AttachDir       = NEXT;
03694     }
03695 
03696     ERROR3IF(pNodeBlend == NULL,"Neither start or end are NodeBlends");
03697     ERROR3IF(pNodeStart == NULL,"The start node ptr is NULL");
03698     ERROR3IF(pNodeEnd   == NULL,"The end node ptr is NULL");
03699     if (pNodeBlend == NULL || pNodeStart == NULL || pNodeEnd == NULL)
03700         return FALSE;
03701 
03702     BlobManager* pBlobManager = GetApplication()->GetBlobManager();
03703     ENSURE(pBlobManager, "Can't get BlobManager");
03704 
03705     ok = DeterminBlendObjectsProcessorHit ();
03706 
03707     // Firstly, record the selection state
03708     if (ok) ok = DoStartSelOp(TRUE,TRUE);
03709 
03710     if (ok) ok = (Tool::GetCurrent() != NULL);
03711     if (ok) pBlobManager->RenderToolBlobsOff(Tool::GetCurrent(), pRefStart->pSpread,NULL);
03712     if (ok) NodeRenderableInk::DeselectAll(FALSE);
03713 
03714     // Select th blend node
03715     if (ok) pNodeBlend->SetSelected(TRUE);
03716 
03717     // Deinit all the blenders in the blend.
03718     if (ok) ok = DoDeinitBlenders(BlenderList);
03719 
03720     // Localise the attributes in the blend before we start moving node around
03721     if (ok) ok = DoLocaliseCommonAttributes(pNodeBlend);
03722 
03723     // If blending to a blend, move the start node, and make sure it's deselected
03724     // Also find the number of paths that will be passed back (for the progress display)
03725     if (ok && !BlendIsStart)    ok = DoMoveNode(pNodeStart,pNodeBlend,FIRSTCHILD);
03726     if (ok && !BlendIsStart)    ok = DoDeselectNode(pNodeStart);
03727 
03728     // If blending from a blend, move the end node, and make sure it's deselected
03729     // Also find the number of paths that will be passed back (for the progress display)
03730     if (ok &&  BlendIsStart)    ok = DoMoveNode(pNodeEnd,pNodeBlend,LASTCHILD);
03731     if (ok &&  BlendIsStart)    ok = DoDeselectNode(pNodeEnd);
03732 
03733     // Create a blender node to blend the two nodes
03734     if (ok) ok = DoCreateBlender(pNodeStart,-1,pNodeEnd,-1,pContextNode,AttachDir);
03735 
03736     // Factor out any common attrs that might have been copied during the blend
03737     if (ok) ok = DoFactorOutCommonChildAttributes(pNodeBlend);
03738 
03739     // Invalidate the whole blend
03740     if (ok) ok = DoInvalidateNodeRegion(pNodeBlend,TRUE);
03741 
03742     // Reinit the blenders using the same start and end pointers they were using before the blend
03743     if (ok) ok = DoReinitBlenders(BlenderList);
03744 
03745     // Clear out the list (we don't want memory leaks, do we).
03746     BlenderList.DeleteAll();
03747 
03748     // Throw away the selection cache
03749     GetApplication()->UpdateSelection();
03750 
03751     return (ok);
03752 }

BOOL OpBlendNodes::DoBlendObjects  )  [private]
 

This blends two objects together to form a new blend object in the tree. All the data that's required is stored in pRefStart (for the start object) and pRefEnd (for the end object). It assumes that neither the start or end objects are blends, so no clever merging of blend objects will take place here.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
12/10/94
Parameters:
(data is taken from pRefStart and pRefEnd member vars) [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise

Definition at line 4230 of file blndtool.cpp.

04231 {
04232     // DMc - are the nodes to be blended shadowed or bevelled ?
04233 //  BOOL bIsShadowed = FALSE;
04234 //  BOOL bIsBevelled = FALSE;
04235 
04236     // What type of blend op are we doing?
04237     OpType = BLENDOPTYPE_NEW;
04238 
04239     // Are we going mad? Better check our onions...
04240     ERROR3IF_PF(pRefStart        == NULL,("pRefStart == NULL"));
04241     ERROR3IF_PF(pRefEnd          == NULL,("pRefEnd == NULL"));
04242     ERROR3IF_PF(pRefStart->pNode == NULL,("pRefStart->pNode == NULL"));
04243     ERROR3IF_PF(pRefEnd  ->pNode == NULL,("pRefEnd->pNode == NULL"));
04244 
04245     BOOL ok = DeterminBlendObjectsProcessorHit ();
04246 
04247     if (!ok)
04248     {
04249         return (FALSE);
04250     }
04251 
04252     ok = DoStartSelOp(TRUE,TRUE);
04253 
04254     CompoundNodeTreeFactoryList CFList;
04255 
04256     RemoveCompoundNodes(&CFList);
04257 
04258     NodeBlend* pNodeBlend;
04259 
04260     // DMc
04261     // move the end nodes upwards to include compound nodes
04262     Node * pParent = pRefStart->pNode;
04263 
04264     while (pParent)
04265     {
04266         if (!pParent->PromoteHitTestOnChildrenToMe() && pParent->IsAnObject())
04267         {
04268             pRefStart->pNode = (NodeRenderableInk *)pParent;
04269         }
04270 
04271         pParent = pParent->FindParent();
04272     }
04273 
04274     pParent = pRefEnd->pNode;
04275 
04276     while (pParent)
04277     {
04278         if (!pParent->PromoteHitTestOnChildrenToMe() && pParent->IsAnObject())
04279         {
04280             pRefEnd->pNode = (NodeRenderableInk *)pParent;
04281         }
04282 
04283         pParent = pParent->FindParent();
04284     }
04285 
04286     BlobManager* pBlobManager = GetApplication()->GetBlobManager();
04287     ENSURE(pBlobManager, "Can't get BlobManager");
04288 
04289     if (ok) ok = (Tool::GetCurrent() != NULL);
04290     if (ok) pBlobManager->RenderToolBlobsOff(Tool::GetCurrent(), pRefStart->pSpread,NULL);
04291     if (ok) NodeRenderableInk::DeselectAll(FALSE,FALSE);
04292 
04293     if (ok) ALLOC_WITH_FAIL(pNodeBlend,new NodeBlend,this);
04294     if (ok) ok = (pNodeBlend != NULL);
04295 
04296     if (ok) pRefStart->pNode->SetSelected(FALSE);
04297     if (ok) pRefEnd  ->pNode->SetSelected(FALSE);
04298 
04299     if (ok) ok = DoInsertNewNode(pNodeBlend,pRefEnd->pNode,NEXT,FALSE,FALSE,FALSE,FALSE);
04300     if (ok) ok = DoMoveNode(pRefStart->pNode,pNodeBlend,LASTCHILD);
04301     if (ok) ok = DoMoveNode(pRefEnd  ->pNode,pNodeBlend,LASTCHILD);
04302     if (ok) ok = DoCreateBlender(pRefStart->pNode,pRefStart->Index,pRefEnd->pNode,pRefEnd->Index,pRefStart->pNode,NEXT);
04303     if (ok) ok = DoInvalidateNodeRegion(pNodeBlend,TRUE);
04304 
04305     // Simon - Factor out the blend's common attributes
04306     if (ok) ok = DoFactorOutCommonChildAttributes(pNodeBlend);
04307 
04308 
04309     if (ok)
04310         pNodeBlend->SetSelected(TRUE);      // Select the new node
04311 
04312     // Throw away the selection cache
04313     GetApplication()->UpdateSelection();
04314 
04315     return (ok);
04316 }

BOOL OpBlendNodes::DoContourNode Node pNode,
DocCoord  PointerPos,
UINT32  Steps
[private]
 

Applies a contour to the given node.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
18/8/99
Parameters:
Node to contour [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise

Definition at line 3342 of file blndtool.cpp.

03343 {
03344     /*
03345     List NodeList;
03346 
03347     // get the bounding rect of the node to be contoured
03348     DocRect br = ((NodeRenderableBounded *)pNode)->GetBoundingRect();
03349 
03350     UINT32 Width = 0;
03351 
03352     INT32 OffsetX = 0;
03353     INT32 OffsetY = 0;
03354 
03355     // try to work out the width of the contour
03356     if (PointerPos.x < br.lo.x && PointerPos.y >= br.lo.y &&
03357         PointerPos.y <= br.hi.y)
03358     {
03359         Width = br.lo.x - PointerPos.x;
03360     }
03361     else if (PointerPos.x > br.hi.x && PointerPos.y >= br.lo.y &&
03362         PointerPos.y <= br.hi.y)
03363     {
03364         Width = PointerPos.x - br.hi.x;
03365     }
03366     else if (PointerPos.x >= br.lo.x && PointerPos.x <= br.hi.x &&
03367         PointerPos.y < br.lo.y)
03368     {
03369         Width = br.lo.y - PointerPos.y;
03370     }
03371     else if (PointerPos.x >= br.lo.x && PointerPos.x <= br.hi.x &&
03372         PointerPos.y > br.hi.y)
03373     {
03374         Width = PointerPos.y - br.hi.y;
03375     }
03376     else if (PointerPos.x < br.lo.x && PointerPos.y < br.lo.y)
03377     {
03378         OffsetX = br.lo.x - PointerPos.x;
03379         OffsetY = br.lo.y - PointerPos.y;
03380 
03381         if (OffsetX > OffsetY)
03382         {
03383             Width = OffsetX;
03384         }
03385         else
03386         {
03387             Width = OffsetY;
03388         }
03389     }
03390     else if (PointerPos.x > br.hi.x && PointerPos.y < br.lo.y)
03391     {
03392         OffsetX = PointerPos.x - br.hi.x ;
03393         OffsetY = br.lo.y - PointerPos.y;
03394 
03395         if (OffsetX > OffsetY)
03396         {
03397             Width = OffsetX;
03398         }
03399         else
03400         {
03401             Width = OffsetY;
03402         }
03403     }
03404     else if (PointerPos.x > br.hi.x && PointerPos.y > br.hi.y)
03405     {
03406         OffsetX = PointerPos.x - br.hi.x ;
03407         OffsetY = PointerPos.y - br.hi.y;
03408 
03409         if (OffsetX > OffsetY)
03410         {
03411             Width = OffsetX;
03412         }
03413         else
03414         {
03415             Width = OffsetY;
03416         }
03417     }
03418     else if (PointerPos.x < br.lo.x && PointerPos.y > br.hi.y)
03419     {
03420         OffsetX = br.lo.x - PointerPos.x ;
03421         OffsetY = PointerPos.y - br.hi.y;
03422 
03423         if (OffsetX > OffsetY)
03424         {
03425             Width = OffsetX;
03426         }
03427         else
03428         {
03429             Width = OffsetY;
03430         }
03431     }
03432 
03433     // find top level of the node to contour
03434     Node * pParent = pNode->FindParent();
03435 
03436     BOOL bContourExists = FALSE;
03437     
03438     while (pParent)
03439     {
03440         if (pParent->IsKindOf(CC_RUNTIME_CLASS(NodeContourController)))
03441         {
03442             pNode = pParent;
03443             bContourExists = TRUE;
03444         }
03445 
03446         pParent = pParent->FindParent();
03447     }
03448 
03449     NodeListItem * pItem = new NodeListItem(pNode);
03450 
03451     NodeList.AddTail(pItem);
03452 
03453     // if a contour exists then change its width
03454     if (!bContourExists)
03455     {
03456         CreateContourParam Param(&NodeList, Steps, Width);
03457 
03458         OpDescriptor * pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpCreateContour));
03459 
03460         if (pOpDesc && Width > 0)
03461         {
03462             pOpDesc->Invoke(&Param);
03463         }
03464     }
03465     else
03466     {
03467         ChangeContourWidthParam Param(&NodeList, Width, FALSE);
03468 
03469         OpDescriptor * pOpDesc = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpChangeContourWidth));
03470 
03471         if (pOpDesc && Width > 0)
03472         {
03473             pOpDesc->Invoke(&Param);
03474         }
03475     }
03476 
03477     NodeList.DeleteAll();
03478     */
03479     
03480     return TRUE;
03481 
03482 }

BOOL OpBlendNodes::DoCreateBlender NodeRenderableInk pNodeStart,
INT32  PathIndexStart,
NodeRenderableInk pNodeEnd,
INT32  PathIndexEnd,
Node pContextNode,
AttachNodeDirection  AttachDir
[private]
 

This forms a blender object in the tree that can blend pRefStart->pNode to pRefEnd->pNode.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
12/10/94
Parameters:
pNodeStart = the start node to blend [INPUTS] PathIndexStart = index into start path, if applicable (-1 means not applicable) pNodeEnd = the end node to blend PathIndexEnd = index into end path, if applicable (-1 means not applicable) pContextNode = ptr to context for insertion of the blender AttachDir = how to attach the blender to the tree in relation to pContextNode
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise

Definition at line 4421 of file blndtool.cpp.

04424 {
04425     ERROR2IF(pNodeStart == NULL,FALSE,"pNodeStart is NULL");
04426     ERROR2IF(pNodeEnd   == NULL,FALSE,"pNodeEnd   is NULL");
04427 
04428     // Work out how many paths will be passed back
04429     // The sum will be used to determine the final count for the progress bar
04430     BecomeA TestStart(BECOMEA_TEST, CC_RUNTIME_CLASS(NodePath));
04431     BecomeA TestEnd(BECOMEA_TEST, CC_RUNTIME_CLASS(NodePath));
04432     TestStart.ResetCount();
04433     TestEnd.ResetCount();
04434     pNodeStart->CanBecomeA(&TestStart);
04435     pNodeEnd  ->CanBecomeA(&TestEnd);
04436 
04437     // Create the hourglass with the correct final count.
04438     Progress Hourglass(_R(IDS_BLENDING), INT32(TestStart.GetCount() + TestEnd.GetCount()) );
04439 
04440     BOOL ok = FALSE;
04441     NodeBlender* pNodeBlender;
04442 
04443     ALLOC_WITH_FAIL(pNodeBlender,new NodeBlender,this);
04444     ok = (pNodeBlender != NULL);
04445 
04446     // If either of the indexes are -ve, make sure both are -ve
04447     if (PathIndexStart < 0 || PathIndexEnd < 0)
04448         PathIndexStart = PathIndexEnd = -1;
04449 
04450     if (ok) ok = DoInsertNewNode(pNodeBlender,pContextNode,AttachDir,FALSE,FALSE,FALSE,FALSE);
04451     if (ok) ok = pNodeBlender->Initialise(pNodeStart,pNodeEnd,PathIndexStart,PathIndexEnd,this,&Hourglass,FALSE);
04452     
04453     pRefStart->pNode = pNodeStart;
04454     pRefEnd->pNode = pNodeEnd;
04455     return (ok);
04456 }

BOOL OpBlendNodes::DoDeinitBlenders List BlenderList  )  [private]
 

This calls DeinitBlenders() on the given list, and creates an action that will call ReinitBlenders() on undo, and DeinitBlenders() on redo.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/11/94
Parameters:
BlenderList = list of blenders to deinit. [INPUTS]
- [OUTPUTS]
Returns:
-

Definition at line 3768 of file blndtool.cpp.

03769 {
03770     InitBlendersAction* pAction;
03771     BOOL ok = (InitBlendersAction::Init(this,&UndoActions,&BlenderList,TRUE,&pAction) != AC_FAIL);
03772 
03773     if (ok) DeinitBlenders(BlenderList);
03774 
03775     return (ok);
03776 }

BOOL OpBlendNodes::DoDrag BlendTool pBlendTool  ) 
 

This starts a drag that may lead to a blend. The DragFinished() method will do the hard work of blending if it can be done.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/10/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-

Definition at line 3121 of file blndtool.cpp.

03122 {
03123     // DMc
03124     // find out the active tool for the drag
03125     if (Tool::GetCurrent()->GetID() == TOOLID_BLEND)
03126     {
03127         pRefStart = BlendTool::GetPtrRefStart();
03128         pRefEnd   = BlendTool::GetPtrRefEnd();
03129     }
03130         
03131     ERROR2IF_PF(pRefStart == NULL || pRefEnd == NULL,FALSE,("Blend tool refs are NULL"));
03132 
03133     pRefEnd->PointerPos = pRefStart->PointerPos;
03134     RenderMyDragBlobs();
03135     m_pBlendTool = pBlendTool;
03136 
03137     // Tell the Dragging system that we need drags to happen
03138     StartDrag( DRAGTYPE_AUTOSCROLL );
03139 
03140     return TRUE;
03141 }

BOOL OpBlendNodes::DoReinitBlenders List BlenderList  )  [private]
 

This calls ReinitBlenders() on the given list, and creates an action that will call DeinitBlenders() on undo, and ReinitBlenders() on redo.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
21/11/94
Parameters:
BlenderList = list of blenders to deinit. [INPUTS]
- [OUTPUTS]
Returns:
-

Definition at line 3792 of file blndtool.cpp.

03793 {
03794     InitBlendersAction* pAction;
03795     BOOL ok = (InitBlendersAction::Init(this,&UndoActions,&BlenderList,FALSE,&pAction) != AC_FAIL);
03796 
03797     if (ok)
03798     {
03799         ok = ReinitBlenders(BlenderList);
03800         if (!ok) FailAndExecuteAllButLast();
03801     }
03802 
03803     return ok;
03804 }

BOOL OpBlendNodes::DoRemapBlend  )  [private]
 

This tries to remap a blend using the data held in pRefStart && pRefEnd. It asks the pNodeBlend object to try and remap the two paths by rotating the path elements so that the element at Index is the first element in the path.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
10/11/94
Parameters:
- (data is taken from pRefStart and pRefEnd member vars) [INPUTS]
- [OUTPUTS]
Returns:
TRUE if all when well, FALSE otherwise

Definition at line 3922 of file blndtool.cpp.

03923 {
03924     // What type of blend op are we doing?
03925     OpType = BLENDOPTYPE_REMAP;
03926 
03927     // Are we going mad? Better check our onions...
03928     ERROR3IF(pRefStart              == NULL,"pRefStart == NULL");
03929     ERROR3IF(pRefEnd                == NULL,"pRefEnd == NULL");
03930     ERROR3IF(pRefStart->pNode       == NULL,"pRefStart->pNode == NULL");
03931     ERROR3IF(pRefEnd  ->pNode       == NULL,"pRefEnd->pNode == NULL");
03932     ERROR3IF(pRefStart->pNodeBlend  == NULL,"pRefStart->pNodeBlend == NULL");
03933     ERROR3IF(pRefEnd  ->pNodeBlend  == NULL,"pRefEnd->pNodeBlend == NULL");
03934     ERROR3IF(pRefStart->pNodeBlend  != pRefEnd->pNodeBlend,"Start and end blend nodes not equal");
03935     ERROR3IF(pRefStart->RemapRef    != pRefEnd->RemapRef,"Start and end remap refs not equal");
03936     ERROR3IF(pRefStart->AStartNode  == pRefEnd->AStartNode,"Start and end AStartNode vals equal");
03937 
03938     BOOL ok = TRUE;
03939     RemapBlendAction* pAction;
03940     NodeBlend*  pNodeBlend  = pRefStart->pNodeBlend;
03941     UINT32      RemapRef    = pRefStart->RemapRef;
03942 
03943     DocCoord    PosStart    = pRefStart->PointerPos;
03944     DocCoord    PosEnd      = pRefEnd  ->PointerPos;
03945 
03946     if (!pRefStart->AStartNode)
03947     {
03948         // Swap the coords around
03949         DocCoord Temp = PosStart;
03950         PosStart = PosEnd;
03951         PosEnd = Temp;
03952     }
03953 
03954     ObjChangeFlags cFlags;
03955     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,pNodeBlend,this);
03956     ok = pNodeBlend->AllowOp(&ObjChange);
03957 
03958     if (ok) ok = DoInvalidateNodeRegion(pRefStart->pNodeBlend,TRUE);
03959 
03960     if (ok) ok = RemapBlendAction::Init(this,&UndoActions,
03961                                         pNodeBlend,RemapRef,PosStart,PosEnd,
03962                                         &pAction) != AC_FAIL;
03963 
03964     if (ok)
03965     {
03966         ObjChange.Define(OBJCHANGE_FINISHED,cFlags,pNodeBlend,this);
03967         UpdateChangedNodes(&ObjChange);
03968     }
03969 
03970     return (ok);
03971 }

void OpBlendNodes::DragFinished DocCoord  PointerPos,
ClickModifiers  ClickMods,
Spread pSpread,
BOOL  Success,
BOOL  bSolidDrag
[virtual]
 

Ends the drag. Either creates a new grid or resizes GridClicked depending on the state of affairs when the drag started.

Author:
Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/10/94
Parameters:
PointerPos - The position of the mouse at the end of the drag [INPUTS] ClickMods - the key modifiers being pressed pSpread - The spread that the drag finished on Success - TRUE if the drag was terminated properly, FALSE if it was ended with the escape key being pressed
See also:
ClickModifiers

Reimplemented from Operation.

Definition at line 3206 of file blndtool.cpp.

03208 {
03209     ERROR3IF(pRefStart == NULL,"pRefStart is NULL");
03210     ERROR3IF(pRefEnd   == NULL,"pRefEnd is NULL");
03211     if ((pRefStart == NULL) || (pRefEnd == NULL)) return;
03212 
03213     // First Rub out the old box
03214     RenderMyDragBlobs();
03215 
03216     if (Success)
03217     {
03218         // Make sure that start and end refer to the same spread
03219