opsmpshp.cpp

Go to the documentation of this file.
00001 // $Id: opsmpshp.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 // The Ellipes creation and Editing operations
00099 
00100 
00101 /*
00102 */
00103 
00104 
00105 #include "camtypes.h"
00106 #include "opsmpshp.h"
00107 
00108 // Code headers
00109 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "noderect.h"
00115 #include "progress.h"
00116 #include "objchge.h"
00117 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 
00120 // Resource headers
00121 //#include "mario.h"
00122 //#include "resource.h"
00123 //#include "rik.h"
00124 #include "bubbleid.h"
00125 
00126 CC_IMPLEMENT_DYNCREATE( OpEditRectangle, SelOperation )
00127 
00128 
00129 #define new CAM_DEBUG_NEW
00130 
00131 
00132 /********************************************************************************************
00133 
00134 >   OpEditRectangle::OpEditRectangle()
00135 
00136     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00137     Created:    1/6/94
00138     Purpose:    Dummy Contrustor
00139 
00140 ********************************************************************************************/
00141 
00142 OpEditRectangle::OpEditRectangle()
00143 {
00144     RectPath = NULL;
00145 }
00146 
00147 
00148 
00149 
00150 /********************************************************************************************
00151 
00152 >   void OpEditRectangle::DoDrag(DocCoord Anchor, Spread* pSpread, NodeEllipse* pElip, INT32 Corner)
00153 
00154     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00155     Created:    1/6/94
00156     Inputs:     Anchor - The starting position of the drag
00157                 pSpread - The spread that the drag started over
00158                 pElip - The NodeEllipse that is being edited
00159                 Corner - The corner of the Parallelogram that is fixed
00160     Purpose:    Starts up a drag for editing a NodeEllipse. It records the start postion and
00161                 start spread etc as well as copying the parallelogram of the NodeEllipse
00162                 to change and creating a new NodeEllipse for the purpose of render EORed
00163                 stuff
00164 
00165 ********************************************************************************************/
00166 
00167 void OpEditRectangle::DoDrag(DocCoord Anchor, Spread* pSpread, NodeRect* pRect, INT32 Corner)
00168 {
00169     // Various starting positions
00170     StartSpread = pSpread;
00171     StartPoint = Anchor;
00172     LastMousePosition = Anchor;
00173 
00174     // The original shape in the tree
00175     OldRect = pRect;
00176 
00177     // Make a copy of the bounding parallelogram
00178     Parallel[0] = pRect->Parallel[0];
00179     Parallel[1] = pRect->Parallel[1];
00180     Parallel[2] = pRect->Parallel[2];
00181     Parallel[3] = pRect->Parallel[3];
00182 
00183     // Which corner of the parallelogram is not moving
00184     FixedCorner = Corner;
00185 
00186     // We will make a rect for the drag blobs
00187     UseRect = FALSE;
00188     RectPath = new NodeRect;
00189     if (RectPath!=NULL)
00190     {   
00191         if (RectPath->SetUpPath(12,12))
00192         {
00193             // Mark the Ellipse as being valid
00194             UseRect = TRUE;
00195 
00196             // Give the ellipse a valid path
00197             RectPath->CreateShape(pRect->GetBoundingRect());
00198             RectPath->Parallel[Corner] = Parallel[Corner];
00199 
00200             // Build a rect from the parallel ready for the Eor blobs
00201             RebuildParallelogram(Anchor);
00202 
00203             // and draw the blobs in
00204             RenderDragBlobs(DocRect(0,0,0,0), StartSpread, FALSE);
00205 
00206             // And tell the Dragging system that we need drags to happen
00207             StartDrag( DRAGTYPE_AUTOSCROLL );
00208         }
00209     }
00210 
00211     // If we do not have a path, then report the error
00212     if (UseRect == FALSE)
00213         InformError(_R(IDS_OUT_OF_MEMORY), _R(IDS_OK));
00214 }
00215     
00216 
00217 
00218 /********************************************************************************************
00219 
00220 >   void OpEditRectangle::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods,
00221                                         Spread* pSpread, BOOL bSolidDrag)
00222 
00223     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00224     Created:    1/6/94
00225     Inputs:     PointerPos - The current position of the mouse
00226                 ClickMods - Which buttons and modifiers are held down
00227                 pSpread - The Spread that the mouse is over now.
00228     Purpose:    Recalculates the ellipse according to the new position of the corner that
00229                 is being dragged, EORs it to the screen and keeps the Parallelogram up
00230                 to date.
00231 
00232 ********************************************************************************************/
00233 
00234 void OpEditRectangle::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods, Spread* pSpread, BOOL bSolidDrag)
00235 {
00236     // Snap the actual mouse position to the grid if needed
00237     DocView::SnapCurrent(pSpread, &PointerPos);
00238 
00239     // Constrain the mouse motion if needed
00240     if (ClickMods.Constrain)
00241         DocView::ConstrainToAngle(StartPoint, &PointerPos);
00242 
00243     // If the mouse is in a different position then do something
00244     if (PointerPos != LastMousePosition)
00245     {
00246         // First Rub out the old Drag blobs
00247         RenderDragBlobs(DocRect(0,0,0,0), StartSpread, bSolidDrag);
00248 
00249         // Make sure that the coords are relative to the coorect spread
00250         if (pSpread != StartSpread)
00251             PointerPos = MakeRelativeToSpread(StartSpread, pSpread, PointerPos);
00252 
00253         // Build an ellipse ready for the Eor blobs
00254         RebuildParallelogram(PointerPos);
00255 
00256         // Update the last mouse position and re-calc the bounding rect
00257         LastMousePosition = PointerPos;
00258         RenderDragBlobs(DocRect(0,0,0,0), StartSpread, bSolidDrag);
00259     }
00260 }
00261 
00262 
00263 
00264 
00265 /********************************************************************************************
00266 
00267 >   void OpEditRectangle::DragFinished(DocCoord PointerPos, ClickModifiers ClickMods,
00268                                     Spread* pSpread, BOOL Success, BOOL bSolidDrag)
00269 
00270     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00271     Created:    1/6/94
00272     Inputs:     PointerPos - The current position of the mouse
00273                 ClickMods - Which buttons and modifiers are held down
00274                 pSpread - The Spread that the mouse is over now.
00275                 Success - TRUE if the drag was completed sucessfully.
00276     Purpose:    If the drag was a success then a copy of the original node in the tree is
00277                 created and updated ellipse built. The original NodeEllipse is hidden and
00278                 the new one if inserted into the tree. If any of these things fail then
00279                 the operation will fail.
00280 
00281 ********************************************************************************************/
00282 
00283 void OpEditRectangle::DragFinished(DocCoord PointerPos, ClickModifiers ClickMods, Spread*, BOOL Success, BOOL bSolidDrag)
00284 {
00285     // First Rub out the old Drag blobs and end the drag
00286     RenderDragBlobs(DocRect(0,0,0,0), StartSpread, bSolidDrag);
00287     EndDrag();
00288 
00289     // Flag to say if everything has worked
00290     BOOL IsOk = FALSE;
00291 
00292     // if the drag was a sucess then start to build undo etc
00293     if (Success)
00294     {
00295         // Will the ellipse allow the op?
00296         ObjChangeFlags cFlags;
00297         cFlags.ReplaceNode = TRUE;
00298         ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,OldRect,this);
00299         IsOk = OldRect->AllowOp(&ObjChange);    
00300 
00301         // build all the undo and complete the edit
00302         if (IsOk) IsOk = CompleteOperation();
00303 
00304         if (IsOk)
00305         {
00306             // Update all the effected parents
00307             ObjChange.Define(OBJCHANGE_FINISHED,cFlags,OldRect,this);
00308             IsOk = UpdateChangedNodes(&ObjChange);
00309         }
00310     }
00311 
00312     // If something went wrong, then fail
00313     if (IsOk==FALSE)
00314         FailAndExecute();
00315 
00316     // If we have an rect to work with then get rid of it
00317     if (UseRect)
00318         delete RectPath;
00319 
00320     // always call end
00321     End();
00322 }
00323 
00324 
00325 
00326 
00327 /********************************************************************************************
00328 
00329 >   BOOL OpEditRectangle::CompleteOperation()
00330 
00331     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00332     Created:    24/8/94
00333     Returns:    TRUE if it worked, FALSE if it failed
00334     Purpose:    Builds all the undo and generally edits the rectangle.
00335 
00336 ********************************************************************************************/
00337 
00338 BOOL OpEditRectangle::CompleteOperation()
00339 {
00340     // Start a slow job
00341     BeginSlowJob();
00342 
00343     // Get a node to copy the original into
00344     Node* pNode;
00345     if (!OldRect->NodeCopy(&pNode))
00346         return FALSE;
00347 
00348     // Get our new node as the correct type
00349     ENSURE(pNode->IsKindOf(CC_RUNTIME_CLASS(NodeRect)), "Node should have been a NodeRect");
00350     NodeRect* pRect = (NodeRect*) pNode;
00351 
00352     // Create an rect to fill the bounding rect
00353     pRect->Parallel[0] = RectPath->Parallel[0];
00354     pRect->Parallel[1] = RectPath->Parallel[1];
00355     pRect->Parallel[2] = RectPath->Parallel[2];
00356     pRect->Parallel[3] = RectPath->Parallel[3];
00357 
00358     pRect->UpdateShape();
00359     pRect->InkPath.IsFilled = TRUE;
00360 
00361     // Start building the undo
00362     if (!DoStartSelOp(FALSE))
00363         return FALSE;
00364 
00365     // Add the new rect to the tree
00366     if (!DoInsertNewNode(pRect, OldRect, NEXT, TRUE))
00367         return FALSE;
00368 
00369     // Invalidate the region of the old rect
00370     if (!DoInvalidateNodeRegion(OldRect, TRUE))
00371         return FALSE;
00372 
00373     // and remove the old Rect from the tree
00374     if (!DoHideNode(OldRect, TRUE))
00375         return FALSE;
00376 
00377     // Transform the Node Children according to bounding box changes
00378     if (!TransformChildAttrs(pRect))
00379         return FALSE;
00380 
00381     // everything has worked, so return TRUE
00382     return TRUE;
00383 }
00384 
00385 
00386 
00387 /********************************************************************************************
00388 
00389 >   BOOL OpEditRectangle::TransformChildAttrs(NodeRect* pRect)
00390 
00391     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00392     Created:    24/8/94
00393     Purpose:    This performs a bodge that Charles asked to be added that scales the attributes
00394                 when the rectangle is edited.
00395 
00396 ********************************************************************************************/
00397 
00398 BOOL OpEditRectangle::TransformChildAttrs(NodeRect* pRect)
00399 {
00400     DocRect OldBounds = OldRect->GetBoundingRect(TRUE);
00401     DocRect NewBounds = pRect->GetBoundingRect(TRUE);
00402 
00403     // Get the Width and Height of the two rectangles
00404     INT32 OldWidth  = OldBounds.Width();
00405     INT32 OldHeight = OldBounds.Height();
00406     INT32 NewWidth  = NewBounds.Width();
00407     INT32 NewHeight = NewBounds.Height();
00408 
00409     // Find the Centre of each rectangle
00410     OldBounds.Translate(OldWidth/2, OldHeight/2);
00411     NewBounds.Translate(NewWidth/2, NewHeight/2);
00412     DocCoord OldCentre = OldBounds.lo;
00413     DocCoord NewCentre = NewBounds.lo;
00414 
00415     // Calculate the difference in size between the two rectangles
00416     FIXED16 xscale = FIXED16(double(NewWidth)/double(OldWidth));
00417     FIXED16 yscale = FIXED16(double(NewHeight)/double(OldHeight));
00418 
00419     // And now make a transform for the attribute
00420     // First move the old attribute position to the origin
00421     Matrix AttrTrans = Matrix(-OldCentre.x, -OldCentre.y);
00422 
00423     // Now scale it
00424     AttrTrans *= Matrix(xscale, yscale);
00425 
00426     // And finally move it to the new position
00427     AttrTrans *= Matrix(NewCentre.x, NewCentre.y);
00428 
00429     // Now scan for all Attribute Children and Transform them
00430     Node* pNode = pRect->FindFirstChild();
00431     while (pNode != NULL)
00432     {
00433         if (pNode->IsKindOf(CC_RUNTIME_CLASS(AttrFillGeometry)))
00434         {
00435             // get the transform to use
00436             Trans2DMatrix* Trans = new Trans2DMatrix(AttrTrans);
00437 
00438             // get the node and transform it
00439             //NodeAttribute* NodeToTransform = (NodeAttribute*)pNode;
00440 //          RangeControl rc = {TRUE, TRUE, FALSE};
00441             Range temp(pNode, pNode, RangeControl(TRUE,TRUE,FALSE));
00442             if (!DoTransformNodes(temp, Trans))
00443             {
00444                 delete Trans;
00445                 return FALSE;
00446             }
00447         }
00448 
00449         // go get the next one
00450         pNode = pNode->FindNext();
00451     }
00452 
00453     return TRUE;
00454 }
00455 
00456 
00457 
00458 
00459 /********************************************************************************************
00460 
00461 >   void OpEditRectangle::RebuildParallelogram(DocCoord PointerPos)
00462 
00463     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00464     Created:    1/6/94
00465     Inputs:     PointerPos - The coords of the Parallelograms corner that is being dragged
00466     Purpose:    Recalculates the parallelogram based on the corner being dragged and the
00467                 fixed corner. The new parallelogram is copied into the Ellipse we are using
00468                 for EORing and the Ellipse rebuilt to fit the parallelogram
00469 
00470 ********************************************************************************************/
00471 
00472 void OpEditRectangle::RebuildParallelogram(DocCoord PointerPos)
00473 {
00474     // Lets number the coordinates. 0 is the fixed one and go clockwise from there
00475     INT32 pos0, pos1, pos2, pos3;
00476     pos0 = FixedCorner;
00477 
00478     if (pos0>1)
00479         pos2 = pos0-2;
00480     else
00481         pos2 = pos0+2;
00482 
00483     if (pos0==3)
00484         pos1 = 0;
00485     else
00486         pos1 = pos0+1;
00487 
00488     if (pos0==0)
00489         pos3 = 3;
00490     else
00491         pos3 = pos0-1;
00492 
00493     // Calculate the offsets from the old point and the fixed point
00494     double dx0 = PointerPos.x - Parallel[pos2].x;
00495     double dy0 = PointerPos.y - Parallel[pos2].y;
00496 
00497     double dx3 = Parallel[pos1].x - Parallel[pos0].x;
00498     double dy3 = Parallel[pos1].y - Parallel[pos0].y;
00499 
00500     double dx4 = Parallel[pos3].x - Parallel[pos0].x;
00501     double dy4 = Parallel[pos3].y - Parallel[pos0].y;
00502     
00503     // Calculate the bits that we need to know
00504     double dx1 = dx3 * ((dy0*dx4-dy4*dx0) / (dx4*dy3-dy4*dx3));
00505     double dy1 = dy3 * ((dy0*dx4-dy4*dx0) / (dx4*dy3-dy4*dx3));
00506     double dx2 = dx4 * ((dx3*dy0-dy3*dx0) / (dy4*dx3-dx4*dy3));
00507     double dy2 = dy4 * ((dx3*dy0-dy3*dx0) / (dy4*dx3-dx4*dy3));
00508 
00509     // Change the parallelogram
00510     RectPath->Parallel[pos1].x = Parallel[pos1].x + (INT32)dx1;
00511     RectPath->Parallel[pos1].y = Parallel[pos1].y + (INT32)dy1;
00512 
00513     RectPath->Parallel[pos3].x = Parallel[pos3].x + (INT32)dx2;
00514     RectPath->Parallel[pos3].y = Parallel[pos3].y + (INT32)dy2;
00515     
00516     RectPath->Parallel[pos2] = PointerPos;
00517 
00518     // Build an ellipse in this parallelogram
00519     RectPath->UpdateShape();
00520 }
00521 
00522 
00523 
00524 /********************************************************************************************
00525 
00526 >   void OpEditRectangle::RenderDragBlobs(DocRect Rect, Spread* pSpread, BOOL bSolidDrag)
00527 
00528     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00529     Created:    1/6/94
00530     Inputs:     Rect - the rect that needs redrawing
00531                 pSpread  - the spread that is being rendered
00532     Purpose:    Renders the Ellipse as it will look if the drag were to end. If we failed
00533                 to create the Ellipse earlier, it will draw a bounding rect
00534 
00535 ********************************************************************************************/
00536 
00537 void OpEditRectangle::RenderDragBlobs(DocRect Rect, Spread* pSpread, BOOL bSolidDrag)
00538 {
00539     // If being called from DocView::RenderView, then the spread could be wrong
00540     if (pSpread != StartSpread)
00541         return;
00542 
00543     // Decide what to area to redraw
00544     DocRect* pRect = NULL;
00545     if (!Rect.IsEmpty())
00546         pRect = &Rect;
00547 
00548     // Start an eor render session
00549     RenderRegion* pRegion = DocView::RenderOnTop(pRect, pSpread, ClippedEOR);
00550     while (pRegion)
00551     {
00552         // Set the line colour 
00553         pRegion->SetLineColour(COLOUR_XORNEW);
00554 
00555         // Draw the Rectangle
00556         RectPath->RenderEorDrag(pRegion);
00557 
00558         // Get the Next render region
00559         pRegion = DocView::GetNextOnTop(pRect);
00560     }
00561 }
00562 
00563 
00564 
00565 
00566 /********************************************************************************************
00567 
00568 >   BOOL OpEditRectangle::Declare()
00569 
00570     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00571     Created:    21/9/93
00572     Returns:    TRUE if all went OK, False otherwise
00573     Purpose:    Adds the operation to the list of all known operations
00574 
00575 ********************************************************************************************/
00576 
00577 BOOL OpEditRectangle::Init()
00578 {
00579     return (RegisterOpDescriptor(
00580                                 0, 
00581                                 _R(IDS_RECTANGLE_TOOL),
00582                                 CC_RUNTIME_CLASS(OpEditRectangle), 
00583                                 OPTOKEN_EDITRECT,
00584                                 OpEditRectangle::GetState,
00585                                 0,  /* help ID */
00586                                 _R(IDBBL_EDITRECTOP),
00587                                 0   /* bitmap ID */));
00588 }
00589 
00590 
00591 /********************************************************************************************
00592 
00593 >   OpState OpEditRectangle::GetState(String_256* Description, OpDescriptor*)
00594 
00595     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00596     Created:    15/11/93
00597     Outputs:    Description - GetState fills this string with an approriate description
00598                 of the current state of the push tool
00599     Returns:    The state of the operation, so that menu items (ticks and greying can be
00600                 done properly
00601     Purpose:    Find out the state of the operation at the specific time
00602 
00603 ********************************************************************************************/
00604 
00605 OpState OpEditRectangle::GetState(String_256* Description, OpDescriptor*)
00606 {
00607     OpState Blobby;
00608     
00609     return Blobby;
00610 }
00611 

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