SelOperation Class Reference

A SelOperation. More...

#include <selop.h>

Inheritance diagram for SelOperation:

UndoableOperation Operation MessageHandler ListItem CCObject SimpleCCObject CarbonCopyOp OpAddBlendPath OpAddPath OpApplyAttrib OpApplyClipView OpApplyNamesToSel OpBaseConvertPathSegment OpBlendNodes OpBreakAtPoints OpBreakShapes OpBringToFront OpChangeBlend OpChangeBlendDistance OpChangeBlendSteps OpChangeBrush OpChangeContourAttributeProfile OpChangeContourColourType OpChangeContourObjectProfile OpChangeContourStepDistance OpChangeContourSteps OpChangeContourToInner OpChangeContourToOuter OpChangeFillProfile OpChangeTranspFillProfile OpClipartImport OpClipboardImport OpCombineLayersToFrameLayer OpCombineShapes OpContourNodes OpConvertPathToShapes OpConvertToBitmap OpCopy OpCreateContour OpCut OpDelete OpDeletePoints OpDeleteTextStory OpDetachBlendPath OpDragRegularShape OpDroppedFile OpEditBlendEndObject OpEditRectangle OpEditRegularShape OpFreeHand OpGroup OpJoinShapes OpLiveEffect OpMakeShapes OpMakeStroke OpMenuExport OpMenuImport OpMenuLoad OpMouldLibSel OpMoveBackwards OpMoveForwards OpMoveToLayer OpMoveToLyrBehind OpMoveToLyrInFront OpNewRegShape OpNodePathEditBlob OpOverprintFill OpOverprintLine OpPaste OpPasteAttributes OpPrintOnAllPlates OpPutToBack OpRedefineNamesAsSel OpReformShapeEdge OpRemoveAttributeFromSelection OpRemoveBlend OpRemoveClipView OpRemoveContour OpRemoveNamesFromSel OpReplaceAttributes OpRetroFit OpRetroSmooth OpReversePath OpShapeMakeRegular OpShapeToggleBase OpShapeToggleSetNumSides OpSmoothSelection OpTextUndoable OpToggleContourInsetPath OpToggleSmooth OpUngroup PlugInUndoOp TraceOp List of all members.

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

SelectionStateSelState
BOOL m_bStartCalled

Static Private Attributes

static BOOL RenderEndSelStateBlobs
static BOOL RenderStartSelStateBlobs
static BOOL UndoRenderEndSelStateBlobs
static BOOL UndoRenderStartSelStateBlobs

Detailed Description

A SelOperation.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
15/2/94
See also:
TransOperation

Definition at line 121 of file selop.h.


Constructor & Destructor Documentation

SelOperation::SelOperation  ) 
 

SelOperation constructor, calls the constructor of the base class.

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

Errors: -

See also:
-

Definition at line 138 of file selop.cpp.

00138                           : UndoableOperation()
00139 {
00140     m_bStartCalled = FALSE;
00141 }

SelOperation::~SelOperation  )  [virtual]
 

SelOperation destructor.

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

Errors: -

See also:
-

Definition at line 158 of file selop.cpp.

00159 {
00160 }


Member Function Documentation

BOOL SelOperation::ApplyAttributeToBrush Node pCurrentNode,
NodeAttribute pAttr
[protected, virtual]
 

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.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
24/2/2000
Parameters:
pCurrentNode - the node that the attribute is being applied to [INPUTS] pAttr - the attribute to apply
Returns:
TRUE if all ok.

Errors: -

See also:
-
Notes: This is only currently operational for fill attributes, others may be added in future. 18/4/2000 - Line widths added

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 }

BOOL SelOperation::ApplyBrushAttr Node pCurrentNode,
AttrBrushType pAttrBrush
[protected, virtual]
 

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.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
24/2/2000
Parameters:
pCurrentNode - the node we are applying the brush to [INPUTS] pAttrBrush - the brush attribute we are applying
Returns:
TRUE if all ok.

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 }

BOOL SelOperation::ApplyLineWidthToBrush AttrBrushType pAttrBrush,
NodeRenderableInk pBrushedNode,
NodeAttribute pAttr
[protected, virtual]
 

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.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
24/2/2000
Parameters:
pAttrBrush - the brush attribute that we wish to update [INPUTS] pBrushedNode -the node that the brush applies to pAttr - the line width that we are applying
Returns:
TRUE if all ok.

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 }

BOOL SelOperation::ApplyStrokeColourToBrush AttrBrushType pAttrBrush,
NodeRenderableInk pBrushedNode
[protected, virtual]
 

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.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
24/2/2000
Parameters:
pAttrBrush - the brush attribute that we wish to update [INPUTS] pbrushed node - the node that the brush applies to
Returns:
TRUE if all ok.

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 }

