ngcore.cpp

Go to the documentation of this file.
00001 // $Id: ngcore.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 /*
00099     $Header: /wxCamelot/Kernel/ngcore.cpp 57    17/11/05 15:31 Luke $
00100     Attribute gallery core object
00101 */
00102 
00103 #include "camtypes.h"
00104 
00105 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "ngcore.h"
00107 #include "ngdialog.h"
00108 #include "ngitem.h"
00109 #include "ngprop.h"
00110 #include "ngscan.h"
00111 #include "ngsentry.h"
00112 #include "ngsetop.h"
00113 
00114 #include "comattrmsg.h"
00115 
00116 #include "keypress.h"
00117 #include "sginit.h"
00118 #include "sgmenu.h"
00119 
00120 //#include "galres.h"
00121 //#include "galstr.h"
00122 
00123 #include "helpuser.h"
00124 //#include "xshelpid.h"
00125 //#include "helppath.h"
00126 //#include "mario.h"
00127 
00128 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 #include "userattr.h"
00130 #include "tmpltatr.h"
00131 #include "layer.h"
00132 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00133 #include "objchge.h"
00134 #include "zoomops.h"
00135 #include "transop.h"
00136 //#include "slicetool.h"
00137 //#include "sliceres.h"
00138 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00139 #include "opscale.h"
00140 #include "opsquash.h"
00141 #include "attrappl.h" // Matt - 12/02/2001 - For OpApplyAttribToSelected
00142 #include "ophist.h"
00143 
00144 #ifdef _DEBUG
00145 #undef THIS_FILE
00146 static char BASED_CODE THIS_FILE[] = __FILE__;
00147 #endif
00148 
00149 DECLARE_SOURCE("$Revision: 1282 $");
00150 
00151 // Implement the dynamic class bits...
00152 CC_IMPLEMENT_DYNCREATE(NameGallery, SuperGallery);
00153 
00154 // This line mustn't go before any CC_IMPLEMENT_... macros
00155 #define new CAM_DEBUG_NEW
00156 
00157 #define TIMER_ELAPSE 150
00158 
00159 // The one and only NameGallery object.
00160 NameGallery* NameGallery::m_pInstance = 0;
00161 
00162 
00163 /********************************************************************************************
00164 >   NameGallery::NameGallery()
00165 
00166     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00167     Created:    27/5/99
00168     Purpose:    Constructs a NameGallery object.
00169 ********************************************************************************************/
00170 
00171 NameGallery::NameGallery()
00172   : m_pUsedNames(0),
00173     m_nPropertyIndex(NamedExportProp::nIndex),
00174     m_nRefresh(0),
00175     m_nHiddenUpdates(0),
00176     m_fMenusCreated(FALSE),
00177     m_fChildChanges(FALSE),
00178     m_Timer(this)
00179 {
00180     DlgResID = _R(IDD_NAMESGALLERY);
00181     ERROR3IF(m_pInstance != 0, "NameGallery::NameGallery: instance already exists");
00182     m_pInstance = this;
00183     m_BarToIgnoreTargetsOf = "";
00184     CreateDisplayTree();
00185 }
00186 
00187 
00188 
00189 /********************************************************************************************
00190 >   NameGallery::~NameGallery()
00191 
00192     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00193     Created:    27/5/99
00194     Purpose:    Destroys a NameGallery object.
00195 ********************************************************************************************/
00196 
00197 NameGallery::~NameGallery()
00198 {
00199     m_pInstance = 0;
00200 }
00201 
00202 
00203 
00204 /********************************************************************************************
00205 >   static NameGallery* NameGallery::Instance()
00206 
00207     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00208     Created:    27/5/99
00209     Returns:    The one and only Name gallery object.
00210 ********************************************************************************************/
00211 
00212 NameGallery* NameGallery::Instance()
00213 {
00214 //  ERROR3IF(m_pInstance == 0, "NameGallery::Instance: no gallery");
00215     return m_pInstance;
00216 }
00217 
00218 
00219 
00220 /********************************************************************************************
00221 >   SGNameGroup* NameGallery::GetFirstGroup()
00222 
00223     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00224     Created:    27/5/99
00225     Returns:    The first group within the Name Gallery.
00226 ********************************************************************************************/
00227 
00228 SGNameGroup* NameGallery::GetFirstGroup()
00229 {
00230     return (SGNameGroup*) (DisplayTree != 0 ? DisplayTree->GetChild() : 0);
00231 }
00232 
00233 
00234 
00235 /********************************************************************************************
00236 >   SGUsedNames* NameGallery::GetUsedNames()
00237 
00238     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00239     Created:    27/5/99
00240     Returns:    The 'Used Names' group within the Name Gallery.
00241 ********************************************************************************************/
00242 
00243 SGUsedNames* NameGallery::GetUsedNames()
00244 {
00245     if (DisplayTree == 0) m_pUsedNames = 0;
00246     return m_pUsedNames;
00247 }
00248 
00249 
00250 
00251 /********************************************************************************************
00252 >   INT32 NameGallery::GetPropertyIndex() const
00253 
00254     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00255     Created:    27/5/99
00256     Returns:    The index of the properties currently shown in the gallery.
00257     SeeAlso:    NameGallery::SetPropertyIndex
00258 ********************************************************************************************/
00259 
00260 INT32 NameGallery::GetPropertyIndex() const
00261 {
00262     return m_nPropertyIndex;
00263 }
00264 
00265 
00266 
00267 /********************************************************************************************
00268 >   INT32 NameGallery::SetPropertyIndex(INT32 nNewIndex)
00269 
00270     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00271     Created:    27/5/99
00272     Inputs:     nNewIndex   ---     the new index of the properties to show.
00273                 fRedraw     ---     whether to redraw the gallery to show the new properties
00274     Returns:    The old value of the index.
00275     SeeAlso:    NameGallery::GetPropertyIndex
00276 ********************************************************************************************/
00277 
00278 INT32 NameGallery::SetPropertyIndex(INT32 nNewIndex)
00279 {
00280     ERROR3IF(0 > nNewIndex || nNewIndex >= SGNameProp::nPropertyCount,
00281                                 "NameGallery::GetPropertyIndex: index out of range");
00282     INT32 n = m_nPropertyIndex;
00283     m_nPropertyIndex = nNewIndex;
00284     DisplayDirty();
00285     return n;
00286 }
00287 
00288 
00289 
00290 /********************************************************************************************
00291 >   void NameGallery::GetHighlightCount(INT32* pnTotalItems, INT32* pnJustNames)
00292 
00293     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00294     Created:    27/5/99
00295     Outputs:    pnTotalItems    ---     how many items in total are highlighted
00296                 pnJustNames     ---     how many 'Used Names' are highlighted
00297     Purpose:    Outputs the highlighted status of items in the Attribute gallery.  Used
00298                 by various GetState() functions to  determine the 'grey' status of their
00299                 associated operations.
00300     SeeAlso:    various GetState() functions in kernel\ngsetop.cpp
00301 ********************************************************************************************/
00302 
00303 void NameGallery::GetHighlightCount(INT32* pnTotalItems, INT32* pnJustNames)
00304 {
00305     // At least one output is mandatory (and sane).
00306     ERROR3IF(pnTotalItems == 0 && pnJustNames == 0,
00307                     "NameGallery::GetHighlightCount: null arguments");
00308 
00309     // Count how many SGNameItems are highlighted in all groups.
00310     if (pnTotalItems != 0)
00311         *pnTotalItems = GetSelectedItemCount();
00312     
00313     // Count how many SGNameItems are highlighted in the SGUsedNames group.
00314     if (pnJustNames != 0)
00315         *pnJustNames = (GetUsedNames() != 0) ? GetUsedNames()->GetSelectedItemCount() : 0;
00316 }
00317 
00318 
00319 
00320 /********************************************************************************************
00321 >   void NameGallery::ForceUpdate()
00322 
00323     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00324     Created:    27/5/99
00325     Purpose:    Forces an immediate redraw of the Attribute gallery.  Useful when making
00326                 changes to the status of sets within the document and querying their
00327                 new status before the gallery redraws in the normal course of (idle)
00328                 events.
00329     SeeAlso:    NameGallery::DisplayDirty; NameGallery::OnIdleEvent
00330 ********************************************************************************************/
00331 
00332 void NameGallery::ForceUpdate()
00333 {
00334     DisplayDirty();
00335     //OnIdleEvent();
00336     //OnTimerEvent();
00337 }
00338 
00339 
00340 
00341 /***********************************************************************************************
00342 >   BOOL NameGallery::PreTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam,
00343                                      Range* pRange)
00344 
00345     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> Modified sjk
00346     Created:    27/6/99 - 3/4/00
00347     Inputs:     pOp     ---     UndoableOperation context for edits to triggers
00348                 pParam  ---     for passing to AllowOp calls
00349                 pRange  ---     objects being edited.
00350     Returns:    TRUE if all targets of triggers affected by the edit successfully AllowOp.
00351     Purpose:    AllowOp now called in the PostTrigger bit where all the extending is done.
00352                 The PreTrigger just needs to record the Op ptr so that the extending actions
00353                 can be added to this ops action lists.
00354     SeeAlso:    NameGallery::PostTriggerEdit
00355 ***********************************************************************************************/
00356 
00357 BOOL NameGallery::PreTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam, Range* pRange)
00358 {
00359     // allowops now called for extending in the PostTriggerEdit
00360     m_fChildChanges = TRUE;
00361     m_LastOpUsed = pOp;
00362     m_TouchedBar = -1;
00363     return TRUE;
00364 }
00365 
00366 
00367 
00368 /***********************************************************************************************
00369 >   BOOL NameGallery::PreTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam,
00370                                      Node* pNode)
00371 
00372     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com> Modified sjk
00373     Created:    27/6/99 - 3/4/00
00374     Inputs:     pOp     ---     UndoableOperation context for edits to triggers
00375                 pParam  ---     for passing to AllowOp calls
00376                 pNode   ---     object being edited.
00377     Returns:    TRUE if all targets of triggers affected by the edit successfully AllowOp.
00378     Purpose:    AllowOp now called in the PostTrigger bit where all the extending is done.
00379                 The PreTrigger just needs to record the Op ptr so that the extending actions
00380                 can be added to this ops action lists.
00381     SeeAlso:    NameGallery::PostTriggerEdit
00382 ***********************************************************************************************/
00383 
00384 BOOL NameGallery::PreTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam, Node* pNode)
00385 {
00386     // allowops now called for extending in the PostTriggerEdit
00387     m_fChildChanges = TRUE;
00388     m_LastOpUsed = pOp;
00389     m_TouchedBar = -1;
00390     return TRUE;
00391 }
00392 
00393 
00394 
00395 /***********************************************************************************************
00396 >   BOOL NameGallery::PostTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam)
00397 
00398     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00399     Created:    27/6/99
00400     Inputs:     pOp     ---     UndoableOperation context for edits to triggers
00401                 pParam  ---     for passing to AllowOp calls
00402     Returns:    TRUE if all targets of triggers affected by the edit successfully update.
00403     Purpose:    Does a quick test to see if there are any targets defined.
00404                 If so there may be some stretching to do, so it calls FastApplyStretchScan() to do it.
00405                 Note that FastApplyStretchScan() calls the NoStretchUpdateChangedNodes() version
00406                 of UpdateChangedNodes().
00407     SeeAlso:    NameGallery::PreTriggerEdit
00408     Notes:      This should be called AFTER the UpdateChangedNodes call for the nodes
00409                 directly affected by the given Operation.
00410 ***********************************************************************************************/
00411 
00412 BOOL NameGallery::PostTriggerEdit(UndoableOperation* pOp, ObjChangeParam* pParam)
00413 {
00414     // If there are no triggers/targets affected then there's nothing to do.
00415     if (!m_fChildChanges || (!Document::GetCurrent()->GetSetSentinel()->TargetsExist() && m_TouchedBar == -1) )
00416         return TRUE;
00417 
00418     // Scan for trigger sets which have changed bounds, and stretch/extend their target
00419     // sets appropiately.
00420     BOOL ok = FastApplyStretchScan(*pParam);
00421 
00422     // reset these variables since we have just completed any scans and stretches
00423     // and everything should now be in the right place
00424     m_fChildChanges = FALSE;
00425     m_BarToIgnoreTargetsOf = "";
00426 
00427     return ok;
00428 }
00429 
00430 
00431 
00432 
00433 /********************************************************************************************
00434 >   virtual BOOL NameGallery::PreCreate()
00435 
00436     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00437     Created:    27/5/99
00438     Returns:    TRUE if the Gallery initialised successfully
00439                 FALSE if it should not be opened due to a failure to initialise
00440     Purpose:    The NameGallery PreCreate handler. This overrides the base class
00441                 PreCreate function. It is called at the very beginning of the
00442                 SuperGallery::Create method, before the window has been created.
00443     Notes:      As this is called before the window is open, it must not attempt to touch
00444                 any of the button gadgets in the window, or force redraws, etc. Also,
00445                 events cannot be passed to the tree, as the tree formatting relies on
00446                 knowing the window size - however, the tree will be reformatted and
00447                 redrawn automatically when the window is opened - this will happen shortly.
00448 ********************************************************************************************/
00449 
00450 BOOL NameGallery::PreCreate()
00451 {
00452     // Try to scan through the tree creating items for each set.
00453     CreateDisplayTree();
00454     return CreateDisplayScan().Scan();
00455 }
00456 
00457 
00458 
00459 /********************************************************************************************
00460 >   BOOL NameGallery::CreateDisplayTree()
00461 
00462     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00463     Created:    20/3/00
00464     Purpose:    Initialises the gallery's display tree with the initial groups.
00465     SeeAlso:    NameGallery::FastUpdateNamedSetSizes
00466 ********************************************************************************************/
00467 
00468 BOOL NameGallery::CreateDisplayTree()
00469 {
00470     // If there's no 'selected' document then just destroy the display.
00471     if (Document::GetSelected() == 0 && DisplayTree != 0)
00472     {
00473         DisplayTree->DestroySubtree();
00474         delete DisplayTree;
00475         DisplayTree = 0;
00476         m_pUsedNames = 0;
00477     }
00478 
00479     // Create the display tree, if necessary.
00480     if (DisplayTree == 0)
00481     {
00482         DisplayTree = new SGDisplayRootScroll(this);
00483         ERRORIF(DisplayTree == 0, _R(IDE_NOMORE_MEMORY), FALSE);
00484             
00485         m_pUsedNames = new SGUsedNames;
00486         ERRORIF(m_pUsedNames == 0, _R(IDE_NOMORE_MEMORY), FALSE);
00487         DisplayTree->AddItem(m_pUsedNames);
00488         
00489         SGUsedFonts* pFonts = new SGUsedFonts;
00490         ERRORIF(pFonts == 0, _R(IDE_NOMORE_MEMORY), FALSE);
00491         DisplayTree->AddItem(pFonts);
00492 
00493         SGUsedBitmaps* pBitmaps = new SGUsedBitmaps;
00494         ERRORIF(pBitmaps == 0, _R(IDE_NOMORE_MEMORY), FALSE);
00495         DisplayTree->AddItem(pBitmaps);
00496 
00497         SGUsedColours* pColours = new SGUsedColours;
00498         ERRORIF(pColours == 0, _R(IDE_NOMORE_MEMORY), FALSE);
00499         DisplayTree->AddItem(pColours);
00500     }
00501 
00502     return TRUE;
00503 }
00504 
00505 
00506 
00507 /********************************************************************************************
00508 >   virtual MsgResult NameGallery::Message(Msg* pMessage)
00509 
00510     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00511     Created:    27/5/99
00512     Inputs:     pMessage - The message to handle
00513     Purpose:    A standard message handler, really.
00514     Notes:      Any messages that this does not handle must be passed down to the
00515                 SuperGallery base class message handler.
00516 
00517                 NOTE WELL that the SuperGallery base class handler does some funky things
00518                 for us - see SuperGallery::Message - such as deleting our display subtree
00519                 for any document which dies (which, uncannily, would explain why they go
00520                 away like that when you close documents ;-), and shading the gallery when
00521                 there are no documents present. [To override this behaviour in these cases,
00522                 you should respond to the message, and return OK rather than calling the
00523                 base class message handler]
00524 
00525     SeeAlso:    SuperGallery::Message; NameGallery::UpdateList
00526 ********************************************************************************************/
00527 
00528 MsgResult NameGallery::Message(Msg* pMessage)
00529 {
00530     // Handle clicks on buttons associated with this gallery.
00531     if (IS_OUR_DIALOG_MSG(pMessage))
00532     {
00533         DialogMsg* pMsg = (DialogMsg*) pMessage;
00534         switch (pMsg->DlgMsg)
00535         {
00536         case DIM_CREATE:
00537             SGInit::UpdateGalleryButton( _R(OPTOKEN_DISPLAY_NAME_GALLERY), TRUE);
00538             break;
00539 
00540         case DIM_CANCEL:
00541             SGInit::UpdateGalleryButton( _R(OPTOKEN_DISPLAY_NAME_GALLERY), FALSE);
00542             break;
00543 
00544         case DIM_LFT_BN_CLICKED:
00545             if( _R(IDC_GALLERY_HELP) == pMsg->GadgetID )
00546             {
00547                 HelpUserTopic(_R(IDS_HELPPATH_Gallery_Name)); break;
00548             }
00549             else
00550             if( _R(IDC_GALLERY_NEW)     == pMsg->GadgetID ||
00551                 _R(IDC_NAMEGAL_RENAME)  == pMsg->GadgetID ||
00552                 _R(IDC_NAMEGAL_SELECT)  == pMsg->GadgetID ||
00553                 _R(IDC_NAMEGAL_INTERSECT) == pMsg->GadgetID ||
00554                 _R(IDC_GALLERY_DELETE)  == pMsg->GadgetID ||
00555                 _R(IDC_LIBGAL_REMOVE)   == pMsg->GadgetID ||
00556                 _R(IDC_NAMEGAL_EXPORT)  == pMsg->GadgetID )
00557             {
00558                 // By-pass default base class handling for these buttons so the default
00559                 // bar implementation can automatically invoke the operations defined
00560                 // for them in bars.ini.
00561                 return DialogOp::Message(pMessage);
00562             }
00563             if( _R(IDC_GALLERY_APPLY)   == pMsg->GadgetID ||
00564                 _R(IDC_GALLERY_REDEFINE) == pMsg->GadgetID )
00565             {
00566                 // Do as above, but afterwards check to ensure that (if any of the sets
00567                 // affected is involved in a stretch) no NodeRegularShapes are involved
00568                 MsgResult tempMsg = DialogOp::Message(pMessage);
00569 
00570 
00571                 // For every SGNameItem currently selected, check if it is involved in a stretch...
00572                 NameGallery *pNameGallery = NameGallery::Instance();
00573                 if (!pNameGallery)  { return tempMsg;   }
00574 
00575                 SGUsedNames *pNames = pNameGallery->GetUsedNames();
00576                 if (!pNames)    { return tempMsg;   }
00577 
00578                 SGNameItem *pNameGalleryItem = (SGNameItem*) pNames->GetChild();
00579                 while (pNameGalleryItem)
00580                 {
00581                     if ((SGDisplayNode *)((SGDisplayItem *)pNameGalleryItem)->Flags.Selected)
00582                     {
00583                         NodeSetProperty* pPropNode = pNameGalleryItem->GetPropertyNode();
00584                         if (pPropNode)
00585                         {
00586                             NamedStretchProp* pProp = (NamedStretchProp*) pPropNode->GetProperty(NamedStretchProp::nIndex);
00587                             if (pProp && pProp->GetState())
00588                             {
00589                                 // OK, we should have the NamedStretchProp for the current selected SGNameItem
00590                                 // AND we have checked to see if it is flagged as being stretched by something...
00591                                 // Therefore, we want to check if it contains a NodeRegularShape...
00592                                 if (!pProp->ValidateStretchingObjects(pNameGalleryItem))
00593                                 {
00594                                     InformWarning(_R(IDE_SGNODEREGULARSHAPESDETECTED));
00595                                     return tempMsg;
00596                                 }
00597                             }
00598                         }
00599 
00600                     }
00601 
00602                     pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
00603                 }
00604 
00605                 return tempMsg;
00606             }
00607             break;
00608             
00609         default:
00610             break;
00611         }
00612     }
00613 
00614     // If we've changed to a different document then refresh everything.
00615     else if (MESSAGE_IS_A(pMessage, DocChangingMsg))
00616     {
00617         DocChangingMsg* pMsg = (DocChangingMsg*) pMessage;
00618         if (pMsg->State == DocChangingMsg::SELCHANGED)
00619             DisplayDirty();
00620         else if (pMsg->State == DocChangingMsg::BORN)
00621         {
00622             // set everything into a clean state for the new doc
00623             if (DisplayTree != 0)
00624             {
00625                 DisplayTree->DestroySubtree();
00626                 delete DisplayTree;
00627                 DisplayTree = 0;
00628                 m_pUsedNames = 0;
00629             }
00630 
00631             CreateDisplayTree();
00632         }
00633     }
00634     
00635     // Redraw after an undo, a redo or a successful undoable operation. We use this
00636     // rather blanket approach because there isn't a message sent around to notify us
00637     // of all the possible changes to attributes and objects that interest us.
00638     else if (MESSAGE_IS_A(pMessage, OpMsg))
00639     {
00640         OpMsg* pMsg = (OpMsg*) pMessage;
00641         switch (pMsg->MsgType)
00642         {
00643         case OpMsg::BEGIN:
00644             // An operation is about to be invoked, so clear out the "affected" and
00645             // "child change" flags etc, ready for calls to PreTriggerEdit etc.
00646             m_fChildChanges = FALSE;
00647             break;
00648 
00649         case OpMsg::END:
00650             if (!pMsg->pOp->IS_KIND_OF(UndoableOperation)) break;
00651             // fall through
00652 
00653         case OpMsg::AFTER_UNDO:
00654         case OpMsg::AFTER_REDO:
00655             DisplayDirty();
00656             break;
00657         
00658         default:
00659             break;
00660         }           
00661     }
00662 
00663     // Redraw after changes to the common attributes.  This will catch changes to
00664     // the currently selected objects.
00665     else if (MESSAGE_IS_A(pMessage, CommonAttrsChangedMsg))
00666         DisplayDirty();
00667 
00668     // Always pass messages on for base class handling.
00669     return SuperGallery::Message(pMessage);
00670 }
00671 
00672 
00673 
00674 /********************************************************************************************
00675 >   virtual void NameGallery::DisplayDirty()
00676 
00677     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00678     Created:    27/5/99
00679     Purpose:    Marks a gallery as needing to be refreshed/redrawn on the next idle
00680                 event sent to the NameGallery.
00681     SeeAlso:    NameGallery::Message; NameGallery::OnIdleEvent
00682 ********************************************************************************************/
00683 
00684 // the timer event adds the idle processor
00685 // which adds to the  latency. Ie we wait 150 ms, before waiting for a free cpu cycle (or 2) to do the scan.
00686 // So why do we have a timer in there too? Well the msgs that the name gallery reacts to tend to come in bursts
00687 // so putting a timer in hopes to minimise unneeded scans that are likely to occur when the msg burst occurs.
00688 // The idles were previously being called more optimistically than hoped. (sjk 6/10/00)
00689 BOOL NameGallery::OnTimerEvent()
00690 {
00691     if (m_nRefresh != 0)
00692     {
00693         GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this);
00694         m_Timer.Stop();
00695     }
00696 
00697     return TRUE;
00698 }
00699 
00700  
00701 
00702 void NameGallery::DisplayDirty()
00703 {
00704     // If the gallery display exists and isn't visible then just remember that it needs
00705     // refreshing when it next shows.
00706 
00707     if (!IsVisible())
00708     {
00709         // needs updating later
00710         m_nHiddenUpdates++;
00711         return;
00712     }
00713 
00714     // If going from the clean to the dirty state then send the gallery high
00715     // priority idle events.
00716     // needs updating very soon now
00717     if (m_nRefresh++ == 0)
00718         m_Timer.Start(TIMER_ELAPSE, TRUE);
00719 }
00720 
00721 
00722 
00723 /********************************************************************************************
00724 >   virtual BOOL NameGallery::OnIdleEvent()
00725 
00726     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00727     Created:    27/5/99
00728     Purpose:    Called on idle events.  Updates the selection if it's been changed, and
00729                 recreates and redraws SGNameGroups if the named objects in their
00730                 associated Documents have been changed.
00731     Notes:      We bypass the standard SuperGallery OnIdleEvent background redraw code as
00732                 we may have to destroy SGNameItems during the refresh operation, which
00733                 cannot be done during the HandleEvent processing.
00734     SeeAlso:    NameGallery::Message; NameGallery::OnIdleEvent; SGNameGroup::SetRefresh;
00735                 Application::RegisterIdleProcessor
00736 ********************************************************************************************/
00737 
00738 BOOL NameGallery::OnIdleEvent()
00739 {
00740     // If they're out of date, recreate the items in this group and redraw them.
00741     if (m_nRefresh != 0)
00742     {
00743         // Reconstruct and redraw the display tree.
00744         PreCreate();
00745         if (IsVisible())
00746             ForceRedrawOfList();
00747 
00748         // Kill idle events now the update has been done.
00749         GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this);
00750         m_nRefresh = 0;
00751 
00752         // Inform the zoom combo that it needs to be updated.
00753         if (DocView::GetCurrent() != 0)
00754             OpZoomComboDescriptor::Update(TRUE);
00755     }
00756 
00757     // Don't call the base class handler.
00758     return FALSE;   // we don't want more idles - we've either removed ourself or nothing is out of date
00759 }
00760 
00761 
00762 
00763 /********************************************************************************************
00764 >   virtual OpState NameGallery::GetCommandState(StringBase* pstrCommandID,
00765                                                  String_256* pstrShade)
00766 
00767     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00768     Created:    15/5/99
00769     Inputs:     pstrCommandID   ---     the ID of the command
00770     Outputs:    pstrShade       ---     if returning (OpState.Greyed == TRUE) then this 
00771                                         is set to the reason that the item is shaded/greyed.
00772     Returns:    An OpState indicating the current menu item state.
00773     Purpose:    To determine the state of a given menu item. This method is an exact
00774                 parallel to an Op's GetState method (in fact, it is called by an Op's
00775                 GetState).
00776     Notes:      Override this method to provide state info for your special commands
00777                 Call the base class for unknown commands.
00778 
00779                 The base class handles all of these (maybe more - see the base class help)
00780                     Properties, Sort, Find;
00781                     New, Edit, Delete, Redefine;
00782                     NextGroup, PrevGroup, FoldGroup, UnfoldGroup;
00783 ********************************************************************************************/
00784 
00785 OpState NameGallery::GetCommandState(StringBase* pstrCommandID, String_256* pstrShade)
00786 {
00787     // Delegate to the corresponding operations or base class.
00788     const TCHAR* pTok;
00789          if (*pstrCommandID == SGCmd_New)           pTok = OPTOKEN_NAME_OBJECTS_DLG;
00790     else if (*pstrCommandID == SGCmd_Rename)        pTok = OPTOKEN_RENAME_OBJECTS_DLG;
00791     else if (*pstrCommandID == SGCmd_Select)        pTok = OPTOKEN_SELECT_UNION_SETS;
00792     else if (*pstrCommandID == SGCmd_Intersect)     pTok = OPTOKEN_SELECT_INTERSECT_SETS;
00793     else if (*pstrCommandID == SGCmd_Apply)         pTok = OPTOKEN_APPLY_NAMES_TO_SEL;
00794     else if (*pstrCommandID == SGCmd_RemoveNames)   pTok = OPTOKEN_REMOVE_NAMES_FROM_SEL;
00795     else if (*pstrCommandID == SGCmd_Redefine)      pTok = OPTOKEN_REDEFINE_NAMES_AS_SEL;
00796     else if (*pstrCommandID == SGCmd_Delete)        pTok = OPTOKEN_DELETE_NAMES_FROM_ALL;
00797     else if (*pstrCommandID == SGCmd_Export)        pTok = OPTOKEN_EXPORT_SETS;
00798     else
00799         return SuperGallery::GetCommandState(pstrCommandID, pstrShade);
00800 
00801     OpDescriptor* pDesc = OpDescriptor::FindOpDescriptor((TCHAR*) pTok);
00802     ERROR3IF(pDesc == 0, "NameGallery::GetCommandState: can't find descriptor");
00803     return pDesc->GetOpsState(pstrShade);
00804 }
00805 
00806 
00807 
00808 /********************************************************************************************
00809 >   virtual void NameGallery::DoCommand(StringBase* pstrCommandID)
00810 
00811     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00812     Created:    15/5/99
00813     Inputs:     pstrCommandID   ---     the ID of the command
00814     Purpose:    Overrides the default virtual function in the SuperGallery base class so
00815                 as to handle the custom SGACTION_UNNAME command etc.
00816 ********************************************************************************************/
00817 
00818 void NameGallery::DoCommand(StringBase* pstrCommandID)
00819 {
00820     // Deletegate to the ops or the base class.
00821     const TCHAR* pTok;
00822          if (*pstrCommandID == SGCmd_New)           pTok = OPTOKEN_NAME_OBJECTS_DLG;
00823     else if (*pstrCommandID == SGCmd_Rename)        pTok = OPTOKEN_RENAME_OBJECTS_DLG;
00824     else if (*pstrCommandID == SGCmd_Select)        pTok = OPTOKEN_SELECT_UNION_SETS;
00825     else if (*pstrCommandID == SGCmd_Intersect)     pTok = OPTOKEN_SELECT_INTERSECT_SETS;
00826     else if (*pstrCommandID == SGCmd_Apply)         pTok = OPTOKEN_APPLY_NAMES_TO_SEL;
00827     else if (*pstrCommandID == SGCmd_RemoveNames)   pTok = OPTOKEN_REMOVE_NAMES_FROM_SEL;
00828     else if (*pstrCommandID == SGCmd_Redefine)      pTok = OPTOKEN_REDEFINE_NAMES_AS_SEL;
00829     else if (*pstrCommandID == SGCmd_Delete)        pTok = OPTOKEN_DELETE_NAMES_FROM_ALL;
00830     else if (*pstrCommandID == SGCmd_Export)        pTok = OPTOKEN_EXPORT_SETS;
00831     else
00832     {
00833         SuperGallery::DoCommand(pstrCommandID);
00834         return;
00835     }
00836 
00837     OpDescriptor* pDesc = OpDescriptor::FindOpDescriptor((TCHAR*) pTok);
00838     ERROR3IF(pDesc == 0, "NameGallery::DoCommand: can't find descriptor");
00839     pDesc->Invoke();
00840 }
00841 
00842 
00843 
00844 /********************************************************************************************
00845 >   virtual BOOL NameGallery::InitMenuCommands()
00846                                                  
00847     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00848     Created:    18/5/99
00849     Returns:    TRUE if successful.
00850     Purpose:    Initialises the pop-up menu commands used by the gallery.
00851 ********************************************************************************************/
00852 
00853 BOOL NameGallery::InitMenuCommands()
00854 {
00855     // Menus are only initialised once.
00856     if (m_fMenusCreated) return TRUE;
00857     return m_fMenusCreated =
00858                 InitMenuCommand((StringBase*) &SGCmd_Find,          _R(IDS_SGMENU_FIND))
00859              && InitMenuCommand((StringBase*) &SGCmd_Apply,         _R(IDS_SGMENU_APPLY))
00860              && InitMenuCommand((StringBase*) &SGCmd_RemoveNames,   _R(IDS_SGMENU_REMOVE_NAMES))
00861              && InitMenuCommand((StringBase*) &SGCmd_Redefine,      _R(IDS_SGMENU_REDEFINE))
00862              && InitMenuCommand((StringBase*) &SGCmd_Select,        _R(IDS_SGMENU_SELECT))
00863              && InitMenuCommand((StringBase*) &SGCmd_Intersect,     _R(IDS_SGMENU_INTERSECT))
00864              && InitMenuCommand((StringBase*) &SGCmd_New,           _R(IDS_SGMENU_NEW))
00865              && InitMenuCommand((StringBase*) &SGCmd_Rename,        _R(IDS_SGMENU_RENAME))
00866              && InitMenuCommand((StringBase*) &SGCmd_Delete,        _R(IDS_SGMENU_DELETE))
00867              && InitMenuCommand((StringBase*) &SGCmd_Export,        _R(IDS_SGMENU_EXPORT))
00868              && InitMenuCommand((StringBase*) &SGCmd_FoldGroup,     _R(IDS_SGMENU_FOLD))
00869              && InitMenuCommand((StringBase*) &SGCmd_UnfoldGroup,   _R(IDS_SGMENU_UNFOLD))
00870              && InitMenuCommand((StringBase*) &SGCmd_PrevGroup,     _R(IDS_SGMENU_PREVGROUP))
00871              && InitMenuCommand((StringBase*) &SGCmd_NextGroup,     _R(IDS_SGMENU_NEXTGROUP));
00872 }
00873 
00874 
00875 
00876 /********************************************************************************************
00877 >   virtual BOOL NameGallery::BuildCommandMenu(GalleryContextMenu* pMenu, SGMenuID id)
00878 
00879     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00880     Created:    15/5/99
00881     Inputs:     pMenu   ---     the menu to add commands to
00882                 id      ---     the menu type (over-list or options-button) to create
00883     Returns:    TRUE if successful.
00884     Purpose:    Builds the pop-menu for gallery items.
00885 ********************************************************************************************/
00886 
00887 BOOL NameGallery::BuildCommandMenu(GalleryContextMenu* pMenu, SGMenuID id)
00888 {
00889     // Only handle pop-ups over display items.
00890     if (id == SGMENU_OVERITEM)
00891     {
00892         SGNameGroup* pGroup = (SGNameGroup*) FindCommandGroup();
00893         return AddCommand(pMenu, (StringBase*) &SGCmd_Find, TRUE)
00894             && AddCommand(pMenu, (StringBase*) &SGCmd_Apply)
00895             && AddCommand(pMenu, (StringBase*) &SGCmd_RemoveNames)
00896             && AddCommand(pMenu, (StringBase*) &SGCmd_Redefine, TRUE)
00897             && AddCommand(pMenu, (StringBase*) &SGCmd_Select)
00898             && AddCommand(pMenu, (StringBase*) &SGCmd_Intersect, TRUE)
00899             && AddCommand(pMenu, (StringBase*) &SGCmd_New)
00900             && AddCommand(pMenu, (StringBase*) &SGCmd_Rename)
00901             && AddCommand(pMenu, (StringBase*) &SGCmd_Delete, TRUE)
00902             && AddCommand(pMenu, (StringBase*) &SGCmd_Export, TRUE)
00903             && AddCommand(pMenu, (StringBase*) ((pGroup == 0 || !pGroup->Flags.Folded)
00904                                                     ? &SGCmd_FoldGroup : &SGCmd_UnfoldGroup))
00905             && AddCommand(pMenu, (StringBase*) &SGCmd_PrevGroup)
00906             && AddCommand(pMenu, (StringBase*) &SGCmd_NextGroup);
00907     }
00908 
00909     // For all other menus just do the default.
00910     return SuperGallery::BuildCommandMenu(pMenu, id);
00911 }
00912 
00913 
00914 
00915 /********************************************************************************************
00916 >   virtual BOOL NameGallery::ApplyAction(SGActionType nAction)
00917 
00918     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00919     Created:    15/5/99
00920     Inputs:     nAction     ---     the SGACTION_XXX to perform.
00921     Returns:    TRUE if successful.
00922     Purpose:    Default handler for standard SGACTION_XXX commands.  Only implements
00923                 SGACTION_APPLY(ADJUST), as required by SGDisplayNode::DefaultClickHandler.
00924                 All Attribute gallery buttons (except for Help) are in fact proper
00925                 stand-alone Camelot operations attached to particular button gadgets
00926                 and hence their clicking bypasses the default gallery code.
00927 ********************************************************************************************/
00928 
00929 BOOL NameGallery::ApplyAction(SGActionType nAction)
00930 {
00931     switch (nAction)
00932     {
00933     case SGACTION_APPLY:
00934     case SGACTION_APPLYADJUST:
00935         {
00936             OpDescriptor* pDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_APPLY_NAMES_TO_SEL);
00937             ERROR3IF(pDesc == 0, "NameGallery::ApplyAction: no descriptor");
00938             String_256 str;
00939             if (!pDesc->GetOpsState(&str).Greyed)
00940                 pDesc->Invoke();
00941         }
00942         return TRUE;
00943         
00944     default:
00945         break;
00946     }
00947 
00948     return SuperGallery::ApplyAction(nAction);
00949 }
00950 
00951 
00952 
00953 /********************************************************************************************
00954 >   virtual void NameGallery::SelectionHasChanged()
00955 
00956     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00957     Created:    15/5/99
00958     Purpose:    Overrides default SuperGallery button state handling to do nothing.
00959 ********************************************************************************************/
00960 
00961 void NameGallery::SelectionHasChanged()
00962 {
00963     // Do nothing except notify the system that its UI state has changed - the state of
00964     // all gallery buttons is determined by the operations they are attached to, allowing
00965     // them to be stand-alone in the original Camelot style.  The base class model is only
00966     // used for the display tree redraw and click handling.
00967     DialogBarOp::SetSystemStateChanged(TRUE);
00968 }
00969 
00970 
00971 
00972 /********************************************************************************************
00973 >   virtual void NameGallery::SetVisibility(BOOL fOpen)
00974 
00975     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00976     Created:    15/5/99
00977     Purpose:    Overrides default SuperGallery hide/show handling to force an update to
00978                 the gallery when 
00979 ********************************************************************************************/
00980 
00981 void NameGallery::SetVisibility(BOOL fOpen)
00982 {
00983     SuperGallery::SetVisibility(fOpen);
00984     if (fOpen && m_nHiddenUpdates != 0)
00985     {
00986         m_nHiddenUpdates = 0;
00987         DisplayDirty();
00988     }
00989 }
00990 
00991 
00992 /********************************************************************************************
00993 >   BOOL NameGallery::FastUpdateNamedSetSizes(BOOL PropagateChanges = TRUE)
00994 
00995     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00996     Created:    3/3/00
00997     Inputs:     PropagateChanges - 
00998     Purpose:    The scans are too slow and this replaces the ForceRedraw function when in the
00999                 middle of an op which just updates the sizes of the named sets and NOTHING ELSE.
01000                 No node is looked at twice, and retests for "most likely" name gallery item first.
01001 ********************************************************************************************/
01002 BOOL NameGallery::FastUpdateNamedSetSizes(BOOL PropagateChanges)
01003 {
01004     TRACEUSER( "GerryX", _T("FastUpdateNamedSetSizes(%s)\n"), PropagateChanges ? _T("TRUE") : _T("FALSE") );
01005 
01006     // scan the tree looking for name attribs
01007     // find one and the size of the parent should be added to the bounds of the set
01008     Spread * pSpread =  Document::GetSelectedSpread();
01009     if (!pSpread)
01010         return FALSE;
01011 
01012     Node *pParent = NULL;
01013     SGUsedNames* pNames = GetUsedNames();
01014     if (!pNames)
01015         return FALSE;
01016 
01017     SGNameItem* pNameGalleryItem = NULL; 
01018 
01019     // reset all the names
01020     pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01021 
01022     while (pNameGalleryItem)
01023     {
01024         pNameGalleryItem->Reset(PropagateChanges);
01025         pNameGalleryItem->m_BarNumber = -1;
01026         pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
01027     }
01028 
01029     String_256 str;
01030     String_256 AttrStr;
01031     String_256 BarName;
01032 
01033     // scan each layer
01034     Node * pTop = pSpread;
01035     Node * pNode = NULL;
01036     BOOL CheckLastAgainQuickly = TRUE;
01037 
01038     if (pTop)
01039     {
01040         // scan from the first layer all through the layers since they are brothers of this layer
01041         pNode = SliceHelper::FindNextNameNode(pTop, pTop);
01042 
01043         // check all the name gallery items
01044         while (pNode)
01045         {
01046             // if I have a last looked at gallery item, its a fair bet for the next one along
01047             CheckLastAgainQuickly = TRUE;
01048             if (!pNameGalleryItem)
01049             {
01050                 pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01051                 CheckLastAgainQuickly = FALSE;
01052             }
01053 
01054             AttrStr = ((TemplateAttribute *)pNode)->GetParam();
01055             pParent = pNode->FindParent();
01056 
01057             // which set is it part of?
01058             while (pNameGalleryItem)
01059             {
01060                 pNameGalleryItem->GetNameText(&str);
01061                 // if the name matches its your man
01062                 if (str.CompareTo(AttrStr) == 0)
01063                 {
01064                     pNameGalleryItem->Include(pParent);
01065                     BarName = SliceHelper::GetBarName((TemplateAttribute *)pNode);
01066                     if (BarName[0] && pNameGalleryItem->m_BarNumber == -1)
01067                     {
01068                         pNameGalleryItem->m_BarNumber = SliceHelper::GetBarNumberFromBarName(BarName);
01069 //                      TRACEUSER( "GerryX", _T("found bar %d\n"), pNameGalleryItem->m_BarNumber);
01070                     }
01071                     break; // shortcut out
01072                 }
01073 
01074                 // no then try the next name set?
01075                 if (CheckLastAgainQuickly)
01076                 {
01077                     CheckLastAgainQuickly = FALSE;
01078                     pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01079                 }
01080                 else
01081                     pNameGalleryItem = (SGNameItem*) pNameGalleryItem->GetNext();
01082             }
01083 
01084             // add this new name to the list
01085             if (!pNameGalleryItem)
01086             {
01087                 pNameGalleryItem = pNames->RegisterMember(pParent, AttrStr);
01088 
01089                 // and what bar is it associated with?
01090                 if (pNameGalleryItem)
01091                 {
01092                     BarName = SliceHelper::GetBarName((TemplateAttribute *)pNode);
01093                     if (BarName[0])
01094                         pNameGalleryItem->m_BarNumber = SliceHelper::GetBarNumberFromBarName(BarName);
01095                     else
01096                         pNameGalleryItem->m_BarNumber = -1;
01097                 }
01098             }
01099 
01100             pNode = SliceHelper::FindNextNameNode(pNode, pTop);
01101         }
01102     }
01103 
01104     TRACEUSER( "GerryX", _T("Named Sets\n"));
01105     pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01106     while (pNameGalleryItem)
01107     {
01108         pNameGalleryItem->GetNameText(&str);
01109         TRACEUSER( "GerryX", _T("Item %s Bar = %d  Nodes = %d\n"), (TCHAR*)str, pNameGalleryItem->m_BarNumber, 
01110             pNameGalleryItem->GetObjectCount());
01111         DocRect Rect;
01112         Rect = pNameGalleryItem->GetSetBounds();
01113         TRACEUSER( "GerryX", _T("Bounds     = (%d, %d) (%d, %d)\n"), Rect.lo.x, Rect.lo.y, Rect.hi.y, Rect.hi.y);
01114         Rect = pNameGalleryItem->GetOldSetBounds();
01115         TRACEUSER( "GerryX", _T("Old Bounds = (%d, %d) (%d, %d)\n"), Rect.lo.x, Rect.lo.y, Rect.hi.y, Rect.hi.y);
01116         pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
01117     }
01118 
01119     return TRUE;
01120 }
01121 
01122 // checks if the rects have the same height and width but ignores location
01123 inline BOOL RectsAreTheSameSize(const DocRect & r1, const DocRect & r2)
01124 {
01125     return ((r1.hi.x - r1.lo.x == r2.hi.x - r2.lo.x) && (r1.hi.y - r1.lo.y == r2.hi.y - r2.lo.y));
01126 }
01127 
01128 
01129 // extension to the NodeListItem to store an index too which I use to refer to an array of data
01130 class NodeListItemWithIndex : public NodeListItem
01131 {
01132 public:
01133     NodeListItemWithIndex(Node* WhichNode, INT32 i) {pNode = WhichNode; Index = i;};    // initialise pNode to be WhichNode
01134     INT32 Index;
01135 };
01136 
01137 /********************************************************************************************
01138 >   BOOL NameGallery::FastApplyStretchScan(ObjChangeParam & ObjChange)
01139 
01140     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01141     Created:    7/3/00
01142     Returns:    TRUE if it performs the extending ok
01143                 FALSE if no extending was performed for any reason like none were defined
01144     Param:      ObjChange   The Objchange Param from the op that spawned this extend.
01145                             This doesn't get altered in any way by this function.
01146     Purpose:    To do the exending once it has decided that it needs to be done.
01147                 This requires a fast tree scan to find what has changed dimensions (see FastUpdateNamedSetSizes)
01148                 Analysis of the name gallery items to work out which trigger has changed and which target
01149                 should extend. Then it calls the extend bit on each node that needs it.
01150     SeeAlso:    NameGallery::FastUpdateNamedSetSizes
01151 ********************************************************************************************/
01152 BOOL NameGallery::FastApplyStretchScan(ObjChangeParam & ObjChange)
01153 {
01154     TRACEUSER( "GerryX", _T("FastApplyStretchScan\n"));
01155 
01156     Spread * pSpread =  Document::GetSelectedSpread();
01157     if (!pSpread || m_LastOpUsed == NULL)
01158         return FALSE;
01159 
01160     SGUsedNames* pNames = GetUsedNames();
01161     if (!pNames)
01162     {
01163         PreCreate(); // set up the name gallery
01164         pNames = GetUsedNames();
01165         if (!pNames)
01166             return FALSE;
01167     }
01168 
01169     BOOL ExtendOk = TRUE; // did it all extend ok?
01170     BOOL Recurse = FALSE;
01171 
01172     m_bResetARelationship = FALSE; // nothing reset yet
01173 
01174     // fill this array with data and it is all we will need to extend items when we scan the tree
01175     struct ExtendStructType
01176     {
01177         SGNameItem * pTriggerSet;
01178         SGNameItem * pTargetSet;
01179         NamedStretchProp * pTargetStretchProp;
01180         DocRect CleanTargetRect;
01181         DocRect CombinedTriggerRect;
01182         DocRect OldCombinedTriggerRect;
01183         BOOL PerformedExtendOK;
01184         DocRect TotalExtend;
01185     } ExtendStruct[MAX_SIM_EXTENDS]; // surely no more than 50 simaltainious extends going on!
01186 
01187     Node * pNodeSetSentinel = Document::GetSelected()->GetSetSentinel(); // the sentinel - basically avoid it!
01188     SGNameItem* pNameGalleryItem = NULL;
01189 
01190     INT32 TimesInLoop = 0;
01191 
01192     // Added this line because OpCut (and presumably others) causes an OpPageResize
01193     // to happen which gets remembered as the last op and we crash at this point 
01194     // because the op has been deleted
01195     m_LastOpUsed = ObjChange.GetOpPointer();
01196 
01197     // list the ops that would allow us to pull a button apart
01198     BOOL IsPossiblePullApartOp =  m_LastOpUsed->IS_KIND_OF(TransOperation) && !IS_A(m_LastOpUsed, OpScaleTrans) && !IS_A(m_LastOpUsed, OpSquashTrans);
01199     BOOL IsAChangePropertyOp = IS_A(m_LastOpUsed, OpChangeBarProperty);
01200     BOOL IsAButtonNoChangingOp =
01201 PORTNOTE("other", "Remove OpDuplicateBar and OpShortenBar")
01202 #ifndef EXCLUDE_FROM_XARALX
01203                                     IS_A(m_LastOpUsed, OpDuplicateBar) || 
01204                                     IS_A(m_LastOpUsed, OpShortenBar) || 
01205 #endif
01206                                     IS_A(m_LastOpUsed, OpRenameAll);
01207 
01208     // force recursion for these two ops
01209     Recurse = IsAButtonNoChangingOp;
01210 
01211     ObjChange.GetSettableChangeFlags()->RegenerateNode = TRUE;
01212 
01213     // which op is being called
01214     TRACEUSER( "GerryX", _T("%s\n"), (LPCTSTR) m_LastOpUsed->GetRuntimeClass()->m_lpszClassName);
01215 
01216     do // this do loop is used for the recursive bit of A extends B which extends C (NB it never gets to D though)
01217     {
01218         TimesInLoop++;
01219 
01220         // get the size of each set
01221         if (!FastUpdateNamedSetSizes())
01222             return FALSE; // scan says there was nothing there at all so don't bother to extend it mate!
01223 
01224         NodeSetProperty* pPropNode = NULL;
01225         NamedStretchProp* pProp = NULL;
01226         NodeBarProperty * pNodeBarProperty = (NodeBarProperty*) ((NodeSetSentinel *)pNodeSetSentinel)->FindBarProperty();
01227 
01228         // zero the array of bar sizes and other cached bar data
01229         memset (m_BarSize,0, sizeof(m_BarSize));
01230 
01231         INT32 TriggeredBar = -1;
01232         if (m_TouchedBar >= 0)
01233         {
01234             if (!SetBSTData(m_TouchedBar, 0, 0, 1, 0))
01235             {
01236                 ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01237                 return FALSE;
01238             }
01239             TriggeredBar = m_TouchedBar;
01240 
01241             // adding a bar member is added over button1
01242             // so first we have to shuffle the button into the correct place
01243             // otherwise the back bar wont be able to expand around it
01244 PORTNOTE("other", "Removed OpDuplicateBar");
01245 #ifndef EXCLUDE_FROM_XARALX
01246             if (IS_A(m_LastOpUsed, OpDuplicateBar) && pNodeBarProperty->Bar(TriggeredBar).IsLive)
01247             {
01248             INT32 barDirection = pNodeBarProperty->Bar(TriggeredBar).IsHorizontal ? 1 : 2;
01249                 if (!pNodeBarProperty->Bar(TriggeredBar).RequiresShuffle)
01250                     barDirection = 0;
01251 
01252                 ShuffleBar( TriggeredBar,
01253                             pNodeBarProperty->Bar(TriggeredBar).Spacing,
01254                             barDirection,
01255                             pNames,
01256                             pSpread,
01257                             ObjChange);
01258 
01259                 FastUpdateNamedSetSizes(); // record the new positions
01260             }
01261 #endif
01262         }
01263 
01264     //INT32 TriggersFound = 0; // not needed in the calculation any more but left as it can be useful for debugging
01265 
01266         /**** FIND OUT WHICH TRIGGERS HAVE BEEN FIRED ***/
01267         // find which triggers have changed
01268         // and set the affected trigger bool in the set item
01269         // which is doesn't require scanning for like it does in the stretch properties if set there
01270         pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01271         while (pNameGalleryItem)
01272         {
01273             // init this the first time round only
01274             if (TimesInLoop == 1)
01275             {
01276                 pNameGalleryItem->m_IsPartOfThisStretch = FALSE;
01277                 pNameGalleryItem->ResetCachedPropertyNode(); // dont rely on a cached value find the actual value in the GetPropertyNode() call bellow!
01278             }
01279 
01280             pPropNode = pNameGalleryItem->GetPropertyNode();
01281             if (pPropNode)
01282                 pProp = (NamedStretchProp*) pPropNode->GetProperty(NamedStretchProp::nIndex);
01283 
01284             if (pProp && pPropNode && (pNameGalleryItem->GetSetBounds() != pNameGalleryItem->GetOldSetBounds()
01285                 || (TimesInLoop > 1 && pNameGalleryItem->m_IsPartOfThisStretch)
01286                 ))
01287             {
01288                 // require that this is a TRIGGER
01289                 // ie it has targets set on it which should be stated in from the add stretches gallery
01290 //              TriggersFound++;
01291                 pNameGalleryItem->m_SetIsAffectedTrigger = TRUE;
01292             }
01293             else
01294                 pNameGalleryItem->m_SetIsAffectedTrigger = FALSE;
01295 
01296             pNameGalleryItem->m_IsATrigger = FALSE; // blank this now to fill in later
01297 
01298             pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
01299         }
01300 
01301         /*** CALC THE LARGEST TRIGGER SIZE PER BAR ***/
01302         // work out the size of the largest trigger of each bar
01303         DocRect TempTriggerRect;
01304         SGNameItem* pTempTriggerSet = NULL;
01305 
01306         // find out the largest bar button size
01307         pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01308         while (pNameGalleryItem)
01309         {
01310             TempTriggerRect.MakeEmpty();
01311 
01312             // scan each set that has a trigger associated
01313             pPropNode = pNameGalleryItem->GetPropertyNode();
01314             if (pPropNode)
01315             {
01316                 pProp = (NamedStretchProp*) pPropNode->GetProperty(NamedStretchProp::nIndex);
01317 
01318                 // union these triggers together and check if any of them have been fired (from the above scan)
01319                 if (pProp && pProp->GetState() && !pProp->GetTriggers().empty())
01320                 {
01321                     // loop around each trigger of this target
01322                     for (std::list<TriggerSet>::iterator pt = pProp->GetTriggers().begin();
01323                         pt != pProp->GetTriggers().end();
01324                         pt++)
01325                     {
01326                         pTempTriggerSet = SliceHelper::LookupNameGalleryItem(pt->m_strSet);
01327 
01328                         if (pTempTriggerSet)
01329                         {
01330                             // union the trigger bounds together
01331                             TempTriggerRect = TempTriggerRect.Union(pTempTriggerSet->GetSetBounds());
01332 
01333                             // this is in a trigger list so is a trigger
01334                             // this info can be used from now on
01335                             pTempTriggerSet->m_IsATrigger = TRUE;
01336 
01337                             // mark this bar as an active bar
01338                             if (pTempTriggerSet->m_SetIsAffectedTrigger && pNameGalleryItem->m_BarNumber >= 0)
01339                             {
01340                                 if (!SetBSTData(pNameGalleryItem->m_BarNumber, 0, 0, 1, 0))
01341                                 {
01342                                     ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01343                                     return FALSE;
01344                                 }
01345                                 TriggeredBar = pNameGalleryItem->m_BarNumber;
01346                             }
01347                         }
01348                     }
01349                 }
01350             }
01351 
01352             // work out the largest unioned item in the bar
01353             // this is used as the size of the virtual trigger
01354             // which all triggers in a bar are assumed to be this size if the bar
01355             // is of equal size
01356             if (pNameGalleryItem->m_BarNumber >= 0 && pNameGalleryItem->m_BarNumber < MAX_BARS && !pNameGalleryItem->IsABackBar())
01357             {
01358                 if (!SetBSTData(pNameGalleryItem->m_BarNumber,
01359                     max( DWORD(TempTriggerRect.Width()), m_BarSize[pNameGalleryItem->m_BarNumber].MaxWidth ),
01360                     max( DWORD(TempTriggerRect.Height()), m_BarSize[pNameGalleryItem->m_BarNumber].MaxHeight ), 0, 0 ) )
01361                 {
01362                     ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01363                     return FALSE;
01364                 }
01365             }
01366 
01367             // mark which bars have backbars
01368             if (pNameGalleryItem->IsABackBar() && TimesInLoop == 1 && pNameGalleryItem->m_BarNumber >= 0)
01369             {
01370                 if (!SetBSTData(pNameGalleryItem->m_BarNumber, 0, 0, 0, 1))
01371                 {
01372                     ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01373                     return FALSE;
01374                 }
01375             }
01376 
01377             pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
01378         }
01379 
01380         // We know which triggers have fired, but we need to work out what targets these
01381         // triggers are affecting
01382     INT32 ExtendsFound = 0;
01383 
01384         /*** LOOK AT EACH TARGET IT IS EITHER 1) EXTENDING 2) RESETING OR 3) DOING NOTHING ***/
01385         
01386         pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01387         while (pNameGalleryItem)
01388         {
01389             pPropNode = pNameGalleryItem->GetPropertyNode();
01390             if (pPropNode && pNodeBarProperty->Bar(pNameGalleryItem->m_BarNumber).IsLive)
01391             {
01392                 // calc the size of the targets triggers
01393                 pProp = (NamedStretchProp*) pPropNode->GetProperty(NamedStretchProp::nIndex);
01394 
01395                 // union these triggers together and check if any of them have been fired (from the above scan)
01396                 if (pProp && pProp->GetState() && !pProp->GetTriggers().empty())
01397                 {
01398                     ExtendStruct[ExtendsFound].CombinedTriggerRect.MakeEmpty();
01399                     ExtendStruct[ExtendsFound].OldCombinedTriggerRect.MakeEmpty();
01400 
01401                     // loop around each trigger of this target
01402                     for (std::list<TriggerSet>::iterator pt = pProp->GetTriggers().begin();
01403                         pt != pProp->GetTriggers().end();
01404                         pt++)
01405                     {
01406                         ExtendStruct[ExtendsFound].pTriggerSet = SliceHelper::LookupNameGalleryItem(pt->m_strSet);
01407 
01408                         // the trigger exists and it is a valid trigger
01409                         if (ExtendStruct[ExtendsFound].pTriggerSet)
01410                         {
01411                             // union the trigger bounds together
01412                             ExtendStruct[ExtendsFound].CombinedTriggerRect = ExtendStruct[ExtendsFound].CombinedTriggerRect.Union(ExtendStruct[ExtendsFound].pTriggerSet->GetSetBounds());
01413                             ExtendStruct[ExtendsFound].OldCombinedTriggerRect = ExtendStruct[ExtendsFound].OldCombinedTriggerRect.Union(ExtendStruct[ExtendsFound].pTriggerSet->GetOldSetBounds());
01414 
01415                             // this is a trigger that has been fired
01416                             if (ExtendStruct[ExtendsFound].pTriggerSet->m_SetIsAffectedTrigger)
01417                             {
01418                                 // mark it as part of this stretch
01419                                 ExtendStruct[ExtendsFound].pTriggerSet->m_IsPartOfThisStretch = TRUE;
01420                             }
01421                         }
01422                     }
01423 
01424                     // add on the virtual trigger size if it is a bar
01425                     // if it is part of a bar and the bar same sizing is turned on then
01426                     // expand the CombinedTriggerRect Around the center by the bar dims
01427                     if (pNameGalleryItem->m_BarNumber >= 0 && // is part of a bar
01428                         GetBSTTriggeredBar(pNameGalleryItem->m_BarNumber) && // and that bar has had a trigger fire in it
01429                         ExtendStruct[ExtendsFound].pTriggerSet && // and it has a trigger associated
01430                         !pNameGalleryItem->IsABackBar()) // and it is not a back bar
01431                     {
01432                         if (pNodeBarProperty->Bar(pNameGalleryItem->m_BarNumber).SameSize < 3 
01433                             && ( ExtendStruct[ExtendsFound].pTriggerSet->GetSetBounds().Height() != 0 || ExtendStruct[ExtendsFound].pTriggerSet->GetSetBounds().Width() != 0))
01434                         {
01435                             // expand up the combined and old combined trigger rects
01436                             ExpandVirtualTriggers(  pNodeBarProperty->Bar(pNameGalleryItem->m_BarNumber).SameSize,
01437                                                     pNameGalleryItem->m_BarNumber,
01438                                                     ExtendStruct[ExtendsFound].CombinedTriggerRect);
01439                         }
01440                     }
01441 
01442                     /*** DO WE EXTEND, RESET OR DO NOTHING? ***/
01443 
01444                     // calc the dimensions of the trigger and the target
01445                     // testing if these dimensions have changed is important to
01446                     // work out if a stretch has occurred.
01447                     BOOL TriggerSameSize = RectsAreTheSameSize(ExtendStruct[ExtendsFound].OldCombinedTriggerRect, ExtendStruct[ExtendsFound].CombinedTriggerRect);
01448                     BOOL TargetSameSize = RectsAreTheSameSize(pNameGalleryItem->GetSetBounds(), pNameGalleryItem->GetOldSetBounds());
01449 
01450                     // trigger changed in size & target hasn't => extend
01451                     // trigger and target both unchanged in size => do nothing
01452                     // otherwise reset the relationships
01453                     BOOL DoExtend = (!TriggerSameSize || // either the trigger has changed size OR
01454                         ( pNameGalleryItem->m_BarNumber >= 0 && // is part of a bar
01455                         GetBSTTriggeredBar(pNameGalleryItem->m_BarNumber)));// it is a triggered bar
01456 
01457                      // and it isn't a trans op on this button's bits
01458                     DoExtend = DoExtend && !(IsPossiblePullApartOp && pNameGalleryItem->GetSelectedCount() > 0);
01459 
01460                     // has the clean target changed size - should be the same size for an extend
01461                     if (DoExtend && !TargetSameSize && pNameGalleryItem->GetSelectedCount() > 0 && ExtendStruct[ExtendsFound].pTriggerSet)
01462                     {
01463                         if (RectsAreTheSameSize(pNameGalleryItem->GetSetBounds(),
01464                                 SliceHelper::ScanForSetSizeExcluding(*(pNameGalleryItem->GetNameTextPtr()), *(ExtendStruct[ExtendsFound].pTriggerSet->GetNameTextPtr()))))
01465                             DoExtend = FALSE;
01466                     }
01467 
01468                     BOOL DoReset = ((pNameGalleryItem->GetSetBounds() != pNameGalleryItem->GetOldSetBounds() ||
01469                         ExtendStruct[ExtendsFound].OldCombinedTriggerRect != ExtendStruct[ExtendsFound].CombinedTriggerRect));
01470 
01471                     // Matt - 12/02/2001
01472                     // OK, here's my contribution to this super-huge function...
01473                     // If you change the text alignment - it causes a translation without being flagged as a TransOp!
01474                     // Therefore, we will be flagged as !DoExtend and DoReset which will give us the wrong effect...
01475                     // It will not move any targets of the trigger, but will instead reset the relationships between them!
01476                     if (!DoExtend && DoReset && (ObjChange.GetOpPointer())->IsKindOf(CC_RUNTIME_CLASS(OpApplyAttribToSelected)))
01477                     {
01478                         DoExtend = TRUE;
01479                         DoReset = FALSE;
01480                     }
01481 
01482                     if (pNameGalleryItem->m_BarNumber != -1 &&
01483                         IsAChangePropertyOp &&
01484                         ((OpChangeBarProperty*)m_LastOpUsed)->m_MakingLive &&
01485                         ((OpChangeBarProperty*)m_LastOpUsed)->m_BarIndex == pNameGalleryItem->m_BarNumber)
01486                     {
01487                         // override extend, force a reset for this bar has just gone live
01488                         DoExtend = FALSE;
01489                         DoReset = TRUE;
01490                         TRACEUSER( "GerryX", _T("Bar gone live\n"));
01491                     }
01492                     
01493                     /*** DO AN EXTEND ***/
01494                     if (DoExtend)
01495                     {
01496 #ifdef DEBUG
01497                         String_256 debug = "";
01498                         pNameGalleryItem->GetNameText(&debug);
01499                         TRACEUSER( "GerryX", _T("%s : Extended\n"), (TCHAR*) (debug));
01500 #endif
01501                         // fill in the rest of the extend details
01502                         // this is used in the later half of this function to actaully do the extending
01503                         ExtendStruct[ExtendsFound].pTargetSet = pNameGalleryItem;
01504                         ExtendStruct[ExtendsFound].pTargetStretchProp = pProp;
01505                         ExtendStruct[ExtendsFound].CleanTargetRect.MakeEmpty();
01506                         ExtendStruct[ExtendsFound].PerformedExtendOK = FALSE;
01507                         ExtendStruct[ExtendsFound].TotalExtend.MakeEmpty();
01508 
01509                         // ready the extends found to accept the next item and count this one
01510                         if (ExtendsFound < MAX_SIM_EXTENDS-1)
01511                             ExtendsFound++;
01512 
01513                         // set the bar being triggered
01514                         if (pNameGalleryItem->m_BarNumber != -1)
01515                         {
01516                             TriggeredBar = pNameGalleryItem->m_BarNumber;
01517                             if (!SetBSTData(TriggeredBar, 0, 0, 1, 0))
01518                             {
01519                                 ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01520                                 return FALSE;
01521                             }
01522                         }
01523 
01524                         // if this target is also a trigger then we may have recursion going on
01525                         if (pNameGalleryItem->m_IsATrigger)
01526                         {
01527                             Recurse = TRUE;
01528                         }
01529 
01530                         pNameGalleryItem->m_IsPartOfThisStretch = TRUE;
01531                     }
01532                     // if either the trigger or the target have changed at all and it is not an extend
01533                     // then it must be a reset
01534                     else if (DoReset)
01535                     {
01536                         if (m_LastOpUsed && m_LastOpUsed->OpStatus == DO)
01537                         {
01538                             /*** DO A RESET ***/
01539 #ifdef DEBUG
01540                             String_256 debug = "";
01541                             pNameGalleryItem->GetNameText(&debug);
01542                             TRACEUSER( "GerryX", _T("%s : Reset\n"), (TCHAR*) (debug));
01543 #endif
01544 
01545                             if (pNameGalleryItem->m_BarNumber >= 0 && // is part of a bar
01546                                 !GetBSTTriggeredBar(pNameGalleryItem->m_BarNumber) /*m_BarSize[pNameGalleryItem->m_BarNumber].TriggeredBar*/ && // and that bar has had a trigger fire in it
01547                                 ExtendStruct[ExtendsFound].pTriggerSet && // and it has a trigger associated
01548                                 !pNameGalleryItem->IsABackBar()) // and it is not a back bar
01549                             {
01550                                 if (pNodeBarProperty->Bar(pNameGalleryItem->m_BarNumber).SameSize < 3 
01551                                     && ( ExtendStruct[ExtendsFound].pTriggerSet->GetSetBounds().Height() != 0 || ExtendStruct[ExtendsFound].pTriggerSet->GetSetBounds().Width() != 0))
01552                                 {
01553                                     // expand up the combined and old combined trigger rects
01554                                     ExpandVirtualTriggers(  pNodeBarProperty->Bar(pNameGalleryItem->m_BarNumber).SameSize,
01555                                                             pNameGalleryItem->m_BarNumber,
01556                                                             ExtendStruct[ExtendsFound].CombinedTriggerRect);
01557                                 }
01558                             }
01559 
01560                             ResetRelationshipRects(pNameGalleryItem,
01561                                                     pProp,
01562                                                     NULL,
01563                                                     &(ExtendStruct[ExtendsFound].CombinedTriggerRect)
01564                                                     );
01565                         }
01566                         else
01567                         {
01568 #ifdef DEBUG
01569                             String_256 debug = "";
01570                             pNameGalleryItem->GetNameText(&debug);
01571                             TRACEUSER( "GerryX", _T("%s : Op Invalid for Reset\n"), (TCHAR*) (debug));
01572 #endif
01573                         }
01574 
01575                         // set the bar being triggered
01576                         if (pNameGalleryItem->m_BarNumber != -1)
01577                         {
01578                             TriggeredBar = pNameGalleryItem->m_BarNumber;
01579                             if (!SetBSTData(TriggeredBar, 0, 0, 1, 0))
01580                             {
01581                                 ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01582                                 return FALSE;
01583                             }
01584                         }
01585                     }
01586                     else
01587                     {
01588 #ifdef DEBUG
01589                         String_256 debug = "";
01590                         pNameGalleryItem->GetNameText(&debug);
01591                         TRACEUSER( "GerryX", _T("%s : No action\n"), (TCHAR*) (debug));
01592 #endif
01593                     }
01594                 }
01595             }
01596 
01597             // look at the next posible target
01598             pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
01599         }
01600 
01601         // bar creation should make the bar shuffle as we know no extending is likely to go on
01602         if (TriggeredBar == -1)
01603         {
01604 PORTNOTE("other", "Removed OpBarCreation");
01605 #ifndef EXCLUDE_FROM_XARALX
01606             if (IS_A(m_LastOpUsed, OpBarCreation))
01607             {
01608                 TriggeredBar = ((OpBarCreation *)m_LastOpUsed)->GetBarNumber();
01609             }
01610 #endif
01611         }
01612         
01613         // no target found to extend, so give up now!
01614         if (ExtendsFound == 0 && !IsAButtonNoChangingOp)
01615         {
01616             if (m_TouchedBar != -1)
01617                 TriggeredBar = m_TouchedBar;
01618 
01619             if (TriggeredBar != -1)
01620             {
01621                 // get the size of each set
01622                 // with reseting the old size of anything
01623                 FastUpdateNamedSetSizes();
01624 
01625                 if (!SetBSTData(TriggeredBar, 0, 0, 1, 0))
01626                 {
01627                     ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01628                     return FALSE;
01629                 }
01630 
01631             for (INT32 i = 0; i < MAX_BARS; i++)
01632                 {
01633                     if (GetBSTTriggeredBar(i) == 1 && pNodeBarProperty->Bar(i).IsLive)
01634                     {
01635                         // but before we just leave does the bar need a shuffle?
01636                         // shuffle the bar if it has been touched but no extends went on
01637                     INT32 barDirection = pNodeBarProperty->Bar(i).IsHorizontal ? 1 : 2;
01638                         if (!pNodeBarProperty->Bar(i).RequiresShuffle)
01639                             barDirection = 0;
01640 
01641                         ShuffleBar( i,
01642                                     pNodeBarProperty->Bar(i).Spacing,
01643                                     barDirection,
01644                                     pNames,
01645                                     pSpread,
01646                                     ObjChange);
01647 
01648                         // only recurse if the shuffled bar has a back bar
01649                         if (GetBSTHasABackBar(i) == 1)
01650                             Recurse = TRUE; // its backbar if it has one will need extending
01651                     }
01652                 }
01653 
01654                 m_TouchedBar = -1;
01655                 m_LastOpUsed->NoStretchUpdateChangedNodes(&ObjChange, Document::GetCurrent());
01656                 // reseting a rel may cause an extend like affect when
01657                 // infact it is just the above NoStretchUpdateChangedNodes that wiggled
01658                 // recalcing the positions now removes this wiggle
01659 //              if (m_bResetARelationship)
01660 //                  FastUpdateNamedSetSizes();
01661 
01662                 // We will always update the set sizes here as otherwise there can be small
01663                 // discrepancies between the current and old sizes at the end of the operation
01664                 // This causes the next operation to go wrong (things get reset rather than 
01665                 // extended)
01666                 FastUpdateNamedSetSizes();
01667             }
01668 
01669             if (!Recurse)
01670                 return FALSE; // no extends so go away!!!
01671         }
01672 
01673         /*** WE KNOW WHAT IS TO EXTEND SO GO DO IT ***/
01674 
01675         // scan to build list of all nodes that have affected targets
01676 
01677         Node * pTop = pSpread->FindFirstLayer()->FindParent(); // start point of the scan
01678         Node * pNode = NULL;    // general node in the scan
01679         Node * pTempNode = NULL; // a tempory use for a node
01680         Node * pParent = NULL; // the parent of pNode
01681 
01682         // list holds the nodes to extend
01683         List ExtendNodeList;
01684 
01685     INT32 i = 0;
01686         BOOL CleanTarget = TRUE;
01687         BOOL StretchAsSingularItem = FALSE;
01688 
01689         if (pTop)
01690         {
01691             // scan entire tree for the Template Attribs
01692             pNode = SliceHelper::FindNextNameNode(pTop, pTop);
01693 
01694             // check for all the name gallery items
01695             while (pNode)
01696             {
01697                 pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01698 
01699                 // of course it is the parent of the attrib that is the node that needs extending
01700                 pParent = pNode->FindParent();
01701 
01702                 if (pParent == pNodeSetSentinel)
01703                     break; // gone too far
01704 
01705                 // add it to the list of nodes to extend if it is a target of a fired trigger
01706                 if (pParent)
01707                 {
01708                     for (i = 0; i < ExtendsFound; i++)
01709                     {
01710                         if (ExtendStruct[i].pTargetSet->GetNameTextPtr()->
01711                             CompareTo(((TemplateAttribute *)pNode)->GetParam()) == 0)
01712                         {
01713                             CleanTarget = TRUE;
01714                             StretchAsSingularItem = FALSE;
01715                             // exclude it if it is the trigger node aswell as a target
01716                             pTempNode = pParent->FindFirstChild(CC_RUNTIME_CLASS(TemplateAttribute));
01717                             while (pTempNode && CleanTarget)
01718                             {
01719                                 if (ExtendStruct[i].pTriggerSet && ExtendStruct[i].pTriggerSet->GetNameTextPtr()->
01720                                     CompareTo(((TemplateAttribute *)pTempNode)->GetParam()) == 0)
01721                                 {
01722                                     CleanTarget = FALSE;
01723                                     // nodes that are not clean
01724                                     // ie the target contains the trigger too
01725                                     // need to use the data of the bounds before the trigger
01726                                     // changed the size of the traget by being part of it.
01727                                     // note of it is clean or not
01728                                 }
01729 
01730                                 pTempNode = pTempNode->FindNext(CC_RUNTIME_CLASS(TemplateAttribute));
01731                             }
01732 
01733                             // check it is not part of the bar we wish to ignore and is clean
01734                             if (CleanTarget && (!m_BarToIgnoreTargetsOf[0] || m_BarToIgnoreTargetsOf.CompareTo(((TemplateAttribute *)pNode)->GetQuestion()) != 0))
01735                             {
01736                                 if (!pParent->IsSelected() || !IsPossiblePullApartOp)
01737                                 {
01738                                     // if all is well add it to the list
01739                                     NodeListItemWithIndex * pItem = new NodeListItemWithIndex(pParent, i);
01740                                     ExtendNodeList.AddTail(pItem);
01741                                     ExtendStruct[i].PerformedExtendOK = TRUE;
01742                                 }
01743                                 // keep record of the clean target rect as we will need this and the usual
01744                                 // scan will not seperate the clean and dirty parts of it for us
01745                                 ExtendStruct[i].CleanTargetRect = ExtendStruct[i].CleanTargetRect.Union(SliceHelper::BoundingNodeSize(pParent));
01746                             }
01747                         }
01748                     }
01749                 }
01750 
01751                 pNode = SliceHelper::FindNextNameNode(pNode, pTop);
01752             }
01753         }
01754 
01755         // allow op and allow extend them all?
01756         ExtendOk = TRUE; // did it all extend ok?
01757 //      DocRect TotalExtend; // total bounds for the extender so the button all extends the same amount
01758         DocRect rDiff; // temp variable
01759 
01760 //      TotalExtend.MakeEmpty(); 
01761         rDiff.MakeEmpty();
01762 
01763         NodeListItemWithIndex * pNodeListItem = (NodeListItemWithIndex *)ExtendNodeList.GetHead();
01764 
01765         // loop around the list of nodes that are extending
01766         while (pNodeListItem && ExtendOk)
01767         {
01768             if (pNodeBarProperty->Bar(ExtendStruct[pNodeListItem->Index].pTargetSet->m_BarNumber).GroupsStretch || !IS_A(pNodeListItem->pNode, NodeGroup))
01769             {
01770                 // check if we are allowed to extend
01771                 rDiff = Extender::CheckValidExtend((NodeRenderableInk*) (pNodeListItem->pNode),
01772                                                 ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetStretchType(), 
01773                                                 ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefUnionTriggerBounds(),
01774                                                 ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefTargetBounds(),
01775                                                 ExtendStruct[pNodeListItem->Index].CombinedTriggerRect,
01776                                                 ExtendStruct[pNodeListItem->Index].OldCombinedTriggerRect,
01777                                                 ExtendStruct[pNodeListItem->Index].CleanTargetRect,
01778                                                 &ExtendOk,
01779                                                 ExtendStruct[pNodeListItem->Index].pTargetSet->m_BarNumber >= 0);
01780 
01781                 if (!ExtendOk)
01782                     break;
01783 
01784                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.IsEmpty())
01785                     ExtendStruct[pNodeListItem->Index].TotalExtend=rDiff;
01786 
01787                 // Minimise the "difference" for any stretches that cannot be fully performed.
01788                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.lo.x > rDiff.lo.x) ExtendStruct[pNodeListItem->Index].TotalExtend.lo.x = rDiff.lo.x;
01789                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.lo.y > rDiff.lo.y) ExtendStruct[pNodeListItem->Index].TotalExtend.lo.y = rDiff.lo.y;
01790                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.hi.x > rDiff.hi.x) ExtendStruct[pNodeListItem->Index].TotalExtend.hi.x = rDiff.hi.x;
01791                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.hi.y > rDiff.hi.y) ExtendStruct[pNodeListItem->Index].TotalExtend.hi.y = rDiff.hi.y;
01792 
01793                 // Karim 11/01/2000
01794                 // Ok, this is a fix for a yukky bug.
01795                 // Bug: most of the time, shrinks are symmetric. However, sometimes they're not, in
01796                 //      which case it is possible for an object to swap sides in the target rect.
01797                 //      This is bad, as extension behaviour is side-dependent.
01798                 // Fix: if an asymmetric shrink is about to happen, force it to be symmetric.
01799                 //      we do this by ensuring that TotalExtend.lo.x and .hi.y are both set
01800                 //      to be the lesser of the two values. Same for top and bottom.
01801                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.lo.x < ExtendStruct[pNodeListItem->Index].TotalExtend.hi.x)
01802                     ExtendStruct[pNodeListItem->Index].TotalExtend.hi.x = ExtendStruct[pNodeListItem->Index].TotalExtend.lo.x;
01803                 else
01804                     ExtendStruct[pNodeListItem->Index].TotalExtend.lo.x = ExtendStruct[pNodeListItem->Index].TotalExtend.hi.x;
01805                     
01806                 if (ExtendStruct[pNodeListItem->Index].TotalExtend.lo.y < ExtendStruct[pNodeListItem->Index].TotalExtend.hi.y)
01807                     ExtendStruct[pNodeListItem->Index].TotalExtend.hi.y = ExtendStruct[pNodeListItem->Index].TotalExtend.lo.y;
01808                 else
01809                     ExtendStruct[pNodeListItem->Index].TotalExtend.lo.y = ExtendStruct[pNodeListItem->Index].TotalExtend.hi.y;
01810                     
01811                 // check allow op
01812                 ExtendOk = pNodeListItem->pNode->AllowOp(&ObjChange);
01813             }
01814 
01815             pNodeListItem = (NodeListItemWithIndex *)ExtendNodeList.GetNext(pNodeListItem);
01816         }
01817 
01818         // if ok call extend on them all and remove them from the list
01819         pNodeListItem = (NodeListItemWithIndex *)ExtendNodeList.GetHead();
01820         NodeListItemWithIndex * pNodeListItemToDel = NULL;
01821 
01822         while (pNodeListItem)
01823         {
01824             if (ExtendOk && (pNodeBarProperty->Bar(ExtendStruct[pNodeListItem->Index].pTargetSet->m_BarNumber).GroupsStretch || !IS_A(pNodeListItem->pNode, NodeGroup)))
01825             {
01826                 TRACEUSER( "GerryX", _T("Extending %s at 0x%08x\n"), pNodeListItem->pNode->GetRuntimeClass()->m_lpszClassName, pNodeListItem->pNode);
01827 
01828                 // do the extend
01829                 Extender::Extend((NodeRenderableInk*) (pNodeListItem->pNode),
01830                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetStretchType(), 
01831                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefUnionTriggerBounds(),
01832                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefTargetBounds(),
01833                     ExtendStruct[pNodeListItem->Index].CombinedTriggerRect,
01834                     ExtendStruct[pNodeListItem->Index].OldCombinedTriggerRect,
01835                     ExtendStruct[pNodeListItem->Index].CleanTargetRect,
01836                     &(ExtendStruct[pNodeListItem->Index].TotalExtend),
01837                     ExtendStruct[pNodeListItem->Index].pTargetSet->m_BarNumber >= 0,
01838                     m_LastOpUsed
01839                     );
01840             }
01841             else if (ExtendOk) // move items that do not stretch but are part of the button
01842             {
01843                 TRACEUSER( "GerryX", _T("Moving %s at 0x%08x\n"), pNodeListItem->pNode->GetRuntimeClass()->m_lpszClassName, pNodeListItem->pNode);
01844                 ExtendParams EPS;
01845                 EPS.pOp = m_LastOpUsed;
01846                 Extender::CalculateExtendParams(&EPS,
01847                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetStretchType(), 
01848                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefUnionTriggerBounds(),
01849                     ExtendStruct[pNodeListItem->Index].pTargetStretchProp->GetRefTargetBounds(),
01850                     ExtendStruct[pNodeListItem->Index].CombinedTriggerRect,
01851                     ExtendStruct[pNodeListItem->Index].OldCombinedTriggerRect,
01852                     ExtendStruct[pNodeListItem->Index].CleanTargetRect,
01853                     &(ExtendStruct[pNodeListItem->Index].TotalExtend),
01854                     ExtendStruct[pNodeListItem->Index].pTargetSet->m_BarNumber >= 0
01855                     );
01856 
01857                 if (m_LastOpUsed)
01858                     m_LastOpUsed->DoInvalidateNodeRegion((NodeRenderableBounded*) pNode, TRUE, FALSE);
01859                 ((NodeRenderable*) (pNodeListItem->pNode))->NodeRenderable::TransformTranslateObject(EPS);
01860                 ((NodeRenderable*) (pNodeListItem->pNode))->NodeRenderable::TransformStretchObject(EPS);
01861                 if (m_LastOpUsed)
01862                     m_LastOpUsed->DoInvalidateNodeRegion((NodeRenderableBounded*) pNode, TRUE, FALSE);
01863             }
01864 
01865             // delete the item from the list and tidy the list
01866             pNodeListItemToDel = pNodeListItem;
01867             pNodeListItem = (NodeListItemWithIndex*)ExtendNodeList.GetNext(pNodeListItem);
01868 
01869             if (pNodeListItemToDel)
01870             {
01871                 ExtendNodeList.RemoveItem((NodeListItemWithIndex*)pNodeListItemToDel);
01872                 delete pNodeListItemToDel;
01873             }
01874         }
01875 
01876         // shuffle the bar
01877         if (TriggeredBar >= 0 && TimesInLoop == 1 && pNodeBarProperty->Bar(TriggeredBar).RequiresShuffle)
01878         {
01879             // get the size of each set
01880             // with reseting the old size of anything
01881             FastUpdateNamedSetSizes();
01882 
01883             if (!SetBSTData(TriggeredBar, 0, 0, 1, 0))
01884             {
01885                 ERROR3("Couldn't Set Triggered Bar -> Index may be out of range!");
01886                 return FALSE;
01887             }
01888 
01889         for (i = 0; i < MAX_BARS; i++)
01890             {
01891                 if (GetBSTTriggeredBar(i) == 1 && pNodeBarProperty->Bar(i).IsLive)
01892                     // but before we just leave does the bar need a shuffle?
01893                     // shuffle the bar if it has been touched but no extends went on
01894                 {
01895                     INT32 barDirection = pNodeBarProperty->Bar(i).IsHorizontal ? 1 : 2;
01896                     if (!pNodeBarProperty->Bar(i).RequiresShuffle)
01897                         barDirection = 0;
01898 
01899                     ShuffleBar( i,
01900                                 pNodeBarProperty->Bar(i).Spacing,
01901                                 barDirection,
01902                                 pNames,
01903                                 pSpread,
01904                                 ObjChange);
01905 
01906                     // only recurse if the shuffled bar has a back bar
01907                     if (GetBSTHasABackBar(i) == 1)
01908                         Recurse = TRUE; // its backbar if it has one will need extending
01909                 }
01910             }
01911         }
01912 
01913         // remove any trace that there was a touched bar, so it doesn't cause recursion etc
01914         m_TouchedBar = -1;
01915 
01916         if (Recurse && (ExtendOk || IsAButtonNoChangingOp) && TimesInLoop < 2)
01917             TRACEUSER( "GerryX", _T("Looping\n"));
01918 
01919     } while(Recurse && (ExtendOk || IsAButtonNoChangingOp) && TimesInLoop < 2); // recursive loop for A extends B extends C
01920 
01921     TRACEUSER( "GerryX", _T("After Loop\n"));
01922 
01923     // tidy up after a delete or a shorten bar op has occured to remove some of the properties
01924     // from bars that still exist
01925     if (m_LastOpUsed->OpStatus == DO && (
01926 PORTNOTE("other", "Removed OpShortenBar")
01927 #ifndef EXCLUDE_FROM_XARALX                                         
01928                                             IS_A(m_LastOpUsed, OpShortenBar) ||
01929 #endif
01930                                             IS_A(m_LastOpUsed, OpDelete)))
01931     {
01932         pNameGalleryItem = (SGNameItem*) pNames->GetChild();
01933         while (pNameGalleryItem)
01934         {
01935             // purge the use of this named set if it has just been deleted somehow
01936             if (pNameGalleryItem->IsEmpty())
01937             {
01938                 String_256 TempSetName = "";
01939                 pNameGalleryItem->GetNameText(&TempSetName);
01940 
01941                 SliceHelper::PurgeUseOfSetName(TempSetName, m_LastOpUsed);
01942                 // remove all properties of the deleted node
01943                 Node * pNode = pNameGalleryItem->GetPropertyNode();
01944                 if (pNode)
01945                     m_LastOpUsed->DoHideNode(pNode, FALSE);
01946 
01947                 // deleted bar members should be got rid of completely
01948                 // remove the attribs from the sentinel
01949                 pNode = Document::GetSelected()->GetSetSentinel()->GetNameAttr(TempSetName);
01950                 if (pNode)
01951                     m_LastOpUsed->DoHideNode(pNode, FALSE);
01952             }
01953 
01954             pNameGalleryItem = (SGNameItem*)pNameGalleryItem->GetNext();
01955         }
01956     }
01957 
01958     m_LastOpUsed->NoStretchUpdateChangedNodes(&ObjChange, Document::GetCurrent());
01959 
01960     // reseting a rel may cause an extend like affect when
01961     // infact it is just the above NoStretchUpdateChangedNodes that wiggled
01962     // recalcing the positions now removes this wiggle
01963 //  if (m_bResetARelationship)
01964 //  {
01965 //      FastUpdateNamedSetSizes();
01966 //      TRACEUSER( "GerryX", _T("Done UpdateSetSizes after reset\n"));
01967 //  }
01968 
01969     // We will always update the set sizes here as otherwise there can be small
01970     // discrepancies between the current and old sizes at the end of the operation
01971     // This causes the next operation to go wrong (things get reset rather than 
01972     // extended)
01973     FastUpdateNamedSetSizes();
01974 
01975     m_TouchedBar = -1;
01976 
01977     TRACEUSER( "GerryX", _T("FastApplyStretchScan returning %s\n"), ExtendOk ? _T("TRUE") : _T("FALSE") );
01978 
01979     return ExtendOk;
01980 }
01981 
01982 
01983 /********************************************************************************************
01984 >   void NameGallery::ResetRelationshipRects(SGNameItem * pTarget, NamedStretchProp * pProp, DocRect * pCleanTargetRect, DocRect * pKnownTriggerRect)
01985 
01986     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01987     Created:    17/3/00
01988     Purpose:    Does what it says on the tin. It takes ptrs to the target set and the properties
01989                 of this target set and updates the relationship rectangles to be exactly as they
01990                 are currently.
01991 
01992 ********************************************************************************************/
01993 void NameGallery::ResetRelationshipRects(SGNameItem * pTarget, NamedStretchProp * pProp, DocRect * pCleanTargetRect, DocRect * pKnownTriggerRect)
01994 {
01995     String_256 debug = "";
01996     pTarget->GetNameText(&debug);
01997     TRACEUSER( "GerryX", _T("ResetRelationshipRects %s\n"), (TCHAR*) (debug));
01998 
01999     if (pTarget->GetSetBounds().Height() != 0 && pTarget->GetSetBounds().Width() != 0
02000         && m_LastOpUsed && m_LastOpUsed->OpStatus == DO)
02001     {
02002         DocRect TempCombinedTriggerRect;
02003         DocRect TempCleanTargetRect;
02004 
02005         // what is the target bounds - use the clean bounds
02006         if (pCleanTargetRect && pCleanTargetRect->Height() > 0 && pCleanTargetRect->Width() > 0)
02007             TempCleanTargetRect = *pCleanTargetRect;
02008         else
02009         {
02010             /*** This appears to be working without the more expensive call to ScanForSetSizeExcluding()
02011                  but will have to test to make sure we can always get away without it (sjk) ***/
02012             // use the first extender as the thing to clean it from (as this works for most buttons)
02013             if (pProp && !pProp->GetTriggers().empty())
02014                 TempCleanTargetRect = SliceHelper::ScanForSetSizeExcluding(*pTarget->GetNameTextPtr(), pProp->GetTriggers().front().m_strSet);
02015             else
02016                 TempCleanTargetRect = pTarget->GetSetBounds();
02017         }
02018 
02019         // either use the known trigger rects or calculate them here
02020         if (pKnownTriggerRect)
02021             TempCombinedTriggerRect = *pKnownTriggerRect;
02022         else
02023         {
02024             TempCombinedTriggerRect.MakeEmpty();
02025             SGNameItem * pTempNameItem = NULL;
02026 
02027             // loop around each trigger of this target
02028             for (std::list<TriggerSet>::iterator pt = pProp->GetTriggers().begin();
02029                 pt != pProp->GetTriggers().end();
02030                 pt++)
02031             {
02032                 pTempNameItem = SliceHelper::LookupNameGalleryItem(pt->m_strSet);
02033                 // union the trigger bounds together
02034                 if (pTempNameItem)
02035                     TempCombinedTriggerRect = TempCombinedTriggerRect.Union(pTempNameItem->GetSetBounds());
02036             }
02037         }
02038 
02039         BOOL ok = TempCombinedTriggerRect.IsValid();
02040 
02041         // if it is ok and this will make a difference
02042         if (ok 
02043             && (TempCleanTargetRect != pProp->GetRefTargetBounds() || TempCombinedTriggerRect != pProp->GetRefUnionTriggerBounds()) 
02044             )
02045         {
02046 #ifdef DEBUG
02047             String_256 debug = "";
02048             pTarget->GetNameText(&debug);
02049             TRACEUSER( "GerryX", _T("Reset %s\n"), (TCHAR*) (debug));
02050 #endif
02051             // copy the old bar data into the new bar data as the new is a copy of the old
02052             NodeSetProperty* pCopy;
02053             ALLOC_WITH_FAIL(pCopy, ((NodeSetProperty*) pTarget->GetPropertyNode()->SimpleCopy()), m_LastOpUsed);
02054             if (pCopy)
02055             {
02056                 // change the data in the tree to do this undoably
02057                 NamedStretchProp* pNewProp = (NamedStretchProp*) pCopy->GetProperty(NamedStretchProp::nIndex);
02058                 pNewProp->SetRefTargetBounds(TempCleanTargetRect);
02059                 pNewProp->SetRefUnionTriggerBounds(TempCombinedTriggerRect);
02060 
02061                 Node * pNodeSetSentinel = Document::GetSelected()->GetSetSentinel(); // the sentinel
02062                 pCopy->AttachNode(pNodeSetSentinel, LASTCHILD);
02063                 // Create a hide node action to hide the node when we undo 
02064                 HideNodeAction* UndoHideNodeAction;
02065                 HideNodeAction::Init(m_LastOpUsed,                    
02066                                      m_LastOpUsed->GetUndoActions(), //&UndoActions,
02067                                      pCopy, 
02068                                      FALSE,          // Include subtree size 
02069                                      ( Action**)(&UndoHideNodeAction));
02070                 
02071                 m_LastOpUsed->DoHideNode(pTarget->GetPropertyNode(), FALSE);
02072                 pTarget->ResetCachedPropertyNode();
02073 
02074                 m_bResetARelationship = TRUE;
02075             }
02076         }
02077     }
02078 }
02079 
02080 
02081 
02082 /********************************************************************************************
02083 >   void NameGallery::ShuffleBar(INT32 BarNumber, UINT32 Spacing, INT32 BarDirection,
02084                                  SGUsedNames* pNames, Spread* pSpread)
02085 
02086     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02087     Created:    20/3/00
02088     Purpose:    Moves the buttons of a bar about according to the principles of the bar
02089                 such as the spacing and the bar direction
02090     SeeAlso:    NameGallery::FastUpdateNamedSetSizes
02091 ********************************************************************************************/
02092 void NameGallery::ShuffleBar(INT32 BarNumber, INT32 Spacing, INT32 BarDirection,
02093                              SGUsedNames* pNames, Spread* pSpread, ObjChangeParam& ObjChange)
02094 {
02095     TRACEUSER( "GerryX", _T("ShuffleBar(%d)\n"), BarNumber);
02096 
02097     DocCoord NextPos(0,0);
02098     DocCoord FirstButtonPos(0,0);
02099     DocCoord FirstButtonSubPixPos(0,0);
02100     DocRect rBounds;
02101     
02102     SGNameItem * Order[MAX_BUTTONS_IN_A_BAR];
02103     INT32 num = 0;
02104 
02105     if (BarDirection != 1 && BarDirection != 2)
02106         return;
02107 
02108     // reset the translations and fill in the Order array of items to be shuffled
02109     SGNameItem* pNameGalleryItem = (SGNameItem*) pNames->GetChild();
02110     while (pNameGalleryItem)
02111     {
02112         if (pNameGalleryItem->m_BarNumber == BarNumber)
02113         {
02114             // default is to not move the shape
02115             pNameGalleryItem->m_Translation.x = 0;
02116             pNameGalleryItem->m_Translation.y = 0;
02117 
02118             // ignore the back bar in these calcs
02119             if (!pNameGalleryItem->IsABackBar())
02120             {
02121                 Order[num] = pNameGalleryItem;
02122                 num++;
02123             }
02124         }
02125 
02126         pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
02127     }
02128 
02129     
02130     // sort them by location
02131     INT32 i;
02132     INT32 j;
02133     if (BarDirection == 1) // horiz
02134         for (i = 0; i < num; i++)
02135         {
02136             for (j = i+1; j < num; j++)
02137             {
02138                 if ((Order[j]->GetSetBounds().lo.x < Order[i]->GetSetBounds().lo.x)
02139                     || (Order[j]->GetSetBounds().lo.x == Order[i]->GetSetBounds().lo.x && Order[j]->GetSetBounds().hi.y > Order[i]->GetSetBounds().hi.y) )
02140                 {
02141                     pNameGalleryItem = Order[j];
02142                     Order[j] = Order[i];
02143                     Order[i] = pNameGalleryItem;
02144                 }
02145             }
02146         }
02147     else 
02148     if (BarDirection == 2) // vert
02149         for (i = 0; i < num; i++)
02150         {
02151             for (j = i+1; j < num; j++)
02152             {
02153                 if ((Order[j]->GetSetBounds().hi.y > Order[i]->GetSetBounds().hi.y)
02154                     || (Order[j]->GetSetBounds().hi.y == Order[i]->GetSetBounds().hi.y && Order[j]->GetSetBounds().lo.x < Order[i]->GetSetBounds().lo.x) )
02155                 {
02156                     pNameGalleryItem = Order[j];
02157                     Order[j] = Order[i];
02158                     Order[i] = pNameGalleryItem;
02159                 }
02160             }
02161         }
02162 
02163     /* this loop works out what translations need to be performed on each button in the bar */
02164     for (i = 0; i < num; i++)
02165     {
02166         rBounds = Order[i]->GetSetBounds();
02167 
02168         if (i == 0)
02169         {
02170             // staple the horz and vertical bars at the top left corner
02171             // but let user positioned bars and manually positioned buttons expand around the text
02172             if (BarDirection == 1 || BarDirection == 2)
02173             {
02174                 Order[i]->m_Translation.x = Order[i]->GetOldSetBounds().lo.x - rBounds.lo.x;
02175                 Order[i]->m_Translation.y = Order[i]->GetOldSetBounds().hi.y - rBounds.hi.y;
02176             }
02177             FirstButtonPos.x = rBounds.lo.x + Order[i]->m_Translation.x;
02178             FirstButtonPos.y = rBounds.hi.y + Order[i]->m_Translation.y;
02179             FirstButtonSubPixPos.x = - (FirstButtonPos.x % 750);
02180             FirstButtonSubPixPos.y = FirstButtonPos.y % 750;
02181         }
02182         else
02183         {   // move button from bar relative to last position
02184             // storing the translation in the name gallery item
02185             Order[i]->m_Translation.x = NextPos.x - rBounds.lo.x;
02186             Order[i]->m_Translation.y = NextPos.y - rBounds.hi.y;
02187 
02188             if (BarDirection == 1)
02189                 Order[i]->m_Translation.x += Spacing;
02190             else if (BarDirection == 2)
02191                 Order[i]->m_Translation.y -= Spacing;
02192 
02193         }
02194 
02195         switch (BarDirection)
02196         {
02197         case 1: // horizontal
02198             if (Spacing == 0 || Spacing >= 3750)
02199                 NextPos.x = ((rBounds.hi.y + Order[i]->m_Translation.x)/750)*750 + FirstButtonSubPixPos.x;
02200             else
02201                 NextPos.x = rBounds.hi.y + Order[i]->m_Translation.x;
02202             NextPos.y = FirstButtonPos.y;
02203             break;
02204 
02205         case 2: // vertical
02206             NextPos.x = FirstButtonPos.x;
02207             if (Spacing == 0 || Spacing >= 3750)
02208                 NextPos.y = ((rBounds.lo.y + Order[i]->m_Translation.y)/750 +1)*750 + FirstButtonSubPixPos.y;
02209             else
02210                 NextPos.y = rBounds.lo.y + Order[i]->m_Translation.y;
02211             break;
02212         }
02213 
02214         TRACEUSER( "GerryX", _T("Moved Bar %d, %d\n"), Order[i]->m_Translation.x, Order[i]->m_Translation.y);
02215     }
02216 
02217 
02218     /* *** This next loop scans the tree translating buttons in the bar *** */
02219 
02220     Node * pTop = pSpread->FindFirstLayer()->FindParent(); // start point of the scan
02221     Node * pNode = NULL;    // general node in the scan
02222     Node * pParent = NULL; // the parent of pNode
02223     Node * pNodeSetSentinel = Document::GetSelected()->GetSetSentinel(); // the sentinel - basically avoid it!
02224 
02225     BOOL UpdateSelection = FALSE;
02226 
02227     Trans2DMatrix Transformer;
02228 
02229     if (pTop)
02230     {
02231         // scan entire tree for the Template Attribs
02232         pNode = SliceHelper::FindNextNameNode(pTop, pTop);
02233 
02234         // check for all the name gallery items
02235         while (pNode)
02236         {
02237             pNameGalleryItem = SliceHelper::LookupNameGalleryItem(((TemplateAttribute *)pNode)->GetParam());
02238 
02239             if (pNameGalleryItem && pNameGalleryItem->m_BarNumber == BarNumber && 
02240                 (pNameGalleryItem->m_Translation.x || pNameGalleryItem->m_Translation.y))
02241             {
02242                 // of course it is the parent of the attrib that is the node that needs extending
02243                 pParent = pNode->FindParent();
02244 
02245                 if (pParent == pNodeSetSentinel)
02246                     break;
02247 
02248                 if (pParent)
02249                 {
02250                     Transformer.SetTransform(pNameGalleryItem->m_Translation.x, pNameGalleryItem->m_Translation.y);
02251 
02252                     if (m_LastOpUsed) m_LastOpUsed->DoInvalidateNodeRegion((NodeRenderableBounded*) pParent, TRUE, FALSE);
02253                     if (pParent->AllowOp(&ObjChange))
02254                     {
02255                         ((NodeRenderableBounded *)pParent)->Transform(Transformer);
02256                         if (pParent->IsSelected())
02257                             UpdateSelection = TRUE;
02258                     }
02259                     if (m_LastOpUsed) m_LastOpUsed->DoInvalidateNodeRegion((NodeRenderableBounded*) pParent, TRUE, FALSE);
02260                 }
02261             }
02262 
02263             pNode = SliceHelper::FindNextNameNode(pNode, pTop);
02264         }
02265     }
02266 
02267     if (UpdateSelection)
02268     {
02269         // the selection will have moved - make sure the blobs are up to date
02270         BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED));
02271         GetApplication()->UpdateSelection();
02272     }
02273 }
02274 
02275 
02276 
02277 /********************************************************************************************
02278 >   BOOL NameGallery::ExpandVirtualTriggers(INT32 ExpandType, INT32 BarNo, DocRect &r1)
02279 
02280     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02281     Created:    27/7/00
02282     Purpose:    Expands up the trigger defined by r1 according to the virtual trigger size
02283                 defined in m_BarSize[] and the Expand type of the bar (Equal size, Equal but left aligned, etc.)
02284     SeeAlso:
02285 ********************************************************************************************/
02286 BOOL NameGallery::ExpandVirtualTriggers(INT32 ExpandType, INT32 BarNo, DocRect &r1)
02287 {
02288     DWORD bstMaxHeight = GetBSTMaxHeight(BarNo);
02289     DWORD bstMaxWidth  = GetBSTMaxWidth(BarNo);
02290     if (!bstMaxHeight || !bstMaxWidth)
02291     {
02292         ERROR3("Problems getting the max height and width -> Index may be out of range");
02293         return FALSE;
02294     }
02295 
02296     INT32 ysize = max( ( bstMaxHeight/*m_BarSize[BarNo].MaxHeight*/ - r1.Height() ) / 2, unsigned(0) ); // not a typo ysize is held as half of xsize
02297     INT32 xsize = max( ( bstMaxWidth/*m_BarSize[BarNo].MaxWidth*/ - r1.Width() ), unsigned(0) );
02298 
02299     switch (ExpandType)
02300     {
02301     case 1: //left align
02302         r1.Inflate(0, ysize);
02303         r1.hi.y += xsize;
02304         return TRUE;
02305 
02306     case 2: // right align
02307         r1.Inflate(0, ysize);
02308         r1.lo.x -= xsize;
02309         return TRUE;
02310 
02311     case 0: // centre
02312         r1.Inflate(xsize/2, ysize);
02313         return TRUE;
02314     }
02315 
02316     return FALSE;
02317 }
02318 
02319 
02320 /***************************************************************************************
02321 
02322 >   BOOL NameGallery::SetBSTData(INT32 Index, DWORD MaxWidth, DWORD MaxHeight, BYTE TriggeredBar, BYTE HasABackBar)
02323 
02324     Author      : Matt Priestley
02325     Created     : 06 February 2001
02326     Purpose     : 
02327 
02328     Returns     : BOOL
02329     Argument    : INT32 Index
02330     Argument    : DWORD MaxWidth
02331     Argument    : DWORD MaxHeight
02332     Argument    : BYTE TriggeredBar
02333     Argument    : BYTE HasABackBar
02334 
02335 ***************************************************************************************/
02336 
02337 BOOL NameGallery::SetBSTData(INT32 Index, DWORD MaxWidth = NULL, DWORD MaxHeight = NULL, BYTE TriggeredBar = NULL, BYTE HasABackBar = NULL)
02338 {
02339     if (Index > MAX_BARS || (!MaxWidth && !MaxHeight && !TriggeredBar && !HasABackBar))
02340     {
02341         ERROR3("Problem calling SetBSTData()");
02342         return FALSE;
02343     }
02344 
02345     if (MaxWidth)       {   m_BarSize[Index].MaxWidth       = MaxWidth;     }
02346     if (MaxHeight)      {   m_BarSize[Index].MaxHeight      = MaxHeight;    }
02347     if (TriggeredBar)   {   m_BarSize[Index].TriggeredBar   = TriggeredBar; }
02348     if (HasABackBar)    {   m_BarSize[Index].HasABackBar    = HasABackBar;  }
02349 
02350     return TRUE;
02351 }

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