opfeathr.cpp

Go to the documentation of this file.
00001 // $Id: opfeathr.cpp 1526 2006-07-25 13:32:07Z 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 #include "camtypes.h" 
00100 
00101 #include "opfeathr.h"
00102 #include "fthrattr.h"
00103 //#include "undoop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 
00106 //#include "resource.h" 
00107 //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "simon.h"
00109 //#include "assoc.h"
00110 #include "bubbleid.h"
00111 //#include "mario.h"
00112 //#include "barsdlgs.h"
00113 //#include "feather.h"
00114 #include "nodedoc.h"        // IS_KIND_OF(NodeDocument)
00115 //#include "rikdlg.h"           // _R(IDB_SLIDERBASE), _R(IDB_SLIDERSLIDER)
00116 //#include "biasres.h"
00117 #include "biasdlg.h"
00118 #include "objchge.h"        // ObjChange and AllowOp stuff
00119 
00120 #include "optsmsgs.h"       // OptionsChangingMsg
00121 
00122 //#include "bars.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "grndrgn.h"
00124 
00125 // not supported yet
00126 #include "nodebev.h"
00127 #include "nodeshad.h"
00128 #include "nbevcont.h"
00129 #include "nodecntr.h"
00130 #include "ncntrcnt.h"
00131 #include "nodetext.h"
00132 #include "selector.h"       // for class SelectorTool
00133 #include "opbevel.h"
00134 #include "offscrn.h"
00135 #include "opliveeffects.h"
00136 #include "nodeliveeffect.h"
00137 
00138 CC_IMPLEMENT_DYNCREATE(OpChangeFeatherSize, UndoableOperation)
00139 CC_IMPLEMENT_DYNCREATE(OpChangeFeatherProfile, UndoableOperation)
00140 CC_IMPLEMENT_DYNCREATE(ChangeFeatherProfileAction, Action)
00141 #ifdef FEATHER_EFFECT
00142 CC_IMPLEMENT_DYNCREATE(ChangeFeatherEffectProfileAction, Action)
00143 CC_IMPLEMENT_DYNCREATE(ChangeFeatherEffectAction, Action)
00144 #endif
00145 CC_IMPLEMENT_DYNCREATE(RegenerateFeatherContourAction, Action)
00146 CC_IMPLEMENT_DYNAMIC(OpChangeFeatherSizeParam, OpParam)
00147 CC_IMPLEMENT_DYNAMIC(FeatherProfileOpParam, OpParam)
00148 CC_IMPLEMENT_DYNAMIC(ChangeFeatherSizeSliderOpDesc, UndoableOpDescriptor)
00149 CC_IMPLEMENT_DYNAMIC(ChangeFeatherProfileOpDesc, UndoableOpDescriptor)
00150 
00151 #define new CAM_DEBUG_NEW
00152 
00153 CBiasGainGadget     ChangeFeatherProfileOpDesc::m_BiasGainGadget;
00154 
00155 const MILLIPOINT    MaxFeatherSize = ((const MILLIPOINT)(MAX_FEATHERSIZE_MP));
00156 const MILLIPOINT    ChangeFeatherSizeSliderOpDesc::MinSlider = 0;
00157 const MILLIPOINT    ChangeFeatherSizeSliderOpDesc::MaxSlider = ((const MILLIPOINT) (MaxFeatherSize / 2 ));
00158 const double        ChangeFeatherSizeSliderOpDesc::SliderChangeRate = 1.5;
00159 
00160 INT32               OpChangeFeatherSize::s_iEditStackPos = STACKPOS_INVALID;
00161 ListRange*          OpChangeFeatherSize::s_pEditRange = NULL;
00162 BOOL                OpChangeFeatherSize::s_DisableUpdates = FALSE;
00163 
00164 
00166 //                                      Changing feather size
00168 
00169 ChangeFeatherSizeSliderOpDesc::ChangeFeatherSizeSliderOpDesc(
00170                             UINT32 toolID,                    // Tool (Module) Identifier
00171                             UINT32 txID,                      // String Resource ID
00172                             CCRuntimeClass* Op,             // pointer to the Op's runtime class object
00173                             TCHAR* tok,                     // pointer to the token string
00174                             pfnGetState gs,                 // pointer to the GetState function
00175                             UINT32 helpId,              // help identifier 
00176                             UINT32 bubbleID,                // string resource for bubble help
00177                             UINT32 resourceID,          // resource ID
00178                             UINT32 controlID,               // control ID within resource
00179                             BOOL ReceiveMessages,       
00180                             BOOL Smart, 
00181                             BOOL Clean,
00182                             UINT32 AutoStateFlags
00183                            )
00184     : UndoableOpDescriptor(toolID, txID, Op, tok, gs, helpId, bubbleID, 
00185                          resourceID, controlID, ReceiveMessages, Smart,
00186                          Clean, 0, AutoStateFlags )
00187 {
00188     m_pOpChangeFeatherSize = NULL;
00189 }
00190 
00191 /********************************************************************************************
00192 
00193 >   void ChangeFeatherSizeSliderOpDesc::OnControlCreate(OpDescControlCreateMsg* CreateMsg)
00194 
00195     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00196     Created:    14/3/2000
00197 
00198     Purpose:    This function is called when the feathering bar is about to be shown.
00199                 This function gets pointers to all of the the controls within the bar
00200                 (after an indirect fashion) and stores these.  These pointers can then be
00201                 used within the other feathering OpDescs' to gain direct access ....
00202 
00203 ********************************************************************************************/
00204 
00205 void ChangeFeatherSizeSliderOpDesc::OnControlCreate(OpDescControlCreateMsg* CreateMsg)
00206 {
00207     DialogOp* pDlg = CreateMsg->pDlgOp;
00208     CGadgetID GadgetID = CreateMsg->SetGadgetID;
00209 
00210     BOOL IsHorizontal = TRUE;
00211     if  (pDlg->IsKindOf(CC_RUNTIME_CLASS(DialogBarOp)))
00212             IsHorizontal = ((DialogBarOp *) pDlg)->IsHorizontal();
00213     pDlg->SetGadgetRange (GadgetID, MinSlider, MaxSlider);
00214     if(IsHorizontal)
00215         pDlg->SetGadgetBitmaps (GadgetID, _R(IDB_QUALITYBASE), _R(IDB_QUALITYSLIDER));
00216     else
00217         pDlg->SetGadgetBitmaps (GadgetID, _R(IDB_QUALITYBASEVERT), _R(IDB_QUALITYSLIDERVERT));
00218 
00219     SetFeatherSizeForCurrentSel();
00220 }
00221 
00222 /********************************************************************************************
00223 >   MsgResult ChangeFeatherSizeSliderOpDesc::Message(Msg* Msg)
00224     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
00225     Created:    5/4/2000
00226 
00227     Purpose:    Needed to override this in order to respond to OpMsg messages
00228                 (ie to update ui controls when undo of any of the feather ops occurs)
00229 ********************************************************************************************/
00230 MsgResult ChangeFeatherSizeSliderOpDesc::Message(Msg* pMessage)
00231 {
00232     if (MESSAGE_IS_A(pMessage, OpMsg))
00233     {
00234         /*
00235         BEGIN,          // An operation is about to be performed
00236         END,            // An operation has successfully ended
00237         BEFORE_UNDO,    // Sent prior to the operation being undone
00238         AFTER_UNDO,     // Sent after the operation has been undone
00239         BEFORE_REDO,    // Sent prior to the operation being redone
00240         AFTER_REDO      // Sent after the operation has been redone
00241         */
00242 
00243         OpMsg* pMsg = (OpMsg*) pMessage;
00244         switch (pMsg->MsgType)
00245         {
00246             case OpMsg::AFTER_UNDO:
00247             case OpMsg::AFTER_REDO:
00248                 if( /*pMsg->pOp->IS_KIND_OF(OpFeather) ||
00249                     pMsg->pOp->IS_KIND_OF(OpUnFeather) ||*/
00250                     pMsg->pOp->IS_KIND_OF(OpChangeFeatherSize) )
00251                 {
00252                     SetFeatherSizeForCurrentSel();
00253                 }
00254                 break;
00255             default:
00256                 break;
00257         }
00258     }
00259     
00260     return UndoableOpDescriptor::Message(pMessage);
00261 }
00262 
00263 /********************************************************************************************
00264 >   BOOL ChangeFeatherSizeSliderOpDesc::OnCommonAttrsChangedMsg()
00265     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
00266     Created:    5/4/2000
00267 
00268     Purpose:    Updating UI controls in response to selection changes
00269 ********************************************************************************************/
00270 BOOL ChangeFeatherSizeSliderOpDesc::OnCommonAttrsChangedMsg()
00271 {
00272     // Not sure if sel changes from one feathered object to another will register
00273     // an attr change
00274     // Using this in place of OnSelChangingMsg (same as OpLineWidthOpDesc)
00275     return SetFeatherSizeForCurrentSel();
00276 }
00277 
00278 
00279 
00280 BOOL ChangeFeatherSizeSliderOpDesc::OnOptionsChangingMsg(OptionsChangingMsg* Msg)
00281 {
00282     OptionsChangingMsg *OpsChangeMsg = (OptionsChangingMsg *) Msg;
00283     if( OpsChangeMsg->State == OptionsChangingMsg::NEWUNITS)
00284     {
00285         // ensure we don't have a cached feather
00286         SelRange* pSelRange = GetApplication()->FindSelection();
00287         if (pSelRange != NULL)
00288             pSelRange->AttrsHaveChanged();
00289 
00290         return SetFeatherSizeForCurrentSel();
00291     }
00292 
00293     return TRUE;
00294 }
00295 
00296 
00297 
00298 BOOL ChangeFeatherSizeSliderOpDesc::OnSelChangingMsg(SelChangingMsg::SelectionState State)
00299 {
00300     // if nodes have been added/removed from the selection, then ensure that
00301     // we abort any drag currently in progress.
00302     // to prevent responding to messages sent from SlideFinished(), copy the ptr first.
00303 //  if (State == SelChangingMsg::SelectionState::SELECTIONCHANGED)
00304 //  {
00305 //      if (m_pOpChangeFeatherSize != NULL)
00306 //      {
00307 //          OpChangeFeatherSize* pOp = m_pOpChangeFeatherSize;
00308 //          m_pOpChangeFeatherSize = NULL;
00309 //          pOp->SlideFinished(FALSE);
00310 //      }
00311 //  }
00312 
00313 
00314     return TRUE;
00315 }
00316 
00317 
00318 // update the feather controls when the selection changes.
00319 BOOL ChangeFeatherSizeSliderOpDesc::SetFeatherSizeForCurrentSel()
00320 {
00321     MILLIPOINT  MpFeather = 0;
00322     String_256  StrFeather("");
00323     SelRange::CommonAttribResult Result = Range::ATTR_NONE;
00324     AttrFeather* pAttr = NULL;
00325 
00326     if (Document::GetSelected() != NULL) 
00327     {
00328         // If we have a specific context within which we should be operating
00329         // use that
00330         Range* pLevelRange = OpChangeFeatherSize::GetEditContext();
00331         if (pLevelRange==NULL)
00332         {
00333             // If not, go get a context from the current selection
00334             SelRange* pSelRange = GetApplication()->FindSelection();
00335             pLevelRange = pSelRange->GetTopClassRange(CC_RUNTIME_CLASS(NodeFeatherEffect), FALSE, TRUE);
00336         }
00337 
00338         if (pLevelRange)
00339         {
00340             Node* pNode = pLevelRange->FindFirst();
00341             while (pNode)
00342             {
00343                 if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsFeatherEffect())
00344                 {
00345                     NodeFeatherEffect* pEffect = (NodeFeatherEffect*)pNode;
00346                     if (Result==Range::ATTR_COMMON && pEffect->GetFeatherSize() != MpFeather)
00347                     {
00348                         Result = Range::ATTR_MANY;
00349                         break;
00350                     }
00351 
00352                     if (Result==Range::ATTR_NONE && pEffect->GetFeatherSize() != 0)
00353                     {
00354                         Result = Range::ATTR_COMMON;
00355                         MpFeather = pEffect->GetFeatherSize();
00356                     }
00357                 }
00358                 else
00359                 if (pNode->IsAnObject())    // sanity check.
00360                 {
00361                     pAttr = (AttrFeather*)pNode->FindFirstChild(CC_RUNTIME_CLASS(AttrFeather));
00362                     if (pAttr)
00363                     {
00364                         if (Result==Range::ATTR_COMMON && pAttr->Value.GetFeatherSize() != MpFeather)
00365                         {
00366                             Result = Range::ATTR_MANY;
00367                             break;
00368                         }
00369 
00370                         if (Result==Range::ATTR_NONE && pAttr->Value.GetFeatherSize() != 0)
00371                         {
00372                             Result = Range::ATTR_COMMON;
00373                             MpFeather = pAttr->Value.GetFeatherSize();
00374                         }
00375                     }
00376                 }
00377 
00378                 pNode = pLevelRange->FindNext(pNode);
00379             }
00380         }
00381 
00382         // -------------------------------------------------
00383         // Show the user the result
00384         switch (Result)
00385         {
00386             case Range::ATTR_COMMON:
00387                 ConvertSizeToUnits(StrFeather, MpFeather);
00388                 break;
00389 
00390             case Range::ATTR_NONE:
00391                 MpFeather   = 0;
00392                 StrFeather  = String_256(_R(IDS_NONE));
00393                 break;
00394 
00395             case Range::ATTR_MANY:
00396                 MpFeather   = 0;
00397                 StrFeather  = String_256(_R(IDS_MANY));
00398                 break;
00399         }
00400     }
00401 
00402     // Set the string in all gadgets associated with the OpDescriptor
00403     return UpdateAllFeatherControls(&StrFeather, MpFeather);
00404 }
00405 
00406 
00407 
00408 /********************************************************************************************
00409 
00410 >   BOOL ChangeFeatherSizeSliderOpDesc::UpdateAllFeatherControls(String_256* Str,
00411                                                                 MILLIPOINT InverseSliderVal)
00412     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> (tidied up and header'ed)
00413     Created:    24 August 2000
00414     Inputs:     Str                 string value to insert into the edit control.
00415                 InverseSliderVal    value used to set the slider bar.
00416 
00417     Returns:    FALSE if nothing went wrong,
00418                 TRUE otherwise.
00419 
00420     Purpose:    Update all feather UI controls.
00421                 Str == NULL or InverseSliderVal < 0 are valid inputs - they just do nothing.
00422 
00423     Errors:     ERROR3 with FALSE if InverseSliderVal > MaxSlider.
00424 
00425     Notes:      Note that the cc_CustomEdit control may get updated TWICE - once for the
00426                 edit text value and again for the slider position. This is because the
00427                 control does not understand the mapping between the two, or have access
00428                 to the selection to determine that "Many" objects are selected.
00429 
00430 ********************************************************************************************/
00431 BOOL ChangeFeatherSizeSliderOpDesc::UpdateAllFeatherControls(String_256* Str,
00432                                                             MILLIPOINT InverseSliderVal)
00433 {
00434     // Don't update controls if we have update disabled
00435     if (OpChangeFeatherSize::IsUpdateDisabled())
00436         return TRUE;
00437 
00438     // Create a list for the dialogue manager to put gadget ID's on.
00439     List* pGadgetList = new List;
00440     if (pGadgetList == NULL)
00441     {
00442         InformError(_R(IDE_NOMORE_MEMORY));
00443         return FALSE;
00444     }
00445 
00446     if (BuildGadgetList(pGadgetList))
00447     {
00448         GadgetListItem* GadgetItem;
00449 
00450         for (GadgetItem = (GadgetListItem*) pGadgetList->GetHead(); 
00451              GadgetItem != 0; 
00452              GadgetItem = (GadgetListItem*) pGadgetList->GetNext(GadgetItem))
00453         {
00454             UINT32      GadgetID = GadgetItem->gidGadgetID;
00455             DialogOp*   pDlg     = GadgetItem->pDialogOp;
00456 
00457             if (Str != NULL)
00458                 pDlg->SetStringGadgetValue(GadgetID, *Str, FALSE, -1);
00459 
00460             // set the position of a cc_Slider or the slider component of a cc_CustomEdit...
00461 TRACEUSER("amb", _T("UpdateAllFeatherContrls: Set slider to %d in [%d .. %d]"), InverseSliderVal, MinSlider, MaxSlider);
00462             SetSliderValue(InverseSliderVal, pDlg, GadgetID);
00463         }
00464     }
00465 
00466     pGadgetList->DeleteAll();
00467     delete pGadgetList;
00468 
00469     return TRUE;
00470 }
00471 
00472 
00473 
00474 /********************************************************************************************
00475 
00476 >   INT32 ChangeFeatherSizeSliderOpDesc::GetSliderValue(DialogOp* pDlg, CGadgetID SliderID)
00477 
00478     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00479     Created:    26 September 2000
00480     Inputs:     pDlg        required to access the slider control.
00481                 SliderID    the ID of the slider control.
00482 
00483     Returns:    The feather value to use in millipoints, derived from the slider's value, or
00484                 -1 if unsuccessful.
00485 
00486 ********************************************************************************************/
00487 INT32 ChangeFeatherSizeSliderOpDesc::GetSliderValue(DialogOp* pDlg, CGadgetID SliderID)
00488 {
00489     BOOL Valid;
00490     INT32 SliderVal = pDlg->GetLongGadgetValue(SliderID, MinSlider, MaxSlider, 0, &Valid);
00491 
00492     if (!Valid)
00493         return -1;
00494 
00495     SliderVal = (INT32)(MaxSlider * pow(SliderVal / (double)MaxSlider, SliderChangeRate));
00496 
00497     return SliderVal;
00498 }
00499 
00500 
00501 
00502 /********************************************************************************************
00503 
00504 >   void ChangeFeatherSizeSliderOpDesc::SetSliderValue( INT32 SliderVal,
00505                                                         DialogOp* pDlg, CGadgetID SliderID  )
00506     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00507     Created:    26 September 2000
00508     Inputs:     SliderVal   the feather value in millipoints to set the slider for.
00509                 pDlg        required to access the slider control.
00510                 GadgetID    the ID of the slider control.
00511 
00512     Outputs:    The feather slider is set so that it represents the given feather size.
00513 
00514 ********************************************************************************************/
00515 void ChangeFeatherSizeSliderOpDesc::SetSliderValue( INT32 SliderVal,
00516                                                     DialogOp* pDlg, CGadgetID SliderID  )
00517 {
00518     static const double InverseChangeRate = 1 / SliderChangeRate;
00519 
00520     if (SliderVal < 0)
00521         return;
00522 
00523     SliderVal = (INT32)(MaxSlider * pow(SliderVal / (double)MaxSlider, InverseChangeRate));
00524     pDlg->SetLongGadgetValue(SliderID, SliderVal);
00525 }
00526 
00527 
00528 
00529 
00530 /********************************************************************************************
00531 
00532 >   void ChangeFeatherSizeSliderOpDesc::ConvertSizeToUnits(String_256& StrSize, MILLIPOINT size)
00533 
00534     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00535     Created:    24 August 2000
00536     Inputs:     strSize     the text string to receive the converted value.
00537                 size        the value to convert.
00538 
00539     Purpose:    Convert the given value to appropriate units, returning the result as a text
00540                 string.
00541 
00542     Errors:     ERROR3 if anything goes wrong.
00543 
00544 ********************************************************************************************/
00545 void ChangeFeatherSizeSliderOpDesc::ConvertSizeToUnits(String_256& StrSize, MILLIPOINT size)
00546 {
00547     Spread*     pSpread     = NULL;
00548     DimScale*   pDimScale   = NULL;
00549     Document*   pDoc = Document::GetSelected();
00550     if (pDoc != NULL)
00551     {
00552         pSpread = pDoc->GetSelectedSpread();
00553         if (pSpread != NULL)
00554         {
00555             pDimScale = DimScale::GetPtrDimScale(pSpread);
00556             if (pDimScale != NULL)
00557             {
00558                 pDimScale->ConvertToUnits(size, &StrSize);
00559             }
00560         }
00561     }
00562 
00563     ERROR3IF(pDimScale == NULL,
00564             "ChangeFeatherSizeSliderOpDesc::ConvertSizeToUnits; error during method setup!");
00565 }
00566 
00567 
00568 
00569 /********************************************************************************************
00570 
00571 >   void ChangeFeatherSizeSliderOpDesc::OnSelectionChange(  OpDescControlMsg* SelChangedMsg,
00572                                                             List* GadgetList )
00573 
00574     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00575     Created:    14/3/2000
00576 
00577     Purpose:    This function is called when the feather size edit box (which is
00578                 'linked' to ChangeFeatherSizeSliderOpDesc) value is changed by the user.  It
00579                 reads the new value from the edit box, and sets our slider accordingly.
00580                 The edit box/slider will be reset to their previous values if the new value
00581                 is not valid.
00582 
00583 ********************************************************************************************/
00584 
00585 void ChangeFeatherSizeSliderOpDesc::OnSelectionChange(OpDescControlMsg* SelChangedMsg, List* GadgetList)
00586 {
00587     DialogOp* pDlg = SelChangedMsg->pDlgOp;
00588     CGadgetID SetGadgetID = SelChangedMsg->SetGadgetID;
00589 
00590     BOOL bSuccess;
00591     MILLIPOINT Result = pDlg->GetUnitGadgetValue(SetGadgetID, PIXELS, MinSlider, MaxFeatherSize,
00592                                                 0, &bSuccess);
00593 
00594     if (bSuccess)
00595     {
00596         MILLIPOINT mp = (Result > MaxSlider) ? MaxSlider : Result;
00597         OpChangeFeatherSize* pOp = new OpChangeFeatherSize();
00598         if (pOp != NULL)
00599         {
00600             OpChangeFeatherSizeParam param(mp, OpChangeFeatherSize::GetEditContext());
00601             pOp->DoWithParam(NULL, &param);
00602             pOp->DoSlide(mp);
00603             pOp->SlideFinished();
00604             UpdateAllFeatherControls((String_256*)NULL, mp);
00605         }
00606 
00607         else
00608             bSuccess = FALSE;
00609     }
00610 
00611     if (!bSuccess)
00612         SetFeatherSizeForCurrentSel();
00613 }
00614 
00615 /********************************************************************************************
00616 
00617 >   void ChangeFeatherSizeSliderOpDesc::OnSliderSet(OpDescControlMsg* SelChangedMsg,
00618                                                     List* GadgetList)
00619 
00620     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00621     Created:    14/3/2000
00622 
00623     Purpose:    This function is called when the user stops dragging the feather size slider.
00624                 It finishes of the resize-feather operation which was started when the user
00625                 began dragging the slider.
00626 
00627 ********************************************************************************************/
00628 
00629 void ChangeFeatherSizeSliderOpDesc::OnSliderSet(OpDescControlMsg* SelChangedMsg)
00630 {
00631     // we can't tell our op to tidy itself up if it doesn't exist.
00632     if (m_pOpChangeFeatherSize == NULL)
00633         return;
00634 
00635     // tell our op to finish changing the sizes.
00636     // to stop ourselves responding to any messages sent from SlideFinished,
00637     // use a copied ptr to our Op to call it.
00638     OpChangeFeatherSize* pOp = m_pOpChangeFeatherSize;
00639     m_pOpChangeFeatherSize = NULL;
00640     pOp->SlideFinished();
00641 
00642     // reinitialise ourself, ready for the next slide.
00643     LastOnscreenPixelSize = -1;
00644 }
00645 
00646 /********************************************************************************************
00647 
00648 >   void ChangeFeatherSizeSliderOpDesc::OnSliderChanging(OpDescControlMsg* SliderChangingMsg)
00649 
00650     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00651     Created:    15/3/2000
00652 
00653     Purpose:    This function is called when the feather size slider (which is
00654                 'linked' to ChangeFeatherSizeSliderOpDesc) value is changed by the user.
00655                 It reads the new value from the slider, and sets our edit box accordingly.
00656 
00657 ********************************************************************************************/
00658 
00659 void ChangeFeatherSizeSliderOpDesc::OnSliderChanging(OpDescControlMsg* SliderChangingMsg)
00660 {
00661     DialogOp* pDlg = SliderChangingMsg->pDlgOp;
00662     CGadgetID SetGadgetID = SliderChangingMsg->SetGadgetID;
00663     INT32 Result = GetSliderValue(pDlg, SetGadgetID);
00664     if (Result < 0)
00665         return;
00666 
00667     const double dpi = (double)GRenderRegion::GetDefaultDPI();
00668     const double MillipointsPerPixel = (dpi <= 0) ? 750.0 : MILLIPOINTS_PER_INCH / dpi;
00669 
00670     MILLIPOINT mp = Result;
00671 
00672     double  fOnscreenPix = (mp / MillipointsPerPixel);
00673             fOnscreenPix *= GetCurrentViewScale().MakeDouble();
00674 
00675     if (fOnscreenPix > 1)
00676         mp = ConvertMeasurementToMillipointsAtCurrentViewScale((INT32)(fOnscreenPix + 0.5), PIXELS);
00677 
00678 //  if (OnscreenPix == LastOnscreenPixelSize)
00679     if (mp == LastOnscreenPixelSize)
00680         return;
00681 
00682     // if we haven't already started a size change, then do so.
00683     if (m_pOpChangeFeatherSize == NULL)
00684     {
00685         m_pOpChangeFeatherSize = new OpChangeFeatherSize;
00686         if (m_pOpChangeFeatherSize != NULL)
00687         {
00688             OpChangeFeatherSizeParam param(mp, OpChangeFeatherSize::GetEditContext());
00689             m_pOpChangeFeatherSize->DoWithParam(NULL, &param);
00690         }
00691         else
00692             return;
00693     }
00694 
00695     // ok, we're currently in the middle of a slide,
00696     // so pass our slide information over to our op.
00697 //  MILLIPOINT mp = ConvertMeasurementToMillipointsAtCurrentViewScale(OnscreenPix, PIXELS);
00698     m_pOpChangeFeatherSize->DoSlide(mp);
00699 
00700     // update our last pixel size.
00701 //  LastOnscreenPixelSize = OnscreenPix;
00702     LastOnscreenPixelSize = mp;
00703 
00704     // update all the feather controls.
00705     String_256 Str;
00706     ConvertSizeToUnits(Str, mp);
00707     UpdateAllFeatherControls(&Str, mp);
00708 }
00709 
00710 /********************************************************************************************
00711 
00712 >   void ChangeFeatherSizeSliderOpDesc::OnSliderCancelled(OpDescControlMsg* SliderChangingMsg)
00713 
00714     Author:     Marc_Power (Xara Group Ltd) <camelotdev@xara.com>
00715     Created:    04/11/2005
00716 
00717     Purpose:    This function is called when the feather size slider (which is
00718                 'linked' to ChangeFeatherSizeSliderOpDesc) is cancelled by the user.
00719 
00720 ********************************************************************************************/
00721 
00722 void ChangeFeatherSizeSliderOpDesc::OnSliderCancelled(OpDescControlMsg* SliderChangingMsg)
00723 {
00724     // to prevent responding to messages sent from SlideFinished(), copy the ptr first.
00725     if (m_pOpChangeFeatherSize != NULL)
00726     {
00727         OpChangeFeatherSize* pOp = m_pOpChangeFeatherSize;
00728         m_pOpChangeFeatherSize = NULL;
00729         pOp->SlideFinished(FALSE);
00730         SetFeatherSizeForCurrentSel();
00731     }
00732 }
00733 
00735 
00736 BOOL OpChangeFeatherSize::Init()
00737 {
00738     OpDescriptor* OpDesc = new ChangeFeatherSizeSliderOpDesc(0,
00739                                              _R(IDS_FEATHERSIZEOP),
00740                                              CC_RUNTIME_CLASS(OpChangeFeatherSize),
00741                                              OPTOKEN_FEATHERSIZE,
00742                                              OpChangeFeatherSize::GetState,         // NB Operations GetState
00743                                              0,
00744                                              _R(IDBBL_FEATHERSIZEOP),
00745                                              SYSTEMBAR_FEATHER,
00746                                              _R(IDC_FEATHERSIZE_CUSTOMEDIT),
00747                                              TRUE,
00748                                              FALSE,
00749                                              FALSE,
00750                                              (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION | DONT_GREY_WHEN_SELECT_INSIDE ) );
00751 
00752     ERROR2IF(!OpDesc, FALSE, _R(IDE_NOMORE_MEMORY));
00753 
00754     return TRUE;
00755 }
00756 
00757 
00758 
00759 
00760 /********************************************************************************************
00761 >   BOOL OpChangeFeatherSize::DeInit()
00762 
00763     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00764     Created:    09/08/2005
00765     Purpose:    Deallocate anything grabbed in Init or grabbed statically
00766 ********************************************************************************************/
00767 
00768 BOOL OpChangeFeatherSize::DeInit()
00769 {
00770     if (s_pEditRange)
00771     {
00772         delete s_pEditRange;
00773         s_pEditRange = NULL;
00774     }
00775 
00776     return TRUE;
00777 }
00778 
00779 
00780 
00781 
00782 OpState OpChangeFeatherSize::GetState(String_256* Description, OpDescriptor*)
00783 {
00784     // Always enabled.
00785     // Wherever a feather attr can't be applied we can apply a feather effect...
00786 
00787     OpState OpSt;
00788 
00789     OpSt.Greyed = FALSE;
00790 
00791     return OpSt;
00792 }
00793 
00794 
00795 
00796 
00797 /********************************************************************************************
00798 
00799 >   static void     OpChangeFeatherSize::SetEditContext(INT32 iStackPos = STACKPOS_INVALID, ListRange* pEditRange = NULL)
00800 
00801     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00802     Created:    10/05/2005
00803     Inputs:     iStackPos   - stack level index
00804                 pEditRange  - list of nodes in that stack level
00805     Purpose:    Tell the feather UI that it must edit a specific set of feather nodes - not
00806                 find it's own set from the selection.
00807     See also:   DoSlide(), SlideFinished().
00808 
00809 ********************************************************************************************/
00810 void OpChangeFeatherSize::SetEditContext(INT32 iStackPos, ListRange* pEditRange)
00811 {
00812     if (s_pEditRange && s_pEditRange != pEditRange)
00813     {
00814         delete s_pEditRange;
00815         s_pEditRange = NULL;
00816     }
00817 
00818     s_iEditStackPos = iStackPos;
00819     if (pEditRange)
00820         s_pEditRange = new ListRange(pEditRange);
00821     else
00822         s_pEditRange = NULL;
00823 
00824     s_DisableUpdates = TRUE; // Disable updates to the slider triggered from this as we haven't set the new
00825                              // feather attribute so we risk setting it back and causing jumpiness
00826     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED));
00827     s_DisableUpdates = FALSE;
00828 }
00829 
00830 
00831 
00832 
00833 /********************************************************************************************
00834 
00835 >   ListRange* OpChangeFeatherSize::GetEditContext()
00836 
00837     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00838     Created:    10/05/2005
00839     Inputs:     -
00840     Outputs:    -
00841     Returns:    Pointer to range 
00842     Purpose:    Get the current edit context for the feather UI controls
00843     See also:   DoSlide(), SlideFinished().
00844 
00845 ********************************************************************************************/
00846 ListRange* OpChangeFeatherSize::GetEditContext()
00847 {
00848     if (s_iEditStackPos==STACKPOS_INVALID || s_pEditRange==NULL)
00849         return NULL;
00850 
00851     if (s_pEditRange->MatchesSelectionEffectLevel(s_iEditStackPos))
00852         return s_pEditRange;
00853 
00854     return NULL;
00855 }
00856 
00857 
00858 
00859 
00860 /********************************************************************************************
00861 
00862 >   void OpChangeFeatherSize::DoWithParam(OpDescriptor*, OpParam*)
00863 
00864     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00865     Created:    24/08/2000
00866 
00867     Inputs:     This method's parameters are unused.
00868 
00869     Purpose:    Called to initiate this action.
00870                 Starts the process of resizing/applying feathers to the selection.
00871 
00872     Notes:      This method works in tandem with DoSlide() and SlideFinished().
00873                 You must always call SlideFinished() at some point after calling this method.
00874                 To perform any useful function, you should also call DoSlide() at least
00875                 once in between this method and SlideFinished().
00876 
00877     See also:   DoSlide(), SlideFinished().
00878 
00879 ********************************************************************************************/
00880 void OpChangeFeatherSize::DoWithParam(OpDescriptor* pOpDesc, OpParam* pParam)
00881 {
00883     // What we do:
00884     //  For all AllowOp()'d nodes in the selection:
00885     //      1. Undoably hide any existing feather attribute.
00886     //      2. Apply a new feather attribute with default settings or same as the old attr,
00887     //      3. adding it to a list of feather attrs to update.
00888     //
00889     BOOL bAddNewFeathers = TRUE;
00890     MILLIPOINT size = 0;
00891     ListRange* pLevelRange = NULL;
00892     ListRange* pLocalRange = NULL;
00893     BOOL bGotSelRange = FALSE;
00894     if (pParam && IS_A(pParam, OpChangeFeatherSizeParam))
00895     {
00896         OpChangeFeatherSizeParam* pCFSParam = (OpChangeFeatherSizeParam*)pParam;
00897         bAddNewFeathers = pCFSParam->bAddNewFeathers;
00898         size = pCFSParam->size;
00899         pLevelRange = pCFSParam->pLevelRange;
00900     }
00901 
00902     ObjChangeFlags cFlags;
00903     cFlags.Attribute = TRUE;
00904 
00905     SelRange* pSelRange = GetApplication()->FindSelection();
00906     pSelRange->MakePartialSelectionWhole(FALSE, TRUE);
00907 
00908     // Since the selection may change during this Op we must get a permanent copy of
00909     // the PostProcessor stack
00910 //  INT32 iStackPos = STACKPOS_TOP;
00911 //  EffectsStack* pStack = pSelRange->GetEffectsStack(TRUE, TRUE);
00912 //  ListRange* pLevelRange = pStack->GetLevelRange(&iStackPos);
00913 
00914     // Since the selection may change during this Op we must get a permanent copy of
00915     // the level range we are working on
00916     if (pLevelRange==NULL)
00917     {
00918         SelRange* pSelRange = GetApplication()->FindSelection();
00919         pLevelRange = pSelRange->GetTopClassRange(CC_RUNTIME_CLASS(NodeFeatherEffect), FALSE, TRUE);
00920         pLocalRange = new ListRange(pLevelRange);
00921         pLevelRange = pLocalRange;
00922         bGotSelRange = TRUE;
00923     }
00924 
00925     DoInvalidateNodesRegions(*pLevelRange, TRUE, FALSE, FALSE, FALSE);
00926 
00927     Node* pSelNode = NULL;
00928     for (   pSelNode = pLevelRange->FindFirst();
00929             pSelNode != NULL;
00930             pSelNode = pLevelRange->FindNext(pSelNode)  )
00931     {
00932         if (!pSelNode->IsAnObject())
00933             continue;
00934 
00935         // What a mess! The following logic allows feather effects to
00936         // be applied to effects, EXCEPT when those effects are shadows
00937         NodeRenderableInk* pInkNode = (NodeRenderableInk*)pSelNode;
00938         AttrFeather* pFthr = (AttrFeather*)pInkNode->FindFirstChild(CC_RUNTIME_CLASS(AttrFeather));
00939         ListRange* pStack = NULL;
00940         Node* pTopEffectNode = NULL;
00941         if (bAddNewFeathers && pFthr==NULL && !pInkNode->IsKindOf(CC_RUNTIME_CLASS(NodeFeatherEffect)))
00942         {
00943             pStack = EffectsStack::GetEffectsStackFromNode(pInkNode);
00944             if (pStack)
00945             {
00946                 pTopEffectNode = pStack->FindLast();
00947                 while (pTopEffectNode && pTopEffectNode->IsAShadowController())
00948                 {
00949                     pTopEffectNode = pStack->FindPrev(pTopEffectNode);
00950                 }
00951                 delete pStack;
00952             }
00953         }
00954         if (bAddNewFeathers && pFthr==NULL && pTopEffectNode!=NULL && pTopEffectNode->IsAnObject())
00955             pInkNode = (NodeRenderableInk*)pTopEffectNode;
00956 
00957 #ifdef FEATHER_EFFECT
00958         // For each node in the top level range
00959         // If the node is a postprocessor we must apply a feather effect
00960         // Otherwise we can apply a legacy style feather effect
00961         NodeCompound* pCompound = NULL;
00962         if (pInkNode->IsCompoundClass())
00963             pCompound = (NodeCompound*)pInkNode;
00964         if (pInkNode->IsEffect() ||
00965             (pCompound && (pCompound->HasEffectAttrs() || pCompound->ContainsEffects()))
00966             )
00967         {
00968             // ----------------------------------------------------
00969             // Feather Effect
00970             //
00971             ObjChangeParam ObjChange(OBJCHANGE_STARTING, cFlags, pInkNode, this, OBJCHANGE_CALLEDBYOP);
00972             if (pInkNode->AllowOp(&ObjChange))
00973             {
00974                 Node* pEffect = NULL;
00975                 if (pInkNode->IsEffect() && ((NodeEffect*)pInkNode)->IsFeatherEffect())
00976                 {
00977                     // Existing Feather Effect
00978                     NodeFeatherEffect* pFeatherNode = (NodeFeatherEffect*)pInkNode;
00979                     pEffect = OpChangeFeatherSize::DoReplaceFeatherEffectNode( this,
00980                                                                         pFeatherNode,
00981                                                                         pFeatherNode->GetFeatherSize(),
00982                                                                         pFeatherNode->GetProfile());
00983                 }
00984                 else if (bAddNewFeathers)
00985                 {
00986 PORTNOTE("effect", "Removed LiveEffect usage")
00987 #ifndef EXCLUDE_FROM_XARALX
00988                     // New Feather Effect
00989                     pEffect = OpLiveEffect::DoApplyFeatherEffectNode(this,
00990                                                                      pInkNode,
00991                                                                      POSTPRO_ID_FEATHER,
00992                                                                      POSTPRO_DISPLAYNAME_FEATHER,
00993                                                                      10 * 750,
00994                                                                      CProfileBiasGain());
00995 #endif
00996                 }
00997 
00998                 if (pEffect==NULL && bAddNewFeathers)
00999                 {
01000                     FailAndExecute();
01001                     return;
01002                 }
01003 
01004                 if (pEffect)
01005                     m_NewFeatherAttrs.AddHead(new NodeListItem(pEffect));
01006             }
01007         }
01008         else
01009 #endif
01010         {
01011             // ----------------------------------------------------
01012             // Feather Legacy Attribute
01013             //
01014             // ensure that this is a featherable node
01015             // (which currently can only be derivatives of NodeRenderableInk).
01016             ObjChangeParam ObjChange(   OBJCHANGE_STARTING, cFlags, pInkNode, this,
01017                                         OBJCHANGE_CALLEDBYOP );
01018             if (pInkNode->AllowOp(&ObjChange))
01019             {
01020                 // undoably hide any existing feather attr.
01021                 FeatherAttrValue* pOldFeatherVal = NULL;
01022                 if (pFthr != NULL)
01023                 {
01024                     pOldFeatherVal = &pFthr->Value;
01025                     DoHideNode(pFthr, FALSE);
01026                 }
01027 
01028                 // non-undoably attach a new feather attr to the selected node.
01029                 if (pFthr || bAddNewFeathers)
01030                 {
01031                     AttrFeather* pNewFthr = new AttrFeather();
01032                     pNewFthr->AttachNode(pInkNode, FIRSTCHILD);
01033                     if (pNewFthr != NULL)
01034                     {
01035                         if (pOldFeatherVal != NULL)
01036                             pNewFthr->Value.SimpleCopy(pOldFeatherVal);
01037                         else
01038                             pNewFthr->Value.SetFeatherSize(0);
01039 
01040                         m_NewFeatherAttrs.AddHead(new NodeListItem(pNewFthr));
01041                     }
01042                 }
01043             }
01044         }
01045     }
01046 
01047     // If we didn't use a supplied edit context
01048     // Then this would be a good time to clear any existing edit context that existed
01049     if (bGotSelRange)
01050     {
01051         SetEditContext();
01052         if (pLocalRange)
01053         {
01054             delete pLocalRange;
01055             pLocalRange = NULL;
01056         }
01057     }
01058 }
01059 
01060 
01061 
01062 /********************************************************************************************
01063 
01064 >   virtual void OpChangeFeatherSize::DoSlide(INT32 SlideValue)
01065 
01066     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01067     Created:    24 August 2000
01068     Inputs:     SlideValue  the value on our slider - we'll use it directly for our feather
01069                 size.
01070 
01071     Purpose:    Called by our OpDescriptor's OnSliderChanging() method.
01072                 Changes all feathers on our list, and causes them to redraw.
01073 
01074     Notes:      There is not time at the mo' (is there ever?), but it may be an idea to
01075                 build these methods into a rudimentery slider or similar framework, like
01076                 the drag framework, which would make implementing slider UI a lot easier,
01077                 and remove lots of bodges.
01078 
01079     See also:   SlideFinished(), DoWithParam().
01080 
01081 ********************************************************************************************/
01082 void OpChangeFeatherSize::DoSlide(INT32 SlideValue)
01083 {
01085     // What we do:
01086     //  1. Change the feather sizes for all feathers in our list with a valid parent.
01087     //  2. Cause a redraw of the invalid region, so the user gets immediate feedback.
01088     //
01089 
01090     // after each slide change, we'll need to invalidate the feathered region
01091     // so that the feathers re-render themselves correctly.
01092     DocRect drInvalidRegion(0, 0, 0, 0);
01093 
01094     NodeListItem*   pListItem       = NULL;
01095     NodeListItem*   pNextListItem   = (NodeListItem*)m_NewFeatherAttrs.GetHead();
01096 
01097     AttrFeather*    pFthrAttr       = NULL;
01098     Node*           pFeatheredNode  = NULL;
01099 
01100     // Prevent slow renderers from doing their stuff while we try to
01101     // show the results of the feather op interactively.
01102     Operation::SetQuickRender(TRUE, this);
01103 
01104     while (pNextListItem != NULL)
01105     {
01106         pListItem       = pNextListItem;
01107         pNextListItem   = (NodeListItem*)m_NewFeatherAttrs.GetNext(pListItem);
01108         Node* pNode     = pListItem->pNode;
01109 #ifdef FEATHER_EFFECT
01110         if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsFeatherEffect())
01111         {
01112             NodeFeatherEffect* pEffect = (NodeFeatherEffect*)pNode;
01113             pEffect->SetFeatherSize(SlideValue);
01114 
01115             drInvalidRegion = drInvalidRegion.Union(pEffect->GetBoundingRect());
01116             drInvalidRegion = drInvalidRegion.Union(pEffect->GetEffectStackBounds());   // There might be effects above us which will re-render after this change
01117             pEffect->ReleaseCached(TRUE, FALSE, TRUE, FALSE);       // Parents and Self
01118         }
01119         else
01120 #endif
01121         {
01122             pFthrAttr = (AttrFeather*)pNode;
01123             pFeatheredNode = pFthrAttr->FindParent();
01124 
01125             if (pFeatheredNode != NULL && pFeatheredNode->IsAnObject())
01126             {
01127                 pFthrAttr->Value.SetFeatherSize(SlideValue);
01128                 pFeatheredNode = pFthrAttr->FindParent();
01129                 drInvalidRegion = drInvalidRegion.Union(
01130                     ((NodeRenderableInk*)pFeatheredNode)->GetBoundingRect()
01131                 );
01132                 drInvalidRegion = drInvalidRegion.Union(((NodeRenderableInk*)pFeatheredNode)->GetEffectStackBounds());  // There might be effects above us which will re-render after this change
01133                 ((NodeRenderableInk*)pFeatheredNode)->ReleaseCached(TRUE, FALSE, TRUE, FALSE);      // Parents only
01134             }
01135         }
01136     }
01137 
01138     // force a redraw of all the feathered nodes.
01139     if (!drInvalidRegion.IsEmpty())
01140     {
01141         Document* pDoc = Document::GetSelected();
01142         if (pDoc != NULL)
01143         {
01144             Spread* pSpread = pDoc->GetSelectedSpread();
01145             if (pSpread != NULL)
01146             {
01147                 pDoc->ForceRedraw(pSpread, drInvalidRegion);
01148                 GetApplication()->ServiceRendering();
01149             }
01150         }
01151     }
01152 
01153     // Re-enable slow renderers
01154     Operation::SetQuickRender(FALSE, this);
01155 }
01156 
01157 
01158 
01159 /********************************************************************************************
01160 
01161 >   virtual void OpChangeFeatherSize::SlideFinished(BOOL SuccessfulFinish = TRUE)
01162 
01163     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01164     Created:    24 August 2000
01165 
01166     Inputs:     SuccessfulFinish    whether or not the finish is successful; if the slide
01167                                     was aborted, then this value should be set to FALSE.
01168 
01169     Purpose:    Called by our OpDescriptor's OnSliderSet() method.
01170                 Finishes off a feather-size slider drag. Removes any zero-size feathers on
01171                 our list from the tree, and adds a hide-node action for legitimate feathers,
01172                 so they hide on undo. Also records an action to invalidate the feathered
01173                 nodes, for undo.
01174 
01175                 If we're asked to abort, then we will FailAndExecute(), which will roll back 
01176                 all changes made and restore the tree to the state it was in before the
01177                 slider drag took place.
01178 
01179     Notes:      There is not time at the mo' (is there ever?), but it may be an idea to
01180                 build these methods into a rudimentery slider or similar framework, like
01181                 the drag framework, which would make implementing slider UI a lot easier,
01182                 and remove lots of bodges.
01183 
01184     See also:   DoSlide(), DoWithParam().
01185 
01186 ********************************************************************************************/
01187 void OpChangeFeatherSize::SlideFinished(BOOL SuccessfulFinish)
01188 {
01190     // What we do:
01191     //  1. Check the size of all feathers in our list.
01192     //      zero size   =>  remove and delete it from the tree.
01193     //      ok size     =>  record a hide-node action so it will be hidden on undo.
01194     //
01195     //  2. Undoably invalidate the region covered by all validly feathered nodes.
01196     //
01197 
01198     // we need to undoably invalidate a region of the document.
01199     DocRect drInvalidRegion(0, 0, 0, 0);
01200 
01201     NodeListItem* pListItem = (NodeListItem*)m_NewFeatherAttrs.GetHead();
01202     AttrFeather* pFthrAttr = NULL;
01203     while (pListItem != NULL)
01204     {
01205         Node* pNode     = pListItem->pNode;
01206 PORTNOTE("effect", "Removed LiveEffect usage")
01207 #ifndef EXCLUDE_FROM_XARALX
01208 #ifdef FEATHER_EFFECT
01209         if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsFeatherEffect())
01210         {
01211             NodeFeatherEffect* pEffect = (NodeFeatherEffect*)pNode;
01212             if (pEffect->GetFeatherSize()==0)
01213                 OpLiveEffect::DoDeletePostProcessor(this, pEffect);
01214 
01215             ReleaseFeatherCache(pEffect, drInvalidRegion);
01216         }
01217         else
01218 #endif
01219 #endif
01220         {
01221             pFthrAttr = (AttrFeather*)pNode;
01222             Node* pFeatheredNode = pFthrAttr->FindParent();
01223 
01224             // remove all zero-size feathers from the selection.
01225             if (pFthrAttr->Value.GetFeatherSize() == 0)
01226             {
01227                 pFthrAttr->UnlinkNodeFromTree();
01228                 delete pFthrAttr;
01229             }
01230             else
01231             {
01232                 // all remaining feathers should have a hide-node-action given to them,
01233                 // so that when the user hits 'undo', they are hidden.
01234                 HideNodeAction* pUndoHideNodeAction = NULL;
01235                 ActionCode ac = HideNodeAction::Init(this,
01236                                                     &UndoActions,
01237                                                     pFthrAttr,
01238                                                     FALSE,      // don't include subtree size
01239                                                     (Action**)&pUndoHideNodeAction,
01240                                                     FALSE);     // don't tell subtree when undone
01241                 if (ac == AC_FAIL)
01242                 {
01243                     pFthrAttr->UnlinkNodeFromTree();
01244                     delete pFthrAttr;
01245                 }
01246             }
01247 
01248             if (pFeatheredNode != NULL && pFeatheredNode->IsAnObject())
01249             {
01250                 ReleaseFeatherCache((NodeRenderableInk*)pFeatheredNode, drInvalidRegion);
01251             }
01252         }
01253 
01254         pListItem = (NodeListItem*)m_NewFeatherAttrs.GetNext(pListItem);
01255     }
01256 
01257     // invalidate the feathered region.
01258     // Note that this is needed to allow nodes which were rendering themselves in a fast mode
01259     // during slider dragging (see Get/SetQuickRender) are now able to render themselves
01260     // fully now that the drag is over
01261     if (!drInvalidRegion.IsEmpty())
01262     {
01263         Document* pDoc = Document::GetSelected();
01264         if (pDoc != NULL)
01265         {
01266             Spread* pSpread = pDoc->GetSelectedSpread();
01267             if (pSpread != NULL)
01268                 DoInvalidateRegion(pSpread, drInvalidRegion);
01269         }
01270     }
01271 
01272     // update any changed nodes.
01273     ObjChangeFlags ocf;
01274     ocf.Attribute = TRUE;
01275     ObjChangeParam ocp(OBJCHANGE_FINISHED, ocf, NULL, this, OBJCHANGE_CALLEDBYOP);
01276     UpdateChangedNodes(&ocp);
01277 
01278     m_NewFeatherAttrs.DeleteAll();
01279 
01280     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED)); 
01281 
01282     if (!SuccessfulFinish)
01283         FailAndExecute();
01284 
01285     End();
01286 }
01287 
01288 
01289 
01290 
01291 /********************************************************************************************
01292 
01293 >   static void OpChangeFeatherSize::ReleaseFeatherCache(NodeRenderableInk* pNode, DocRect& drRegion)
01294     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01295     Created:    11/05/2005
01296     Inputs:     pNode - pointer to node (either FeatherEffect or node above Feather Attr)
01297                 drRegion - Region rectangle to be updated
01298     Outputs:    drRegion - Updated region rectangle
01299     Returns:    -
01300     Purpose:    Encapsulate common bounding rect and cache control for feather attribute changing
01301 
01302 ********************************************************************************************/
01303 void OpChangeFeatherSize::ReleaseFeatherCache(NodeRenderableInk* pNode, DocRect& drRegion)
01304 {
01305     ERROR3IF(pNode==NULL, "ReleaseFeatherCache passed NULL node ptr");
01306 
01307     // T'would be better if ReleaseCached returned a rectangle that needs to
01308     // be invalidated to recover all the cached data...
01309     if (pNode->IsEffect())
01310         pNode->ReleaseCached(TRUE, FALSE, FALSE, FALSE);
01311     else
01312         pNode->ReleaseCached(TRUE, FALSE, TRUE, TRUE);
01313 
01314     NodeRenderableInk* pBoundsNode = pNode;
01315     ListRange* pStack = EffectsStack::GetEffectsStackFromNode(pNode);
01316     if (pStack)
01317     {
01318         pBoundsNode = (NodeEffect*)pStack->FindLast();
01319         delete pStack;
01320     }
01321 
01322     drRegion = drRegion.Union(pBoundsNode->GetBoundingRect());
01323 }
01324 
01325 
01326 
01327 
01328 /********************************************************************************************
01329 
01330 >   static NodeFeatherEffect* OpChangeFeatherSize::DoReplaceFeatherEffectNode(UndoableOperation* pOp,
01331                                                           NodeFeatherEffect* pSel,
01332                                                           MILLIPOINT FeatherSize,
01333                                                           CProfileBiasGain Profile)
01334     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01335     Created:    27/04/2005
01336     Inputs:     pSel - pointer to node to insert Feather Effect above
01337                 strDispayName - The display name of the effect we're going to apply
01338     Outputs:    -
01339     Returns:    Pointer to newly created NodeFeatherEffect or NULL
01340     Purpose:    
01341     Errors:     
01342     See also:   
01343 
01344 ********************************************************************************************/
01345 #ifdef FEATHER_EFFECT
01346 NodeFeatherEffect* OpChangeFeatherSize::DoReplaceFeatherEffectNode(UndoableOperation* pOp,
01347                                               NodeFeatherEffect* pNode,
01348                                               MILLIPOINT FeatherSize,
01349                                               CProfileBiasGain Profile)
01350 {
01351     ENSURE(pNode, "DoApplyLiveEffect not given a useful node");
01352 
01353     // Read the current state of the node
01354     MILLIPOINT OldFeatherSize = pNode->GetFeatherSize();
01355     CProfileBiasGain OldFeatherProfile = pNode->GetProfile();
01356 
01357     // Setup the action to undo this Operation
01358     ChangeFeatherEffectAction* pAct = NULL;
01359     if (ChangeFeatherEffectAction::Init(pOp, 
01360                                         pOp->GetUndoActionList(),
01361                                         pNode,
01362                                         OldFeatherSize,
01363                                         OldFeatherProfile,
01364                                         &pAct   ) != AC_OK )
01365     {
01366         pOp->FailAndExecute();
01367         pOp->End();
01368         return NULL;
01369     }
01370 
01371     // Now we know the action was allocated OK, change the data structure...
01372     pNode->SetFeatherSize(FeatherSize);
01373     pNode->SetProfile(Profile);
01374 
01375     return pNode;
01376 }
01377 #endif
01378 
01379 
01380 
01382 //                                      Changing feather profile
01384 
01385 
01386 ChangeFeatherProfileOpDesc::ChangeFeatherProfileOpDesc(
01387                             UINT32 toolID,                    // Tool (Module) Identifier
01388                             UINT32 txID,                      // String Resource ID
01389                             CCRuntimeClass* Op,             // pointer to the Op's runtime class object
01390                             TCHAR* tok,                     // pointer to the token string
01391                             pfnGetState gs,                 // pointer to the GetState function
01392                             UINT32 helpId,              // help identifier 
01393                             UINT32 bubbleID,                // string resource for bubble help
01394                             UINT32 resourceID,          // resource ID
01395                             UINT32 controlID,               // control ID within resource
01396                             BOOL ReceiveMessages,       
01397                             BOOL Smart, 
01398                             BOOL Clean,
01399                             UINT32 AutoStateFlags
01400                            )
01401     : UndoableOpDescriptor(toolID, txID, Op, tok, gs, helpId, bubbleID, 
01402                          resourceID, controlID, ReceiveMessages, Smart,
01403                          Clean, 0, AutoStateFlags )
01404 {
01405     m_bProfileChanging      = FALSE;
01406     m_bProfileInitialChange = TRUE;
01407 }
01408 
01409 /********************************************************************************************
01410 
01411 >   void ChangeFeatherProfileOpDesc::OnControlCreate(OpDescControlCreateMsg* CreateMsg)
01412 
01413     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01414     Created:    14/3/2000
01415 
01416     Purpose:    This function is called after ChangeFeatherSizeSliderOpDesc::OnControlCreate ()
01417                 has been called.  This function initialises the biasgain gadget that appears
01418                 on our feathering bar.
01419     See Also:   ChangeFeatherSizeSliderOpDesc::OnControlCreate
01420 
01421 ********************************************************************************************/
01422 
01423 void ChangeFeatherProfileOpDesc::OnControlCreate(OpDescControlCreateMsg* CreateMsg)
01424 {
01425     DialogOp* pDlg = CreateMsg->pDlgOp;
01426     CGadgetID GadgetID = CreateMsg->SetGadgetID;
01427 
01428     // link the profile gadget to its controlling button/infobar ....   
01429     m_BiasGainGadget.Init(pDlg, GadgetID, _R(IDBBL_BIASGAIN), _R(IDS_BIASGAINDLG));
01430     m_BiasGainGadget.ToggleFillProfile();
01431 }
01432 
01433 
01434 
01435 MsgResult ChangeFeatherProfileOpDesc::Message(Msg* pMessage)
01436 {
01437     if (MESSAGE_IS_A(pMessage, OpDescControlMsg))
01438     {
01439         OpDescControlMsg* pOpDescCtrlMsg = reinterpret_cast<OpDescControlMsg*>(pMessage);
01440         
01441         if (pOpDescCtrlMsg->DlgMsg == DIM_PROFILE_CHANGED)
01442             OnProfileChanged(pOpDescCtrlMsg);
01443         else if (pOpDescCtrlMsg->DlgMsg == DIM_PROFILE_CHANGING)
01444             OnProfileChanging(pOpDescCtrlMsg);
01445     }
01446     
01447     return UndoableOpDescriptor::Message(pMessage);
01448 }
01449 
01450 
01451 
01452 /********************************************************************************************
01453 
01454 >   void ChangeFeatherProfileOpDesc::OnSliderSet(OpDescControlMsg* SelChangedMsg)
01455 
01456     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01457     Created:    15/3/2000
01458 
01459     Purpose:    Process the profile chenged message (it's send from BiasGain dialog
01460                 when the combobox is changed or when a slider is set (probably after dragging).
01461 
01462 ********************************************************************************************/
01463 void ChangeFeatherProfileOpDesc::OnProfileChanged(OpDescControlMsg* SelChangedMsg)
01464 {
01465     // ILAN:  Although it is possible for me to ammend the SelChangedMsg message so that the new
01466     // profile is part of it (i.e.  like how the other profiles work); it is not worth me doing
01467     // this just to get the following working + it would also slow things down somewhat ....
01468 
01469     CProfileBiasGain NewBiasGain = m_BiasGainGadget.GetCurrentDialogProfile();
01470 
01471     if (m_bProfileChanging)
01472     {
01473         // expect SliderChanging to be true before a set is called. Already saved initial 
01474         // state in first Op initiated by OpSliderChanging()
01475         m_bProfileInitialChange = FALSE;
01476     }
01477     else
01478     {
01479         m_bProfileInitialChange = TRUE;
01480     }
01481     
01482     m_bProfileChanging = FALSE;
01483 
01484     FeatherProfileOpParam Param(NewBiasGain, OpChangeFeatherSize::GetEditContext());
01485     OpChangeFeatherProfile* Op = new OpChangeFeatherProfile();
01486     Op->DoWithParam(this, &Param);
01487 }
01488 
01489 /********************************************************************************************
01490 
01491 >   void ChangeFeatherProfileOpDesc::OnSliderChanging(OpDescControlMsg* SliderChangingMsg)
01492 
01493     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01494     Created:    15/3/2000
01495 
01496     Purpose:    Handles profile changing message. Usually sent by BiasGain dialog when user
01497                 drags a slider (after the user finished dragging, DIM_PROFILE_CHANGED message
01498                 is sent).
01499 
01500 ********************************************************************************************/
01501 void ChangeFeatherProfileOpDesc::OnProfileChanging(OpDescControlMsg* SliderChangingMsg)
01502 {
01503     // ILAN:  Although it is possible for me to ammend the SelChangedMsg message so that the new
01504     // profile is part of it (i.e.  like how the other profiles work); it is not worth me doing
01505     // this just to get the following working + it would also slow things down somewhat ....
01506     
01507     CProfileBiasGain NewBiasGain = m_BiasGainGadget.GetCurrentDialogProfile();
01508 
01509     if (m_bProfileChanging)
01510     {
01511         // Successive slider changing message
01512         // Don't add to undo history
01513         m_bProfileInitialChange = FALSE;
01514     }
01515     else
01516     {
01517         // Store selections initial feather states so that it can be saved in undo list
01518         // once all sliding has finished (ie. in OnProfileChanged())
01519         m_bProfileChanging      = TRUE;
01520         m_bProfileInitialChange = TRUE;
01521     }
01522 
01523     FeatherProfileOpParam Param(NewBiasGain, OpChangeFeatherSize::GetEditContext());
01524     OpChangeFeatherProfile* Op = new OpChangeFeatherProfile();
01525     Op->DoWithParam(this, &Param);
01526 }
01527 
01529 
01530 BOOL OpChangeFeatherProfile::Init()
01531 {
01532     OpDescriptor* OpDesc = new ChangeFeatherProfileOpDesc(0,
01533                                              _R(IDS_FEATHERPROFILEOP),
01534                                              CC_RUNTIME_CLASS(OpChangeFeatherProfile),
01535                                              OPTOKEN_FEATHERPROFILE,
01536                                              OpChangeFeatherProfile::GetState,          // NB Operations GetState
01537                                              0,
01538                                              _R(IDBBL_FEATHERPROFILEOP),
01539                                              SYSTEMBAR_FEATHER,
01540                                              _R(IDC_FEATHERPROFILE_GDGT),
01541                                              TRUE,
01542                                              FALSE,
01543                                              FALSE,
01544                                              (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION | DONT_GREY_WHEN_SELECT_INSIDE ) );
01545 
01546     ERRORIF(!OpDesc, FALSE, _R(IDE_NOMORE_MEMORY));
01547 
01548     return TRUE;
01549 }
01550 
01551 
01552 
01553 
01554 /********************************************************************************************
01555 
01556 >   OpState OpChangeFeatherProfile::GetState(String_256* UIDescription, OpDescriptor*)
01557 
01558     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01559     Created:    27/04/2005
01560     Purpose:    Return availability of OpChangeFeatherProfile
01561 
01562 ********************************************************************************************/
01563 
01564 OpState OpChangeFeatherProfile::GetState(String_256* UIDescription, OpDescriptor*)
01565 {
01566     OpState OpSt;
01567 
01568     SelRange::CommonAttribResult status = GetProfileFromSelection2(TRUE, NULL);
01569     if (status == Range::ATTR_NONE)
01570     {
01571         OpSt.Greyed = TRUE;
01572         String_256 DisableReason(_R(IDS_NO_FEATHERED_OBJECTS));
01573         *UIDescription = DisableReason;            
01574     }
01575 
01576     return OpSt;
01577 }
01578 
01579 
01580 
01581 
01582 /********************************************************************************************
01583 
01584 >   void OpChangeFeatherProfile::Do(OpDescriptor* pOp)
01585 
01586     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01587     Created:    13/3/2000
01588 
01589     Purpose:    This function is called when the user clicks our linked profile button
01590                 (yahoo!).  This function does one of two things:
01591 
01592                 1)  Gets the current feathering profile (if there is one); and invokes the
01593                     profile dialog with it.
01594                 2)  Closes the profile dialog down.
01595 
01596     See Also:   InformationBarOp::GetProfileFromSelection() for tips of implementing the
01597                 remainder of this function.
01598 
01599     NOTE:       At present one should NOT implement OpChangeFeatherProfile::DoWithParam ()
01600 
01601 ********************************************************************************************/
01602 
01603 void OpChangeFeatherProfile::Do(OpDescriptor* pOp)
01604 {
01605     if (!(ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen ()))
01606     {
01607         CBiasGainDlg* pDialog_m  =  new CBiasGainDlg();
01608         CProfileBiasGain CommonProfile;
01609         SelRange::CommonAttribResult status = GetProfileFromSelection2(FALSE, &CommonProfile);
01610 
01611         // I don't why this isn't working like the other profile gadgets do, BUT 
01612         // force the controlling button to stay down!
01613 
01614         // AUGH!!!!!!  why on earth do I get a divide by zero error from the dialog if I call 
01615         // SetBoolGadgetSelected?  well sod it, the button can damn well stay up!
01616 
01617         //pDlg->SetLongGadgetValue (FeatherProfile->GetUniqueGadgetID (), 1);
01618 
01619         //ChangeFeatherProfileOpDesc::m_BiasGainGadget.GetOwningBar ()->SetBoolGadgetSelected (_R(IDC_FEATHERPROFILE_GDGT), TRUE);
01620         
01621         //ChangeFeatherProfileOpDesc::SetBoolGadgetSelected (_R(IDC_FEATHERPROFILE_GDGT), TRUE);
01622         
01623         pDialog_m->InvokeVia(ChangeFeatherProfileOpDesc::m_BiasGainGadget, &CommonProfile, status==Range::ATTR_MANY);
01624     }
01625     else
01626     {
01627         //ChangeFeatherProfileOpDesc::m_BiasGainGadget.GetOwningBar ()->SetBoolGadgetSelected (_R(IDC_FEATHERPROFILE_GDGT), FALSE);
01628         ChangeFeatherProfileOpDesc::m_BiasGainGadget.CloseDialog();
01629         //ChangeFeatherProfileOpDesc::SetBoolGadgetSelected (_R(IDC_FEATHERPROFILE_GDGT), FALSE);
01630     }
01631 }
01632 
01633 void ChangeFeatherProfileOpDesc::SetBoolGadgetSelected (CGadgetID Gadget, BOOL IsSelected)
01634 {
01635     /*OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_FEATHERPROFILE);
01636     if (pOpDesc!=NULL)
01637     {
01638         // Found the opdescriptor. Now find all the gadgets associated with it
01639         List Gadgets;
01640         if (pOpDesc->BuildGadgetList(&Gadgets))
01641         {
01642             // Found some. Set the controls accordingly
01643             GadgetListItem* pGadgetItem = (GadgetListItem*) Gadgets.GetHead();
01644 
01645             while (pGadgetItem != NULL)
01646             {
01647                 // Set the gadget
01648                 pGadgetItem->pDialogBarOp->SetBoolGadgetSelected(pGadgetItem->gidGadgetID,
01649                                                                     IsSelected);
01650                 // Find the next gadget
01651                 pGadgetItem = (GadgetListItem*) Gadgets.GetNext(pGadgetItem);
01652             }
01653     
01654             // Clean out the list
01655             Gadgets.DeleteAll();
01656         }
01657     }*/
01658 }
01659 
01660 
01661 /********************************************************************************************
01662 
01663 >   static SelRange::CommonAttribResult OpChangeFeatherProfile::GetProfileFromSelection2(BOOL bFastScan,
01664                                                                                           CProfileBiasGain* pCommonProfile)
01665 
01666     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01667     Created:    27/04/2005
01668     Inputs:     -
01669     Outputs:    Common profile if there is one
01670     Returns:    Enum indicating None, Common or Many Profiles
01671     Purpose:    See InformationBarOp::GetProfileFromSelection() for a description of this
01672                 function.
01673                 See BlendInfoBarOp::GetProfileFromSelection for multi-gadget eg.
01674 
01675 *********************************************************************************************/
01676 
01677 SelRange::CommonAttribResult OpChangeFeatherProfile::GetProfileFromSelection2(BOOL bFastScan,
01678                                                                                       CProfileBiasGain* pCommonProfile)
01679 {   
01680     // we must now examine all our nodes ....
01681     
01682     // If we have a specific context within which we should be operating
01683     // use that
01684     Range* pLevelRange = OpChangeFeatherSize::GetEditContext();
01685     if (pLevelRange==NULL)
01686     {
01687         // If not, go get a context from the current selection
01688         SelRange* pSelRange = GetApplication()->FindSelection();
01689         pLevelRange = pSelRange->GetTopClassRange(CC_RUNTIME_CLASS(NodeFeatherEffect), FALSE, TRUE);
01690     }
01691     if (pLevelRange==NULL)
01692         return Range::ATTR_NONE;
01693     
01694     BOOL bFoundFeather = FALSE;
01695     CProfileBiasGain FirstProfile;
01696     AttrFeather* pAttr = NULL;
01697     SelRange::CommonAttribResult status = Range::ATTR_NONE;
01698     MonotonicTime timer;
01699 
01700     Node* pNode = pLevelRange->FindFirst();
01701     while (pNode && !(bFastScan && timer.Elapsed(100)))
01702     {
01703 #ifdef FEATHER_EFFECT
01704         if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsFeatherEffect())
01705         {
01706             // -------------------------------------------------------------------------
01707             // Feather effect case:
01708             NodeFeatherEffect* pEffect = (NodeFeatherEffect*)pNode;
01709             if (!bFoundFeather)
01710             {
01711                 bFoundFeather = TRUE;
01712                 FirstProfile = pEffect->GetProfile();
01713                 status = Range::ATTR_COMMON;
01714             }
01715             else
01716             {
01717                 if (!(FirstProfile == pEffect->GetProfile()))
01718                 break;
01719             }
01720         }
01721         else
01722 #endif
01723         {
01724             // -------------------------------------------------------------------------
01725             // Feather attribute case:
01726             // Feather attributes don't get optimised so we know we should find it it in the child list of the selected item
01727             pAttr = (AttrFeather*)pNode->FindFirstChild(CC_RUNTIME_CLASS(AttrFeather));
01728 
01729             if (pAttr)
01730             {
01731                 if (!bFoundFeather)
01732                 {
01733                     bFoundFeather = TRUE;
01734                     FirstProfile = pAttr->Value.GetProfile();
01735                     status = Range::ATTR_COMMON;
01736                 }
01737                 else
01738                 {
01739                     if (!(FirstProfile == pAttr->Value.GetProfile()))
01740                     break;
01741                 }
01742             }
01743             else
01744             {
01745                 // node is using default feather - got two cases to handle here
01746                 // Or may be INSIDE a feathered Node!!! So checking default value is pointless!
01747             }
01748         }
01749 
01750         pNode = pLevelRange->FindNext(pNode);
01751     }
01752 
01753     // If we exited the loop while there were still more nodes to process
01754     // We must have run out of time or aborted early because we detected the "many" case
01755     if (pNode)
01756     {
01757         status = Range::ATTR_MANY;
01758         if (pCommonProfile)
01759             *pCommonProfile = *(new CProfileBiasGain());        // Reset to defaults
01760     }
01761     else
01762     {
01763         if (pCommonProfile)
01764             *pCommonProfile = FirstProfile;
01765     }
01766 
01767     return status;
01768 }
01769 
01770 
01771 
01772 
01773 /********************************************************************************************
01774 
01775 >   void OpChangeFeatherProfile::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
01776 
01777     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01778     Created:    27/04/2005
01779     Inputs:     -
01780     Outputs:    -
01781     Returns:    -
01782     Purpose:    Change all selected feather profiles
01783     Note:       It's important that the basic logic of this function is the same as
01784                 that in GetProfileFromSelection2
01785 
01786 *********************************************************************************************/
01787 
01788 void OpChangeFeatherProfile::DoWithParam(OpDescriptor* pOp, OpParam* pParam)
01789 {
01790     ObjChangeFlags cFlags;
01791     cFlags.Attribute = TRUE;
01792     DocRect InvalidRegion(0,0,0,0); // To prevent individual node redraws we union all bounding
01793                                     // rects of nodes which get feathered and then generate a
01794                                     // single redraw action (DoInvalidateNodeRegion)
01795     CProfileBiasGain NewProfile;
01796     ListRange* pLevelRange = NULL;
01797     AttrFeather* pAttr = NULL;
01798 
01799     if (pParam && IS_A(pParam, FeatherProfileOpParam))
01800     {
01801         FeatherProfileOpParam* pProfileParam = (FeatherProfileOpParam*)pParam;
01802         pLevelRange = pProfileParam->pLevelRange;
01803         NewProfile = pProfileParam->P;
01804     }
01805 
01806     if (pLevelRange==NULL)
01807     {
01808         SelRange* pSelRange = GetApplication()->FindSelection();
01809         pLevelRange = pSelRange->GetTopClassRange(CC_RUNTIME_CLASS(NodeFeatherEffect), FALSE, TRUE);
01810     }
01811 
01812     // Since the selection may change during this Op we must get a permanent copy of
01813     // the level range we are working on
01814     ListRange* pLocalRange = new ListRange(pLevelRange);
01815     if (pLocalRange==NULL)
01816     {
01817         FailAndExecute();
01818         End();
01819         return;
01820     }
01821 
01822     if (((ChangeFeatherProfileOpDesc*)pOp)->m_bProfileChanging)
01823     {
01824         // Prevent slow renderers from doing their stuff while we try to
01825         // show the results of the feather op interactively.
01826         Operation::SetQuickRender(TRUE, this);
01827     }
01828 
01829     DoInvalidateNodesRegions(*pLocalRange, TRUE, FALSE, FALSE, FALSE);
01830 
01831     Node* pNode = pLocalRange->FindFirst();
01832     while (pNode)
01833     {
01834 #ifdef FEATHER_EFFECT
01835         if (pNode->IsEffect() && ((NodeEffect*)pNode)->IsFeatherEffect())
01836         {
01837             // -------------------------------------------------------------------------
01838             // Feather effect case:
01839             NodeFeatherEffect* pEffect = (NodeFeatherEffect*)pNode;
01840             CProfileBiasGain undoProf = pEffect->GetProfile();
01841 
01842             // Setup the action to undo this Operation
01843             ChangeFeatherEffectProfileAction* pAct = NULL;
01844             if (ChangeFeatherEffectProfileAction::Init(this, 
01845                                                         &UndoActions,
01846                                                         pEffect,
01847                                                         undoProf,
01848                                                         &pAct   ) != AC_OK )
01849             {
01850                 FailAndExecute();
01851                 End();
01852                 return;
01853             }
01854 
01855             // Only set the new profile if the action was successfully allocated
01856             pEffect->SetProfile(NewProfile);
01857 
01858             // union feathered node bounding rect so only one redraw per feather op
01859             OpChangeFeatherSize::ReleaseFeatherCache(pEffect, InvalidRegion);
01860 
01861         }
01862         else
01863 #endif
01864         {
01865             // -------------------------------------------------------------------------
01866             // Feather attribute case:
01867             // Feather attributes don't get optimised so we know we should find it it in the child list of the selected item
01868             pAttr = (AttrFeather*)pNode->FindFirstChild(CC_RUNTIME_CLASS(AttrFeather));
01869 
01870 //          if (!pAttr)
01871 //          {
01872 //              // if there is no feather - see if the parent node is a compound; and if so,
01873 //              // see if it has been feathered ....
01874 //
01875 //              if (pNode->FindParent ()->IsController ())
01876 //              {
01877 //                  pAttr = pNode->FindParent ()->FindFirstChild(CC_RUNTIME_CLASS(AttrFeather));
01878 //              }
01879 //          }
01880 //
01881             if (pAttr)
01882             {
01883                 ObjChangeParam ObjChange(OBJCHANGE_STARTING, cFlags, pNode, this);
01884                 if (pNode->AllowOp(&ObjChange))
01885                 {
01886                     if (!DoChangeFeatherProfile(&pAttr->Value, NewProfile))
01887                     {
01888                         FailAndExecute();
01889                         End();
01890                         return;
01891                     }
01892 
01893                     // union feathered node bounding rect so only one redraw per feather op
01894                     if (pNode->IsAnObject())
01895                     {
01896                         OpChangeFeatherSize::ReleaseFeatherCache((NodeRenderableInk*)pNode, InvalidRegion);
01897                     }
01898 
01899                     // send the objchange message to trigger any OnChildChange messages
01900                     ObjChange.Define(OBJCHANGE_FINISHED, cFlags, pNode, this);
01901                     UpdateChangedNodes(&ObjChange);
01902                 }
01903             }
01904         }
01905 
01906         pNode = pLocalRange->FindNext(pNode);
01907     }
01908 
01909     delete pLocalRange;
01910     pLocalRange = NULL;
01911 
01912     // send through the redraw
01913     if (!(InvalidRegion.hi.x==0) || !(InvalidRegion.lo.x==0) || !(InvalidRegion.hi.y==0) || !(InvalidRegion.lo.y==0))
01914     {
01915         Document* SelectedDoc = Document::GetSelected();
01916         ENSURE(SelectedDoc,"No selected doc.");
01917         Spread* pSpread = SelectedDoc->GetSelectedSpread();
01918         ENSURE(pSpread,"No selected spread.");
01919 
01920         DoInvalidateRegion(pSpread,InvalidRegion);
01921     }
01922     else
01923     {
01924         // no nodes feathered
01925         SucceedAndDiscard();
01926     }
01927 
01928     if (!((ChangeFeatherProfileOpDesc*)pOp)->m_bProfileInitialChange)
01929     {
01930         // don't want op in op hist
01931         // nb Action::Init modifies the ophist size in anticipation of the op being added
01932         // to the history list. Hence modify the size
01933         SucceedAndDiscard();
01934     }
01935 
01936     if (((ChangeFeatherProfileOpDesc*)pOp)->m_bProfileChanging)
01937     {
01938         // Prevent slow renderers from doing their stuff while we try to
01939         // show the results of the feather op interactively.
01940         Operation::SetQuickRender(FALSE, this);
01941     }
01942 
01943     // bodge/hack alert!  I found it necessary to add some code to the selector tool to prevent
01944     // profile dilaogs from closing down when changing the selection.  Unfortunately, when you
01945     // change the profile within the feathers profile dialog - this same code is called; which
01946     // attempts to close down the dialog.  It must not do this!  I traced the offending call
01947     // (which invokes OpChangeFeatherProfile::OnSelChangingMsg ()) to being the following one
01948     // to End ().
01949     SelectorTool::SetNormalClick_CheckProfileDialog (TRUE);
01950     End();
01951     SelectorTool::SetNormalClick_CheckProfileDialog (FALSE);
01952 }
01953 
01954 
01955 
01956 
01957 /********************************************************************************************
01958 
01959 >   BOOL OpChangeFeatherProfile::OnSelChangingMsg(SelChangingMsg::SelectionState State)
01960 
01961     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01962     Created:    27/04/2005
01963     Inputs:     -
01964     Outputs:    -
01965     Returns:    -
01966     Purpose:    Update the Profile dialog when the selection changes
01967 
01968 *********************************************************************************************/
01969 
01970 BOOL OpChangeFeatherProfile::OnSelChangingMsg(SelChangingMsg::SelectionState State)
01971 {
01972     if (ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen ())
01973     {   
01974         CProfileBiasGain CommonProfile;
01975         SelRange::CommonAttribResult status = GetProfileFromSelection2(FALSE, &CommonProfile);
01976         if (status == Range::ATTR_MANY)
01977         {
01978             // handles case where we click on another blend
01979             ChangeFeatherProfileOpDesc::m_BiasGainGadget.ReInitialiseDialog(&CommonProfile, TRUE);
01980         }
01981         else if (status == Range::ATTR_COMMON)
01982         {   
01983             // handles case where we click on another blend
01984             ChangeFeatherProfileOpDesc::m_BiasGainGadget.ReInitialiseDialog(&CommonProfile, FALSE);
01985         }
01986         else
01987         {
01988             // CGS:  wo there!  when selecting another object, everything is deselected - and then just that node
01989             // selected.  This is a problem, since if we proceed regardless, the profile dialog closes (when it
01990             // possibly shouldn't have).  As such, I now check for this occurring ....
01991             if (!SelectorTool::GetNormalClick_CheckProfileDialog())
01992             {
01993                 // user click on no object at all - close the profile dialog ....
01994                 ChangeFeatherProfileOpDesc::m_BiasGainGadget.CloseDialog();
01995             }
01996             else
01997                 ChangeFeatherProfileOpDesc::m_BiasGainGadget.ReInitialiseDialog(&CommonProfile, FALSE);
01998         }
01999     }
02000     
02001     return (TRUE);
02002 }
02003 
02004 
02005 
02006 
02007 /********************************************************************************************
02008 
02009 >   BOOL OpChangeFeatherProfile::DoChangeFeatherProfile(FeatherAttrValue* pFeather, CProfileBiasGain &newProf)
02010 
02011     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02012     Created:    27/04/2005
02013     Inputs:     -
02014     Outputs:    -
02015     Returns:    -
02016     Purpose:    Change one feather profile
02017 
02018 *********************************************************************************************/
02019 
02020 BOOL OpChangeFeatherProfile::DoChangeFeatherProfile(FeatherAttrValue* pFeather, CProfileBiasGain &newProf)
02021 {
02022     CProfileBiasGain undoProf = pFeather->GetProfile();
02023 
02024     if (!pFeather->ChangeFeatherProfile(newProf))
02025     {
02026         // ChangeFeatherProfileAction doesn't need to alloc any memory so shouldn't ever fail
02027         return FALSE;
02028     }
02029 
02030     ChangeFeatherProfileAction* pAct = NULL;
02031 
02032     // Setup the action to undo this Operation
02033     if (!ChangeFeatherProfileAction::Init(  this, 
02034                                             &UndoActions,
02035                                             pFeather,
02036                                             undoProf,
02037                                             &pAct   ) == AC_OK )
02038     {
02039         return FALSE;
02040     }
02041 
02042     return TRUE;
02043 }
02044 
02045 
02046 
02047 
02049 
02050 ChangeFeatherProfileAction::ChangeFeatherProfileAction()
02051 {
02052     m_pFeather = NULL;
02053 }
02054 
02055 /********************************************************************************************
02056 >   ActionCode ChangeFeatherProfileAction::Execute()
02057     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
02058     Created:    2/12/99
02059     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02060     Purpose:    Executes the action.
02061     Errors:     -
02062     SeeAlso:    Action::Init()
02063 ********************************************************************************************/
02064 ActionCode ChangeFeatherProfileAction::Execute()
02065 {
02066     ActionCode Act = AC_FAIL;
02067     ChangeFeatherProfileAction* pAction;
02068 
02069     // First time an instance of this Action is executed is when called during and
02070     // UndoList->ExecuteBackwards inside an OpUndo invoked OpHist->GetTail()->Undo (where
02071     // the tail OpHist item is an OpChangeFeatherProfile. SHEW!
02072     // However may also be called by a Redo as we are about to stick an instance into the
02073     // Redo list
02074     CProfileBiasGain UndoProf = m_pFeather->GetProfile();
02075     if (m_pFeather->ChangeFeatherProfile(m_LastProfile))
02076         Act = ChangeFeatherProfileAction::Init( pOperation, 
02077                                         pOppositeActLst,
02078                                         m_pFeather,
02079                                         UndoProf,
02080                                         &pAction );
02081 
02082     if (ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen())
02083     {
02084         // only way I can think of to get the profile dialog to reinialise itself is
02085         // to fake a OnSelChangingMsg message ....
02086 
02087         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::SELECTIONCHANGED, FALSE));
02088     }
02089 
02090     return Act;
02091 }
02092 
02093 /********************************************************************************************
02094 >   ActionCode ChangeFeatherProfileAction::Init(    Operation*  pOp,
02095                                                 ActionList* pActionList,
02096                                                 FeatherAttrValue*   pFeather,
02097                                                 INT32 FeatherSize,
02098                                                 ChangeFeatherProfileAction**    ppNewAction )
02099     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
02100     Created:    2/12/99
02101     Inputs:     pOp             = ptr to the operation to which this action belongs
02102                 pActionList     = ptr to Operations action list to which this action should be added
02103                 pFeather        = ptr to a feather attribute
02104                 FeatherSize     = New feather size for pFeather
02105     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02106                                   a pointer to the created action
02107     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02108     SeeAlso:    Action::Init()
02109     Notes:      Doesn't redraw the Node (either before or after the change).
02110                 Bounding Box doesn't change so you don't need to remove blobs before and after
02111                 this action - ie DoInvalidateNodeBounds(no blob) on either side of this
02112 ********************************************************************************************/
02113 ActionCode ChangeFeatherProfileAction::Init( Operation* pOp,
02114                             ActionList* pActionList,
02115                             FeatherAttrValue* pFeather,
02116                             CProfileBiasGain FeatherProfile,
02117                             ChangeFeatherProfileAction** ppNewAction )
02118 {
02119     UINT32 ActSize = sizeof(ChangeFeatherProfileAction);
02120 
02121     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(ChangeFeatherProfileAction),(Action**)ppNewAction);
02122 
02123     if (Ac != AC_FAIL)
02124     {
02125         (*ppNewAction)->m_pFeather = pFeather;
02126         (*ppNewAction)->m_LastProfile = FeatherProfile;
02127     }
02128 
02129     return Ac;
02130 }
02131 
02132 
02134 
02135 #ifdef FEATHER_EFFECT
02136 /********************************************************************************************
02137 >   ActionCode ChangeFeatherEffectProfileAction::Init(  Operation*  pOp,
02138                                                         ActionList* pActionList,
02139                                                         NodeFeatherEffect*  pFeatherEffect,
02140                                                         CProfileBiasGain FeatherProfile,
02141                                                         ChangeFeatherEffectProfileAction** ppNewAction )
02142     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02143     Created:    27/04/2005
02144     Inputs:     pOp             = ptr to the operation to which this action belongs
02145                 pActionList     = ptr to Operations action list to which this action should be added
02146                 pFeatherEffect  = ptr to a feather effect
02147                 FeatherSize     = New feather size for pFeather
02148     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02149                                   a pointer to the created action
02150     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02151     SeeAlso:    Action::Init()
02152     Notes:      Doesn't redraw the Node (either before or after the change).
02153                 Bounding Box doesn't change so you don't need to remove blobs before and after
02154                 this action - ie DoInvalidateNodeBounds(no blob) on either side of this
02155 ********************************************************************************************/
02156 ActionCode ChangeFeatherEffectProfileAction::Init(  Operation* pOp,
02157                                                     ActionList* pActionList,
02158                                                     NodeFeatherEffect* pFeatherEffect,
02159                                                     CProfileBiasGain FeatherProfile,
02160                                                     ChangeFeatherEffectProfileAction** ppNewAction )
02161 {
02162     UINT32 ActSize = sizeof(ChangeFeatherEffectProfileAction);
02163 
02164     ActionCode Ac = Action::Init(pOp,
02165                                  pActionList,
02166                                  ActSize,
02167                                  CC_RUNTIME_CLASS(ChangeFeatherEffectProfileAction),
02168                                  (Action**)ppNewAction);
02169     if (Ac != AC_FAIL)
02170     {
02171         (*ppNewAction)->m_pFeatherEffect = pFeatherEffect;
02172         (*ppNewAction)->m_LastProfile = FeatherProfile;
02173     }
02174 
02175     return Ac;
02176 }
02177 
02178 
02179 /********************************************************************************************
02180 >   ActionCode ChangeFeatherEffectProfileAction::Execute()
02181     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02182     Created:    27/04/2005
02183     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02184     Purpose:    Executes the action.
02185     Errors:     -
02186     SeeAlso:    Action::Init()
02187 ********************************************************************************************/
02188 ActionCode ChangeFeatherEffectProfileAction::Execute()
02189 {
02190     ActionCode Act = AC_FAIL;
02191     ChangeFeatherEffectProfileAction* pAction;
02192 
02193     // First time an instance of this Action is executed is when called during and
02194     // UndoList->ExecuteBackwards inside an OpUndo invoked OpHist->GetTail()->Undo (where
02195     // the tail OpHist item is an OpChangeFeatherProfile. SHEW!
02196     // However may also be called by a Redo as we are about to stick an instance into the
02197     // Redo list
02198     CProfileBiasGain UndoProf = m_pFeatherEffect->GetProfile();
02199 
02200     Act = ChangeFeatherEffectProfileAction::Init(pOperation, 
02201                                                  pOppositeActLst,
02202                                                  m_pFeatherEffect,
02203                                                  UndoProf,
02204                                                  &pAction );
02205 
02206     if (Act==AC_OK)
02207         m_pFeatherEffect->SetProfile(m_LastProfile);
02208 
02209     if (ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen())
02210     {
02211         // only way I can think of to get the profile dialog to reinialise itself is
02212         // to fake a OnSelChangingMsg message ....
02213 
02214         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::SELECTIONCHANGED, FALSE));
02215     }
02216 
02217     return Act;
02218 }
02219 
02220 
02222 
02223 /********************************************************************************************
02224 >   ActionCode ChangeFeatherEffectAction::Init( Operation*  pOp,
02225                                                 ActionList* pActionList,
02226                                                 NodeFeatherEffect* pFeatherEffect,
02227                                                 MILLIPOINT FeatherSize,
02228                                                 CProfileBiasGain FeatherProfile,
02229                                                 ChangeFeatherEffectAction** ppNewAction )
02230     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02231     Created:    27/04/2005
02232     Inputs:     pOp             = ptr to the operation to which this action belongs
02233                 pActionList     = ptr to Operations action list to which this action should be added
02234                 pFeatherEffect  = ptr to a feather effect
02235                 FeatherSize     = New feather size for pFeather
02236     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02237                                   a pointer to the created action
02238     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02239     SeeAlso:    Action::Init()
02240     Notes:      Doesn't redraw the Node (either before or after the change).
02241                 Bounding Box doesn't change so you don't need to remove blobs before and after
02242                 this action - ie DoInvalidateNodeBounds(no blob) on either side of this
02243 ********************************************************************************************/
02244 ActionCode ChangeFeatherEffectAction::Init( Operation* pOp,
02245                                             ActionList* pActionList,
02246                                             NodeFeatherEffect* pFeatherEffect,
02247                                             MILLIPOINT FeatherSize,
02248                                             CProfileBiasGain FeatherProfile,
02249                                             ChangeFeatherEffectAction** ppNewAction )
02250 {
02251     UINT32 ActSize = sizeof(ChangeFeatherEffectAction);
02252 
02253     ActionCode Ac = Action::Init(pOp,
02254                                  pActionList,
02255                                  ActSize,
02256                                  CC_RUNTIME_CLASS(ChangeFeatherEffectAction),
02257                                  (Action**)ppNewAction);
02258     if (Ac != AC_FAIL)
02259     {
02260         (*ppNewAction)->m_pFeatherEffect = pFeatherEffect;
02261         (*ppNewAction)->m_LastFeatherSize = FeatherSize;
02262         (*ppNewAction)->m_LastProfile = FeatherProfile;
02263     }
02264 
02265     return Ac;
02266 }
02267 
02268 
02269 /********************************************************************************************
02270 >   ActionCode ChangeFeatherEffectAction::Execute()
02271     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02272     Created:    27/04/2005
02273     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02274     Purpose:    Executes the action.
02275     Errors:     -
02276     SeeAlso:    Action::Init()
02277 ********************************************************************************************/
02278 ActionCode ChangeFeatherEffectAction::Execute()
02279 {
02280     ActionCode Act = AC_FAIL;
02281     ChangeFeatherEffectAction* pAction;
02282 
02283     CProfileBiasGain UndoProf = m_pFeatherEffect->GetProfile();
02284     MILLIPOINT UndoSize = m_pFeatherEffect->GetFeatherSize();
02285 
02286     Act = ChangeFeatherEffectAction::Init(pOperation, 
02287                                           pOppositeActLst,
02288                                           m_pFeatherEffect,
02289                                           UndoSize,
02290                                           UndoProf,
02291                                           &pAction );
02292 
02293     if (Act==AC_OK)
02294     {
02295         m_pFeatherEffect->SetFeatherSize(m_LastFeatherSize);
02296         m_pFeatherEffect->SetProfile(m_LastProfile);
02297     }
02298 
02299     if (ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen())
02300     {
02301         // only way I can think of to get the profile dialog to reinitialise itself is
02302         // to fake a OnSelChangingMsg message ....
02303         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::SELECTIONCHANGED, FALSE));
02304 //      BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED)); 
02305     }
02306 
02307     return Act;
02308 }
02309 #endif
02310 
02311 
02313 
02314 RegenerateFeatherContourAction::RegenerateFeatherContourAction()
02315 {
02316     m_pFeather = NULL;
02317     m_pContour = NULL;
02318 }
02319 
02320 RegenerateFeatherContourAction::~RegenerateFeatherContourAction()
02321 {
02322     // must free path on document deletion when actions slaughtered
02323     if (m_pContour)
02324     {
02325         delete m_pContour;
02326     }
02327 }
02328 
02329 /********************************************************************************************
02330 >   ActionCode RegenerateFeatherContourAction::Execute()
02331     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
02332     Created:    2/12/99
02333     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02334     Purpose:    Executes the action.
02335     Errors:     -
02336     SeeAlso:    Action::Init()
02337 ********************************************************************************************/
02338 ActionCode RegenerateFeatherContourAction::Execute()
02339 {
02340     ActionCode Act = AC_FAIL;
02341     RegenerateFeatherContourAction* pAction;
02342 
02343     // First time an instance of this Action is executed is when called during and
02344     // UndoList->ExecuteBackwards inside an OpUndo invoked OpHist->GetTail()->Undo (where
02345     // the tail OpHist item is an OpChangeFeatherProfile. SHEW!
02346     // However may also be called by a Redo as we are about to stick an instance into the
02347     // Redo list
02348     Path* UndoPath = m_pFeather->GetOuterContour();
02349     m_pFeather->SetOuterContour(m_pContour);
02350     m_pContour = NULL;      // prevent ~RegenerateFeatherContourAction from deleting path
02351 
02352     Act = RegenerateFeatherContourAction::Init( pOperation, 
02353                                                 pOppositeActLst,
02354                                                 m_pFeather,
02355                                                 UndoPath,
02356                                                 &pAction );
02357 
02358     if (ChangeFeatherProfileOpDesc::m_BiasGainGadget.IsDialogOpen())
02359     {
02360         // only way I can think of to get the profile dialog to reinialise itself is
02361         // to fake a OnSelChangingMsg message ....
02362 
02363         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::SELECTIONCHANGED, FALSE));
02364     }
02365 
02366     return Act;
02367 }
02368 
02369 /********************************************************************************************
02370 >   ActionCode RegenerateFeatherContourAction::Init(    Operation*  pOp,
02371                                                 ActionList* pActionList,
02372                                                 FeatherAttrValue*   pFeather,
02373                                                 INT32 FeatherSize,
02374                                                 RegenerateFeatherContourAction**    ppNewAction )
02375     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
02376     Created:    2/12/99
02377     Inputs:     pOp             = ptr to the operation to which this action belongs
02378                 pActionList     = ptr to Operations action list to which this action should be added
02379                 pFeather        = ptr to a feather attribute
02380                 FeatherSize     = New feather size for pFeather
02381     Outputs:    ppNewAction     = ptr to a ptr to an action, allowing the function to return
02382                                   a pointer to the created action
02383     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02384     SeeAlso:    Action::Init()
02385     Notes:      Doesn't redraw the Node (either before or after the change).
02386                 Bounding Box doesn't change so you don't need to remove blobs before and after
02387                 this action - ie DoInvalidateNodeBounds(no blob) on either side of this
02388 ********************************************************************************************/
02389 ActionCode RegenerateFeatherContourAction::Init( Operation* pOp,
02390                             ActionList* pActionList,
02391                             FeatherAttrValue* pFeather,
02392                             Path* pFeatherContour,
02393                             RegenerateFeatherContourAction** ppNewAction )
02394 {
02395     UINT32 ActSize = sizeof(RegenerateFeatherContourAction);
02396 
02397     ActionCode Ac = Action::Init(pOp,pActionList,ActSize,CC_RUNTIME_CLASS(RegenerateFeatherContourAction),(Action**)ppNewAction);
02398 
02399     if (Ac != AC_FAIL && *ppNewAction!=NULL)
02400     {
02401         (*ppNewAction)->m_pFeather = pFeather;
02402         (*ppNewAction)->m_pContour = pFeatherContour;
02403     }
02404 
02405     return Ac;
02406 }

Generated on Sat Nov 10 03:46:14 2007 for Camelot by  doxygen 1.4.4