opbarcreation.cpp

Go to the documentation of this file.
00001 // $Id: opbarcreation.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: /Camelot/kernel/OpBarCreation.cpp 44    26/05/05 15:49 Luke $
00100 */
00101 
00102 #include "camtypes.h"
00103 #include "opbarcreation.h"
00104 //#include "simon.h"
00105 //#include "resource.h"
00106 
00107 #include "transop.h"
00108 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 
00110 #include "slice.h"
00111 
00112 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "userattr.h"
00114 #include "tmpltatr.h"
00115 
00116 #include "progress.h"
00117 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 
00120 
00121 // bevel stuff for playing with light angles
00122 #include "nbevcont.h"
00123 #include "attrbev.h"
00124 #include "opbevel.h"
00125 
00126 // name set stuff
00127 #include "ngcore.h"
00128 #include "ngitem.h"
00129 #include "ngprop.h"
00130 #include "ngsentry.h"
00131 
00132 #include "layermsg.h"   // the layer messaging
00133 #include "sprdmsg.h"    // SpreadMsg
00134 
00135 #include "slicehelper.h"
00136 //#include "sliceres.h"
00137 
00138 #include "fillramp.h"   // for ColRampItem
00139 #include "objchge.h" // for the allow op flags
00140 
00141 #include "extender.h"
00142 #include "nodetxts.h"
00143 
00144 #include "nodetxts.h"
00145 #include "nodetxtl.h"
00146 #include "nodetext.h"
00147 #include "nodecntr.h"
00148 
00149 #include "page.h"
00150 
00151 #include "extender.h"
00152 
00153 // need to know about shadows and bevels since they size funny for the GetNodeBounding()
00154 #include "nodeshad.h"
00155 
00156 #include "opdupbar.h" // for the showlayer stuff
00157 
00158 #include "nodeblnd.h"
00159 
00160 #ifdef _DEBUG
00161 #undef THIS_FILE
00162 static char BASED_CODE THIS_FILE[] = __FILE__;
00163 #endif
00164 
00165 DECLARE_SOURCE("$Revision: 1282 $");
00166 
00167 CC_IMPLEMENT_DYNCREATE(OpBarCreation, CarbonCopyOp)
00168 
00169 #define new CAM_DEBUG_NEW
00170 
00171 
00172 /********************************************************************************************
00173 
00174 >   OpClone::OpBarCreation() 
00175 
00176     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    27/8/99
00178     Purpose:    OpBarCreation constructor
00179     Errors:     -
00180     SeeAlso:    CarbonCopyOp
00181 
00182 ********************************************************************************************/            
00183 OpBarCreation::OpBarCreation(): CarbonCopyOp()                              
00184 {                              
00185 }
00186 
00187 
00188 
00189 /********************************************************************************************
00190 
00191 >   BOOL OpBarCreation::Init()
00192 
00193     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00194     Created:    27/8/99
00195     Returns:    TRUE if the operation could be successfully initialised 
00196                 FALSE if no more memory could be allocated 
00197     Purpose:    OpBarCreation initialiser method
00198     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00199                 operation.
00200     SeeAlso:    -
00201 
00202 ********************************************************************************************/
00203 BOOL OpBarCreation::Init()
00204 {
00205     return  (RegisterOpDescriptor(0,
00206                                 _R(IDS_BARCREATIONOP),
00207                                 CC_RUNTIME_CLASS(OpBarCreation),
00208                                 OPTOKEN_BARCREATIONOP,
00209                                 OpBarCreation::GetState,
00210                                 0,                  // help ID 
00211                                 _R(IDBBL_BARCREATIONOP),// bubble help
00212                                 0,                  // resource ID
00213                                 0, //_R(IDC_BC_CREATE),     // control ID
00214                                 SYSTEMBAR_ILLEGAL,  // Bar ID
00215                                 TRUE,               // Receive messages
00216                                 FALSE,
00217                                 FALSE,
00218                                 0,
00219                                 (GREY_WHEN_NO_CURRENT_DOC) ));
00220 }
00221 
00222 
00223 
00224 /********************************************************************************************
00225 
00226 >   OpState OpBarCreation::GetState(String_256*, OpDescriptor*)
00227 
00228     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com> based on Jason
00229     Created:    27/8/99
00230     Returns:    The state of the OpBarCreation
00231     Purpose:    For finding the operations state.  
00232 
00233 ********************************************************************************************/
00234 OpState OpBarCreation::GetState(String_256* UIDescription, OpDescriptor *Bob)
00235 {
00236     OpState OpSt;
00237 
00238     // if we don't allow it
00239     OpSt.Greyed = TRUE;
00240     Spread* pSpread = Document::GetSelectedSpread();
00241     if (pSpread && !pSpread->FindActiveLayer()->IsFrame())
00242         OpSt.Greyed = FALSE;
00243 
00244     return(OpSt);   
00245 }
00246 
00247 /********************************************************************************************
00248 
00249 >   void OpBarCreation::DoWithParam(OpDescriptor* token, OpParam* pOpParam)
00250 
00251     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00252     Created:    27/8/99
00253     Inputs:     OpParam - describes the number of buttons, what layers to create, any mutation
00254     Outputs:    -
00255     Returns:    -
00256     Purpose:    Creates a navigation rollover bar in the drawing by copying the selection
00257                 several times unto named layers, and naming each copy of the selection.
00258     Errors:     -
00259     SeeAlso:    OpBarCreation::DoWithParam, CarbonCopyOp::DoProcessing
00260 
00261 ********************************************************************************************/   
00262 void OpBarCreation::DoWithParam(OpDescriptor* token, OpParam* pOpParam)
00263 {
00264     // start the op
00265     if (pOpParam != NULL && DoStartSelOp(FALSE,TRUE))
00266     {
00267         // do the biz
00268         // create or edit the bar depending on the params
00269         BOOL ok = TRUE;
00270         
00271         // touch the bar in question
00272         NameGallery * pNameGallery = NameGallery::Instance();
00273         if (pNameGallery)
00274         {
00275             pNameGallery->m_TouchedBar = SliceHelper::GetBarNumberFromBarName(((OpParamBarCreation*)pOpParam)->m_BarName);
00276         }
00277 
00278         if (((OpParamBarCreation*)pOpParam)->m_DelExistingState)
00279         {
00280             INT32 NewLayerNo = 0;
00281 
00282             if (((OpParamBarCreation*)pOpParam)->m_WantMouse)
00283                 NewLayerNo = 1;
00284             else if (((OpParamBarCreation*)pOpParam)->m_WantClicked)
00285                 NewLayerNo = 2;
00286             else if (((OpParamBarCreation*)pOpParam)->m_WantSelected)
00287                 NewLayerNo = 3;
00288 
00289             // delete elements in this state before we create it
00290             OpDelBar::DelBar(((OpParamBarCreation*)pOpParam)->m_BarName, NewLayerNo, this);
00291         }
00292 
00293         if (((OpParamBarCreation*)pOpParam)->m_WantBackBar)
00294         {
00295             // want to build the bar and the backbar at once!!!
00296             if (((OpParamBarCreation*)pOpParam)->m_WantDefault)
00297                 ok = CreateBarAndBackBar(pOpParam); // generates its own warnings if required
00298             else
00299             {
00300                 ok = CreateBackBarFromSelection(pOpParam);
00301                 if (ok)
00302                     InformMessage(_R(IDS_BACKBAR_CREATED_OK));
00303                 else
00304                     InformWarning(_R(IDS_FAILLED_MAKE_BACKBAR));
00305             }
00306         }
00307         else
00308         {
00309             if (((OpParamBarCreation*)pOpParam)->m_FromSelection)
00310                 ok = CreateOrEditBar(pOpParam);
00311             else
00312                 ok = CreateFromDefaultState(pOpParam);
00313 
00314             if (!ok)
00315                 InformWarning(_R(IDS_FAILLED_MAKE_BAR));
00316         }
00317 
00318         if (!ok)
00319             FailAndExecute();
00320 
00321         // end the op
00322         End();
00323 
00324         // update the bars
00325         DialogBarOp::SetSystemStateChanged();
00326         DialogBarOp::UpdateStateOfAllBars(); 
00327     }
00328     else
00329     {
00330         // give up and go home
00331         FailAndExecute();
00332         End();
00333     }
00334 }
00335 
00336     
00337 /********************************************************************************************
00338 
00339 >   BOOL OpBarCreation::CreateOrEditBar (OpParam* pOpParam)
00340 
00341     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    27/8/99 - re-writen 17/4/00
00343     Inputs:     OpParam - describes the number of buttons, what layers to create, any mutation
00344     Outputs:    -
00345     Returns:    TRUE on success, FALSE on failure
00346     Purpose:    Creates a navigation rollover bar in the drawing by copying the selection
00347                 several times unto named layers, and naming each copy of the selection.
00348     Errors:     -
00349     SeeAlso:    OpBarCreation::DoWithParam
00350 
00351 ********************************************************************************************/   
00352 BOOL OpBarCreation::CreateOrEditBar (OpParam* pOpParam)
00353 {
00354     String_256 ActiveLayerStr(_R(IDS_ROLLOVER_DEFAULT));
00355     Spread* pSpread = Document::GetSelectedSpread();
00356     if (pSpread)
00357     {
00358         ActiveLayerStr = pSpread->FindActiveLayer()->GetLayerID();
00359     }
00360 
00361     OpParamBarCreation* pBarParam = (OpParamBarCreation*)pOpParam;
00362     if (pBarParam->m_NoOfButtons > MAX_BUTTONS_IN_A_BAR)
00363         return FALSE; // too many buttons requested
00364 
00365     // get the name of this bar
00366     m_BarName = pBarParam->m_BarName;
00367     INT32 BarNo = SliceHelper::GetBarNumberFromBarName(m_BarName);
00368 
00369     // set up the layer names
00370     m_RolloverName[DEFAULT].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default";
00371     m_RolloverName[MOUSE].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse";
00372     m_RolloverName[CLICKED].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked";
00373     m_RolloverName[SELECTED].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected";
00374     m_RolloverName[BACKBAR].Load(_R(IDS_BACK_BAR)); // = "Back Bar";
00375 
00376     INT32 NewLayerNo = 0;
00377 
00378     if (pBarParam->m_WantMouse)
00379         NewLayerNo = 1;
00380     else if (pBarParam->m_WantClicked)
00381         NewLayerNo = 2;
00382     else if (pBarParam->m_WantSelected)
00383         NewLayerNo = 3;
00384 
00385     List SelectionList; // list of nodes we are copying to each point
00386     List DelList;       // list of nodes we no longer have any use for
00387     Node * pNode = NULL;
00388 
00389     // get the selection
00390     Range Sel(*(GetApplication()->FindSelection()));
00391 
00392     // set the range flags so it includes shadow and bevel manager nodes
00393     RangeControl rg = Sel.GetRangeControlFlags();
00394     rg.PromoteToParent = TRUE;
00395     Sel.Range::SetRangeControl(rg);
00396 
00397     // remove any quickshape objects from the selection
00398     if (Extender::ConvertQuickShapesInSelRangeToPaths(this, &Sel))
00399     {
00400         Sel = *(GetApplication()->FindSelection());
00401         rg = Sel.GetRangeControlFlags();
00402         rg.PromoteToParent = TRUE;
00403         Sel.Range::SetRangeControl(rg);
00404     }
00405 
00406     if (Sel.IsEmpty())
00407     {
00408         InformWarning(_R(IDS_WARNING_NO_SEL_TEMPLATE));
00409         return FALSE;
00410     }
00411     
00412     // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them
00413     ObjChangeFlags cFlags;
00414     cFlags.MultiReplaceNode = TRUE;
00415     cFlags.RegenerateNode = TRUE;
00416     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
00417 
00418     // Mark nodes that will allow this to happen, and error if no nodes will let it happen
00419     if (!Sel.AllowOp(&ObjChange))
00420         return FALSE; // op not allowed
00421 
00422     // modify the selection to the allowed constraints
00423     // use the selection list from now on
00424     CleanSelection (&Sel, &SelectionList, &DelList, NewLayerNo);
00425 
00426     if (SelectionList.IsEmpty())
00427     {
00428         InformWarning(_R(IDS_WARNING_NO_SEL_TEMPLATE));
00429         return FALSE;
00430     }
00431 
00432     // create the new layer
00433     Layer * pNewLayer = AddLayer(m_RolloverName[NewLayerNo], NewLayerNo);
00434     
00435     if (!pNewLayer)
00436         return FALSE;
00437 
00438     // mark the existing back bar for deletion if not in the selection
00439     SliceHelper::BuildListOfNodesInBar(&DelList, pNewLayer, m_BarName);
00440 
00441     // the deletion list should be of the actual nodes not the attribs as these
00442     // can get removed in the process
00443     NodeListItem * pNodeListItem = (NodeListItem *)DelList.GetHead();
00444 
00445     while(pNodeListItem)
00446     {
00447         Node *pParent = pNodeListItem->pNode;
00448 
00449         // if it is the template attrib we are looking at
00450         // we mean the node on which it is attached
00451         if (IS_A(pParent, TemplateAttribute))
00452         {
00453             pParent = pParent->FindParent();
00454             pNodeListItem->pNode = pParent;
00455         }
00456 
00457         // if it is under a bevel or shadow or something look at the top node of the compound thing
00458         while (!IS_A(pParent->FindParent(), NodeGroup) && !pParent->FindParent()->IsLayer())
00459         {
00460             pParent = pParent->FindParent();
00461             pNodeListItem->pNode = pParent;
00462         }
00463 
00464         pNodeListItem = (NodeListItem *)DelList.GetNext(pNodeListItem);
00465     }
00466 
00467     // get the size of the selection
00468     DocRect SelRect;
00469     SelRect.MakeEmpty();
00470     DocRect FullSelRect;
00471     FullSelRect.MakeEmpty();
00472     
00473     // localise all the attribs in the selection list
00474     pNodeListItem = (NodeListItem *)SelectionList.GetHead();
00475 
00476     while(pNodeListItem)
00477     {
00478         // localise attribs for this node
00479         DoLocaliseForAttrChange((NodeRenderableInk*) pNodeListItem->pNode, (AttrTypeSet *)NULL, (ObjectSet*) NULL);
00480 
00481         // calc the size of this node as part of the size of the selection
00482         SelRect = SelRect.Union(SliceHelper::BoundingNodeSize(pNodeListItem->pNode));
00483         if (IS_A(pNodeListItem->pNode, NodeShadowController) || IS_A(pNodeListItem->pNode, TextStory))
00484             FullSelRect = FullSelRect.Union(SliceHelper::BoundingNodeSize(pNodeListItem->pNode));
00485         else
00486             FullSelRect = FullSelRect.Union(((NodeRenderableBounded*)(pNodeListItem->pNode))->GetBoundingRect());
00487 
00488         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
00489     }
00490 
00491     // find the center of the selection
00492     DocCoord SelCentre = SelRect.Centre();
00493 
00494     // not used by this function but set it up for later
00495     m_BarSelectionRect = SelRect;
00496     m_FinishedBarRect.MakeEmpty();
00497 
00498 
00499     // Matt - 20/12/2000
00500     // We wish you a Merry Christmas, We wish you a Merry Christmas, We wish you a Merry Christmas and a Happy New Year... That'll be 10p guv...
00501     // Find out whereabouts the centre of each button ON THIS LAYER was previously if we have a user positioned bar or LiveStretching is OFF
00502     // This is so that in these cases, when the user chooses 'Set New Design' we know the location and do not reposition/misalign things !!!
00503     BOOL LiveStretching = FALSE;
00504     BOOL IgnoreSettings = FALSE;
00505     INT32 m_ExistingButtonsInBar = 0;
00506     DocCoord oldbuttoncentres[MAX_BUTTONS_IN_A_BAR];
00507     TemplateAttribute ** m_ppFoundButton[MAX_BUTTONS_IN_A_BAR];
00508     for (INT32 temp = 0; temp < MAX_BUTTONS_IN_A_BAR; temp++)
00509     {
00510         m_ppFoundButton[temp] = NULL;
00511     }
00512 
00513     SliceHelper::CountButtonsInBarScan(pNewLayer, (TemplateAttribute **) m_ppFoundButton, &m_ExistingButtonsInBar, m_BarName);
00514 
00515     NodeBarProperty* pNodeBarProperty = (NodeBarProperty*) Document::GetCurrent()->GetSetSentinel()->FindBarProperty();
00516     BarDataType NewBarData = pNodeBarProperty->Bar(BarNo);
00517     if (pNodeBarProperty  && BarNo < pNodeBarProperty->HowMany())
00518     {
00519         LiveStretching = NewBarData.IsLive;
00520     }
00521 
00522     if (!LiveStretching || !NewBarData.RequiresShuffle)
00523     {
00524         // We need to get all nodes that are on this layer, for each of the buttons of this bar (in turn) - then we need to find out their bounding box in order
00525         // to record their centre position - this may take a while...
00526 
00527         for (INT32 i = 0; i < pBarParam->m_NoOfButtons; i++)
00528         {
00529             List * pList = new List;
00530             DocRect ButtonRect;
00531             ButtonRect.MakeEmpty();
00532 
00533             if (!((TemplateAttribute *) m_ppFoundButton[i]))
00534             {
00535                 IgnoreSettings = TRUE;
00536                 i = pBarParam->m_NoOfButtons;
00537             }
00538             else
00539             {
00540                 SliceHelper::BuildListOfNodesInButton(pList, pNewLayer, ((TemplateAttribute *) m_ppFoundButton[i])->GetParam());
00541 
00542                 NodeListItem * pNodeListItem = NULL;
00543                 if (pList)
00544                 {
00545                     pNodeListItem = (NodeListItem *)pList->GetHead();
00546                 }
00547 
00548                 while(pNodeListItem)
00549                 {
00550                     // localise attribs for this node
00551                     DoLocaliseForAttrChange((NodeRenderableInk*) pNodeListItem->pNode, (AttrTypeSet *)NULL, (ObjectSet*) NULL);
00552                     ButtonRect = ButtonRect.Union(SliceHelper::BoundingNodeSize(pNodeListItem->pNode));
00553 
00554                     pNodeListItem = (NodeListItem *)pList->GetNext(pNodeListItem);
00555                 }
00556 
00557                 oldbuttoncentres[i] = ButtonRect.Centre();
00558 
00559                 pList->DeleteAll();
00560                 delete pList;
00561             }
00562         }
00563     }
00564 
00565 
00566 
00567 
00568     // *** Calculate the properties needed to be added to the buttons for stretching *** 
00569 
00570     // set up the target and extender strs by scanning the selection
00571     String_256  Target = ""; // the button name of the selection
00572     String_256  Extender = ""; // the thing in this button that extends it
00573     BOOL        MakeItStretch = TRUE; // nothing stretched before - but I want it to stretch using button text
00574     BOOL        TextStoryInSelection = FALSE;
00575     BYTE        ExtenderFlags = 0; // the way the buttons will extend
00576 
00577     DocRect TargetRect;
00578     DocRect ExtenderRect;
00579     DocRect TextRect;
00580     DocRect NoTextRect;
00581 
00582     // find the Target, extender and if there are any text stories in the selection
00583     pNodeListItem = (NodeListItem *)SelectionList.GetHead();
00584     Node * pTextStory = NULL;
00585 
00586     INT32 RequiredLevel = 0;
00587     while (pNodeListItem && RequiredLevel < 2)
00588     {
00589         Node * pCurrent = pNodeListItem->pNode;
00590 
00591         RequiredLevel = SliceHelper::FindTargetAndExtender(pCurrent, Target, Extender, RequiredLevel, &ExtenderFlags,
00592                                                             &TargetRect, &ExtenderRect);
00593         pTextStory = SliceHelper::FindNextOfClass(pCurrent, pCurrent, CC_RUNTIME_CLASS(TextStory), TRUE);
00594         if (pTextStory)
00595         {
00596             TextStoryInSelection = TRUE;
00597             TextRect = TextRect.Union(SliceHelper::BoundingNodeSize(pCurrent));
00598 
00599             // warn if there are any grouped text stories and fail
00600             while (!pTextStory->IsLayer())
00601             {
00602                 if (IS_A(pTextStory, NodeGroup)) //cant call ->IsAGroup() since shadows say yes!
00603                 {
00604                     InformWarning(_R(IDS_WARNING_GROUPED_TEXT));
00605                     SelectionList.DeleteAll();
00606                     DelList.DeleteAll();
00607                     return FALSE;
00608                 }
00609                 pTextStory = pTextStory->FindParent();
00610             }
00611 
00612         }
00613         else
00614             NoTextRect = NoTextRect.Union(SliceHelper::BoundingNodeSize(pCurrent));
00615 
00616 
00617         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
00618     }
00619 
00620     // for this level we copy the stretch data across rather than "make it stretch"
00621     // or if there is no text story then it we can't use the "make it stretch"
00622     if (RequiredLevel > 1 || !TextStoryInSelection || NoTextRect.IsEmpty())
00623         MakeItStretch = FALSE;
00624 
00625 //  if (MakeItStretch)
00626 //  {
00627 //      NoTextRect = NoTextRect.Union(TextRect); // since the text trigger is also part of the target!
00628 //  }
00629 
00630 
00631     // *** calculate the translation to build up the bar into the correct location ***
00632 
00633     // data class to store temp data needed to build up this bar
00634     class ButtonDataType
00635     {
00636     public:
00637         DocCoord Translation;
00638         String_256  Name;
00639         BOOL HaveCreatedProperty;
00640         TextStory * pOriginalStory;
00641         String_256 Storytext;
00642         DocRect OriginalTextStoryDims;
00643         DocRect NewTextStoryDims;
00644     } ButtonData[MAX_BUTTONS_IN_A_BAR];
00645 
00646     INT32 ButtonsInitialised = 0;
00647 
00648     // ask the name gallery what buttons do we already have defined
00649     // get their names and work out the translations to line up a new state
00650     NameGallery * pNameGallery = NameGallery::Instance();
00651 
00652     if (pNameGallery)
00653     {
00654         pNameGallery->FastUpdateNamedSetSizes(); // make sure we are using the most up-to-date data
00655         
00656         SGUsedNames* pNames = pNameGallery->GetUsedNames();
00657         SGNameItem* pNameGalleryItem = pNames ? (SGNameItem*) pNames->GetChild() : NULL;
00658     
00659             
00660         while (pNameGalleryItem)
00661         {
00662             if (pNameGalleryItem->m_BarNumber == BarNo && !pNameGalleryItem->IsEmpty() && !pNameGalleryItem->IsABackBar())
00663             {
00664                 // set the name
00665                 pNameGalleryItem->GetNameText(&(ButtonData[ButtonsInitialised].Name));
00666                 ButtonData[ButtonsInitialised].HaveCreatedProperty = FALSE;
00667     
00668                 // Matt 19/12/2000
00669                 // If the LiveStretching check box is turned on, then we should reposition the buttons relative to the centre of their set bounds.
00670                 // If not, then we should position them central to where their set bounds on THIS layer are...
00671                 // This is so that you can change some colours (etc) on one state, click 'SetNewDesign' and be sure that your button isn't
00672                 // about to realign itself centrally to its set (when this may not have been appropriate)
00673                 BOOL LiveStretching = FALSE;
00674                 NodeBarProperty* pNodeBarProperty = (NodeBarProperty*) Document::GetCurrent()->GetSetSentinel()->FindBarProperty();
00675                 BarDataType NewBarData = pNodeBarProperty->Bar(BarNo);
00676                 if (pNodeBarProperty  && BarNo < pNodeBarProperty->HowMany())
00677                 {
00678                     LiveStretching = NewBarData.IsLive;
00679                 }
00680     
00681                 // If LiveStretching is not enabled or the bar does not require shuffling (ie user positioned)
00682                 if ((!LiveStretching || !NewBarData.RequiresShuffle) && !IgnoreSettings)
00683                 {
00684                     // Unfortunately, I now want to know where the old version of this button was... I need to know this so that I can position the new buttons with
00685                     // their new designs in the same place as the original ones so as to minimise on-screen fun... Also, we should use this in the case of User Positioned
00686                     // buttons so that we don't turn them into Vertical Bars everytime the user clicks 'Set New Design' - not very user positioned!
00687                     ButtonData[ButtonsInitialised].Translation.x = oldbuttoncentres[ButtonsInitialised].x - SelCentre.x;
00688                     ButtonData[ButtonsInitialised].Translation.y = oldbuttoncentres[ButtonsInitialised].y - SelCentre.y;
00689                 }
00690                 else
00691                 {
00692                     // position to new button state on top of the other button states
00693                     ButtonData[ButtonsInitialised].Translation.x = pNameGalleryItem->GetSetBounds().Centre().x - SelCentre.x;
00694                     ButtonData[ButtonsInitialised].Translation.y = pNameGalleryItem->GetSetBounds().Centre().y - SelCentre.y;
00695                 }
00696     
00697                 ButtonsInitialised++;
00698     
00699             }
00700             pNameGalleryItem = (SGNameItem *) pNameGalleryItem->GetNext();
00701         }
00702     }
00703 
00704     // init buttons that haven't been seen yet working out their new names and their locations
00705     INT32 listbuttonno = 0;
00706     for (;ButtonsInitialised < pBarParam->m_NoOfButtons; ButtonsInitialised++)
00707     {
00708         // get the next free button name and put it into listbuttonno
00709         SliceHelper::GetNextFreeButtonName(listbuttonno, &(ButtonData[ButtonsInitialised].Name));
00710         ButtonData[ButtonsInitialised].HaveCreatedProperty = FALSE;
00711 
00712         if (ButtonsInitialised == 0)
00713         {
00714             ButtonData[ButtonsInitialised].Translation.x = 0;
00715             ButtonData[ButtonsInitialised].Translation.y = 0;
00716 
00717         }
00718         else
00719         {
00720             if (pBarParam->m_IsVertical)
00721             {
00722                 ButtonData[ButtonsInitialised].Translation.x = ButtonData[ButtonsInitialised-1].Translation.x;
00723 
00724                 ButtonData[ButtonsInitialised].Translation.y = ButtonData[ButtonsInitialised-1].Translation.y
00725                     - pBarParam->m_Spacing - SelRect.Height();
00726 
00727                 // place the new button on the same subpixel level as the first button?
00728                 if (pBarParam->m_Spacing == 0 || pBarParam->m_Spacing >= 3750)
00729                     ButtonData[ButtonsInitialised].Translation.y = (ButtonData[ButtonsInitialised].Translation.y /750)*750;
00730             }
00731             else
00732             {
00733                 ButtonData[ButtonsInitialised].Translation.x = ButtonData[ButtonsInitialised-1].Translation.x
00734                     + pBarParam->m_Spacing + SelRect.Width();
00735 
00736                 ButtonData[ButtonsInitialised].Translation.y = ButtonData[ButtonsInitialised-1].Translation.y;
00737 
00738                 // place the new button on the same subpixel level as the first button?
00739                 if (pBarParam->m_Spacing == 0 || pBarParam->m_Spacing >= 3750)
00740                     ButtonData[ButtonsInitialised].Translation.x = (ButtonData[ButtonsInitialised].Translation.x /750)*750;
00741             }
00742         }
00743     }
00744 
00745     // find a ptr to the original text stories in this bar
00746     for (ButtonsInitialised = 0; ButtonsInitialised < pBarParam->m_NoOfButtons; ButtonsInitialised++)
00747     {
00748         ButtonData[ButtonsInitialised].pOriginalStory = SliceHelper::FindNextTextStoryToSync( NULL,
00749                                                 pNewLayer,
00750                                                 NULL,
00751                                                 ButtonData[ButtonsInitialised].Name,
00752                                                 "",
00753                                                 TRUE);
00754 
00755         if (ButtonData[ButtonsInitialised].pOriginalStory)
00756             ButtonData[ButtonsInitialised].Storytext = ButtonData[ButtonsInitialised].pOriginalStory->GetStoryAsString();
00757 
00758 
00759         ButtonData[ButtonsInitialised].OriginalTextStoryDims.MakeEmpty();
00760         ButtonData[ButtonsInitialised].NewTextStoryDims.MakeEmpty();
00761     }
00762 
00763     // activate the layer we are about to stuff things on
00764     SliceHelper::ShowLayer(TRUE, pNewLayer, pSpread, this);
00765     LayerSGallery::MakeActiveLayer(pNewLayer, FALSE); // dont tell as this will be restored
00766 
00767     // add items directly after the layer node as its first child
00768     Node * pTail = pNewLayer;
00769     AttachNodeDirection TailAttachDirection = FIRSTCHILD;
00770 
00771     pNodeListItem = NULL;
00772     Trans2DMatrix Transformer;
00773 
00774 
00775     // for each button we want to produce
00776     INT32 but;
00777     for (but = 0; but < pBarParam->m_NoOfButtons; but++)
00778     {
00779         // copy the selection from where it is to the new layer
00780         pNodeListItem = (NodeListItem *)SelectionList.GetHead();
00781 
00782         // set the transformer to position the button
00783         Transformer.SetTransform(   ButtonData[but].Translation.x,
00784                                     ButtonData[but].Translation.y);
00785 
00786         while (pNodeListItem)
00787         {
00788             pNode = pNodeListItem->pNode;
00789             if (pNode)
00790             {
00791                 // add this node into the tree on the layer defined in list order
00792                 // Make a copy of the current node
00793                 Node* pTheCopy;
00794                 BOOL ok;
00795                 
00796                 CALL_WITH_FAIL(pNode->NodeCopy(&pTheCopy), this, ok);
00797 
00798                 if (ok && !DoInsertNewNode((NodeRenderableBounded *)pTheCopy, pTail, TailAttachDirection,
00799                                          TRUE,      // Do Invalidate region 
00800                                          FALSE))    // Don't Clear the selections
00801                     {
00802                         ok = FALSE;
00803                     }
00804 
00805                 if (ok)
00806                 {
00807                     // don't have any of these new nodes selected
00808                     pTheCopy->SetSelected(but == 0);
00809 
00810                     // move it to the new location
00811                     ((NodeRenderableBounded *)pTheCopy)->Transform(Transformer);
00812                     pTheCopy->AllowOp(&ObjChange);
00813                     DoInvalidateNodeRegion((NodeRenderableBounded*) pTheCopy, TRUE, FALSE);
00814 
00815                     // not used by this function but recorded by the object
00816                     m_FinishedBarRect = m_FinishedBarRect.Union(SliceHelper::BoundingNodeSize(pTheCopy));
00817 
00818                     // sync the text as it goes in
00819                     if (ButtonData[but].pOriginalStory && !ButtonData[but].Storytext.IsEmpty())
00820                     {
00821                         TextStory * pStory = (TextStory *) SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(TextStory), TRUE);
00822                         while (pStory)
00823                         {
00824                             // work out how to reposition this newly sync'ed text
00825                             Node * pNodeSetSentinel = Document::GetSelected()->GetSetSentinel();
00826                             NodeBarProperty * pNodeBarProperty = (NodeBarProperty*) ((NodeSetSentinel *)pNodeSetSentinel)->FindBarProperty();
00827                             INT32 alignment = pNodeBarProperty->Bar(BarNo).SameSize;
00828 
00829                             // where is the defining position of the text story before the change?
00830                             DocRect OldRect = SliceHelper::BoundingNodeSize(pStory);
00831                             BOOL changed = SliceHelper::SyncTextStories(pStory, ButtonData[but].pOriginalStory, this);
00832                             if (changed)
00833                             {
00834                                 DocRect NewRect = SliceHelper::BoundingNodeSize(pStory);
00835                                 // make the new and old texts be centred in the same place
00836                                 INT32 tx = OldRect.Centre().x - NewRect.Centre().x;
00837                                 INT32 ty = OldRect.Centre().y - NewRect.Centre().y;
00838 
00839                                 if (alignment == 1)
00840                                     tx = OldRect.lox - NewRect.lox;
00841                                 else
00842                                 if (alignment == 2)
00843                                     tx = OldRect.hix - NewRect.hix;
00844                                 
00845                                 Trans2DMatrix TextTransformer(tx, ty);
00846                                 pStory->Transform(TextTransformer);
00847 
00848                                 if (alignment == 3) // only store the data if they are different sizes
00849                                 {
00850                                     NewRect.Translate(tx,ty);
00851                                     ButtonData[but].NewTextStoryDims = ButtonData[but].NewTextStoryDims.Union(NewRect);
00852                                     ButtonData[but].OriginalTextStoryDims = ButtonData[but].OriginalTextStoryDims.Union(OldRect);
00853                                 }
00854                             }
00855                             // translate the altered text story to have the same defining position
00856                             pStory = (TextStory *) SliceHelper::FindNextOfClass(pStory, pTheCopy, CC_RUNTIME_CLASS(TextStory));
00857                         }
00858                     }
00859 
00860                     // Look at the wix attribs it has been given
00861                     if (!Target.IsEmpty()) // only if we know the target name
00862                     {
00863                         TemplateAttribute * pTemplateAttribute = (TemplateAttribute *) SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(TemplateAttribute));
00864                         while (pTemplateAttribute)
00865                         {
00866                             TemplateAttribute * pNextTemplateAttribute = (TemplateAttribute *) SliceHelper::FindNextOfClass(pTemplateAttribute, pTheCopy, CC_RUNTIME_CLASS(TemplateAttribute));
00867                             // found a target
00868                             if (Target.CompareTo(pTemplateAttribute->GetParam()) == 0)
00869                             {
00870                                 // hide this, it is replaced by the ApplyNameAttr call bellow
00871                                 // which will use the buttons new name
00872                                 //NodeListItem * pItem = new NodeListItem(pTemplateAttribute);
00873                                 //DelList.AddTail(pItem);
00874                                 DoHideNode(pTemplateAttribute, TRUE);
00875                             }
00876                             else if (!Extender.IsEmpty() && Extender.CompareTo(pTemplateAttribute->GetParam()) == 0)
00877                             {
00878                                 // found a node that matches the extender object in the selection
00879                                 // replace this with a new button name that matches the buttons
00880                                 // new name but has the word extender stuffed after it.
00881                                 // We also need to add to the node sentinel the fact that
00882                                 // NewExtenderName stretches ButtonName in the same way that
00883                                 // Extender stretched Target
00884                                 String_32   ExtenderPostfix;
00885                                 ExtenderPostfix.Load(_R(IDS_EXTENDER_POSTFIX));
00886                                 String_256  NewExtenderName = ButtonData[but].Name;
00887                                 NewExtenderName += ExtenderPostfix;
00888                                 // apply the extender name, but not the bar name to it
00889                                 ApplyNameAttr(&NewExtenderName, pTheCopy, FALSE);
00890 
00891                                 //NodeListItem * pItem = new NodeListItem(pTemplateAttribute);
00892                                 //DelList.AddTail(pItem);
00893                                 DoHideNode(pTemplateAttribute, TRUE);
00894 
00895                                 if (!ButtonData[but].HaveCreatedProperty)
00896                                 {
00897                                     TRACE( _T("redef from existing data\n"));
00898 
00899                                     DocRect TempTarget(TargetRect);
00900                                     TempTarget.Translate(   ButtonData[but].Translation.x,
00901                                                             ButtonData[but].Translation.y);
00902                                     DocRect TempExtender(ExtenderRect);
00903                                     TempExtender.Translate( ButtonData[but].Translation.x,
00904                                                             ButtonData[but].Translation.y);
00905 
00906                                     // create the properties for the button/Target that this extender extends
00907                                     SliceHelper::CreatePropertiesForSet(ButtonData[but].Name, m_BarName, TRUE, ExtenderFlags != 0, FALSE, ExtenderFlags,
00908                                                                         NewExtenderName, FALSE, &TempTarget, &TempExtender,
00909                                                                         this);
00910 
00911                                     // create default properties for the extender
00912                                     SliceHelper::CreatePropertiesForSet(NewExtenderName, TEXT(""),  FALSE, FALSE, FALSE, 0,
00913                                                                         TEXT(""), FALSE, NULL, NULL, this);
00914 
00915                                     ButtonData[but].HaveCreatedProperty = TRUE;
00916                                 }
00917                             }
00918                             pTemplateAttribute = pNextTemplateAttribute;
00919                         }
00920                     }
00921 
00922                     // make it stretch if it didn't before
00923                     if (MakeItStretch)
00924                     {
00925                         if (IS_A(pTheCopy,TextStory) || SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(TextStory)))
00926                         {
00927                             // found a node that matches the extender object in the selection
00928                             // replace this with a new button name that matches the buttons
00929                             // new name but has the word extender stuffed after it.
00930                             // We also need to add to the node sentinel the fact that
00931                             // NewExtenderName stretches ButtonName in the same way that
00932                             // Extender stretched Target
00933                             String_32   ExtenderPostfix;
00934                             ExtenderPostfix.Load(_R(IDS_EXTENDER_POSTFIX));
00935                             String_256  NewExtenderName = ButtonData[but].Name;
00936                             NewExtenderName += ExtenderPostfix;
00937                             // apply the extender name, but not the bar name to it
00938                             ApplyNameAttr(&NewExtenderName, pTheCopy, FALSE);
00939 
00940                             if (!ButtonData[but].HaveCreatedProperty)
00941                             {
00942                                 DocRect TempTarget(NoTextRect);
00943                                 TempTarget.Translate(   ButtonData[but].Translation.x,
00944                                                         ButtonData[but].Translation.y);
00945                                 DocRect TempExtender(TextRect);
00946                                 TempExtender.Translate( ButtonData[but].Translation.x,
00947                                                         ButtonData[but].Translation.y);
00948 
00949                                 // create the properties for the button/Target that this extender extends
00950                                 SliceHelper::CreatePropertiesForSet(ButtonData[but].Name, m_BarName, TRUE, pBarParam->m_ExtendFlags != 0, FALSE,
00951                                                                     pBarParam->m_ExtendFlags, NewExtenderName, FALSE,
00952                                                                     &TempTarget, &TempExtender, this);
00953 
00954                                 // create default properties for the extender
00955                                 SliceHelper::CreatePropertiesForSet(NewExtenderName, m_BarName, FALSE, FALSE, FALSE, 0,
00956                                                                     TEXT(""), FALSE, NULL, NULL, this);
00957 
00958                                 ButtonData[but].HaveCreatedProperty = TRUE;
00959                             }
00960                         }
00961                     }
00962 
00963                     // give it the button's name
00964                     ApplyNameAttr(&ButtonData[but].Name, pTheCopy);
00965 
00966                     // no extender?
00967                     // then we should add the default properties to the button
00968                     // in the node sentry too
00969                     if (Extender.IsEmpty() && !ButtonData[but].HaveCreatedProperty && !MakeItStretch)
00970                     {
00971                         SliceHelper::CreatePropertiesForSet(ButtonData[but].Name, m_BarName, TRUE, FALSE, FALSE,
00972                                                             0, TEXT(""), FALSE, NULL, NULL, this);
00973                         ButtonData[but].HaveCreatedProperty = TRUE;
00974                     }
00975 
00976                     // factor out common attribs
00977                     if (pTheCopy->IsCompound() && !pTheCopy->IsABlend())
00978                         DoFactorOutCommonChildAttributes((NodeRenderableInk*) pTheCopy);
00979                     else
00980                         DoFactorOutAfterAttrChange((NodeRenderableInk*) pTheCopy, (AttrTypeSet *)NULL);
00981 
00982                     // attach the next node after this one
00983                     TailAttachDirection = NEXT;
00984                     pTail = pTheCopy;
00985                 }
00986             }
00987 
00988             // and for the next item in the list
00989             pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
00990         }
00991     }
00992 
00993     // clean up the selection list
00994     pNodeListItem = (NodeListItem *)SelectionList.GetHead();
00995     NodeListItem *pNodeListItemToDel = NULL;
00996 
00997     while (pNodeListItem)
00998     {
00999         pNodeListItemToDel = pNodeListItem;
01000         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
01001         SelectionList.RemoveItem((NodeListItem *)pNodeListItemToDel);
01002         delete pNodeListItemToDel;
01003     }
01004 
01005     // delete the existing back bar nodes
01006     pNodeListItem = (NodeListItem *)DelList.GetHead();
01007 
01008     while(pNodeListItem)
01009     {
01010         Node *pParent = pNodeListItem->pNode;
01011 
01012         BOOL HideIt = TRUE;
01013         NodeListItem * pPreviousNodeListItem = (NodeListItem *)DelList.GetHead();
01014 
01015         //TRACEUSER( "SimonK", _T("considering %s %d\n"), (LPCTSTR) pParent->GetRuntimeClass()->m_lpszClassName, pParent);
01016 
01017         // test for deleting this item twice - a double delete will crash!!!
01018         while (pPreviousNodeListItem && pPreviousNodeListItem != pNodeListItem && HideIt)
01019         {
01020             //TRACEUSER( "SimonK", _T("testing %s %d\n"), (LPCTSTR) pPreviousNodeListItem->pNode->GetRuntimeClass()->m_lpszClassName, pPreviousNodeListItem->pNode);
01021             if (pParent == pPreviousNodeListItem->pNode)
01022             {
01023                 HideIt = FALSE; // since it has already been hidden by us
01024                 //TRACEUSER( "SimonK", _T("MATCHED\n"));
01025             }
01026 
01027             pPreviousNodeListItem = (NodeListItem *)DelList.GetNext(pPreviousNodeListItem);
01028         }
01029 
01030         // hide the node if we haven't already done so
01031         if (HideIt)
01032         {
01033             DoInvalidateNodeRegion((NodeRenderableBounded*) pParent, TRUE, FALSE);
01034             pParent->SetSelected(FALSE);
01035             DoHideNode(pParent, TRUE);
01036         }
01037 
01038         pNodeListItem = (NodeListItem *)DelList.GetNext(pNodeListItem);
01039     }
01040 
01041 
01042     pNodeListItem = (NodeListItem *)DelList.GetHead();
01043     pNodeListItemToDel = NULL;
01044 
01045     while(pNodeListItem)
01046     {
01047         pNodeListItemToDel = pNodeListItem;
01048         pNodeListItem = (NodeListItem *)DelList.GetNext(pNodeListItem);
01049         DelList.RemoveItem((NodeListItem *)pNodeListItemToDel);
01050         delete pNodeListItemToDel;
01051     }
01052 
01053     // sort out any buttons just created that need to be extended due to the text
01054     // having been swapped. This usually happens if during the "redefine state" op
01055     // added 25/8/00 by sjk
01056 
01057     for (but = 0; but < pBarParam->m_NoOfButtons; but++)
01058     {
01059         NodeSetSentinel * pNodeSetSentinel = Document::GetSelected()->GetSetSentinel();
01060         if (ButtonData[but].OriginalTextStoryDims != ButtonData[but].NewTextStoryDims)
01061         {
01062             NodeSetProperty * pProp = pNodeSetSentinel->FindPropertyNode(ButtonData[but].Name);
01063             NamedStretchProp* pStretchProp = pProp ? (NamedStretchProp*) pProp->GetProperty(NamedStretchProp::nIndex) : NULL;
01064 
01065             if (pStretchProp)
01066             {
01067                 // found an altered text story
01068                 DocRect ButtonRect = TargetRect;
01069                 if (ButtonRect.IsEmpty() || !ButtonRect.IsValid())
01070                     ButtonRect = SelRect;
01071 
01072                 ButtonRect.Translate(   ButtonData[but].Translation.x,
01073                                         ButtonData[but].Translation.y);
01074 
01075                 Node * pNode = SliceHelper::FindNextNameNode(pNewLayer, pNewLayer);
01076 
01077                 while (pNode)
01078                 {
01079                     Node * pParent = pNode->FindParent();
01080                     if (!IS_A(pParent, TextStory) && ButtonData[but].Name.CompareTo(((TemplateAttribute *)pNode)->GetParam()) == 0)
01081                         // do the extend
01082                         Extender::Extend((NodeRenderableInk*) (pParent),
01083                             pBarParam->m_ExtendFlags,
01084                             pStretchProp->GetRefUnionTriggerBounds(),
01085                             pStretchProp->GetRefTargetBounds(),
01086                             ButtonData[but].NewTextStoryDims,
01087                             ButtonData[but].OriginalTextStoryDims,
01088                             ButtonRect,
01089                             NULL, // no restrictions on extending
01090                             TRUE
01091                             );
01092 
01093                     pNode = SliceHelper::FindNextNameNode(pNode, pNewLayer);
01094                 }
01095             }
01096         }
01097     }
01098 
01099     // set the active layer to the layer that was active before
01100     // if that is possible
01101     Layer* pActiveLayer = SliceHelper::FindLayerCalled(ActiveLayerStr);
01102     if (pActiveLayer != 0)
01103         LayerSGallery::MakeActiveLayer(pActiveLayer, FALSE); // dont tell as we are putting it back
01104 
01105     // inform that there may well be more/less layers about to be visible or not
01106     BROADCAST_TO_ALL(LayerMsg(pActiveLayer, LayerMsg::LayerReason::LAYER_VISIBILITY_CHANGED));
01107 
01108     // the selection will have changed - after all we just deleted it
01109     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED));
01110     GetApplication()->UpdateSelection();
01111 
01112     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
01113     UpdateChangedNodes(&ObjChange);
01114 
01115     return TRUE;
01116 }
01117 
01118 /********************************************************************************************
01119 
01120 >   void OpBarCreation::Do(OpDescriptor*)
01121 
01122     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01123     Created:    27/8/99
01124     Inputs:     OpDescriptor (unused)
01125     Outputs:    -
01126     Returns:    -
01127     Purpose:    Creates a navigation rollover bar in the drawing by copying the selection
01128                 several times unto named layers, and naming each copy of the selection.
01129     Errors:     -
01130     SeeAlso:    OpBarCreation::DoWithParam, CarbonCopyOp::Do
01131 
01132 ********************************************************************************************/   
01133 void OpBarCreation::Do(OpDescriptor* token)
01134 {   
01135     OpParamBarCreation BarParam;
01136     DoWithParam(token, &BarParam);
01137 }
01138 
01139 
01140 /********************************************************************************************
01141 
01142 >   Layer * OpBarCreation::AddLayer(String_256 LayerName)
01143 
01144     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01145     Created:    27/8/99
01146     Inputs:     Name of the Layer to create
01147     Outputs:    Pointer to the newly created layer
01148     Returns:    -
01149     Purpose:    Create a new named layer
01150 
01151 ********************************************************************************************/
01152 Layer * OpBarCreation::AddLayer(String_256 LayerName, INT32 NewLayerNo)
01153 {
01154     Spread* pSpread = Document::GetSelectedSpread();
01155     if (pSpread == NULL)
01156         return NULL;
01157 
01158     // check to see if we need to add one first 
01159     Layer * pStandardLayer = SliceHelper::FindLayerCalled(LayerName);
01160     if (pStandardLayer)
01161     {
01162         LayerSGallery::MakeActiveLayer(pStandardLayer, FALSE); // dont tell, but we must put this back
01163         return pStandardLayer;
01164     }
01165 
01166     // find out where to add it and create it now
01167     Layer*              pLayer      = NULL;
01168     Node*               pContextNode= pSpread;
01169     AttachNodeDirection AttDir      = FIRSTCHILD;
01170     LayerStatus         NewStatus;
01171     NewStatus.StringLayerID = LayerName;
01172 
01173     // avoid the page - make the layers after the page node
01174     Node * pNode = pSpread->FindFirstChild();
01175     while (pNode)
01176     {
01177         // after the page node
01178         if (IS_A(pNode, Page))
01179         {
01180             pContextNode = pNode;
01181             AttDir = NEXT;
01182         }
01183         // and after any background nodes
01184         else if (pNode->IS_KIND_OF(Layer))
01185         {
01186             if (((Layer *)pNode)->IsBackground())
01187             {
01188                 pContextNode = pNode;
01189                 AttDir = NEXT;
01190             }
01191         }
01192 
01193         pNode = pNode->FindNext();
01194     }
01195 
01196     // order the special layers
01197     BOOL FoundHigherLayer = FALSE;
01198     INT32 LayerToFind = NewLayerNo-1;
01199     while (!FoundHigherLayer && LayerToFind >= DEFAULT)
01200     {
01201         pStandardLayer = SliceHelper::FindLayerCalled(m_RolloverName[LayerToFind]);
01202         if (pStandardLayer)
01203         {
01204             FoundHigherLayer = TRUE; // found the layer to stick it just previous to
01205 
01206             pContextNode = pStandardLayer;
01207             AttDir      = PREV;
01208         }
01209         else
01210         {
01211             LayerToFind--;
01212         }
01213     }
01214 
01215     // create the new layer and stick it in the tree
01216     ALLOC_WITH_FAIL(pLayer, (new Layer()), this);         
01217     if (pLayer == NULL) return NULL;
01218 
01219     // Set the new layer's status  
01220     pLayer->SetLayerStatus(NewStatus); 
01221 
01222     if (DoInsertNewNode(pLayer,pContextNode,AttDir,FALSE))
01223     {
01224         LayerSGallery::MakeActiveLayer(pLayer, FALSE); // dont tell but we must put this back
01225     }
01226 
01227     return pLayer;
01228 }
01229 
01230 /********************************************************************************************
01231 
01232 >   BOOL OpBarCreation::ApplyNameAttr(String_256 * pNameAttr, Node * pNode, BOOL UseBarName)
01233 
01234     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01235     Created:    27/8/99
01236     Inputs:     The object name and the node to apply it to
01237     Returns:    TRUE unless a error occurred
01238     Purpose:    To apply the names Button1, Button2, etc to the different buttons
01239                 so that the image slicing/rollover stuff works okay.
01240                 NB. it uses the question part of the wix attribute to store the
01241                 bar name. This then gets saved out in the wix files but will be
01242                 destroyed by Merlin if wixxed up.
01243 
01244 ********************************************************************************************/   
01245 BOOL OpBarCreation::ApplyNameAttr(String_256 * pNameAttr, Node * pNode, BOOL UseBarName)
01246 {
01247     TemplateAttribute* pAttr = new TemplateAttribute(   String_256(TEXT("ObjectName")),
01248                                                         UseBarName ? m_BarName : "",
01249                                                         *pNameAttr);
01250 
01251     if (!pAttr) return FALSE;
01252 
01253     // add the attrib into the tree
01254     pAttr->AttachNode(pNode, FIRSTCHILD);
01255 
01256     return TRUE;
01257 }
01258 
01259 
01260 /********************************************************************************************
01261 
01262 >   void OpBarCreation::FindAttribColours(Node * pAttrNode, INT32 PercentColourChange, INT32 State)
01263 
01264     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01265     Created:    27/8/99
01266     Inputs:     The Node to test and manipulate (it will test all its children too and their
01267                 children recursively - so use with care).
01268                 PercentColourChange - is a relative amount to change the colours by (100 does nothing)
01269                 State = (DEFAULT = 0, MOUSE = 1, CLICKED = 2, SELECTED = 3) used to gadge the
01270                 state of the button being modified.
01271     Returns:    -
01272     Purpose:    Modifies the colours of objects for the "suggest design" mode
01273                 Will also rotate bevels for the SELECTED state.
01274 
01275 ********************************************************************************************/   
01276 void OpBarCreation::FindAttribColours(Node * pAttrNode, INT32 PercentColourChange, INT32 State)
01277 {
01278     if (pAttrNode->IsAnAttribute())
01279     {
01280         // change the colour of the attribute
01281         if (PercentColourChange != 100 && pAttrNode->IsKindOf(CC_RUNTIME_CLASS(AttrFlatColourFill)))
01282         {
01283             DocColour* pdoccol = ((AttrFlatColourFill *)pAttrNode)->GetStartColour();
01284             ShiftColourValue(pdoccol, PercentColourChange);
01285         }
01286         // this else clause *must* come before that which tests for AttrFillGeometry!
01287         else if (PercentColourChange != 100 && pAttrNode->IsKindOf(CC_RUNTIME_CLASS(AttrFillGeometry)))
01288         {
01289             ColRampItem* pColItem;
01290             ColourRamp* pColRamp = ((AttrFillGeometry*)pAttrNode)->GetColourRamp();
01291             if (pColRamp != NULL)
01292             {
01293                 pColItem = pColRamp->GetFirstCol();
01294                 while (pColItem != NULL)
01295                 {
01296                     ShiftColourValue(pColItem->GetColourAddr(), PercentColourChange);
01297                     pColItem = pColRamp->GetNextCol(pColItem);
01298                 }
01299             }
01300 
01301             DocColour* pdoccol = ((AttrFillGeometry *)pAttrNode)->GetStartColour();
01302             ShiftColourValue(pdoccol, PercentColourChange);
01303             pdoccol = ((AttrFillGeometry *)pAttrNode)->GetEndColour();
01304             ShiftColourValue(pdoccol, PercentColourChange);
01305             pdoccol = ((AttrFillGeometry *)pAttrNode)->GetEndColour2();
01306             ShiftColourValue(pdoccol, PercentColourChange);
01307             pdoccol = ((AttrFillGeometry *)pAttrNode)->GetEndColour3();
01308             ShiftColourValue(pdoccol, PercentColourChange);
01309         }
01310         // rotate the bevel light angle for selected states
01311         else if (State == SELECTED && pAttrNode->IsKindOf(CC_RUNTIME_CLASS(AttrBevelLightAngle)))
01312         {
01313             // assumes the parent of the bevel attrib is the bevel controller
01314             INT32 angle = 135;
01315             Node * pParent = pAttrNode->FindParent();
01316             if (pParent->IsKindOf(CC_RUNTIME_CLASS(NodeBevelController)))
01317             {
01318                 angle = (INT32)((NodeBevelController *)pAttrNode->FindParent())->m_LightAngle + 180;
01319                 if (angle > 360) angle -= 360;
01320             }
01321             ((AttrBevelLightAngle *)pAttrNode)->SetValue(angle);
01322         }
01323     }
01324     else // find anything else interesting?
01325     {
01326         Node * pChildNode = pAttrNode->FindFirstChild();
01327 
01328         while (pChildNode)
01329         {
01330             // recursive call
01331             FindAttribColours(pChildNode, PercentColourChange, State);
01332             pChildNode = pChildNode->FindNext();
01333         }
01334     }
01335 }
01336 
01337 
01338 /********************************************************************************************
01339 
01340 >   void OpBarCreation::ShiftColourValue(DocColour* pdoccol, INT32 PercentColourChange)
01341 
01342     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01343     Created:    27/8/99
01344     Inputs:     ptr to the doc colour - changing this changes the colour
01345                 PercentColourChange - amount of colour to change
01346     Returns:    -
01347     Purpose:    Modifies the colours of objects for the "suggest design" mode
01348                 Uses HSV colour model. Drops or raises V. When this goes out of bounds
01349                 it lowers s too.
01350 
01351 ********************************************************************************************/   
01352 void OpBarCreation::ShiftColourValue(DocColour* pdoccol, INT32 PercentColourChange)
01353 {
01354     if (!pdoccol || pdoccol->IsTransparent())
01355         return;
01356 
01357     INT32 h,s,v;
01358 
01359     pdoccol->GetHSVValue(&h, &s, &v);
01360 
01361 
01362     // usual lighter and darker code
01363     if (PercentColourChange != 0)
01364     {
01365         v -= PercentColourChange - 100;
01366         if (v < 0)
01367         {
01368             s -= v*2;
01369             if (s > 255) s = 255;
01370             v = 0;
01371         }
01372         else
01373         if (v > 255)
01374         {
01375             s -= (v-255)*2;
01376             if (s < 0) s = 0;
01377             v = 255;
01378         }
01379     }
01380     else // spin the hue!!!
01381     {
01382         h += 35; // arbitry amount that you can see the difference with
01383         if (h > 255)
01384             h -= 255;
01385     }
01386     pdoccol->SetHSVValue(h, s, v);
01387 
01388 }
01389 
01390 
01391 /********************************************************************************************
01392 >   NodeBarProperty* GetBarData()
01393 
01394     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
01395     Created:    23/3/00
01396     Returns:    Current document's NodeBarProperty, if any.
01397     SeeAlso:    BarDataType; NodeBarProperty; NodeSetSentinel
01398 ********************************************************************************************/
01399 
01400 NodeBarProperty* GetBarData()
01401 {
01402     return (NodeBarProperty*) Document::GetCurrent()->GetSetSentinel()->FindBarProperty();
01403 }
01404 
01405 
01406 /********************************************************************************************
01407 >   BOOL OpBarCreation::CreateFromDefaultState (OpParam* pOpParam)
01408 
01409     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> K
01410     Created:    25/3/00
01411     Purpose:    Pretty much just has to copy the contents of this bar from the default
01412                 layer to the layer prescribed. All bar properties and stetching etc should
01413                 already have been set up from creating the MouseOff state/layer
01414 
01415     Returns:    TRUE if all went well
01416 ********************************************************************************************/
01417 BOOL OpBarCreation::CreateFromDefaultState (OpParam* pOpParam)
01418 {
01419     // work out which is the active layer so we can set this back when
01420     // we are finished playing around with them all
01421     String_256 ActiveLayerStr(_R(IDS_ROLLOVER_DEFAULT));
01422     Spread* pSpread = Document::GetSelectedSpread();
01423     if (pSpread)
01424     {
01425         ActiveLayerStr = pSpread->FindActiveLayer()->GetLayerID();
01426     }
01427 
01428     OpParamBarCreation* pBarParam = (OpParamBarCreation*)pOpParam;
01429 
01430     // get the name of this bar
01431     m_BarName = pBarParam->m_BarName;
01432 
01433     // set up the layer names
01434     m_RolloverName[DEFAULT].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default";
01435     m_RolloverName[MOUSE].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse";
01436     m_RolloverName[CLICKED].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked";
01437     m_RolloverName[SELECTED].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected";
01438     m_RolloverName[BACKBAR].Load(_R(IDS_BACK_BAR)); // = "Back Bar";
01439 
01440     INT32 NewLayerNo = 0;
01441 
01442     if (pBarParam->m_WantMouse)
01443         NewLayerNo = 1;
01444     else if (pBarParam->m_WantClicked)
01445         NewLayerNo = 2;
01446     else if (pBarParam->m_WantSelected)
01447         NewLayerNo = 3;
01448 
01449     // create the new layer
01450     Layer * pNewLayer = AddLayer(m_RolloverName[NewLayerNo], NewLayerNo);
01451     
01452     if (!pNewLayer)
01453         return FALSE;
01454 
01455     // make the new layer visible
01456     SliceHelper::ShowLayer(TRUE, pNewLayer, pSpread, this);
01457 
01458     Layer * pLayer = NULL;
01459 
01460     List BarList;
01461 
01462     pLayer = SliceHelper::FindLayerCalled(m_RolloverName[DEFAULT]);
01463 
01464     if (!pLayer)
01465         return FALSE;
01466 
01467     // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them
01468     ObjChangeFlags cFlags;
01469     cFlags.RegenerateNode = TRUE;
01470     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
01471 
01472     // list all of this bar that is on the default layer
01473     SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, m_BarName);
01474 
01475     // copy each item referenced by a template attrib marked with this bar ID
01476     NodeListItem * pNodeListItem = (NodeListItem *)BarList.GetHead();
01477     NodeListItem * pDelThisToo = NULL;
01478 
01479     Node * pTail = pNewLayer;
01480     AttachNodeDirection TailAttachDirection = FIRSTCHILD;
01481 
01482     while(pNodeListItem)
01483     {
01484         pDelThisToo = pNodeListItem;
01485         Node *pNode = pNodeListItem->pNode->FindParent();
01486         if (pNode)
01487         {
01488             // add this node into the tree on the layer defined in list order
01489             // Make a copy of the current node
01490             Node* pTheCopy;
01491             BOOL ok = TRUE;
01492             
01493             if (ok)
01494                 CALL_WITH_FAIL(pNode->NodeCopy(&pTheCopy), this, ok);
01495 
01496             if (ok && pBarParam->m_SuggestDesign)
01497             {
01498                 INT32 ColShift = 100;
01499                 if (NewLayerNo == MOUSE)
01500                     ColShift = 40;
01501                 else if (NewLayerNo == SELECTED)
01502                     ColShift = 150;
01503                 else if (NewLayerNo == CLICKED)
01504                     ColShift = 0; // this plays with the hue instead
01505 
01506                 FindAttribColours(pTheCopy, ColShift, NewLayerNo);
01507             }
01508 
01509             if (ok && !DoInsertNewNode((NodeRenderableBounded *)pTheCopy, pTail, TailAttachDirection,
01510                                      TRUE,      // Do Invalidate region 
01511                                      FALSE))    // Don't Clear the selections
01512                 {
01513                     ok = FALSE;
01514                 }
01515 
01516             if (ok)
01517             {
01518                 // if we are making the selected version check that we didn't have a default light angle
01519                 // on the bevel that we would have missed. If we did miss it add in a reverse of the 
01520                 // default light angle
01521                 if (NewLayerNo == SELECTED && pBarParam->m_SuggestDesign)
01522                 {
01523                     // was there a bevel? With out a bev light angle?
01524                     Node * pBev = SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(NodeBevelController), TRUE );
01525                     if (pBev && !SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(AttrBevelLightAngle) ))
01526                     {
01527                         // then give it a bev light angle
01528                         AttrBevelLightAngle* pNewLightAttr = new AttrBevelLightAngle();
01529                         if (pNewLightAttr)
01530                         {
01531                             pNewLightAttr->Value.m_LightAngle = 120; // reverse of the default
01532                             // add the attrib into the tree
01533                             pNewLightAttr->AttachNode(pTheCopy, FIRSTCHILD);
01534 
01535                         }
01536                     }
01537                 }
01538 
01539                 // don't have any of these new nodes selected
01540                 pTheCopy->SetSelected(FALSE);
01541 
01542                 // make it regenerate
01543                 pTheCopy->AllowOp(&ObjChange);
01544 
01545                 // attach the next node after this one
01546                 TailAttachDirection = NEXT;
01547                 pTail = pTheCopy;
01548             }
01549         }
01550 
01551         pNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem);
01552 
01553         // tidy up the list as we go along
01554         BarList.RemoveItem((NodeListItem *)pDelThisToo);
01555         delete pDelThisToo;
01556     }
01557 
01558     // set the active layer to the layer that was active before
01559     // if that is possible
01560     Layer* pActiveLayer = SliceHelper::FindLayerCalled(ActiveLayerStr);
01561     if (pActiveLayer != 0)
01562         LayerSGallery::MakeActiveLayer(pActiveLayer, FALSE); // dont tell as we are putting this back
01563 
01564     // show just the new layer we have made
01565     ShowState(NewLayerNo);
01566 
01567     // inform that there may well be more/less layers about to be visible or not
01568     BROADCAST_TO_ALL(LayerMsg(pActiveLayer, LayerMsg::LayerReason::LAYER_VISIBILITY_CHANGED));
01569     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED));
01570 
01571     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
01572     UpdateChangedNodes(&ObjChange);
01573 
01574 
01575     // the selection will have changed - after all we just deleted it
01576     GetApplication()->UpdateSelection();
01577     return TRUE;
01578 }
01579 
01580 
01581 /********************************************************************************************
01582 >   BOOL OpBarCreation::CreateBackBarFromSelection (OpParam* pOpParam)
01583 
01584     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> K
01585     Created:    5/4/00
01586     Purpose:    Creates the back bar from the selection
01587     Returns:    TRUE if all went well
01588 ********************************************************************************************/
01589 BOOL OpBarCreation::CreateBackBarFromSelection (OpParam* pOpParam, BOOL Extend)
01590 {
01591     String_256 ActiveLayerStr(_R(IDS_ROLLOVER_DEFAULT));
01592     Spread* pSpread = Document::GetSelectedSpread();
01593     if (pSpread)
01594     {
01595         ActiveLayerStr = pSpread->FindActiveLayer()->GetLayerID();
01596     }
01597 
01598     OpParamBarCreation* pBarParam = (OpParamBarCreation*)pOpParam;
01599 
01600     // get the name of this bar
01601     m_BarName = pBarParam->m_BarName;
01602 
01603     // work out the name of the back bar
01604     String_256 BackBarName = "";
01605     BackBarName.MakeMsg(_R(IDS_BACKBARNAME), SliceHelper::GetBarNumberFromBarName(m_BarName) +1);
01606 
01607     // set up the layer names
01608     m_RolloverName[DEFAULT].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default";
01609     m_RolloverName[MOUSE].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse";
01610     m_RolloverName[CLICKED].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked";
01611     m_RolloverName[SELECTED].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected";
01612     m_RolloverName[BACKBAR].Load(_R(IDS_BACK_BAR)); // = "Back Bar";
01613 
01614     List SelectionList;
01615     List DelList;
01616 
01617     // get the selection
01618     Range Sel(*(GetApplication()->FindSelection()));
01619 
01620     // set the range flags so it includes shadow and bevel manager nodes
01621     RangeControl rg = Sel.GetRangeControlFlags();
01622     rg.PromoteToParent = TRUE;
01623     Sel.Range::SetRangeControl(rg);
01624 
01625     // remove any quickshape objects from the selection
01626     if (Extender::ConvertQuickShapesInSelRangeToPaths(this, &Sel))
01627     {
01628         Sel = *(GetApplication()->FindSelection());
01629         rg = Sel.GetRangeControlFlags();
01630         rg.PromoteToParent = TRUE;
01631         Sel.Range::SetRangeControl(rg);
01632     }
01633 
01634     if (Sel.IsEmpty())
01635     {
01636         InformWarning(_R(IDS_WARNING_NO_SEL_BACKBAR));
01637         return FALSE;
01638     }
01639     
01640     // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them
01641     ObjChangeFlags cFlags;
01642     cFlags.MultiReplaceNode = TRUE;
01643     cFlags.RegenerateNode = TRUE;
01644     ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this);
01645 
01646     // Mark nodes that will allow this to happen, and error if no nodes will let it happen
01647     if (!Sel.AllowOp(&ObjChange))
01648         return FALSE; // op not allowed
01649 
01650     // get the size of the selection
01651     DocRect SelRect; // = Sel.GetBoundingRect();
01652     SelRect.MakeEmpty();
01653 
01654     // modify the selection to the allowed constraints
01655     // use the selection list from now on
01656     CleanSelection (&Sel, &SelectionList, &DelList, BACKBAR);
01657     if (SelectionList.IsEmpty())
01658     {
01659         InformWarning(_R(IDS_WARNING_NO_SEL_BACKBAR));
01660         return FALSE;
01661     }
01662 
01663     // define the SelRect from the selection list
01664     NodeListItem * pNodeListItem = (NodeListItem *)SelectionList.GetHead();
01665     while(pNodeListItem)
01666     {
01667         // localise attribs for this node
01668         DoLocaliseForAttrChange((NodeRenderableInk*) pNodeListItem->pNode, (AttrTypeSet *)NULL, (ObjectSet*) NULL);
01669 
01670         // calc the size of this node as part of the size of the selection
01671         SelRect = SelRect.Union(SliceHelper::BoundingNodeSize(pNodeListItem->pNode));
01672 
01673         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
01674     }
01675 
01676     // create a barBar layer if there isn't one
01677     Layer * pNewLayer = AddLayer(m_RolloverName[BACKBAR], BACKBAR);
01678 
01679     // mark the existing back bar for deletion if not in the selection
01680     SliceHelper::BuildListOfNodesInBar(&DelList, pNewLayer, m_BarName);
01681 
01682     // activate the layer we are about to stuff things on
01683     SliceHelper::ShowLayer(TRUE, pNewLayer, pSpread, this);
01684 
01685     LayerSGallery::MakeActiveLayer(pNewLayer, FALSE); // dont tell as we will put this back
01686 
01687     // add items directly after the layer node as its first child
01688     Node * pTail = pNewLayer;
01689     AttachNodeDirection TailAttachDirection = FIRSTCHILD;
01690 
01691     // copy the selection from where it is to the backbar layer
01692     pNodeListItem = (NodeListItem *)SelectionList.GetHead();
01693     Node * pNode;
01694 
01695     while (pNodeListItem)
01696     {
01697         pNode = pNodeListItem->pNode;
01698         if (pNode)
01699         {
01700             // add this node into the tree on the layer defined in list order
01701             // Make a copy of the current node
01702             Node* pTheCopy;
01703             BOOL ok;
01704             
01705             CALL_WITH_FAIL(pNode->NodeCopy(&pTheCopy), this, ok);
01706 
01707             if (ok && !DoInsertNewNode((NodeRenderableBounded *)pTheCopy, pTail, TailAttachDirection,
01708                                      TRUE,      // Do Invalidate region 
01709                                      FALSE))    // Don't Clear the selections
01710                 {
01711                     ok = FALSE;
01712                 }
01713 
01714             if (ok)
01715             {
01716                 // have all of these new nodes selected
01717                 pTheCopy->SetSelected(TRUE);
01718 
01719                 // delete any wix attribs that are on this node
01720                 TemplateAttribute * pTemplateAttribute = (TemplateAttribute *) SliceHelper::FindNextOfClass(pTheCopy, pTheCopy, CC_RUNTIME_CLASS(TemplateAttribute));
01721                 while (pTemplateAttribute)
01722                 {
01723                     TemplateAttribute * pNextTemplateAttribute = (TemplateAttribute *) SliceHelper::FindNextOfClass(pTemplateAttribute, pTheCopy, CC_RUNTIME_CLASS(TemplateAttribute));
01724                     // found a bar element
01725                     if (SliceHelper::GetBarNumberFromBarName(pTemplateAttribute->GetQuestion()) >= 0)
01726                     {
01727                         // hide this, it is replaced by the ApplyNameAttr call bellow
01728                         // which will use the buttons new name
01729                         DoHideNode(pTemplateAttribute, TRUE);
01730                     }
01731 
01732                     pTemplateAttribute = pNextTemplateAttribute;
01733                 }
01734 
01735                 // if it is not correctly named add the name now
01736                 ApplyNameAttr(&BackBarName, pTheCopy);
01737 
01738                 // if extending extend this backbar item on the fly!
01739                 if (Extend)
01740                 {
01741                     // do the extend
01742                     Extender::Extend((NodeRenderableInk*) (pTheCopy),
01743                         pBarParam->m_ExtendFlags,
01744                         m_BarSelectionRect,
01745                         SelRect,
01746                         m_FinishedBarRect,
01747                         m_BarSelectionRect,
01748                         SelRect,
01749                         NULL, // no restrictions on extending
01750                         TRUE
01751                         );
01752                     
01753                     // wake up blends They appear to need this extra wake up call otherwise they
01754                     // do not redraw to their new extended dimensions
01755                     if (pTheCopy->IsABlend())
01756                         ((NodeBlend*)(pTheCopy))->Reinit(FALSE);
01757                 }
01758 
01759                 // factor out common attribs
01760                 if (pTheCopy->IsCompound() && !pTheCopy->IsABlend())
01761                     DoFactorOutCommonChildAttributes((NodeRenderableInk*) pTheCopy);
01762                 else
01763                     DoFactorOutAfterAttrChange((NodeRenderableInk*) pTheCopy, (AttrTypeSet *)NULL);
01764 
01765                 // attach the next node after this one
01766                 TailAttachDirection = NEXT;
01767                 pTail = pTheCopy;
01768             }
01769         }
01770 
01771         // and for the next item in the list
01772         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
01773     }
01774 
01775 
01776     // add the back bar properties, which means it is extended by every member of the bar
01777     SliceHelper::CreatePropertiesForSet(BackBarName, m_BarName, FALSE, pBarParam->m_ExtendFlags != 0, TRUE, pBarParam->m_ExtendFlags,
01778                 TEXT(""), FALSE, &SelRect, Extend ? &m_BarSelectionRect : NULL, this);
01779 
01780     // clean up the selection list
01781     pNodeListItem = (NodeListItem *)SelectionList.GetHead();
01782     NodeListItem *pNodeListItemToDel = NULL;
01783 
01784     while (pNodeListItem)
01785     {
01786         pNodeListItemToDel = pNodeListItem;
01787         pNodeListItem = (NodeListItem *)SelectionList.GetNext(pNodeListItem);
01788         SelectionList.RemoveItem((NodeListItem *)pNodeListItemToDel);
01789         delete pNodeListItemToDel;
01790     }
01791 
01792     // delete the existing back bar nodes
01793     pNodeListItem = (NodeListItem *)DelList.GetHead();
01794     pNodeListItemToDel = NULL;
01795 
01796     while(pNodeListItem)
01797     {
01798         pNodeListItemToDel = pNodeListItem;
01799         Node *pParent = pNodeListItem->pNode;
01800 
01801         // if it is the template attrib we are looking at
01802         // we mean the node on which it is attached
01803         if (IS_A(pParent, TemplateAttribute))
01804             pParent = pParent->FindParent();
01805 
01806         if (pParent->FindParent())
01807         {
01808             DoInvalidateNodeRegion((NodeRenderableBounded*) pParent, TRUE, FALSE);
01809             pParent->SetSelected(FALSE);
01810             DoHideNode(pParent, TRUE);
01811         }
01812 
01813         pNodeListItem = (NodeListItem *)DelList.GetNext(pNodeListItem);
01814         DelList.RemoveItem((NodeListItem *)pNodeListItemToDel);
01815         delete pNodeListItemToDel;
01816     }
01817 
01818     // set the active layer to the layer that was active before
01819     // if that is possible
01820     Layer* pActiveLayer = SliceHelper::FindLayerCalled(ActiveLayerStr);
01821     if (pActiveLayer != 0) 
01822     {
01823         LayerSGallery::MakeActiveLayer(pActiveLayer, FALSE); // don't tell as we are putting it back
01824     }
01825 
01826     // inform that there may well be more/less layers about to be visible or not
01827     BROADCAST_TO_ALL(LayerMsg(pActiveLayer, LayerMsg::LayerReason::LAYER_VISIBILITY_CHANGED));
01828 
01829     // the selection will have changed - after all we just deleted it
01830     BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED));
01831     GetApplication()->UpdateSelection();
01832 
01833     ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this);
01834     UpdateChangedNodes(&ObjChange, pSpread);
01835     return TRUE;
01836 }
01837 
01838 
01839 /********************************************************************************************
01840 >   BOOL OpBarCreation::CleanSelection (Range * pSel, List * pSelectionList, List * pDeletionList)
01841 
01842     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> K
01843     Created:    30/3/00
01844     Purpose:    Has a look at the selection making it into a node list called selection
01845                 if it is on a state layer that is not the current state layer it should be
01846                 excluded from the selection as this must be an accident
01847                 if the item is in the selection but not in any state layer
01848                 it needs to be in the selection so it can be copied and added to the deletion list
01849                 so it can be removed from play.
01850 
01851     Returns:    TRUE if all went well
01852 ********************************************************************************************/
01853 BOOL OpBarCreation::CleanSelection (Range * pSel, List * pSelectionList, List * pDeletionList, INT32 LayerNumToCreate)
01854 {
01855     Layer * pLayer = NULL;
01856     Node * pCurrent = pSel->FindFirst();
01857     Node * pParent = NULL;
01858     Spread* pSpread = Document::GetSelectedSpread();
01859     BOOL AllOk = TRUE;
01860     String_256 ButtonBeingEdited = "";
01861 
01862     // for each node in the selection
01863     while (pCurrent)
01864     {
01865         // find the layer on which it resides
01866         pParent = pCurrent;
01867         while (!pParent->IsLayer())
01868             pParent = pParent->FindParent();
01869 
01870         pLayer = (Layer *)pParent;
01871 
01872         BOOL ok = FALSE;
01873 
01874         // use nodes from the layer we are going to be adding to
01875         if (LayerNumToCreate >=0 && LayerNumToCreate <=4)
01876         {
01877             if (pLayer->GetLayerID() == m_RolloverName[LayerNumToCreate])
01878                 ok = TRUE;
01879         }
01880 
01881         if (!ok)
01882         {   
01883             ok = TRUE;
01884             // test the newly found layer against the state layers
01885             // if it is not on a state layer it should be in the sel and del lists
01886             for (INT32 i = 0; i < 5; i++)
01887             {
01888                 if (pLayer->GetLayerID() == m_RolloverName[i])
01889                 {
01890                     ok = FALSE;
01891                     AllOk = FALSE;
01892                 }
01893             }
01894 
01895             if (!ok)
01896             {
01897                 // it could be a normal shape drawn on the wrong layer
01898                 // so if it is not tagged with a bar tag make it ok
01899                 ok = TRUE;
01900 
01901                 // of course we need to find the template attribs first
01902 
01903                 Node * pAttr = SliceHelper::FindNextOfClass(pCurrent,pCurrent, CC_RUNTIME_CLASS(TemplateAttribute));
01904 
01905                 while (pAttr)
01906                 {
01907                     if (!SliceHelper::GetBarName((TemplateAttribute *)pAttr).IsEmpty())
01908                     {
01909                         ok = FALSE;
01910                         break;
01911                     }
01912 
01913                     pAttr = SliceHelper::FindNextOfClass(pAttr,pCurrent, CC_RUNTIME_CLASS(TemplateAttribute));
01914                 }
01915             }
01916 
01917             if (ok) // add to the deletion list - its on Layer 1 or whatever
01918             {
01919                 NodeListItem * pItem = new NodeListItem(pCurrent);
01920                 pDeletionList->AddTail(pItem);
01921             }
01922         }
01923         else // drawn on the layer you are going to copy to? 
01924             //  still want to delete your original drawing as it wont have the tags required
01925         {
01926             // only want to copy from a single button
01927             // if it is from a different button do not add it to the selection or
01928             // delete it
01929             // of course we need to find the template attribs first
01930 
01931             Node * pAttr = SliceHelper::FindNextOfClass(pCurrent,pCurrent, CC_RUNTIME_CLASS(TemplateAttribute));
01932             BOOL FromThisBar = TRUE;
01933 
01934             while (pAttr)
01935             {
01936                 if (!SliceHelper::GetBarName((TemplateAttribute *)pAttr).IsEmpty())
01937                 {
01938                     // the source is from another bar
01939                     if (m_BarName.CompareTo(SliceHelper::GetBarName((TemplateAttribute *)pAttr)) != 0)
01940                     {
01941                         FromThisBar = FALSE;
01942                     }
01943 
01944                     String_256 AttrSet = SliceHelper::GetSetNameFromAttrib(pAttr);
01945                     if (ButtonBeingEdited.IsEmpty())
01946                     {
01947                         ButtonBeingEdited = AttrSet;
01948                         break;
01949                     }
01950                     else if (ButtonBeingEdited == AttrSet || AttrSet.IsEmpty())
01951                     {
01952                         break;
01953                     }
01954                     else
01955                         ok = FALSE; // it is of another bar name set
01956                     break;
01957                 }
01958 
01959                 pAttr = SliceHelper::FindNextOfClass(pAttr,pCurrent, CC_RUNTIME_CLASS(TemplateAttribute));
01960             }
01961             
01962             if (ok && FromThisBar) // delete it from here
01963             {
01964                 NodeListItem * pItem = new NodeListItem(pCurrent);
01965                 pDeletionList->AddTail(pItem);
01966             }
01967         }
01968 
01969         if (ok)
01970         { // add to the selection list
01971             NodeListItem * pItem = new NodeListItem(pCurrent);
01972             pSelectionList->AddTail(pItem);
01973         }
01974 
01975         // check the next item on the list
01976         pCurrent = pSel->FindNext(pCurrent);
01977     }
01978 
01979     return AllOk;
01980 }
01981 
01982 
01983 /********************************************************************************************
01984 
01985 >   void OpBarCreation::ShowState(INT32 ShowLayer)
01986 
01987     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01988     Created:    12/6/00
01989     Returns:    -
01990     Purpose:    Makea sure that that just the state is shown, out of the specail states
01991                 Updates the screen drawing and informs other dlgs/galleries such as
01992                 the layer gallery.
01993 
01994 ********************************************************************************************/
01995 void OpBarCreation::ShowState(INT32 ShowLayer)
01996 {
01997     OpShowState::ShowState(ShowLayer, this);
01998 }
01999 
02000 BOOL OpBarCreation::CreateBarAndBackBar (OpParam* pOpParam)
02001 {
02002 
02003     // unselect the back object and note it down to make into a back bar
02004     Node * pBackObj = NULL;
02005 
02006     // get the selection
02007     Range Sel(*(GetApplication()->FindSelection()));
02008 
02009     // set the range flags so it includes shadow and bevel manager nodes
02010     RangeControl rg = Sel.GetRangeControlFlags();
02011     rg.PromoteToParent = TRUE;
02012     Sel.Range::SetRangeControl(rg);
02013 
02014     if (Sel.Count() < 2)
02015         return FALSE;
02016     else
02017     {
02018         pBackObj = Sel.FindFirst();
02019         pBackObj->SetSelected(FALSE);
02020     }
02021 
02022 
02023     BOOL ok = CreateOrEditBar(pOpParam);
02024 
02025     if (!ok)
02026     {
02027         InformWarning(_R(IDS_FAILLED_MAKE_BAR));
02028         return FALSE;
02029     }
02030 
02031     // deselect everything
02032     NodeRenderableInk::DeselectAll(TRUE);
02033 
02034     // select everything in the group not the group itself
02035     // dont bother with this now as we deal with true groups extending
02036 /*  if (pBackObj->IsCompound())
02037     {
02038         pBackObj = pBackObj->FindFirstChild();
02039         while (pBackObj)
02040         {
02041             if (!pBackObj->IsNodeHidden() && !pBackObj->IsAnAttribute())
02042                 pBackObj->SetSelected(TRUE);
02043 
02044             pBackObj = pBackObj->FindNext();
02045         }
02046     }
02047     else // else select the node
02048 */      pBackObj->SetSelected(TRUE);
02049 
02050     ok = CreateBackBarFromSelection(pOpParam, TRUE);
02051 
02052     if (!ok)
02053         InformWarning(_R(IDS_FAILLED_MAKE_BACKBAR));
02054 
02055     return ok;
02056 }
02057 

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