Esempio n. 1
0
/********************************************************************************************

>	virtual void OpApplyClipView::Do(OpDescriptor* pOpDesc, OpParam* pOpParam)

	Author:		Karim_MacDonald (Xara Group Ltd) <*****@*****.**>
	Created:	01 February 2000
	Inputs:		
	Outputs:	
	Returns:	
	Purpose:	
	Errors:		
	See also:	

********************************************************************************************/
void OpApplyClipView::Do(OpDescriptor* pOpDesc)
{
	// obtain the current selection.
	Range Sel(*(GetApplication()->FindSelection()));
	RangeControl rc = Sel.GetRangeControlFlags();
	rc.PromoteToParent = TRUE;
	Sel.Range::SetRangeControl(rc);

	// check that at least two nodes are selected.
	Node* pNode = NULL;
	Node* pFirstNode = Sel.FindFirst();
	if (pFirstNode != NULL)
		pNode = Sel.FindNext(pFirstNode);
		
	if (pFirstNode == NULL || pNode == NULL)
	{
		ERROR3("OpApplyClipView invoked with less than two selected nodes. This should never occur.");
		End();
		return;
	}

	// render blobs off for tools which don't automatically redraw their blobs.
	Tool* pTool = Tool::GetCurrent();
	Spread* pSpread = Document::GetSelectedSpread();
	if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
		pTool->RenderToolBlobs(pSpread, NULL);

	// record the current selection state and if required, render off any selection blobs.
	if (!DoStartSelOp(FALSE, FALSE))
	{
		End();
		return;
	}

	// invalidate the region bounding the selection.
	// the commented code doesn't do the job properly (doesn't tackle undo)
	// though it should - I get the feeling I'm not using it correctly.
	// so we'll just have to invalidate the selection node by node.
//	if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE))
//	{
//		End();
//		return;
//	}
	Node* pSelNode = Sel.FindFirst();
	while (pSelNode != NULL)
	{
		if (pSelNode->IsAnObject())
		{
			if (!DoInvalidateNodeRegion((NodeRenderableInk*)pSelNode, TRUE))
			{
				End();
				return;
			}
		}
		pSelNode = Sel.FindNext(pSelNode);
	}

	// we need to insert the controller node at the position of the highest
	// selected node in the z-order, ie last in the selection, so find it.
	Node* pLastNode = NULL;
	while (pNode != NULL)
	{
		pLastNode = pNode;
		pNode = Sel.FindNext(pLastNode);
	}	// loop terminates with pNode == NULL, pLastNode == last-node-in-sel.

	// create a new NodeClipViewController, which we will shortly insert into the tree;
	// note that ALLOC_WITH_FAIL automatically calls FailAndExecute() if things go wrong.
	NodeClipViewController* pClipViewController = NULL;
	ALLOC_WITH_FAIL(pClipViewController, new NodeClipViewController, this);
	BOOL ok = (pClipViewController != NULL);

	// put an action to hide the NodeClipViewController onto the undo action-list,
	// so that if the user presses undo then it will be hidden.
	if (ok)
	{
		HideNodeAction* pUndoHideNodeAction = NULL;
		ActionCode ac = HideNodeAction::Init(this,
											&UndoActions,
											pClipViewController,
											FALSE,		// don't include subtree size
											(Action**)&pUndoHideNodeAction,
											FALSE);		// don't tell subtree when undone
		if (ac == AC_FAIL)
		{
			delete pClipViewController;
			End();
			return;
		}
		else
		{
			// right! we've got our node, we've got our action - lets stick it in the tree
			// (at a position just next to the last node which will go in the group).
			pClipViewController->AttachNode(pLastNode, NEXT);
		}
	}

	// move each item from the selection into our ClipView group,
	// remembering to deselect them as we go.
	// TODO:
	//	sneaky suspicion I should be putting this in a Do fn in UndoableOperation...
	if (ok)
	{
		pNode = Sel.FindNext(pFirstNode);				// the node we're moving now.
		ok = DoMoveNode(pFirstNode, pClipViewController, FIRSTCHILD);
		if (ok)
			((NodeRenderable*)pFirstNode)->DeSelect(FALSE);
	}

	Node* pNextNode		= NULL;							// the next node to move.
	Node* pAnchorNode	= pFirstNode;					// the node we've just moved.
	while (ok && pNode != NULL)
	{
		// get the next node to move.
		pNextNode = Sel.FindNext(pNode);

		// now move the current node next to the anchor and deselect it.
		ok = DoMoveNode(pNode, pAnchorNode, NEXT);
		if (ok)
			((NodeRenderable*)pNode)->DeSelect(FALSE);

		// get the new anchor node and the next node to move.
		pAnchorNode = pNode;
		pNode = pNextNode;
	}

	// try and locate a suitable candidate for a keyhole node.
	Node* pKeyhole = NULL;
	if (ok)
	{
		// now get the keyhole node, which is the first object-node child of the NCVC.
		pKeyhole = pClipViewController->FindFirstChild();
		while (pKeyhole != NULL && !pKeyhole->IsAnObject())
		{
			pKeyhole = pKeyhole->FindNext();
		}

		// doh! can't find _one_ NodeRenderableInk child! I don't know...
		if (pKeyhole == NULL)
		{
			ok = FALSE;
			ERROR2RAW("ClipViewController has no object children");
		}
	}

	// now attach a new NodeClipView, as the immediate NEXT-sibling of the keyhole node.
	NodeClipView* pClipView = NULL;
	if (ok)
	{
		ALLOC_WITH_FAIL(pClipView, new NodeClipView(pKeyhole, NEXT), this);
		ok = (pClipView != NULL);
	}

	// wow - succeeded! now all we need to do is some house-keeping.
	if (ok)
	{
		// tell the new NodeClipViewController that its current keyhole path is now invalid.
		pClipViewController->MarkKeyholeInvalid();

		// invalidate ours and our parent's bounding rects. our bounding rect is almost
		// certainly already invalid, as we haven't done anything to make it valid yet.
		// this is why we invalidate *both* rects - just to cover all cases.
		pClipViewController->InvalidateBoundingRect();
		Node* pParent = pClipViewController->FindParent();
		if (pParent != NULL && pParent->IsBounded())
			((NodeRenderableBounded*)pParent)->InvalidateBoundingRect();

		// select the new NodeClipViewController, but don't draw any blobs yet.
		pClipViewController->Select(FALSE);

		// invalidate the region bounding the selection.
		if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE))
		{
			End();
			return;
		}

		// factor out any common attributes.
		if (!DoFactorOutCommonChildAttributes(pClipViewController))
		{
			End();
			return;
		}
		
		// render blobs back on if the current tool doesn't automatically redraw its blobs.
		if (pSpread != NULL && pTool != NULL && !pTool->AreToolBlobsRenderedOnSelection())
			pTool->RenderToolBlobs(pSpread, NULL);
	}
	else
	{
		FailAndExecute();
	}

	// end the operation.
 	End();
}
Esempio n. 2
0
void OpBreakAtPoints::Do(OpDescriptor*)
{   
	
	// Obtain the current selections 
	SelRange* Selected = GetApplication()->FindSelection();
	NodePath* pSplitNode;

	// Now, because we're going to be doing mad things to the selection, we have to make a list
	// of all the selected nodes, so that adding nodes into the tree won't confuse us

	List* NodeList = Selected->MakeListOfNodes();
	NodeListItem* CurItem = (NodeListItem*)(NodeList->GetHead());

	if (!CurItem)
		goto FailAndDeleteList;

	if (!DoStartSelOp(TRUE,TRUE))
		goto FailAndDeleteList;

	while (CurItem)
	{
		// get a pointer to the NodePath
		NodePath* pThisNode = (NodePath*)(CurItem->pNode);

		// Only interested in NodePaths that have a sub selection, and that will allow the op to happen
		if ((IS_A(pThisNode,NodePath) || IS_A(pThisNode,NodeBlendPath)) && pThisNode->InkPath.IsSubSelection())
		{
			// Find out how many nodes this op will reproduce
			INT32 NumSplinters = pThisNode->InkPath.NumSplinters();
			BOOL DoThisNode = FALSE;

			if (NumSplinters > 0)
			{
				// We need to ask the effected nodes if they (and their parents) can handle this node being replaced
				ObjChangeFlags cFlags;

				if (NumSplinters > 1)
					cFlags.MultiReplaceNode = TRUE;	// Node will be replaced with more than one node.
				else
					cFlags.ReplaceNode = TRUE;		// Node will be replaced with one node only.

				ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
				DoThisNode = pThisNode->AllowOp(&ObjChange);
			}

			if (DoThisNode)
			{

				BOOL ok;
				Node* pnode;

				// Copy the nodepath and all its children, without placing the copy in the tree
				CALL_WITH_FAIL(pThisNode->NodeCopy(&pnode), this, ok);
				if (!ok) goto DeleteList;
				pSplitNode = (NodePath*)pnode;

				// remove the fill from this path as we're about to open it
				pSplitNode->InkPath.IsFilled = FALSE;

				// Now stick the new path into the tree
				CALL_WITH_FAIL
				(
					DoInsertNewNode(pSplitNode, pThisNode, NEXT, TRUE, FALSE),
					this,ok
				);
				
				if (!ok) 
					goto DeleteListAndPath;

				// Now breakup this copy of the path where necessary
				Path* pChildPath;
				INT32 split;

			    do
			    {
					// Create a new path, ready for split
					ALLOC_WITH_FAIL(pChildPath, new Path, this);
					if (!pChildPath) 
						goto DeleteList;

					// Now split the path, possibly into two pieces.
			    	split = pSplitNode->InkPath.BreakInTwo(pChildPath);

					if (split==-1) 
					{
						InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK));
						delete pChildPath;
						goto FailAndDeleteList;
					}

					/*	Karim 05/12/2000
						No longer required - see code addition at the bottom of this loop.

					if (split==1) 
			    	{
						delete pChildPath;
			    		continue;
					}

					*/

					if (split>1)
					{

						// update the split paths bounding rectangle
						pSplitNode->InvalidateBoundingRect();

						// Create a new nodepath.
						NodePath* pChildNode;
						ALLOC_WITH_FAIL(pChildNode, new NodePath(), this);
						if (!pChildNode)
						{
							delete pChildPath;
							goto DeleteList;
						}

						// make room for the new path in the node path.
						CALL_WITH_FAIL
						(
							pChildNode->SetUpPath(pChildPath->GetNumCoords(),12),
							this,ok
						);
				
						if (!ok)
						{
							delete pChildNode;
							delete pChildPath;
							goto DeleteList;
						}

						// now copy the path data in there.
						pChildNode->InkPath.CopyPathDataFrom(pChildPath);
						delete pChildPath;

						// Clear the selection flag from the first element in both the split
						// and child paths.  All others apart from the last will be	unselected
						// by definition.  Also select the last element in the child
						(pSplitNode->InkPath.GetFlagArray())[0].IsSelected = FALSE;
						(pChildNode->InkPath.GetFlagArray())[0].IsSelected = FALSE;
						(pChildNode->InkPath.GetFlagArray())[(pChildNode->InkPath.GetNumCoords()-1)].IsSelected = TRUE;
						pChildNode->InkPath.IsFilled = FALSE;

						// now, copy all attributes from the parent split to the child split
						Node* pAttr = pSplitNode->FindFirstChild();
						while (pAttr != NULL)
						{
							if (pAttr->IsKindOf(CC_RUNTIME_CLASS(NodeAttribute)))
							{
								Node* pAttrCopy;
								CALL_WITH_FAIL(pAttr->NodeCopy(&pAttrCopy), this,ok);
								if (!ok) 
								{
									pChildNode->CascadeDelete();
									delete pChildNode;
									goto DeleteList;
								}
								pAttrCopy->AttachNode(pChildNode, FIRSTCHILD);
							}
							pAttr = pAttr->FindNext();
						}

						for (INT32 loop = 0; loop < pChildNode->InkPath.GetNumCoords(); loop ++)
						{
							pChildNode->InkPath.GetVerbArray()[loop] = pChildNode->InkPath.GetVerbArray()[loop] & ~PT_CLOSEFIGURE;
						}

						// Now stick the new path into the tree
						CALL_WITH_FAIL
						(
							DoInsertNewNode(pChildNode, pSplitNode, NEXT, TRUE, FALSE),
							this,ok
						);

						if (!ok)
						{
							pChildNode->CascadeDelete();
							delete pChildNode;
							goto DeleteList;
						}

						pSplitNode = pChildNode;
					}

					// Karim 05/12/2000
					// Fix for memory leak.
					else
					{
						delete pChildPath;
					}
			    }
			    while (split);

				// Clear out any remaining closefigures on the last bit of the path
				for (INT32 loop = 0; loop < pSplitNode->InkPath.GetNumCoords(); loop ++)
				{
					pSplitNode->InkPath.GetVerbArray()[loop] = pSplitNode->InkPath.GetVerbArray()[loop] & ~PT_CLOSEFIGURE;
				}

				// Now we've broken up this path, let's hide it
				CALL_WITH_FAIL(DoHideNode(pThisNode,TRUE), this, ok)
				if (!ok) goto DeleteList;
			}
		}
		CurItem = (NodeListItem*)(NodeList->GetNext(CurItem));
	}
