shadtool.cpp

Go to the documentation of this file.
00001 // $Id: shadtool.cpp 1386 2006-06-28 17:49:55Z 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 // Implementation of the Shadow Tool
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "shadtool.h"           // Shadow Tool header
00105 #include "nodecont.h"
00106 //#include "oilkeys.h"
00107 #include "keypress.h"
00108 #include "vkextra.h"
00109 
00110 #ifdef BUILDSHADOWS
00111 
00112 // code headers
00113 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "blobs.h"
00115 #include "csrstack.h"
00116 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 #include "oilfiles.h"
00118 #include "opshadow.h"
00119 #include "shadinfo.h"
00120 #include "toollist.h"
00121 #include "layer.h"
00122 #include "layermsg.h"
00123 #include "nodeshad.h"
00124 
00125 // resource headers
00126 //#include "markn.h"
00127 //#include "shadbar.h"
00128 //#include "shadres.h"
00129 //#include "viewrc.h"
00130 #include "opbevel.h"
00131 //#include "biasres.h"          // bias profile header
00132 #include "objchge.h"
00133 #include "bubbleid.h"
00134 //#include "mario.h"
00135 #include "nodetxts.h"
00136 #include "nodeblnd.h"
00137 #include "nodebldr.h"
00138 #include "slicehelper.h"
00139 #include "opliveeffects.h"
00140 #include "liveeffectstool.h"
00141 #include "ophist.h"
00142 #include "shadinfo.h"
00143 
00144 DECLARE_SOURCE( "$Revision: 1386 $" );
00145 
00146 CC_IMPLEMENT_MEMDUMP(SoftShadowTool,Tool_v1)
00147 CC_IMPLEMENT_DYNCREATE(OpDragCreateShadow2, SelOperation)
00148 CC_IMPLEMENT_DYNCREATE(SaveShadowSettingsAction, Action)
00149 
00150 // Must come after the last CC_IMPLEMENT.. macro
00151 #define new CAM_DEBUG_NEW     
00152 
00153 // default shadow colour is black.
00154 #define DEFAULT_SHADOW_COLOUR   COLOUR_BLACK
00155 
00156 // These are still char* while we wait for resource technology to be developed for modules
00157 TCHAR* SoftShadowTool::FamilyName   = _T("Shadow Tools");
00158 TCHAR* SoftShadowTool::ToolName     = _T("Shadow Tool");
00159 TCHAR* SoftShadowTool::Purpose      = _T("Shadow manipulation");
00160 TCHAR* SoftShadowTool::Author       = _T("DavidMc");
00161 
00162 // Init those other useful static vars
00163 BOOL                    SoftShadowTool::CurrentTool             = FALSE;
00164 SoftShadowInfoBarOp*    SoftShadowTool::pSoftShadowInfoBarOp    = NULL;
00165 UINT32                  SoftShadowTool::StatusID                = _R(IDS_SOFTSHADOWSTATUS_FINDSTART);
00166 
00167 
00168 
00169 /********************************************************************************************
00170 
00171 >   SoftShadowTool::SoftShadowTool()
00172 
00173     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00174     Created:    29/10/96
00175     Purpose:    Default Constructor.
00176                 Other initialisation is done in SoftShadowTool::Init which is called by the Tool Manager
00177     SeeAlso:    SoftShadowTool::Init
00178 
00179 ********************************************************************************************/
00180 SoftShadowTool::SoftShadowTool()
00181 {
00182     pcCurrentCursor = NULL;
00183     m_bBlobRendering = TRUE;
00184     pLastBlobSpread = NULL;
00185     m_iEditStackPos = STACKPOS_TOP;
00186     m_pEditRange = NULL;
00187 }
00188 
00189 
00190 
00191 /********************************************************************************************
00192 
00193 >   SoftShadowTool::~SoftShadowTool()
00194 
00195     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00196     Created:    29/10/96
00197     Purpose:    Destructor (Virtual). Does nothing.
00198 
00199 ********************************************************************************************/
00200 SoftShadowTool::~SoftShadowTool()
00201 {
00202     if (m_pEditRange)
00203     {
00204         delete m_pEditRange;
00205         m_pEditRange = NULL;
00206     }
00207 }
00208 
00209 
00210 
00211 /********************************************************************************************
00212 
00213 >   BOOL SoftShadowTool::Init( INT32 Pass )
00214 
00215     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00216     Created:    29/10/96
00217     Returns:    FALSE if it does not want to be created, TRUE otherwise
00218     Purpose:    Used to check if the Tool was properly constructed
00219     SeeAlso:    SoftShadowTool::SoftShadowTool
00220 
00221 ********************************************************************************************/
00222 BOOL SoftShadowTool::Init()
00223 {
00224     // Declare all your ops here and only succeed if all declarations succeed
00225     BOOL ok = TRUE;
00226     if (ok) 
00227         ok = (  OpApplyShadow::Declare() && 
00228                 OpChangeShadowType::Declare() && 
00229                 OpRemoveShadow::Declare() && 
00230                 OpShadowPosition::Declare() && 
00231                 OpShadowPenumbra::Declare() &&
00232                 OpShadowAngle::Declare() &&
00233                 OpShadowHeight::Declare() &&
00234                 OpShadowScale::Declare() &&
00235                 OpShadowHeightAndAngle::Declare() &&
00236                 OpSaveShadowData::Declare() &&
00237                 OpGlowWidth::Declare() &&
00238                 OpChangeShadowProfile::Declare() &&
00239                 OpChangeShadowDarkness::Declare() &&
00240                 OpDragCreateShadow2::Declare());
00241 
00242 
00243     // This section reads in the infobar definition and creates an instance of
00244     // SoftShadowInfoBarOp.  Also pSoftShadowInfoBarOp, the ptr to the tool's infobar, is set up
00245     // after the infobar is successfully read and created.
00246     if (ok)
00247     {
00248         pSoftShadowInfoBarOp = new SoftShadowInfoBarOp;
00249         ERROR2IF(pSoftShadowInfoBarOp==NULL, FALSE, "Can't create Shadow tool Infobar");
00250         if (pSoftShadowInfoBarOp)
00251             pSoftShadowInfoBarOp->pSoftShadowTool = this;
00252 
00253 /*      CCResTextFile       file;               // Resource File
00254         SoftShadowInfoBarOpCreate BarCreate;            // Object that creates BlankInfoBarOp objects
00255 
00256                 ok = file.open(_R(IDM_SOFTSHADOW_BAR), _R(IDT_INFO_BAR_RES));       // Open resource
00257         if (ok) ok = DialogBarOp::ReadBarsFromFile(file,BarCreate); // Read and create info bar
00258         if (ok) file.close();                                       // Close resource
00259 
00260         ERROR3IF(!ok,"Unable to load shadbar.ini from resource\n"); 
00261 
00262         if (ok)
00263         {
00264             // Info bar now exists.  Now get a pointer to it
00265             String_32 str = String_32(_R(IDS_SHADOWTOOL_INFOBARNAME));
00266             DialogBarOp* pDialogBarOp = DialogBarOp::FindDialogBarOp(str);
00267             ok = (pDialogBarOp != NULL);
00268 
00269             if (ok)
00270                 ok = pDialogBarOp->IsKindOf(CC_RUNTIME_CLASS(SoftShadowInfoBarOp));
00271 
00272             if (ok)
00273             {
00274                 pSoftShadowInfoBarOp = (SoftShadowInfoBarOp*)pDialogBarOp;
00275                 pSoftShadowInfoBarOp->pSoftShadowTool = this;
00276             }
00277         }
00278         
00279         ERROR3IF(!ok,"Error finding the shadow tool info bar");
00280 */  }
00281 
00282     return (ok);
00283 }
00284 
00285 
00286 
00287 /********************************************************************************************
00288 
00289 >   void SoftShadowTool::Describe(void *InfoPtr)
00290 
00291     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00292     Created:    29/10/96
00293     Inputs:     InfoPtr -   A pointer to a tool info block. It is passed cast to void* as
00294                             the version of the tool is unknown at this point. Later versions 
00295                             of the Tool class may have more items in this block, that this 
00296                             tool will not use
00297     Outputs:    InfoPtr -   The structure pointed to by InfoPtr will have had all the info
00298                             that this version of the Tool knows about
00299     Purpose:    Allows the tool manager to extract information about the tool
00300 
00301 ********************************************************************************************/
00302 void SoftShadowTool::Describe(void *InfoPtr)
00303 {
00304     // Cast structure into the latest one we understand.
00305     ToolInfo_v1 *Info = (ToolInfo_v1 *) InfoPtr;
00306 
00307     Info->InfoVersion = 1;
00308     
00309     Info->InterfaceVersion = GetToolInterfaceVersion();  // You should always have this line.
00310         
00311     // These are all arbitrary at present.
00312     Info->Version = 1;
00313     Info->ID      = GetID();
00314     Info->TextID  = _R(IDS_SOFTSHADOW_TOOL);
00315 
00316     Info->Family  = FamilyName;
00317     Info->Name    = ToolName;
00318     Info->Purpose = Purpose;
00319     Info->Author  = Author;
00320 
00321     Info->BubbleID = _R(IDBBL_SOFTSHADOW_TOOLBOX);
00322 }
00323 
00324 
00325 
00326 /********************************************************************************************
00327 
00328 >   virtual void SoftShadowTool::SelectChange(BOOL isSelected)
00329 
00330     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00331     Created:    29/10/96
00332     Inputs:     isSelected  - TRUE  = tool has been selected
00333                             - FALSE = tool has been deselected
00334     Outputs:    -
00335     Returns:    -
00336     Purpose:    Starts up and closes down the blank tool
00337     Errors:     Debug warning if creating the cursor fails.
00338     SeeAlso:    -
00339 
00340 ********************************************************************************************/
00341 void SoftShadowTool::SelectChange(BOOL isSelected)
00342 {
00343     if (isSelected)
00344     {
00345         if (!CreateCursors()) return;
00346         CurrentCursorID = CursorStack::GPush(pcNormalSoftShadowCursor, FALSE);      // Push cursor but don't display now
00347         pcCurrentCursor = pcNormalSoftShadowCursor;
00348 
00349         // This tool is now the current one
00350         CurrentTool = TRUE;
00351         SetShadowEditRangeFromSelection();
00352 
00353         // Create and display the tool's info bar
00354         pSoftShadowInfoBarOp->Create();
00355 
00356         if (pSoftShadowInfoBarOp->pSoftShadowInfoBar)
00357         {
00358             // Update the InfoBar 
00359             pSoftShadowInfoBarOp->UpdateInfoBar();
00360         }
00361 
00362         // Say which blobs should be displayed
00363         BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00364         if (BlobMgr != NULL)
00365         {
00366             // Decide which blobs we will display and tell the blob manager
00367             BlobStyle MyBlobs;
00368             MyBlobs.Tiny = TRUE;
00369             BlobMgr->ToolInterest(MyBlobs);
00370         }
00371 
00372         RenderToolBlobs(Document::GetSelectedSpread(), NULL);
00373     }
00374     else
00375     {
00376         // Deselection - destroy the tool's cursors, if they exist.
00377         if (pcCurrentCursor != NULL)
00378         {
00379             CursorStack::GPop(CurrentCursorID);
00380             pcCurrentCursor = NULL;
00381             CurrentCursorID = 0;
00382         }
00383         DestroyCursors();
00384 
00385         pSoftShadowInfoBarOp->CloseProfileDialog (pSoftShadowInfoBarOp->BiasGainGadget_m);
00386 
00387         // Remove the info bar from view by deleting the actual underlying window
00388         pSoftShadowInfoBarOp->Delete();
00389 
00390         // ensure any tool object blobs are removed.
00391         BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00392         if (BlobMgr != NULL)
00393         {
00394             BlobStyle bsRemoves;
00395             bsRemoves.ToolObject = TRUE;
00396             BlobMgr->RemoveInterest(bsRemoves);
00397         }
00398 
00399         // No longer the current tool
00400         CurrentTool = FALSE;
00401 
00402         RenderToolBlobs(Document::GetSelectedSpread(), NULL);
00403     }
00404 }
00405 
00406 
00407 
00408 /********************************************************************************************
00409 
00410 >   BOOL SoftShadowTool::CreateCursors()
00411 
00412     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00413     Created:    29/10/96
00414     Inputs:     -
00415     Outputs:    -
00416     Returns:    TRUE if all the shadow tool cursors have been successfully created
00417     Purpose:    Creates all the shadow tool cursors
00418     SeeAlso:    -
00419 
00420 ********************************************************************************************/
00421 BOOL SoftShadowTool::CreateCursors()
00422 {
00423     // This tool has just been selected.  Create the cursors.
00424     pcNormalSoftShadowCursor = new Cursor(this, _R(IDC_SOFTSHADOWTOOLCURSOR));
00425     pcBlobSoftShadowCursor = new Cursor(this, _R(IDC_SOFTSHADOWBLOBCURSOR));
00426 
00427     if ( pcNormalSoftShadowCursor==NULL || !pcNormalSoftShadowCursor->IsValid() || 
00428         pcBlobSoftShadowCursor==NULL || !pcBlobSoftShadowCursor->IsValid())
00429     {
00430         DestroyCursors();
00431         return FALSE;
00432     }
00433     else
00434         return TRUE;
00435 }
00436 
00437 
00438 
00439 /********************************************************************************************
00440 
00441 >   void SoftShadowTool::DestroyCursors()
00442 
00443     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00444     Created:    29/10/96
00445     Inputs:     -
00446     Outputs:    -
00447     Returns:    -
00448     Purpose:    Destroys all the Shadow Tool cursors
00449     SeeAlso:    -
00450 
00451 ********************************************************************************************/
00452 void SoftShadowTool::DestroyCursors()
00453 {
00454     if (pcNormalSoftShadowCursor != NULL) delete pcNormalSoftShadowCursor;
00455     if (pcBlobSoftShadowCursor != NULL) delete pcBlobSoftShadowCursor ;
00456 }
00457 
00458 
00459 
00460 /********************************************************************************************
00461 
00462 >   void SoftShadowTool::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00463                         Spread* pSpread )
00464 
00465     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00466     Created:    15/06/2000
00467     Inputs:     PointerPos      DocCoord of the point where the mouse button was clicked.
00468                 Click           The type of click that was detected.
00469                 ClickMods       Any modifiers on the click, eg CTRL/SHIFT held down.
00470                 pSpread         Spread in which the click happened.
00471     Returns:    
00472     Purpose:    The Shadow tool's mouse-click handler.
00473     SeeAlso:    Tool::MouseClick;   ClickType;  ClickModifiers
00474 
00475 ********************************************************************************************/
00476 void SoftShadowTool::OnClick(   DocCoord PointerPos,    ClickType cType,
00477                                 ClickModifiers cMods,   Spread* pSpread )
00478 {
00479     if (cMods.Menu) return;                         // Don't do anything if the user clicked the Menu button
00480 
00481     switch (cType)
00482     {
00483         // if a drag is performed, then we have an Op especially for this contingency :o)
00484         case CLICKTYPE_DRAG:
00485         {
00486             OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_DRAGCREATESHADOW);
00487             DragCreateShadowParam DragParam(this, pSoftShadowInfoBarOp, PointerPos, cMods);
00488             if (pOpDesc != NULL)
00489                 pOpDesc->Invoke(&DragParam);
00490         }
00491         break;
00492         default:
00493         {
00494             // call the base class ....
00495 
00496             DragTool::OnClick (PointerPos, cType, cMods, pSpread);
00497         }
00498         break;
00499     }
00500 }
00501 
00502 
00503 
00504 /********************************************************************************************
00505 
00506 >   void SoftShadowTool::OnMouseMove( DocCoord PointerPos,Spread* pSpread, ClickModifiers ClickMod )
00507 
00508     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00509     Created:    29/10/96
00510     Inputs:     PointerPos  -   The DocCoord of the point where the mouse has moved to
00511                 pSpread     -   The spread in which the move occurred
00512                 ClickMods   -   The state of the various modifiers at the time of the mouse move
00513     Returns:    TRUE if it handled the Click, FALSE otherwise
00514     Purpose:    To handle a Mouse Move event for the Blank Tool.
00515 
00516                 This method lets the tool provide user feedback by changing status line text
00517                 and the mouse cursor, depending on where the mouse is and what modifiers
00518                 the user is pressing at the mo'.
00519 
00520     SeeAlso:    Tool::MouseClick; ClickType; ClickModifiers
00521 
00522 ********************************************************************************************/
00523 void SoftShadowTool::OnMouseMove(DocCoord PointerPos, Spread* pSpread, ClickModifiers ClickMods)
00524 {
00525     String_256 strFeedback;
00526     BOOL bShadowingOn = FigureUserFeedback(&strFeedback, pSpread, PointerPos, ClickMods);
00527 
00528     // we've found something we can drag a shadow from.
00529     if (bShadowingOn)
00530     {
00531         if (pcCurrentCursor != pcBlobSoftShadowCursor)
00532         {
00533             CursorStack::GSetTop(pcBlobSoftShadowCursor, CurrentCursorID);
00534             pcCurrentCursor = pcBlobSoftShadowCursor;
00535         }
00536     }
00537 
00538     // no dragging here, sonny.
00539     else
00540     {
00541         if (pcCurrentCursor != pcNormalSoftShadowCursor)
00542         {
00543             CursorStack::GSetTop(pcNormalSoftShadowCursor, CurrentCursorID);
00544             pcCurrentCursor = pcNormalSoftShadowCursor;
00545         }
00546     }
00547 
00548     // make sure the status line is up to date.
00549     GetApplication()->UpdateStatusBarText(&strFeedback);
00550 }
00551 
00552 
00553 
00554 /********************************************************************************************
00555 
00556 >   virtual BOOL SoftShadowTool::GetStatusLineText(String_256* ptext, Spread* pSpread, DocCoord DocPos, ClickModifiers ClickMods)
00557 
00558     Author:     Olivier_Gascoin (Xara Group Ltd) <camelotdev@xara.com>
00559     Created:    29/10/96
00560     Inputs:     ptest - pointer to a string
00561                 pSpread points to a spread
00562                 DocPos points to a point in a document
00563                 ClickMods are the current click modifiers
00564     Outputs:    Updates the string in ptext
00565     Returns:    TRUE if the string was updates (FALSE if not updated)
00566     Purpose:    Returns the current status line help string
00567     SeeAlso:    SoftShadowTool::GetCurrentStatusText, Tool_v1::GetStatusLineText
00568 
00569 ********************************************************************************************/
00570 BOOL SoftShadowTool::GetStatusLineText(String_256* ptext, Spread* pSpread, DocCoord DocPos, ClickModifiers ClickMods)
00571 {
00572     // We can call the underlying help function to get a string and return the result.
00573     String_256 strFeedback;
00574     FigureUserFeedback(&strFeedback, pSpread, DocPos, ClickMods);
00575 
00576     *ptext += strFeedback;
00577     return TRUE;
00578 }
00579 
00580 
00581 
00582 /********************************************************************************************
00583 
00584 >   BOOL SoftShadowTool::FigureUserFeedback(String_256* pText,      Spread* pSpread,
00585                                             const DocCoord& dcPos,  ClickModifiers cMods)
00586     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00587     Created:    31 August 2000
00588 
00589     Returns:    TRUE if the mouse is in a position where the shadow tool can be used,
00590                 FALSE if the mouse is in a position where the tool cannot be used.
00591 
00592     Purpose:    Determines our status line feedback text, dependent on the mouse position,
00593                 click modifiers etc.
00594 
00595 ********************************************************************************************/
00596 BOOL SoftShadowTool::FigureUserFeedback(String_256* pText,      Spread* pSpread,
00597                                         const DocCoord& dcPos,  ClickModifiers cMods)
00598 {
00599     NodeRenderableInk* pTargetInk = NodeRenderableInk::FindSimpleAtPoint(pSpread, dcPos);
00600 
00601     if (pTargetInk == NULL)
00602     {
00603         // There's nothing under the pointer!
00604         // "Move pointer over object to shadow"
00605         pText->Empty();
00606         pText->Load(_R(IDS_SHADOWSTATUS_MOVEPOINTER));
00607         return FALSE;
00608     }
00609 
00610     // Find out whether the clicked item relates to a shadow in the postprocessor stack
00611 //  Range* pTargetRange = NULL;
00612 //  INT32 iPos = STACKPOS_TOP;
00613 //  BOOL bTopLevel = FALSE;
00614 
00615     // if we're over an existing shadow, tell the user what result dragging will have.
00616     // "Drag to position wall shadows"
00617     // "Drag to change angle and height of floor shadows"
00618     // "Drag left/right or up/down to change width of glow shadows"
00619     if (pTargetInk->IsAShadow())
00620     {
00621         NodeShadowController* pControl = (NodeShadowController*)((NodeShadow*)pTargetInk)->GetParentController();
00622         if (pControl != NULL)
00623         {
00624             ShadowType sType = pControl->GetShadowType();
00625             UINT32 StatusID = 0;
00626             StatusID =  (sType == SHADOWTYPE_WALL)  ? _R(IDS_SHADOWSTATUS_DRAGWALLSHADOWS) :
00627                         (sType == SHADOWTYPE_FLOOR) ? _R(IDS_SHADOWSTATUS_DRAGFLOORSHADOWS) :
00628                         (sType == SHADOWTYPE_GLOW)  ? _R(IDS_SHADOWSTATUS_DRAGGLOWSHADOWS) :
00629                         0;
00630             pText->Empty();
00631             if (StatusID != 0)
00632                 pText->Load(StatusID);
00633             else
00634                 ERROR3("Unrecognised shadow type!");
00635         }
00636         else
00637         {
00638             ERROR3("NodeShadow found without a NodeShadowController!");
00639         }
00640 
00641         return TRUE;
00642     }
00643 
00644     pText->Empty();
00645     pText->Load(_R(IDS_SHADOWSTATUS_DRAGTOSHADOW));
00646 
00647     return TRUE;
00648 }
00649 
00650 
00651 
00652 
00653 /********************************************************************************************
00654 
00655 >   ListRange* SoftShadowTool::GetShadowEditRange(NodeShadowController** ppMasterShadow = NULL)
00656 
00657     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00658     Created:    13/05/2005
00659     Inputs:     -
00660     Outputs:    -
00661     Returns:    Pointer to a range of shadow nodes to operate on (owned by this function, no need to delete)
00662                 NULL if no current range is editable
00663     Purpose:    Find the editable shadow nodes in the current selection
00664     Errors:     -
00665     SeeAlso:    -
00666 
00667 ********************************************************************************************/
00668 
00669 ListRange* SoftShadowTool::GetShadowEditRange(NodeShadowController** ppMasterShadow)
00670 {
00671     // See whether we have a specific list of nodes...
00672 //  if (m_pEditRange && m_pEditRange->MatchesSelectionEffectLevel(m_iEditStackPos))
00673     if (m_pEditRange==NULL)
00674         SetShadowEditRangeFromSelection();
00675 
00676     if (m_pEditRange)
00677     {
00678         if (ppMasterShadow)
00679         {
00680             if (!m_pEditRange->IsEmpty())
00681             {
00682                 ERROR3IF(!m_pEditRange->FindFirst()->IsAShadowController(), "Stored ShadowEditRange contains non-shadow");
00683                 *ppMasterShadow = (NodeShadowController*)m_pEditRange->FindFirst();
00684             }
00685             else
00686                 *ppMasterShadow = NULL;
00687         }
00688 
00689         return m_pEditRange;
00690     }
00691 
00692 /*  // See whether the user has selected shadow nodes himself...
00693     if (SetShadowEditRangeFromSelection())
00694     {
00695         // We found that all nodes in the sel range are shadows
00696         if (ppMasterShadow)
00697         {
00698             ERROR3IF(!m_pEditRange->FindFirst()->IsAShadowController(), "Stored ShadowEditRange contains non-shadow");
00699             *ppMasterShadow = (NodeShadowController*)m_pEditRange->FindFirst();
00700         }
00701 
00702         return m_pEditRange;
00703     }
00704 */
00705     ERROR3("I don't think we should ever get here!");
00706     // Stored edit context doesn't match the current selection
00707     // so we must find the top surface of shadows in the effects stack above the selection
00708     SelRange* pSelRange = GetApplication()->FindSelection();
00709     return pSelRange->GetTopClassRange(CC_RUNTIME_CLASS(NodeShadowController), TRUE, FALSE, (Node**)ppMasterShadow, NULL);
00710 }
00711 
00712 
00713 
00714 
00715 /********************************************************************************************
00716 
00717 >   void SoftShadowTool::SetShadowEditRange(ListRange* pNewRange, INT32 iNewPos, BOOL bConsistent = FALSE)
00718 
00719     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00720     Created:    12/05/2005
00721     Inputs:     pNewRange - pointer to new range to edit
00722                 iStackPos - value of stack pos
00723     Outputs:    -
00724     Returns:    -
00725     Purpose:    Find the editable shadow nodes in the current selection
00726     Errors:     -
00727     SeeAlso:    -
00728 
00729 ********************************************************************************************/
00730 
00731 void SoftShadowTool::SetShadowEditRange(ListRange* pNewRange, INT32 iNewPos, BOOL bConsistent)
00732 {
00733     if (m_pEditRange && m_pEditRange != pNewRange)
00734     {
00735         delete m_pEditRange;
00736         m_pEditRange = NULL;
00737     }
00738 
00739     m_iEditStackPos = iNewPos;
00740     if (pNewRange)
00741         m_pEditRange = new ListRange(pNewRange);
00742     else
00743         m_pEditRange = NULL;
00744 
00745     // Since the user usually indicates a shadow range by selecting shadow nodes
00746     // we must do the same thing for consistency
00747 /*  if (m_pEditRange)
00748     {
00749         NodeRenderableInk::DeselectAll();
00750 
00751         Node* pNode = m_pEditRange->FindFirst();
00752         while (pNode)
00753         {
00754             if (pNode->IsAShadowController())
00755             {
00756                 NodeShadowController* pController = (NodeShadowController*) pNode;
00757                 pController->GetShadow()->Select(FALSE);
00758             }
00759 
00760             pNode = m_pEditRange->FindNext(pNode);
00761         }
00762     }
00763 
00764     // Make sure InfoBar is updated to reflect the new stored edit range
00765     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED));
00766 */
00767 }
00768 
00769 
00770 
00771 
00772 /********************************************************************************************
00773 
00774 >   void SoftShadowTool::SelectShadowRange(ListRange* pNewRange)
00775 
00776     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00777     Created:    11/07/2005
00778     Inputs:     pNewRange - pointer to new range to edit
00779     Outputs:    -
00780     Returns:    -
00781     Purpose:    Find the editable shadow nodes in the current selection
00782     Errors:     -
00783     SeeAlso:    -
00784 
00785 ********************************************************************************************/
00786 
00787 void SoftShadowTool::SelectShadowRange(ListRange* pNewRange)
00788 {
00789     ERROR3IF(pNewRange==NULL, "SelectShadowRange not given range pointer");
00790 
00791     // Make a local copy because the passed-in list may automatically die
00792     // when the selection changes
00793     ListRange myRange(pNewRange);
00794 
00795     NodeRenderableInk::DeselectAll(TRUE, TRUE);
00796     Node* pNode = myRange.FindFirst();
00797     while (pNode)
00798     {
00799         if (pNode->IsAShadowController())
00800         {
00801             NodeShadowController* pController = (NodeShadowController*)pNode;
00802             if (pController->GetShadow())
00803                 pController->GetShadow()->Select(TRUE);
00804         }
00805 
00806         pNode = myRange.FindNext(pNode);
00807     }
00808 
00809     // Make sure InfoBar is updated to reflect the new stored edit range
00810     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED));
00811 }
00812 
00813 
00814 
00815 
00816 /********************************************************************************************
00817 
00818 >   BOOL SoftShadowTool::SetShadowEditRangeFromSelection(BOOL bBroadcast = FALSE)
00819 
00820     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00821     Created:    18/05/2005
00822     Inputs:     -
00823     Outputs:    -
00824     Returns:    -
00825     Purpose:    Scan the selection to see whether it contains just shadow nodes
00826                 and whether they map to a level in the effects stack
00827                 If so, set the edit range from that info
00828     Errors:     -
00829     SeeAlso:    -
00830 
00831 ********************************************************************************************/
00832 
00833 BOOL SoftShadowTool::SetShadowEditRangeFromSelection(BOOL bBroadcast)
00834 {
00835     SelRange mySelRange = *GetApplication()->FindSelection();
00836     mySelRange.SetPromoteToParent(FALSE);
00837 
00838     LiveEffectsTool* pLETool = NULL;
00839     INT32 iPos = 0;
00840     EffectsStack* pStack = mySelRange.GetEffectsStack();
00841     Node* pNode = mySelRange.FindFirst();
00842 //  if (pNode==NULL)
00843 //      return FALSE;
00844 
00845     ListRange* pShadowRange = new ListRange;
00846 
00847     while (pNode)
00848     {
00849         if (pNode->IsAShadowController() && !pShadowRange->Contains(pNode))
00850             pShadowRange->AddNode(pNode);
00851 
00852         else if (pNode->IsAShadow())
00853         {
00854             NodeShadow* pShadow = (NodeShadow*)pNode;
00855             ERROR3IF(pShadow->GetParentController()==NULL, "Shadow has no controller!");
00856             if (!pShadowRange->Contains(pShadow->GetParentController()))
00857                 pShadowRange->AddNode(pShadow->GetParentController());
00858         }
00859 
00860         else
00861         {
00862             Node* pParent = pNode->FindParent();
00863             NodeShadowController* pTopController = NULL;
00864             while (pParent && (pParent->IsEffect() || pParent->IsController()))
00865             {
00866                 if (pParent->IsAShadowController())
00867                     pTopController = (NodeShadowController*)pParent;
00868 
00869                 pParent = pParent->FindParent();
00870             }
00871             if (pTopController && !pShadowRange->Contains(pTopController))
00872                 pShadowRange->AddNode(pTopController);
00873         }
00874 
00875         pNode = mySelRange.FindNext(pNode);
00876     }
00877 
00878     // Let's set up the range we've just made for editing!
00879     if (m_pEditRange)
00880     {
00881         delete m_pEditRange;
00882         m_pEditRange = NULL;
00883     }
00884 
00885     // Here we have a listrange containing only shadow controller nodes
00886     while (iPos < (INT32)pStack->GetCount())
00887     {
00888         if (pShadowRange->MatchesSelectionEffectLevel(iPos))
00889             break;
00890 
00891         iPos++;
00892     }
00893     if (iPos >= (INT32)pStack->GetCount())
00894         iPos = STACKPOS_INVALID;
00895 
00896     // Tell the effects tool about this consistent range of effects
00897     m_iEditStackPos = iPos;
00898     m_pEditRange = pShadowRange;                    // Assign ownership of this list to the class
00899     pLETool = (LiveEffectsTool*)Tool::FindTool(TOOLID_LIVEEFFECT);
00900     if (pLETool)
00901     {
00902         pLETool->SetCurrentEffectID(POSTPRO_ID_SHADOW);
00903         pLETool->SetCurrentStackPos(iPos);
00904     }
00905 
00906     if (bBroadcast)
00907     {
00908         // Make sure InfoBar is updated to reflect the new stored edit range
00909         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::EFFECTSTACKCHANGED));
00910     }
00911     return TRUE;
00912 
00913 //NoSet:
00914 //  if (pShadowRange)
00915 //      delete pShadowRange;
00916 //
00917 //  return FALSE;
00918 }
00919 
00920 
00921 
00922 
00923 /********************************************************************************************
00924 
00925 >   NodeShadowController* SoftShadowTool::GetShadowEditField(ShadowMaskBits flags, String_256* pStrInfo = NULL)
00926 
00927     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00928     Created:    16/05/2005
00929     Inputs:     flags - bitfield describing which fields to search for
00930     Outputs:    -
00931     Returns:    Pointer to a sample node
00932                 NULL if no common nodes could be found
00933     Purpose:    Find the editable shadow nodes with common values in the current selection
00934     Errors:     -
00935     SeeAlso:    -
00936 
00937 ********************************************************************************************/
00938 
00939 NodeShadowController* SoftShadowTool::GetShadowEditField(ShadowMaskBits flags, String_256* pStrInfo)
00940 {
00941     BOOL bNone = TRUE;
00942     BOOL bConsistent = FALSE;
00943     BOOL bMany = FALSE;
00944     NodeShadowController* pMaster = NULL;
00945 
00946     pMaster = GetShadowEditField(flags, &bNone, &bConsistent, &bMany);
00947 
00948     // There are no fields of the required type
00949     if (bNone && pStrInfo!=NULL)
00950         pStrInfo->Load(_R(IDS_SHADOWSTRING_NONE));
00951 
00952     // There are many fields of the required type until we prove otherwise
00953     if (bMany && pStrInfo!=NULL)
00954         pStrInfo->Load(_R(IDS_SHADOWSTRING_MANY));
00955 
00956     // Don't confuse the caller by returning None or Many when there is a consistent value
00957     if (bConsistent && pStrInfo!=NULL)
00958         pStrInfo->Empty();
00959 
00960     return pMaster;
00961 }
00962 
00963 
00964 
00965 
00966 /********************************************************************************************
00967 
00968 >   NodeShadowController* SoftShadowTool::GetShadowEditField(ShadowMaskBits flags, BOOL* pbNone, BOOL* pbConsistent, BOOL* pbMany)
00969 
00970     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00971     Created:    16/05/2005
00972     Inputs:     flags - bitfield describing which fields to search for
00973     Outputs:    -
00974     Returns:    Pointer to a sample node
00975                 NULL if no common nodes could be found
00976     Purpose:    Find the editable shadow nodes with common values in the current selection
00977     Errors:     -
00978     SeeAlso:    -
00979 
00980 ********************************************************************************************/
00981 
00982 NodeShadowController* SoftShadowTool::GetShadowEditField(ShadowMaskBits flags, BOOL* pbNone, BOOL* pbConsistent, BOOL* pbMany)
00983 {
00984     ERROR3IF(pbNone==NULL, "!1");
00985     ERROR3IF(pbConsistent==NULL, "!2");
00986     ERROR3IF(pbMany==NULL, "!3");
00987 
00988     *pbNone = TRUE;
00989     *pbConsistent = FALSE;
00990     *pbMany = FALSE;
00991 
00992     Range* pRange = GetShadowEditRange();
00993     if (pRange==NULL || pRange->IsEmpty())
00994         return NULL;
00995 
00996     *pbNone = FALSE;
00997 
00998     NodeShadowController* pMaster = NULL;
00999     Node* pNode = pRange->FindFirst();
01000     ShadowFieldMask mask(flags);
01001     while (pNode)
01002     {
01003         ENSURE(pNode->IsAShadowController(), "Expected a NodeShadowController in GetShadowField");
01004 
01005         if (pMaster==NULL)
01006             pMaster = (NodeShadowController*)pNode;
01007         else
01008         {
01009             *pbMany = TRUE;
01010             if (!pMaster->CompareState((NodeShadowController*)pNode, mask))
01011                 return NULL;
01012         }
01013 
01014         pNode = pRange->FindNext(pNode);
01015     }
01016 
01017     *pbConsistent = TRUE;
01018     return pMaster;
01019 }
01020 
01021 
01022 
01023 
01024 /********************************************************************************************
01025 
01026 >   virtual BOOL SelectorTool::OnKeyPress(KeyPress* pKey)
01027 
01028     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01029     Created:    23/11/2004
01030     Inputs:     pKey            pointer to a key-press object representing a keystroke.
01031     Outputs:    -
01032     Returns:    TRUE if the key-event is handled, FALSE if not.
01033     Purpose:    Called when a key is pressed of released.  If the key is a "click modifier"
01034                 such as the ALT or CTRL key then the cursor is changed to indicate whatever
01035                 the tool can do with that modifier.
01036     Errors:     -
01037     SeeAlso:    -
01038 
01039 ********************************************************************************************/
01040 
01041 BOOL SoftShadowTool::OnKeyPress(KeyPress* pKey)
01042 {
01043     // Find the current state of the "click" keyboard modifiers...
01044     ClickModifiers ClickMods = ClickModifiers::GetClickModifiers();
01045 
01046     switch (pKey->GetVirtKey())
01047     {
01048     case CAMKEY(1):                                 // toggle tool blobs
01049         if (pKey->IsPress() && !pKey->IsModified())
01050         {
01051             pSoftShadowInfoBarOp->HandleShadowTypeChange(SHADOWTYPE_NONE);
01052             return TRUE;
01053         }
01054         break;
01055 
01056     case CAMKEY(2):                                 // toggle edit blobs
01057         if (pKey->IsPress() && !pKey->IsModified())
01058         {
01059             pSoftShadowInfoBarOp->HandleShadowTypeChange(SHADOWTYPE_WALL);
01060             return TRUE;
01061         }
01062         break;
01063 
01064     case CAMKEY(3):                                 // toggle fill blobs
01065         if (pKey->IsPress() && !pKey->IsModified())
01066         {
01067             pSoftShadowInfoBarOp->HandleShadowTypeChange(SHADOWTYPE_FLOOR);
01068             return TRUE;
01069         }
01070         break;
01071 
01072     case CAMKEY(4):                                 // toggle bounds/rotate blobs
01073         if (pKey->IsPress() && !pKey->IsModified())
01074         {
01075             pSoftShadowInfoBarOp->HandleShadowTypeChange(SHADOWTYPE_GLOW);
01076             return TRUE;
01077         }
01078         break;
01079 
01080     case CAMKEY(5):                                 // toggle bounds/rotate blobs
01081         if (pKey->IsPress() && !pKey->IsModified())
01082         {
01083             pSoftShadowInfoBarOp->HandleShadowTypeChange(SHADOWTYPE_FEATHER);
01084             return TRUE;
01085         }
01086         break;
01087 
01088     case CAMKEY(A):                                 // select all shadows only
01089         if (pKey->IsPress() && !pKey->IsModified())
01090         {
01091             pSoftShadowInfoBarOp->SelectShadowsAlone();
01092             return TRUE;
01093         }
01094         break;
01095     }   
01096 
01097     return FALSE;
01098 }
01099 
01100 
01101 
01102 //-------------------------------------------------------------------------------------------
01103 //-------------------------------------------------------------------------------------------
01104 //-------------------------------------------------------------------------------------------
01105 //-------------------------------------------------------------------------------------------
01106 
01107 
01108 
01109 /********************************************************************************************
01110 
01111 >   OpDragCreateShadow2::OpDragCreateShadow2()
01112 
01113     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01114     Created:    14/06/2000
01115     Purpose:    Constructor.
01116 
01117 ********************************************************************************************/
01118 OpDragCreateShadow2::OpDragCreateShadow2()
01119 {
01120     m_pInfoBar  = NULL;
01121     m_pTool     = NULL;
01122     m_plInitialShadowSettings   = NULL;
01123     m_pOwnedRange = NULL;
01124 }
01125 
01126 
01127 
01128 /********************************************************************************************
01129 
01130 >   OpDragCreateShadow2::~OpDragCreateShadow2()
01131 
01132     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01133     Created:    14/06/2000
01134     Purpose:    Destructor.
01135                 Free any resources used during this drag.
01136 
01137 ********************************************************************************************/
01138 OpDragCreateShadow2::~OpDragCreateShadow2()
01139 {
01140     m_pInfoBar  = NULL;
01141     m_pTool     = NULL;
01142     if (m_plInitialShadowSettings != NULL)
01143     {
01144         m_plInitialShadowSettings->DeleteAll();
01145         delete m_plInitialShadowSettings;
01146         m_plInitialShadowSettings = NULL;
01147     }
01148 
01149     if (m_pOwnedRange)
01150     {
01151         delete m_pOwnedRange;
01152         m_pOwnedRange = NULL;
01153     }
01154 }
01155 
01156 
01157 
01158 /********************************************************************************************
01159 
01160 >   virtual void OpDragCreateShadow2::DoWithParam(OpDescriptor* pOpDesc, OpParam* pOpParam)
01161 
01162     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01163     Created:    14/06/2000
01164     Inputs:     pOpDesc     ptr to the OpDescriptor which invoked this operation.
01165                 pOpParam    parameter structure required by the operation to perform.
01166     Purpose:    Called to start this drag operation.
01167                 Description of behaviour for the various dragging scenarios:
01168 
01169                 Selected    Shadowed    Dragged     Result
01170                 --------    --------    -------     ------
01171                 No          No          Shape       Select shape, then apply & drag shadow.
01172                             Yes         Shape       Select shape, then drag shadow.
01173                                         Shadow      Select shadow, then drag it.
01174                 Yes         No          Shape       Apply and   } drag shadow, and copy its
01175                             Yes         Shape                   } settings to all similar 
01176                                         Shadow                  } shadows in the selection.
01177 
01178     Notes:      Apart from initially biding by the selection rules for groups, it doesn't
01179                 matter whether the target object is grouped or not - we act on the selection.
01180 
01181                 The node on which the drag started determines the behaviour of the drag.
01182                 If it has no shadow, then a default shadow will be applied to it.
01183                 Selected nodes without shadows will have the control shadow applied to them.
01184                 Selected nodes with shadows will only mirror the control shadow if they have
01185                 the same type of shadow.
01186 
01187 ********************************************************************************************/
01188 void OpDragCreateShadow2::DoWithParam(OpDescriptor* pOpDesc, OpParam* pOpParam)
01189 {
01190     // sometimes we work on the selection, and sometimes we change the selection and
01191     // _then_ work on it; either way, we gotta be a selop...
01192     // ps don't know what the BOOLs do - they're one of the few things left from Dave's code.
01193     DoStartSelOp(FALSE, FALSE, FALSE, FALSE);
01194 
01195     // initialise our internal state, partly from the passed-in parameter.
01196     DragCreateShadowParam* pParam = (DragCreateShadowParam*)pOpParam;
01197 
01198     m_pInfoBar          = pParam->m_pInfoBar;
01199     m_pTool             = pParam->m_pTool;
01200     m_InitialPointerPos = pParam->m_PointerPos;
01201 
01202     m_pMasterShadow     = NULL;
01203     if (m_plInitialShadowSettings != NULL)
01204     {
01205         m_plInitialShadowSettings->DeleteAll();
01206         delete m_plInitialShadowSettings;
01207         m_plInitialShadowSettings = NULL;
01208     }
01209 
01210     // -----------------------------------------------------
01211     // get the node under the pointer, and use it to determine our target node for the drag.
01212     // if there is none, then exit.
01213     NodeRenderableInk* pTargetInk = NodeRenderableInk::FindSimpleAtPoint(Document::GetSelectedSpread(),
01214                                                                          m_InitialPointerPos);
01215     if (pTargetInk == NULL)
01216     {
01217         NodeRenderableInk::DeselectAll(TRUE, TRUE);
01218         End();
01219         return;
01220     }
01221     NodeRenderableInk* pTargetCompound = NodeRenderableInk::FindCompoundFromSimple(pTargetInk); // Normal click logic
01222     NodeCompound* pController = pTargetInk->GetParentController();
01223     BOOL bControllerOfSelected = FALSE;
01224     if (pController)
01225         bControllerOfSelected = pController->IsParentOfSelected();
01226 
01227     // By default assume that the selected shadows, as decribed by m_pEditRange will be dragged
01228     // If the clicked node is selected
01229     // Or is the shadow of a selected node
01230     // Or is the inknode of a selected shadow
01231     // Then just use the selection as is
01232     // Otherwise, call Select the clicked object and call SetEditRangeFromSelection
01233 
01234 //  INT32 iPos = STACKPOS_INVALID;
01235 //  BOOL bTopLevel = FALSE;
01236     ListRange* pShadowRange = NULL;
01237 //  ListRange* pTempRange = NULL;
01238 
01239     // Get the master shadow from the current edit range
01240     m_pTool->GetShadowEditRange(&m_pMasterShadow);
01241 
01242     // If the clicked node was a shadow but is not in the selection
01243     if (pTargetInk->IsAShadow())
01244     {
01245         Node* pShadowedInk = NULL;
01246         if (pController && pController->IsAShadowController())
01247         {
01248             pShadowedInk = ((NodeShadowController*)pController)->GetInkNodeFromController();
01249         }
01250 
01251         if (pTargetInk->IsSelected() || pShadowedInk->IsSelected())
01252         {
01253             // Shadow is in selection
01254         }
01255         else
01256         {
01257             // Shadow is not in selection so alter the selection to refer to the
01258             // clicked shadow
01259             NodeRenderableInk::DeselectAll(TRUE, TRUE);
01260             pTargetInk->Select(TRUE);
01261             m_pTool->SetShadowEditRangeFromSelection();
01262             m_pTool->GetShadowEditRange(&m_pMasterShadow);
01263         }
01264     }
01265     else
01266     {
01267         if (pTargetCompound->IsSelected())
01268         {
01269             // Clicked node is in selection
01270         }
01271         else
01272         {
01273             // Clicked node is not in selection
01274             NodeRenderableInk::DeselectAll(TRUE, TRUE);
01275             pTargetCompound->Select(TRUE);
01276             m_pTool->SetShadowEditRangeFromSelection();
01277             m_pTool->GetShadowEditRange(&m_pMasterShadow);
01278         }
01279     }
01280 
01281     // Make sure you call GetShadowEditRange from this point onwards to get the stored COPY of pShadowRange!
01282 
01283     // after all the malarky above, we'll see if we can get the target's shadow controller.
01284     // if we can't, or if the Shift key was pressed, then we'll make a new one.
01285     if (m_pMasterShadow == NULL || pParam->m_ClickMods.Adjust)
01286     {
01287         // Doesn't yet have a shadow so we can create one for the whole selection
01288         NodeShadowParam NSParam(NodeShadowController::DefaultType);
01289         Range TempRange(*GetApplication()->FindSelection());
01290         TempRange.SetPromoteToParent(TRUE);
01291         pShadowRange = OpApplyShadow::DoApplyShadow(this, &TempRange, &NSParam);
01292         m_pOwnedRange = pShadowRange;
01293         m_pTool->SetShadowEditRange(pShadowRange, STACKPOS_TOP, TRUE);
01294 
01295         // Make sure you call GetShadowEditRange from this point onwards to get the stored COPY of pShadowRange!
01296 
01297         // quit gracefully if we can't create it.
01298         if (pShadowRange == NULL)
01299         {
01300             FailAndExecute();
01301             End();
01302             return;
01303         }
01304 
01305         m_pMasterShadow = (NodeShadowController*)pShadowRange->FindFirst();
01306         if (m_pMasterShadow == NULL)
01307         {
01308             FailAndExecute();
01309             End();
01310             return;
01311         }
01312 
01313         SliceHelper::AddNamesToController(this, m_pMasterShadow);
01314     }
01315     else
01316     {
01317         // Find out whether we have a consistent level or not
01318         // (And preserve current shadow settings while we're looking)
01319         pShadowRange = m_pTool->GetShadowEditRange();
01320         Node* pNode = pShadowRange->FindFirst();
01321 //      NodeShadowController* pNewController = NULL;
01322         BOOL bOK;
01323         while (pNode)
01324         {
01325             if (pNode->IsAShadowController())
01326             {
01327                 bOK = m_pMasterShadow->CompareState((NodeShadowController*)pNode) && SaveSettings((NodeShadowController*)pNode);
01328                 if (!bOK)
01329                 {
01330                     FailAndExecute();
01331                     End();
01332                     return;
01333                 }
01334             }
01335             else
01336             {
01337                 FailAndExecute();
01338                 End();
01339                 return;
01340             }
01341 
01342             pNode = pShadowRange->FindNext(pNode);
01343         }
01344     }
01345 
01346     // at this point in the proceedings, we should definitely have a master shadow controller.
01347     // if we don't, then something somewhere has gone fruity :o)
01348     if (m_pMasterShadow == NULL)
01349     {
01350         ERROR3("OpDragCreateShadow2::DoWithParam; Selection problem");
01351         FailAndExecute();
01352         End();
01353         return;
01354     }
01355 
01356     // Conditionally issue redraws if there were other effects above us in the stack
01357     pShadowRange = m_pTool->GetShadowEditRange();
01358     Node* pNode = pShadowRange->FindFirst();
01359 //  NodeShadowController* pNewController = NULL;
01360     BOOL bOK;
01361     bOK = DoInvalidateNodesRegions(*pShadowRange, TRUE, FALSE, FALSE, FALSE);   // Don't recache
01362     if (!bOK)
01363     {
01364         FailAndExecute();
01365         End();
01366         return;
01367     }
01368 
01369     while (pNode)
01370     {
01371         if (pNode->IsAShadowController())
01372         {
01373             NodeShadowController* pController = (NodeShadowController*)pNode;
01374 //          pController->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01375             pController->ReleaseCached(TRUE, FALSE, FALSE, FALSE);
01376         }
01377 
01378         pNode = pShadowRange->FindNext(pNode);
01379     }
01380 
01381     // record initial information from the master shadow.
01382     m_InitialGlowWidth              = m_pMasterShadow->GetGlowWidth();
01383     m_dcInitialWallOffset           = m_pMasterShadow->GetWallShadowOffset();
01384     m_dcInitialFloorShadowVector    = m_pMasterShadow->GetFloorShadowVector();
01385     m_InitialFeatherWidth           = m_pMasterShadow->GetFeatherWidth();
01386 
01387     // tell the info-bar to update itself for whatever objects are now selected.
01388     if (m_pInfoBar != NULL)
01389         m_pInfoBar->UpdateAllGadgets();
01390 
01391     // Prevent re-cacheing during this drag
01392     Operation::SetQuickRender(TRUE);
01393 
01394     // ok, stop faffing around and get on with the drag.
01395     StartDrag(DRAGTYPE_AUTOSCROLL);
01396 }
01397 
01398 
01399 
01400 
01401 /********************************************************************************************
01402 
01403 >   static NodeRenderableInk* OpDragCreateShadow2::GetSelectedShadowFromNode(NodeRenderableInk* pClickedNode)
01404 
01405     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01406     Created:    18/11/2004
01407     Inputs:     pClickedInk - ptr to a simple node which the user has clicked on
01408     Outputs:    ppLevelRange - output ptr to range of NodeShadowControllers
01409     Returns:    NodeRenderableInk* - ptr to a user-selectable node in the postprocessor stack
01410                 above the selection, if present
01411                 NULL otherwise
01412     Purpose:    Determine whether the clicked item is at an editable position in the
01413                 postprocessor stack
01414 
01415 ********************************************************************************************/
01416 NodeRenderableInk* OpDragCreateShadow2::GetSelectedShadowFromNode(NodeRenderableInk* pClickedNode)
01417 {
01418     Node* pUpNode = pClickedNode->FindParent();
01419     while (pUpNode && (pUpNode->IsAShadowController() || pUpNode->IsNodeHidden()))
01420     {
01421         if (pUpNode->IsAShadowController())
01422         {
01423             NodeShadowController* pController = (NodeShadowController*)pUpNode;
01424             NodeShadow* pShadow = pController->GetShadow();
01425             if (pShadow && pShadow->IsSelected())
01426             {
01427                 return pShadow;
01428             }
01429         }
01430 
01431         pUpNode = pUpNode->FindParent();
01432     }
01433 
01434     return NULL;
01435 }
01436 
01437 
01438 
01439 
01440 /********************************************************************************************
01441 
01442 >   virtual void OpDragCreateShadow2::DragPointerMove(  DocCoord PointerPos,
01443                                                         ClickModifiers ClickMods,
01444                                                         Spread* pSpread, BOOL bSolidDrag)
01445     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01446     Created:    14/06/2000
01447     Inputs:     PointerPos      where it's at, man ;)
01448                 ClickMods       what's happenin', man ;)
01449                 pSpread         the spread where the action is, dude ;)
01450 
01451     Purpose:    Called by Camelot's drag code whenever the pointer moves as a shadow is
01452                 being dragged. Updates the master shadow according to the position of the
01453                 mouse pointer, and mirrors the master shadow's settings in all other shadows
01454                 of the same type, which were selected when the drag was started.
01455     Errors:     
01456     See also:   
01457 
01458 ********************************************************************************************/
01459 void OpDragCreateShadow2::DragPointerMove(  DocCoord PointerPos,
01460                                             ClickModifiers ClickMods,
01461                                             Spread* pSpread, BOOL bSolidDrag)
01462 {
01463     // ok, decide how the drag is gonna change our master shadow controller,
01464     // then apply its settings to all other shadows in our shadow-list.
01465 
01466     // the shadow settings are calculated relative to this rectangle.
01467     DocRect drBaseRect = m_pMasterShadow->GetInsideBoundingRect();
01468 
01469     // two useful offset vectors which we use to determine the shadow settings.
01470     DocCoord dcTotalOffset  = PointerPos - m_InitialPointerPos;
01471 
01472     // we have different behaviours, depending on the type of shadow we are dealing with.
01473     switch (m_pMasterShadow->GetShadowType())
01474     {
01475     // wall shadows are simply offset by the pointer.
01476     case SHADOWTYPE_WALL:
01477         {
01478             DocCoord dcControlOffset = m_dcInitialWallOffset + dcTotalOffset;
01479 
01480             // set the same shadow settings in all wall-shadow members of the shadow list.
01481             ChangeAllShadows(&dcControlOffset, NULL, 0, SHADOWTYPE_WALL);
01482 
01483             // update the info-bar with these settings as well:
01484             //  1. to feedback the wall-shadow position in the UI, and
01485             //  2. to keep a record of the most recent wall-shadow settings.
01486             m_pInfoBar->UpdateGadgetPositionShadowX();
01487             m_pInfoBar->UpdateGadgetPositionShadowY();
01488         }
01489         break;
01490 
01491     // floor shadows are positioned so as to maintain two constant values:
01492     //  1. the ratio of the shadow's height to the pointer's height above the shadow's base (alpha).
01493     //  2. the horizontal distance from the pointer to the centre of the shadow (offx / alpha)
01494     //
01495     // in this model, the floor shadow is a parallelogram with a fixed base.
01496     // it has a defining line from the centre of its base to the centre of its top,
01497     // and the control pointer is glued to one of the sides.
01498     case SHADOWTYPE_FLOOR:
01499         {
01500             DocCoord BaseCentre((drBaseRect.hi.x + drBaseRect.lo.x) / 2, drBaseRect.lo.y);
01501             DocCoord InitVector = m_InitialPointerPos - BaseCentre;
01502 
01503             // we don't like a zero initial pointer height.
01504             if (InitVector.y > 0)
01505             {
01506                 DocCoord NewVector  = PointerPos - BaseCentre;
01507 
01508                 const double alpha  = (double)m_dcInitialFloorShadowVector.y / (double)InitVector.y;
01509                 const double offx   = (double)m_dcInitialFloorShadowVector.x - ((double)InitVector.x * alpha);
01510 
01511                 DocCoord    dcControlVector((MILLIPOINT)(0.5 + (double)NewVector.x * alpha + offx),
01512                                             (MILLIPOINT)(0.5 + (double)NewVector.y * alpha)         );
01513 
01514                 // set the same shadow settings in all floor-shadow members of the shadow list.
01515                 ChangeAllShadows(NULL, &dcControlVector, 0, SHADOWTYPE_FLOOR);
01516             }
01517         }
01518         break;
01519 
01520     // it's very hard to accurately feed back glow-width changes, as the outline of the
01521     // shadowed node would need to be taken into account. therefore, we use a clever & quick
01522     // approximation from David's old code - add up the x- and y- offsets from where the
01523     // drag started, taking into account our position relative to the centre of the shadowed
01524     // node. the upshot of this is that vertical or horizontal mouse movements directly
01525     // relate to how wide the glow is.
01526     case SHADOWTYPE_GLOW:
01527         {
01528             if (m_InitialPointerPos.x < drBaseRect.Centre().x)
01529                 dcTotalOffset.x = -dcTotalOffset.x;
01530 
01531             if (m_InitialPointerPos.y < drBaseRect.Centre().y)
01532                 dcTotalOffset.y = -dcTotalOffset.y;
01533 
01534             MILLIPOINT GlowWidth = m_InitialGlowWidth + (dcTotalOffset.x + dcTotalOffset.y);
01535 
01536             if (GlowWidth < 0)
01537                 GlowWidth = 0;
01538 
01539             // set the same shadow settings in all glow-shadow members of the shadow list.
01540             ChangeAllShadows(NULL, NULL, GlowWidth, SHADOWTYPE_GLOW);
01541         }
01542         break;
01543 
01544     case SHADOWTYPE_FEATHER:
01545         {
01546             if (m_InitialPointerPos.x < drBaseRect.Centre().x)
01547                 dcTotalOffset.x = -dcTotalOffset.x;
01548 
01549             if (m_InitialPointerPos.y < drBaseRect.Centre().y)
01550                 dcTotalOffset.y = -dcTotalOffset.y;
01551 
01552             MILLIPOINT FeatherWidth = m_InitialFeatherWidth + (dcTotalOffset.x + dcTotalOffset.y);
01553 
01554             if (FeatherWidth < 0)
01555                 FeatherWidth = 0;
01556 
01557             // set the same shadow settings in all glow-shadow members of the shadow list.
01558             ChangeAllShadows(NULL, NULL, FeatherWidth, SHADOWTYPE_FEATHER);
01559         }
01560         break;
01561 
01562     default:
01563         ERROR3("OpDragCreateShadow2::DragPointerMove; found an unrecognised shadow type!");
01564         return;
01565     }
01566 }
01567 
01568 
01569 
01570 /********************************************************************************************
01571 
01572 >   virtual void OpDragCreateShadow2::DragFinished( DocCoord PointerPos,
01573                                                     ClickModifiers ClickMods,
01574                                                     Spread* pSpread, BOOL bSuccess, BOOL bSolidDrag)
01575     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01576     Created:    14/06/2000
01577     Inputs:     PointerPos      where the pointer is when the drag ends.
01578                 ClickMods       modifiers (eg CTRL/SHIFT) in use when the drag ends.
01579                 pSpread         the spread where the drag is taking place.
01580                 bSuccess        whether the drag finished successfully, or aborted
01581                                 half way through, eg if the user pressed Escape.
01582 
01583     Purpose:    Lets us tidy ourselves up, refresh the view etc. after the drag has finished.
01584                 Used by the shadowing code to save or restore the old shadow settings from
01585                 before the drag.
01586     Errors:     
01587     See also:   
01588 
01589 ********************************************************************************************/
01590 void OpDragCreateShadow2::DragFinished( DocCoord PointerPos, ClickModifiers ClickMods,
01591                                         Spread* pSpread, BOOL bSuccess, BOOL bSolidDrag)
01592 {
01593     // tell the drag framework that we're finished.
01594     EndDrag();
01595 
01596     // Allow re-cacheing after this drag
01597     Operation::SetQuickRender(FALSE);
01598 
01599     // if we've succeeded so far, then attempt to create a new action in which the original
01600     // shadow settings are saved. if there are no saved shadow settings, then we obviously
01601     // don't need to worry about this.
01602 
01603     // also, note that the process of saving settings means that we relinquish control of our
01604     // list of initial settings to the action. to make sure we don't try to access this
01605     // list again, we set our pointer to it to NULL.
01606     if (bSuccess)
01607     {
01608         if (m_plInitialShadowSettings != NULL && !m_plInitialShadowSettings->IsEmpty() )
01609         {
01610             ActionCode ac = SaveShadowSettingsAction::Init( this, GetUndoActionList(),
01611                                                             m_plInitialShadowSettings );
01612             if (ac == AC_FAIL)
01613                 bSuccess = FALSE;
01614             else
01615                 m_plInitialShadowSettings = NULL;
01616         }
01617     }
01618 
01619     if (m_pOwnedRange)
01620     {
01621         delete m_pOwnedRange;
01622         m_pOwnedRange = NULL;
01623     }
01624 
01625     // if something went wrong, eg the user cancelled the drag, then fail,
01626     // and reset all shadows to their initial settings before the drag.
01627     if (!bSuccess)
01628     {
01629         // Force Redraw all the affected regions
01630         ListRange* pShadowRange = m_pTool->GetShadowEditRange();
01631         Node* pNode = pShadowRange->FindFirst();
01632         DocRect drInvalidRegion;
01633         while (pNode)
01634         {
01635             ENSURE(pNode->IsAShadowController(), "Unexpected node type in ChangeAllShadows");
01636             NodeShadowController* pShadowController = (NodeShadowController*)pNode;
01637             NodeShadow* pNodeShadow                 = pShadowController->GetShadow();
01638             drInvalidRegion = drInvalidRegion.Union(pShadowController->GetEffectStackBounds());
01639             pShadowController->ReleaseCached(TRUE, FALSE, FALSE, TRUE); // Parents and derived data only
01640 
01641             // record the current bounds covered by the shadows.
01642             drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
01643 
01644             pNode = pShadowRange->FindNext(pNode);
01645         }
01646 
01647         // redraw the invalidated screen areas.
01648         Document* pDoc  = Document::GetCurrent();
01649         Spread* pSpread = pDoc->GetSelectedSpread();
01650         if (pDoc != NULL && pSpread != NULL)
01651         {
01652             pDoc->ForceRedraw(pSpread, drInvalidRegion, FALSE, NULL, FALSE);    // Don't automatically flush out subtree caches
01653         }
01654 
01655         RestoreSavedSettings();
01656         FailAndExecute();
01657     }
01658     else
01659     {
01660         // Conditionally issue redraws if there were other effects above us in the stack
01661         EffectsStack* pStack = GetApplication()->FindSelection()->GetEffectsStack();    // From cache
01662         ENSURE(pStack, "Something's gone seriously wrong");
01663         if (!pStack->NodeInTopLevel(m_pMasterShadow))
01664         {
01665             ListRange* pShadowRange = m_pTool->GetShadowEditRange();
01666             DoInvalidateNodesRegions(*pShadowRange, TRUE);      // Argh! this function wants an actual Range!
01667         }
01668     }
01669 
01670     // tell the Op system that we're finished.
01671     End();
01672 }
01673 
01674 
01675 
01676 /********************************************************************************************
01677 
01678 >   static BOOL OpDragCreateShadow2::Declare()
01679 
01680     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01681     Created:    14/06/2000
01682     Returns:    TRUE if all went ok,
01683                 FALSE otherwise.
01684     Purpose:    Adds ourself to the list of all known operations.
01685 
01686     See also:   SoftShadowTool::Init(), where this function is called from.
01687 
01688 ********************************************************************************************/
01689 BOOL OpDragCreateShadow2::Declare()
01690 {
01691     return (RegisterOpDescriptor(
01692                                 0, 
01693                                 _R(IDS_DRAGCREATESHADOWOP),
01694                                 CC_RUNTIME_CLASS(OpDragCreateShadow2), 
01695                                 OPTOKEN_DRAGCREATESHADOW,
01696                                 OpDragCreateShadow2::GetState));
01697 }
01698 
01699 
01700 
01701 /********************************************************************************************
01702 
01703 >   static OpState OpDragCreateShadow2::GetState(   String_256* pstrDescription,
01704                                                     OpDescriptor* pOpDesc   )
01705     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01706     Created:    14/06/2000
01707     Returns:    The state of the operation.
01708     Purpose:    Get the state of this operation, ie whether or not it can be invoked.
01709 
01710                 We currently always give an all-clear - this function is really a lot more
01711                 use for Ops which live in menus.
01712 
01713 ********************************************************************************************/
01714 OpState OpDragCreateShadow2::GetState(String_256* pstrDescription, OpDescriptor* pOpDesc)
01715 {
01716     OpState DefaultOpSt;
01717     return DefaultOpSt;
01718 }
01719 
01720 
01721 
01722 /********************************************************************************************
01723 
01724 >   void OpDragCreateShadow2::ChangeAllShadows( DocCoord* pdcWallOffset,
01725                                                 DocCoord* pdcFloorVector,
01726                                                 MILLIPOINT GlowWidth,
01727                                                 ShadowType ChangeType   )
01728     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01729     Created:    16/06/2000
01730     Inputs:     pdcWallOffset   the offset to reset wall shadows with.
01731                 pdcFloorVector  the vector to reset floor shadows with.
01732                 GlowWidth       the width to reset glow shadows with.
01733                 ChangeType      which 
01734 
01735     Outputs:    Shadows of type ChangeType in m_ShadowList have their parameters reset
01736                 accordingly.
01737 
01738     Purpose:    Change all shadows in our list, of type ChangeType, in a way specific to the
01739                 type:
01740                 SHADOWTYPE_WALL     Wall shadow is offset.
01741                 SHADOWTYPE_FLOOR    Floor shadow vector is reset.
01742                 SHADOWTYPE_GLOW     Glow shadow width is reset.
01743 
01744                 Each shadow is regenerated, and the document is refreshed accordingly.
01745 
01746     Errors:     ERROR3 in DEBUG if an invalid ShadowType, or if the specific input
01747                                 parameter relating to the ShadowType is invalid.
01748 
01749                 NB Does *NOT* check for errors in release!
01750 
01751 ********************************************************************************************/
01752 void OpDragCreateShadow2::ChangeAllShadows( DocCoord* pdcWallOffset,
01753                                             DocCoord* pdcFloorVector,
01754                                             MILLIPOINT GlowWidth, ShadowType ChangeType )
01755 {
01756     // input validation, only in _DEBUG.
01757     // Declare this outside the DEBUG bit so it can be used below...
01758     MILLIPOINT FeatherWidth = GlowWidth;
01759     BOOL fInvalidParams = FALSE;
01760     double dFloorShadowAngle = 0;
01761     double dFloorShadowHeight = 0;
01762     switch (ChangeType)
01763     {
01764     case SHADOWTYPE_WALL:
01765         // wall shadows - must have a valid wall offset.
01766         fInvalidParams = (pdcWallOffset == NULL);
01767         break;
01768     case SHADOWTYPE_FLOOR:
01769         // floor shadows - must have a valid floor control vector.
01770         fInvalidParams = (pdcFloorVector == NULL);
01771         if (pdcFloorVector)
01772         {
01773             // Compute common angle and height for all selected floor shadows
01774             INT32 BaseHeight = m_pMasterShadow->GetInsideBoundingRect().Height();
01775             if (BaseHeight > 0)
01776                 dFloorShadowHeight = (double)pdcFloorVector->y / (double)BaseHeight;
01777             else
01778                 dFloorShadowHeight = 1.0;
01779 
01780             if (dFloorShadowHeight > MAXSHADOWHEIGHT)
01781                 dFloorShadowHeight = MAXSHADOWHEIGHT;
01782             else if (dFloorShadowHeight < 0.01)
01783                 dFloorShadowHeight = 0.01;
01784 
01785             // the angle of the floor shadow is the clockwise rotation of the control vector
01786             // from the vertical, in degrees.
01787             // Phil says: ARGH! Should be anti-clockwise from due east! What's wrong with the mathematical convention?
01788             dFloorShadowAngle = pdcFloorVector->AngleFromVertical();
01789             if (dFloorShadowAngle < -MAXSHADOWANGLE)
01790                 dFloorShadowAngle = -MAXSHADOWANGLE;
01791             else if (dFloorShadowAngle > MAXSHADOWANGLE)
01792                 dFloorShadowAngle = MAXSHADOWANGLE;
01793         }
01794         break;
01795     case SHADOWTYPE_GLOW:
01796         // glow shadows - must have a non-negative glow-width.
01797         fInvalidParams = (GlowWidth < 0);
01798         break;
01799     case SHADOWTYPE_FEATHER:
01800         // glow shadows - must have a non-negative glow-width.
01801         fInvalidParams = (FeatherWidth < 0);
01802         break;
01803     default:
01804         // unrecognised ShadowType.
01805         fInvalidParams = TRUE;
01806         break;
01807     }
01808     ERROR3IF(fInvalidParams, "OpDragCreateShadow2::ChangeAllShadows; Invalid input params!");
01809 
01810     // the region to redraw onscreen.
01811     DocRect drInvalidRegion;
01812 
01813     // initialisation - get the bounds of the first shadow on our list.
01814     NodeShadowController* pShadowController = NULL;
01815     NodeShadow* pNodeShadow = NULL;
01816     ENSURE(!drInvalidRegion.IsValid() || drInvalidRegion.IsEmpty(), "bounding rect should be invalid before loop!");
01817 
01818     // apply the new settings to every shadow we have which matches ChangeType.
01819     ListRange* pShadowRange = m_pTool->GetShadowEditRange();
01820     Node* pNode = pShadowRange->FindFirst();
01821     while (pNode)
01822     {
01823         ENSURE(pNode->IsAShadowController(), "Unexpected node type in ChangeAllShadows");
01824         pShadowController   = (NodeShadowController*)pNode;
01825         pNodeShadow         = pShadowController->GetShadow();
01826         drInvalidRegion     = drInvalidRegion.Union(pShadowController->GetEffectStackBounds());
01827         pShadowController->ReleaseCached(TRUE, FALSE, FALSE, TRUE); // Parents and derived data only
01828 
01829         if (pShadowController->GetShadowType() == ChangeType)
01830         {
01831             // record the bounds covered by the shadows before the change.
01832             drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
01833 
01834             // make the change.
01835             switch (ChangeType)
01836             {
01837             case SHADOWTYPE_WALL:
01838                 {
01839                     pShadowController->SetWallShadowOffset(*pdcWallOffset, TRUE);
01840                 }
01841                 break;
01842 
01843             case SHADOWTYPE_FLOOR:
01844                 {
01845 //                  pShadowController->SetFloorShadowVector(*pdcFloorVector);
01846                     pShadowController->SetFloorShadowAngle(dFloorShadowAngle);
01847                     pShadowController->SetFloorShadowHeight(dFloorShadowHeight);
01848                     pShadowController->RegenerateNode(NULL);
01849                 }
01850                 break;
01851 
01852             case SHADOWTYPE_GLOW:
01853                 {
01854                     pShadowController->SetGlowWidth(GlowWidth);
01855                     pShadowController->RegenerateNode(NULL);
01856                 }
01857                 break;
01858 
01859             case SHADOWTYPE_FEATHER:
01860                 {
01861                     pShadowController->SetFeatherWidth(FeatherWidth);
01862                     pShadowController->RegenerateNode(NULL);
01863                 }
01864                 break;
01865 
01866             default:
01867                 // Do nothing
01868                 break;
01869             }
01870 
01871             // record the current bounds covered by the shadows.
01872             drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
01873         }
01874 
01875         // Karim 16/11/2000
01876         // Feathers BODGE - search up the tree for any GeometryLinkedAttrs attached to
01877         // ourself or our parents, and tell them that their linked node geometry has changed.
01878         {
01879             for (Node*  pParent =  pShadowController;
01880                         pParent != NULL && pParent->IsAnObject();
01881                         pParent =  pParent->FindParent() )
01882             {
01883                 for (NodeAttribute* pGLA = pParent->FindFirstGeometryLinkedAttr();
01884                                     pGLA != NULL;
01885                                     pGLA = pGLA->FindNextGeometryLinkedAttr() )
01886                 {
01887                     pGLA->LinkedNodeGeometryHasChanged(this);
01888                 }
01889             }
01890         }
01891 
01892         pNode = pShadowRange->FindNext(pNode);
01893     }
01894 
01895     // redraw the invalidated screen areas.
01896     Document* pDoc  = Document::GetCurrent();
01897     Spread* pSpread = pDoc->GetSelectedSpread();
01898     if (pDoc != NULL && pSpread != NULL)
01899     {
01900         pDoc->ForceRedraw(pSpread, drInvalidRegion, FALSE, NULL, FALSE);    // Don't automatically flush out subtree caches
01901         GetApplication()->ServiceRendering();
01902     }
01903 }
01904 
01905 
01906 
01907 /********************************************************************************************
01908 
01909 >   BOOL OpDragCreateShadow2::SaveSettings(Range* pShadowRange)
01910 
01911     Author:     Phli
01912     Created:    25/11/2004
01913     Inputs:     pShadow     the shadow whose settings we will save.
01914 
01915     Outputs:    m_plInitialShadowSettings is created if necessary,
01916                 and updated with the saved settings.
01917 
01918     Returns:    TRUE if successful,
01919                 FALSE otherwise.
01920 
01921     Purpose:    Record the given shadow's settings.
01922 
01923     Errors:     ERROR3 if pShadow is NULL.
01924     See also:   RestoreSavedSettings().
01925 
01926 ********************************************************************************************/
01927 BOOL OpDragCreateShadow2::SaveSettings(Range* pShadowRange)
01928 {
01929     ERROR3IF(pShadowRange == NULL, "OpDragCreateShadow2::SaveSettings; NULL input params!");
01930 
01931     NodeShadowController* pController = (NodeShadowController*)pShadowRange->FindFirst();
01932     while (pController)
01933     {
01934         BOOL bOK = SaveSettings(pController);
01935         if (!bOK)
01936             return FALSE;
01937 
01938         pController = (NodeShadowController*)pShadowRange->FindNext(pController);
01939     }
01940 
01941     return TRUE;
01942 }
01943 
01944 
01945 
01946 /********************************************************************************************
01947 
01948 >   BOOL OpDragCreateShadow2::SaveSettings(NodeShadowController* pShadow)
01949 
01950     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01951     Created:    17/06/2000
01952     Inputs:     pShadow     the shadow whose settings we will save.
01953 
01954     Outputs:    m_plInitialShadowSettings is created if necessary,
01955                 and updated with the saved settings.
01956 
01957     Returns:    TRUE if successful,
01958                 FALSE otherwise.
01959 
01960     Purpose:    Record the given shadow's settings.
01961 
01962     Errors:     ERROR3 if pShadow is NULL.
01963     See also:   RestoreSavedSettings().
01964 
01965 ********************************************************************************************/
01966 BOOL OpDragCreateShadow2::SaveSettings(NodeShadowController* pShadow)
01967 {
01968     ERROR3IF(pShadow == NULL, "OpDragCreateShadow2::SaveSettings; NULL input params!");
01969 
01970     if (m_plInitialShadowSettings == NULL)
01971     {
01972         ALLOC_WITH_FAIL(m_plInitialShadowSettings, new List, this);
01973         if (m_plInitialShadowSettings == NULL)
01974             return FALSE;
01975     }
01976 
01977     ShadowSettingsItem* pShadowSettings = NULL;
01978     ALLOC_WITH_FAIL(pShadowSettings, new ShadowSettingsItem(pShadow), this);
01979     if (pShadowSettings == NULL)
01980         return FALSE;
01981 
01982     switch (pShadow->GetShadowType())
01983     {
01984     case SHADOWTYPE_WALL:
01985         pShadowSettings->dcWallOffset   = pShadow->GetWallShadowOffset();
01986         break;
01987     case SHADOWTYPE_FLOOR:
01988         pShadowSettings->dcFloorVector  = pShadow->GetFloorShadowVector();
01989         break;
01990     case SHADOWTYPE_GLOW:
01991         pShadowSettings->GlowWidth      = pShadow->GetGlowWidth();
01992         break;
01993     case SHADOWTYPE_FEATHER:
01994         pShadowSettings->FeatherWidth   = pShadow->GetFeatherWidth();
01995         break;
01996     default:
01997         ERROR3("OpDragCreateShadow2::SaveSettings; unrecognised shadow type!");
01998         break;
01999     }
02000 
02001     m_plInitialShadowSettings->AddTail(pShadowSettings);
02002 
02003     return TRUE;
02004 }
02005 
02006 
02007 
02008 /********************************************************************************************
02009 
02010 >   void OpDragCreateShadow2::RestoreSavedSettings()
02011 
02012     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02013     Created:    17/06/2000
02014 
02015     Outputs:    Nothing happens to m_plInitialShadowSettings.
02016 
02017     Purpose:    For all shadows in our saved-settings list, restore their settings to those
02018                 stored with them in the list.
02019 
02020                 Note that this routine also causes the shadows to regenerate, and causes
02021                 redraws for the invalidated areas of the screen.
02022     Errors:     
02023     See also:   
02024 
02025 ********************************************************************************************/
02026 void OpDragCreateShadow2::RestoreSavedSettings()
02027 {
02028     // first of all, check whether we actually have any shadow settings to restore.
02029     if (m_plInitialShadowSettings == NULL || m_plInitialShadowSettings->IsEmpty())
02030         return;
02031 
02032     // the region to redraw onscreen.
02033     DocRect drInvalidRegion;
02034 
02035     // initialisation - get the bounds of the first shadow on our list.
02036     ShadowSettingsItem* pShadowSettings = (ShadowSettingsItem*)m_plInitialShadowSettings->GetHead();
02037     NodeShadowController* pShadowController = pShadowSettings->pShadow;
02038     NodeShadow* pNodeShadow = pShadowController->GetShadow();
02039     drInvalidRegion = pNodeShadow->GetBlobBoundingRect();
02040 
02041     // skip through our list and reset all shadows on it.
02042     while (pShadowSettings != NULL)
02043     {
02044         pShadowController   = pShadowSettings->pShadow;
02045         pNodeShadow         = pShadowController->GetShadow();
02046         drInvalidRegion     = drInvalidRegion.Union(pShadowController->GetEffectStackBounds());
02047         pShadowController->ReleaseCached();
02048         pNodeShadow->ReleaseCached();
02049 
02050         // record the bounds covered by the shadows before the change.
02051         drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
02052 
02053         // change the shadows appropriately.
02054         switch (pShadowController->GetShadowType())
02055         {
02056         case SHADOWTYPE_WALL:
02057             pShadowController->SetWallShadowOffset(pShadowSettings->dcWallOffset, TRUE);
02058             break;
02059         case SHADOWTYPE_FLOOR:
02060             pShadowController->SetFloorShadowVector(pShadowSettings->dcFloorVector);
02061             pShadowController->RegenerateNode(this);
02062             break;
02063         case SHADOWTYPE_GLOW:
02064             pShadowController->SetGlowWidth(pShadowSettings->GlowWidth);
02065             pShadowController->RegenerateNode(this);
02066             break;
02067         case SHADOWTYPE_FEATHER:
02068             pShadowController->SetFeatherWidth(pShadowSettings->FeatherWidth);
02069             pShadowController->RegenerateNode(this);
02070             break;
02071         default:
02072             ERROR3("OpDragCreateShadow2::RestoreSavedSettings; unrecognised shadow type!");
02073             break;
02074         }
02075 
02076         // record the new bounds of the shadows.
02077         drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
02078 
02079         pShadowSettings = (ShadowSettingsItem*)m_plInitialShadowSettings->GetNext(pShadowSettings);
02080     }
02081 
02082     // now redraw the invalid screen-region.
02083     Document*   pDoc    = Document::GetCurrent();
02084     Spread*     pSpread = pDoc->GetSelectedSpread();
02085     if (pDoc != NULL && pSpread != NULL)
02086     {
02087         pDoc->ForceRedraw(pSpread, drInvalidRegion);
02088         GetApplication()->ServiceRendering();
02089     }
02090 }
02091 
02092 
02093 
02094 //-------------------------------------------------------------------------------------------
02095 //-------------------------------------------------------------------------------------------
02096 //-------------------------------------------------------------------------------------------
02097 //-------------------------------------------------------------------------------------------
02098 
02099 
02100 
02101 /********************************************************************************************
02102 
02103 >   SaveShadowSettingsAction::SaveShadowSettingsAction()
02104 
02105     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02106     Created:    20/06/2000
02107     Purpose:    Constructor.
02108 
02109 ********************************************************************************************/
02110 SaveShadowSettingsAction::SaveShadowSettingsAction()
02111 {
02112     m_plShadowSettings = NULL;
02113 }
02114 
02115 
02116 
02117 /********************************************************************************************
02118 
02119 >   SaveShadowSettingsAction::~SaveShadowSettingsAction()
02120 
02121     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02122     Created:    20/06/2000
02123     Purpose:    Destructor - free used resources.
02124 
02125 ********************************************************************************************/
02126 SaveShadowSettingsAction::~SaveShadowSettingsAction()
02127 {
02128     if (m_plShadowSettings != NULL)
02129     {
02130         m_plShadowSettings->DeleteAll();
02131         delete m_plShadowSettings;
02132         m_plShadowSettings = NULL;
02133     }
02134 }
02135 
02136 
02137 
02138 /********************************************************************************************
02139 
02140 >   ActionCode SaveShadowSettingsAction::Init(  UndoableOperation* pUndoOp,
02141 
02142     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02143     Created:    20/06/2000
02144     Inputs:     pUndoOp             ptr to the Op which invokes this action.
02145                 pActionList         ptr to the action list which this action should live on.
02146                 plShadowSettings    ptr to a list of saved shadows & their settings.
02147 
02148     Returns:    AC_OK       if we're successful.
02149                 AC_NORECORD if things went wrong but we can continue, just without undo.    
02150                 AC_FAIL     if things went so wrong that the op will have to rewind itself.
02151 
02152     Purpose:    Doh! Just realised that this action's name is a complete misnomer!
02153                 It actually restores saved shadow settings, given a pointer to a list of
02154                 ShadowSettingsItem's, saving the settings before the restore into a new
02155                 a new action on the opposite undo/redo list.
02156 
02157 ********************************************************************************************/
02158 ActionCode SaveShadowSettingsAction::Init(  UndoableOperation* pUndoOp,
02159                                             ActionList* pActionList,
02160                                             List* plShadowSettings )
02161 {
02162     // call the base class to create and put the action onto the action list.
02163     ActionCode ac = AC_FAIL;
02164     UINT32 ActSize = sizeof(SaveShadowSettingsAction);
02165     SaveShadowSettingsAction* pNewAction = NULL;
02166     ac = Action::Init(  pUndoOp,
02167                         pActionList,
02168                         ActSize,
02169                         CC_RUNTIME_CLASS(SaveShadowSettingsAction),
02170                         (Action**)&pNewAction  );
02171 
02172     // ok, the action now exists.
02173     // initialise it with the passed-in list of saved shadow settings.
02174     if (ac != AC_FAIL && pNewAction != NULL)
02175     {
02176         pNewAction->SetShadowList(plShadowSettings);
02177     }
02178 
02179     return ac;
02180 }
02181 
02182 
02183 
02184 /********************************************************************************************
02185 
02186 >   ActionCode SaveShadowSettingsAction::Execute()
02187 
02188     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02189     Created:    23/06/2000
02190     Inputs:     
02191     Outputs:    
02192     Returns:    
02193     Purpose:    The nitty gritty bit, which is called on undo/redo.
02194     Errors:     
02195     See also:   
02196 
02197 ********************************************************************************************/
02198 ActionCode SaveShadowSettingsAction::Execute()
02199 {
02200     List* plCurrentSettings = NULL;
02201     ALLOC_WITH_FAIL(plCurrentSettings, new List, pOperation);
02202     if (plCurrentSettings == NULL)
02203         return AC_FAIL;
02204 
02205     // first loop - save the current settings for each shadow we'll be changing.
02206     //
02207     ShadowSettingsItem* pOldSettings = NULL;
02208     ShadowSettingsItem* pNewSettings = (ShadowSettingsItem*)m_plShadowSettings->GetHead();
02209     while (pNewSettings != NULL)
02210     {
02211         NodeShadowController* pShadow = pNewSettings->pShadow;
02212 
02213         pOldSettings = NULL;
02214         ALLOC_WITH_FAIL(pOldSettings, new ShadowSettingsItem(pShadow), pOperation);
02215         if (pOldSettings == NULL)
02216         {
02217             plCurrentSettings->DeleteAll();
02218             return AC_FAIL;
02219         }
02220 
02221         switch (pShadow->GetShadowType())
02222         {
02223         case SHADOWTYPE_WALL:
02224             pOldSettings->dcWallOffset  = pShadow->GetWallShadowOffset();
02225             break;
02226         case SHADOWTYPE_FLOOR:
02227             pOldSettings->dcFloorVector = pShadow->GetFloorShadowVector();
02228             break;
02229         case SHADOWTYPE_GLOW:
02230             pOldSettings->GlowWidth     = pShadow->GetGlowWidth();
02231             break;
02232         case SHADOWTYPE_FEATHER:
02233             pOldSettings->FeatherWidth  = pShadow->GetFeatherWidth();
02234             break;
02235         default:
02236             ERROR3("SaveShadowSettingsAction::Execute; unrecognised shadow type!");
02237             break;
02238         }
02239 
02240         plCurrentSettings->AddTail(pOldSettings);
02241 
02242         pNewSettings = (ShadowSettingsItem*)m_plShadowSettings->GetNext(pNewSettings);
02243     }
02244 
02245     // second loop - reset each shadow with the settings stored for it in the list.
02246     //
02247     DocRect drInvalidRegion;
02248 
02249     pNewSettings = (ShadowSettingsItem*)m_plShadowSettings->GetHead();
02250     NodeShadowController* pShadow = pNewSettings->pShadow;
02251     NodeShadow* pNodeShadow = pShadow->GetShadow();
02252     drInvalidRegion = pNodeShadow->GetBlobBoundingRect();
02253 
02254     while (pNewSettings != NULL)
02255     {
02256         pShadow     = pNewSettings->pShadow;
02257         pNodeShadow = pShadow->GetShadow();
02258         drInvalidRegion = drInvalidRegion.Union(pShadow->GetEffectStackBounds());
02259         pShadow->ReleaseCached();
02260         pNodeShadow->ReleaseCached();
02261 
02262         drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
02263 
02264         switch (pShadow->GetShadowType())
02265         {
02266         case SHADOWTYPE_WALL:
02267             pShadow->SetWallShadowOffset(pNewSettings->dcWallOffset, TRUE);
02268             break;
02269         case SHADOWTYPE_FLOOR:
02270             pShadow->SetFloorShadowVector(pNewSettings->dcFloorVector);
02271             pShadow->RegenerateNode((UndoableOperation*)pOperation);
02272             break;
02273         case SHADOWTYPE_GLOW:
02274             pShadow->SetGlowWidth(pNewSettings->GlowWidth);
02275             pShadow->RegenerateNode((UndoableOperation*)pOperation);
02276             break;
02277         case SHADOWTYPE_FEATHER:
02278             pShadow->SetFeatherWidth(pNewSettings->FeatherWidth);
02279             pShadow->RegenerateNode((UndoableOperation*)pOperation);
02280             break;
02281         default:
02282             ERROR3("SaveShadowSettingsAction::Execute; unrecognised shadow type!");
02283             break;
02284         }
02285 
02286         drInvalidRegion = drInvalidRegion.Union(pNodeShadow->GetBlobBoundingRect());
02287 
02288 
02289         pNewSettings = (ShadowSettingsItem*)m_plShadowSettings->GetNext(pNewSettings);
02290     }
02291 
02292     // update the document.
02293     Document*   pDoc    = Document::GetCurrent();
02294     Spread*     pSpread = pDoc->GetSelectedSpread();
02295     if (pDoc != NULL && pSpread != NULL)
02296     {
02297         pDoc->ForceRedraw(pSpread, drInvalidRegion);
02298         GetApplication()->ServiceRendering();
02299     }
02300 
02301     // empty our current list of settings and use our new one to create a new action.
02302     m_plShadowSettings->DeleteAll();
02303     delete m_plShadowSettings;
02304     m_plShadowSettings = NULL;
02305     return SaveShadowSettingsAction::Init(  (UndoableOperation*)pOperation,
02306                                             pOppositeActLst,
02307                                             plCurrentSettings   );
02308 }
02309 
02310 
02311 
02312 #endif  // BUILDSHADOWS

Generated on Sat Nov 10 03:47:57 2007 for Camelot by  doxygen 1.4.4