BOOL SelOperation::ApplyTransparencyToBrush AttrBrushType pAttrBrush,
NodeRenderableInk pBrushedNode
[protected, virtual]
 

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.

Author:
Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
Date:
24/2/2000
Parameters:
pAttrBrush - the brush attribute that we wish to update [INPUTS] pAttr - the attribute to apply
Returns:
TRUE if all ok.

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 }

BOOL SelOperation::DoApply Node CurrentNode,
NodeAttribute Attrib,
BOOL  Mutate,
BOOL  InvalidateRegion = TRUE,
BOOL  KeepExistingCols = TRUE,
BOOL *  pbAttribWasRequired = NULL,
BOOL *  pbCanDiscardUndo = NULL
[virtual]
 

Will not apply the attribute to CurrentNode if it does not require it.

Author:
Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
Date:
5/4/95
Parameters:
InvalidateRegion,: When TRUE DoInvalidateNodeRegion is called before and [INPUTS] after the attribute has been applied. If the attribute is being applied to a range of objects then it is inefficient to do this. KeepExistingCols: When TRUE the new attribute takes on the colour characteristics of the attribute it is replacing.
AttribWasRequired:This output is optional. It indicates if the [OUTPUTS] Attrib was required by the object.
Returns:
TRUE if successful FALSE if the operation should be aborted (TIDYUP THEN CALL End()!)

Errors: -

See also:
NodeRenderableInk::GetObjectToApplyTo

Definition at line 229 of file attrappl.cpp.

00237 {
00238     return SelOperation::DoApply(this, CurrentNode, Attrib, Mutate, InvalidateRegion, KeepExistingCols, TRUE, pbAttribWasRequired, pbCanDiscardUndo);
00239 }

BOOL SelOperation::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]
 

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 }

BOOL SelOperation::DoApplyAttribsToSelection OpParam pOpParam,
BOOL  bClearIfNoneApplied = FALSE
[virtual]
 

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().

Author:
Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> (from Simon)
Date:
16/02/2005 (from 16/8/93)
Parameters:
OpParam,: This must be a ApplyAttribsToSelectedParam type [INPUTS]
OpParam->AttribsToApply: This is the list of attributes that is to be applied to the selection. Each item on this list must be a NodeAttributePtrItem.

OpParam->undoAttribStrID: Specifies the undo string to display (eg. Paste Atrributes)

Parameters:
OpParam->AttrGroupList,: This list must be empty on entry to this function [OUTPUTS] If (Success) then this list will contain one ListListItem per attribute on the AttribsToApplyList. Each of these items will point to a Set of AttributeGroupItems.
Attribute -> { Set of current attribute groups }

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 EndOperation;
02455         }
02456     }
02457 
02458     if (!GetStarted())
02459     {
02460         if (!DoStartSelOp(FALSE,FALSE, TRUE,TRUE))   // Try to record the selection state , don't
02461                                                      // render the blobs though 
02462             goto EndOperation;
02463 
02464         bWeStartedThisOp = TRUE;
02465     }
02466 
02467     // Make a stable range
02468 //  Range SelRng(*(GetApplication()->FindSelection()));
02469 
02470     // Invalidate objects regions (include blobs because this may be neccessary, 
02471     //                             there is little overhead anyway).
02472     if (!DoInvalidateNodesRegions(SelRng, TRUE, FALSE))
02473         goto EndOperation;
02474 
02475     // Before we apply the attribute to the selection we must localise all attributes
02476     // with the same type that we are going to apply. If we don't do this then the
02477     // tree will be left in an invalid state. 
02478     
02479     if (!LineLevelAttrTypes.IsEmpty() && SelRng.FindFirst()!=NULL)
02480     {
02481         if (!DoLocaliseForAttrChange(&SelRng, &LineLevelAttrTypes))
02482             goto EndOperation;
02483     }
02484 
02485     if (!OtherAttrTypes.IsEmpty() && SelRng.FindFirst()!=NULL)
02486     {
02487         if (!DoLocaliseForAttrChange(&SelRng, &OtherAttrTypes))
02488             goto EndOperation;
02489     }
02490 
02491     // -----------------------------------------------------------
02492     if (!DoApplyToSelection(pAttrsToApply, AttrGroupList, &bAnyApplied))
02493     {
02494         goto EndOperation;
02495     }
02496 
02497     // -----------------------------------------------------------
02498     // If attributes were applied we must factor them out
02499     if (bAnyApplied)
02500     {
02501         // Having applied the attributes, we  must now try and factor out the newly 
02502         // applied attributes
02503         if (!LineLevelAttrTypes.IsEmpty())
02504         {
02505             if (!DoFactorOutAfterAttrChange(&SelRng, 
02506                                         &LineLevelAttrTypes))
02507             {
02508                 goto EndOperation;
02509             }
02510         }
02511 
02512         if (!OtherAttrTypes.IsEmpty())
02513         {
02514             if (!DoFactorOutAfterAttrChange(&SelRng, 
02515                                         &OtherAttrTypes))
02516             {
02517                 goto EndOperation;
02518             }
02519         }
02520 
02521         {   
02522             ObjChangeFlags cFlags;
02523             cFlags.Attribute = TRUE;
02524 
02525             ObjChangeParam ObjChange(OBJCHANGE_FINISHED,cFlags,NULL,this);
02526             if (!UpdateChangedNodes(&ObjChange))
02527             {
02528                 FailAndExecute();
02529                 goto EndOperation;
02530             }
02531         }
02532 
02533         // Invalidate after
02534         if (!DoInvalidateNodesRegions(SelRng, TRUE, FALSE))
02535         {
02536             goto EndOperation;
02537         }
02538     }
02539     else if (bClearIfNoneApplied)
02540     {
02541         // We applied no attributes so we can just chuck this undo record
02542         // and all its actions away
02543         SucceedAndDiscard();
02544     }
02545 
02546     // Output values
02547     *Success = TRUE;                // If we got here we must have succeeded
02548     *AppliedAttrs = bAnyApplied;    // Tell caller if any attributes were applied
02549   
02550 EndOperation:
02551     
02552     // Delete our lists of attribute types
02553     LineLevelAttrTypes.DeleteAll();
02554     OtherAttrTypes.DeleteAll();
02555 
02556     if (bWeStartedThisOp)
02557         End();
02558 
02559     return *Success;
02560 } 

