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; }
NodeRenderableBounded *CDRArrowheadStore::GetConvertedNode(DWORD Reference, INT32 *Distance, BOOL *NotPresent) { // set up the not present thingy *NotPresent = FALSE; // find the correct chunk CDRArrowheadStoredItem *Item; INT32 Size; if(IsEmpty()) return 0; // no items in the list Item = (CDRArrowheadStoredItem *)GetHead(); // scan though the list looking for the reference while(Item != 0) { if(CDRDATA_DWORD(*((DWORD *)(Item->Block))) == Reference) { Size = Item->Size; break; } Item = (CDRArrowheadStoredItem *)GetNext(Item); } // did we find a chunk? if(Item == 0) { *NotPresent = TRUE; return 0; } // locate the coordinates cdrfArrowhead *Arrow = (cdrfArrowhead *)Item->Block; cdrfCoord *Coords = (cdrfCoord *)(Item->Block + CDRDATA_WORD(Arrow->CoordsOffset) + cdrfARROWHEAD_COORDOFF_CORRECT); // store the distance from the definitons *Distance = CDRDATA_SWORD(Arrow->Distance); // check to see if a cached pointer is available if(Item->pNode != 0) return Item->pNode; // OK, convert that arrowhead // this is not particularly pleasant. We need to scan though the coords creating a path, // each sub path must be a seperate path unless the next subpath has the same closedness // as the previous one, in which case it's a sub path. // this is because closed sub paths have different attributes to open ones. It's a nasty // system, and rather overcomplicated, but never mind. INT32 ThisType = GCN_LASTSUB_NONE; // the type of this subpath INT32 LastType = GCN_LASTSUB_NONE; // the type of the last subpath NodePath *FirstPath = 0; // the first path in my set of paths NodePath *LastPath = 0; // the last path in my set of paths NodePath *ThisPath = 0; // the path I'm currently working on // check that the first node type is a move to avoid stuffing up my next bit if((Arrow->NodeTypes[0] & cdrfPATHCOORDTYPE_MASK) != cdrfPATHCOORDTYPE_MOVE) { // for now, if the first element isn't a move, pretend that it doesn't exist *NotPresent = TRUE; return 0; } INT32 CoordType; INT32 l; UINT32 Control1 = 0; // number of first control point UINT32 Control2 = 0; // of second DocCoord co, cn1, cn2; // coordinates PathFlags Flags; INT32 NNodes = CDRDATA_WORD(Arrow->NNodes); BOOL NeedMoveTo = TRUE; // convert all the coordinates for(l = 0; l < NNodes; l++) { CoordType = Arrow->NodeTypes[l] & cdrfPATHCOORDTYPE_MASK; if(CoordType == cdrfPATHCOORDTYPE_MOVE || l == 0) { // start a new path! LastType = ThisType; // first of all, what type of path is this? if((Arrow->NodeTypes[l] & cdrfPATHCOORDATTR_CLOSE) != 0) ThisType = GCN_LASTSUB_CLOSED; else ThisType = GCN_LASTSUB_OPEN; // OK, do we need to start a new path? if(ThisType != LastType) { // yep, attach the last one we did if(ThisPath != 0) { // check that the path is OK if(!ThisPath->InkPath.EnsureValid()) { // no, it's completely knackered delete ThisPath; ThisPath = 0; } else { // finish off the path ThisPath->InvalidateBoundingRect(); if(FirstPath == 0) FirstPath = ThisPath; if(LastPath != 0) ThisPath->AttachNode(LastPath, NEXT); LastPath = ThisPath; ThisPath = 0; } } // get a new path ThisPath = new NodePath; if(ThisPath == 0) return 0; // no path created. A bit of a pity // set it up ready for conversion if(!ThisPath->SetUpPath()) return 0; ThisPath->InkPath.FindStartOfPath(); // set whether it's filled or not if(ThisType == GCN_LASTSUB_CLOSED) { ThisPath->InkPath.IsFilled = TRUE; ThisPath->InkPath.IsStroked = FALSE; } else { ThisPath->InkPath.IsFilled = FALSE; ThisPath->InkPath.IsStroked = TRUE; } } } co.x = CDRDATA_SWORD(Coords[l].X); co.y = CDRDATA_SWORD(Coords[l].Y); // ensure we get all the move tos we need. if(NeedMoveTo && CoordType != cdrfPATHCOORDTYPE_MOVE) { if(!ThisPath->InkPath.InsertMoveTo(co)) return 0; } NeedMoveTo = FALSE; // convert the coordinates switch(CoordType) { case cdrfPATHCOORDTYPE_MOVE: // add a move to this path if(!ThisPath->InkPath.InsertMoveTo(co)) return 0; break; case cdrfPATHCOORDTYPE_LINETO: // add a line to this coord to the path if(!ThisPath->InkPath.InsertLineTo(co)) return 0; break; case cdrfPATHCOORDTYPE_CURVE: // check we have some control points for this curve // a control point cannot be the first coord, so it's OK to check against 0 if(Control1 == 0 || Control2 == 0) { TRACEUSER( "Ben", _T("No control points for curve element\n")); return 0; } // convert the control points cn1.x = CDRDATA_SWORD(Coords[Control1].X); cn1.y = CDRDATA_SWORD(Coords[Control1].Y); cn2.x = CDRDATA_SWORD(Coords[Control2].X); cn2.y = CDRDATA_SWORD(Coords[Control2].Y); // create the curve Flags.IsSelected = FALSE; Flags.IsSmooth = Flags.IsRotate = ((Arrow->NodeTypes[l] & cdrfPATHCOORDATTR_SMOOTH) != 0)?TRUE:FALSE; Flags.IsEndPoint; // insert it into the path if(!ThisPath->InkPath.InsertCurveTo(cn1, cn2, co, &Flags)) return 0; break; case cdrfPATHCOORDTYPE_CONTROL: // shuffle the control points we've already got and add the new one Control1 = Control2; Control2 = l; break; default: break; } // is this a close subpath situtation? if((Arrow->NodeTypes[l] & cdrfPATHCOORDATTR_CLOSE) != 0) { // close the sub path if(CoordType != cdrfPATHCOORDTYPE_MOVE) { if(!ThisPath->InkPath.CloseSubPath()) return 0; // check the next coord type NeedMoveTo = TRUE; } } } // finish off the last path ThisPath->InvalidateBoundingRect(); // finish off this path we're doing if(ThisPath != 0) { if(FirstPath == 0) FirstPath = ThisPath; if(LastPath != 0) ThisPath->AttachNode(LastPath, NEXT); LastPath = ThisPath; ThisPath = 0; } // make up a nice group if there's more than one path NodeRenderableBounded *ToInsert = 0; if(FirstPath == LastPath) { ToInsert = FirstPath; } else { ToInsert = new NodeGroup; if(ToInsert == 0) return 0; FirstPath->InsertChainSimple(ToInsert, FIRSTCHILD); } Item->pNode = ToInsert; return ToInsert; }