#include <selop.h>
Inheritance diagram for SelOperation:

Public Member Functions | |
| SelOperation () | |
| SelOperation constructor, calls the constructor of the base class. | |
| virtual | ~SelOperation () |
| SelOperation destructor. | |
| BOOL | DoStartSelOp (BOOL RenderEndSelStateBlobs, BOOL RenderStartSelStateBlobs=TRUE, BOOL UndoRenderEndSelStateBlobs=FALSE, BOOL UndoRenderStartSelStateBlobs=FALSE) |
| This function must be called by all SelOperations. It does the following:. | |
| virtual void | End () |
| Calls DoEndSelOp(), then Operation::End(). | |
| virtual BOOL | MayChangeNodeBounds () const |
| virtual BOOL | GetStarted () const |
| virtual BOOL | DoAttributesSelected (List &AttribsToApply, UINT32 OpName, BOOL bPasteAttrs) |
| This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes). | |
| virtual BOOL | DoApplyAttribsToSelection (OpParam *pOpParam, BOOL bClearIfNoneApplied=FALSE) |
| Performs the OpApplyAttribsToSelected operation. This tries to apply the list of attributes in the OpParam->AttribsToApplyList to the selection. If no attribute can be applied then the operation does not generate any actions, and so will be a NOP and be destroyed during End(). | |
| virtual BOOL | DoApplyToSelection (List *Attribs, List *AttrGroupList, BOOL *pAttribWasRequired) |
| virtual BOOL | DoApply (Node *CurrentNode, NodeAttribute *Attrib, BOOL Mutate, BOOL InvalidateRegion=TRUE, BOOL KeepExistingCharacteristics=TRUE, BOOL *AttribWasRequired=NULL, BOOL *pbCanDiscardUndo=NULL) |
| Will not apply the attribute to CurrentNode if it does not require it. | |
Static Public Member Functions | |
| static BOOL | DoApply (SelOperation *pOp, Node *CurrentNode, NodeAttribute *Attrib, BOOL Mutate, BOOL InvalidateRegion=TRUE, BOOL KeepExistingCharacteristics=TRUE, BOOL bOptimise=TRUE, BOOL *AttribWasRequired=NULL, BOOL *pbCanDiscardUndo=NULL) |
| static BOOL | InvalidateNodeRegion (SelOperation *pOp, NodeRenderableBounded *CurrentNode, NodeAttribute *Attrib, BOOL Mutate) |
| static BOOL | ReleaseCachedForAttrApply (NodeRenderableBounded *pNode, BOOL bEffectRootOnly) |
| If we have just set an effect attribute then we can avoid releasing cached info of the specified node and all its children... We RELY on invalidations associated with this function not calling ReleaseCached themselves! | |
Protected Member Functions | |
| virtual BOOL | ApplyAttributeToBrush (Node *pCurrentNode, NodeAttribute *pAttr) |
| Works out if pCurrentNode has an applied brush attribute, and if so then sets up an action to tell the brush to use the attribute being applied. | |
| virtual BOOL | ApplyLineWidthToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode, NodeAttribute *pAttr) |
| If we are applying a line width to a brushed node we need to tell the brush that it must scale to line width. We must also do an additional invalidate region so that if we are increasing in size then the brush will be rerendered properly. | |
| virtual BOOL | ApplyStrokeColourToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode) |
| When a new stroke colour is applied to a brushed object we wish to set the flag that tells the brush to override the named colours in the brush with the colour applied. | |
| virtual BOOL | ApplyTransparencyToBrush (AttrBrushType *pAttrBrush, NodeRenderableInk *pBrushedNode) |
| When a transparency is applied to a brushed object we need to set a flag in the brush to tell it to use this new transparency. | |
| virtual BOOL | ApplyBrushAttr (Node *pCurrentNode, AttrBrushType *pAttrBrush) |
| When we apply a brush attribute to an object we want to check to see if the current line width attribute is the same as the default attribute. If it is then we will apply the default line width suggested by the brush itself. This is because people keep on applying brush attributes to 500MP lines and ending up with thousands of brush objects, which makes everything really slow. | |
Private Member Functions | |
| BOOL | DoEndSelOp () |
| This function gets called automatically by End(). | |
Private Attributes | |
| SelectionState * | SelState |
| BOOL | m_bStartCalled |
Static Private Attributes | |
| static BOOL | RenderEndSelStateBlobs |
| static BOOL | RenderStartSelStateBlobs |
| static BOOL | UndoRenderEndSelStateBlobs |
| static BOOL | UndoRenderStartSelStateBlobs |
Definition at line 121 of file selop.h.
|
|
SelOperation constructor, calls the constructor of the base class.
Definition at line 138 of file selop.cpp. 00138 : UndoableOperation() 00139 { 00140 m_bStartCalled = FALSE; 00141 }
|
|
|
SelOperation destructor.
Definition at line 158 of file selop.cpp.
|
|
||||||||||||
|
Works out if pCurrentNode has an applied brush attribute, and if so then sets up an action to tell the brush to use the attribute being applied.
Definition at line 770 of file attrappl.cpp. 00771 { 00772 ERROR2IF(pCurrentNode == NULL, FALSE, "Current node is NULL"); 00773 ERROR2IF(pAttr == NULL, FALSE, "Attribute is NULL"); 00774 00775 // currently this only works for colour changes and transparent fills 00776 if (!pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColourChange)) && !pAttr->IsATranspFill() 00777 && !pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrLineWidth)) && !pAttr->IsABrush()) 00778 return TRUE; 00779 00780 // first get the existing brush attribute 00781 AttrBrushType* pAttrBrush = NULL; 00782 // for some reason we don't check the return value here?? 00783 /*BOOL ok =*/ ((NodeRenderableInk*)pCurrentNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), 00784 (NodeAttribute**)&pAttrBrush); 00785 00786 // if we're applying a brush attribute then do something else 00787 if (pAttr->IsABrush()) 00788 { 00789 AttrBrushType* pNewAttrBrush = (AttrBrushType*)pAttr; 00790 return ApplyBrushAttr(pCurrentNode, pNewAttrBrush); 00791 } 00792 00793 00794 // there isn't one - thats ok 00795 if (pAttrBrush == NULL || pAttrBrush->GetBrushHandle() == BrushHandle_NoBrush) 00796 return TRUE; 00797 00798 // so now we have a brush attribute, so lets determine what to do: 00799 if (pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrStrokeColourChange))) 00800 { 00801 // only do this is the new colour is not transparent 00802 AttrStrokeColourChange* pStrokeCol = static_cast<AttrStrokeColourChange*>(pAttr); 00803 DocColour* pCol = pStrokeCol->GetStartColour(); 00804 //PORTNOTE("other","Removed DocColour usage") - AMB Unremoved 00805 if (pCol->IsTransparent()) 00806 return TRUE; 00807 00808 return ApplyStrokeColourToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode); 00809 } 00810 00811 // Is this a porting comment-out? AMB 00812 // if (pAttr->IsATranspFill()) 00813 // return ApplyTransparencyToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode); 00814 if (pAttr->IsKindOf(CC_RUNTIME_CLASS(AttrLineWidth))) 00815 return ApplyLineWidthToBrush(pAttrBrush, (NodeRenderableInk*)pCurrentNode, pAttr); 00816 00817 // trash the cached bounding rect 00818 pAttrBrush->ClearCachedRect(); 00819 00820 // if it isn't one of the above then we dont have to do anything 00821 return TRUE; 00822 }
|
|
||||||||||||
|
When we apply a brush attribute to an object we want to check to see if the current line width attribute is the same as the default attribute. If it is then we will apply the default line width suggested by the brush itself. This is because people keep on applying brush attributes to 500MP lines and ending up with thousands of brush objects, which makes everything really slow.
Definition at line 961 of file attrappl.cpp. 00962 { 00963 ERROR2IF(pCurrentNode == NULL || pAttrBrush == NULL, FALSE, "Null input pointers to OpApplyAttrib::ApplyBrushAttr"); 00964 ERROR2IF(!pCurrentNode->IsAnObject(), FALSE, "Input node is not an ink node in OpApplyAttrib::ApplyBrushAttr"); 00965 00966 // its too complicated when you have compound nodes 00967 if (pCurrentNode->IsCompound()) 00968 return TRUE; 00969 00970 AttrLineWidth* pCurrentLineWidth = NULL; 00971 ((NodeRenderableInk*)pCurrentNode)->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), (NodeAttribute**)&pCurrentLineWidth); 00972 00973 if (pCurrentLineWidth != NULL) 00974 { 00975 // Get the default line width 00976 AttrLineWidth* pDefault = (AttrLineWidth*)(AttributeManager::GetDefaultAttribute(ATTR_LINEWIDTH)); 00977 if (pDefault == NULL) 00978 { 00979 ERROR3("Unable to get default line width, theres no way this can happen Jim!"); 00980 // continue anyway 00981 } 00982 else 00983 { 00984 // check to see if default is the same as current, if not then just leave 00985 if (pCurrentLineWidth->Value.LineWidth != pDefault->Value.LineWidth-1) 00986 { 00987 delete pDefault; 00988 PathProcessorBrush* pPPB = pAttrBrush->GetPathProcessor(); 00989 if (pPPB) 00990 { 00991 BOOL UsesPressure = pAttrBrush->GetPressureCache() != NULL; 00992 pPPB->ScaleToValue(pCurrentLineWidth->Value.LineWidth, !UsesPressure); 00993 pPPB->AdjustSpacingForClosedPath((NodeRenderableInk*)pCurrentNode); 00994 } 00995 00996 return TRUE; 00997 } 00998 delete pDefault; 00999 } 01000 } 01001 01002 01003 // otherwise we want a new line width attribute 01004 MILLIPOINT LineWidth = pAttrBrush->GetDefaultLineWidth(TRUE); 01005 01006 //DoApply makes a copy so we only need to make this local 01007 AttrLineWidth NewLineWidth; 01008 01009 NewLineWidth.Value.LineWidth = LineWidth; 01010 01011 // now apply it 01012 return DoApply(pCurrentNode, &NewLineWidth, FALSE, FALSE); 01013 01014 }
|
|
||||||||||||||||
|
If we are applying a line width to a brushed node we need to tell the brush that it must scale to line width. We must also do an additional invalidate region so that if we are increasing in size then the brush will be rerendered properly.
Definition at line 921 of file attrappl.cpp. 00923 { 00924 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00925 ERROR2IF(pBrushedNode == NULL, FALSE, "Node pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00926 ERROR2IF(pAttr == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyLineWidthToBrush"); 00927 00928 // if we are on a closed path then ask the PPB to even out the spacing 00929 PathProcessorBrush* pPPB = pAttrBrush->GetPathProcessor(); 00930 if (pPPB != NULL) 00931 { 00932 // scale to the new line width 00933 AttrLineWidth* pLineWidth = (AttrLineWidth*)pAttr; 00934 BOOL UsesPressure = pAttrBrush->GetPressureCache() != NULL; 00935 pPPB->ScaleToValue(pLineWidth->Value.LineWidth, !UsesPressure); 00936 pPPB->AdjustSpacingForClosedPath(pBrushedNode); 00937 } 00938 00939 return TRUE; 00940 }
|
|
||||||||||||
|
When a new stroke colour is applied to a brushed object we wish to set the flag that tells the brush to override the named colours in the brush with the colour applied.
Definition at line 871 of file attrappl.cpp. 00872 { 00873 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyStrokeColourToBrush"); 00874 ERROR2IF(pBrushedNode == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyStrokeColourToBrush"); 00875 00876 00877 00878 00879 // if the brush already uses local colours then don't bother doing anything 00880 PathProcessorBrush *pPPB = pAttrBrush->GetPathProcessor(); 00881 if (pPPB == NULL) 00882 return TRUE; 00883 00884 if (pPPB->GetUseLocalFillColour() || !pPPB->GetUseNamedColours()) 00885 return TRUE; 00886 00887 // make the OpParam 00888 ChangeBrushOpParam Param; 00889 00890 Param.ChangeType = CHANGEBRUSH_USENAMEDCOL; 00891 Param.m_bNewUseNamed = FALSE; 00892 ChangeBrushAction* pAction = NULL; 00893 // initialise the action 00894 if (ChangeBrushAction::Init(this, &UndoActions, pBrushedNode, 00895 &Param, &pAction) == AC_FAIL) 00896 return FALSE; 00897 00898 return TRUE; 00899 }
|
|
||||||||||||
|
When a transparency is applied to a brushed object we need to set a flag in the brush to tell it to use this new transparency.
Definition at line 838 of file attrappl.cpp. 00839 { 00840 ERROR2IF(pAttrBrush == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyTransparencyToBrush"); 00841 ERROR2IF(pBrushedNode == NULL, FALSE, "Attribute pointer is NULL in OnApplyAttrib::ApplyTransparencyToBrush"); 00842 00843 // make the OpParam 00844 ChangeBrushOpParam Param; 00845 00846 Param.ChangeType = CHANGEBRUSH_USELOCALTRANSP; 00847 Param.m_bNewUseLocalTransp = TRUE; 00848 ChangeBrushAction* pAction = NULL; 00849 // initialise the action 00850 if (ChangeBrushAction::Init(this, &UndoActions, pBrushedNode, &Param, &pAction) == AC_FAIL) 00851 return FALSE; 00852 00853 return TRUE; 00854 }
|
|
||||||||||||||||||||||||||||||||
|
Will not apply the attribute to CurrentNode if it does not require it.
Definition at line 229 of file attrappl.cpp. 00237 { 00238 return SelOperation::DoApply(this, CurrentNode, Attrib, Mutate, InvalidateRegion, KeepExistingCols, TRUE, pbAttribWasRequired, pbCanDiscardUndo); 00239 }
|
|
||||||||||||||||||||||||||||||||||||||||
|
Definition at line 241 of file attrappl.cpp. 00251 { 00252 BOOL AttributeExists = FALSE; // Until we find that the attribute does exist 00253 00254 CCRuntimeClass* AttrType = Attrib->GetAttributeType(); 00255 00256 ERROR3IF(!CurrentNode->IsAnObject(), "Trying to apply an attribute to a non-NodeRenderableInk"); 00257 00258 // We don't allow attributes like 'Quality' to be applied to objects directly. 00259 ERROR3IF(!(Attrib->CanBeAppliedToObject()), "Trying to apply an illegal attribute to the object"); 00260 00261 if (!(Attrib->CanBeAppliedToObject())) 00262 return TRUE; // Just pretend they ever tried. 00263 00264 Node* OriginalCurrentNode = CurrentNode; 00265 00266 if (CurrentNode->IsAnObject()) 00267 { 00268 00269 // Obtain the real object to apply the attribute to 00270 CurrentNode = ((NodeRenderableInk*)CurrentNode)->GetObjectToApplyTo(Attrib->GetAttributeType()); 00271 if (!CurrentNode) 00272 { 00273 ERROR3("OpApplyAttrib::DoApply, Unable to find object to apply to"); 00274 return TRUE; 00275 } 00276 } 00277 00278 // NOTE! Better to get the value of this flag here, now that GetObjectToApplyTo has been called 00279 BOOL bEffectRootOnly = (CurrentNode->IsAnObject() && ((NodeRenderableInk*)CurrentNode)->IsValidEffectAttr(Attrib)); 00280 00281 // If we are applying attributes to the Caret alone then the caller should not retain an undo record 00282 // for this operation... 00283 if (pbCanDiscardUndo) 00284 *pbCanDiscardUndo = *pbCanDiscardUndo && CurrentNode->DiscardsAttributeChildren(); 00285 00286 // BODGE! ------------------------------------------------------------ 00287 // Don't apply stroke transparency as an effect attribute - nothing 00288 // needs it. Test has to be done here because other objects in the 00289 // selection might need it... 00290 if (bEffectRootOnly && AttrType == CC_RUNTIME_CLASS(AttrStrokeTransp)) 00291 return TRUE; 00292 // END-BODGE! -------------------------------------------------------- 00293 00294 // Needed to support adding triggers, who can be multiply applied 00295 BOOL AddEvenIfMultiple = FALSE; 00296 00297 // Do not apply the attribute if CurrentNode does not require it 00298 if ((((NodeRenderableInk*)CurrentNode)->RequiresAttrib(Attrib))) 00299 { 00300 00301 if (pbAttribWasRequired) 00302 *pbAttribWasRequired = TRUE; 00303 00304 if (CurrentNode != OriginalCurrentNode) 00305 { 00306 // BODGE TEXT 00307 // We need to call AllowOp, for the TextStories benefit, 00308 // so that lines know they have been affected 00309 00310 ObjChangeFlags cFlags; 00311 cFlags.Attribute = TRUE; 00312 ObjChangeParam ObjChange(OBJCHANGE_STARTING, cFlags, NULL, pOp); 00313 00314 if (!CurrentNode->AllowOp(&ObjChange)) 00315 { 00316 // It's already passed the test once. 00317 ERROR3("Doing op when no nodes will allow it"); 00318 } 00319 } 00320 00321 // ----------------------------------------------------------------------------- 00322 // Determine if the current node already has an attribute which is the same 00323 // runtime class as Attrib. 00324 Node* n = CurrentNode->FindFirstChild(); 00325 Node* pLastBoundedNode = NULL; 00326 if (bEffectRootOnly) 00327 { 00328 pLastBoundedNode = CurrentNode->FindLastChild(CC_RUNTIME_CLASS(NodeRenderableBounded)); 00329 ERROR3IF(pLastBoundedNode==NULL, "Attempt to apply effect attr to node with no children"); 00330 00331 if (pLastBoundedNode) n = pLastBoundedNode->FindNext(); 00332 } 00333 00334 while (n && (n->IsOrHidesAnAttribute())) 00335 { 00336 // Now lets see if we can find an attribute of the same type 00337 // as the one we are interested in. 00338 if (n->IsAnAttribute()) 00339 { 00340 NodeAttribute* pNdAttr = (NodeAttribute*)n; 00341 00342 if( pNdAttr->GetAttributeType() == AttrType) 00343 { 00344 // Attributes are of the same type (whatever that might mean) 00345 00346 // Look for another attribute of the same Type if we're allowed more than 00347 // one per object 00348 BOOL LookForMultiple = FALSE; 00349 00350 if (Attrib->CanBeMultiplyApplied()) 00351 { 00352 // If the classID's are the same then we want to replace the old one 00353 // (unless they're identical) 00354 if (Attrib->GetAttributeClassID() == pNdAttr->GetAttributeClassID()) 00355 { 00356 LookForMultiple = FALSE; // stop looking now 00357 AddEvenIfMultiple = FALSE; // replace the old one 00358 } 00359 else 00360 { 00361 // they're not the same classID's then we'll add a new one 00362 // but keep looking for a duplicate 00363 LookForMultiple = TRUE; 00364 AddEvenIfMultiple = TRUE; 00365 } 00366 } 00367 00368 // Do the attributes have the same value ?. If they do then there is no point in 00369 // applying it a second time 00370 00371 // to have the same value they must share the same runtime class 00372 if (IS_SAME_CLASS(pNdAttr, Attrib)) 00373 { 00374 // Found an identical attribute, so ignore this apply 00375 if ((*pNdAttr)==(*Attrib)) 00376 return TRUE; // We are not failing, just doing nothing. 00377 00378 if (Attrib->IsABrush()) 00379 ((AttrBrushType*)Attrib)->OnReplaceAttribute((AttrBrushType*)pNdAttr); 00380 } 00381 00382 // if applying a brush attribute we must copy some data over 00383 if (!LookForMultiple) 00384 { 00385 AttributeExists = TRUE; 00386 break; 00387 } 00388 } 00389 } 00390 n = n->FindNext(); // Find next child of CurrentNode 00391 } 00392 00393 // >>>> Temporary BODGE to aid select-inside... 00394 // >>>> ALWAYS clear any attributes of the same type from the subtree (even if the 00395 // >>>> attribute just applied replaced an existing one) so that dubious 00396 // >>>> attribute states (due to this routine not dealing with Select-inside 00397 // >>>> properly yet) can be cleared. 00398 // >>>> NOTE! the current att (n) is passed in to DoRemoveAttTypeFromSubtree so 00399 // >>>> that it won't be deleted along with atts of the same type - that would be 00400 // >>>> (has been) disastrous! 00401 // Triggers can be multiply applied to groups, so we need to check CanBeMultiplyApplied 00402 if (CurrentNode->IsCompound() && !Attrib->CanBeMultiplyApplied() && !bEffectRootOnly) 00403 { 00404 // Remove all instances of attributes of the same type from the subtree. 00405 // This is not neccessary if the AttributeExists flag is TRUE because 00406 // we know in this situation that the subtree cannot contain any other 00407 // instances of the attribute !. 00408 if (pOp && !pOp->DoRemoveAttrTypeFromSubtree(CurrentNode, Attrib->GetAttributeType(), n)) 00409 { 00410 pOp->FailAndExecute(); // Just to make sure 00411 return FALSE; 00412 } 00413 } 00414 00415 // At this point we have Either ..... 00416 // 1. Found an attribute of the same type as the new one, and we will 00417 // now replace it. 00418 // 2. Found the specific attribute we were looking for and will replace 00419 // that. 00420 // 3. Found an attribute to mutate. 00421 // 4. Found no attribute of the correct type, indicating that it has 00422 // been factored out, and we need to put a new one in here. 00423 // 5. The attribute had CanBeMultiplyApplied() set, and no exact same 00424 // Attribute was found. 00425 // 00426 // Have we have got an Attribute to do something with ? 00427 NodeAttribute* AttribClone = NULL; 00428 if ( !AddEvenIfMultiple && n && n->IsAnAttribute()) 00429 { 00430 // Yes ! 00431 NodeAttribute* pAttr = (NodeAttribute*)n; 00432 00433 if (Mutate) 00434 { 00435 // Mutate it into the new type. 00436 AttribClone = ((AttrFillGeometry*)n)->Mutate((AttrFillGeometry*)Attrib, bOptimise); 00437 } 00438 else 00439 { 00440 // We're gunna just replace the attribute with the new one. 00441 00442 // First make a copy of the new attribute. 00443 if (pOp) 00444 ALLOC_WITH_FAIL(AttribClone ,((NodeAttribute*)Attrib->SimpleCopy()), pOp) 00445 else 00446 AttribClone = (NodeAttribute*)Attrib->SimpleCopy(); 00447 if (AttribClone == NULL) 00448 return FALSE; 00449 00450 // Complication !! 00451 // If we are replacing a Fill Attribute and the attribute we are replacing 00452 // is already filled, then we need to extract the colour of the existing 00453 // fill and use them for the new fill. 00454 if ( KeepExistingCols && ((NodeAttribute*)n)->IsAFillAttr() ) 00455 { 00456 AttrFillGeometry* NodeReplaced = (AttrFillGeometry*)n; 00457 00458 // Copy the old fill characteristics into the new Fill 00459 if (!OpApplyAttrib::KeepExistingCharacteristics(NodeReplaced, (AttrFillGeometry*)AttribClone)) 00460 return FALSE; 00461 } 00462 00463 if ( Attrib->IsATranspFill() && Attrib->IsAFlatFill()) 00464 { 00465 ((AttrFillGeometry*)n)->RenderFillBlobs(); 00466 } 00467 } 00468 00469 // If Mutate returned NULL, which means the Mutate 00470 // did nothing, we should return TRUE, which will move 00471 // onto the next object. 00472 if (AttribClone == NULL) 00473 return TRUE; 00474 00475 // ---------------------------------------------------------- 00476 // If we have just set an effect attribute then we can avoid releasing 00477 // cached info of the specified node and all its children... 00478 // 00479 // We RELY on invalidations associated with this function not 00480 // calling ReleaseCached themselves! 00481 // 00482 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00483 // ---------------------------------------------------------- 00484 00485 if (InvalidateRegion) 00486 { 00487 // Invalidate the Object before the attribute is applied 00488 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00489 return FALSE; 00490 } 00491 00492 // Now we have done with the old attribute, so lets hide it, so 00493 // the changes can be undone 00494 // 00495 // Don't write any undo info if we don't have an op or the node 00496 // discards attributes by itself 00497 if (pOp && !CurrentNode->DiscardsAttributeChildren()) 00498 { 00499 // Note that we wouldn't need this test and we wouldn't need 00500 // to use the HideNode/ShowNode actions here if solid fill 00501 // dragging used OpApplyAttrInteractive. Instead it uses an 00502 // older system which relies on the HideNodeAction recording 00503 // a pointer to an attribute at the start of the drag which 00504 // is subsequently updated during the drag. 00505 if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttrInteractive))) 00506 { 00507 ApplyAction* pUndoApply; 00508 // Create an action to re-apply the attribute when we undo 00509 if ( ApplyAction::Init(pOp, 00510 pOp->GetUndoActionList(), 00511 CurrentNode, 00512 pAttr, 00513 TRUE, // When the attribute gets hidden we 00514 // must include its size 00515 (Action**)(&pUndoApply)) 00516 == AC_FAIL) 00517 { 00518 return FALSE; 00519 } 00520 pAttr->CascadeDelete(); 00521 delete pAttr; 00522 pAttr = NULL; 00523 } 00524 else 00525 { 00526 if (!pOp->DoHideNode(n, TRUE)) // Include the subtree size 00527 return FALSE; 00528 } 00529 } 00530 else 00531 { 00532 pAttr->CascadeDelete(); 00533 delete pAttr; 00534 pAttr = NULL; 00535 } 00536 00537 } 00538 else // if (n != NULL) 00539 { 00540 // We've not found an attribute to replace, so we'll have to put 00541 // a new one in 00542 NodeAttribute* TempAttr = NULL; 00543 00544 BOOL FoundAttr = ((NodeRenderableInk*)CurrentNode)-> 00545 FindAppliedAttribute(Attrib->GetAttributeType(), &TempAttr); 00546 00547 if (!FoundAttr || TempAttr == NULL) 00548 return FALSE; 00549 00550 if (Mutate) 00551 { 00552 AttribClone = ((AttrFillGeometry*)TempAttr)->Mutate((AttrFillGeometry*)Attrib, bOptimise); 00553 } 00554 else 00555 { 00556 // We'll just put a copy of our attribute in the tree. 00557 if (pOp) 00558 ALLOC_WITH_FAIL(AttribClone ,((NodeAttribute*)Attrib->SimpleCopy()), pOp) 00559 else 00560 AttribClone = (NodeAttribute*)Attrib->SimpleCopy(); 00561 00562 if ( KeepExistingCols && (TempAttr->IsAFillAttr()) ) 00563 { 00564 AttrFillGeometry* NodeReplaced = (AttrFillGeometry*)TempAttr; 00565 00566 // Copy the old fill characteristics into the new Fill 00567 if (!OpApplyAttrib::KeepExistingCharacteristics(NodeReplaced, (AttrFillGeometry*)AttribClone)) 00568 return FALSE; 00569 } 00570 00571 if (Attrib->IsATranspFill() && Attrib->IsAFlatFill()) 00572 { 00573 // If we are mutating into a flat fill, then we need 00574 // to make sure we remove any existing fill blobs. 00575 ((AttrFillGeometry*)TempAttr)->RenderFillBlobs(); 00576 } 00577 } 00578 00579 if (AttribClone) 00580 { 00581 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00582 00583 if (InvalidateRegion) 00584 { 00585 // Make sure the node is redrawn 00586 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00587 return FALSE; 00588 } 00589 } 00590 } 00591 00592 // If the AttribClone has the same value as an applied attribute 00593 // (A default attr if the attribs have been localised). Then we don't want to apply it ! 00594 if (AttribClone && AttribClone->ShouldBeOptimized() && !bEffectRootOnly && bOptimise) 00595 { 00596 NodeAttribute* pAppliedAttr; 00597 if (((NodeRenderableInk*)CurrentNode)->FindAppliedAttribute(AttribClone->GetAttributeType(), 00598 &pAppliedAttr)) 00599 { 00600 // Do the attributes have the same value ? 00601 if ((IS_SAME_CLASS(AttribClone, pAppliedAttr))) 00602 { 00603 if ((*AttribClone)==(*pAppliedAttr)) 00604 { 00605 AttribClone->CascadeDelete(); // Delete the attribute 00606 00607 // If attribute affect's the bounds of the object (eg. a LineWidth) then invalidate the 00608 // bounds of the object 00609 00610 if (pAppliedAttr->EffectsParentBounds()) 00611 { 00612 ((NodeRenderableBounded*)CurrentNode)->InvalidateBoundingRect(TRUE); 00613 } 00614 00615 delete AttribClone; 00616 AttribClone = NULL; 00617 } 00618 } 00619 } 00620 } 00621 00622 // Effect attributes don't optimise so if the value of this is the 00623 // same as the default value we should not add it here 00624 // 00625 if (AttribClone && bEffectRootOnly && AttribClone->HasEquivalentDefaultValue() && bOptimise) 00626 { 00627 // Just allow the attribute to be hidden 00628 AttribClone->CascadeDelete(); // Delete the attribute 00629 delete AttribClone; 00630 AttribClone = NULL; 00631 } 00632 00633 if (AttribClone) 00634 { 00635 // Finally !! We can add the new attribute node into the tree. 00636 if (bEffectRootOnly) 00637 AttribClone->AttachNode(pLastBoundedNode, NEXT); 00638 else 00639 AttribClone->AttachNode(CurrentNode, FIRSTCHILD); 00640 00641 AttributeManager::pLastNodeAppliedTo = (NodeRenderableInk*)CurrentNode; 00642 00643 // And now it's in the tree, we need to make sure that any fill control 00644 // points are valid. 00645 if (AttribClone->IsAFillAttr()) 00646 { 00647 ((AttrFillGeometry*)AttribClone)->AttributeChanged(); 00648 } 00649 00650 if (pOp && !CurrentNode->DiscardsAttributeChildren()) 00651 { 00652 // Note that we wouldn't need this test and we wouldn't need 00653 // to use the HideNode/ShowNode actions here if solid fill 00654 // dragging used OpApplyAttrInteractive. Instead it uses an 00655 // older system which relies on the HideNodeAction recording 00656 // a pointer to an attribute at the start of the drag and the 00657 // contents of the attribute being updated during the drag. 00658 if (pOp->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttrInteractive))) 00659 { 00660 UnApplyAction* pUndoApply; 00661 // Create an action to hide the attribute when we undo 00662 if ( UnApplyAction::Init(pOp, 00663 pOp->GetUndoActionList(), 00664 CurrentNode, 00665 AttribClone, 00666 TRUE, // When the attribute gets hidden we 00667 // must include its size 00668 (Action**)(&pUndoApply)) 00669 == AC_FAIL) 00670 { 00671 AttribClone->CascadeDelete(); 00672 delete (AttribClone); 00673 return FALSE; 00674 } 00675 } 00676 else 00677 { 00678 HideNodeAction* UndoHideNodeAction; 00679 // Create an action to hide the attribute when we undo 00680 if ( HideNodeAction::Init(pOp, 00681 pOp->GetUndoActionList(), 00682 AttribClone, 00683 TRUE, // When the attribute gets hidden we 00684 // must include its size 00685 (Action**)(&UndoHideNodeAction)) 00686 == AC_FAIL) 00687 { 00688 AttribClone->CascadeDelete(); 00689 delete (AttribClone); 00690 return FALSE; 00691 } 00692 } 00693 } 00694 00695 } 00696 00697 ReleaseCachedForAttrApply((NodeRenderableBounded*)CurrentNode, bEffectRootOnly); 00698 00699 if (InvalidateRegion) 00700 { 00701 // Invalidate the node rectangle, now the new attr has been applied 00702 if (!InvalidateNodeRegion(pOp, (NodeRenderableBounded*)CurrentNode, Attrib, Mutate)) // Doesn't invalidate cached info! 00703 return FALSE; 00704 } 00705 } 00706 00707 // we may have to apply this to a brushed node 00708 if (pOp) // TODO: Make this work when no undo op specified? 00709 { 00710 if (!pOp->ApplyAttributeToBrush(CurrentNode, Attrib)) 00711 return FALSE; 00712 } 00713 return TRUE; // success 00714 }
|
|
||||||||||||
|
Performs the OpApplyAttribsToSelected operation. This tries to apply the list of attributes in the OpParam->AttribsToApplyList to the selection. If no attribute can be applied then the operation does not generate any actions, and so will be a NOP and be destroyed during End().
OpParam->undoAttribStrID: Specifies the undo string to display (eg. Paste Atrributes)
Whenever an attribute is applied to an object, the Current AttributeGroup associated with the object is added to the attributes set of current attribute groups. Therefore if an attribute's set is empty then we know that the attribute has not been applied. OpParam->Success: FALSE if the operation failed. i.e. FailAndExecute() was called. anyAttrsApplied: FALSE if the operation has not applied any attributes This Operation currently does not support mutation Definition at line 2388 of file attrappl.cpp. 02389 { 02390 // Ensure that the OpParam is valid 02391 ERROR3IF(!pOpParam, "No parameters passed to OpApplyAttribsToSelected"); 02392 ApplyAttribsToSelectedParam* pParam = (ApplyAttribsToSelectedParam*)pOpParam; 02393 // get inputs 02394 List* pAttrsToApply = pParam->AttribsToApply; 02395 // m_pAttribList = pAttrsToApply; 02396 02397 // UndoAttribStrID = pParam->UndoAttribStrID; // TODO: Fix this? 02398 02399 // and outputs 02400 List* AttrGroupList = pParam->AttrGroupList; 02401 ERROR3IF(!(AttrGroupList->IsEmpty()), 02402 "AttributeGroupList not empty on entry to OpApplyAttribsToSelected"); 02403 BOOL* Success = pParam->Success; 02404 *Success = FALSE; // Let's be pessimistic 02405 BOOL* AppliedAttrs = pParam->AnyAttrsApplied; 02406 *AppliedAttrs = FALSE; 02407 BOOL bAnyApplied = FALSE; 02408 BOOL bWeStartedThisOp = FALSE; 02409 02410 // Create a stable range of objects to apply to 02411 Range SelRng(*(GetApplication()->FindSelection())); 02412 02413 // We need two sets of attribute types 02414 // one for Line level attributes, and one for non Line level attributes. This is because the localise 02415 // and factor out routines require each attribute in the set to be all applicable to the same 02416 // object. This would not be true if our set contained a BOLD, and a LINE_SPACING attribute for example. 02417 02418 // Make our attribute type sets 02419 AttrTypeSet LineLevelAttrTypes; 02420 AttrTypeSet OtherAttrTypes; 02421 NodeAttributePtrItem* pAttrItem = (NodeAttributePtrItem*)(pAttrsToApply->GetHead()); 02422 NodeAttribute* pAttr; 02423 AttrTypeSet* SetToAddTo; 02424 while (pAttrItem) 02425 { 02426 pAttr = pAttrItem->NodeAttribPtr; 02427 ERROR3IF(!pAttr, "Should be an attribute"); 02428 if (pAttr->IsALineLevelAttrib()) 02429 SetToAddTo = &LineLevelAttrTypes; 02430 else 02431 SetToAddTo = &OtherAttrTypes; 02432 02433 if (!SetToAddTo->AddToSet(pAttr->GetAttributeType())) 02434 { 02435 FailAndExecute(); 02436 goto EndOperation; 02437 } 02438 pAttrItem = (NodeAttributePtrItem*)(pAttrsToApply->GetNext(pAttrItem)); 02439 } 02440 02441 // ----------------------------------------------------------- 02442 if (SelRng.FindFirst()!=NULL) 02443 { 02444 SelRange* Sel; 02445 ObjChangeFlags cFlags; 02446 cFlags.Attribute = TRUE; 02447 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 02448 02449 Sel = GetApplication()->FindSelection(); 02450 02451 if (!Sel->AllowOp(&ObjChange)) 02452 { 02453 FailAndExecute(); 02454 goto |