BOOL SelOperation::DoApplyToSelection List Attribs,
List AttrGroupList,
BOOL *  pAttribWasRequired
[virtual]
 

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
4/10/95
Parameters:
A list of attributes to apply to the selection. Each item in the list is [INPUTS] a NodeAttributePtrItem.
AttrGroupList,: This list must be empty on entry to this function [OUTPUTS] If (Success) then this list will contain one ListListItem per attribute on the Attribs List. Each of these items will point to a Set of AttributeGroupItems.
Attribute -> { Set of current attribute groups }

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.

Returns:
TRUE if successful FALSE if the operation should be aborted (TIDYUP THEN CALL End()!)
See also:
OpApplyAttribsToSelected::DoWithParam

Definition at line 2594 of file attrappl.cpp.

02595 {
02596     ERROR3IF(!(AttrGroupList->IsEmpty()), "Invalid output param");
02597 
02598     // Set up a range of all selected nodes 
02599     SelRange* pSel = GetApplication()->FindSelection();
02600     EffectsStack* pStack = pSel->GetEffectsStack(FALSE, FALSE); // Get cached stack, don't escape derived objects (allow attrs to be applie to derived objects)
02601     ERROR3IF(pStack==NULL, "Failed to get PPStack in ApplyToSelection");
02602     INT32 stackpos = STACKPOS_TOP;
02603     Range* pLevel = pStack->GetLevelRange(&stackpos, FALSE);            // Don't escape old controllers, apply attr to base nodes
02604 
02605     BOOL bCanDiscardUndo = TRUE;
02606 
02607     NodeAttributePtrItem* pAttrItem = (NodeAttributePtrItem*)(Attribs->GetHead());
02608     while (pAttrItem)
02609     {
02610         NodeAttribute* pAttr = pAttrItem->NodeAttribPtr;
02611 
02612         // Create the pAttr's set of current attribute groups { currently empty }
02613         ListListItem* pAttrsSetItem = new ListListItem;
02614         if (!pAttrsSetItem)
02615             goto Failed;
02616         List* pAttrsSet = &(pAttrsSetItem->list);
02617         AttrGroupList->AddTail(pAttrsSetItem); 
02618         
02619         // While there are still nodes to apply the attribute to
02620         Node* CurrentNode = pLevel->FindFirst();
02621 //      Node* FirstNode = CurrentNode;
02622         while (CurrentNode)   
02623         {
02624             NodeAttribute* AttrToApply = pAttr;
02625             BOOL AppliedAttribIsCopy = FALSE;
02626             BOOL ThisAttrWasRequired = FALSE;
02627             if (pAttr->IsAFillAttr())
02628             {
02629                 // Transform the attribute to fit the node's bounds
02630                 DocRect NodeBounds = ((NodeRenderableInk*)CurrentNode)->GetBoundingRect(TRUE);
02631                 // We will transform a copy of the attribute.
02632                 AttrToApply = (NodeAttribute*)(pAttr->SimpleCopy());
02633                 AppliedAttribIsCopy = TRUE; // cos it is
02634                 if (!AttrToApply)
02635                     goto Failed;
02636                 AttrToApply->TransformToNewBounds(NodeBounds);
02637             }
02638 
02639             if (!DoApply(CurrentNode, 
02640                          AttrToApply, 
02641                          FALSE,  // Don't mutate
02642                          FALSE,  // Don't invalidate region
02643                          FALSE,  // Don't keep existing characteristics
02644                          &ThisAttrWasRequired,
02645                          &bCanDiscardUndo))
02646             {
02647                 goto Failed;
02648             }
02649 
02650             if (ThisAttrWasRequired)
02651             {
02652                 *pAttribWasRequired = TRUE;
02653 
02654                 // This next bit is a bit yucky, we are in desperate need of templates to implement
02655                 // proper sets.
02656                 // The attribute was required by the object
02657                 // Add the current attribute group associated with the object to the attributes set
02658                 // Search the pAttrsSet set to see if it's already there
02659 
02660                 CCRuntimeClass* NewAttrGroup = ((NodeRenderableInk*)CurrentNode)->GetCurrentAttribGroup();
02661                 ERROR3IF(NewAttrGroup == NULL, "Object has a NULL attribute group"); 
02662                 BOOL InSet = FALSE;
02663                 AttributeGroupItem* pAttrGrpItem = (AttributeGroupItem*)pAttrsSet->GetHead();
02664                 while(pAttrGrpItem != NULL)
02665                 {
02666                     CCRuntimeClass* InSetAttrGroup = pAttrGrpItem->AttrGroup;
02667                     ERROR3IF(InSetAttrGroup == NULL, "NULL attribute group found");
02668                     if (NewAttrGroup == InSetAttrGroup)
02669                     {
02670                         InSet = TRUE; 
02671                         break; // It's already in the set don't add it
02672                     }
02673                     pAttrGrpItem = (AttributeGroupItem*)pAttrsSet->GetNext(pAttrGrpItem);
02674                 }
02675             
02676                 if (!InSet) // The AttrGroup needs adding to the pAttrsSet 
02677                 {
02678                     // Create a new AttrGroupItem
02679                     pAttrGrpItem = new AttributeGroupItem();
02680                     if (!pAttrGrpItem)
02681                         goto Failed;
02682 
02683                     pAttrGrpItem->AttrGroup = NewAttrGroup;
02684 
02685                     // And add it to our set
02686                     pAttrsSet->AddHead(pAttrGrpItem); 
02687                 }  
02688             }
02689 
02690             if (CurrentNode->IsAnObject())
02691                 ((NodeRenderableInk*)CurrentNode)->InvalidateBoundingRect();
02692 
02693             CurrentNode = pLevel->FindNext(CurrentNode);
02694             if (AppliedAttribIsCopy)
02695             {
02696                 delete AttrToApply; // not required
02697                 AttrToApply = NULL; 
02698             }
02699         }
02700         ContinueSlowJob();
02701         pAttrItem = (NodeAttributePtrItem*)(Attribs->GetNext(pAttrItem));
02702     }
02703 
02704     // If all nodes report DiscardsAttributeChildren() = TRUE
02705     // Then we can abandon the entire Op once it's finished
02706     if (bCanDiscardUndo)
02707         SucceedAndDiscard();
02708 
02709     return TRUE; 
02710 
02711     Failed:
02712     // Tidyup, and return FALSE
02713     AttrGroupList->DeleteAll(); 
02714     return FALSE;
02715 }

