effects_stack.cpp

Go to the documentation of this file.
00001 // $Id: effects_stack.cpp 859 2006-04-22 15:42:02Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 //
00099 // Implementation of Effects Stack.
00100 //
00101 
00102 #include "camtypes.h"           // pre-compiled header
00103 #include "effects_stack.h"
00104 
00105 #include "nodeliveeffect.h"
00106 #include "opliveeffects.h"
00107 
00108 // dynamic class creation stuff.
00109 CC_IMPLEMENT_DYNAMIC(PPStackLevel, ListItem);
00110 CC_IMPLEMENT_DYNAMIC(EffectsStack, List);
00111 
00112 DECLARE_SOURCE("$Revision: 859 $");
00113 
00114 #define new CAM_DEBUG_NEW
00115 
00116 
00117 
00118 
00120 // The EffectsStack class                                                                    //
00122 
00123 /********************************************************************************************
00124 
00125 >   EffectsStack::EffectsStack()
00126 
00127     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00128     Created:    17/11/2004
00129     Purpose:    Constructor.
00130     Errors:     
00131     See also:   
00132 
00133 ********************************************************************************************/
00134 EffectsStack::EffectsStack()
00135 {
00136     bConsistent = FALSE;
00137     m_pNewLevelRange = NULL;
00138 }
00139 
00140 
00141 
00142 /********************************************************************************************
00143 
00144 >   EffectsStack::~EffectsStack()
00145 
00146     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00147     Created:    17/11/2004
00148     Purpose:    Destructor.
00149     Errors:     
00150     See also:   
00151 
00152 ********************************************************************************************/
00153 EffectsStack::~EffectsStack()
00154 {
00155     // We own m_pNewLevelRange so we must delete it...
00156     if (m_pNewLevelRange)
00157     {
00158         delete m_pNewLevelRange;
00159         m_pNewLevelRange = NULL;
00160     }
00161 
00162     Clear();
00163 }
00164 
00165 
00166 
00167 /********************************************************************************************
00168 
00169 >   EffectsStack* EffectsStack::GetEffectsStackFromSelection(Range* pRange = NULL, BOOL bEscapeDerived = TRUE, BOOL bIncludeLocked = FALSE)
00170 
00171     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00172     Created:    05/10/2004
00173     Inputs:     -
00174     Outputs:    -
00175     Returns:    pStack - pointer to ListRange representing stack applied consistently to selection
00176     Purpose:    Get a list of LE nodes that are common to all selected nodes
00177                 Only returns a list of ALL the selected nodes have identical stacks
00178                 above them...
00179 
00180 ********************************************************************************************/
00181 
00182 EffectsStack* EffectsStack::GetEffectsStackFromSelection(Range* pRange, BOOL bEscapeDerived, BOOL bIncludeLocked)
00183 {
00184     // Loop through selection ensuring that all nodes are LiveEffects
00185     // and that they all share the same edit list
00186     if (pRange==NULL)
00187         pRange = GetApplication()->FindSelection();
00188     ENSURE(pRange, "!");
00189     ENSURE(pRange->GetRangeControlFlags().PromoteToParent==FALSE, "GetEffectsStackFromSel given a bad range");
00190 
00191     EffectsStack* pPPStack = new EffectsStack();        // New stack is marked as being "inconsistent"
00192     BOOL bStartNewStack = TRUE;
00193     ListRange* pLocalStack = NULL;
00194     BOOL bLiveEffectsAreApplied = FALSE;
00195 
00196     // Ensure that pEditedLE has a useful value...
00197     // Loop through the current selection and search the parents of each selected node for LiveEffects...
00198     Node* pNode = pRange->FindFirst();
00199     Node* pLastNode = NULL;
00200     while (pNode!=NULL)
00201     {
00202         if (pNode->IsAnObject())
00203         {
00204             // Don't try to add the same stack to the system more than once
00205             // (For instance NodeShadows and their originals are siblings and can both be selected
00206             //  below a NodeShadowController)
00207             if (!NodesSharePPStack(pNode, pLastNode, TRUE, bIncludeLocked))
00208             {
00209                 // Get the local stack
00210                 pLocalStack = GetEffectsStackFromNode(pNode, TRUE, bEscapeDerived, bIncludeLocked);     // If this node is in the middle of a stack, find the whole stack
00211 
00212                 if (pLocalStack)
00213                 {
00214                     bLiveEffectsAreApplied = TRUE;
00215 
00216                     if (bStartNewStack)
00217                     {
00218                         if (pPPStack->IsEmpty())
00219                         {
00220                             pPPStack->Initialise(pLocalStack);
00221                         }
00222                         else
00223                         {
00224                             BOOL bOK = pPPStack->Intersect(pLocalStack);
00225                             if (!bOK)
00226                             {
00227                                 delete pLocalStack;
00228                                 pPPStack->Clear();                      // Just to make sure!
00229                                 return pPPStack;
00230                             }
00231                         }
00232                     }
00233 
00234                     delete pLocalStack;
00235                 }
00236                 else
00237                 {
00238                     // A node in the selection doesn't have any LiveEffects applied but we can't stop
00239                     // because we have to keep scanning to see whether ANY nodes have LiveEffects
00240                     // Clear the effect stack out because this node has none.
00241                     pPPStack->Clear();
00242                     bStartNewStack = FALSE;
00243 
00244                     // Could test for lengthy scanning here and if it takes too long return <UNKNOWN>
00245                     // if (taking too long) code = SELTYPE_UNKNOWN;
00246                 }
00247             }
00248             pLastNode = pNode;
00249         }
00250 
00251         pNode = pRange->FindNext(pNode);
00252     }
00253 
00254     if (pPPStack->IsEmpty() && bLiveEffectsAreApplied)
00255         pPPStack->bConsistent = FALSE;
00256     else
00257         pPPStack->bConsistent = TRUE;
00258 
00259     return pPPStack;
00260 }
00261 
00262 
00263 
00264 
00265 /********************************************************************************************
00266 
00267 >   BOOL EffectsStack::Initialise(ListRange* pRange)
00268 
00269     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00270     Created:    18/10/2004
00271     Inputs:     
00272     Outputs:    
00273     Returns:    
00274     Purpose:
00275     Errors:     
00276     See also:   
00277 
00278 ********************************************************************************************/
00279 BOOL EffectsStack::Initialise(ListRange* pRange)
00280 {
00281     ENSURE(pRange, "EffectsStack::Initialise must be given a range");
00282 
00283     Node* pNode = pRange->FindFirst();
00284     while (pNode)
00285     {
00286         ENSURE(pNode->IsEffect(), "PostProcessor list contains non-PostProcessor in EffectsStack::Initialise");
00287         NodeEffect* pLE = (NodeEffect*)pNode;
00288 
00289         PPStackLevel* pNewItem = new PPStackLevel();
00290 
00291         pNewItem->pPPNode = pLE;
00292 
00293         pNewItem->listSelNodes.AddNode(pLE);
00294         pNewItem->strPostProID = pLE->GetPostProcessorID();
00295 
00296         AddTail(pNewItem);
00297 
00298         pNode = pRange->FindNext(pNode);
00299     }
00300 
00301     return TRUE;
00302 }
00303 
00304 
00305 
00306 
00307 /********************************************************************************************
00308 
00309 >   BOOL EffectsStack::Intersect(ListRange* pRange)
00310 
00311     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00312     Created:    18/10/2004
00313     Inputs:     pRange - A stack of LiveEffects above a node in the selection
00314     Outputs:    
00315     Returns:    
00316     Purpose:    Find whether the LE nodes in the presented range match those already in this
00317                 LE stack. Remove any mismatches from the PPStack, add new nodes to the
00318                 stack level lists.
00319     Errors:     
00320     See also:   
00321 
00322 ********************************************************************************************/
00323 BOOL EffectsStack::Intersect(ListRange* pRange)
00324 {
00325     ENSURE(pRange, "EffectsStack::Intersect must be given a range");
00326 
00327     Node* pNode = pRange->FindFirst();
00328     while (pNode)
00329     {
00330         ENSURE(pNode->IsEffect(), "PostProcessor list contains non-PostProcessor in EffectsStack::Intersect");
00331         NodeEffect* pLE = (NodeEffect*)pNode;
00332 
00333         PPStackLevel* pLastMatchItem = NULL;
00334         PPStackLevel* pFirstMatchItem = (PPStackLevel*)GetHead();
00335         NodeEffect* pStackSample;
00336         while (pFirstMatchItem!=NULL && pLastMatchItem==NULL)
00337         {
00338             pStackSample = pFirstMatchItem->pPPNode;
00339 
00340             pLastMatchItem = FindMatch(pFirstMatchItem, pRange, pLE);
00341             if (pLastMatchItem)
00342                 break;                                              // Stop as soon as we find a match!
00343 
00344             pFirstMatchItem = (PPStackLevel*)GetNext(pFirstMatchItem);
00345         }
00346 
00347         if (pLastMatchItem)
00348         {
00349             // ------------------------------------------------------------
00350             // We have a match so remove the stack levels that didn't match
00351             PPStackLevel* pItem = (PPStackLevel*)GetHead();
00352             while (pItem != pFirstMatchItem)
00353             {
00354                 PPStackLevel* pNextItem = (PPStackLevel*)GetNext(pItem);
00355 
00356                 RemoveItem(pItem);
00357 
00358                 pItem = pNextItem;
00359             }
00360 
00361             // ------------------------------------------------------------
00362             // Add the nodes that do match to the ListRanges in the levels
00363             do
00364             {
00365                 pItem->listSelNodes.AddNode(pLE);
00366 
00367                 pLE = (NodeEffect*)pRange->FindNext(pLE);
00368                 pItem = (PPStackLevel*)GetNext(pItem);
00369             }
00370             while (pItem!=NULL && pItem!=pLastMatchItem && pLE!=NULL);
00371 
00372             if (pItem!=NULL && pItem==pLastMatchItem && pLE!=NULL)
00373             {
00374                 pItem->listSelNodes.AddNode(pLE);
00375             }
00376 
00377             // ------------------------------------------------------------
00378             // Remove further levels that didn't match
00379             if (pItem)
00380             {
00381                 pItem = (PPStackLevel*)GetNext(pItem);
00382                 while (pItem != NULL)
00383                 {
00384                     PPStackLevel* pNextItem = (PPStackLevel*)GetNext(pItem);
00385 
00386                     RemoveItem(pItem);
00387 
00388                     pItem = pNextItem;
00389                 }
00390             }
00391 
00392             return TRUE;
00393         }
00394 
00395         pNode = pRange->FindNext(pNode);
00396     }
00397 
00398     Clear();
00399     return FALSE;
00400 }
00401 
00402 
00403 
00404 
00405 /********************************************************************************************
00406 
00407 >   BOOL EffectsStack::FindBestProcessor(String_256* pstrEffectID, INT32* piStackPos)
00408 
00409     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00410     Created:    20/10/2004
00411     Inputs:     
00412     Outputs:    
00413     Returns:    TRUE if an effect was found
00414                 FALSE otherwise
00415     Purpose:    Find the most appropriate effect in this effect stack mathcing the given
00416                 name and stack position.
00417     Errors:     
00418     See also:   
00419 
00420 ********************************************************************************************/
00421 BOOL EffectsStack::FindBestProcessor(String_256* pstrEffectID, INT32* piStackPos)
00422 {
00423     INT32 pos = *piStackPos;
00424     PPStackLevel* pLevel = NULL;
00425 
00426     // Search up from the last known stack position for an effect of the same name
00427     do
00428     {
00429         pLevel = (PPStackLevel*)FindItem(pos);
00430 
00431         if (pLevel && pLevel->strPostProID==*pstrEffectID)
00432         {
00433             *piStackPos = pos;
00434             return TRUE;
00435         }
00436 
00437         pos++;
00438     }
00439     while (pLevel);
00440 
00441     // Search down from the last known stack position for an effect of the same name
00442     pos = *piStackPos-1;
00443     do
00444     {
00445         pLevel = (PPStackLevel*)FindItem(pos);
00446 
00447         if (pLevel && pLevel->strPostProID==*pstrEffectID)
00448         {
00449             *piStackPos = pos;
00450             return TRUE;
00451         }
00452 
00453         pos--;
00454     }
00455     while (pLevel);
00456 
00457     return FALSE;
00458 }
00459 
00460 
00461 
00462 
00463 /********************************************************************************************
00464 
00465 >   BOOL EffectsStack::GetLevelInfo(String_256* pstrEffectID, INT32* piStackPos)
00466 
00467     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00468     Created:    08/11/2004
00469     Inputs:     
00470     Outputs:    
00471     Returns:    TRUE if an effect was found
00472                 FALSE otherwise
00473     Purpose:    Find the most appropriate effect in this effect stack mathcing the given
00474                 name and stack position.
00475     Errors:     
00476     See also:   
00477 
00478 ********************************************************************************************/
00479 BOOL EffectsStack::GetLevelInfo(String_256* pstrEffectID, INT32* piStackPos)
00480 {
00481     PPStackLevel* pLevel = NULL;
00482 
00483     if (*piStackPos>=STACKPOS_TOP)
00484         pLevel = (PPStackLevel*)GetTail();
00485     else
00486         pLevel = (PPStackLevel*)FindItem(*piStackPos);
00487 
00488     if (pLevel)
00489     {
00490         *piStackPos = (INT32) this->FindPosition(pLevel);
00491         *pstrEffectID = pLevel->strPostProID;
00492         return TRUE;
00493     }
00494 
00495     return FALSE;
00496 }
00497 
00498 
00499 
00500 
00501 /********************************************************************************************
00502 
00503 >   void EffectsStack::Clear()
00504 
00505     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00506     Created:    18/10/2004
00507     Inputs:     
00508     Outputs:    
00509     Returns:    
00510     Purpose:    
00511     Errors:     
00512     See also:   
00513 
00514 ********************************************************************************************/
00515 void EffectsStack::Clear()
00516 {
00517     // No match so clear out the Stack and return
00518     while (GetCount()!=0)
00519     {
00520         PPStackLevel* pItem = (PPStackLevel*)RemoveTail();
00521         delete pItem;
00522     }
00523 }
00524 
00525 
00526 
00527 
00528 /********************************************************************************************
00529 
00530 >   PPStackLevel* EffectsStack::FindMatch(PPStackLevel* pFirstItem, ListRange* pRange, NodeEffect* pPP)
00531 
00532     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00533     Created:    18/10/2004
00534     Inputs:     pRange - A stack of LiveEffects above a node in the selection
00535     Outputs:    
00536     Returns:    
00537     Purpose:    Find whether the LE nodes in the presented range match those already in this
00538                 LE stack. Remove any mismatches from the PPStack, add new nodes to the
00539                 stack level lists.
00540     Errors:     
00541     See also:   
00542 
00543 ********************************************************************************************/
00544 PPStackLevel* EffectsStack::FindMatch(PPStackLevel* pFirstItem, ListRange* pRange, NodeEffect* pPP)
00545 {
00546     PPStackLevel* pItem = pFirstItem;
00547     PPStackLevel* pLastMatchItem = NULL;
00548     BOOL bMatch = TRUE;
00549 //  HRESULT hr;
00550 
00551     do
00552     {
00553         bMatch = pPP->CompareState(pItem->pPPNode);         // Polymorphic compare for PostProcessors
00554         if (bMatch)
00555             pLastMatchItem = pItem;
00556 // Possible future change to detect inconsistent levels. But this would require changes elsewhere
00557 //      bMatch = (pPP->GetRuntimeClass() == pItem->pPPNode->GetRuntimeClass());
00558 //      if (pItem->bConsistent)
00559 //      {
00560 //          pItem->bConsistent = pPP->CompareState(pItem->pPPNode);
00561 //      }
00562 
00563         pPP = (NodeEffect*)pRange->FindNext(pPP);
00564         pItem = (PPStackLevel*)GetNext(pItem);
00565     }
00566     while (bMatch && pItem!=NULL && pPP);
00567 
00568     return pLastMatchItem;
00569 }
00570 
00571 
00572 
00573 
00574 /********************************************************************************************
00575 
00576 >   ListRange* EffectsStack::GetEffectsStackFromNode(Node* pNode, BOOL bNodeMaybeMidStack = FALSE, BOOL bEscapeDerived = TRUE, bIncludeLocked = FALSE)
00577 
00578     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00579     Created:    18/10/2004
00580     Inputs:     pNode - pointer to node in tree which may have a LiveEffect stack above it
00581     Outputs:    -
00582     Returns:    pPPStack    - NULL if <None>
00583                             - Empty if <Many>
00584                             - Populated if consistent stack (caller becomes owner of this list!)
00585     Purpose:    Get a list of LE nodes that are common to all selected nodes
00586                 Only returns a list of ALL the selected nodes have identical stacks
00587                 above them...
00588                 Does nothing about setting current stack pos or current effect name
00589     SeeAlso:    LiveEffectsTool::GetLEListFromSelAndStack
00590 
00591 ********************************************************************************************/
00592 
00593 ListRange* EffectsStack::GetEffectsStackFromNode(Node* pNode, BOOL bNodeMaybeMidStack, BOOL bEscapeDerived, BOOL bIncludeLocked)
00594 {
00595     // First, test whether node CAN be in a PPStack or stands aside from it
00596     // (E.g. shadows)
00597     //
00598     if (!bEscapeDerived && pNode->NeedsParent(pNode->FindParent()))
00599         return NULL;
00600 
00601     ListRange* pStack = new ListRange();
00602     Node* pUpNode = pNode;
00603 
00604     // If the node could be in the middle of a stack then we need to find the base
00605     // of the stack before we start our scan
00606     // (E.g. the node could be a selected Shadow node somewhere high above the
00607     //  object it applies to)
00608     if (bNodeMaybeMidStack)
00609     {
00610         pUpNode = FindStackBaseFrom(pUpNode, bIncludeLocked);
00611     }
00612 
00613     // Special case handling for old legacy effects until they become true
00614     // PostProcessors...
00615     // Search for Contour, Bevel, ClipView controllers above selected node
00616     // and if found, make them the base for PostProcessor scanning
00617     pUpNode = EscapeOldControllers(pUpNode);
00618 
00619     // Now go up the post processor stack, adding every one we find to the list
00620     do
00621     {
00622         if (pUpNode->IsEffect())
00623             pStack->AddNode(pUpNode);
00624 
00625         pUpNode = pUpNode->FindParent();
00626     }
00627     while (pUpNode && pUpNode->IsEffect());
00628 
00629     // Best to get rid of the list here if it's empty (don't trust caller)
00630     if (pStack->IsEmpty())
00631     {
00632         delete pStack;
00633         pStack = NULL;
00634     }
00635 
00636     return pStack;
00637 }
00638 
00639 
00640 
00641 
00642 /********************************************************************************************
00643 
00644 >   BOOL EffectsStack::NodesSharePPStack(Node* pNode, Node* pLastNode, BOOL bNodeMaybeMidStack = FALSE, BOOL bIncludeLocked = FALSE)
00645 
00646     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00647     Created:    16/11/2004
00648     Inputs:     pNode - pointer to node in tree which may have a LiveEffect stack above it
00649                 pLastNode - pointer to another node whicyh may have a LiveEffect stack
00650     Outputs:    -
00651     Returns:    TRUE if both nodes have the same stack above them
00652                 FALSE if the nodes have different stacks
00653     Purpose:    Find out whether two sibling nodes in the tree share the same stack
00654                 (So that we can avoid adding the same node stack to the combined stack
00655                  more than once)
00656     SeeAlso:    LiveEffectsTool::GetLEListFromSelAndStack
00657 
00658 ********************************************************************************************/
00659 
00660 BOOL EffectsStack::NodesSharePPStack(Node* pNode, Node* pLastNode, BOOL bNodeMaybeMidStack, BOOL bIncludeLocked)
00661 {
00662     if (pNode==NULL || pLastNode==NULL)
00663         return FALSE;
00664 
00665     if (bNodeMaybeMidStack)
00666     {
00667         // Find the true stack base for both these
00668         pNode = FindStackBaseFrom(pNode, bIncludeLocked);
00669         pLastNode = FindStackBaseFrom(pLastNode, bIncludeLocked);
00670     }
00671 
00672     // Special case handling for old legacy effects until they become true
00673     // PostProcessors...
00674     // Search for Contour, Bevel, ClipView controllers above selected node
00675     // and if found, make them the base for PostProcessor scanning
00676     pNode = EscapeOldControllers(pNode);
00677     pLastNode = EscapeOldControllers(pLastNode);
00678 
00679     if (!bIncludeLocked)
00680     {
00681         if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsLockedEffect())
00682             return FALSE;
00683 
00684         if (pLastNode->IsEffect() && ((NodeEffect*)pLastNode)->IsLockedEffect())
00685             return FALSE;
00686     }
00687 
00688     if (pNode->IsEffect() && !((NodeEffect*)pNode)->CanBeUnlocked())
00689         return FALSE;
00690 
00691     if (pLastNode->IsEffect() && !((NodeEffect*)pLastNode)->CanBeUnlocked())
00692         return FALSE;
00693 
00694     Node* pParent = pNode->FindParent();
00695     if (pParent==NULL)
00696         return FALSE;
00697 
00698     return (pParent == pLastNode->FindParent() && pParent->IsEffect());
00699 }
00700 
00701 
00702 
00703 
00704 /********************************************************************************************
00705 
00706 >   Node* EffectsStack::FindStackBaseFrom(Node* pNode, BOOL bIncludeLocked)
00707 
00708     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00709     Created:    25/11/2004
00710     Inputs:     pNode - pointer to node in tree which may have a LiveEffect stack above it
00711                         and below it!
00712     Outputs:    -
00713     Returns:    Pointer to node at the base of the stack containing the input node
00714     Purpose:    From the specified node, find the base of the local stack containing that
00715                 node
00716 
00717 ********************************************************************************************/
00718 
00719 Node* EffectsStack::FindStackBaseFrom(Node* pNode, BOOL bIncludeLocked)
00720 {
00721     Node* pStackNode = pNode;
00722 
00723     if (!pStackNode->IsEffect())
00724     {
00725         if (pStackNode->GetParentController())
00726             pStackNode = pStackNode->GetParentController();
00727     }
00728 
00729     while (pStackNode && pStackNode->IsEffect())
00730     {
00731         // Stop immediately if we find a destructive post pro - the user cannot be
00732         // allowed to see or manipulate anything underneath one of those...
00733         if (!bIncludeLocked && ((NodeEffect*)pStackNode)->IsLockedEffect())
00734             break;
00735 
00736         if (!((NodeEffect*)pStackNode)->CanBeUnlocked())
00737             break;
00738 
00739         pStackNode = ((NodeEffect*)pStackNode)->GetInkNodeFromController();
00740     }
00741 
00742     return pStackNode;
00743 }
00744 
00745         
00746         
00747         
00748 /********************************************************************************************
00749 
00750 >   Node* EffectsStack::EscapeOldControllers(Node* pUserNode)
00751 
00752     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00753     Created:    29/11/2004
00754     Inputs:     pNode - pointer to node in tree which may have a LiveEffect stack above it
00755     Outputs:    -
00756     Returns:    Node* - pointer to node above presented node which is an old style
00757                 non-postprocessor controller node
00758     Purpose:    Find the node which PostProcessors should be wrapped around, taking
00759                 old style Controller nodes into account.
00760 
00761 ********************************************************************************************/
00762 Node* EffectsStack::EscapeOldControllers(Node* pUserNode)
00763 {
00764     Node* pTestNode = pUserNode->FindParent();
00765     while (pTestNode && pTestNode->IsController() && !pTestNode->IsEffect())
00766     {
00767         pUserNode = pTestNode;
00768         pTestNode = pTestNode->FindParent();
00769     }
00770 
00771     return pUserNode;
00772 }
00773 
00774     
00775     
00776     
00777 /********************************************************************************************
00778 
00779 >   BOOL EffectsStack::LockableNonEmpty()
00780 
00781     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00782     Created:    18/10/2004
00783     Inputs:     pNode - pointer to node in tree which may have a LiveEffect stack above it
00784     Outputs:    -
00785     Returns:    TRUE if stack has some lockable effects layers
00786                 FALSE if no levels or any level contains an unlockable effect
00787     Purpose:    Determine whether stack is empty or has destructive effects in it
00788     SeeAlso:    LiveEffectsTool::GetLEListFromSelAndStack
00789 
00790 ********************************************************************************************/
00791 
00792 BOOL EffectsStack::LockableNonEmpty()
00793 {
00794     if (IsEmpty())
00795         return FALSE;
00796 
00797     PPStackLevel* pItem = (PPStackLevel*)GetHead();
00798     NodeEffect* pLENode;
00799     while (pItem!=NULL)
00800     {
00801         pLENode = pItem->pPPNode;
00802         ENSURE(pLENode, "PPStackLevel node pointer is NULL in LockableNonEmpty");
00803 
00804         if (!pLENode->CanBeUnlocked())
00805             return FALSE;
00806 
00807         pItem = (PPStackLevel*)GetNext(pItem);
00808     }
00809 
00810     return TRUE;
00811 }
00812 
00813 
00814 
00815 
00816 /********************************************************************************************
00817 
00818 >   ListRange* EffectsStack::GetLevelRange(INT32* piStackPos, BOOL bEscapeOldControllers = TRUE)
00819 
00820     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00821     Created:    29/09/2004
00822     Inputs:     iStackPos - position in LiveEffect stack to find nodes
00823                             0 means first stack pos above selection
00824     Outputs:    
00825     Returns:    A pointer to a list range owned by the EffectsStack - i.e. you don't have to 
00826                 delete it when you're finished.
00827     Purpose:    
00828     Errors:     
00829     See also:   
00830 
00831 ********************************************************************************************/
00832 ListRange* EffectsStack::GetLevelRange(INT32* piStackPos, BOOL bEscapeOldControllers)
00833 {
00834     ENSURE(*piStackPos>=0, "Invalid stack pos in GetLevelRange!");
00835 
00836     // If the stack is inconsistent then we need to make a range of nodes that arch
00837     // over the selection and any stacked PostProcessors that might be on them
00838     // In this case we expect our caller to not have specified a valid stack position
00839     if (!bConsistent || IsEmpty() || *piStackPos>=STACKPOS_TOP)
00840     {
00841         ENSURE(*piStackPos>=STACKPOS_TOP, "Incorrect attempt to insert into an inconsistent PostPro stack");
00842 
00843         // By definition, if someone had previously requested a new level range
00844         // during the lifetime of this effects stack then the same range must
00845         // still apply (otherwise the EffectsStack would have been destroyed).
00846         // So just return the range we already found...
00847         if (m_pNewLevelRange)
00848         {
00849             return m_pNewLevelRange;
00850 //          delete m_pNewLevelRange;
00851 //          m_pNewLevelRange = NULL;
00852         }
00853 
00854         m_pNewLevelRange = GetNewLevelRange(NULL, bEscapeOldControllers);           // We own this listrange, so we can delete it later
00855 
00856         // Return new stack pos; correct number for consistent stack, INVALID for inconsistent stack
00857         if (bConsistent)
00858             *piStackPos = ((INT32)GetCount())-1;
00859         else
00860             *piStackPos = STACKPOS_INVALID;
00861 
00862         return m_pNewLevelRange;
00863     }
00864 
00865     // This is the typical case: Adding/Inserting to a consistent stack
00866     if (*piStackPos>=(INT32)GetCount())
00867         *piStackPos = ((INT32)GetCount())-1;
00868 
00869     PPStackLevel* pLevel = (PPStackLevel*)FindItem(*piStackPos);
00870     ENSURE(pLevel, "Argh something's got out of line!");
00871     ListRange* pLERange = &pLevel->listSelNodes;
00872 
00873     return pLERange;                                        // The EffectsStack owns this listrange
00874 }
00875 
00876 
00877 
00878 
00879 /********************************************************************************************
00880 
00881 >   void EffectsStack::AttrsHaveChanged()
00882 
00883     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00884     Created:    01/10/2005
00885     Inputs:     -
00886     Outputs:    -
00887     Returns:    -
00888     Purpose:    Tell any stored ranges that any cahced attr data trhey have is now out
00889                 of date
00890 
00891 ********************************************************************************************/
00892 
00893 void EffectsStack::AttrsHaveChanged()
00894 {
00895     if (m_pNewLevelRange)
00896     {
00897         m_pNewLevelRange->AttrsHaveChanged();
00898     }
00899 }
00900 
00901 
00902 
00903 
00904 /********************************************************************************************
00905 
00906 >   static ListRange* EffectsStack::GetNewLevelRange(Range* pRange, BOOL bEscapeOldControllers = TRUE)
00907 
00908     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00909     Created:    26/10/2004
00910     Inputs:     -
00911     Outputs:    
00912     Returns:    A pointer to a list range owned by you!
00913     Purpose:    Get a range of nodes forming a surface above the selection and above
00914                 any live effects applied to the selection
00915     Errors:     
00916     See also:   
00917 
00918 ********************************************************************************************/
00919 ListRange* EffectsStack::GetNewLevelRange(Range* pRange, BOOL bEscapeOldControllers)
00920 {
00921     // Loop through selection ensuring that all nodes are LiveEffects
00922     // and that they all share the same edit list
00923     if (pRange==NULL)
00924         pRange = GetApplication()->FindSelection();
00925     ENSURE(pRange, "No selection in GetNewLevelRange!");
00926 
00927     // We want to apply the LiveEffect to the entire selection, however inconsistent it is
00928     //
00929     // Loop through the current selection and search the parents of each selected node for LiveEffects...
00930     ListRange* pLERange = new ListRange();
00931     Node* pNode = pRange->FindFirst();
00932     INT32 pos = 0;
00933     while (pNode!=NULL)
00934     {
00935         NodeEffect* pFirstEditedLE = NULL;
00936         Node* pBaseNode = pNode;
00937 
00938         // Only traverse the effect stack if the selected node is 'in' the effect stack
00939         // (it could be offset, e.g. NodeShadow)
00940         if (!pNode->NeedsParent(pNode->FindParent()))
00941         {
00942             if (bEscapeOldControllers)
00943                 pBaseNode = EscapeOldControllers(pNode);
00944 
00945             Node* pUpNode = pBaseNode;
00946 
00947             pos = 0;
00948             do
00949             {
00950                 pUpNode = pUpNode->FindParent();
00951 
00952                 if (pUpNode && pUpNode->IsEffect())
00953                     pFirstEditedLE = (NodeEffect*)pUpNode;
00954 
00955                 pos++;
00956             }
00957             while (pUpNode && pUpNode->IsEffect());
00958         }
00959 
00960         if (pFirstEditedLE)
00961         {
00962             pLERange->AddNode(pFirstEditedLE);
00963         }
00964         else
00965         {
00966             pLERange->AddNode(pBaseNode);
00967         }
00968 
00969         pNode = pRange->FindNext(pNode);
00970     }
00971 
00972     return pLERange;
00973 }
00974 
00975 
00976 
00977 
00978 /********************************************************************************************
00979 
00980 >   static ListRange* EffectsStack::GetTopClassRange(CCRuntimeClass* pClass,
00981                                                         BOOL bClassOnly = TRUE,
00982                                                         BOOL bIgnorePassThroughEffects = FALSE
00983                                                         Node** pMasterNode = NULL,
00984                                                         INT32* piStackPos = NULL,
00985                                                         Range* pRange = NULL,
00986                                                         BOOL bEscapeOldControllers = TRUE
00987                                                         )
00988 
00989     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00990     Created:    11/05/2005
00991     Inputs:     pClass      - pointer to class of node to find in effects stack
00992                 bClassOnly  - Only allow nodes of the specified class to be added to the list
00993                 pRange      - pointer to range of nodes to scan
00994                 bEscapeConts- TRUE if old controller nodes should be escaped
00995     Outputs:    pMasterNode - pointer to one example of this class of node in the returned range
00996                 piStackPos  - pointer to stack pos INT32
00997     Returns:    A pointer to a list range owned by you!
00998     Purpose:    Get a range of nodes forming a surface above the selection and within
00999                 any live effects applied to the selection consisting of all effect nodes of type
01000                 "class" applied to the selection
01001     Errors:     
01002 
01003 ********************************************************************************************/
01004 ListRange* EffectsStack::GetTopClassRange(CCRuntimeClass* pClass,
01005                                              BOOL bClassOnly,
01006                                              BOOL bIgnorePassThroughEffects,
01007                                              Node** ppMasterNode,
01008                                              INT32* piStackPos,
01009                                              Range* pRange,
01010                                              BOOL bEscapeOldControllers
01011                                              )
01012 {
01013     // Loop through selection ensuring that all nodes are LiveEffects
01014     // and that they all share the same edit list
01015     if (pRange==NULL)
01016         pRange = GetApplication()->FindSelection();
01017     ENSURE(pRange, "No selection in GetClassRange!");
01018 
01019     if (ppMasterNode)
01020         *ppMasterNode = NULL;
01021 
01022     // We want to apply the LiveEffect to the entire selection, however inconsistent it is
01023     //
01024     // Loop through the current selection and search the parents of each selected node for LiveEffects...
01025     ListRange* pLERange = new ListRange();
01026     Node* pNode = pRange->FindFirst();
01027     INT32 pos = 0;
01028     while (pNode!=NULL)
01029     {
01030         NodeEffect* pFirstEditedLE = NULL;
01031         NodeEffect* pFirstEditedEffectClass = NULL;
01032         Node* pBaseNode = pNode;
01033 
01034         // Only traverse the effect stack if the selected node is 'in' the effect stack
01035         // (it could be offset/derived, e.g. NodeShadow)
01036 // In this context we know that we always want to go up effects stacks whether the selected node
01037 // is mainstream or derived...
01038 //      if (!pNode->NeedsParent(pNode->FindParent()))
01039 //      {
01040             if (bEscapeOldControllers)
01041                 pBaseNode = EscapeOldControllers(pNode);
01042 
01043             Node* pUpNode = pBaseNode;
01044 
01045             pos = 0;
01046             do
01047             {
01048                 pUpNode = pUpNode->FindParent();
01049 
01050                 if (pUpNode && pUpNode->IsEffect())
01051 //                  if (!(bIgnorePassThroughEffects && ((NodeEffect*)pUpNode)->IsPassThroughEffect()))
01052 //  The meaning of the bIgnorePassThroughEffects has changed to mean "ignore all effects"
01053                     if (!bIgnorePassThroughEffects)
01054                         pFirstEditedLE = (NodeEffect*)pUpNode;
01055 
01056                 if (pUpNode && pUpNode->IsEffect() && pUpNode->GetRuntimeClass() == pClass)
01057                 {
01058                     pFirstEditedEffectClass = (NodeEffect*)pUpNode;
01059 //                  iClassPos = pos;
01060                 }
01061 
01062                 pos++;
01063             }
01064             while (pUpNode && pUpNode->IsEffect());
01065 //      }
01066 
01067         // Decide what effect node should be added to the listrange for this node in the input range
01068         // Add a node of the specified class if we found one
01069         if (pFirstEditedEffectClass)
01070         {
01071             pLERange->AddNode(pFirstEditedEffectClass);
01072 
01073             if (ppMasterNode && *ppMasterNode==NULL)
01074                 *ppMasterNode = pFirstEditedEffectClass;
01075         }
01076         // Add the last effect if effects were found
01077         else if (!bClassOnly)
01078         {
01079             if (pFirstEditedLE)
01080             {
01081                 pLERange->AddNode(pFirstEditedLE);
01082             }
01083             // Add the input node itself if no effects were found
01084             else
01085             {
01086                 pLERange->AddNode(pBaseNode);
01087             }
01088         }
01089 
01090         pNode = pRange->FindNext(pNode);
01091     }
01092 
01093     // Temp hack
01094     if (piStackPos)
01095         *piStackPos = STACKPOS_INVALID;
01096 
01097     return pLERange;
01098 }
01099 
01100 
01101 
01102 
01103 /********************************************************************************************
01104 
01105 >   ListRange* EffectsStack::GetBaseLevelRange()
01106 
01107     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01108     Created:    03/12/2004
01109     Inputs:     -
01110     Outputs:    
01111     Returns:    A pointer to a list range owned by you!
01112     Purpose:    Get a range of nodes forming a surface above the selection and BELOW
01113                 any live effects applied to the selection!
01114                 (Used by legacy effects like Bevel, Contour)
01115     Errors:     
01116     See also:   
01117 
01118 ********************************************************************************************/
01119 ListRange* EffectsStack::GetBaseLevelRange()
01120 {
01121     // Loop through selection ensuring that all nodes are LiveEffects
01122     // and that they all share the same edit list
01123     Range* pRange = GetApplication()->FindSelection();
01124     ENSURE(pRange, "No selection in GetNewLevelRange!");
01125 
01126     // We want to apply the LiveEffect to the entire selection, underneath any PostProcessors
01127     //
01128     // Loop through the current selection and search the parents of each selected node
01129     ListRange* pLERange = new ListRange();
01130     Node* pNode = pRange->FindFirst();
01131 //  INT32 pos = 0;
01132     while (pNode!=NULL)
01133     {
01134         Node* pEscNode = pNode;
01135 
01136         // Only traverse the effect stack if the selected node is 'in' the effect stack
01137         // (it could be offset, e.g. NodeShadow)
01138         if (!pNode->NeedsParent(pNode->FindParent()))
01139             pEscNode = EscapeOldControllers(pNode);
01140 
01141         pLERange->AddNode(pEscNode);
01142 
01143         pNode = pRange->FindNext(pNode);
01144     }
01145 
01146     return pLERange;
01147 }
01148 
01149 
01150 
01151 
01152 /********************************************************************************************
01153 
01154 >   ListRange* EffectsStack::FindLevelContaining(NodeEffect* pNode, INT32* piStackPos)
01155 
01156     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01157     Created:    18/11/2004
01158     Inputs:     pNode - Pointer to node to search for
01159     Outputs:    -
01160     Returns:    A pointer to a list range owned by the PostProcessor stack describing
01161                 the layer of consistent nodes in the stack of which Node was a member
01162                 NULL if couldn't find node in stack
01163     Purpose:    Find a given node in the post processor stack
01164     Errors:     
01165     See also:   
01166 
01167 ********************************************************************************************/
01168 ListRange* EffectsStack::FindLevelContaining(NodeEffect* pNode, INT32* piStackPos)
01169 {
01170     *piStackPos = STACKPOS_TOP;
01171     if (IsEmpty())
01172         return NULL;
01173 
01174     PPStackLevel* pItem = (PPStackLevel*)GetHead();
01175     *piStackPos = 0;
01176     while (pItem!=NULL)
01177     {
01178         Node* pTestNode = pItem->listSelNodes.FindFirst();
01179         while (pTestNode)
01180         {
01181             if (pNode==pTestNode)
01182                 return &pItem->listSelNodes;
01183 
01184             pTestNode = pItem->listSelNodes.FindNext(pTestNode);
01185         }
01186 
01187         (*piStackPos)++;
01188         pItem = (PPStackLevel*)GetNext(pItem);
01189     }
01190 
01191     *piStackPos = STACKPOS_TOP;
01192     return NULL;
01193 }
01194 
01195 
01196 
01197 
01198 /********************************************************************************************
01199 
01200 >   BOOL EffectsStack::NodeInTopLevel(NodeEffect* pNode)
01201 
01202     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01203     Created:    22/11/2004
01204     Inputs:     pNode - Pointer to node to search for
01205     Outputs:    -
01206     Returns:    TRUE if the node is in the top level of the stack
01207                 FALSE otherwise
01208     Purpose:    Find a given node in the post processor stack
01209     Errors:     
01210     See also:   
01211 
01212 ********************************************************************************************/
01213 BOOL EffectsStack::NodeInTopLevel(NodeEffect* pNode)
01214 {
01215     if (IsEmpty())
01216         return TRUE;
01217 
01218     PPStackLevel* pItem = (PPStackLevel*)GetTail();
01219     Node* pTestNode = pItem->listSelNodes.FindFirst();
01220     while (pTestNode)
01221     {
01222         if (pNode==pTestNode)
01223             return TRUE;
01224 
01225         pTestNode = pItem->listSelNodes.FindNext(pTestNode);
01226     }
01227 
01228     return FALSE;
01229 }
01230 
01231 
01232 
01233 
01234 /********************************************************************************************
01235 
01236 >   INT32 EffectsStack::FindSelectionPos()
01237 
01238     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01239     Created:    25/11/2004
01240     Inputs:     -
01241     Outputs:    -
01242     Returns:    The stack position of the selection or -1
01243     Purpose:    Find whether the selection has a consistent level INT32 he stack other
01244                 than the usual base level, -1
01245     Errors:     
01246     See also:   
01247 
01248 ********************************************************************************************/
01249 INT32 EffectsStack::FindSelectionPos()
01250 {
01251     INT32 Pos = -1;
01252 
01253     Range* pRange = GetApplication()->FindSelection();
01254     ENSURE(pRange, "!");
01255     ENSURE(pRange->GetRangeControlFlags().PromoteToParent==FALSE, "GetEffectsStackFromSel given a bad range");
01256 
01257     PPStackLevel* pFoundLevel = NULL;
01258     Node* pNode = pRange->FindFirst();
01259     while (pNode)
01260     {
01261         Node* pStackNode = pNode->GetParentController();
01262         if (pStackNode==NULL)
01263             return -1;
01264 
01265         if (pFoundLevel==NULL)
01266         {
01267             PPStackLevel* pItem = (PPStackLevel*)GetHead();
01268             Pos = 0;
01269             while (pItem!=NULL && pFoundLevel==NULL)
01270             {
01271                 Node* pTestNode = pItem->listSelNodes.FindFirst();
01272                 while (pTestNode && pTestNode!=pStackNode)
01273                 {
01274                     pTestNode = pItem->listSelNodes.FindNext(pTestNode);
01275                 }
01276 
01277                 if (pTestNode==pStackNode)
01278                 {
01279                     pFoundLevel = pItem;
01280                     break;
01281                 }
01282 
01283                 Pos++;
01284                 pItem = (PPStackLevel*)GetNext(pItem);
01285             }
01286 
01287             if (pFoundLevel==NULL)
01288                 return -1;
01289         }
01290         else
01291         {
01292             // Just look in the level we have already identified...
01293             Node* pTestNode = pFoundLevel->listSelNodes.FindFirst();
01294             while (pTestNode && pTestNode!=pStackNode)
01295             {
01296                 pTestNode = pFoundLevel->listSelNodes.FindNext(pTestNode);
01297             }
01298 
01299             if (pTestNode!=pStackNode)
01300             {
01301                 return -1;
01302             }
01303         }
01304 
01305         pNode = pRange->FindNext(pNode);
01306     }
01307 
01308     return Pos;
01309 }
01310 
01311 
01312 
01313 
01314 /********************************************************************************************
01315 
01316 >   BOOL EffectsStack::BuildEffectMenu(ContextMenu* pMenu)
01317 
01318     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01319     Created:    22/06/2005
01320     Inputs:     pMenu - Pointer to ContextMenu we should add items to
01321     Outputs:    -
01322     Returns:    TRUE if everything is OK
01323                 FALSE if something went wrong enough to require caller to stop building menus
01324     Purpose:    Find whether the selection has a consistent level INT32 he stack other
01325                 than the usual base level, -1
01326     Errors:     
01327     See also:   
01328 
01329 ********************************************************************************************/
01330 BOOL EffectsStack::BuildEffectMenu(ContextMenu* pMenu)
01331 {
01332 PORTNOTE("menu", "BuildEffectMenu can't do anything until we have XPEHost::GetEffectDetails or equivalent");
01333 #ifndef EXCLUDE_FROM_XARALX
01334     PPStackLevel* pItem = (PPStackLevel*)GetHead();
01335 //  PPStackLevel* pNextItem = NULL;
01336     INT32 pos = 0;
01337 
01338     pMenu->BuildCommand(OPTOKEN_EDITEFFECTS);
01339     MenuItem* pRootItem = pMenu->GetLastItem();
01340 
01341     while (pItem!=NULL)
01342     {
01343 //      pNextItem = (PPStackLevel*)GetNext(pItem);
01344 
01345         String_64 strDisplayName;
01346         BOOL bDestructive = FALSE;
01347         XPEHost::GetEffectDetails(pItem->strPostProID, &strDisplayName, &bDestructive);
01348         OpLiveEffectParam* pParam = new OpLiveEffectParam();
01349         if (pParam==NULL)
01350             return FALSE;
01351 
01352         pParam->strOpUnique = pItem->strPostProID;
01353         pParam->bIsDestructive = bDestructive;
01354         pParam->StackPosition = pos;
01355         pParam->pPPStack = this;
01356 
01357         if (pItem->strPostProID==String_256(POSTPRO_ID_SHADOW))
01358             pMenu->BuildCommand(OPTOKEN_EDIT_LEGACYEFFECT, FALSE, pRootItem, strDisplayName, pParam);
01359 
01360         else if (pItem->strPostProID==String_256(POSTPRO_ID_FEATHER))
01361             pMenu->BuildCommand(OPTOKEN_EDIT_LEGACYEFFECT, FALSE, pRootItem, strDisplayName, pParam);
01362 
01363         else
01364             pMenu->BuildCommand(OPTOKEN_EDIT_LIVEEFFECT, FALSE, pRootItem, strDisplayName, pParam);
01365 
01366         pItem = (PPStackLevel*)GetNext(pItem);
01367         pos++;
01368     }
01369 
01370 #endif
01371     return TRUE;
01372 }
01373 
01374 
01375 
01376 

Generated on Sat Nov 10 03:45:05 2007 for Camelot by  doxygen 1.4.4