aligndlg.cpp

Go to the documentation of this file.
00001 // $Id: aligndlg.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 /*
00100 */
00101 
00102 #include "camtypes.h"
00103 
00104 DECLARE_SOURCE("$Revision: 1282 $");
00105 
00106 #include "camelot.h"
00107 //#include "dlgtypes.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00108 #include "aligndlg.h" 
00109 //#include "mario.h"
00110 //#include "ed.h"
00111 //#include "eddlg.h"
00112 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "rnddlgs.h"
00117 #include "ccdc.h"
00118 #include "progress.h"
00119 #include "grnddib.h"
00120 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "page.h"
00123 //#include "dialogop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "selmsg.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "qualattr.h"
00126 #include "dlgcol.h"
00127 //#include "barsdlgs.h"
00128 #include "keypress.h"
00129 #include "bubbleid.h"
00130 #include "ophist.h"
00131 
00132 CC_IMPLEMENT_DYNCREATE(ArrangeAlignment, DialogOp)   
00133 CC_IMPLEMENT_DYNCREATE(OpAlign, TransOperation)   
00134 #define new CAM_DEBUG_NEW
00135 
00136 const CDlgMode ArrangeAlignment::Mode=MODELESS;
00137 const UINT32     ArrangeAlignment::IDD =_R(IDD_ALIGNDIALOG);
00138 
00139 // lists of grouped radio buttons
00140 const CGadgetID TargetArea[]={_R(IDC_ALIGNDIALOG_TOSELECTION),  // default
00141                               _R(IDC_ALIGNDIALOG_TOPAGE),       
00142                     //  WEBSTER-ranbirr-13/11/96
00143                     #ifndef WEBSTER
00144                               _R(IDC_ALIGNDIALOG_TOSPREAD),     
00145                     #endif //webster
00146                               0};
00147 
00148 // string ID lists for combo boxes (null terminated) 
00149 // >>>> NB. must be in same order as AlignType enum <<<<
00150 const INT32 HAlignIDS[]={_R(IDS_HALIGNNONE),
00151                         _R(IDS_HALIGNLEFT),
00152                         _R(IDS_HALIGNCENTRE),
00153                         _R(IDS_HALIGNRIGHT),
00154                         _R(IDS_HDISTRIBUTELEFT),
00155                         _R(IDS_HDISTRIBUTECENTRE),
00156                         _R(IDS_HDISTRIBUTERIGHT),
00157                         _R(IDS_HDISTRIBUTEEQUI),
00158                         0};
00159 const INT32 VAlignIDS[]={_R(IDS_VALIGNNONE),
00160                         _R(IDS_VALIGNBOTTOM),
00161                         _R(IDS_VALIGNCENTRE),
00162                         _R(IDS_VALIGNTOP),
00163                         _R(IDS_VDISTRIBUTEBOTTOM),
00164                         _R(IDS_VDISTRIBUTECENTRE),
00165                         _R(IDS_VDISTRIBUTETOP),
00166                         _R(IDS_VDISTRIBUTEEQUI),
00167                         0};
00168 
00169 // constants defining the size and position of the rectangles on the align dialog
00170 const INT32 DiagWidth =100;
00171 const INT32 DiagHeight=100;
00172 const INT32  DiagRectWidth[DiagRects]={6,14,22,30};
00173 const INT32 DiagRectHeight[DiagRects]={6,30,14,22};
00174 const INT32 DiagRectOrderX[DiagRects]={1,3,0,2};
00175 const INT32 DiagRectOrderY[DiagRects]={0,2,1,3};
00176 const INT32 DiagRectGapX[DiagRects-1]={13,6,8};
00177 const INT32 DiagRectGapY[DiagRects-1]={13,6,8};
00178 LineData   ArrangeAlignment::DiagRectX[8][DiagRects];
00179 LineData   ArrangeAlignment::DiagRectY[8][DiagRects];
00180 
00181 // initial state of dialog
00182 AlignParam ArrangeAlignment::Align={AlignNone,AlignNone,ToSelection};
00183               
00184 /******************************************************************************
00185 >   ArrangeAlignment::ArrangeAlignment() :
00186         DialogOp(ArrangeAlignment::IDD, ArrangeAlignment::Mode) 
00187 
00188     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00189     Created:    29/9/94
00190     Purpose:    ArrangeAlignment constructor
00191 ******************************************************************************/
00192 
00193 ArrangeAlignment::ArrangeAlignment():
00194     DialogOp(ArrangeAlignment::IDD, ArrangeAlignment::Mode) 
00195 {
00196 }              
00197 
00198 /******************************************************************************
00199 >   BOOL ArrangeAlignment::Init()
00200 
00201     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00202     Created:    29/9/94
00203     Returns:    FALSE if it fails (due to lack of memory)
00204     Purpose:    Creates an OpDescriptor for a ArrangeAlignment dialog
00205 ******************************************************************************/
00206 
00207 BOOL ArrangeAlignment::Init()
00208 {
00209     // init array holding coords of diagram rects on dialog in all alignments
00210     ArrangeAlignment::CalcDiagramRectsOneAxis(ArrangeAlignment::DiagRectX,DiagRectWidth,
00211         DiagRectOrderX,DiagRectGapX,DiagWidth-1);
00212     ArrangeAlignment::CalcDiagramRectsOneAxis(ArrangeAlignment::DiagRectY,DiagRectHeight,
00213         DiagRectOrderY,DiagRectGapY,DiagHeight-1);
00214 
00215     return RegisterOpDescriptor(
00216         0,                                  // Tool ID
00217         _R(IDS_ARRANGE_ALIGNMENT),          // String resource ID
00218         CC_RUNTIME_CLASS(ArrangeAlignment), // Runtime class
00219         OPTOKEN_ALIGNDLG,                   // Token string
00220         ArrangeAlignment::GetState,         // GetState function
00221         0,                                  // Help ID
00222         _R(IDBBL_ALIGNEMENT),                   // Bubble ID
00223         _R(IDD_BARCONTROLSTORE),                // Resource ID
00224         _R(IDC_ALIGNEMENT),                     // Control ID
00225         SYSTEMBAR_EDIT,                     // Bar ID
00226         TRUE,                               // Recieve system messages
00227         FALSE,                              // Smart duplicate operation
00228         TRUE,                               // Clean operation
00229         0,                                  // No vertical counterpart
00230         _R(IDS_ARRANGEALIGNMENT_ONE),           // String for one copy only
00231         (DONT_GREY_WHEN_SELECT_INSIDE | GREY_WHEN_NO_CURRENT_DOC) // Auto state flags
00232     );
00233 }   
00234 
00235 /******************************************************************************
00236 >   void    ArrangeAlignment::CalcDiagramRectsOneAxis(
00237                 LineData    x[8][DiagRects],
00238                 const INT32 width[DiagRects],
00239                 const INT32 order[DiagRects],
00240                 const INT32 gap[DiagRects-1]
00241             )
00242 
00243     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00244     Created:    18/10/94
00245     Purpose:    calculate the x positions of the diagram rectangles
00246                 Written as for x but applys equally to y with different params!
00247 ******************************************************************************/
00248 
00249 void ArrangeAlignment::CalcDiagramRectsOneAxis(
00250     LineData x[8][DiagRects],
00251     const INT32 width[DiagRects], 
00252     const INT32 order[DiagRects],
00253     const INT32 gap[DiagRects-1],
00254     const INT32 DiagWidth
00255 )
00256 {
00257     INT32   i;
00258     INT32  sum=0;
00259     for (i=0; i<DiagRects; i++)
00260         sum+=width[i];
00261     float first=(float)width[order[0]];
00262     float last =(float)width[order[DiagRects-1]];
00263     float PosnLeft=(float)0;
00264     float PosnCntr=first/2;
00265     float PosnRght=first;
00266     float PosnEqui=(float)0;
00267     float GapLeft =((float)DiagWidth-last)/3;
00268     float GapCntr =((float)DiagWidth-first/2-last/2)/3;
00269     float GapRght =((float)DiagWidth-first)/3;
00270     float GapEqui =(float)(DiagWidth-sum)/3;
00271     for (i=0; i<DiagRects; i++)
00272     {
00273         INT32 j=order[i];
00274         x[AlignNone       ][j].lo = i ? x[AlignNone][order[i-1]].hi+gap[i-1] : 0;
00275         x[AlignLow        ][j].lo = 0;
00276         x[AlignCentre     ][j].lo =(DiagWidth-width[j])/2;
00277         x[AlignHigh       ][j].lo = DiagWidth-width[j];
00278         x[DistributeLow   ][j].lo = (INT32)PosnLeft;
00279         x[DistributeCentre][j].lo = (INT32)(PosnCntr-width[j]/2);
00280         x[DistributeHigh  ][j].lo = (INT32)(PosnRght-width[j]);
00281         x[DistributeEqui  ][j].lo = (INT32)PosnEqui;
00282 
00283         PosnLeft+=GapLeft;
00284         PosnCntr+=GapCntr;
00285         PosnRght+=GapRght;
00286         PosnEqui+=GapEqui+width[j];
00287 
00288         INT32 w=width[j];
00289         x[AlignNone       ][j].hi = x[AlignNone       ][j].lo + w;
00290         x[AlignLow        ][j].hi = x[AlignLow        ][j].lo + w;
00291         x[AlignCentre     ][j].hi = x[AlignCentre     ][j].lo + w;
00292         x[AlignHigh       ][j].hi = x[AlignHigh       ][j].lo + w;
00293         x[DistributeLow   ][j].hi = x[DistributeLow   ][j].lo + w;
00294         x[DistributeCentre][j].hi = x[DistributeCentre][j].lo + w;
00295         x[DistributeHigh  ][j].hi = x[DistributeHigh  ][j].lo + w;
00296         x[DistributeEqui  ][j].hi = x[DistributeEqui  ][j].lo + w;
00297     }
00298 }
00299 
00300 /******************************************************************************
00301 >   OpState ArrangeAlignment::GetState(String_256* pHelpString, OpDescriptor*)
00302 
00303     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00304     Created:    29/9/94
00305     Purpose:    Returns the OpState of the ArrangeAlignment dialogue operation
00306                 ie. whether or not it is greyed on the menu etc!!!
00307 ******************************************************************************/
00308 
00309 OpState ArrangeAlignment::GetState(String_256* pHelpString, OpDescriptor*)
00310 {
00311     static OpState DialogState;
00312     DialogState.Greyed=FALSE;
00313 //  DialogState.Greyed=GetApplication()->FindSelection()->Count()==0;
00314 //  if (DialogState.Greyed)
00315 //      pHelpString->MakeMsg(_R(IDS_ARRANGEALIGNMENT_GREY));
00316     return DialogState;
00317 }
00318 
00319 /******************************************************************************
00320 >   void ArrangeAlignment::Do(OpDescriptor*)
00321 
00322     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00323     Created:    29/9/94 
00324     Purpose:    Creates and shows a ArrangeAlignment dialog
00325 ******************************************************************************/
00326 
00327 void ArrangeAlignment::Do(OpDescriptor*)
00328 {
00329     Create();
00330     Open();
00331 }
00332 
00333 /******************************************************************************
00334 >   MsgResult ArrangeAlignment::Message(Msg* Message)
00335 
00336     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00337     Created:    29/9/94
00338     Purpose:    Handles all the ArrangeAlignment dialog's messages 
00339 ******************************************************************************/
00340 
00341 MsgResult ArrangeAlignment::Message(Msg* Message)
00342 {
00343     if (IS_OUR_DIALOG_MSG(Message))
00344     {
00345         DialogMsg* Msg=(DialogMsg*)Message;
00346 
00347         switch (Msg->DlgMsg)
00348         {
00349             case DIM_CREATE:                // dialog created - restore its previous state
00350                 BuildIDSDropList(_R(IDC_ALIGNDIALOG_HORIZONTAL), HAlignIDS, Align.h);
00351                 BuildIDSDropList(_R(IDC_ALIGNDIALOG_VERTICAL),   VAlignIDS, Align.v);
00352                 SetRadioGroup(TargetArea, TargetArea[Align.target]);
00353                 UpdateState();
00354                 break;
00355 
00356             case DIM_LFT_BN_CLICKED:        // mouse clicks may change greyed state of buttons
00357             case DIM_SELECTION_CHANGED:     // mouse clicks may change greyed state of buttons
00358                 UpdateState();
00359                 break;
00360 
00361             case DIM_LFT_BN_DOWN:           // Handle clicks in the diagram control
00362                 if (Msg->GadgetID == _R(IDC_ALIGNDIALOG_DIAGRAM))
00363                     DiagramClicked((ReDrawInfoType*) Msg->DlgMsgParam);
00364                 break;
00365 
00366             case DIM_REDRAW:                // handle redraw request for diagram gadget
00367                 if (Msg->GadgetID == _R(IDC_ALIGNDIALOG_DIAGRAM))
00368                     RedrawDiagram((ReDrawInfoType*)Msg->DlgMsgParam);
00369                 break;
00370 
00371             case DIM_COMMIT:                // handle left hand OK click
00372                 DialogOKed();
00373                 break;
00374 
00375             case DIM_CANCEL:                // handle cancel
00376                 // Close();
00377                 // End(); // Do not call Close() and End(). The base class does this.
00378                 break;
00379 
00380             default:
00381                 break;
00382         }
00383     }
00384     else if (MESSAGE_IS_A(Message, SelChangingMsg))
00385     {
00386         // if selection has changed, update state of dialog
00387         if ( ((SelChangingMsg*)Message)->State == SelChangingMsg::SELECTIONCHANGED )
00388             UpdateState();
00389     }
00390 
00391     // Pass all unhandled messages to base class for default processing!
00392     return DialogOp::Message(Message);  
00393 }  
00394 
00395 /******************************************************************************
00396 >   void ArrangeAlignment::DiagramClicked(ReDrawInfoType *Info)
00397 
00398     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00399     Created:    2/3/96
00400     Purpose:    Handles clicks on the diagram on the align dialog
00401                 There are 3 zones in each of the X, Y axes. An unmodified
00402                 click will adjust both axes. Holding down ctrl will constrain
00403                 the X axis to none while holding down shift will constrain
00404                 the Y axis to none. (Ctrl+shift = reset both axes)
00405 ******************************************************************************/
00406 void ArrangeAlignment::DiagramClicked(ReDrawInfoType *Info)
00407 {
00408     // We'll default to resetting any axis not changed below
00409     Align.h = Align.v = AlignNone;
00410 
00411     // We only do Y direction if constrain (ctrl) is depressed
00412     if (!KeyPress::IsConstrainPressed())
00413     {
00414         if (Info->pMousePos->x < Info->dx/3)            // Bottom row
00415             Align.h = AlignLow;
00416         else if (Info->pMousePos->x < (2 * Info->dx)/3) // Middle row
00417             Align.h = AlignCentre;
00418         else                                            // Top row
00419             Align.h = AlignHigh;
00420     }
00421 
00422     // We only do X direction if adjust (shift) is depressed
00423     if (!KeyPress::IsAdjustPressed())
00424     {
00425         if (Info->pMousePos->y < Info->dy/3)            // Left column
00426             Align.v = AlignLow;
00427         else if (Info->pMousePos->y < (2 * Info->dy)/3) // Middle column
00428             Align.v = AlignCentre;
00429         else                                            // Right column
00430             Align.v = AlignHigh;
00431     }
00432 
00433     // Update the drop-down lists
00434     SetSelectedValueIndex(_R(IDC_ALIGNDIALOG_HORIZONTAL), Align.h);
00435     SetSelectedValueIndex(_R(IDC_ALIGNDIALOG_VERTICAL),   Align.v);
00436     UpdateState();
00437 }
00438 
00439 
00440 
00441 /******************************************************************************
00442 >   void ArrangeAlignment::RedrawDiagram(ReDrawInfoType* ExtraInfo)
00443 
00444     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00445     Created:    17/10/94
00446     Purpose:    Redraws the diagram on the align dialog
00447     Note:       Code to render objects with grad-fills commented out
00448                 As it is allegedly too slow (but this decision will probably be reversed)
00449 ******************************************************************************/
00450 
00451 void ArrangeAlignment::RedrawDiagram(ReDrawInfoType* ExtraInfo)
00452 {
00453     // objects drawn in the render region must be relatively large in the given coord space
00454     // else Gavin's curve flattening results in visible straight lines
00455     // so every dimension is scaled by scale
00456     INT32 scale=1000;
00457 
00458     // make a render region
00459     DocRect VirtRendRect;
00460     VirtRendRect.lo.x=-1*scale;
00461     VirtRendRect.lo.y=-2*scale;
00462     VirtRendRect.hi.x=(DiagWidth +1)*scale;
00463     VirtRendRect.hi.y=(DiagHeight+2)*scale;
00464     RenderRegion* pRender=CreateGRenderRegion(&VirtRendRect,ExtraInfo);
00465 
00466     if (pRender!=NULL)
00467     {
00468         pRender->SaveContext();
00469 
00470         // currently this must be set here before any colour tables calculated
00471         Quality             AntiAliasQuality(Quality::QualityMax);
00472         QualityAttribute    AntiAliasQualityAttr(AntiAliasQuality);
00473         pRender->SetQuality(&AntiAliasQualityAttr,FALSE);
00474 
00475         // Render the background rectangle
00476         DialogColourInfo RedrawColours;
00477         pRender->SetLineColour(RedrawColours.DialogBack());
00478         pRender->SetFillColour(RedrawColours.DialogBack());
00479         pRender->DrawRect(&VirtRendRect);
00480 
00481         // declared at this scope else RestoreContext() dies!
00482         RadialFillAttribute Fill;       
00483 
00484         // set up some defaults used by all objects
00485         Fill.MakeElliptical();
00486         Fill.Colour=DocColour(255,255,255);
00487         pRender->SetLineColour(BLACK);
00488         pRender->SetLineWidth(0);
00489 
00490         for (INT32 i=0; i<DiagRects; i++)
00491         {
00492             // reverse order in which objets are rendered (now filled!)
00493             INT32 j=DiagRects-1-i;
00494 
00495             // set fill colour of each object
00496             switch (j)
00497             {
00498                 case  0: Fill.EndColour=DocColour(255,255,0); break;
00499                 case  1: Fill.EndColour=DocColour(0,0,255);   break;
00500                 case  2: Fill.EndColour=DocColour(255,0,0);   break;
00501                 case  3: Fill.EndColour=DocColour(0,160,0);   break;
00502                 default: Fill.EndColour=DocColour(0,0,0);     break;
00503             }
00504 
00505             // get bound rect of object to be drawn
00506             INT32 x=DiagRectX[Align.h][j].lo*scale;
00507             INT32 w=DiagRectX[Align.h][j].hi*scale-x;
00508             INT32 y=DiagRectY[Align.v][j].lo*scale;
00509             INT32 h=DiagRectY[Align.v][j].hi*scale-y;
00510 
00511             // create shape and fill geometries
00512             Path shape;
00513             shape.Initialise(16,8);
00514             shape.IsFilled=TRUE;
00515             shape.FindStartOfPath();
00516             switch (j)
00517             {
00518                 case 0:
00519                 {
00520                     // create a rectangle
00521                     shape.InsertMoveTo(DocCoord(x,y));
00522                     shape.InsertLineTo(DocCoord(x,y+h));
00523                     shape.InsertLineTo(DocCoord(x+w,y+h));
00524                     shape.InsertLineTo(DocCoord(x+w,y));
00525                     shape.InsertLineTo(DocCoord(x,y));
00526 
00527 //                  // create a radial fill
00528 //                  Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4);
00529 //                  Fill.EndPoint  =DocCoord(x+w*3/8,y+h/2);
00530 //                  Fill.EndPoint2 =DocCoord(x+w*3/8,y+h);
00531                     break;
00532                 }
00533 
00534                 case 1:
00535                 {
00536                     // create a pseudo ellipse
00537                     shape.InsertMoveTo( DocCoord(x,y+h/2));
00538                     shape.InsertCurveTo(DocCoord(x,y+h*3/4),  DocCoord(x+w/4,y+h),  DocCoord(x+w/2,y+h));
00539                     shape.InsertCurveTo(DocCoord(x+w*3/4,y+h),DocCoord(x+w,y+h*3/4),DocCoord(x+w,y+h/2));
00540                     shape.InsertCurveTo(DocCoord(x+w,y+h/4),  DocCoord(x+w*3/4,y),  DocCoord(x+w/2,y));
00541                     shape.InsertCurveTo(DocCoord(x+w/4,y),    DocCoord(x,y+h/4),    DocCoord(x,y+h/2));
00542 
00543 //                  // create a radial fill
00544 //                  Fill.StartPoint=DocCoord(x+w*3/8,y+h*5/8);
00545 //                  Fill.EndPoint  =DocCoord(x+w*6/8,y+h/4);
00546 //                  Fill.EndPoint2 =DocCoord(x+w*6/8,y+h);
00547                     break;
00548                 }
00549 
00550                 default:
00551                 {
00552                     // create a rounded rectangle
00553                     shape.InsertMoveTo( DocCoord(x,y+h/2));
00554                     shape.InsertCurveTo(DocCoord(x,y+h),  DocCoord(x,y+h),  DocCoord(x+w/2,y+h));
00555                     shape.InsertCurveTo(DocCoord(x+w,y+h),DocCoord(x+w,y+h),DocCoord(x+w,y+h/2));
00556                     shape.InsertCurveTo(DocCoord(x+w,y),  DocCoord(x+w,y),  DocCoord(x+w/2,y));
00557                     shape.InsertCurveTo(DocCoord(x,y),    DocCoord(x,y),    DocCoord(x,y+h/2));
00558 
00559 //                  // create a radial fill
00560 //                  Fill.StartPoint=DocCoord(x+w*3/16,y+h*3/4);
00561 //                  Fill.EndPoint  =DocCoord(x+w*3/8,y+h/2);
00562 //                  Fill.EndPoint2 =DocCoord(x+w*3/8,y+h);
00563                     break;
00564                 }
00565 
00566             }
00567 //          pRender->SetFillGeometry(&Fill,FALSE);
00568             pRender->SetFillColour(Fill.EndColour);
00569             pRender->DrawPath(&shape);
00570         }
00571 
00572         pRender->RestoreContext();
00573         DestroyGRenderRegion(pRender);  // also blt's to screen
00574     }
00575 }
00576 
00577 /******************************************************************************
00578 >   void ArrangeAlignment::UpdateState(void)
00579 
00580     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00581     Created:    29/9/94
00582     Purpose:    Updates the HState, VState, and Alignments vars in the class
00583                 Also updates the grey state of all the dialog gadgets
00584 ******************************************************************************/
00585 
00586 void ArrangeAlignment::UpdateState()
00587 {
00588     // update target
00589     CGadgetID Target = ReadRadioGroup(TargetArea,TargetArea[0]);
00590     if (Target == _R(IDC_ALIGNDIALOG_TOSELECTION))
00591     {
00592         Align.target=ToSelection;
00593     }
00594     else if (Target == _R(IDC_ALIGNDIALOG_TOPAGE))
00595     {
00596         Align.target=ToPage;
00597     }
00598     //  WEBSTER-ranbirr-13/11/96
00599     #ifndef WEBSTER
00600     else if (Target == _R(IDC_ALIGNDIALOG_TOSPREAD))
00601     {
00602         Align.target=ToSpread;
00603     }
00604     #endif //webster
00605     else
00606     {
00607         ERROR3("ArrangeAlignment::UpdateState() - unknown target");
00608     }
00609 
00610     // read alignments from horizontal and vertical combo boxes
00611     Align.h = (AlignType)GetSelectedValueIndex(_R(IDC_ALIGNDIALOG_HORIZONTAL));
00612     Align.v = (AlignType)GetSelectedValueIndex(_R(IDC_ALIGNDIALOG_VERTICAL));
00613     
00614     // force the diagram to redraw
00615     InvalidateGadget(_R(IDC_ALIGNDIALOG_DIAGRAM));
00616 
00617     // set state of Apply button
00618     INT32 NumObjs = 0;
00619     if (Document::GetSelected())
00620         NumObjs = GetApplication()->FindSelection()->Count();
00621     BOOL ApplyButtonState = (NumObjs>0);
00622     if (NumObjs==1 && Target==_R(IDC_ALIGNDIALOG_TOSELECTION)) ApplyButtonState = FALSE;
00623     if (Align.h==AlignNone && Align.v==AlignNone)          ApplyButtonState = FALSE;
00624     EnableGadget(_R(IDOK),ApplyButtonState);
00625 }
00626 
00627 
00628 /******************************************************************************
00629 >   void ArrangeAlignment::DialogOKed(void)
00630 
00631     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00632     Created:    30/9/94
00633     Purpose:    invokes the Op
00634 ******************************************************************************/
00635 
00636 void ArrangeAlignment::DialogOKed()
00637 {
00638     if (Align.h!=AlignNone || Align.v!=AlignNone)
00639     {
00640         OpDescriptor* pOpDesc=OpDescriptor::FindOpDescriptor(OPTOKEN_OPALIGN);
00641         ERROR3IF_PF(pOpDesc==NULL,("Couldn't find OPTOKEN_OPALIGN op descriptor"));
00642         pOpDesc->Invoke((OpParam*)&Align);
00643     }
00644 }
00645 
00646 /******************************************************************************
00647 >   void        ArrangeAlignment::BuildIDSDropList(
00648                     const CGadgetID DropListID,
00649                     const INT32*        IDSList,
00650                     const INT32         Default=0
00651                 )
00652 
00653     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00654     Created:    7th November 1994
00655     Purpose:    Builds a drop down list for a combo box from a null terminated 
00656                 list of string IDs, selecting a default value
00657     Errors:     IF LIST NOT NULL TERMINATED => same prob as non-term strings!
00658 ******************************************************************************/
00659 
00660 void ArrangeAlignment::BuildIDSDropList(const CGadgetID DropListID,
00661         const INT32* IDSList, INT32 Default)
00662 {
00663     // Make sure the list is empty
00664     DeleteAllValues(DropListID);
00665 
00666     // build the list
00667     String_32 Str;
00668     INT32 i=0;
00669     while (IDSList[i])
00670     {
00671         Str.MakeMsg(IDSList[i]);
00672         SetStringGadgetValue( DropListID, Str );
00673         i++;
00674     }
00675     SetComboListLength(DropListID);
00676 
00677     // select one of the entries in the list
00678     if (Default<0 || Default>=i)
00679     {
00680         ERROR3("BuildIDSDropList() passed a default outside the list");
00681         Default=0;
00682     }
00683     SetSelectedValueIndex(DropListID,Default);
00684 }
00685 
00686 /******************************************************************************
00687 >   CGadgetID   ArrangeAlignment::ReadRadioGroup(
00688                     const CGadgetID* IDCList,
00689                     const CGadgetID IDCDefault=NULL
00690                 )
00691 
00692     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00693     Created:    13th October 1994
00694     Purpose:    Returns ID of the first set radio button in a group specified
00695                 in a null terminated list (irespective of greyed state)
00696                 If none are selected it returns the default ID (default NULL)
00697     Errors:     IF LIST NOT NULL TERMINATED => same prob as non-term strings!
00698 ******************************************************************************/
00699 
00700 CGadgetID ArrangeAlignment::ReadRadioGroup(const CGadgetID* IDCList,
00701                                            const CGadgetID IDCDefault)
00702 {
00703     BOOL valid;
00704     INT32  i=0;
00705     while (IDCList[i])
00706     {
00707         if (GetLongGadgetValue(IDCList[i],0,1,0,&valid))
00708             return (IDCList[i]);
00709         i++;
00710     }
00711     return (IDCDefault);
00712 }
00713 
00714 /******************************************************************************
00715 >   void    ArrangeAlignment::SetRadioGroup(
00716                 const CGadgetID* IDCList,
00717                 const CGadgetID IDC
00718             )
00719 
00720     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00721     Created:    13th October 1994
00722     Purpose:    Sets the specified radio button in a group specified in a null 
00723                 terminated list (irespective of whether or not it is greyed)
00724                 resetting all others in the group.
00725                 If IDC is not in list, none are set.
00726     Errors:     IF LIST NOT NULL TERMINATED => same prob as non-term strings!
00727 ******************************************************************************/
00728 
00729 void ArrangeAlignment::SetRadioGroup(const CGadgetID* IDCList, const CGadgetID IDC)
00730 {
00731     INT32 i=0;
00732     while (IDCList[i])
00733     {
00734         SetLongGadgetValue(IDCList[i],IDCList[i]==IDC);
00735         i++;
00736     }
00737 }
00738 
00740 
00741 /******************************************************************************
00742 >   OpAlign::OpAlign() : TransOperation()
00743 
00744     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00745     Created:    29/9/94
00746     Purpose:    OpAlign constructor
00747 ******************************************************************************/
00748 
00749 OpAlign::OpAlign() : TransOperation() 
00750 {
00751 }       
00752 
00753 /******************************************************************************
00754 >   BOOL OpAlign::Init()
00755 
00756     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00757     Created:    30/9/94
00758     Returns:    FALSE if it fails (due to lack of memory)
00759     Purpose:    Creates an OpDescriptor for an Align operation
00760 ******************************************************************************/
00761 
00762 BOOL OpAlign::Init()
00763 {  
00764     return RegisterOpDescriptor(
00765         0,                          // Tool ID
00766         _R(IDS_OPALIGN),                // String resource ID
00767         CC_RUNTIME_CLASS(OpAlign),  // Runtime class
00768         OPTOKEN_OPALIGN,            // Token string
00769         OpAlign::GetState,          // GetState function
00770         0,                          // Help ID
00771         0,                          // Bubble ID
00772         0,                          // Resource ID
00773         0                           // Control ID
00774 //  needs   'GREY_WHEN_NO_CURRENT_DOC'
00775     );
00776 }   
00777 
00778 /******************************************************************************
00779 >   OpState OpAlign::GetState(String_256* pString, OpDescriptor* pOpDesc)
00780 
00781     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00782     Created:    29/9/94
00783     Purpose:    Returns the OpState of the OpAlign dialogue operation
00784 ******************************************************************************/
00785 
00786 OpState OpAlign::GetState(String_256* pString, OpDescriptor* pOpDesc)
00787 {
00788     return ArrangeAlignment::GetState(pString, pOpDesc);
00789 }
00790 
00791 /******************************************************************************
00792 >   void OpAlign::DoWithParam(OpDescriptor* pOp, OpParam* pAlignParam)
00793 
00794     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00795     Created:    29/9/94 
00796     Purpose:    performs the desired align operation
00797 ******************************************************************************/
00798 
00799 void OpAlign::DoWithParam(OpDescriptor* pOp, OpParam* pAlignParam)
00800 {
00801     // DMc alterations so that this works with compound nodes   
00802     SelRange   Selection(*(GetApplication()->FindSelection()));
00803 
00804     RangeControl rg = Selection.GetRangeControlFlags();
00805     rg.PromoteToParent = TRUE;
00806     Selection.Range::SetRangeControl(rg);
00807 
00808     DocRect     SelRect   = Selection.GetBoundingRect();
00809     DocRect     TargetRect;
00810     TargetRect.MakeEmpty();
00811     INT32        NumObjs   = Selection.Count();
00812     AlignParam* pAlign    =(AlignParam*)pAlignParam;
00813 
00814     BOOL moved=FALSE;                   // set to TRUE if any object is moved
00815     BeginSlowJob(-1,FALSE);
00816     BOOL OK=DoStartTransOp(FALSE);
00817 
00818     // find parent spread of first object in selection
00819     Node*   pFirstNode=NULL;
00820     Spread* pSpread   =NULL;
00821     if (OK)
00822     {
00823         pFirstNode=Selection.FindFirst();
00824         if (pFirstNode!=NULL)
00825             pSpread=pFirstNode->FindParentSpread();
00826         OK=(pSpread!=NULL);
00827         if (!OK)
00828             ERROR2RAW("OpAlign::DoWithParam() - could not find parent spread");
00829     }
00830 
00831     // Find the size of the target rectangle
00832     if (pAlign->target==ToSelection)
00833         TargetRect=SelRect;
00834     else
00835     {
00836         Page* pPage=pSpread->FindFirstPageInSpread();
00837         while (pPage)
00838         {
00839             DocRect PageRect=pPage->GetPageRect();
00840             if (pAlign->target==ToSpread || SelRect.IsIntersectedWith(PageRect))
00841                 TargetRect=TargetRect.Union(PageRect);
00842             pPage=pPage->FindNextPage();
00843         }
00844     }
00845 
00846     // allocate all dynamic memory required
00847     Node**   pObj=NULL;
00848     ObjInfo* x   =NULL;
00849     ObjInfo* y   =NULL;
00850     INT32*    dx  =NULL;
00851     INT32*    dy  =NULL;
00852     if (OK)         ALLOC_WITH_FAIL(pObj,(Node**)  CCMalloc(NumObjs*sizeof(Node*)),  this);
00853     if (pObj!=NULL) ALLOC_WITH_FAIL(x,   (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this);
00854     if (   x!=NULL) ALLOC_WITH_FAIL(y,   (ObjInfo*)CCMalloc(NumObjs*sizeof(ObjInfo)),this);
00855     if (   y!=NULL) ALLOC_WITH_FAIL(dx,  (INT32*)   CCMalloc(NumObjs*sizeof(INT32)),   this);
00856     if (  dx!=NULL) ALLOC_WITH_FAIL(dy,  (INT32*)   CCMalloc(NumObjs*sizeof(INT32)),   this);
00857     OK=(dy!=NULL);
00858 
00859     // if memory claimed OK and target rect not empty proceed with op
00860     // (ie. do nothing if 'within page(s)' when no object on a page)
00861     DocRect EmptyRect;
00862     if (OK && TargetRect!=EmptyRect)
00863     {
00864         // create an array of pointers to objects (nodes) to be affected
00865         Node* pNode=Selection.FindFirst();
00866         INT32  i=0;
00867         while (pNode!=NULL)
00868         {
00869             if (pNode->IsBounded() && !((NodeRenderableBounded*)pNode)->GetBoundingRect(TRUE).IsEmpty())
00870                 pObj[i++]=pNode;
00871             pNode=Selection.FindNext(pNode);
00872         }
00873         NumObjs=i;
00874 
00875         // cache x & y info in separate arrays so they can be sorted separately
00876         XLONG SumObjWidths =0;
00877         XLONG SumObjHeights=0;
00878         for (i=0; i<NumObjs; i++)
00879         {
00880             DocRect ObjRect=((NodeRenderableBounded*)pObj[i])->GetBoundingRect();
00881             x[i].i=i;
00882             x[i].lo=ObjRect.lo.x;
00883             x[i].hi=ObjRect.hi.x;
00884             SumObjWidths+=ObjRect.hi.x-ObjRect.lo.x;
00885             y[i].i=i;
00886             y[i].lo=ObjRect.lo.y;
00887             y[i].hi=ObjRect.hi.y;
00888             SumObjHeights+=ObjRect.hi.y-ObjRect.lo.y;
00889         }
00890 
00891         // for each object, calculate the x and y displacements independently
00892         AlignOneAxis(pAlign->h,NumObjs,SumObjWidths, TargetRect.lo.x,TargetRect.hi.x,x,dx);
00893         AlignOneAxis(pAlign->v,NumObjs,SumObjHeights,TargetRect.lo.y,TargetRect.hi.y,y,dy);
00894 
00895         // apply the x and y displacements simultaneously to each object
00896         for (i=0; i<NumObjs; i++)
00897             if (dx[i]!=0 || dy[i]!=0)
00898             {
00899                 moved=TRUE;
00900                 Trans2DMatrix* pMatrix=new Trans2DMatrix(dx[i],dy[i]);
00901                 DoTransformNode((NodeRenderableInk*)pObj[i],pMatrix);
00902             }
00903     }
00904 
00905     // free up any memory which was allocated
00906     CCFree(dx);
00907     CCFree(dy);
00908     CCFree(x);
00909     CCFree(y);
00910     CCFree(pObj);
00911 
00912     if (moved)
00913     {
00914         Document::GetSelected()->ForceRedraw(pSpread, TargetRect);
00915         GetApplication()->UpdateSelection();
00916     }
00917     else
00918         FailAndExecute();
00919     End();
00920     EndSlowJob();
00921 }
00922 
00923 /******************************************************************************
00924  following routines used by the 'C' library qsort() in OpAlign::AlignOneAxis()
00925 ******************************************************************************/
00926 extern "C" INT32 CompareObjInfoLow(const void* elem1, const void* elem2)
00927 {
00928     ObjInfo* a=(ObjInfo*)elem1;
00929     ObjInfo* b=(ObjInfo*)elem2;
00930     if (a->lo == b->lo)
00931         return (a->i  < b->i  ? -1 : 1);    // sort by Z order
00932     else
00933         return (a->lo < b->lo ? -1 : 1);
00934 }
00935 /*****************************************************************************/
00936 extern "C" INT32 CompareObjInfoHigh(const void* elem1, const void* elem2)
00937 {
00938     ObjInfo* a=(ObjInfo*)elem1;
00939     ObjInfo* b=(ObjInfo*)elem2;
00940     if (a->hi == b->hi)
00941         return (a->i  < b->i  ? -1 : 1);    // sort by Z order
00942     else
00943         return (a->hi < b->hi ? -1 : 1);
00944 }
00945 /*****************************************************************************/
00946 extern "C" INT32 CompareObjInfoCentre(const void* elem1, const void* elem2)
00947 {
00948     ObjInfo* a=(ObjInfo*)elem1;
00949     ObjInfo* b=(ObjInfo*)elem2;
00950     INT32     d=(a->lo+a->hi)-(b->lo+b->hi);
00951     if (d==0)
00952         return (a->i < b->i ? -1 : 1);      // sort by Z order
00953     else
00954         return (   d < 0    ? -1 : 1);
00955 }
00956 
00957 /******************************************************************************
00958 >   void OpAlign::AlignOneAxis(
00959         AlignType Align,
00960         INT32     NumObjs,
00961         XLONG     SumObjWidths,
00962         INT32     RectLow,
00963         INT32     RectHigh,
00964         ObjInfo*  x,            // returned sorted (ascending) if distributing
00965         INT32*    dx            // returns displacements for each object
00966     )
00967 
00968     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00969     Created:    29/9/94 
00970     Purpose:    aligns the object in one axis at a time, in the specified way
00971                 (written as though for x, but same algorithm applies to y)
00972                 distributing a single object leaves it unchanged.
00973 ******************************************************************************/
00974 
00975 void OpAlign::AlignOneAxis(AlignType Align, INT32 NumObjs, XLONG SumObjWidths,
00976                            INT32 RectLow, INT32 RectHigh, ObjInfo* x, INT32* dx)
00977 {
00978     INT32 i;
00979 
00980     switch (Align)
00981     {
00982         case DistributeLow:
00983             if (NumObjs==1)
00984                 dx[0]=0;
00985             else
00986             {
00987                 qsort(x,NumObjs,sizeof(ObjInfo),CompareObjInfoLow);
00988                 INT32 RectWidth=RectHigh-RectLow;
00989                 INT32 LastObjWidth =x[NumObjs-1].hi-x[NumObjs-1].lo;
00990                 INT32 gap=(RectWidth-LastObjWidth)/(NumObjs-1);
00991                 INT32 pos=RectLow;
00992                 for (i=0; i<NumObjs; i++)
00993                 {                                                                                                 
00994                     dx[x[i].i]=pos-x[i].lo;
00995                     pos+=gap;
00996                 }
00997             }
00998             break;
00999 
01000         case DistributeHigh:
01001             if (NumObjs==1)
01002                 dx[0]=0;
01003             else
01004             {
01005                 qsort(x,NumObjs,sizeof(ObjInfo),CompareObjInfoHigh);
01006                 INT32 RectWidth=RectHigh-RectLow;
01007                 INT32 FirstObjWidth=x[0].hi-x[0].lo;
01008                 INT32 gap=(RectWidth-FirstObjWidth)/(NumObjs-1);
01009                 INT32 pos=RectLow+FirstObjWidth;
01010                 for (i=0; i<NumObjs; i++)
01011                 {
01012                     dx[x[i].i]=pos-x[i].hi;
01013                     pos+=gap;
01014                 }
01015             }
01016             break;
01017 
01018         case DistributeCentre:
01019             if (NumObjs==1)
01020                 dx[0]=0;
01021             else
01022             {
01023                 qsort(x,NumObjs,sizeof(ObjInfo),CompareObjInfoCentre);
01024                 INT32 RectWidth=RectHigh-RectLow;
01025                 INT32 LastObjWidth =x[NumObjs-1].hi-x[NumObjs-1].lo;
01026                 INT32 FirstObjWidth=x[0].hi-x[0].lo;
01027                 INT32 gap=(RectWidth-(FirstObjWidth+LastObjWidth)/2)/(NumObjs-1);
01028                 INT32 pos=RectLow+FirstObjWidth/2;
01029                 for (i=0; i<NumObjs; i++)
01030                 {
01031                     dx[x[i].i]=pos-(x[i].hi+x[i].lo)/2;
01032                     pos+=gap;
01033                 }
01034             }
01035             break;
01036 
01037         case DistributeEqui:
01038             if (NumObjs==1)
01039                 dx[0]=0;
01040             else
01041             {
01042                 qsort(x,NumObjs,sizeof(ObjInfo),CompareObjInfoCentre);
01043                 INT32 RectWidth=RectHigh-RectLow;
01044                 INT32 gap=((XLONG)RectWidth-SumObjWidths)/(NumObjs-1);
01045                 INT32 pos=RectLow;
01046                 for (i=0; i<NumObjs; i++)
01047                 {
01048                     dx[x[i].i]=pos-x[i].lo;
01049                     pos+=gap+x[i].hi-x[i].lo;
01050                 }
01051             }
01052             break;
01053          
01054         case AlignLow:
01055             for (i=0; i<NumObjs; i++)
01056                 dx[i]=RectLow-x[i].lo;
01057             break;
01058 
01059         case AlignCentre:
01060             for (i=0; i<NumObjs; i++)
01061                 dx[i]=(RectHigh-x[i].hi+RectLow-x[i].lo)/2;
01062             break;
01063 
01064         case AlignHigh:
01065             for (i=0; i<NumObjs; i++)
01066                 dx[i]=RectHigh-x[i].hi;
01067             break;
01068 
01069         case AlignNone:
01070             for (i=0; i<NumObjs; i++)
01071                 dx[i]=0;
01072             break;
01073     }
01074 }

Generated on Sat Nov 10 03:44:09 2007 for Camelot by  doxygen 1.4.4