BOOL SelOperation::DoAttributesSelected List AttribsToApply,
UINT32  OpName,
BOOL  bPasteAttrs
[virtual]
 

This high level function should be called whenever we need to apply multiple attributes to the selection (eg. PasteAttributes).

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
13/6/94
Parameters:
AttribsToApply,: A list of NodeAttributePtrItems. These are the attributes [INPUTS] which will be applied to the selection. The function does not currently support attribute mutation.
All AttrFillGeometry attributes should have their current bounds set using AttrFillGeometry::SetBoundingRect.

very important ~~~~~~~~~~~~~~

This function only ever applies copies of attributes in the AttribsToApply list. It is the responsibility of the caller to delete these attributes, if this is appropriate.

OpName: The name to give the operation which is performed by this function to apply attributes. eg. 'Paste Attributes'

Parameters:
- [OUTPUTS]
Returns:
-
If any objects are selected then the function invokes an operation to apply the attributes to these objects. Before an AttrFillGeometry is applied to an object it gets moved and scaled.

If no nodes are selected then the attributes may become current depending on the preferences and what the user decides.

See also:
AttributeManager::AttributeSelected

Definition at line 2779 of file attrmgr.cpp.

02780 {
02781     // The AttributeList cannot be empty
02782     ERROR3IF(AttribsToApply.IsEmpty(), "No attributes to apply in AttributeManager::AttributesSelected"); 
02783     if (AttribsToApply.IsEmpty()) return FALSE; // nothing to do
02784 
02785     // If there is no current document then there is very little we can do
02786     Document* CurrentDoc = Document::GetSelected();
02787     if (CurrentDoc == NULL)
02788         return TRUE; // We are not going to be able to do anything if there is no document
02789 
02790     SelRange* Sel = GetApplication()->FindSelection();
02791     ERROR3IF(Sel==NULL,"Can't find SelRange!");
02792     if (Sel==NULL) return TRUE;
02793 
02794     // If there are no objects in the selection, or if none of the selected objects require
02795     // the attribute, then it will not be applied
02796                             
02797     List AttrGroupsList;  // Will contain a list of current Attribute group sets. one for each attribute 
02798                           // in the AttribsToApply list. Each item in this list will be a ListListItem.
02799 
02800     BOOL Success;               // FALSE if the operation fails
02801     BOOL AnyAttrsApplied;       // FALSE if the operation has not applied any attributes
02802 
02803     // Build the parameter we are about to pass to the operation
02804     ApplyAttribsToSelectedParam OpParam(&AttribsToApply,
02805                                         OpName, 
02806                                         &AttrGroupsList,        // One per attribute applied
02807                                         &Success,               // Indicates if op was successful
02808                                         &AnyAttrsApplied);      // Indicates if the operation applied
02809                                                                 // any attributes
02810 
02811     
02812     // Invoke the core of the operation
02813     DoApplyAttribsToSelection(&OpParam, !GetStarted());         // Don't clear actions if the caller already called DoStartSelOp
02814 
02815     if (Success)
02816     {
02817         // Inform neccessary parties
02818         if (AnyAttrsApplied)
02819         {
02820             // Inform the selection that attributes have changed
02821             Sel->AttrsHaveChanged();
02822 
02823             // We've probably changed a Colour
02824             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::COLOURATTCHANGED)); 
02825             // and the Attrib may have changed shape or summit. Who knows ?
02826             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 
02827             Sel->UpdateBounds();
02828         }
02829         
02830         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
02831         // Now decide which attributes in the AttribsToApply list should be made current
02832                                                
02833         AttributeManager& AttrMgr = CurrentDoc->GetAttributeMgr();
02834         AttributeManager::AttrsToMakeCurrent AttribsToMakeCurrent = AttrMgr.GetAttributesToMakeCurrent(AttribsToApply, 
02835                                                                              AttrGroupsList,
02836                                                                              bPasteAttrs);
02837                                                                     
02838         if( AttribsToMakeCurrent == AttributeManager::NONE )
02839         {
02840             // Allow fill tools to update after a cancel
02841             // I'm not sure if we need this ???? Ask Will
02842             BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); 
02843         }
02844         else
02845         {
02846             BOOL AttributeApplied;
02847             NodeAttributePtrItem* pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetHead());
02848             ListListItem* pAttrsGroups = (ListListItem*) (AttrGroupsList.GetHead());
02849             while (pAttr)
02850             {
02851                 AttributeApplied = (!(pAttrsGroups->list.IsEmpty())); // Empty Current attribute group list
02852                 if (!AttributeApplied || (AttribsToMakeCurrent == AttributeManager::ALL))
02853                 {
02854                     // Add attribute to all current attribute groups in the list, or to the 
02855                     // group associated with the current tool if the list is empty.
02856                     AttributeManager::UpdateCurrentAttr(pAttr->NodeAttribPtr, 
02857                                       FALSE, // Not a mutator
02858                                       &(pAttrsGroups->list), 
02859                                       FALSE); // Don't tell world yet (too slow)
02860                 }
02861                 pAttr = (NodeAttributePtrItem*)(AttribsToApply.GetNext(pAttr));
02862                 pAttrsGroups = (ListListItem*)(AttrGroupsList.GetNext(pAttrsGroups));
02863             }
02864             // Tell world current attributes have changed
02865             BROADCAST_TO_ALL(CurrentAttrChangedMsg()); 
02866         } 
02867     }
02868     // Tidyup
02869     AttrGroupsList.DeleteAll(); // Delete all group lists 
02870 
02871     // And ensure that if we've caused the SelRange to set up any delayed message
02872     // broadcasts, that it sends them now rather than at some random time in the future
02873     // when some Op just happens to end.
02874     Sel->BroadcastAnyPendingMessages();
02875 
02876     return Success;
02877 }