Esempio n. 3
0
BOOL NodeSimpleShape::DoBecomeA(BecomeA* pBecomeA)
{
	// Check for a NULL entry param
	ERROR2IF_PF(pBecomeA == NULL,FALSE,("pBecomeA is NULL"));

	// This lump checks that the Reason is one that we understand
	// It also makes sure that we don't have a NULL UndoOp ptr
	BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK);
	ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason()));

	// pBecomeA->Reason is one that we understand.

	BOOL 		Success = TRUE;			// Our success flag (Important that this defaults to TRUE)
	NodePath* 	pNewNodePath = NULL;	// Ptr to a new NodePath, if we get to make one.

	if (pBecomeA->BAPath())
	{
		// We need to create a new NodePath, no matter what the reason.
		
		// Allocate a new NodePath node
		ALLOC_WITH_FAIL(pNewNodePath, (new NodePath), pBecomeA->GetUndoOp()); 
		Success = (pNewNodePath != NULL);

		// Initialise the path
		if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.Initialise(InkPath.GetNumCoords(),12), pBecomeA->GetUndoOp(), Success);
		if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.CopyPathDataFrom(&InkPath), pBecomeA->GetUndoOp(), Success);

		// If Success is TRUE, then we now have a new NodePath object that contains this shape's path

		if (Success)
		{
		 	switch (pBecomeA->GetReason())
			{
		 		case BECOMEA_REPLACE :
				{
					// It's a BECOMEA_REPLACE, so replace this node with the new NodePath in an undoable way

					// Can't do it in an undoable way without an Undo Op
					ERROR2IF_PF(pBecomeA->GetUndoOp() == NULL,FALSE,("GetUndoOp() returned NULL"));

					// Firstly, hide this node
					NodeHidden* pNodeHidden; 
					Success = pBecomeA->GetUndoOp()->DoHideNode(this, TRUE, &pNodeHidden);

					if (Success)
					{
						// Insert the new NodePath into the tree, next to the hidden node
						pNewNodePath->AttachNode(pNodeHidden,NEXT);

						// Copy the node's attributes
						CALL_WITH_FAIL(CopyChildrenTo(pNewNodePath), pBecomeA->GetUndoOp(), Success); 

						if (Success)
						{
							// Set the bounds  
							pNewNodePath->InvalidateBoundingRect();
							pNewNodePath->SetSelected(IsSelected());

							// Create a hide node action to hide the node when we undo 
							HideNodeAction* UndoHideNodeAction;     
							Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(),
											  		 pBecomeA->GetUndoOp()->GetUndoActionList(),
									 				 pNewNodePath, 
									 				 TRUE, 		 // Include subtree size 
							  		 				 ( Action**)(&UndoHideNodeAction))
							  		  				 != AC_FAIL);
						}
					}

					if (Success)
						pBecomeA->PassBack(pNewNodePath, this);
				}
				break;

				case BECOMEA_PASSBACK :
					Success = pBecomeA->PassBack(pNewNodePath,this);
				break;

				default:
					break;
			}
		}
	}

	if (!Success)
	{
		if (pNewNodePath != NULL)
		{
			// Delete all the NodePath's children (if it has any) and unlink it from the tree (if it's linked)
			// This is all done by CascadeDelete()
			pNewNodePath->CascadeDelete(); 
			delete pNewNodePath;
			pNewNodePath = NULL;
		}
	}

	return Success;
}
Esempio n. 4
0
void OpAlign::DoWithParam(OpDescriptor* pOp, OpParam* pAlignParam)
{
	// DMc alterations so that this works with compound nodes	
	SelRange   Selection(*(GetApplication()->FindSelection()));

	RangeControl rg = Selection.GetRangeControlFlags();
	rg.PromoteToParent = TRUE;
	Selection.Range::SetRangeControl(rg);

	DocRect		SelRect   = Selection.GetBoundingRect();
	DocRect		TargetRect;
	TargetRect.MakeEmpty();
	INT32        NumObjs   = Selection.Count();
	AlignParam* pAlign    =(AlignParam*)pAlignParam;

	BOOL moved=FALSE;					// set to TRUE if any object is moved
	BeginSlowJob(-1,FALSE);
	BOOL OK=DoStartTransOp(FALSE);

	// find parent spread of first object in selection
	Node*   pFirstNode=NULL;
	Spread* pSpread   =NULL;
	if (OK)
	{
		pFirstNode=Selection.FindFirst();
		if (pFirstNode!=NULL)
			pSpread=pFirstNode->FindParentSpread();
		OK=(pSpread!=NULL);
		if (!OK)
			ERROR2RAW("OpAlign::DoWithParam() - could not find parent spread");
	}

	// Find the size of the target rectangle
	if (pAlign->target==ToSelection)
		TargetRect=SelRect;
	else
	{
		Page* pPage=pSpread->FindFirstPageInSpread();
		while (pPage)
		{
			DocRect PageRect=pPage->GetPageRect();
			if (pAlign->target==ToSpread || SelRect.IsIntersectedWith(PageRect))
				TargetRect=TargetRect.Union(PageRect);
			pPage=pPage->FindNextPage();
		}
	}

	// allocate all dynamic memory required
	Node**	 pObj=NULL;
	ObjInfo* x   =NULL;
	ObjInfo* y   =NULL;
	INT32*    dx  =NULL;
	INT32*    dy  =NULL;
	if (OK)			ALLOC_WITH_FAIL(pObj,(Node**)  CCMalloc(NumObjs*sizeof(Node*)),  this);
	if (pObj!=NULL)	ALLOC_WITH_FAIL(x,   (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this);
	if (   x!=NULL) ALLOC_WITH_FAIL(y,   (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this);
	if (   y!=NULL) ALLOC_WITH_FAIL(dx,  (INT32*)   CCMalloc(NumObjs*sizeof(INT32)),   this);
	if (  dx!=NULL) ALLOC_WITH_FAIL(dy,  (INT32*)   CCMalloc(NumObjs*sizeof(INT32)),   this);
	OK=(dy!=NULL);

	// if memory claimed OK and target rect not empty proceed with op
	// (ie. do nothing if 'within page(s)' when no object on a page)
	DocRect EmptyRect;
	if (OK && TargetRect!=EmptyRect)
	{
		// create an array of pointers to objects (nodes) to be affected
		Node* pNode=Selection.FindFirst();
		INT32  i=0;
		while (pNode!=NULL)
		{
			if (pNode->IsBounded() && !((NodeRenderableBounded*)pNode)->GetBoundingRect(TRUE).IsEmpty())
				pObj[i++]=pNode;
			pNode=Selection.FindNext(pNode);
		}
		NumObjs=i;

		// cache x & y info in separate arrays so they can be sorted separately
		XLONG SumObjWidths =0;
		XLONG SumObjHeights=0;
		for (i=0; i<NumObjs; i++)
		{
			DocRect ObjRect=((NodeRenderableBounded*)pObj[i])->GetBoundingRect();
			x[i].i=i;
			x[i].lo=ObjRect.lo.x;
			x[i].hi=ObjRect.hi.x;
			SumObjWidths+=ObjRect.hi.x-ObjRect.lo.x;
			y[i].i=i;
			y[i].lo=ObjRect.lo.y;
			y[i].hi=ObjRect.hi.y;
			SumObjHeights+=ObjRect.hi.y-ObjRect.lo.y;
		}

		// for each object, calculate the x and y displacements independently
		AlignOneAxis(pAlign->h,NumObjs,SumObjWidths, TargetRect.lo.x,TargetRect.hi.x,x,dx);
		AlignOneAxis(pAlign->v,NumObjs,SumObjHeights,TargetRect.lo.y,TargetRect.hi.y,y,dy);

		// apply the x and y displacements simultaneously to each object
		for (i=0; i<NumObjs; i++)
			if (dx[i]!=0 || dy[i]!=0)
			{
				moved=TRUE;
				Trans2DMatrix* pMatrix=new Trans2DMatrix(dx[i],dy[i]);
				DoTransformNode((NodeRenderableInk*)pObj[i],pMatrix);
			}
	}

	// free up any memory which was allocated
	CCFree(dx);
	CCFree(dy);
	CCFree(x);
	CCFree(y);
	CCFree(pObj);

	if (moved)
	{
		Document::GetSelected()->ForceRedraw(pSpread, TargetRect);
		GetApplication()->UpdateSelection();
	}
	else
		FailAndExecute();
	End();
	EndSlowJob();
}