zordops.cpp

Go to the documentation of this file.
00001 // $Id: zordops.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 //Revision 1.13  1994/04/29  12:41:05  Simon
00100 //Changed all operations so that they correctly work across layers
00101 //
00102 //Revision 1.12  1994/04/14  18:13:00  Tim
00103 //Major change to Node class hierarchy.
00104 //
00105 //Revision 1.11  1994/03/25  17:59:32  Simon
00106 //New messaging system changes + Moved  certain Op flags into opDescriptors
00107 //
00108 //Revision 1.10  1994/03/14  10:24:00  Simon
00109 //Changed all ops so they use the new high level Do functions 
00110 //
00111 //Revision 1.9  1994/02/25  15:34:10  JustinF
00112 //Added bubble help resource ID's to all uses of OpDescriptor
00113 //
00114 //Revision 1.8  1994/01/26  17:01:59  Rik
00115 //Fixed Blob and bounding rectangle problems
00116 //
00117 //Revision 1.7  1993/12/23  10:49:39  Tim
00118 //New Spread based coordinate system
00119 //
00120 //Revision 1.6  1993/11/25  12:17:20  Simon
00121 //Added operation disabled reason strings to all operations 
00122 //
00123 //Revision 1.5  1993/11/19  17:53:58  Simon
00124 //No change 
00125 //
00126 //Revision 1.4  1993/10/20  16:14:25  Simon
00127 //Made all Z operations undoable
00128 //
00129 //Revision 1.3  1993/10/11  17:34:33  Mario
00130 //Changed prototype of GetState() function to use String_256*
00131 //
00132 //Revision 1.2  1993/10/11  12:18:21  Simon
00133 //Added Bring forwards and Move backwards operations
00134 //
00135 //Revision 1.1  1993/10/01  18:17:16  Simon
00136 //Initial revision
00137 //
00138 
00139 #include "camtypes.h" 
00140 #include "zordops.h"
00141 //#include "simon.h" 
00142 //#include "errors.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00143 //#include "ensure.h"    - in camtypes.h [AUTOMATICALLY REMOVED]
00144 //#include "docview.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00145 //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00146 //#include "mario.h"
00147 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00148 //#include "ink.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00149 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00150 #include "layer.h"
00151 //#include "markn.h"
00152 #include "bubbleid.h"
00153 
00154 //#include "prevwres.h" // _R(IDS_COMBINELAYERSTOFRAMELAYER)
00155 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00156 //#include "layergal.h" // LayerStateAction
00157 #include "sprdmsg.h"    // SpreadMsg::SpreadReason::LAYERCHANGES
00158 #include "layermsg.h"   // UPDATE_ACTIVE_LAYER
00159 //#include "bmpsdlgr.h"
00160 //#include "opbevel.h"
00161 #include "slicehelper.h"
00162 #include "ophist.h"
00163       
00164 DECLARE_SOURCE("$Revision: 1282 $");  
00165 
00166 CC_IMPLEMENT_DYNCREATE(OpBringToFront, SelOperation)
00167 CC_IMPLEMENT_DYNCREATE(OpPutToBack, SelOperation)
00168 CC_IMPLEMENT_DYNCREATE(OpMoveForwards, SelOperation)  
00169 CC_IMPLEMENT_DYNCREATE(OpMoveBackwards, SelOperation)
00170 CC_IMPLEMENT_DYNCREATE(OpMoveToLyrInFront, SelOperation)  
00171 CC_IMPLEMENT_DYNCREATE(OpMoveToLyrBehind, SelOperation)
00172 CC_IMPLEMENT_DYNAMIC(FrameInFrontOpDescriptor, OpDescriptor)
00173 CC_IMPLEMENT_DYNAMIC(FrameBehindOpDescriptor, OpDescriptor)
00174 
00175 //CC_IMPLEMENT_DYNCREATE(OpCombineLayersToFrameLayer, SelOperation)
00176 
00177 #define new CAM_DEBUG_NEW    
00178 
00179 // ------------------------------------------------------------------------------------------
00180 // WEBSTER Z-ORDER OPS (markn 2/2/97)
00181 //
00182 // As Webster doesn't have a concept of layers, the z-order operations have been rewritten so
00183 // that they function across layers.  I.e. when an object has its Z position changed, it is not
00184 // localised to the selected object's layer.  It will move across layers when necessary.
00185 //
00186 // The ops "Move to layer infront" and "Move to layer behind" have been removed as they are
00187 // obsolete in WEBSTER
00188 //
00189 // Neville 23/6/97
00190 // The ops "Move to layer infront" and "Move to layer behind" are now back in but perform
00191 // across frame layers.
00192 
00193 #ifdef WEBSTER
00194 // ------------------------------------------------------------------------------------------
00195 // Help funcs - WEBSTER - markn 2/2/97
00196 
00197 // static Node* FindLastObject(Layer* pLayer)
00198 //
00199 // Finds the last object on a layer, but only if the layer is one that can be edited.
00200 // Returns NULL if conditions aren't right
00201 static Node* FindLastObject(Layer* pLayer)
00202 {
00203     if (pLayer == NULL)
00204         return NULL;
00205 
00206     if (pLayer->IsLocked() || pLayer->IsGuide())
00207         return NULL;
00208 
00209     return pLayer->FindLastChild(CC_RUNTIME_CLASS(NodeRenderableInk));
00210 }
00211 
00212 // static Node* FindFirstObject(Layer* pLayer)
00213 //
00214 // Finds the first object on a layer, but only if the layer is one that can be edited.
00215 // Returns NULL if conditions aren't right
00216 static Node* FindFirstObject(Layer* pLayer)
00217 {
00218     if (pLayer == NULL)
00219         return NULL;
00220 
00221     if (pLayer->IsLocked() || pLayer->IsGuide())
00222         return NULL;
00223 
00224     return pLayer->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk));
00225 }
00226 #endif // WEBSTER
00227 
00228 // ------------------------------------------------------------------------------------------
00229 // OpBringToFront methods
00230             
00231 /********************************************************************************************
00232 
00233 >   OpBringToFront::OpBringToFront() 
00234 
00235     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00236     Created:    29/9/93
00237     Inputs:     -
00238     Outputs:    -
00239     Returns:    -
00240     Purpose:    OpBringToFront constructor
00241     Errors:     -
00242     SeeAlso:    -
00243 
00244 ********************************************************************************************/
00245             
00246             
00247 OpBringToFront::OpBringToFront(): SelOperation()                                
00248 {                              
00249 }
00250 
00251  /********************************************************************************************
00252 
00253 >   BOOL OpBringToFront::Init()
00254 
00255     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00256     Created:    28/9/93
00257     Inputs:     -
00258     Outputs:    -
00259     Returns:    TRUE if the operation could be successfully initialised 
00260                 FALSE if no more memory could be allocated 
00261                 
00262     Purpose:    OpBringToFront initialiser method
00263     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00264                 operation.
00265     SeeAlso:    -
00266 
00267 ********************************************************************************************/
00268 
00269 BOOL OpBringToFront::Init()
00270 {
00271     return (RegisterOpDescriptor(0,
00272                                 _R(IDS_BRINGTOFRONTOP),
00273                                 CC_RUNTIME_CLASS(OpBringToFront),
00274                                 OPTOKEN_BRINGTOFRONT,
00275                                 OpBringToFront::GetState,
00276                                 0,  /* help ID */
00277                                 _R(IDBBL_BRINGTOFRONTOP),
00278                                 0,  
00279                                 0,
00280                                 SYSTEMBAR_ILLEGAL,          // For now !
00281                                 TRUE,                       // Receive messages
00282                                 FALSE,
00283                                 FALSE,
00284                                 0,
00285                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
00286 
00287                                 )); 
00288 
00289 }               
00290 
00291 /********************************************************************************************
00292 
00293 >   OpState OpBringToFront::GetState(String_256*, OpDescriptor*)
00294 
00295     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
00296     Created:    28/9/93
00297     Inputs:     -
00298     Outputs:    -
00299     Returns:    The state of the OpBringToFront operation
00300     Purpose:    For finding OpBringToFront's state. 
00301 
00302                 See note at the top of file about WEBSTER z-order ops
00303     Errors:     -
00304     SeeAlso:    -
00305 
00306 ********************************************************************************************/
00307 
00308 OpState OpBringToFront::GetState(String_256*  UIDescription, OpDescriptor*)
00309 {
00310 #ifdef WEBSTER
00311     OpState OpSt;
00312     String_256 DisableReason; 
00313 
00314     // DMc changed for select inside on bevels etc
00315     
00316     SelRange Sel(*( GetApplication()->FindSelection());
00317     RangeControl rg = Sel.GetRangeControlFlags();
00318     rg.PromoteToParent = TRUE;
00319     Sel.Range::SetRangeControl(rg);
00320 
00321     Node* pSelNode = Sel.FindFirst();
00322     while (pSelNode != NULL)
00323     {
00324         Node* pNode = pSelNode;
00325         while (pNode != NULL)
00326         {
00327             Node* pOldNode = pNode;     // Remember this node
00328 
00329             if (pNode != NULL)
00330                 pNode = pNode->FindNext();  // Get the node after this node
00331 
00332             // If the next node is an unselected object, then we can move this object to the front
00333             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00334                 goto End;
00335 
00336             if (pNode == NULL)
00337             {
00338                 // Find the parent layer
00339                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
00340 
00341                 // Find the last object on the first editable layer we can find that follows this layer
00342                 do
00343                 {
00344                     pLayer = pLayer->FindNextLayer(TRUE);
00345                     pNode = FindFirstObject(pLayer);
00346 
00347                 } while (pLayer != NULL && pNode == NULL);
00348 
00349                 // If the next node is an unselected object, then we can move this object to the front
00350                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00351                     goto End;
00352             }
00353         } 
00354 
00355         // Try the next selected node.
00356         pSelNode = Sel.FindNext(pSelNode);
00357     }
00358 
00359     OpSt.Greyed = TRUE;
00360  
00361     // Determine which reason string to return
00362     if (Sel.Count() > 1)
00363     {
00364         DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTP)); // A plural description
00365     }
00366     else
00367     {
00368         DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTS));
00369     }
00370     *UIDescription = DisableReason;                                       
00371 
00372     End:                                                 
00373     return(OpSt);
00374 
00375 #else
00376 // WEBSTER - markn 2/2/97
00377 // Original code
00378 
00379     OpState OpSt;
00380     String_256 DisableReason;
00381 
00382     // DMc changed for select inside on bevels etc
00383     SelRange Sel (*(GetApplication()->FindSelection()));
00384     RangeControl rg = Sel.GetRangeControlFlags();
00385     rg.PromoteToParent = TRUE;
00386     Sel.Range::SetRangeControl(rg);
00387 
00388     // If all selected objects are already at the front of their layers then the operation should be
00389     // disabled. 
00390     Node* Current = Sel.FindFirst(); 
00391     Node* LastCurrent;
00392     MODE PresentMode = FRAME; // In case Current is NULL
00393 
00394     // Determine the correct document mode.
00395     if(Current)
00396     {
00397         Layer* CurrentLayer = (Layer*) (Current->FindParent(CC_RUNTIME_CLASS(Layer)));
00398         ERROR2IF(CurrentLayer == NULL, OpSt, "Cannot find layer of first selected object"); 
00399 
00400         // The mode of this document - Frame/Layer.
00401         PresentMode = (MODE)CurrentLayer->IsFrame();
00402     }
00403 
00404     BOOL bSelected = FALSE;
00405     
00406     while(Current != NULL) // Loop for all layers
00407     {   
00408         // If an unselected object is found on this layer with a higher z-order position than
00409         // Current then the operation can be performed.
00410         do
00411         {
00412             // DMc revision 4/6/99
00413             if (Current->ShouldITransformWithChildren())
00414             {
00415                 // check to see if any of its children are selected
00416                 RangeControl rg(TRUE, FALSE);
00417                 Range rng(Current, Current, rg);
00418 
00419                 if (rng.IsEmpty())
00420                 {
00421                     bSelected = FALSE;
00422                 }
00423                 else
00424                 {
00425                     bSelected = TRUE;
00426                 }
00427             }
00428             else
00429             {
00430                 bSelected = Current->IsSelected();
00431             }
00432             
00433             if ((Current->IsAnObject()) && (!(bSelected)))
00434             {
00435                 goto End; // The operation can be performed
00436             }
00437             LastCurrent = Current;
00438             Current = Current->FindNext(); 
00439         } while (Current != NULL);
00440         // Obtain the next selected object (on the next layer)
00441         Current = Sel.FindNext(LastCurrent); 
00442     }
00443     // All selected objects are already at the front of their layers
00444     OpSt.Greyed = TRUE; 
00445 
00446     if(PresentMode == FRAME)
00447     {
00448         // Determine which reason string to return
00449         if (Sel.Count() > 1)
00450         {
00451             DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTP_FRAME)); // A plural description
00452         }
00453         else
00454         {
00455             DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTS_FRAME));
00456         }
00457     }
00458     else if (PresentMode == LAYER)
00459     {
00460         // Determine which reason string to return
00461         if (Sel.Count() > 1)
00462         {
00463             DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTP)); // A plural description
00464         }
00465         else
00466         {
00467             DisableReason = String_256(_R(IDS_ALREADY_AT_FRONTS));
00468         }
00469     }
00470     else
00471         ERROR3("OpBringToFront::GetState - Bad mode!");
00472 
00473     *UIDescription = DisableReason;                                       
00474     End:                                                 
00475     return(OpSt);   
00476 
00477 #endif // WEBSTER
00478 }
00479 
00480 /********************************************************************************************
00481 
00482 >   void OpBringToFront::Do(OpDescriptor*)
00483 
00484     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
00485     Created:    16/8/93
00486     Inputs:     OpDescriptor (unused)
00487     Outputs:    -
00488     Returns:    -
00489     Purpose:    Performs the BringToFront operation, this moves all selected objects to the 
00490                 front of their layers.
00491                 
00492                 See note at the top of file about WEBSTER z-order ops
00493     Errors:     -
00494     SeeAlso:    -
00495 
00496 ********************************************************************************************/
00497         
00498 void OpBringToFront::Do(OpDescriptor*)         
00499 {  
00500 #ifdef WEBSTER
00501     OpState OpSt;
00502     String_256 DisableReason; 
00503 
00504     SelRange Sel (*( GetApplication()->FindSelection());
00505     RangeControl rg = Sel.GetRangeControlFlags();
00506     rg.PromoteToParent = TRUE;
00507     Sel.Range::SetRangeControl(rg);
00508 
00509     Node* pSelNode = Sel.FindLast();
00510 
00511     // If there are selected objects, record undo stuff about the selection
00512     if (pSelNode != NULL)
00513     {
00514         // Try to record the selection state , don't render the blobs though
00515         // the invalidate will take care of this. 
00516         if (!DoStartSelOp(FALSE,FALSE))
00517             goto EndOperation;  
00518 
00519         // We need to invalidate the region
00520         if (!DoInvalidateNodesRegions(*Sel, TRUE))
00521             goto EndOperation; 
00522     }
00523 
00524     while (pSelNode != NULL)
00525     {
00526         Node* pContextNode = NULL;
00527 
00528         Node* pNode = pSelNode;
00529         while (pNode != NULL)
00530         {
00531             Node* pOldNode = pNode;     // Remember this node
00532 
00533             if (pNode != NULL)
00534                 pNode = pNode->FindNext();  // Get the node after this node
00535 
00536             // If the next node is an unselected object, then we can move this object to the front
00537             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00538                 pContextNode = pNode;
00539 
00540             if (pNode == NULL)
00541             {
00542                 // Find the parent layer
00543                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
00544 
00545                 // Find the last object on the first editable layer we can find that follows this layer
00546                 do
00547                 {
00548                     pLayer = pLayer->FindNextLayer(TRUE);
00549                     pNode = FindFirstObject(pLayer);
00550 
00551                 } while (pLayer != NULL && pNode == NULL);
00552 
00553                 // If the next node is an unselected object, then we can move this object to the front
00554                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00555                     pContextNode = pNode;
00556             }
00557         } 
00558 
00559         pNode = pSelNode;
00560         // Try the next selected node.
00561         pSelNode = Sel.FindPrev(pSelNode);
00562 
00563         if (pContextNode != NULL)
00564         {
00565             if (!DoMoveNode(pNode, pContextNode, NEXT))
00566                 goto EndOperation;
00567 
00568             pNode->SetSelected(TRUE);
00569         }
00570     }
00571 
00572     EndOperation:    
00573     End(); // End of operation
00574 
00575 #else
00576 // WEBSTER - markn 2/2/97
00577 // Original code
00578 
00579     // Obtain the current selections
00580     // Copy SelRange into a range so that it cannot change during the operation
00581     // Note: the cache is freshened by this 
00582     Range Sel(*(GetApplication()->FindSelection()));
00583     RangeControl rg = Sel.GetRangeControlFlags();
00584     rg.PromoteToParent = TRUE;
00585     Sel.Range::SetRangeControl(rg);
00586 
00587 
00588     // Find the first node which is selected 
00589     Node* FirstSelectedNode = Sel.FindFirst(); 
00590  
00591     // The first selected node should not ever be NULL. The GetState fn should have seen
00592     // to this.
00593     ENSURE(FirstSelectedNode != NULL, 
00594         "The OpBringToFront's GetState fn has not done a very good job"); 
00595     
00596     // lets be defensive about it anyway
00597     if (FirstSelectedNode != NULL) 
00598     {
00599         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state 
00600         {
00601             goto EndOperation;  
00602         }
00603 
00604         // We need to invalidate the region
00605         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
00606         {
00607             goto EndOperation; 
00608         }
00609         
00610         Spread* pSpread; 
00611         Node* Tail;
00612         Node* NextSelNode;  
00613 
00614         // We will need to scan the layers one at a time so create a Range control to
00615         // acheive this. 
00616 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE };  // Selected + don't cross layers  
00617         Range LayerRange; 
00618         
00619         // Find the spread that the selection lies on
00620         pSpread = FirstSelectedNode->FindParentSpread();
00621         
00622         Node* CurrentNode = FirstSelectedNode;     
00623         Node* LastNodeOnLayer;
00624 
00625         // Loop for all layers
00626         while(CurrentNode != NULL)
00627         {
00628 
00629             // Create a range of selected nodes on this layer
00630             Range temp(CurrentNode, 
00631                                NULL, 
00632                                RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
00633             LayerRange = temp;
00634 //          LayerRange = Range(CurrentNode, 
00635 //                             NULL,
00636 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
00637 
00638             FirstSelectedNode = CurrentNode; 
00639             
00640             // Find the last ink object on this layer
00641             LastNodeOnLayer = CurrentNode->FindParent(CC_RUNTIME_CLASS(Layer))->FindLastChild();
00642             if (LastNodeOnLayer->IsAnObject())
00643             {
00644                 Tail = LastNodeOnLayer;
00645             }
00646             else
00647             {
00648                 Tail = LastNodeOnLayer->FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk));
00649             }
00650                 
00651             // If the first node selected is already at the front then we don't really want
00652             // to move it. In this situation we know that there can be no other selected nodes 
00653             // so we need not do anything                    
00654             if (FirstSelectedNode != Tail)
00655             {    
00656                 do 
00657                 {   
00658                     ENSURE (CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), 
00659                     "Selected node not a NodeRenderableBounded");
00660                 
00661                     // Find the next selected node on the current layer
00662                     NextSelNode = LayerRange.FindNext(CurrentNode); 
00663             
00664                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
00665                     if (!DoMoveNode(CurrentNode, Tail, NEXT)) 
00666                     {
00667                         goto EndOperation;
00668                     }
00669 
00670                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
00671                     CurrentNode->SetSelected(TRUE);
00672                      
00673                     Tail = CurrentNode; 
00674                     CurrentNode = NextSelNode;     
00675             
00676                     // Stop when we hit the first node which was moved. 
00677                     // or when there are no more selected nodes (This can only happen if there is only
00678                     // one node selected). 
00679                 } while ((CurrentNode != FirstSelectedNode) && (CurrentNode != NULL)); 
00680          
00681             } 
00682             // Get the first selected node of the next layer
00683             CurrentNode = Sel.FindNext(Tail); 
00684             ENSURE(LayerRange.FindNext(Tail) == NULL, 
00685                 "Current Node is not the last selected node on the layer"); 
00686         } 
00687         // We need to invalidate the region
00688         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE, FALSE))
00689         {
00690             goto EndOperation; 
00691         }
00692     }
00693 
00694     EndOperation:
00695     GetApplication()->UpdateSelection();
00696     
00697     End(); // End of operation
00698 
00699 #endif // WEBSTER
00700 } 
00701 
00702 // ------------------------------------------------------------------------------------------
00703 // OpPutToBack methods
00704             
00705 /********************************************************************************************
00706 
00707 >   OpPutToBack::OpPutToBack() 
00708 
00709     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00710     Created:    29/9/93
00711     Inputs:     -
00712     Outputs:    -
00713     Returns:    -
00714     Purpose:    OpPutToBack constructor
00715     Errors:     -
00716     SeeAlso:    -
00717 
00718 ********************************************************************************************/
00719             
00720             
00721 OpPutToBack::OpPutToBack(): SelOperation()                              
00722 {                              
00723 }
00724 
00725 /********************************************************************************************
00726 
00727 >   OpState OpPutToBack::GetState(String_256*, OpDescriptor*)
00728 
00729     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
00730     Created:    28/9/93
00731     Inputs:     -
00732     Outputs:    -
00733     Returns:    The state of the OpPutToBack operation
00734     Purpose:    For finding OpPutToBack's state. 
00735 
00736                 See note at the top of file about WEBSTER z-order ops
00737     Errors:     -
00738     SeeAlso:    -
00739 
00740 ********************************************************************************************/
00741 
00742 OpState OpPutToBack::GetState(String_256*  UIDescription, OpDescriptor*)
00743 {
00744 #ifdef WEBSTER
00745 
00746     OpState OpSt;
00747     String_256 DisableReason; 
00748 
00749     SelRange Sel(*( GetApplication()->FindSelection()));
00750 
00751     Node* pSelNode = Sel.FindFirst();
00752     while (pSelNode != NULL)
00753     {
00754         Node* pNode = pSelNode;
00755         while (pNode != NULL)
00756         {
00757             Node* pOldNode = pNode;     // Remember this node
00758 
00759             if (pNode != NULL)
00760                 pNode = pNode->FindPrevious();  // Get the node before this node
00761 
00762             // If the previous node is an unselected object, then we can move this object back
00763             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00764                 goto End;
00765 
00766             if (pNode == NULL)
00767             {
00768                 // Find the parent layer
00769                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
00770 
00771                 // Find the last object on the first editable layer we can find that preceeds this layer
00772                 do
00773                 {
00774                     pLayer = pLayer->FindPrevLayer(TRUE);
00775                     pNode = FindLastObject(pLayer);
00776 
00777                 } while (pLayer != NULL && pNode == NULL);
00778 
00779                 // If the previous node is an unselected object, then we can move this object back
00780                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
00781                     goto End;
00782             }
00783         } 
00784 
00785         // Try the next selected node.
00786         pSelNode = Sel.FindNext(pSelNode);
00787     }
00788 
00789     OpSt.Greyed = TRUE;
00790  
00791     // Determine which reason string to return
00792     if (Sel.Count() > 1)
00793     {
00794         DisableReason = String_256(_R(IDS_ALREADY_AT_BACKP)); // A plural description
00795     }
00796     else
00797     {
00798         DisableReason = String_256(_R(IDS_ALREADY_AT_BACKS));
00799     }
00800     *UIDescription = DisableReason;                                       
00801 
00802     End:                                                 
00803     return(OpSt);
00804 
00805 #else
00806 
00807 // WEBSTER - markn 30/1/97
00808 // Original code
00809 
00810     OpState OpSt;
00811     String_256 DisableReason; 
00812 
00813     // DMc
00814     Range Sel(*(GetApplication()->FindSelection()));
00815     RangeControl rg = Sel.GetRangeControlFlags();
00816     rg.PromoteToParent = TRUE;
00817     Sel.Range::SetRangeControl(rg);
00818 
00819     // Find the first node which is selected 
00820     Node* FirstSelectedNode = Sel.FindFirst(); 
00821 
00822     // If all selected objects are already at the back then the operation should be
00823     // disabled
00824     Node* Current = FirstSelectedNode; 
00825     MODE PresentMode = LAYER;
00826 
00827     Spread* pSpread = (Spread*) (Current->FindParent (CC_RUNTIME_CLASS (Spread)));
00828     
00829     // Determine the correct document mode.
00830     if (Current && pSpread)
00831     {
00832         Layer* CurrentLayer = (Layer*) (Current->FindParent(CC_RUNTIME_CLASS(Layer)));
00833         ERROR2IF(CurrentLayer == NULL, OpSt, "Cannot find layer of first selected object"); 
00834 
00835         // The mode of this document - Frame/Layer.
00836         PresentMode = (MODE)CurrentLayer->IsFrame();
00837     }
00838 
00839     // now scan each layer ....
00840 
00841     BOOL allowed = FALSE;
00842 
00843     Layer* pNode = (Layer*) SliceHelper::FindNextOfClass(pSpread, pSpread, CC_RUNTIME_CLASS (Layer));
00844 
00845     // If an unselected object is found on this layer with a lower z-order position than
00846     // LastSelCurrent then the operation can be performed.
00847 
00848     while (pNode)
00849     {
00850         Node* lastSelected = NULL;
00851         BOOL currentLayerAllow = FALSE;             // so that we can detect an individual layer NOT allowing
00852                                                     // the op, where previous have
00853         
00854         if (Current->FindParent (CC_RUNTIME_CLASS (Layer)) == Sel.FindLast ()->FindParent (CC_RUNTIME_CLASS (Layer)))
00855         {
00856             lastSelected = Sel.FindLast ();
00857         }
00858         else
00859         {
00860             // scan for the last selected node on this layer ....
00861 
00862             Node* Scan = pNode->FindLastChild ();
00863 
00864             while (Scan != NULL)
00865             {
00866                 if (Scan->IsAnObject() && Scan->IsSelected())
00867                 {
00868                     lastSelected = Scan;
00869                     break; 
00870 
00871                 }
00872                 Scan = Scan->FindPrevious();
00873             }
00874         }
00875 
00876         // -----------------------------------------------------------------------------
00877         // If an unselected object is found on this layer with a lower z-order position than
00878         // LastSelCurrent then the operation can be performed.
00879 
00880         Node* Current = lastSelected;
00881 
00882         if (Current)
00883         {
00884             do
00885             {
00886                 // DMc revision 4/6/99
00887                 BOOL bSelected = FALSE;
00888                 if (Current->ShouldITransformWithChildren())
00889                 {
00890                     // check to see if any of its children are selected
00891                     RangeControl rg(TRUE, FALSE);
00892                     Range rng(Current, Current, rg);
00893 
00894                     if (rng.IsEmpty())
00895                     {
00896                         bSelected = FALSE;
00897                     }
00898                     else
00899                     {
00900                         bSelected = TRUE;
00901                     }
00902                 }
00903                 else
00904                 {
00905                     bSelected = Current->IsSelected();
00906                 }
00907                     
00908                 if ((Current->IsAnObject()) && (!(bSelected)))
00909                 {
00910                     currentLayerAllow = TRUE;   // weve set this layer
00911                     allowed = TRUE;             // The operation can be performed
00912                 }
00913                     
00914                 Current = Current->FindPrevious(); 
00915             } while (Current != NULL);
00916         }
00917         else
00918         {
00919             currentLayerAllow = TRUE;       // nothing on this layer, we should still allow the op
00920         }
00921 
00922         // wo there, if one layer returned TRUE, and this one returned FALSE, then we MUST disable the op!
00923 
00924         if (allowed && !currentLayerAllow)
00925         {
00926             goto Disable;
00927         }
00928     
00929         pNode = (Layer*) SliceHelper::FindNextOfClass(pNode, pSpread, CC_RUNTIME_CLASS (Layer));
00930     }
00931 
00932     if (allowed)
00933     {
00934         goto End;
00935     }
00936 
00937     Disable:
00938 
00939     OpSt.Greyed = TRUE;
00940 
00941     if(PresentMode == LAYER)
00942     {
00943         // Determine which reason string to return
00944         if (Sel.Count() > 1)
00945         {
00946             DisableReason = String_256(_R(IDS_ALREADY_AT_BACKP)); // A plural description
00947         }
00948         else
00949         {
00950             DisableReason = String_256(_R(IDS_ALREADY_AT_BACKS));
00951         }
00952     }
00953     else if(PresentMode == FRAME)
00954     {
00955         // Determine which reason string to return
00956         if (Sel.Count() > 1)
00957         {
00958             DisableReason = String_256(_R(IDS_ALREADY_AT_BACKP_FRAME)); // A plural description
00959         }
00960         else
00961         {
00962             DisableReason = String_256(_R(IDS_ALREADY_AT_BACKS_FRAME));
00963         }
00964     }
00965     else
00966         ERROR3("OpBringToFront::GetState - Bad mode!");
00967 
00968     *UIDescription = DisableReason;                                       
00969 
00970     End:                                                 
00971     return(OpSt);   
00972 
00973 #endif // WEBSTER
00974 }
00975  /********************************************************************************************
00976 
00977 >   BOOL OpPutToBack::Init()
00978 
00979     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00980     Created:    28/9/93
00981     Inputs:     -
00982     Outputs:    -
00983     Returns:    TRUE if the operation could be successfully initialised 
00984                 FALSE if no more memory could be allocated 
00985                 
00986     Purpose:    OpPutToBack initialiser method
00987     Errors:     ERROR will be called if there was insufficient memory to allocate the 
00988                 operation.
00989     SeeAlso:    -
00990 
00991 ********************************************************************************************/
00992 
00993 
00994 BOOL OpPutToBack::Init()
00995 {
00996     return (RegisterOpDescriptor(0,
00997                                 _R(IDS_PUTTOBACKOP),
00998                                 CC_RUNTIME_CLASS(OpPutToBack),
00999                                 OPTOKEN_PUTTOBACK,
01000                                 OpPutToBack::GetState,
01001                                 0,  /* help id */
01002                                 _R(IDBBL_PUTTOBACKOP),
01003                                 0,  /* bitmap ID */
01004                                 0,
01005                                 SYSTEMBAR_ILLEGAL,          // For now !
01006                                 TRUE,                       // Receive messages
01007                                 FALSE,
01008                                 FALSE,
01009                                 0,
01010                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
01011 
01012                                 )); 
01013 }               
01014 
01015 
01016 
01017 /********************************************************************************************
01018 
01019 >   void OpPutToBack::Do(OpDescriptor*)
01020 
01021     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
01022     Created:    16/8/93
01023     Inputs:     OpDescriptor (unused)
01024     Outputs:    -
01025     Returns:    -
01026     Purpose:    Performs the PutToBack operation 
01027 
01028                 See note at the top of file about WEBSTER z-order ops
01029     Errors:     -
01030     SeeAlso:    -
01031 
01032 ********************************************************************************************/
01033     
01034 void OpPutToBack::Do(OpDescriptor*)        
01035 {   
01036 #ifdef WEBSTER
01037 
01038     SelRange* Sel = GetApplication()->FindSelection();
01039 
01040     Node* pSelNode = Sel->FindFirst();
01041 
01042     // If there are selected objects, record undo stuff about the selection
01043     if (pSelNode != NULL)
01044     {
01045         // Try to record the selection state , don't render the blobs though
01046         // the invalidate will take care of this. 
01047         if (!DoStartSelOp(FALSE,FALSE))
01048             goto EndOperation;  
01049 
01050         // We need to invalidate the region
01051         if (!DoInvalidateNodesRegions(*Sel, TRUE))
01052             goto EndOperation; 
01053     }
01054 
01055     while (pSelNode != NULL)
01056     {
01057         Node* pContextNode = NULL;
01058 
01059         Node* pNode = pSelNode;
01060         while (pNode != NULL)
01061         {
01062             Node* pOldNode = pNode;     // Remember this node
01063 
01064             if (pNode != NULL)
01065                 pNode = pNode->FindPrevious();  // Get the node before this node
01066 
01067             // If the previous node is an unselected object, then we can move this object back
01068             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01069                 pContextNode = pNode;
01070 
01071             if (pNode == NULL)
01072             {
01073                 // Find the parent layer
01074                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
01075 
01076                 // Find the last object on the first editable layer we can find that preceeds this layer
01077                 do
01078                 {
01079                     pLayer = pLayer->FindPrevLayer(TRUE);
01080                     pNode = FindLastObject(pLayer);
01081 
01082                 } while (pLayer != NULL && pNode == NULL);
01083 
01084                 // If the previous node is an unselected object, then we can move this object back
01085                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01086                     pContextNode = pNode;
01087             }
01088         } 
01089 
01090         pNode = pSelNode;
01091         // Try the next selected node.
01092         pSelNode = Sel->FindNext(pSelNode);
01093 
01094         if (pContextNode != NULL)
01095         {
01096             if (!DoMoveNode(pNode, pContextNode, PREV))
01097                 goto EndOperation;
01098 
01099             pNode->SetSelected(TRUE);
01100         }
01101     }
01102 
01103     EndOperation:    
01104     End(); // End of operation
01105 
01106 #else
01107 
01108 // WEBSTER - markn 2/2/97
01109 // Original code
01110 
01111     // Obtain the current selections 
01112     Range Sel(*(GetApplication()->FindSelection()));
01113     RangeControl rg = Sel.GetRangeControlFlags();
01114     rg.PromoteToParent = TRUE;
01115     Sel.Range::SetRangeControl(rg);
01116 
01117     // Find the first node which is selected 
01118     Node* FirstSelectedNode = Sel.FindFirst(); 
01119  
01120     // The first selected node should not ever be NULL
01121     ENSURE(FirstSelectedNode != NULL, 
01122         "The OpPutToBack's GetState fn has not done a very good job"); 
01123 
01124     if (FirstSelectedNode != NULL)  
01125     {   
01126         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state , don't
01127                                          // render the blobs though, the invalidate
01128                                          // will take care of this. 
01129         {
01130             goto EndOperation;  
01131         }
01132 
01133         // We need to invalidate the region
01134         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
01135         {
01136             goto EndOperation; 
01137         }
01138 
01139         // Find the spread that the selection lies on
01140 //      Spread* pSpread = FirstSelectedNode->FindParentSpread();
01141 
01142 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE }; 
01143         Range LayerRange; 
01144 
01145         Node* FirstSelectedNextLayer; 
01146 
01147         // Loop for all layers
01148         while (FirstSelectedNode != NULL)
01149         {
01150             Range temp(FirstSelectedNode,
01151                                NULL, 
01152                                RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) ); // Selected + don't cross layers
01153             LayerRange = temp;
01154 //          LayerRange = Range(FirstSelectedNode, 
01155 //                             NULL, 
01156 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) ); // Selected + don't cross layers  
01157 
01158             // Find the last selected node on the current layer
01159             Node* LastSelectedNode=NULL;  
01160             Node* Scout = FirstSelectedNode; // First selected node on layer 
01161 
01162             // Loop until we find the last selected node
01163             while (Scout != NULL)
01164             {
01165                 LastSelectedNode = Scout; 
01166                 Scout = LayerRange.FindNext(Scout);     
01167             }
01168 
01169             Node* CurrentNode = LastSelectedNode; 
01170 
01171             // Find the first selected node of the next layer
01172             FirstSelectedNextLayer = Sel.FindNext(CurrentNode);
01173 
01174             // Find the head of the selection list
01175             Node* Head = FirstSelectedNode->FindParent()->FindFirstChild(CC_RUNTIME_CLASS(NodeRenderableInk));
01176 
01177             // If the last node selected is already at the back then we don't really want
01178             // to move it. In this situation we know that there can be no other selected nodes
01179             // so we need not do anything.
01180             if (LastSelectedNode != Head)
01181             {
01182                 Node* PrevSelNode;
01183                 do
01184                 {
01185                     ENSURE (CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)),
01186                             "Selected node not a NodeRenderableBounded");
01187 
01188                     // (ChrisG 15/2/2001) Since we're using a SelRange to determine what's selected,
01189                     //  we really should use this to find the previous selected node, rather than
01190                     //  relying on "Selected" flags, as controllers, etc... are never selected, but are
01191                     //  included in selection ranges.
01192 
01193                     // Find the previous selected node before CurrentNode moves. 
01194                     PrevSelNode = LayerRange.FindPrev (CurrentNode, FALSE);
01195 
01196                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01197                     if (!DoMoveNode(CurrentNode, Head, PREV))
01198                     {
01199                         goto EndOperation;
01200                     }
01201 
01202                     // (ChrisG 15/2/2001) This isn't really all that good, as it will select objects
01203                     //  that weren't previously selected, as promote to parent will select the parent
01204                     //  object, and SetSelected will then set all the children to selected. Which is
01205                     //  fine, unless not all of the children were previously selected.
01206                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01207                     CurrentNode->SetSelected(TRUE);
01208 
01209                     Head = CurrentNode;
01210                     CurrentNode = PrevSelNode;
01211                 
01212                 // Stop when we hit the first node which was moved.
01213                 // or when there are no more selected nodes (This can only happen if there is only
01214                 // one node selected).
01215                 } while ((CurrentNode != LastSelectedNode) && (CurrentNode != NULL));
01216             
01217                 // Invalidate the region which bounds all selected nodes
01218                 if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE, FALSE))
01219                 {
01220                     goto EndOperation;
01221                 }
01222             }
01223                  
01224             // (ChrisG - 15/02/2001) Moved outside of if "is object at back of layer already", as this
01225             //  could cause an infinite loop if there were selected objects on two (or more) layers, 
01226             //  but the objects on the first layer were already at the back.
01227 
01228             // Now process next layer
01229             FirstSelectedNode = FirstSelectedNextLayer;  
01230         }
01231     }
01232     EndOperation:    
01233     GetApplication()->UpdateSelection();
01234     
01235     End(); // End of operation
01236 
01237 #endif // WEBSTER
01238 }  
01239 
01240 // ------------------------------------------------------------------------------------------
01241 // OpMoveForwards methods
01242             
01243 /********************************************************************************************
01244 
01245 >   OpMoveForwards::OpMoveForwards() 
01246 
01247     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01248     Created:    29/9/93
01249     Inputs:     -
01250     Outputs:    -
01251     Returns:    -
01252     Purpose:    OpMoveForwards constructor
01253     Errors:     -
01254     SeeAlso:    -
01255 
01256 ********************************************************************************************/
01257             
01258             
01259 OpMoveForwards::OpMoveForwards(): SelOperation()                                
01260 {                              
01261 }
01262 
01263  /********************************************************************************************
01264 
01265 >   BOOL OpMoveForwards::Init()
01266 
01267     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01268     Created:    28/9/93
01269     Inputs:     -
01270     Outputs:    -
01271     Returns:    TRUE if the operation could be successfully initialised 
01272                 FALSE if no more memory could be allocated 
01273                 
01274     Purpose:    OpMoveForwards initialiser method
01275     Errors:     ERROR will be called if there was insufficient memory to allocate the 
01276                 operation.
01277     SeeAlso:    -
01278 
01279 ********************************************************************************************/
01280 
01281 BOOL OpMoveForwards::Init()
01282 {
01283     return(RegisterOpDescriptor(
01284                                 0,
01285                                 _R(IDS_MOVEFORWARDSOP),
01286                                 CC_RUNTIME_CLASS(OpMoveForwards),
01287                                 OPTOKEN_MOVEFORWARDS,
01288                                 OpBringToFront::GetState,   // MoveForwards uses the getstate
01289                                                             // fn of OpBringToFront
01290                                 0,  /* help ID */
01291                                 _R(IDBBL_MOVEFORWARDSOP),
01292                                 0,  /* bitmap ID */
01293                                 0,
01294                                 SYSTEMBAR_ILLEGAL,          // For now !
01295                                 TRUE,                       // Receive messages
01296                                 FALSE,
01297                                 FALSE,
01298                                 0,
01299                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
01300 
01301                                 )); 
01302 
01303 }               
01304 
01305 /********************************************************************************************
01306 
01307 >   void OpMoveForwards::Do(OpDescriptor*)
01308 
01309     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
01310     Created:    16/8/93
01311     Inputs:     OpDescriptor (unused)
01312     Outputs:    -
01313     Returns:    -
01314     Purpose:    Performs the MoveForwards operation 
01315 
01316                 See note at the top of file about WEBSTER z-order ops
01317     Errors:     -
01318     SeeAlso:    -
01319 
01320 ********************************************************************************************/
01321         
01322 void OpMoveForwards::Do(OpDescriptor*)         
01323 {     
01324 #ifdef WEBSTER
01325 
01326     OpState OpSt;
01327     String_256 DisableReason; 
01328 
01329     SelRange* Sel = GetApplication()->FindSelection();
01330 
01331     Node* pSelNode = Sel->FindLast();
01332 
01333     // If there are selected objects, record undo stuff about the selection
01334     if (pSelNode != NULL)
01335     {
01336         // Try to record the selection state , don't render the blobs though
01337         // the invalidate will take care of this. 
01338         if (!DoStartSelOp(FALSE,FALSE))
01339             goto EndOperation;  
01340 
01341         // We need to invalidate the region
01342         if (!DoInvalidateNodesRegions(*Sel, TRUE))
01343             goto EndOperation; 
01344     }
01345 
01346     while (pSelNode != NULL)
01347     {
01348         Node* pContextNode = NULL;
01349         BOOL SelNodeFound = FALSE;
01350 
01351         Node* pNode = pSelNode;
01352         while (pNode != NULL && pContextNode == NULL && !SelNodeFound)
01353         {
01354             Node* pOldNode = pNode;     // Remember this node
01355 
01356             if (pNode != NULL)
01357                 pNode = pNode->FindNext();  // Get the node after this node
01358 
01359             // If the next node is an unselected object, then we can move this object to the front
01360             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01361                 pContextNode = pNode;
01362 
01363             SelNodeFound = (pNode != NULL && pNode->IsAnObject() && pNode->IsSelected());
01364 
01365             if (pNode == NULL)
01366             {
01367                 // Find the parent layer
01368                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
01369 
01370                 // Find the last object on the first editable layer we can find that follows this layer
01371                 do
01372                 {
01373                     pLayer = pLayer->FindNextLayer(TRUE);
01374                     pNode = FindFirstObject(pLayer);
01375 
01376                 } while (pLayer != NULL && pNode == NULL);
01377 
01378                 // If the next node is an unselected object, then we can move this object to the front
01379                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01380                     pContextNode = pNode;
01381             }
01382         } 
01383 
01384         pNode = pSelNode;
01385         // Try the next selected node.
01386         pSelNode = Sel->FindPrev(pSelNode);
01387 
01388         if (pContextNode != NULL && !SelNodeFound)
01389         {
01390             if (!DoMoveNode(pNode, pContextNode, NEXT))
01391                 goto EndOperation;
01392 
01393             pNode->SetSelected(TRUE);
01394         }
01395     }
01396 
01397     EndOperation:    
01398     End(); // End of operation
01399 
01400 #else
01401 
01402 // WEBSTER - markn 2/2/97
01403 // Original code
01404 
01405     // Obtain the current selections
01406     Range Sel(*(GetApplication()->FindSelection()));
01407     RangeControl rg = Sel.GetRangeControlFlags();
01408     rg.PromoteToParent = TRUE;
01409     Sel.Range::SetRangeControl(rg);
01410 
01411 
01412     // Find the first node which is selected 
01413     Node* FirstSelectedNode = Sel.FindFirst(); 
01414  
01415     // The first selected node should not ever be NULL
01416     ENSURE(FirstSelectedNode != NULL, 
01417         "The OpPutToBack's GetState fn has not done a very good job"); 
01418     
01419     // Make sure we are dealing with a NodeRenderable
01420     ENSURE (FirstSelectedNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), 
01421             "Selected node not a NodeRenderableBounded");  
01422      
01423     // We can only do something if there are any selected nodes  
01424     if (FirstSelectedNode != NULL)  
01425     {                                                           
01426         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state , don't
01427                                          // render the blobs though, the invalidate
01428                                          // will take care of this. 
01429         {
01430             goto EndOperation;  
01431         }
01432 
01433         // We need to invalidate the region
01434         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
01435         {
01436             goto EndOperation; 
01437         }
01438 
01439         // Find the spread that the selection lies in
01440 //      Spread* pSpread = FirstSelectedNode->FindParentSpread();
01441 
01442 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE }; // Selected + don't cross layers
01443         Range LayerRange;
01444 
01445         Node* NextLayerFirstSelectedNode; 
01446         
01447         // Loop for all layers
01448         // FirstSelectedNode points to the first node in the range on the layer we are currently
01449         // processing
01450         while (FirstSelectedNode != NULL)
01451         {
01452             // Create a range of selected nodes on this layer
01453             Range temp(FirstSelectedNode, 
01454                                NULL, 
01455                                RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
01456             LayerRange = temp;
01457 //          LayerRange = Range(FirstSelectedNode, 
01458 //                             NULL,
01459 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
01460 
01461             // Find the last selected node on the layer
01462             Node* TempSelNode = FirstSelectedNode; 
01463             Node* LastSelectedNode = NULL; 
01464             while (TempSelNode != NULL)
01465             {
01466                 LastSelectedNode = TempSelNode;                          // At end of loop will hold 
01467                                                                          // the last node selected. 
01468                 TempSelNode = LayerRange.FindNext(TempSelNode);     
01469             }
01470          
01471             // Obtain the first node in the range of the next layer,
01472             //  store it away until it's required
01473             NextLayerFirstSelectedNode = Sel.FindNext(LastSelectedNode); 
01474 
01475             // We are going to start at the tail of the list i.e. at the node with the highest 
01476             // Z-order.   
01477             Node* CurrentNode = LastSelectedNode;             
01478         
01479             Node* PrevSelNode = NULL;  // We never ever move a node further forward than the previously 
01480                                        // processed node (This is to maintain the relative Z-Order of the 
01481                                        // nodes).    
01482                                    
01483             Node* NextSelNode;          
01484         
01485             Node* SrchNode;            // Used for searching for nodes which overlap
01486          
01487             BOOL Intersects;           // Flag which indicates if there is a node which overlaps the
01488                                        // current node. 
01489             BOOL PassedPrevSel;        
01490        
01491             
01492             // loop until there are no more selected nodes                       
01493             while (CurrentNode != NULL) 
01494             {   
01495                 // Make sure we are dealing with a NodeRenderableBounded
01496                 ENSURE (CurrentNode->IsAnObject(), 
01497                         "Selected node not a NodeRenderableInk");
01498                     
01499                 // The current node will probably be moving very shortly, so lets find out the next node 
01500                 // which needs to be processed now. We could do this after the node has been moved but 
01501                 // this would be less than optimal.  
01502                 NextSelNode = LayerRange.FindPrev (CurrentNode, FALSE);
01503 
01504                 // We first need to decide where the CurrentNode is to be moved to, if it is to be 
01505                 // moved at all. 
01506             
01507                 // -------------------------------------------------------------------------
01508                 // See if there is a node which is overlapping the current node 
01509              
01510                 Intersects = FALSE;        
01511                 PassedPrevSel = FALSE;    
01512              
01513                 SrchNode = CurrentNode->FindNext();     
01514                 DocRect CurrentBounds = ((NodeRenderableBounded*)CurrentNode)->GetBoundingRect();
01515                 while (SrchNode != NULL)           
01516                 {   
01517                     if (SrchNode->IsAnObject()) // Ignore hidden nodes/ Insertion node etc.
01518                     {           
01519                         if (SrchNode == PrevSelNode)
01520                         {   
01521                             PassedPrevSel = TRUE;                   
01522                             // carry on searching 
01523                         }
01524                         if (((NodeRenderableBounded*)SrchNode)->GetBoundingRect().IsIntersectedWith
01525                             (CurrentBounds))
01526                         {         
01527                             Intersects = TRUE;           
01528                             break; 
01529                         }
01530                     }
01531                     SrchNode = SrchNode->FindNext();    
01532                 }
01533 
01534                 // -------------------------------------------------------------------------
01535                   
01536                 // If there is a node which overlaps: then either insert the node as a next sibling of this 
01537                 // node, or as a previous sibling of the previously processed node (whichever is lower). 
01538                   
01539                 if (Intersects) 
01540                 {     
01541                     if (PassedPrevSel) // We cannot insert the node in front of the node which 
01542                                        // overlaps it. This would destroy the relative
01543                                        // Z order !
01544                     {
01545                         if (PrevSelNode->FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk))  != CurrentNode) 
01546                         {
01547                             // Insert the node as a previous sibling of the previously processed node
01548                             ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01549                             if (!DoMoveNode(CurrentNode, PrevSelNode, PREV)) 
01550                                 goto EndOperation; 
01551 
01552                             ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01553                             CurrentNode->SetSelected(TRUE);
01554                         }                                              
01555                         // else the node is already in the correct position behind the previously
01556                         // processed node. 
01557                     }
01558                     else
01559                     {
01560                         // Insert the node after the node which intersects it. 
01561                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01562                         if (!DoMoveNode(CurrentNode, SrchNode, NEXT)) 
01563                             goto EndOperation; 
01564 
01565                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01566                         CurrentNode->SetSelected(TRUE);
01567                     }
01568                 }
01569                 else // No node intersects with the current node 
01570                 { 
01571                     // There is no overlapping node, so move the node one position, or do not move it 
01572                     // at all if the next node is the previously moved node, or if the node is 
01573                     // already at the front of the list.      
01574 
01575                     Node* NextObjAfterCurrent = CurrentNode->FindNext(CC_RUNTIME_CLASS(NodeRenderableInk));
01576                         
01577                     if (NextObjAfterCurrent != PrevSelNode) 
01578                     {   
01579                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01580                         if (!DoMoveNode(CurrentNode,NextObjAfterCurrent, NEXT))
01581                             goto EndOperation;   
01582 
01583                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01584                         CurrentNode->SetSelected(TRUE);
01585                     } 
01586                     // else either
01587                     // -Current node is the previous selected sibling of PrevSelNode so don't move it. 
01588                     // -or the current node is already at the head of the list so don't move it 
01589                 }                                     
01590              
01591                 PrevSelNode = CurrentNode;  
01592                 CurrentNode = NextSelNode; // Get next node  
01593         
01594             }
01595             // Process the next layer
01596             FirstSelectedNode = NextLayerFirstSelectedNode;    
01597         }
01598         // We need to invalidate the region
01599         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE, FALSE))
01600         {
01601             goto EndOperation; 
01602         }
01603     } 
01604     EndOperation:
01605     GetApplication()->UpdateSelection();
01606     
01607     End(); // End of operation
01608 
01609 #endif // WEBSTER
01610 }
01611 // ------------------------------------------------------------------------------------------
01612 // OpMoveBackwards methods
01613             
01614 /********************************************************************************************
01615 
01616 >   OpMoveForwards::OpMoveBackwards() 
01617 
01618     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01619     Created:    29/9/93
01620     Inputs:     -
01621     Outputs:    -
01622     Returns:    -
01623     Purpose:    OpMoveBackwards constructor
01624     Errors:     -
01625     SeeAlso:    -
01626 
01627 ********************************************************************************************/
01628             
01629             
01630 OpMoveBackwards::OpMoveBackwards(): SelOperation()                              
01631 {                              
01632 }
01633 
01634  /********************************************************************************************
01635 
01636 >   BOOL OpMoveBackwards::Init()
01637 
01638     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01639     Created:    28/9/93
01640     Inputs:     -
01641     Outputs:    -
01642     Returns:    TRUE if the operation could be successfully initialised 
01643                 FALSE if no more memory could be allocated 
01644                 
01645     Purpose:    OpMoveBackwards initialiser method
01646     Errors:     ERROR will be called if there was insufficient memory to allocate the 
01647                 operation.
01648     SeeAlso:    -
01649 
01650 ********************************************************************************************/
01651 
01652 BOOL OpMoveBackwards::Init()
01653 {
01654     return (RegisterOpDescriptor(0,
01655                                 _R(IDS_MOVEBACKWARDSOP),
01656                                 CC_RUNTIME_CLASS(OpMoveBackwards),
01657                                 OPTOKEN_MOVEBACKWARDS,
01658                                 OpPutToBack::GetState,
01659                                 0,  /* help ID */
01660                                 _R(IDBBL_MOVEBACKWARDSOP),
01661                                 0,  /* bitmap ID */
01662                                 0,
01663                                 SYSTEMBAR_ILLEGAL,          // For now !
01664                                 TRUE,                       // Receive messages
01665                                 FALSE,
01666                                 FALSE,
01667                                 0,
01668                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
01669 
01670                                 )); 
01671 }               
01672 
01673 
01674 /********************************************************************************************
01675 
01676 >   void OpMoveBackwards::Do(OpDescriptor*)
01677 
01678     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com> (rewritten by Markn for WEBSTER - 2/2/97)
01679     Created:    16/8/93
01680     Inputs:     OpDescriptor (unused)
01681     Outputs:    -
01682     Returns:    -
01683     Purpose:    Performs the MoveBackwards operation 
01684 
01685                 See note at the top of file about WEBSTER z-order ops
01686     Errors:     -
01687     SeeAlso:    -
01688 
01689 ********************************************************************************************/
01690 
01691 void OpMoveBackwards::Do(OpDescriptor*)        
01692 {   
01693 #ifdef WEBSTER
01694 
01695     SelRange* Sel = GetApplication()->FindSelection();
01696 
01697     Node* pSelNode = Sel->FindFirst();
01698 
01699     // If there are selected objects, record undo stuff about the selection
01700     if (pSelNode != NULL)
01701     {
01702         // Try to record the selection state , don't render the blobs though
01703         // the invalidate will take care of this. 
01704         if (!DoStartSelOp(FALSE,FALSE))
01705             goto EndOperation;  
01706 
01707         // We need to invalidate the region
01708         if (!DoInvalidateNodesRegions(*Sel, TRUE))
01709             goto EndOperation; 
01710     }
01711 
01712     while (pSelNode != NULL)
01713     {
01714         Node* pContextNode = NULL;
01715         BOOL SelNodeFound = FALSE;
01716 
01717         Node* pNode = pSelNode;
01718         while (pNode != NULL && pContextNode == NULL && !SelNodeFound)
01719         {
01720             Node* pOldNode = pNode;     // Remember this node
01721 
01722             if (pNode != NULL)
01723                 pNode = pNode->FindPrevious();  // Get the node before this node
01724 
01725             // If the previous node is an unselected object, then we can move this object back
01726             if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01727                 pContextNode = pNode;
01728 
01729             SelNodeFound = (pNode != NULL && pNode->IsAnObject() && pNode->IsSelected());
01730 
01731             if (pNode == NULL)
01732             {
01733                 // Find the parent layer
01734                 Layer* pLayer = (Layer*)pOldNode->FindParent(CC_RUNTIME_CLASS(Layer));
01735 
01736                 // Find the last object on the first editable layer we can find that preceeds this layer
01737                 do
01738                 {
01739                     pLayer = pLayer->FindPrevLayer(TRUE);
01740                     pNode = FindLastObject(pLayer);
01741 
01742                 } while (pLayer != NULL && pNode == NULL);
01743 
01744                 // If the previous node is an unselected object, then we can move this object back
01745                 if (pNode != NULL && pNode->IsAnObject() && !pNode->IsSelected())
01746                     pContextNode = pNode;
01747             }
01748         } 
01749 
01750         pNode = pSelNode;
01751         // Try the next selected node.
01752         pSelNode = Sel->FindNext(pSelNode);
01753 
01754         if (pContextNode != NULL && !SelNodeFound)
01755         {
01756             if (!DoMoveNode(pNode, pContextNode, PREV))
01757                 goto EndOperation;
01758 
01759             pNode->SetSelected(TRUE);
01760         }
01761     }
01762 
01763     EndOperation:    
01764     End(); // End of operation
01765 
01766 #else
01767 
01768 // WEBSTER - markn 2/2/97
01769 // Original code
01770 
01771     // Obtain the current selections
01772     Range Sel(*(GetApplication()->FindSelection()));
01773 
01774     // DMc
01775     RangeControl rg = Sel.GetRangeControlFlags();
01776     rg.PromoteToParent = TRUE;
01777     Sel.Range::SetRangeControl(rg);
01778 
01779     // Find the first node which is selected 
01780     Node* FirstSelectedNode = Sel.FindFirst(); 
01781  
01782     // The first selected node should not ever be NULL
01783     ENSURE(FirstSelectedNode != NULL, 
01784         "The OpPutToBack's GetState fn has not done a very good job"); 
01785     
01786     // Make sure we are dealing with a NodeRenderable
01787     ENSURE (FirstSelectedNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), 
01788             "Selected node not a NodeRenderableBounded");  
01789      
01790     // We can only do something if there are any selected nodes  
01791     if (FirstSelectedNode != NULL)  
01792     {                                                           
01793         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state , don't
01794                                          // render the blobs though, the invalidate
01795                                          // will take care of this. 
01796         {
01797             goto EndOperation;  
01798         }
01799 
01800         // We need to invalidate the region
01801         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
01802         {
01803             goto EndOperation; 
01804         }
01805         
01806         Node* CurrentNode; 
01807         CurrentNode = FirstSelectedNode;
01808 
01809         // Find the spread that the selection lies on
01810 //      Spread* pSpread = CurrentNode->FindParentSpread();
01811 
01812 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE }; // Selected + don't cross layers
01813         
01814         Range LayerRange;
01815 
01816         Node* PrevSelNode;  
01817 
01818         Node* NextSelNode;          
01819         
01820         Node* SrchNode;            // Used for searching for nodes which overlap
01821                                        
01822         BOOL Intersects;           // Flag which indicates if there is a node which intersects the
01823                                    // current node. 
01824         BOOL PassedPrevSel;        
01825      
01826         Node* LastSelectedOnLayer=NULL; 
01827 
01828         // Loop for all layers
01829         while (CurrentNode != NULL)
01830         {
01831 
01832             // Create a range of the selected nodes on this layer
01833             Range temp(CurrentNode,
01834                             NULL,
01835                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
01836             LayerRange = temp;
01837 //          LayerRange = Range(CurrentNode,
01838 //                             NULL,
01839 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
01840 
01841         
01842             PrevSelNode = NULL;    // We never ever move a node further backward than the previously 
01843                                 // processed node (This is to maintain the relative Z-Order of the 
01844                                 // nodes).    
01845             
01846             // loop until there are no more selected nodes on this layer                     
01847             while (CurrentNode != NULL) 
01848             {   
01849                 // Make sure we are dealing with a NodeRenderableBounded
01850                 ENSURE (CurrentNode->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), 
01851                         "Selected node not a NodeRenderableBounded");      
01852                     
01853                 // The current node will probably be moving very shortly, so lets find out the next node 
01854                 // which needs to be processed now. We could do this after the node has been moved but 
01855                 // this would be less than optimal.  
01856                 NextSelNode = LayerRange.FindNext(CurrentNode); 
01857             
01858                 // We first need to decide where the CurrentNode is to be moved to, if it is to be 
01859                 // moved at all. 
01860             
01861                 // ------------------------------------------------------------------------- 
01862                 // See if there is a node which is intersecting the current node 
01863             
01864                 Intersects = FALSE;     
01865                 PassedPrevSel = FALSE; 
01866                 
01867                 DocRect CurrentsBounds = ((NodeRenderableBounded*)CurrentNode)->GetBoundingRect();   
01868             
01869                 SrchNode = CurrentNode->FindPrevious();     
01870                 while (SrchNode != NULL)           
01871                 {   
01872                     if (SrchNode->IsAnObject())     // Ignore Hidden/Insertion nodes
01873                     {           
01874                         if (SrchNode == PrevSelNode)
01875                         {   
01876                             PassedPrevSel = TRUE;                   
01877                             // carry on searching 
01878                         }
01879                         if (((NodeRenderableBounded*)SrchNode)->GetBoundingRect().IsIntersectedWith
01880                             (CurrentsBounds))
01881                         {         
01882                             Intersects = TRUE;           
01883                             break; 
01884                         }
01885                     }
01886                     SrchNode = SrchNode->FindPrevious(); 
01887                 }
01888                 
01889                 // -------------------------------------------------------------------------
01890                   
01891                 // If there is a node which intersects: Then either insert the node as previous 
01892                 // sibling of this node, or as a next sibling of the previously processed node 
01893                 // (whichever is higher). 
01894                  
01895                 Node* ObjPrevCurrent = CurrentNode->FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk));   
01896                 if (Intersects) 
01897                 {     
01898                     if (PassedPrevSel) // We cannot insert the node behind the node which 
01899                                        // it overlaps. This would destroy the relative
01900                                        // Z order !
01901                     {
01902                         if (PrevSelNode  != ObjPrevCurrent) 
01903                         {
01904                             // Insert the node as a next sibling of the previously processed node
01905                             ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01906                             if (!DoMoveNode((NodeRenderableBounded*)CurrentNode, PrevSelNode, NEXT))
01907                                 goto EndOperation;   
01908 
01909                             ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01910                             CurrentNode->SetSelected(TRUE);
01911                         }                                              
01912                         // else the node is already in the correct position as a next sibling of the
01913                         // previously processed node. 
01914                     }
01915                     else
01916                     {   
01917                         // Insert the node as a previous sibling of the node which it currently overlaps.
01918                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01919                         if (!DoMoveNode((NodeRenderableBounded*)CurrentNode, SrchNode, PREV))
01920                             goto EndOperation;   
01921 
01922                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01923                         CurrentNode->SetSelected(TRUE);
01924                 
01925                     }
01926                 }
01927                 else // No node intersects with the current node 
01928                 { 
01929                     // There is no overlapping node, so move the node one position, or do not move it 
01930                     // at all if the prev node is the previously moved node, or if the node is 
01931                     // already at the tail of the list.      
01932                 
01933                     if (PrevSelNode  != ObjPrevCurrent) 
01934                     {   
01935                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01936                         if (!DoMoveNode((NodeRenderableBounded*)CurrentNode, ObjPrevCurrent, PREV))
01937                             goto EndOperation;   
01938 
01939                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
01940                         CurrentNode->SetSelected(TRUE);
01941                     } 
01942                     // else either
01943                     // - Current node is the next selected sibling of PrevSelNode so don't move it. 
01944                     // - or current node is already at the tail of the list so don't move it 
01945                 }                                     
01946                 PrevSelNode = CurrentNode;  
01947                 LastSelectedOnLayer = CurrentNode; 
01948                 CurrentNode = NextSelNode; // Get next node  
01949             }
01950 
01951             // Process the next layer
01952             ENSURE(LayerRange.FindNext(LastSelectedOnLayer) == NULL, 
01953                 "Current should be the last selected node on the layer");
01954 
01955             CurrentNode = Sel.FindNext(LastSelectedOnLayer);
01956         }
01957 
01958         // We need to invalidate the region
01959         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE, FALSE))
01960         {
01961             goto EndOperation; 
01962         }
01963 
01964     }   
01965     EndOperation:
01966     GetApplication()->UpdateSelection();
01967     
01968     End(); // End of operation
01969 
01970 #endif // WEBSTER
01971 }  
01972 
01973 // ------------------------------------------------------------------------------------------
01974 // OpMoveToLyrInFront methods
01975 
01976 
01977 
01978 /********************************************************************************************
01979 
01980 >   OpMoveToLyrInFront::OpMoveToLyrInFront() 
01981 
01982     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01983     Created:    29/9/93
01984     Inputs:     -
01985     Outputs:    -
01986     Returns:    -
01987     Purpose:    OpMoveToLyrInFront constructor
01988     Errors:     -
01989     SeeAlso:    -
01990 
01991 ********************************************************************************************/
01992             
01993             
01994 OpMoveToLyrInFront::OpMoveToLyrInFront(): SelOperation()                                
01995 {                              
01996 }
01997 
01998  /********************************************************************************************
01999 
02000 >   BOOL OpMoveToLyrInFront::Init()
02001 
02002     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02003     Created:    28/9/93
02004     Inputs:     -
02005     Outputs:    -
02006     Returns:    TRUE if the operation could be successfully initialised 
02007                 FALSE if no more memory could be allocated 
02008                 
02009     Purpose:    OpMoveToLyrInFront initialiser method
02010     Errors:     ERROR will be called if there was insufficient memory to allocate the 
02011                 operation.
02012     SeeAlso:    -
02013 
02014 **********************************************************************************************/
02015 
02016 BOOL OpMoveToLyrInFront::Init()
02017 {
02018 /*
02019     return (RegisterOpDescriptor(0,
02020                                 _R(IDS_MOVELAYERINFRONT),
02021                                 CC_RUNTIME_CLASS(OpMoveToLyrInFront),
02022                                 OPTOKEN_MOVELAYERINFRONT,
02023                                 OpMoveToLyrInFront::GetState,
02024                                 0,  
02025                                 _R(IDBBL_MOVELAYERINFRONT),
02026                                 _R(IDD_ANIMATIONBAR),               // resource ID
02027                                 _R(IDC_FRAME_MOVEUPAFRAME),         // control ID
02028                                 SYSTEMBAR_ANIMATION,            // Bar ID
02029                                 TRUE,                           // Receive messages
02030                                 FALSE,
02031                                 FALSE,
02032                                 0,
02033                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
02034 
02035                                 )); 
02036 */
02037     // Changed for Camelot2, Layer/Frame integration - RanbirR.
02038 
02039     FrameInFrontOpDescriptor* pOpDesc = new FrameInFrontOpDescriptor(OPTOKEN_MOVELAYERINFRONT, 
02040                                                                      CC_RUNTIME_CLASS(OpMoveToLyrInFront),
02041                                                                      OpMoveToLyrInFront::GetState);
02042     if(pOpDesc)
02043         return TRUE;
02044 
02045     return FALSE;
02046 }               
02047 
02048 /********************************************************************************************
02049 
02050 >   OpState OpMoveToLyrInFront::GetState(String_256*, OpDescriptor*)
02051 
02052     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02053     Created:    28/9/93
02054     Inputs:     -
02055     Outputs:    -
02056     Returns:    The state of the OpMoveToLyrInFront operation
02057     Purpose:    For finding OpMoveToLyrInFront's state. 
02058     Errors:     -
02059     SeeAlso:    -
02060 
02061 ********************************************************************************************/
02062 
02063 OpState OpMoveToLyrInFront::GetState(String_256*  UIDescription, OpDescriptor*)
02064 {
02065     OpState OpSt;
02066 
02067     String_256 DisableReason;
02068 
02069     SelRange Sel(*( GetApplication()->FindSelection()));
02070     RangeControl rg = Sel.GetRangeControlFlags();
02071     rg.PromoteToParent = TRUE;
02072     Sel.Range::SetRangeControl(rg);
02073 
02074 
02075     Node* pNode = Sel.FindFirst();
02076 
02077     while (pNode != NULL)
02078     {
02079         Node* pLayer = pNode->FindParent(CC_RUNTIME_CLASS(Layer));
02080         if (pLayer != NULL && ((Layer*)pLayer)->IsGuide())
02081         {
02082             *UIDescription = String_256(_R(IDS_CANT_MOVE_OFF_GUIDE_LAYER));
02083             OpSt.Greyed = TRUE;
02084             return OpSt;
02085         }
02086 
02087         pNode = Sel.FindNext(pNode);
02088     }
02089 
02090     // Find the first node which is selected 
02091     Node* FirstSelectedNode = Sel.FindFirst(); 
02092 
02093     // The operation is disabled if the first object which is selected is already on the highest
02094     // visible layer.
02095     BOOL HighestVisible = TRUE; 
02096     Layer* CurrentLayer = (Layer*) (FirstSelectedNode->FindParent(CC_RUNTIME_CLASS(Layer)));
02097     ERROR2IF(CurrentLayer == NULL, OpSt, "Cannot find layer of first selected object"); 
02098 // WEBSTER - markn 2/2/97
02099 // Not needed in Webster
02100 // Neville 23/6/97 Now needed but must work in Frame mode in Webster
02101 // RanbirR - 28/10/97 - Changed for Camelot v2, Frame/Layer integration. 
02102 
02103 #ifdef WEBSTER
02104     // Find the next frame layer
02105     do
02106     {
02107         CurrentLayer = CurrentLayer->FindNextFrameLayer();
02108         if (CurrentLayer != NULL)
02109         {
02110             // Is the layer not a guide or a page background layer?
02111             if (!CurrentLayer->IsGuide() && !CurrentLayer->IsPageBackground())
02112             {
02113                 HighestVisible = FALSE; // The first node selected is not on the highest visible layer
02114                                         // so the operation can be performed. 
02115                 break;
02116             }
02117         } 
02118     } while (CurrentLayer != NULL);   
02119 
02120 #else
02121     // Are we in frame or layer mode.
02122     MODE PresentMode = (MODE)CurrentLayer->IsFrame();
02123 
02124     if (PresentMode == FRAME)
02125     {
02126         do
02127         {
02128             CurrentLayer = CurrentLayer->FindNextFrameLayer();
02129             if (CurrentLayer != NULL)
02130             {
02131                 // Is the layer not a guide or a page background layer?
02132                 if (!CurrentLayer->IsGuide() && !CurrentLayer->IsPageBackground())
02133                 {
02134                     HighestVisible = FALSE; // The first node selected is not on the highest visible layer
02135                                             // so the operation can be performed. 
02136                     break;
02137                 }
02138             } 
02139         } while (CurrentLayer != NULL);   
02140     }
02141     else if (PresentMode == LAYER)
02142     {
02143         do
02144         {
02145             CurrentLayer = CurrentLayer->FindNextLayer();
02146             if (CurrentLayer != NULL)
02147             {
02148                 // Is the layer visible
02149                 if (CurrentLayer->IsVisible() && !CurrentLayer->IsLocked() && !CurrentLayer->IsGuide())
02150                 {
02151                     HighestVisible = FALSE; // The first node selected is not on the highest visible layer
02152                                             // so the operation can be performed. 
02153                     break;
02154                 }
02155             } 
02156         } while (CurrentLayer != NULL);   
02157     }
02158     else
02159         ERROR3("OpMoveToLyrInFront::GetState - Bad mode!");
02160 
02161 #endif // WEBSTER
02162 
02163     if (HighestVisible)
02164     {
02165         // The operation must be disabled
02166         OpSt.Greyed = TRUE;
02167 
02168         #ifdef WEBSTER
02169 
02170             if (Sel.FindNext(FirstSelectedNode) == NULL)
02171             {
02172                 // There is only a single selected node
02173                 DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_FRMS)); 
02174             }
02175             else
02176             {
02177                 // There is more than one selected node
02178                 DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_FRM)); 
02179             }
02180         #else
02181             if(PresentMode == LAYER)
02182             {
02183                 if (Sel.FindNext(FirstSelectedNode) == NULL)
02184                 {
02185                     // There is only a single selected node
02186                     DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_LYRS)); 
02187                 }
02188                 else
02189                 {
02190                     // There is more than one selected node
02191                     DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_LYRP)); 
02192                 }
02193             }
02194             else if(PresentMode == FRAME)
02195             {
02196                 if (Sel.FindNext(FirstSelectedNode) == NULL)
02197                 {
02198                     // There is only a single selected node
02199                     DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_FRMS)); 
02200                 }
02201                 else
02202                 {
02203                     // There is more than one selected node
02204                     DisableReason = String_256(_R(IDS_ALREADY_ON_TOP_FRM)); 
02205                 }
02206             }
02207             else
02208                 ERROR3("OpMoveToLyrInFront::Do - Bad mode!");
02209         #endif
02210     }
02211 
02212     *UIDescription = DisableReason;  
02213 
02214     return(OpSt);   
02215 }
02216 
02217 /********************************************************************************************
02218 
02219 >   void OpMoveToLyrInFront::Do(OpDescriptor*)
02220 
02221     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02222     Created:    16/8/93
02223     Inputs:     OpDescriptor (unused)
02224     Outputs:    -
02225     Returns:    -
02226     Purpose:    Performs the MoveToLayerInFront operation. This moves those selected objects
02227                 which are not on the highest visible layer to the lowest z-order position of the next 
02228                 visible layer in front. 
02229     Errors:     -
02230     SeeAlso:    -
02231 
02232 ********************************************************************************************/
02233         
02234 void OpMoveToLyrInFront::Do(OpDescriptor*)         
02235 {  
02236     // Obtain the current selections 
02237     Range Sel(*(GetApplication()->FindSelection()));
02238     RangeControl rg = Sel.GetRangeControlFlags();
02239     rg.PromoteToParent = TRUE;
02240     Sel.Range::SetRangeControl(rg);
02241 
02242     // Find the first node which is selected 
02243     Node* FirstSelectedNode = Sel.FindFirst(); 
02244  
02245     // The first selected node should not ever be NULL
02246     ENSURE(FirstSelectedNode != NULL, "The OpMoveToLyrInFront's GetState fn has not done a very good job"); 
02247     
02248     if (FirstSelectedNode != NULL) 
02249     {
02250         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state , don't
02251                                          // render the blobs though 
02252         {
02253             goto EndOperation;  
02254         }
02255 
02256         // We need to invalidate the region
02257         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
02258         {
02259             goto EndOperation; 
02260         }
02261 
02262         Node*   CurrentNode         = FirstSelectedNode; 
02263         
02264 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE };  // Selected + don't cross layers  
02265         Range   LayerRange; 
02266         Layer*  NxtLyr              = NULL;
02267         Node*   NextNode            = NULL; 
02268         Node*   ThisLayer           = NULL;
02269         Node*   FirstSelectedNxtLyr = NULL;
02270         Node*   LastObjectMoved     = NULL; 
02271 
02272         BOOL    OldVisible          = FALSE;
02273         BOOL    OldLocked           = FALSE;
02274 
02275 #ifndef WEBSTER
02276         MODE PresentMode            = LAYER; 
02277 #endif
02278         // Loop for all layers
02279         // Current Node is the first selected object on the layer we are currently processing
02280         while (CurrentNode != NULL)
02281         {
02282             ENSURE(CurrentNode->IsAnObject(), "Non ink node in OpMoveToLyrInFront");
02283 
02284             ThisLayer = CurrentNode->FindParent(CC_RUNTIME_CLASS(Layer));
02285 
02286             if (ThisLayer != NULL)
02287                 ((Layer*)ThisLayer)->InvalidateBoundingRect();
02288 
02289 // WEBSTER - markn 2/2/97
02290 // Not needed in Webster
02291 // Neville 23/6/97 Now needed but must work in Frame mode in Webster
02292 // RanbirR - 28/10/97 - Changed for Camelot v2, Frame/Layer integration. 
02293 
02294 #ifdef WEBSTER
02295             // ----------------------------------------------------------------------------
02296             // Find the next visible frame
02297             NxtLyr = (Layer*)ThisLayer;
02298             do
02299             {
02300                 NxtLyr = NxtLyr->FindNextFrameLayer();
02301                 if (NxtLyr != NULL)
02302                 {
02303                     // Is the layer not a guide or a page background layer?
02304                     if (!NxtLyr->IsGuide() && !NxtLyr->IsPageBackground())
02305                     {
02306                         // found
02307                         break;
02308                     }
02309                 }
02310                 
02311             } while (NxtLyr != NULL); 
02312 
02313             if (NxtLyr != NULL)
02314             {
02315                 // Make the layer visible and editable so we don't loose the selection
02316                 // do it blatently as it will be fixed up properly latter
02317                 OldVisible = NxtLyr->IsVisible();
02318                 OldLocked = NxtLyr->IsLocked();
02319                 NxtLyr->SetVisible(TRUE);
02320                 NxtLyr->SetLocked(FALSE);
02321             }
02322             
02323 #else
02324             // ----------------------------------------------------------------------------
02325 
02326             // Determine the Document Mode.
02327             NxtLyr = (Layer*)ThisLayer;
02328             PresentMode = (MODE)NxtLyr->IsFrame();
02329             
02330             if(PresentMode == LAYER)
02331             {
02332                 do
02333                 {
02334                     NxtLyr = NxtLyr->FindNextLayer();
02335                     if (NxtLyr != NULL)
02336                     {
02337                         if (NxtLyr->IsVisible() && !NxtLyr->IsLocked() && !NxtLyr->IsGuide())
02338                         {
02339                             // found
02340                             break;
02341                         }
02342                     }
02343                     
02344                 } while (NxtLyr != NULL); 
02345 
02346                 if (NxtLyr != NULL)
02347                 {
02348                     // Make the layer visible and editable so we don't loose the selection
02349                     // do it blatently as it will be fixed up properly latter
02350                     OldVisible = NxtLyr->IsVisible();
02351                     OldLocked = NxtLyr->IsLocked();
02352                     NxtLyr->SetVisible(TRUE);
02353                     NxtLyr->SetLocked(FALSE);
02354                 }
02355             }
02356             else if (PresentMode == FRAME)
02357             {
02358                 // Find the next visible frame
02359                 do
02360                 {
02361                     NxtLyr = NxtLyr->FindNextFrameLayer();
02362                     if (NxtLyr != NULL)
02363                     {
02364                         // Is the layer not a guide or a page background layer?
02365                         if (!NxtLyr->IsGuide() && !NxtLyr->IsPageBackground())
02366                         {
02367                             // found
02368                             break;
02369                         }
02370                     }
02371                 
02372                 } while (NxtLyr != NULL); 
02373 
02374                 if (NxtLyr != NULL)
02375                 {
02376                     // Make the layer visible and editable so we don't loose the selection
02377                     // do it blatently as it will be fixed up properly latter
02378                     OldVisible = NxtLyr->IsVisible();
02379                     OldLocked = NxtLyr->IsLocked();
02380                     NxtLyr->SetVisible(TRUE);
02381                     NxtLyr->SetLocked(FALSE);
02382                 }
02383             }
02384             else
02385                 ERROR3("OpMoveToLyrInFront::Do - Bad mode!");
02386 #endif 
02387 
02388             if (NxtLyr == NULL)
02389             {
02390                 ENSURE(CurrentNode != FirstSelectedNode, "OpMoveToLyrInFront called with nothing to do"); 
02391                 
02392                 // There is no layer in front so the operation is complete
02393                 goto EndOperation;
02394             } 
02395 
02396             NxtLyr->InvalidateBoundingRect();
02397 
02398             // Create a range of selected nodes on this layer, we will move these to the layer
02399             // in front.
02400             Range temp(CurrentNode, 
02401                                NULL, 
02402                                RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
02403             LayerRange = temp;
02404 //          LayerRange = Range(CurrentNode, 
02405 //                             NULL, 
02406 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
02407             
02408             // Find the first selected node on the layer in front of the layer we are currently 
02409             // processing. 
02410 
02411             FirstSelectedNxtLyr = CurrentNode;
02412             
02413             do 
02414             {
02415                 if (FirstSelectedNxtLyr->FindParent(CC_RUNTIME_CLASS(Layer)) != ThisLayer)
02416                 {
02417                     break; // Found     
02418                 }
02419                 FirstSelectedNxtLyr = Sel.FindNext(FirstSelectedNxtLyr);
02420 
02421             } while (FirstSelectedNxtLyr != NULL);
02422             
02423             // We haven't moved any objects from this layer yet
02424             LastObjectMoved = NULL; 
02425 
02426             // Shift all selected nodes on this layer to the lowest z-order position on the layer in front
02427             // maintaining the objects relative order 
02428             do
02429             {
02430                 NextNode = LayerRange.FindNext(CurrentNode); // Hand over hand
02431 
02432                 if (LastObjectMoved == NULL)
02433                 {
02434                     // No previous objects have been copied from this layer to the NxtLayer, therefore
02435                     // Attach the node as a first child of the next layer
02436                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
02437                     if (!DoMoveNode(CurrentNode, NxtLyr, FIRSTCHILD)) 
02438                     {
02439                         goto EndOperation;
02440                     }
02441 
02442                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
02443                     CurrentNode->SetSelected(TRUE);
02444                 }
02445                 else
02446                 {
02447                     // Copy the rest of the objects after the first object
02448                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
02449                     if (!DoMoveNode(CurrentNode, LastObjectMoved, NEXT)) 
02450                     {
02451                         goto EndOperation;
02452                     }
02453 
02454                     ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
02455                     CurrentNode->SetSelected(TRUE);
02456                 }
02457 
02458                 LastObjectMoved = CurrentNode;  // Remember the node we have just moved
02459                 CurrentNode = NextNode; 
02460             
02461             } while (NextNode != NULL);
02462 
02463 //#ifdef WEBSTER    Included in Camelot2 for Frame/Layer integration - RanbirR 03/11/97 
02464 #ifdef WEBSTER
02465             if (NxtLyr != NULL)
02466 #else
02467             if (NxtLyr != NULL && PresentMode == FRAME)
02468 #endif
02469             {
02470                 // Put back the old states so we get the redraw correct
02471                 NxtLyr->SetVisible(OldVisible);
02472                 //NxtLyr->SetLocked(OldLocked);
02473             }
02474 //#endif    
02475             // Get the first selected node of the next layer
02476             CurrentNode = FirstSelectedNxtLyr; 
02477         } 
02478 
02479 //#ifdef WEBSTER    Included in Camelot2 for Frame/Layer integration - RanbirR 03/11/97 
02480 
02481         // Switch to viewing the destination layer
02482         // Otherwise, the user will see the objects dissappear and will be worried
02483         // Also, the range blows up as the destination is invisible
02484 #ifdef WEBSTER
02485         if (NxtLyr != NULL)
02486 #else
02487         if (NxtLyr != NULL && PresentMode == FRAME)
02488 #endif
02489         {
02490 PORTNOTETRACE("gallery", "Removed used of FrameSGallery from OpMoveToLyrInFront");
02491 #if !defined(EXCLUDE_FROM_XARALX)
02492             FrameSGallery::MakeActiveLayer(NxtLyr);
02493             BROADCAST_TO_ALL(LayerMsg(NxtLyr,LayerMsg::UPDATE_ACTIVE_LAYER));
02494 #endif
02495         }
02496 
02497 //#endif // WEBSTER     Included in Camelot2 for Frame/Layer integration - RanbirR 03/11/97 
02498         
02499         // We need to invalidate the region
02500         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE, FALSE, FALSE, FALSE))
02501         {
02502             goto EndOperation; 
02503         }
02504     
02505         // Invalidate the bounding rects
02506         if (FirstSelectedNode->IsBounded())
02507         {
02508             NodeRenderableBounded* pNodeRB = (NodeRenderableBounded*)FirstSelectedNode;
02509             pNodeRB->InvalidateBoundingRect();
02510         }
02511     }
02512 
02513     EndOperation:
02514 
02515     End(); // End of operation
02516 } 
02517 
02518 
02519 // ------------------------------------------------------------------------------------------
02520 // OpMoveToLyrBehind methods
02521 
02522 
02523 /********************************************************************************************
02524 
02525 >   OpMoveToLyrBehind::OpMoveToLyrBehind() 
02526 
02527     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02528     Created:    29/9/93
02529     Inputs:     -
02530     Outputs:    -
02531     Returns:    -
02532     Purpose:    OpMoveToLyrBehind constructor
02533     Errors:     -
02534     SeeAlso:    -
02535 
02536 ********************************************************************************************/
02537             
02538             
02539 OpMoveToLyrBehind::OpMoveToLyrBehind(): SelOperation()                              
02540 {                              
02541 }
02542 
02543  /********************************************************************************************
02544 
02545 >   BOOL OpMoveToLyrBehind::Init()
02546 
02547     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02548     Created:    28/9/93
02549     Inputs:     -
02550     Outputs:    -
02551     Returns:    TRUE if the operation could be successfully initialised 
02552                 FALSE if no more memory could be allocated 
02553                 
02554     Purpose:    OpMoveToLyrBehind initialiser method
02555     Errors:     ERROR will be called if there was insufficient memory to allocate the 
02556                 operation.
02557     SeeAlso:    -
02558 
02559 ********************************************************************************************/
02560 
02561 BOOL OpMoveToLyrBehind::Init()
02562 {
02563 /*
02564     return (RegisterOpDescriptor(0,
02565                                 _R(IDS_MOVELAYERBEHIND),
02566                                 CC_RUNTIME_CLASS(OpMoveToLyrBehind),
02567                                 OPTOKEN_MOVELAYERBEHIND,
02568                                 OpMoveToLyrBehind::GetState,
02569                                 0,  // help ID
02570                                 _R(IDBBL_MOVELAYERBEHIND),
02571                                 _R(IDD_ANIMATIONBAR),               // resource ID
02572                                 _R(IDC_FRAME_MOVEDOWNAFRAME),       // control ID
02573                                 SYSTEMBAR_ANIMATION,            // Bar ID
02574                                 TRUE,                           // Receive messages
02575                                 FALSE,
02576                                 FALSE,
02577                                 0,
02578                                 (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)
02579 
02580                                 ));
02581 */
02582 
02583     FrameBehindOpDescriptor* pOpDesc = new FrameBehindOpDescriptor(OPTOKEN_MOVELAYERBEHIND, 
02584                                                                    CC_RUNTIME_CLASS(OpMoveToLyrBehind),
02585                                                                    OpMoveToLyrBehind::GetState);
02586 
02587     if(pOpDesc)
02588         return TRUE;
02589     
02590     return FALSE;
02591 }               
02592 
02593 /********************************************************************************************
02594 
02595 >   OpState OpMoveToLyrBehind::GetState(String_256*, OpDescriptor*)
02596 
02597     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02598     Created:    28/9/93
02599     Inputs:     -
02600     Outputs:    -
02601     Returns:    The state of the OpMoveToLyrBehind operation
02602     Purpose:    For finding OpMoveToLyrBehind's state. 
02603     Errors:     -
02604     SeeAlso:    -
02605 
02606 ********************************************************************************************/
02607 
02608 OpState OpMoveToLyrBehind::GetState(String_256*  UIDescription, OpDescriptor*)
02609 {
02610     OpState OpSt;
02611 
02612     // In Camelot, work as before in layer mode
02613     // In Webster, work only on frame layers
02614     // This should never go off in Webster but we will leave it in just in case
02615     String_256 DisableReason;
02616 
02617     SelRange Sel(*(GetApplication()->FindSelection()));
02618     RangeControl rg = Sel.GetRangeControlFlags();
02619     rg.PromoteToParent = TRUE;
02620     Sel.Range::SetRangeControl(rg);
02621 
02622     Node* pNode = Sel.FindFirst();
02623     while (pNode != NULL)
02624     {
02625         Node* pLayer = pNode->FindParent(CC_RUNTIME_CLASS(Layer));
02626         if (pLayer != NULL && ((Layer*)pLayer)->IsGuide())
02627         {
02628             *UIDescription = String_256(_R(IDS_CANT_MOVE_OFF_GUIDE_LAYER));
02629             OpSt.Greyed = TRUE;
02630             return OpSt;
02631         }
02632 
02633         pNode = Sel.FindNext(pNode);
02634     }
02635 
02636 // WEBSTER - markn 2/2/97
02637 // Not needed in Webster. Now required but must be frame orientated
02638 // RanbirR - 28/10/97 - Changed for Camelot v2, Frame/Layer integration. 
02639 
02640 #ifdef WEBSTER
02641     // We need to work in Frame mode in Webster
02642 
02643     // The operation is disabled if there does not exist a selected node on a layer 
02644     // which is not the bottom-most layer.
02645     
02646     // Find the first node which is selected 
02647     Node* pLastSelectedNode = Sel.FindLast(); 
02648          
02649     // The operation is disabled if the last selected object is already on the lowest
02650     // visible layer.
02651     BOOL LowestVisible = TRUE; 
02652     Layer* pCurrentLayer = (Layer*) (pLastSelectedNode->FindParent(CC_RUNTIME_CLASS(Layer)));
02653     ERROR2IF(pCurrentLayer == NULL, OpSt, "Cannot find layer of first selected object"); 
02654     do
02655     {
02656         pCurrentLayer = pCurrentLayer->FindPrevFrameLayer();
02657         if (pCurrentLayer != NULL)
02658         {
02659             // Is the layer not a guide or a page background layer?
02660             if (!pCurrentLayer->IsGuide() && !pCurrentLayer->IsPageBackground())
02661             {
02662                 LowestVisible = FALSE; // The last node selected is not on the lowest visible frame
02663                                        // so the operation can be performed. 
02664                 break;
02665             }
02666         } 
02667     } while (pCurrentLayer != NULL);   
02668 
02669 #else
02670 
02671     // Find the first node which is selected 
02672     Node* pLastSelectedNode = Sel.FindLast();
02673     
02674     // Karim 18/04/2000 - spot-check! - any NULL pointers??
02675     if (pLastSelectedNode == NULL)
02676     {
02677         // fail in the same way as the layer check below, but we'll only complaing in debug.
02678         ERROR3("OpMoveToLyrBehind::GetState; NULL returned as last node in Selection!");
02679         return OpSt;
02680     }
02681 
02682     // The operation is disabled if the last selected object is already on the lowest
02683     // visible layer.
02684     BOOL LowestVisible = TRUE; 
02685     Layer* pCurrentLayer = (Layer*) (pLastSelectedNode->FindParent(CC_RUNTIME_CLASS(Layer)));
02686     ERROR2IF(pCurrentLayer == NULL, OpSt, "Cannot find layer of first selected object"); 
02687 
02688     // Determine the Document mode. 
02689     MODE PresentMode = (MODE)pCurrentLayer->IsFrame();
02690     if (PresentMode == LAYER)
02691     {
02692         do
02693         {
02694             pCurrentLayer = pCurrentLayer->FindPrevLayer();
02695             if (pCurrentLayer != NULL)
02696             {
02697                 // Is the layer visible
02698                 if (pCurrentLayer->IsVisible() && !pCurrentLayer->IsLocked() && !pCurrentLayer->IsGuide())
02699                 {
02700                         LowestVisible = FALSE; // The last node selected is not on the lowest visible layer
02701                                         // so the operation can be performed. 
02702                     break;
02703                 }
02704             } 
02705         } while (pCurrentLayer != NULL);   
02706     }
02707     else if (PresentMode == FRAME)
02708     {
02709         do
02710         {
02711             pCurrentLayer = pCurrentLayer->FindPrevFrameLayer();
02712             if (pCurrentLayer != NULL)
02713             {
02714                 // Is the layer not a guide or a page background layer?
02715                 if (!pCurrentLayer->IsGuide() && !pCurrentLayer->IsPageBackground())
02716                 {
02717                     LowestVisible = FALSE; // The last node selected is not on the lowest visible frame
02718                                            // so the operation can be performed. 
02719                     break;
02720                 }
02721             } 
02722         } while (pCurrentLayer != NULL);   
02723     }
02724     else
02725         ERROR3("OpMoveToLyrInFront::GetState - Bad mode!");
02726 #endif // WEBSTER
02727 
02728     if (LowestVisible)
02729     {
02730         // The operation must be disabled
02731         OpSt.Greyed = TRUE;
02732 
02733 
02734         if (Sel.FindFirst() == pLastSelectedNode)
02735         {
02736             #ifdef WEBSTER
02737                 // There is only a single selected node
02738                 DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_FRMS));                 
02739             #else
02740                 if(PresentMode == FRAME)
02741                     DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_FRMS));                 
02742                 else if(PresentMode == LAYER)
02743                     DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_LYRS)); 
02744                 else
02745                     ERROR3("OpMoveToLyrInBehind::GetState - Bad mode!");
02746             #endif
02747         }
02748         else
02749         {
02750             #ifdef WEBSTER
02751                 // There is more than one selected node
02752                 DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_FRM));  
02753             #else
02754                 if(PresentMode == FRAME)
02755                 {
02756                     // There is more than one selected node
02757                     DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_FRM));                      
02758                 }
02759                 else if (PresentMode == LAYER)
02760                 {
02761                     // There is more than one selected node
02762                     DisableReason = String_256(_R(IDS_ALREADY_ON_BOTTOM_LYRP)); 
02763                 }
02764                 else
02765                     ERROR3("OpMoveToLyrInFront::GetState - Bad mode!");
02766             #endif
02767         }
02768     }
02769     
02770     *UIDescription = DisableReason;  
02771 
02772     return(OpSt);   
02773 }
02774 
02775 /********************************************************************************************
02776 
02777 >   void OpMoveToLyrBehind::Do(OpDescriptor*)
02778 
02779     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02780     Created:    16/8/93
02781     Inputs:     OpDescriptor (unused)
02782     Outputs:    -
02783     Returns:    -
02784     Purpose:    Performs the OpMoveToLyrBehind operation. This moves all selected nodes 
02785                 (which are not on the lowest visible layer) to the highest z-order position 
02786                 on the next visible layer behind.
02787                 
02788                 
02789     Errors:     -
02790     SeeAlso:    -
02791 
02792 ********************************************************************************************/
02793         
02794 void OpMoveToLyrBehind::Do(OpDescriptor*)          
02795 {
02796     // Obtain the current selections 
02797     Range Sel(*(GetApplication()->FindSelection()));
02798     RangeControl rg = Sel.GetRangeControlFlags();
02799     rg.PromoteToParent = TRUE;
02800     Sel.Range::SetRangeControl(rg);
02801 
02802 
02803     // Find the first node which is selected 
02804     Node* FirstSelectedNode = Sel.FindFirst(); 
02805  
02806     // The first selected node should not ever be NULL
02807     ENSURE(FirstSelectedNode != NULL, 
02808         "The OpMoveToLyrInFront's GetState fn has not done a very good job"); 
02809     
02810     if (FirstSelectedNode != NULL) 
02811     {
02812         if (!DoStartSelOp(FALSE,FALSE))  // Try to record the selection state , don't
02813                                          // render the blobs though 
02814         {
02815             goto EndOperation;  
02816         }
02817 
02818         // We need to invalidate the region
02819         if (!DoInvalidateNodesRegions(Sel, TRUE, FALSE, FALSE, FALSE))
02820         {
02821             goto EndOperation; 
02822         }
02823 
02824         Node*   CurrentNode             = FirstSelectedNode; 
02825         
02826 //      RangeControl LyrCntrl = { TRUE, FALSE, FALSE };  // Selected + don't cross layers  
02827         Range   LayerRange; 
02828 
02829         Node*   Destination             = NULL; // Pointer to the last child of the previous layer.
02830                                                 // We move all nodes to be next siblings of this node
02831         Node*   ThisLayer               = NULL;
02832         Layer*  PrevLayer               = NULL;
02833         Node*   LastSelectedThisLayer   = NULL;
02834         Node*   NextNode                = NULL;
02835 
02836         BOOL    OldVisible              = FALSE;
02837         BOOL    OldLocked               = FALSE;
02838 
02839 #ifndef WEBSTER
02840         MODE PresentMode                = LAYER;
02841 #endif
02842         // Loop for all layers
02843         while (CurrentNode != NULL)
02844         {
02845             ENSURE(CurrentNode->IsAnObject(), "Non ink node in OpMoveToLyrBehind");
02846 
02847             // Create a range of selected nodes on this layer
02848             Range temp(CurrentNode, 
02849                                NULL, 
02850                                RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
02851             LayerRange = temp;
02852 //          LayerRange = Range(CurrentNode, 
02853 //                             NULL, 
02854 //                             RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE) );
02855 
02856             // -----------------------------------------------------------------------------
02857             // Find the last child object of the previous visible layer, which is the destination for all
02858             // nodes moved from this layer.
02859             // - there may not be a previous layer
02860             // - there may not be any children on the previous layer
02861             Destination = NULL;
02862 
02863             ThisLayer = CurrentNode->FindParent(CC_RUNTIME_CLASS(Layer));
02864 
02865             if (ThisLayer != NULL)
02866                 ((Layer*)ThisLayer)->InvalidateBoundingRect();
02867                         
02868 // WEBSTER - markn 2/2/97
02869 // Not needed in Webster.
02870 // Neville 23/6/97 Now needed but must work in Frame mode in Webster
02871 // RanbirR - 28/10/97 - Changed for Camelot v2, Frame/Layer integration. 
02872 
02873 #ifdef WEBSTER
02874             // ----------------------------------------------------------------------------
02875             // Find the previous frame
02876             PrevLayer = (Layer*)ThisLayer;
02877             do
02878             {
02879                 PrevLayer = PrevLayer->FindPrevFrameLayer();
02880                 if (PrevLayer != NULL)
02881                 {
02882                     // Is the layer not a guide or a page background layer?
02883                     if (!PrevLayer->IsGuide() && !PrevLayer->IsPageBackground())
02884                     {
02885                         // found
02886                         break;
02887                     }
02888                 }
02889                 
02890             } while (PrevLayer != NULL); 
02891 
02892             if (PrevLayer != NULL)
02893             {
02894                 // Make the layer visible and editable so we don't loose the selection
02895                 // do it blatently as it will be fixed up properly latter
02896                 OldVisible = PrevLayer->IsVisible();
02897                 OldLocked = PrevLayer->IsLocked();
02898                 PrevLayer->SetVisible(TRUE);
02899                 PrevLayer->SetLocked(FALSE);
02900             }
02901 
02902 #else
02903             // -----------------------------------------------------------------------------
02904 
02905             // Determine the document mode.
02906             PrevLayer = (Layer*)ThisLayer;
02907             PresentMode = (MODE)PrevLayer->IsFrame();
02908 
02909             if(PresentMode == LAYER)
02910             {
02911                 do
02912                 {
02913                     PrevLayer = (Layer*)(PrevLayer->FindPrevious(CC_RUNTIME_CLASS(Layer)));
02914                     if (PrevLayer != NULL)
02915                     {
02916                         if (PrevLayer->IsVisible() && !PrevLayer->IsLocked() && !PrevLayer->IsGuide())
02917                         {
02918                             // found
02919                             break;
02920                         }
02921                     }
02922                     
02923                 } while (PrevLayer != NULL); 
02924 
02925                 if (PrevLayer != NULL)
02926                 {
02927                     // Make the layer visible and editable so we don't loose the selection
02928                     // do it blatently as it will be fixed up properly latter
02929                     OldVisible = PrevLayer->IsVisible();
02930                     OldLocked = PrevLayer->IsLocked();
02931                     PrevLayer->SetVisible(TRUE);
02932                     PrevLayer->SetLocked(FALSE);
02933                 }
02934             }
02935             else if (PresentMode == FRAME)
02936             {
02937                 // Find the previous visible layer
02938                 do
02939                 {
02940                     PrevLayer = PrevLayer->FindPrevFrameLayer();
02941                     if (PrevLayer != NULL)
02942                     {
02943                         // Is the layer not a guide or a page background layer?
02944                         if (!PrevLayer->IsGuide() && !PrevLayer->IsPageBackground())
02945                         {
02946                             // found
02947                             break;
02948                         }
02949                     }
02950                 
02951                 } while (PrevLayer != NULL); 
02952 
02953                 if (PrevLayer != NULL)
02954                 {
02955                     // Make the layer visible and editable so we don't loose the selection
02956                     // do it blatently as it will be fixed up properly latter
02957                     OldVisible = PrevLayer->IsVisible();
02958                     OldLocked = PrevLayer->IsLocked();
02959                     PrevLayer->SetVisible(TRUE);
02960                     PrevLayer->SetLocked(FALSE);
02961                 }
02962             }
02963             else
02964                 ERROR3("OpMoveToLyrBehind::Do - Bad mode");
02965 #endif
02966             if (PrevLayer != NULL)
02967             {
02968                 PrevLayer->InvalidateBoundingRect();
02969 
02970                 Destination = PrevLayer->FindLastChild();
02971                 
02972                 if (Destination != NULL)  // It will be NULL if there are no objects on the
02973                                                // previous layer
02974                 {
02975                     // The Destination node could be an Insertion node, we certainly don't want to insert
02976                     // after that
02977                     if (!(Destination->IsAnObject()))
02978                     {
02979                         Destination = Destination->FindPrevious(CC_RUNTIME_CLASS(NodeRenderableInk));   
02980                     }
02981 
02982                 }
02983             } 
02984 
02985             // If there is a previous layer then shift all selected nodes 
02986             // on this layer to the layer behind.
02987             do
02988             {
02989                 NextNode = LayerRange.FindNext(CurrentNode); // Hand over hand
02990 
02991                 if (PrevLayer != NULL)   
02992                 {
02993                     if (Destination == NULL)
02994                     {
02995                         // The destination is NULL which means that the layer
02996                         // has no existing objects
02997                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
02998                         if (!DoMoveNode(CurrentNode, PrevLayer, FIRSTCHILD)) 
02999                         {
03000                             goto EndOperation;
03001                         }
03002 
03003                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
03004                         CurrentNode->SetSelected(TRUE);
03005                     }
03006                     else
03007                     {
03008                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
03009                         if (!DoMoveNode(CurrentNode, Destination, NEXT)) 
03010                         {
03011                             goto EndOperation;
03012                         }
03013 
03014                         ((NodeRenderableBounded*)CurrentNode)->ReleaseCached(TRUE, FALSE, FALSE, TRUE);
03015                         CurrentNode->SetSelected(TRUE);
03016                     }
03017                     Destination = CurrentNode; 
03018                 } 
03019 
03020 
03021                 LastSelectedThisLayer = CurrentNode;  // Used to find first 
03022                                                       // selected on next layer
03023 
03024                 CurrentNode = NextNode; 
03025             
03026             } while (CurrentNode != NULL);
03027 
03028 // #ifdef WEBSTER //  Include in Camelot2 for Frame/Layer integration - RanbirR 03/11/97
03029 #ifdef WEBSTER
03030             if (PrevLayer != NULL)
03031 #else
03032             if (PrevLayer != NULL && PresentMode == FRAME)
03033 #endif
03034             {
03035                 // Put back the old states so we get the redraw correct
03036                 PrevLayer->SetVisible(OldVisible);
03037                 //PrevLayer->SetLocked(OldLocked);
03038             }
03039 
03040 //#endif    
03041             // Obtain the first selected node of the next layer
03042             CurrentNode = Sel.FindNext(LastSelectedThisLayer); 
03043         } 
03044         
03045 //#ifdef WEBSTER    Include in Camelot2 for Frame/Layer integration - RanbirR 03/11/97  
03046 
03047         // Switch to viewing the destination layer
03048         // Otherwise, the user will see the objects dissappear and will be worried
03049         // Also, the range blows up as the destination is invisible
03050 #ifdef WEBSTER //  Include in Camelot2 for Frame/Layer integration - RanbirR 03/11/97
03051         if (PrevLayer != NULL)
03052 #else
03053         if (PrevLayer != NULL && PresentMode == FRAME)
03054 #endif
03055         {
03056 PORTNOTETRACE("gallery", "Removed used of FrameSGallery from OpMoveToLyrBehind");
03057 #if !defined(EXCLUDE_FROM_XARALX)
03058             FrameSGallery::MakeActiveLayer(PrevLayer);
03059             BROADCAST_TO_ALL(LayerMsg(PrevLayer,LayerMsg::UPDATE_ACTIVE_LAYER));
03060 #endif
03061         }
03062 
03063 //#endif // WEBSTER     
03064         
03065         // We need to invalidate the region
03066         if (!DoInvalidateNodesRegions(*(GetApplication()->FindSelection()), TRUE))
03067         {
03068             goto EndOperation; 
03069         }
03070 
03071         // Call ChangeBounds() on the first node to ensure all parent node bounds contain
03072         // the newly moved nodes bounds
03073         if (FirstSelectedNode->IsBounded())
03074         {
03075             NodeRenderableBounded* pNodeRB = (NodeRenderableBounded*)FirstSelectedNode;
03076             pNodeRB->InvalidateBoundingRect();
03077         }
03078     }
03079 
03080 EndOperation:
03081     GetApplication()->UpdateSelection();
03082 
03083     End(); // End of operation  
03084 
03085 } 
03086 
03087 /********************************************************************************************
03089 ********************************************************************************************/
03090 
03091 /********************************************************************************************
03092 
03093 >   OpCombineLayersToFrameLayer::OpCombineLayersToFrameLayer() 
03094 
03095     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03096     Created:    18/6/97
03097     Purpose:    OpCombineLayersToFrameLayer constructor
03098 
03099 ********************************************************************************************/
03100             
03101             
03102 /* OpCombineLayersToFrameLayer::OpCombineLayersToFrameLayer(): SelOperation()                               
03103 {                              
03104 } */
03105 
03106  /********************************************************************************************
03107 
03108 >   BOOL OpCombineLayersToFrameLayer::Init()
03109 
03110     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03111     Created:    18/6/97
03112     Returns:    TRUE if the operation could be successfully initialised 
03113                 FALSE if no more memory could be allocated 
03114     Purpose:    OpCombineLayersToFrameLayer constructor
03115     Errors:     ERROR will be called if there was insufficient memory to allocate the 
03116                 operation.
03117     SeeAlso:    -
03118 
03119 ********************************************************************************************/
03120 
03121 /* BOOL OpCombineLayersToFrameLayer::Init()
03122 {
03123     return RegisterOpDescriptor(
03124                                 0,                              // Tool ID 
03125                                 _R(IDS_COMBINELAYERSTOFRAMELAYER),  // String resource ID
03126                                 CC_RUNTIME_CLASS(OpCombineLayersToFrameLayer),  // Runtime class
03127                                 OPTOKEN_COMBINELAYERSTOFRAMELAYER,      // Token string
03128                                 OpCombineLayersToFrameLayer::GetState,  // GetState function
03129                                 0,                              // help ID
03130                                 0,                              // bubble help
03131                                 0,                              // resource ID
03132                                 0,                              // control ID
03133                                 SYSTEMBAR_ILLEGAL,              // Bar ID
03134                                 TRUE,                           // Recieve system messages
03135                                 FALSE,                          // Smart duplicate operation
03136                                 FALSE,                          // Clean operation
03137                                 NULL,                           // String for one copy only error
03138                                 (DONT_GREY_WHEN_SELECT_INSIDE | GREY_WHEN_NO_CURRENT_DOC) // Auto state flags
03139                                );
03140 }  */             
03141 
03142 /********************************************************************************************
03143 
03144 >   OpState OpCombineLayersToFrameLayer::GetState(String_256*, OpDescriptor*)
03145 
03146     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03147     Created:    18/6/97
03148     Inputs:     Name of the OpDescriptor being queried
03149     Outputs:    The string to show to the user
03150     Returns:    The state of the OpCombineLayersToFrameLayer operation
03151     Purpose:    For finding the OpCombineLayersToFrameLayer's state. 
03152 
03153 ********************************************************************************************/
03154 
03155 /* OpState  OpCombineLayersToFrameLayer::GetState(String_256*  UIDescription, OpDescriptor*)
03156 {
03157     // We are not a visible operation and so don't need to return reason strings
03158 
03159     OpState OpSt;
03160 
03161     // Assume operation is disabled by default
03162     OpSt.Greyed = TRUE;
03163     
03164     // Is there a selected spread?
03165     Spread * pSpread = Document::GetSelectedSpread();
03166     if (pSpread)
03167     {
03168         // See if we have frame layers present. If so, then do we have non-frame layers present?
03169         // The operation needs to ensure that all other non-guide and non-background layers are frame layers
03170         // We could be in the situation where we have a single non-frame layer present, so we must
03171         // include this
03172 //      Layer* pFrameLayer = pSpread->FindFirstFrameLayer();
03173 //      if (pFrameLayer)
03174         UINT32 NonFrameLayersFound = 0;
03175         Layer* pCurrentLayer = pSpread->FindFirstLayer();
03176         while (pCurrentLayer != NULL)
03177         {
03178             if (!pCurrentLayer->IsBackground() && !pCurrentLayer->IsGuide() &&
03179                 !pCurrentLayer->IsPageBackground() && !pCurrentLayer->IsFrame())
03180             {
03181                 NonFrameLayersFound++;
03182             }
03183 
03184             pCurrentLayer = pCurrentLayer->FindNextLayer();
03185         }
03186 
03187         if (NonFrameLayersFound > 0)
03188         {
03189             // The operation is enabled
03190             OpSt.Greyed = FALSE;
03191         }
03192     }
03193 
03194     return OpSt;   
03195 } */
03196 
03197 /********************************************************************************************
03198 
03199 >   virtual void OpCombineLayersToFrameLayer::Do(OpDescriptor*)
03200 
03201     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03202     Created:    18/6/97
03203     Inputs:     OpDescriptor (unused)
03204     Purpose:    Performs the OpCombineLayersToFrameLayer operation.
03205                 This sees if we have frame layers present. If so, then it checks if there 
03206                 are any non-frame layers present. If we have a mixture of frame and non-frame
03207                 layers then combine all non-frame layers together onto one layer and make it
03208                 a frame layer.
03209 
03210 ********************************************************************************************/
03211         
03212 /* void OpCombineLayersToFrameLayer::Do(OpDescriptor* pOpDesc)         
03213 {
03214     TRACEUSER( "Neville", _T("OpCombineLayersToFrameLayer::Do\n"));
03215     // Is there a selected spread?
03216     Spread * pSpread = Document::GetSelectedSpread();
03217     if (pSpread)
03218     {
03219         OpParam Param;
03220         Param.Param1 = (INT32)pSpread;
03221         DoWithParam(pOpDesc, &Param);
03222     }
03223 } */
03224 
03225 /********************************************************************************************
03226 
03227 >   virtual void OpCombineLayersToFrameLayer::Do(OpDescriptor*)
03228 
03229     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03230     Created:    18/6/97
03231     Inputs:     OpDescriptor (unused)
03232                 pParam->Param1  pointer to the spread to use
03233     Purpose:    Performs the OpCombineLayersToFrameLayer operation.
03234                 This sees if we have frame layers present. If so, then it checks if there 
03235                 are any non-frame layers present. If we have a mixture of frame and non-frame
03236                 layers then combine all non-frame layers together onto one layer and make it
03237                 a frame layer.
03238 
03239 ********************************************************************************************/
03240 
03241 /* void OpCombineLayersToFrameLayer::DoWithParam(OpDescriptor* pOpDesc, OpParam* pParam)
03242 {
03243     if (pParam == NULL)
03244     {
03245         ERROR3("OpCombineLayersToFrameLayer::DoWithParam Bad params!");
03246         End();
03247         return;
03248     }
03249 
03250     TRACEUSER( "Neville", _T("OpCombineLayersToFrameLayer::DoWithParam\n"));
03251     
03252     // Recover the passed in spread pointer
03253     Spread * pSpread = (Spread*)pParam->Param1;
03254     ERROR3IF(!pSpread->IS_KIND_OF(Spread), "OpParam->Param2 passed is not a Spread!");
03255     if (pSpread == NULL)
03256     {
03257         ERROR3("OpCombineLayersToFrameLayer::DoWithParam Bad spread pointer");
03258         End();
03259         return;
03260     }
03261 
03262     // Do something useful
03263     // Ensure that all other non-guide and non-background layers are frame layers
03264     UINT32 NonFrameLayersFound = 0;
03265     Layer* pCurrentLayer = pSpread->FindFirstLayer();
03266     while (pCurrentLayer != NULL)
03267     {
03268         if (!pCurrentLayer->IsBackground() && !pCurrentLayer->IsGuide() &&
03269             !pCurrentLayer->IsPageBackground() && !pCurrentLayer->IsFrame())
03270         {
03271             // Do an undoable form of pCurrentLayer->SetFrame(TRUE);
03272             OpLayerGalParam Param(LAYER_MAKEFRAME, pSpread);
03273             Param.pLayer = pCurrentLayer;
03274             LayerStateAction::Init(this, &UndoActions, Param);
03275             
03276             NonFrameLayersFound++;
03277         }
03278 
03279         pCurrentLayer = pCurrentLayer->FindNextLayer();
03280     }
03281 
03282     if (NonFrameLayersFound > 0)
03283     {
03284         TRACEUSER( "Neville", _T("++++++++++EnsureFrameLayerIntegrity found %d non-frame layers\n"),NonFrameLayersFound);
03285 
03286         // We need to update the display as one or more layer items have changed status
03287         // So tell ourselves about the change. (We are static and so cannot do it directly!)
03288         BROADCAST_TO_ALL(SpreadMsg(pSpread, SpreadMsg::SpreadReason::LAYERCHANGES));
03289     }
03290 
03291     End(); // End of operation  
03292     return;
03293 } */
03294 
03295 /**************************************************************************************************************************
03296 
03297 >   FrameInFrontOpDescriptor::FrameInFrontOpDescriptor( const TCHAR* pcszToken, 
03298                                                         CCRuntimeClass* pClass = CC_RUNTIME_CLASS(PlugInOp),
03299                                                         pfnGetState gs = PlugInOp::GetState)
03300 
03301     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>
03302     Created:    11/12/96
03303     Inputs:     pcszToken       the "OpToken" of the associated Operation
03304                 pClass          the runtime class to use.
03305                 gs              the GetState function to use.
03306     Outputs:    -
03307     Returns:    -
03308     Purpose:    Constructs the new FrameInFrontOpDescriptor
03309     Errors:     -
03310     SeeAlso:    -
03311 
03312 ***************************************************************************************************************************/
03313 
03314 FrameInFrontOpDescriptor::FrameInFrontOpDescriptor( const TCHAR* pcszToken, 
03315                                                     CCRuntimeClass* pClass, pfnGetState gs)
03316   : OpDescriptor(   0,                                                          // tool ID
03317                     _R(IDS_MOVELAYERINFRONT),                                       // String resource ID (use same for all)
03318                     pClass,                                                     //CC_RUNTIME_CLASS(PlugInOp), Runtime class
03319                     (TCHAR*) pcszToken,                                         // OpToken
03320                     gs,                                                         // GetState function
03321                     0,                                                      // help ID
03322                     _R(IDBBL_MOVELAYERINFRONT),                                     // bubble help
03323                     _R(IDD_ANIMATIONBAR),                                           // resource ID
03324                     _R(IDC_FRAME_MOVEUPAFRAME),                                     // control ID
03325                     TRUE,                                                       // Recieve system messages
03326                     FALSE,                                                      // Smart duplicate operation
03327                     TRUE,                                                       // Clean operation
03328                     0,                                                          // String for one copy only error
03329                     (GREY_WHEN_NO_CURRENT_DOC | GREY_WHEN_NO_SELECTION)         // Auto state flags
03330                 )
03331 {}
03332 
03333 
03334 /********************************************************************************************
03335 
03336 >   static OpState FrameInFrontOpDescriptor::GetState(String_256* pDesc, OpDescriptor* pOpDesc)
03337 
03338     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>
03339     Created:    21/10/97
03340     Inputs:     pDesc       --- A pointer to a String. GetState fills this with the
03341                                 appropriate details for the conditions arising eg. why
03342                                 "Previous Zoom" is greyed out.
03343                 pOpDesc     --- A pointer to the OpDescriptor whose state is being
03344                                 queried.
03345     Returns:    An OpState containing the flags that show what is valid.
03346     Purpose:    Returns the state that this operation should appear in the menus 
03347                 or as a buttom, for example - greyed out, or ticked.
03348 
03349 ********************************************************************************************/
03350 
03351 OpState FrameInFrontOpDescriptor::GetState(String_256*, OpDescriptor* pOpDesc)
03352 {
03353     // At present, this item is always available.
03354     OpState OpSt;
03355     return OpSt;
03356 }
03357 
03358 
03359 /********************************************************************************************
03360 
03361 >   virtual void FrameInFrontOpDescriptor::GetText(String_256* Description, OpTextFlags WhichText)
03362 
03363     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>  (From Mario code in base class.)
03364     Created:    21/10/97
03365     Inputs:     TextFlag - Identifies which text string to retrieve from the string resource
03366     Outputs:    Description - Operation description string if it is found or
03367                 NULL otherwise.
03368     Returns:    TRUE if successfully retrieves the string and FALSE othersise.
03369     Purpose:    Depending upon the document Mode, (i.e Frame or Layer),
03370                 this function will obtain the String resource describing an operation. 
03371                 String resources may have one or more text descriptions in them, therefore,
03372                 a TextFlag can be used to identify the the appropriate text required.
03373     
03374 ********************************************************************************************/
03375 
03376 BOOL FrameInFrontOpDescriptor::GetText(String_256* Description, OpTextFlags WhichText)
03377 {   
03378     // Assume we are in layer mode.
03379     BOOL LayerMode = TRUE;
03380     TCHAR* ok;
03381     
03382     //Determine the document mode.
03383     Document* pDoc = Document::GetSelected();
03384 
03385     // Ensure a valid ptr.
03386     if(pDoc)
03387     {
03388         // Get a ptr to the selected spread
03389         Spread* pSpread = pDoc->GetSelectedSpread();
03390     
03391         // Ensure a valid spread ptr.
03392         if(pSpread)
03393         {
03394 
03395             // Are there any frame layers?
03396             Layer* pFrameLayer = pSpread->FindFirstFrameLayer();    
03397 
03398             //If a frame layer exists, then this is an animation doc.
03399             if (pFrameLayer)
03400                 LayerMode = FALSE;
03401         }
03402     }
03403 
03404     if(LayerMode)
03405     {
03406         // In layer mode.
03407         String_256  ResourceText( _R(IDS_MOVELAYERINFRONT), ModuleID );
03408 
03409         // Explicitly cast return value from GetDescription from a TCHAR* to a String_256
03410         ok = GetDescription((TCHAR*) ResourceText, WhichText);
03411     }
03412     else
03413     {
03414         // In frame mode.
03415         String_256 ResourceText( _R(IDS_MOVEFRAMERINFRONT), ModuleID );
03416 
03417         // Explicitly cast return value from GetDescription from a TCHAR* to a String_256
03418         ok = GetDescription((TCHAR*) ResourceText, WhichText);
03419     }
03420     
03421     // if description is found then return true else return false
03422     if (ok)        
03423     {
03424         *Description = String_256(ok);
03425         return TRUE;
03426     }
03427     else
03428         return FALSE;
03429 
03430 }
03431 
03432 
03433 /**************************************************************************************************************************
03434 
03435 >   FrameBehindOpDescriptor::FrameBehindOpDescriptor(   const TCHAR* pcszToken, 
03436                                                         CCRuntimeClass* pClass = CC_RUNTIME_CLASS(PlugInOp),
03437                                                         pfnGetState gs = PlugInOp::GetState)
03438 
03439     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>
03440     Created:    11/12/96
03441     Inputs:     pcszToken       the "OpToken" of the associated Operation
03442                 pClass          the runtime class to use.
03443                 gs              the GetState function to use.
03444     Outputs:    -
03445     Returns:    -
03446     Purpose:    Constructs the new FrameInFrontOpDescriptor
03447     Errors:     -
03448     SeeAlso:    -
03449 
03450 ***************************************************************************************************************************/
03451 
03452 FrameBehindOpDescriptor::FrameBehindOpDescriptor(   const TCHAR* pcszToken, 
03453                                                     CCRuntimeClass* pClass, pfnGetState gs)
03454   : OpDescriptor(   0,                                                          // tool ID
03455                     _R(IDS_MOVELAYERBEHIND),                                        // String resource ID (use same for all)
03456                     pClass,                                                     //CC_RUNTIME_CLASS(PlugInOp), Runtime class
03457                     (TCHAR*) pcszToken,                                         // OpToken
03458                     gs,                                                         // GetState function
03459                     0,                                                          // help ID
03460                     _R(IDBBL_MOVELAYERBEHIND),                                      // bubble help
03461                     _R(IDD_ANIMATIONBAR),                                           // resource ID
03462                     _R(IDC_FRAME_MOVEDOWNAFRAME),                                   // control ID
03463                     TRUE,                                                       // Recieve system messages
03464                     FALSE,                                                      // Smart duplicate operation
03465                     TRUE,                                                       // Clean operation
03466                     0,                                                          // String for one copy only error
03467                     (GREY_WHEN_NO_SELECTION | GREY_WHEN_NO_CURRENT_DOC)         // Auto state flags
03468                 )
03469 {}
03470 
03471 /********************************************************************************************
03472 
03473 >   static OpState FrameBehindOpDescriptor::GetState(String_256* pDesc, OpDescriptor* pOpDesc)
03474 
03475     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>
03476     Created:    21/10/97
03477     Inputs:     pDesc       --- A pointer to a String. GetState fills this with the
03478                                 appropriate details for the conditions arising eg. why
03479                                 "Previous Zoom" is greyed out.
03480                 pOpDesc     --- A pointer to the OpDescriptor whose state is being
03481                                 queried.
03482     Returns:    An OpState containing the flags that show what is valid.
03483     Purpose:    Returns the state that this operation should appear in the menus 
03484                 or as a buttom, for example - greyed out, or ticked.
03485 
03486 ********************************************************************************************/
03487 
03488 OpState FrameBehindOpDescriptor::GetState(String_256*, OpDescriptor* pOpDesc)
03489 {
03490     // At present, this item is always available.
03491     OpState OpSt;
03492     return OpSt;
03493 }
03494 
03495 /********************************************************************************************
03496 
03497 >   virtual void FrameBehindOpDescriptor::GetText(String_256* Description, OpTextFlags WhichText)
03498 
03499     Author:     Ranbir_Rana (Xara Group Ltd) <camelotdev@xara.com>  (From Mario code in base class.)
03500     Created:    21/10/97
03501     Inputs:     TextFlag - Identifies which text string to retrieve from the string resource
03502     Outputs:    Description - Operation description string if it is found or
03503                 NULL otherwise.
03504     Returns:    TRUE if successfully retrieves the string and FALSE othersise.
03505     Purpose:    Depending upon the document Mode, (i.e Frame or Layer),
03506                 this function will obtain the String resource describing an operation. 
03507                 String resources may have one or more text descriptions in them, therefore,
03508                 a TextFlag can be used to identify the the appropriate text required.
03509     
03510 ********************************************************************************************/
03511 
03512 BOOL FrameBehindOpDescriptor::GetText(String_256* Description, OpTextFlags WhichText)
03513 {   
03514     // Assume we are in layer mode.
03515     BOOL LayerMode = TRUE;
03516     TCHAR* ok;
03517     
03518     //Determine the document mode.
03519     Document* pDoc = Document::GetSelected();
03520 
03521     // Ensure a valid ptr.
03522     if(pDoc)
03523     {
03524         // Get a ptr to the selected spread
03525         Spread* pSpread = pDoc->GetSelectedSpread();
03526     
03527         // Ensure a valid spread ptr.
03528         if(pSpread)
03529         {
03530             // Are there any frame layers?
03531             Layer* pFrameLayer = pSpread->FindFirstFrameLayer();    
03532 
03533             //If a frame layer exists, then this is an animation doc.
03534             if (pFrameLayer)
03535                 LayerMode = FALSE;
03536         }
03537     }
03538 
03539     if(LayerMode)
03540     {
03541         // In layer mode.
03542         String_256  ResourceText( _R(IDS_MOVELAYERBEHIND), ModuleID );
03543 
03544         // Explicitly cast return value from GetDescription from a TCHAR* to a String_256
03545         ok = GetDescription((TCHAR*) ResourceText, WhichText);
03546     }
03547     else
03548     {
03549         // In frame mode.
03550         String_256 ResourceText( _R(IDS_MOVERFAMEBEHIND), ModuleID );
03551 
03552         // Explicitly cast return value from GetDescription from a TCHAR* to a String_256
03553         ok = GetDescription((TCHAR*) ResourceText, WhichText);
03554     }
03555     
03556     // if description is found then return true else return false
03557     if (ok)        
03558     {
03559         *Description = String_256(ok);
03560         return TRUE;
03561     }
03562     else
03563         return FALSE;
03564 
03565 }

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