BOOL SelOperation::DoEndSelOp  )  [private]
 

This function gets called automatically by End().

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
15/2/94
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
-
It Invalidates the rectangle covered by the selection and its blobs

Scope: protected

Returns:
Errors: -
See also:
-

Definition at line 306 of file selop.cpp.

00307 {
00308     // Create a SelectionState object
00309     ALLOC_WITH_FAIL(SelState, (new SelectionState()), this); 
00310     if (SelState == NULL)
00311     {
00312         return FALSE; // Failure 
00313     }
00314 
00315     // We have managed to create a SelectionState instance, now lets try and 
00316     // record the current selections 
00317 
00318     BOOL Success; 
00319 
00320     CALL_WITH_FAIL(SelState->Record(), this, Success)
00321 
00322     if (!Success)  // We failed to allocate enough memory to store the selection state
00323     {
00324         // There was insufficient memory to record the selections 
00325         delete SelState;            // Delete the selection state 
00326         SelState = NULL; 
00327         return FALSE; 
00328     }
00329 
00330     // We have successfully managed to create a Selection state, create an action 
00331     // to restore the selections when executed 
00332 
00333     // Recorded the current selection state ok
00334     RestoreSelectionsAction* RestoreAct;  
00335     ActionCode ActCode;  
00336 
00337     // Attempt to initialise the action    
00338     ActCode = RestoreSelectionsAction::Init(this,                    
00339                                             &UndoActions,  
00340                                             SelState, 
00341                                             FALSE,      // Don't Toggle
00342                                             FALSE,      
00343                                             FALSE,      // The SelState is not shared
00344                                             UndoRenderStartSelStateBlobs,
00345                                             UndoRenderEndSelStateBlobs, 
00346                                             TRUE,       // restore at start of undo             
00347                                             ( Action**)(&RestoreAct)); 
00348     if (ActCode == AC_FAIL)
00349     {
00350         delete SelState; // We won't be needing this 
00351         return FALSE;  
00352     }
00353 
00354     // OK the operation should have finished playing with the selection states, so we can turn
00355     // the blob rendering back on. If the operation needs to render the end SelState blobs then
00356     // this is done.
00357     
00358     // If the operation needs to restore the blobs then do so
00359     
00360 #if !defined(EXCLUDE_FROM_RALPH)
00361     if (RenderEndSelStateBlobs)
00362     {
00363         ENSURE(Camelot.FindSelection() != NULL, "There is no SelRange");
00364         Node* SelNd = Camelot.FindSelection()->FindFirst();
00365         if (SelNd != NULL)
00366         {
00367             Spread* SelSpread = (Spread*) SelNd->FindParent(CC_RUNTIME_CLASS(Spread));
00368             ENSURE(SelSpread != NULL, "Could not find spread of selected item"); 
00369 
00370             // Put the blobs back
00371             Camelot.GetBlobManager()->RenderOn(NULL, SelSpread);
00372         }
00373     }
00374 #endif
00375 
00376     m_bStartCalled = FALSE;
00377     return TRUE; 
00378 }

BOOL SelOperation::DoStartSelOp BOOL  renderEndSelStateBlobs,
BOOL  renderStartSelBlobs = TRUE,
BOOL  UndorenderEndSelStateBlobs = FALSE,
BOOL  UndorenderStartSelBlobs = FALSE
 

This function must be called by all SelOperations. It does the following:.

Author:
Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
Date:
15/2/94
Parameters:
RenderEndSelStateBlobs,: Flag indicating if the blobs should be drawn for [INPUTS] the end selection state or not.
This flag should be set to TRUE if the bounds of all selected objects at the end of the operation are not invalidated.

RenderStartSelBlobs: Flag indicating if the blobs should be drawn for the start selection state or not.

This flag should be set to TRUE if the bounds of all selected objects at the start of an operation are not invalidated.

All operations which insert a new object into the tree will have RenderStartSelBlobs set to TRUE.

Parameters:
- [OUTPUTS]
Returns:
TRUE if successful, FALSE if memory ran out (call End)
Records the current selection status

Returns:
Errors: -
See also:
SelOperation::End()

Definition at line 201 of file selop.cpp.

00205 {
00206     SelOperation::RenderStartSelStateBlobs = renderStartSelBlobs;
00207     SelOperation::RenderEndSelStateBlobs = renderEndSelStateBlobs; 
00208 
00209     if (UndorenderEndSelStateBlobs)
00210         SelOperation::UndoRenderEndSelStateBlobs = !renderEndSelStateBlobs; 
00211     else
00212         SelOperation::UndoRenderEndSelStateBlobs = renderEndSelStateBlobs; 
00213 
00214     if (UndorenderStartSelBlobs)
00215         SelOperation::UndoRenderStartSelStateBlobs = !renderStartSelBlobs; 
00216     else
00217         SelOperation::UndoRenderStartSelStateBlobs = renderStartSelBlobs; 
00218 
00219     // Create a SelectionState object
00220     ALLOC_WITH_FAIL(SelState, (new SelectionState()), this); 
00221     if (SelState == NULL)
00222     {
00223         return FALSE; // Failure 
00224     }
00225 
00226     // We have managed to create a SelectionState instance, now lets try and 
00227     // record the current selections 
00228 
00229     BOOL Success; 
00230     
00231     CALL_WITH_FAIL(SelState->Record(), this, Success)
00232 
00233     if (!Success)  // We failed to allocate enough memory to store the selection state
00234     {
00235         // There was insufficient memory to record the selections 
00236         delete SelState;            // Delete the selection state 
00237         SelState = NULL; 
00238         return FALSE; 
00239     }
00240     
00241     // We have successfully managed to create a Selection state, create an action 
00242     // to restore the selections when executed 
00243 
00244     // Recorded the current selection state ok
00245     RestoreSelectionsAction* RestoreAct;  
00246     ActionCode ActCode;  
00247 
00248     // Attempt to initialise the action    
00249     ActCode = RestoreSelectionsAction::Init(this,                    
00250                                             &UndoActions,  
00251                                             SelState, 
00252                                             FALSE,                      // Don't Toggle
00253                                             FALSE,       
00254                                             FALSE,                      // The SelState is not shared   
00255                                             UndoRenderStartSelStateBlobs,   // Render the start blobs ?
00256                                             UndoRenderEndSelStateBlobs,     // Render the end blobs ?
00257                                             FALSE,                      // End restore              
00258                                             ( Action**)(&RestoreAct)); 
00259     
00260     
00261 #if !defined(EXCLUDE_FROM_RALPH)
00262     if (RenderEndSelStateBlobs)
00263     {
00264         // Remove all existing blobs
00265         ENSURE(Camelot.FindSelection() != NULL, "There is no SelRange");
00266         Node* SelNd = Camelot.FindSelection()->FindFirst();
00267         if (SelNd != NULL)
00268         {
00269             Spread* SelSpread = (Spread*) SelNd->FindParent(CC_RUNTIME_CLASS(Spread));
00270             ENSURE(SelSpread != NULL, "Could not find spread of selected item"); 
00271 
00272             // Remove the blobs
00273             Camelot.GetBlobManager()->RenderOff(NULL, SelSpread);
00274         }
00275     }
00276 #endif
00277 
00278     if (ActCode == AC_FAIL)
00279     {
00280         delete SelState; // We won't be needing this 
00281         return FALSE;  
00282     } 
00283     m_bStartCalled = TRUE;
00284     return TRUE; 
00285 }

void SelOperation::End  )  [virtual]
 

Calls DoEndSelOp(), then Operation::End().

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

Errors: -

See also:
-

Reimplemented from Operation.

Reimplemented in OpAsynchClipartImport.

Definition at line 398 of file selop.cpp.

00399 {
00400     if (OpStatus == DO && (!OpFlags.Failed))
00401     {
00402         DoEndSelOp();      // We don't want to perform this if we are undoing or 
00403     }
00404     Operation::End(); 
00405 }

virtual BOOL SelOperation::GetStarted  )  const [inline, virtual]
 

Reimplemented from UndoableOperation.

Definition at line 139 of file selop.h.

00139 { return m_bStartCalled; }

BOOL SelOperation::InvalidateNodeRegion SelOperation pOp,
NodeRenderableBounded CurrentNode,
NodeAttribute Attrib,
BOOL  Mutate
[static]
 

Definition at line 1092 of file attrappl.cpp.

01096 {
01097     // Include the blobs, if the attribute will change the parents bounds.
01098     BOOL IncludeBlobs = Attrib->EffectsParentBounds();
01099 
01100     if ( (Mutate && !Attrib->IsAValueChange()) ||
01101          Attrib->GetRuntimeClass() == CC_RUNTIME_CLASS(AttrBitmapDpiChange) )
01102     {
01103         // Check for special cases of, either a mutate from one fill type to another,
01104         // or a dpi change.  Both of these can change the blob bounds.
01105         IncludeBlobs = TRUE;
01106     }
01107 
01108     // Invalidate the bounds of the node, including the blobs if necessary.
01109     if (pOp)
01110     {
01111         if (!pOp->DoInvalidateNodeRegion(CurrentNode, IncludeBlobs, FALSE, FALSE, FALSE))   // NOTE! We do not release cached info!
01112                                                                                         // Must be used in conjunction with ApplyToSelection
01113         {
01114             // Summit went wrong.
01115             return FALSE;
01116         }
01117     }
01118     else
01119     {
01120         BaseDocument* pBaseDoc = CurrentNode->FindOwnerDoc();
01121         if (pBaseDoc && pBaseDoc->IsKindOf(CC_RUNTIME_CLASS(Document)))
01122         {
01123             Document* pDoc = (Document*)pBaseDoc;
01124             Spread* pSpread = (Spread*)CurrentNode->FindParent(CC_RUNTIME_CLASS(Spread));
01125             DocRect TempRect; 
01126             TempRect = (IncludeBlobs ? 
01127                             (CurrentNode->GetUnionBlobBoundingRect()):
01128                             (CurrentNode->GetBoundingRect())
01129                          );
01130             TempRect = TempRect.Union(CurrentNode->GetEffectStackBounds());
01131             pDoc->ForceRedraw(pSpread, TempRect, TRUE, CurrentNode, FALSE);
01132         }
01133     }
01134 
01135     return TRUE;    // All ok
01136 }

virtual BOOL SelOperation::MayChangeNodeBounds  )  const [inline, virtual]
 

Reimplemented from UndoableOperation.

Reimplemented in OpCopy, OpGroup, OpMenuImport, OpDroppedFile, OpConvertToBitmap, OpMakeStroke, OpMenuLoad, OpBreakAtPoints, OpOverprintLine, OpOverprintFill, OpPrintOnAllPlates, OpBreakShapes, OpPutToBack, OpMoveForwards, OpMoveBackwards, OpMoveToLyrInFront, OpMoveToLyrBehind, OpCombineLayersToFrameLayer, OpChangeBlendSteps, OpApplyClipView, OpRemoveClipView, OpCreateContour, OpRemoveContour, OpChangeContourSteps, OpChangeContourColourType, OpChangeContourAttributeProfile, OpChangeContourObjectProfile, OpChangeContourStepDistance, OpConvertPathToShapes, OpToggleContourInsetPath, OpApplyLiveEffect, OpApplyFeatherEffect, OpEditLiveEffect, OpDeleteLiveEffect, OpDeleteAllLiveEffect, OpEffectRes, OpEffectLock, and OpEffectLockAll.

Definition at line 137 of file selop.h.

00137 { return TRUE; }

BOOL SelOperation::ReleaseCachedForAttrApply NodeRenderableBounded pNode,
BOOL  bEffectRootOnly
[static]
 

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!

Author:
Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
Date:
08/03/2005
Parameters:
pCurrentNode - the node that the attribute is being applied to [INPUTS] bEffectRootOnly - TRUE if
Returns:
TRUE if all ok.

Errors: -

See also:
-

Definition at line 737 of file attrappl.cpp.

00738 {
00739     if (bEffectRootOnly)
00740         pNode->ReleaseCached(TRUE, FALSE, FALSE, TRUE);                     // Parents and Derived data only
00741     else
00742         pNode->ReleaseCached();                                             // Self, Parents, Children and derived data
00743 
00744     return TRUE;
00745 }


Member Data Documentation

BOOL SelOperation::m_bStartCalled [private]
 

Definition at line 195 of file selop.h.

BOOL SelOperation::RenderEndSelStateBlobs [static, private]
 

Definition at line 199 of file selop.h.

BOOL SelOperation::RenderStartSelStateBlobs [static, private]
 

Definition at line 200 of file selop.h.

SelectionState* SelOperation::SelState [private]
 

Definition at line 191 of file selop.h.

BOOL SelOperation::UndoRenderEndSelStateBlobs [static, private]
 

Definition at line 201 of file selop.h.

BOOL SelOperation::UndoRenderStartSelStateBlobs [static, private]
 

Definition at line 202 of file selop.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 04:00:51 2007 for Camelot by  doxygen 1.4.4