textinfo.cpp

Go to the documentation of this file.
00001 // $Id: textinfo.cpp 1718 2006-08-25 11:06:06Z martin $
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 // Implementation of the text tool infobar
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "textinfo.h"   
00105 
00106 // Resource files
00107 //#include "richard.h"
00108 //#include "richard2.h"
00109 //#include "richard3.h"
00110 //#include "simon.h"
00111 //#include "textres.h"
00112 
00113 // Code headers
00114 #include "nodetxts.h"
00115 #include "nodetxtl.h"
00116 #include "texttool.h"
00117 //#include "prefs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "txtattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "textops.h"
00123 #include "optsmsgs.h"
00124 #include "nodetext.h"
00125 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00126 #include "finfodlg.h"
00127 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00129 //#include "fonts.h"
00130 //#include "atminfo.h"
00131 #include "fontman.h"
00132 #include "fontdrop.h"
00133 #include "fontbase.h"
00134 //#include "sgfonts.h"
00135 #include "localenv.h"
00136 #include "unicdman.h"
00137 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00138 //#include "camvw.h"
00139 #include "blobs.h"
00140 #include "rulers.h"
00141 #include "usercord.h"
00142 #include "dlgmgr.h"
00143 #include "statline.h"
00144 
00145 // For tab stop dragging
00146 #include "csrstack.h"
00147 
00148 DECLARE_SOURCE( "$Revision: 1718 $" );
00149 
00150 CC_IMPLEMENT_DYNCREATE(TextInfoBarOp,InformationBarOp)
00151 CC_IMPLEMENT_DYNCREATE(TextInfoBarData,CCObject)
00152 CC_IMPLEMENT_DYNCREATE(TextInfoBarEnumFont, OILEnumFonts )
00153 CC_IMPLEMENT_DYNCREATE(TextRulerBarData, CCObject)
00154 CC_IMPLEMENT_DYNCREATE(TabStopDragOp, Operation)
00155 
00156 #define TABSTOPDRAG_CURSORID_UNSET -1
00157 
00158 // Must come after the last CC_IMPLEMENT.. macro
00159 #define new CAM_DEBUG_NEW     
00160 
00161 // consts ...
00162 const INT32 KernNudge      = 10;        // ems/1000
00163 const INT32 KernLimit      = 999999;    // ems/1000    +/-
00164 const INT32 BaseLineNudge  = 200;       // millipoints
00165 const INT32 BaseLineLimit  = 999999;    // millipoints +/-
00166 const INT32 TrackingNudge  = 10;        // ems/1000
00167 const INT32 TrackingLimit  = 9999;  // ems/1000    +/-
00168 const INT32 LineSpaceNudge = 200;       // millipoints
00169 const INT32 LineSpaceLimit = 999999;    // millipoints +/-
00170 const INT32 LineSpacePercentNudge = 5; // percent
00171 const INT32 LineSpacePercentMin = -99999;   // percent
00172 const INT32 LineSpacePercentMax = 99999;// percent
00173 const INT32 FontSizeMin    = 100;       // millipoints
00174 const INT32 FontSizeMax    = 999999;    // millipoints
00175 const INT32 FontAspectMin  = 1;     // percent
00176 const INT32 FontAspectMax  = 9999;  // percent
00177 
00178 const INT32 CurrentTabButtonPos = -36;    // in pixels measured from the origin
00179 
00180 #define INVALID_ATTVAL -1000000
00181 // statics ...
00182 double TextInfoBarOp::SuperScriptSize;
00183 double TextInfoBarOp::SuperScriptOffset;
00184 double TextInfoBarOp::SubScriptSize;
00185 double TextInfoBarOp::SubScriptOffset;
00186 
00187 // the current text infobar allow static access
00188 InformationBarOp* TextInfoBarOp::pTextInfoBar     = NULL;
00189 BOOL              TextInfoBarOp::DisplayFontIsInstalled  = FALSE;
00190 BOOL              TextInfoBarOp::RegainCaretAfterOp = FALSE;
00191 
00192 UnitType          TextInfoBarOp::CurrentFontUnits = COMP_POINTS;
00193 TextInfoBarData   TextInfoBarOp::InfoData;
00194 TextRulerBarData  TextInfoBarOp::RulerData;
00195 Document*         TextInfoBarOp::pDoc             = NULL;
00196 CommonAttrSet     TextInfoBarOp::CommonAttrsToFindSet;  // A set which will contain all attribute types
00197                                                         // that we need to find common attributes for
00198 // cached bitmap sizes
00199 UINT32 TextInfoBarOp::TabBitmapWidth;
00200 UINT32 TextInfoBarOp::TabBitmapHeight;
00201 UINT32 TextInfoBarOp::CurrentTabButtonWidth;
00202 UINT32 TextInfoBarOp::LeftMarginBitmapWidth;
00203 UINT32 TextInfoBarOp::LeftMarginBitmapHeight;
00204 UINT32 TextInfoBarOp::RightMarginBitmapWidth;
00205 
00206 FontDropDown    *TextInfoBarOp::NameDropDown = NULL;    // Font name drop-down list support for the font list and
00207 
00208 String_64   TextInfoBarData::FontName;
00209 FontClass   TextInfoBarData::FontType;
00210 JustifyMode TextInfoBarData::Justify;
00211 BOOL        TextInfoBarData::Bold;
00212 BOOL        TextInfoBarData::Italic;
00213 BOOL        TextInfoBarData::UnderLine;
00214 ScriptModes TextInfoBarData::CurrentScriptMode;
00215 FIXED16     TextInfoBarData::AspectRatio;
00216 MILLIPOINT  TextInfoBarData::FontSize; // in 1/72000
00217 MILLIPOINT  TextInfoBarData::BaseLineShift;
00218 MILLIPOINT  TextInfoBarData::LineSpace;
00219 double      TextInfoBarData::LineSpacePercent;
00220 BOOL        TextInfoBarData::IsLineSpaceAPercent;
00221 INT32       TextInfoBarData::HorizontalKern;
00222 INT32       TextInfoBarData::Tracking;
00223 BOOL        TextInfoBarData::AutoKerning;
00224 
00225 
00226 /********************************************************************************************
00227 
00228 >   TextInfoBarData::TextInfoBarData() 
00229 
00230     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00231     Created:    13/02/95
00232     Inputs:     -
00233     Outputs:    -
00234     Returns:    -
00235     Purpose:    Constructor
00236 
00237 ********************************************************************************************/
00238                    
00239 
00240 TextInfoBarData::TextInfoBarData()
00241 {
00242     FontType = FC_UNDEFINED;
00243     Bold = FALSE;
00244     Italic = FALSE;
00245     UnderLine = FALSE;
00246     CurrentScriptMode = NormalScript;
00247     AspectRatio = 1;
00248     FontSize = 16000;
00249     BaseLineShift = 0;
00250     HorizontalKern = 0;
00251     Tracking = 0;
00252     LineSpace = 0;
00253     IsLineSpaceAPercent = TRUE;
00254     LineSpacePercent = 100;
00255     Justify = JustifyLeft;
00256     AutoKerning = TRUE;
00257 }
00258 
00259 /********************************************************************************************
00260 
00261 >   BOOL TextInfoBarOp::IsDisplayFontInstalled() 
00262 
00263     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00264     Created:    19/05/95                
00265     Inputs:     -
00266     Outputs:    -
00267     Returns:    TRUE if the font has been installed
00268     Purpose:    Determine whether our display fonts are installed
00269 
00270 ********************************************************************************************/
00271 
00272 BOOL TextInfoBarOp::IsDisplayFontInstalled()
00273 {
00274 PORTNOTE("text", "Removed IsDisplayFontInstalled");
00275 #ifndef EXCLUDE_FROM_XARALX
00276     // if we are running on a DBCS OS then we don't use our display font at all.
00277     if (UnicodeManager::IsDBCSOS())
00278         return TRUE;
00279 
00280     // get a DC
00281     CDC *pDesktopDC = CWnd::GetDesktopWindow()->GetDC();
00282     
00283     // Alex added ...
00284     if (!pDesktopDC) return FALSE; // Apparently we don't need to set an error
00285 
00286     // create one of the fonts we use
00287     CFont * TestFont = FontFactory::GetCFont(STOCKFONT_DIALOGBARSMALL);
00288     // if it's null, run on and we'll select a NULL font.
00289 
00290     // select it into the DC
00291     CFont * pOldFont = pDesktopDC->SelectObject(TestFont);
00292     
00293     // get the type face name
00294     TCHAR buff[64];
00295     pDesktopDC->GetTextFace(64,buff);
00296 
00297     // Select old font back into screen DC
00298     pDesktopDC->SelectObject(pOldFont);
00299     
00300     // Alex added Free the DC (better do it the way Chris got it :-) )
00301     CWnd::GetDesktopWindow()->ReleaseDC(pDesktopDC);
00302 
00303     // is it one of ours ?
00304     String_32 CCSmall(_R(IDS_FONTS_EDITFIELDSMALL)); // "CCSMALL"
00305     return camStrncmp(buff, (TCHAR *)CCSmall, 64)==0;
00306 #else
00307     return FALSE;
00308 #endif
00309 }
00310 
00311 
00312 /********************************************************************************************
00313 
00314 >   INT32 TextInfoBarOp::BuildFontList() 
00315 
00316     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00317     Created:    12/09/95                
00318     Inputs:     -
00319     Outputs:    -
00320     Returns:    the number of fonts placed in the list
00321     Purpose:    Build a simple list of fonts. This function uses the call back API facility
00322                 EnumFontFamilies to build a list of TrueType fonts
00323 
00324 ********************************************************************************************/
00325 
00326 INT32 TextInfoBarOp::BuildFontList()
00327 {
00328     TextInfoBarEnumFont EnumObj;
00329     EnumObj.Execute();
00330 
00331     return EnumObj.GetCount();
00332 }
00333 
00334 BOOL TextInfoBarEnumFont::NewFont(FontClass, ENUMLOGFONT *lpelf)
00335 {
00336     return TRUE;
00337 }
00338 
00339 
00340 /********************************************************************************************
00341 
00342 >   TextInfoBarOp::~TextInfoBarOp()
00343 
00344     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00345     Created:    5/3/94
00346     Inputs:     -
00347     Outputs:    -
00348     Returns:    -
00349     Purpose:    destructor - deletes the font cache
00350     Errors:     -
00351     SeeAlso:    
00352 
00353 ********************************************************************************************/
00354 
00355 TextInfoBarOp::~TextInfoBarOp()
00356 {
00357     // DeleteFontCache();
00358     pTextInfoBar= NULL;
00359 
00360     // Delete our drop-down font list
00361     if (NameDropDown != NULL)
00362     {
00363         delete NameDropDown;
00364         NameDropDown = NULL;
00365     }
00366 }
00367 
00368 
00369 /********************************************************************************************
00370 
00371 >   TextInfoBarOp::TextInfoBarOp() 
00372 
00373     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00374     Created:    13/02/95
00375     Inputs:     -
00376     Outputs:    -
00377     Returns:    -
00378     Purpose:    Initialises the infobar
00379 
00380 ********************************************************************************************/
00381 
00382 TextInfoBarOp::TextInfoBarOp()
00383 {
00384     DlgResID = _R(IDD_TEXT_INFO_BAR);
00385 
00386     SuperScriptSize   = Text_SuperScriptSize;
00387     SuperScriptOffset = Text_SuperScriptOffset;
00388     SubScriptSize     = Text_SubScriptSize;
00389     SubScriptOffset   = Text_SubScriptOffset;
00390     /*if (Camelot.DeclareSection("ScriptValues", 6))
00391     {
00392         Camelot.DeclarePref(NULL, "SuperScriptSize",   &SuperScriptSize);
00393         Camelot.DeclarePref(NULL, "SuperScriptOffset", &SuperScriptOffset);
00394         Camelot.DeclarePref(NULL, "SubScriptSize",     &SubScriptSize);
00395         Camelot.DeclarePref(NULL, "SubScriptOffset",   &SubScriptOffset,-100,100);
00396     }
00397     */
00398     pTextTool = NULL;
00399     // InitFontCache();
00400     pDoc = Document::GetSelected();
00401     if(pDoc)
00402         CurrentFontUnits = pDoc->GetDocFontUnits(); 
00403 
00404     // NameDropDown = NULL;
00405 }
00406 
00407 /********************************************************************************************
00408 
00409 >   static BOOL TextInfoBarOp::Init()
00410 
00411     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00412     Created:    20/9/95
00413     Returns:    FALSE if we run out of memory
00414     Purpose:    Initialises the TextInfoBarOp's static data. 
00415 
00416 ********************************************************************************************/
00417 
00418 BOOL TextInfoBarOp::Init()
00419 {
00420     // Initialise the CommonAttrsToFindSet 
00421     BOOL ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtJustification));
00422     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtBold));
00423     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtItalic));
00424     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtFontSize));
00425     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtFontTypeface));
00426     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtAspectRatio));
00427     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtTracking));
00428     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtLineSpace));
00429     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtBaseLine));
00430     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtScript));
00431     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtRuler));
00432     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtLeftMargin));
00433     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtRightMargin));
00434     if (ok) ok = CommonAttrsToFindSet.AddTypeToSet(CC_RUNTIME_CLASS(AttrTxtFirstIndent));
00435     if (ok) ok = TabStopDragOp::Init();
00436 
00437     // find out about the sizes of the various tab ruler bitmaps (rather than hard-coding
00438     // the sizes into the mouse click detection code in OnRulerClick())
00439     // first, the size of the "current tab type" button - we ask for the left tab variant,
00440     // but they should all be the same size
00441     UINT32 Dummy;
00442     if (ok) ok = FindBitmapSize(_R(clefttab), &CurrentTabButtonWidth, &Dummy);
00443     // find out about the size of tab stop blobs - we ask for the left tab variant, but they
00444     // should all be the same size
00445     if (ok) ok = FindBitmapSize(_R(lefttab), &TabBitmapWidth, &TabBitmapHeight);
00446     // find out about the width and height of the first indent blob
00447     if (ok) ok = FindBitmapSize(_R(leftmar), &LeftMarginBitmapWidth, &LeftMarginBitmapHeight);
00448     // find out about the width of the left/right margin blobs
00449     if (ok) ok = FindBitmapSize(_R(rightmar), &RightMarginBitmapWidth, &Dummy); 
00450     return ok;
00451 }
00452 
00453 /********************************************************************************************
00454 
00455 >   static BOOL TextInfoBarOp::FindBitmapSize(ResourceID ID, UINT32* pWidth, UINT32* pHeight)
00456 
00457     Author:     Martin Wuerthner <xara@mw-software.com>
00458     Created:    14/07/06
00459     Returns:    FALSE if failed
00460     Purpose:    Find the width and height of a resource bitmap
00461 
00462 ********************************************************************************************/
00463 
00464 BOOL TextInfoBarOp::FindBitmapSize(ResourceID ID, UINT32* pWidth, UINT32* pHeight)
00465 {
00466     BOOL ok = FALSE;
00467     OILBitmap* pOilBitmap = OILBitmap::Create();
00468     if (pOilBitmap) ok = pOilBitmap->LoadBitmap(ID);
00469     if (ok)
00470     {
00471         // create a kernel bitmap based on our OilBitmap
00472         KernelBitmap KBitmap(pOilBitmap);
00473         if (KBitmap.IsOK())
00474         {
00475             *pWidth = KBitmap.GetWidth();
00476             *pHeight = KBitmap.GetHeight();
00477             ok = TRUE;
00478         }
00479     }
00480     return ok;
00481 }
00482 
00483 /********************************************************************************************
00484 
00485 >   static void TextInfoBarOp::DeInit()
00486 
00487     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00488     Created:    20/9/95
00489     Purpose:    DeInits the TextInfoBarOp's static data. 
00490 
00491 ********************************************************************************************/
00492 
00493 void TextInfoBarOp::DeInit()
00494 {
00495     CommonAttrsToFindSet.DeleteAll();
00496 } 
00497 
00498 
00499 
00500 /********************************************************************************************
00501 
00502 >void TextInfoBarOp::OnFieldChange()
00503 
00504     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00505     Created:    13/2/95
00506     Inputs:     ThisChange - Enum Value for the Attribute that has changed
00507     Outputs:    -
00508     Returns:    -
00509     Purpose:    Called whenever the user changes a field on the infobar
00510                 Applies atrributes to the current selection
00511 
00512                 Note: This function also applies autokerning to a story which is not
00513                 an attribute
00514     Errors:     Out Of Memory errors if we can't create new attributes
00515     SeeAlso:    -
00516 
00517 ********************************************************************************************/
00518 
00519 void TextInfoBarOp::OnFieldChange(FontAttribute ThisChange)
00520 {
00521     NodeAttribute * Attrib = NULL;
00522     
00523     switch (ThisChange)
00524     {               
00525         case LeftMarginA:
00526         {
00527             if(RulerData.IsLeftMarginValid)
00528             {
00529                 AttrTxtLeftMargin  * LeftMarginAttrib = new AttrTxtLeftMargin();
00530                 if (LeftMarginAttrib == NULL)
00531                 {
00532                     InformError();
00533                     return;
00534                 }
00535                 LeftMarginAttrib->Value.Value = RulerData.LeftMargin;
00536                 Attrib = LeftMarginAttrib;
00537             }
00538             break;
00539         }
00540         case RightMarginA:
00541         {
00542             if(RulerData.IsRightMarginValid)
00543             {
00544                 AttrTxtRightMargin  * RightMarginAttrib = new AttrTxtRightMargin();
00545                 if (RightMarginAttrib == NULL)
00546                 {
00547                     InformError();
00548                     return;
00549                 }
00550                 RightMarginAttrib->Value.Value = RulerData.RightMargin;
00551                 Attrib = RightMarginAttrib;
00552             }
00553             break;
00554         }
00555         case FirstIndentA:
00556         {
00557             if(RulerData.IsFirstIndentValid)
00558             {
00559                 AttrTxtFirstIndent  * FirstIndentAttrib = new AttrTxtFirstIndent();
00560                 if (FirstIndentAttrib == NULL)
00561                 {
00562                     InformError();
00563                     return;
00564                 }
00565                 FirstIndentAttrib->Value.Value = RulerData.FirstIndent;
00566                 Attrib = FirstIndentAttrib;
00567             }
00568             break;
00569         }
00570         case RulerA:
00571         {
00572             Attrib = RulerData.pNewRuler;
00573             break;
00574         }
00575         case BaseLineShiftA:
00576         {
00577             if(InfoData.BaseLineShift != INVALID_ATTVAL)
00578             {
00579                 AttrTxtBaseLine  * BaseLineAttrib = new AttrTxtBaseLine();
00580                 if (BaseLineAttrib == NULL)
00581                 {
00582                     InformError();
00583                     return;
00584                 }
00585                 MILLIPOINT  RealBaseLine = InfoData.BaseLineShift;
00586                 BaseLineAttrib->Value.Value = RealBaseLine;
00587                 Attrib = BaseLineAttrib;    
00588             }
00589             break;
00590         }
00591         case LineSpacePercentA:
00592         {
00593             if(InfoData.LineSpacePercent != INVALID_ATTVAL)
00594             {
00595                 FIXED16 NewRatio =   InfoData.LineSpacePercent/100;
00596                 AttrTxtLineSpace  * LineSpaceAttrib = new AttrTxtLineSpace(NewRatio);
00597                 if (LineSpaceAttrib == NULL)
00598                 {
00599                     InformError();
00600                     return;
00601                 }
00602                 Attrib = LineSpaceAttrib;   
00603             }   
00604             break;
00605         }
00606         case LineSpaceA:
00607         {
00608             if(InfoData.LineSpace != INVALID_ATTVAL)
00609             {
00610                 MILLIPOINT  RealLineSpace = InfoData.LineSpace;
00611                 AttrTxtLineSpace  * LineSpaceAttrib = new AttrTxtLineSpace(RealLineSpace);
00612                 if (LineSpaceAttrib == NULL)
00613                 {
00614                     InformError();
00615                     return;
00616                 }
00617                 Attrib = LineSpaceAttrib;   
00618             }
00619             break;
00620         }
00621         case ScriptA:
00622         {
00623             AttrTxtScript  * ScriptAttrib = new AttrTxtScript();
00624             if (ScriptAttrib == NULL)
00625             {
00626                 InformError();
00627                 return;
00628             }
00629 
00630             // normal
00631             ScriptAttrib->Value.Offset = 0;
00632             ScriptAttrib->Value.Size = 1;
00633 
00634             if(InfoData.CurrentScriptMode== SubScript)
00635             {
00636                 ScriptAttrib->Value.Offset = FIXED16(SubScriptOffset);
00637                 ScriptAttrib->Value.Size =   FIXED16(SubScriptSize);
00638             }
00639             else if(InfoData.CurrentScriptMode == SuperScript)
00640             {
00641                 ScriptAttrib->Value.Offset = FIXED16(SuperScriptOffset);
00642                 ScriptAttrib->Value.Size =   FIXED16(SuperScriptSize);
00643             }
00644 
00645             Attrib = ScriptAttrib;  
00646             
00647             break;
00648         }
00649         case JustifyA:
00650         {
00651             AttrTxtJustification  * JustifyAttrib = new AttrTxtJustification();
00652             if (JustifyAttrib == NULL)
00653             {
00654                 InformError();
00655                 return;
00656             }
00657             JustifyAttrib->Value.justification = (Justification) InfoData.Justify;
00658             Attrib = JustifyAttrib; 
00659             break;
00660         }
00661         case BoldA:
00662         {
00663             AttrTxtBold  * BoldAttrib = new AttrTxtBold();
00664             if (BoldAttrib == NULL)
00665             {
00666                 InformError();
00667                 return;
00668             }
00669             BoldAttrib->Value.BoldOn = InfoData.Bold;
00670             Attrib = BoldAttrib;
00671             break;
00672         }
00673         case ItalicA:
00674         {
00675             AttrTxtItalic  * ItalicAttrib = new AttrTxtItalic();
00676             if (ItalicAttrib == NULL)
00677             {
00678                 InformError();
00679                 return;
00680             }
00681             ItalicAttrib->Value.ItalicOn = InfoData.Italic;
00682             Attrib = ItalicAttrib;
00683             break;
00684         }
00685         case UnderLineA:
00686         {
00687             AttrTxtUnderline  * UnderLineAttrib = new AttrTxtUnderline();
00688             if (UnderLineAttrib == NULL)
00689             {
00690                 InformError();
00691                 return;
00692             }
00693             UnderLineAttrib->Value.Underlined = InfoData.UnderLine;
00694             Attrib = UnderLineAttrib;   
00695             break;
00696         }
00697         case AspectRatioA:
00698         {   
00699             if(InfoData.AspectRatio != FIXED16(INVALID_ATTVAL))
00700             {
00701                 AttrTxtAspectRatio  * AspectAttrib = new AttrTxtAspectRatio();
00702                 if (AspectAttrib == NULL)
00703                 {
00704                     InformError();
00705                     return;
00706                 }
00707                 FIXED16  RealAspect = InfoData.AspectRatio;
00708                 AspectAttrib->Value.AspectRatio = RealAspect;
00709                 Attrib = AspectAttrib;  
00710             }
00711             break;
00712         }
00713         case FontSizeA:
00714         {
00715             if(InfoData.FontSize != INVALID_ATTVAL)
00716             {
00717                 AttrTxtFontSize * FontSizeAttrib = new AttrTxtFontSize();
00718                 if (FontSizeAttrib == NULL)
00719                 {
00720                     InformError();
00721                     return;
00722                 }
00723                 MILLIPOINT  RealSize = InfoData.FontSize;
00724                 FontSizeAttrib->Value.FontSize = RealSize;
00725                 Attrib = FontSizeAttrib;
00726             }
00727             break;
00728         }
00729         case FontNameA:
00730         {
00731                         
00732             AttrTxtFontTypeface * TypeFaceAttrib = new AttrTxtFontTypeface();   
00733             if (TypeFaceAttrib == NULL)
00734             {
00735                 InformError();
00736                 return;
00737             }
00738             
00739             TypeFaceAttrib->Value.HTypeface = FONTMANAGER->GetFontHandle(&InfoData.FontName, InfoData.FontType);
00740             Attrib = TypeFaceAttrib;
00741             break;
00742         }
00743         case TrackingA:
00744         {
00745             if(InfoData.Tracking != INVALID_ATTVAL)
00746             {
00747                 AttrTxtTracking * TrackingAttrib = new AttrTxtTracking();
00748                 if (TrackingAttrib == NULL)
00749                 {
00750                     InformError();
00751                     return;
00752                 }TrackingAttrib->Value.Tracking = InfoData.Tracking;
00753                 Attrib = TrackingAttrib;
00754             }
00755             break;  
00756         }
00757         default:
00758             break;
00759     }
00760     
00761     if (Attrib)
00762     {
00763         TRACEUSER("wuerthne", _T("calling AttributeSelected"));
00764         AttributeManager::AttributeSelected(Attrib,NULL);
00765         TRACEUSER("wuerthne", _T("called AttributeSelected"));
00766     }
00767     // make sure the infobar reflects the current attributes
00768     switch (ThisChange)
00769     {
00770         case HorizontalKernA:
00771         {
00772             // Invoke an operation to apply the kern
00773             OpDescriptor* OpDesc =
00774                 OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpTextKern));
00775 
00776             if (OpDesc != NULL)
00777             {
00778                 OpParam param(InfoData.HorizontalKern,0);
00779                 OpDesc->Invoke(&param);
00780             }
00781             break;
00782         }
00783         case AutoKernText:
00784         {
00785             // Invoke an operation to apply the kern
00786             OpDescriptor* OpDesc =
00787                 OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpTextAutoKern));
00788 
00789             if (OpDesc != NULL)
00790             {
00791                 OpParam param(InfoData.AutoKerning,0);
00792                 OpDesc->Invoke(&param);
00793             }
00794             break;
00795         }
00796         default:
00797             break;
00798     }
00799 
00800     Update();
00801 }
00802 
00803 
00804 
00805 
00806 
00807 /********************************************************************************************
00808 
00809 >void TextInfoBarOp::UpdateGadgets()
00810 
00811     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00812     Created:    13/2/95
00813     Inputs:     -
00814     Outputs:    -
00815     Returns:    -
00816     Purpose:    Update all infobar fields according to the data in InfoData
00817     Errors:     -
00818     SeeAlso:    -
00819 
00820 ********************************************************************************************/
00821 
00822 void TextInfoBarOp::UpdateGadgets()
00823 {
00824 
00825     if(pTextInfoBar== NULL)
00826         return;
00827     if(!pTextInfoBar->HasWindow())
00828         return ;
00829 
00830     // Font Name
00831     NameDropDown->SetTopFontName(&InfoData.FontName, InfoData.FontType, FALSE);
00832     FontDropItem Dummy(InfoData.FontName, InfoData.FontType);
00833     NameDropDown->SetSelection(&Dummy);
00834 
00835     // Kerning
00836     pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1);
00837     if(Document::GetSelected()!= NULL)
00838         pTextInfoBar->SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1);
00839     else
00840     {
00841         String_64 ZeroPt(_R(IDS_TEXTINFO_0PT));
00842         pTextInfoBar->SetStringGadgetValue(_R(IDC_KERN_EDIT_Y),ZeroPt,0,-1);
00843     }
00844 
00845     SetLineSpaceGadget();
00846     // Tracking
00847     pTextInfoBar->SetLongGadgetValue(_R(IDC_TRACKING_EDIT),InfoData.Tracking);
00848  
00849     // Aspect Ratio
00850     pTextInfoBar->SetDoubleGadgetValue(_R(IDC_ASPECTEDIT),InfoData.AspectRatio.MakeDouble()*100); 
00851  
00852     // buttons
00853     UpdateButtonStates();
00854 
00855 }
00856 
00857 /********************************************************************************************
00858 
00859 >void TextInfoBarOp::Update()
00860 
00861     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
00862     Created:    13/2/95
00863     Inputs:     -
00864     Outputs:    -
00865     Returns:    -
00866     Purpose:    Update the infobar according to the current selection 
00867                 called on selchange messages 
00868                 only update fields as required
00869                 return if tool is not active
00870     Errors:     -
00871     SeeAlso:    -
00872 
00873 ********************************************************************************************/
00874 
00875 BOOL TextInfoBarOp::Update(BOOL DoUpdate)
00876 {
00877     
00878     static BOOL ForceUpdate = FALSE;
00879     static BOOL BoldChanged = FALSE;
00880     static BOOL ItalicChanged = FALSE;
00881     static BOOL ValidChanged = FALSE;
00882 
00883     BOOL IllegalHandle = FALSE;
00884     BOOL KernSet = FALSE;
00885     
00886     Document* pDoc = Document::GetCurrent();
00887     
00888     if (pDoc==NULL)
00889         return FALSE;
00890 
00891 
00892     Document *SelectedDoc = Document::GetSelected();
00893     TextStory *SelectedStory = TextStory::GetFocusStory(); // used for updating auto-kerning button
00894 
00895     if (SelectedDoc == NULL)
00896         return FALSE;
00897 
00898     if(pTextInfoBar== NULL)
00899         return FALSE;
00900     if(!pTextInfoBar->HasWindow())
00901         return FALSE;
00902 
00903 
00904     SelRange *Selection = Camelot.FindSelection();
00905     ENSURE(Selection != NULL, "No Selection SelRange!?!");
00906 
00907     // Find common attribute details for all attribute types we need to know about
00908     if (!Selection->FindCommonAttributes(&CommonAttrsToFindSet))
00909         return FALSE; 
00910 
00911     UpdateRulerBar(Selection, DoUpdate);
00912 
00913     SelRange::CommonAttribResult result;
00914     NodeAttribute* pAttr;
00915 
00916     // Justification  ---------------------------------------------------------------       
00917     AttrTxtJustification * JustifyAttrib;
00918     
00919     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtJustification), 
00920                                        &pAttr,
00921                                        &result);
00922     
00923     JustifyAttrib = (AttrTxtJustification*)pAttr; 
00924 
00925     if ( result != SelRange ::ATTR_MANY)
00926     {
00927         ERROR2IF(JustifyAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
00928         JustifyMode J =  (JustifyMode) JustifyAttrib->Value.justification ;
00929         if(InfoData.Justify != J||DoUpdate)
00930         {
00931             InfoData.Justify =  J;
00932             UpdateJustifyButtons();
00933         }
00934     }
00935     else
00936     {
00937           UpdateJustifyButtons(TRUE);
00938     }
00939 
00940     // BUTTONS 
00941     // Bold -------------------------------------------------------------------------
00942     AttrTxtBold * BoldAttrib;
00943     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtBold), 
00944                                        &pAttr,
00945                                        &result);
00946     
00947     BoldAttrib = (AttrTxtBold*)pAttr; 
00948 
00949     if (result == SelRange ::ATTR_MANY)
00950     {
00951         if(InfoData.Bold != FALSE)
00952         {
00953             InfoData.Bold = FALSE;
00954             pTextInfoBar->SetBoolGadgetSelected(_R(IDC_BOLDBUTTON),InfoData.Bold);
00955         }
00956     }
00957     else
00958     {
00959         ERROR2IF(BoldAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
00960         BOOL B = BoldAttrib->Value.BoldOn;
00961         if(InfoData.Bold!=B||DoUpdate)
00962         {
00963             InfoData.Bold = B;
00964             pTextInfoBar->SetBoolGadgetSelected(_R(IDC_BOLDBUTTON),InfoData.Bold);
00965         }
00966     }
00967     // AutoKerning -------------------------------------------------------------------------
00968     if (SelectedStory)
00969     {
00970         bool kerning = SelectedStory->IsAutoKerning();
00971         InfoData.AutoKerning = kerning;
00972         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_AUTOKERN),InfoData.AutoKerning);
00973     }
00974 
00975     // Italic ------------------------------------------------------------------------
00976     AttrTxtItalic * ItalicAttrib;
00977     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtItalic), 
00978                                        &pAttr,
00979                                        &result);
00980     
00981     ItalicAttrib = (AttrTxtItalic*)pAttr; 
00982 
00983     if (result == SelRange ::ATTR_MANY)
00984     {
00985         if(InfoData.Italic != FALSE)
00986         {
00987             InfoData.Italic = FALSE;
00988             pTextInfoBar->SetBoolGadgetSelected(_R(IDC_ITALICBUTTON),InfoData.Italic);
00989         }       
00990     }
00991     else
00992     {
00993         ERROR2IF(ItalicAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
00994         BOOL I =  ItalicAttrib->Value.ItalicOn;
00995         if(InfoData.Italic!=I||DoUpdate)
00996         {
00997             InfoData.Italic = ItalicAttrib->Value.ItalicOn;
00998             pTextInfoBar->SetBoolGadgetSelected(_R(IDC_ITALICBUTTON),InfoData.Italic);
00999         }
01000     }
01001 
01002     // Font Size ---------------------------------------------------------------------
01003     
01004     AttrTxtFontSize * FontSizeAttrib;
01005     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtFontSize), 
01006                                          &pAttr,
01007                                          &result);
01008     
01009     FontSizeAttrib = (AttrTxtFontSize*)pAttr; 
01010 
01011     if (result == SelRange ::ATTR_MANY)
01012     {
01013         InfoData.FontSize = INVALID_ATTVAL;
01014         String_64 empty(_T(""));
01015         pTextInfoBar->SetStringGadgetValue(_R(IDC_POINT_COMBO),empty,0,-1);
01016 
01017     }
01018     else 
01019     {
01020         ERROR2IF(FontSizeAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01021         MILLIPOINT DocFontSize = FontSizeAttrib->Value.FontSize;
01022         if(DocFontSize != InfoData.FontSize||DoUpdate )         
01023         {                                          
01024             InfoData.FontSize = DocFontSize;
01025             pTextInfoBar->SetUnitGadgetValue(_R(IDC_POINT_COMBO),CurrentFontUnits,InfoData.FontSize,0,-1);
01026         } 
01027     }
01028     
01029     // Font Name --------------------------------------------------------------------
01030     AttrTxtFontTypeface * FontTypeAttrib;
01031 
01032     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtFontTypeface), 
01033                                          &pAttr,
01034                                          &result);
01035     
01036     FontTypeAttrib = (AttrTxtFontTypeface*)pAttr; 
01037 
01038     if (result == SelRange ::ATTR_MANY)
01039     {
01040         String_64 Multiple(_R(IDS_TEXTTOOL_MULTIPLE));
01041         NameDropDown->SetTopFontName(&Multiple, FC_UNDEFINED, TRUE);
01042         ForceUpdate = TRUE;
01043         InfoData.FontName = _R(IDS_TEXTINFO_MULTIPLE); // "Multiple" just to invalidate this field
01044     }
01045     else 
01046     {
01047         ERROR2IF(FontTypeAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01048         //CachedFontItem* ThisData = FONTMANAGER->GetFont(FontTypeAttrib->Value.HTypeface,FALSE);
01049         CachedFontItem* ThisData = FONTMANAGER->GetCachedFont(FontTypeAttrib->Value.HTypeface);
01050         if (ThisData)
01051         {
01052             
01053             if( !ThisData->Compare(&InfoData.FontName)
01054                 ||ThisData->GetFontClass() != InfoData.FontType
01055                 ||ForceUpdate
01056                 ||DoUpdate
01057                 ||FontTypeAttrib->IsBold()!=BoldChanged
01058                 ||FontTypeAttrib->IsItalic()!=ItalicChanged
01059                 ||ThisData->IsValid()!=ValidChanged
01060                 )
01061             {
01062                 InfoData.FontType = ThisData->GetFontClass();
01063                 InfoData.FontName = *(ThisData->GetFontName());
01064                 String_256 FontName = InfoData.FontName;
01065 
01066                 // If this is set to TRUE, then the current selection in the font menu will be deselected.
01067                 // This makes it possible to override the text in the top icon with a asterisk, B or I...
01068                 BOOL Deselect = FALSE;
01069 
01070                 // indicate that the font isn't installed 
01071                 if(ThisData->IsReplaced())
01072                 {
01073                     Deselect = TRUE;
01074                     FontName += String_8(_R(IDS_TEXTINFO_STAR));  //" *"
01075                     ValidChanged = FALSE;
01076                 }
01077                 else
01078                     ValidChanged = TRUE;
01079 
01080                 // remember Bold\Italic states so we can force an update if they change
01081                 // modify the string accordingly
01082                 if(FontTypeAttrib->IsBold())
01083                 {
01084                     Deselect = TRUE;
01085                     FontName += String_8(_R(IDS_TEXTINFO_BOLD));  //" B";
01086                     BoldChanged = TRUE;
01087                 }
01088                 else
01089                     BoldChanged = FALSE;
01090                 
01091                 if(FontTypeAttrib->IsItalic())
01092                 {
01093                     Deselect = TRUE;
01094                     FontName += String_8(_R(IDS_TEXTINFO_ITALIC));  //" I";
01095                     ItalicChanged = TRUE;
01096                 }
01097                 else
01098                     ItalicChanged = FALSE;
01099 
01100                 NameDropDown->SetTopFontName(&FontName, InfoData.FontType, Deselect);
01101                 if(!Deselect)
01102                 {
01103                     FontDropItem Dummy(InfoData.FontName, InfoData.FontType);
01104                     NameDropDown->SetSelection(&Dummy);
01105                 }
01106 
01107                 ForceUpdate = !ThisData->IsValid();
01108             }
01109         }
01110         // couldn't find a font with that handle
01111         else 
01112             IllegalHandle = TRUE;
01113 
01114     }
01115 
01116     // AspectRatio  -----------------------------------------------------------------
01117     AttrTxtAspectRatio * AspectAttrib;
01118     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtAspectRatio), 
01119                                          &pAttr,
01120                                          &result);
01121     
01122     AspectAttrib = (AttrTxtAspectRatio*)pAttr; 
01123 
01124     if (result == SelRange ::ATTR_MANY)
01125     {
01126         InfoData.AspectRatio = INVALID_ATTVAL;
01127         String_64 empty(_T(""));
01128         pTextInfoBar->SetStringGadgetValue(_R(IDC_ASPECTEDIT),empty,0,-1);
01129     }
01130     else 
01131     {
01132         ERROR2IF(AspectAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01133         FIXED16 DocAspect = AspectAttrib->Value.AspectRatio;
01134         if(InfoData.AspectRatio != DocAspect||DoUpdate)
01135         {
01136             InfoData.AspectRatio = DocAspect;
01137             pTextInfoBar->SetDoubleGadgetValue(_R(IDC_ASPECTEDIT),InfoData.AspectRatio.MakeDouble()*100,0,-1); 
01138         }
01139     }
01140 
01141     // Tracking ---------------------------------------------------------------------
01142     AttrTxtTracking * TrackingAttrib;
01143 
01144     
01145     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtTracking), 
01146                                          &pAttr,
01147                                          &result);
01148     
01149     TrackingAttrib = (AttrTxtTracking*)pAttr; 
01150 
01151     if (result == SelRange ::ATTR_MANY)
01152     {
01153         InfoData.Tracking = INVALID_ATTVAL;
01154         String_64 empty(_T(""));
01155         pTextInfoBar->SetStringGadgetValue(_R(IDC_TRACKING_EDIT),empty,0,-1);
01156     }
01157     else 
01158     {
01159         ERROR2IF(TrackingAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01160         INT32 T = TrackingAttrib->Value.Tracking;
01161         if(InfoData.Tracking != T||DoUpdate)
01162         {
01163             InfoData.Tracking = T;
01164             pTextInfoBar->SetLongGadgetValue(_R(IDC_TRACKING_EDIT),InfoData.Tracking,0,-1);
01165             pTextInfoBar->PaintGadgetNow(_R(IDC_TRACKING_EDIT));
01166         }
01167     }
01168 
01169     // Line Spacing ---------------------------------------------------------------------
01170     AttrTxtLineSpace * LineSpaceAttrib;
01171         
01172     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtLineSpace), 
01173                                          &pAttr,
01174                                          &result);
01175     
01176     LineSpaceAttrib = (AttrTxtLineSpace*)pAttr; 
01177 
01178     if (result == SelRange ::ATTR_MANY)
01179     {
01180         String_64 empty(_T(""));
01181         pTextInfoBar->SetStringGadgetValue(_R(IDC_SPACING_EDIT),empty,0,-1);
01182         InfoData.LineSpacePercent = InfoData.LineSpace = INVALID_ATTVAL;
01183         
01184     }
01185     else 
01186     {
01187         ERROR2IF(LineSpaceAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01188 
01189         if(LineSpaceAttrib->IsARatio())
01190         {
01191             FIXED16 Ratio =  LineSpaceAttrib->Value.Ratio;
01192             double Percent = (Ratio + FIXED16_DBL(0.00003)).MakeDouble()*100;
01193             if(Percent != InfoData.LineSpacePercent||DoUpdate|| !InfoData.IsLineSpaceAPercent)
01194             {
01195                 SetCurrentLineSpacePercent(Percent);
01196                 SetLineSpaceGadget();
01197             }
01198         }
01199         else
01200         {
01201             MILLIPOINT DocLineSpace = LineSpaceAttrib->Value.Value;
01202             if(InfoData.LineSpace != DocLineSpace||DoUpdate||InfoData.IsLineSpaceAPercent)
01203             {
01204                 SetCurrentLineSpace(DocLineSpace);
01205                 pTextInfoBar->SetUnitGadgetValue(_R(IDC_SPACING_EDIT),CurrentFontUnits,InfoData.LineSpace,0,-1);
01206             }
01207         }
01208         pTextInfoBar->PaintGadgetNow(_R(IDC_SPACING_EDIT)); 
01209     }
01210     
01211     // Base Line Shift ---------------------------------------------------------------------
01212     AttrTxtBaseLine * BaseLineAttrib;
01213     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtBaseLine), 
01214                                          &pAttr,
01215                                          &result);
01216     
01217     BaseLineAttrib = (AttrTxtBaseLine*)pAttr; 
01218 
01219     if (result == SelRange ::ATTR_MANY)
01220     {
01221         InfoData.BaseLineShift = INVALID_ATTVAL;
01222         String_64 empty(_T(""));
01223         pTextInfoBar->SetStringGadgetValue(_R(IDC_KERN_EDIT_Y),empty,0,-1);
01224     }
01225     else 
01226     {
01227         ERROR2IF(BaseLineAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01228         MILLIPOINT DocBaseLine = BaseLineAttrib->Value.Value;
01229         if(InfoData.BaseLineShift != DocBaseLine||DoUpdate)
01230         {
01231             InfoData.BaseLineShift = DocBaseLine;
01232             pTextInfoBar->SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1);
01233             pTextInfoBar->PaintGadgetNow(_R(IDC_KERN_EDIT_Y));
01234         }
01235     }
01236     
01237     // Script ---------------------------------------------------------------------
01238     AttrTxtScript * ScriptAttrib;
01239     CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtScript), 
01240                                          &pAttr,
01241                                          &result);
01242     
01243     ScriptAttrib = (AttrTxtScript*)pAttr; 
01244 
01245 
01246     if (result == SelRange ::ATTR_MANY)
01247     {
01248         InfoData.CurrentScriptMode = NormalScript;
01249         UpdateScriptButtons();
01250     }
01251     else 
01252     {
01253         ERROR2IF(ScriptAttrib==NULL,FALSE,"FindCommonAttribute returned NULL");
01254         FIXED16 Offset = ScriptAttrib->Value.Offset;
01255         FIXED16 Size = ScriptAttrib->Value.Size;
01256         ScriptModes NewMode = NormalScript;
01257         if(Size == FIXED16(SuperScriptSize) 
01258            && Offset == FIXED16(SuperScriptOffset))
01259         {   
01260                 NewMode = SuperScript;
01261         }
01262         else if(Size == FIXED16(SubScriptSize) 
01263            && Offset == FIXED16(SubScriptOffset))
01264         {   
01265                 NewMode = SubScript;
01266         }
01267         if(InfoData.CurrentScriptMode!= NewMode||DoUpdate)
01268         {
01269             InfoData.CurrentScriptMode = NewMode;
01270             UpdateScriptButtons();
01271         }
01272     }
01273 
01274     // Horizontal Kerning update - check the node to the left of the caret
01275     TextStory * ActiveStory = TextStory::GetFocusStory();
01276     if(ActiveStory)
01277     {
01278         CaretNode * pCaret = ActiveStory->GetCaret();
01279         if(pCaret)
01280         {
01281             VisibleTextNode * LastNode = pCaret->FindPrevAbstractTextCharInStory();
01282             if(LastNode)
01283             {
01284                 if(IS_A(LastNode, KernCode))
01285                 {
01286                     KernCode * Kern = (KernCode *) LastNode;
01287                     DocCoord ThisKern = Kern->GetValue();
01288                     InfoData.HorizontalKern =ThisKern.x;
01289                     pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1);
01290                     pTextInfoBar->PaintGadgetNow(_R(IDC_KERN_EDIT_X)); 
01291                     KernSet = TRUE;
01292                 }
01293             }
01294         }
01295 
01296     }
01297     
01298     if(InfoData.HorizontalKern!=0 && ! KernSet)
01299     {
01300         InfoData.HorizontalKern =0;
01301         pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1); 
01302     }
01303     
01304     ERROR2IF(IllegalHandle==TRUE,FALSE,"Can't find a font for that handle");
01305 
01306     return TRUE;
01307 }
01308 
01309 
01310 /********************************************************************************************
01311 
01312 >void TextInfoBarOp::UpdateJustifyButtons()
01313 
01314     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01315     Created:    13/2/95
01316     Inputs:     -
01317     Outputs:    -
01318     Returns:    -
01319     Purpose:    updates the Justify Buttons
01320     Errors:     -
01321     SeeAlso:    -
01322 
01323 ********************************************************************************************/
01324 
01325 
01326 void TextInfoBarOp::UpdateJustifyButtons(BOOL Clear)
01327 {
01328     if(Clear)
01329     {
01330         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYLEFT),FALSE);
01331         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYCENTRE),FALSE);
01332         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYRIGHT),FALSE);
01333         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYFULL),FALSE);
01334     }
01335     else
01336     {
01337         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYLEFT),InfoData.Justify==JustifyLeft);
01338         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYCENTRE),InfoData.Justify==JustifyCentre);
01339         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYRIGHT),InfoData.Justify==JustifyRight);
01340         pTextInfoBar->SetBoolGadgetSelected(_R(IDC_JUSTIFYFULL),InfoData.Justify==JustifyFull);
01341     }
01342 }
01343 
01344 /********************************************************************************************
01345 
01346 >void TextInfoBarOp::UpdateScriptButtons()
01347 
01348     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01349     Created:    13/2/95
01350     Inputs:     -
01351     Outputs:    -
01352     Returns:    -
01353     Purpose:    updates the Super/SubScript Buttons
01354     Errors:     -
01355     SeeAlso:    -
01356 
01357 ********************************************************************************************/
01358 
01359 
01360 void TextInfoBarOp::UpdateScriptButtons()
01361 {
01362     pTextInfoBar->SetBoolGadgetSelected(_R(IDC_SUPERSCRIPT),InfoData.CurrentScriptMode==SuperScript);
01363     pTextInfoBar->SetBoolGadgetSelected(_R(IDC_SUBSCRIPT),InfoData.CurrentScriptMode==SubScript);
01364 }
01365 
01366 /********************************************************************************************
01367 
01368 >void TextInfoBarOp::UpdateButtonStates()
01369 
01370     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01371     Created:    13/2/95
01372     Inputs:     -
01373     Outputs:    -
01374     Returns:    -
01375     Purpose:    updates the info bar buttons and edit fields
01376     Errors:     -
01377     SeeAlso:    -
01378 
01379 ********************************************************************************************/
01380 
01381 
01382 void TextInfoBarOp::UpdateButtonStates()
01383 {
01384     pTextInfoBar->SetBoolGadgetSelected(_R(IDC_BOLDBUTTON),InfoData.Bold);
01385     pTextInfoBar->SetBoolGadgetSelected(_R(IDC_ITALICBUTTON),InfoData.Italic);
01386     UpdateJustifyButtons();
01387     UpdateScriptButtons();
01388 }
01389 
01390 /********************************************************************************************
01391 
01392 >void TextInfoBarOp::SetCurrentJustify(JustifyMode NewJustify)
01393 
01394     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01395     Created:    13/2/95
01396     Inputs:     -
01397     Outputs:    -
01398     Returns:    -
01399     Purpose:    Called to set the current justify state
01400     Errors:     -
01401     SeeAlso:    -
01402 
01403 ********************************************************************************************/
01404 
01405 void TextInfoBarOp::SetCurrentJustify(UINT32 Button)
01406 {
01407     if (Button == _R(IDC_JUSTIFYFULL))
01408     {
01409         InfoData.Justify = JustifyFull;
01410     }
01411     else if (Button == _R(IDC_JUSTIFYLEFT))
01412     {
01413         InfoData.Justify = JustifyLeft;
01414     }
01415     else if (Button == _R(IDC_JUSTIFYRIGHT))
01416     {
01417         InfoData.Justify = JustifyRight;
01418     }
01419     else if (Button == _R(IDC_JUSTIFYCENTRE))
01420     {
01421         InfoData.Justify = JustifyCentre;
01422     }
01423 
01424     UpdateJustifyButtons();
01425 }
01426 
01427 /********************************************************************************************
01428 
01429 >void TextInfoBarOp::SetCurrentScript(ScriptMode Script)
01430 
01431     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01432     Created:    13/2/95
01433     Inputs:     -
01434     Outputs:    -
01435     Returns:    -
01436     Purpose:    Called to set the current font ( i.e.the one in the edit field of the combo )
01437     Errors:     -
01438     SeeAlso:    -
01439 
01440 ********************************************************************************************/
01441 
01442 void TextInfoBarOp::SetCurrentScript(ScriptModes Script)
01443 {
01444     
01445     if(InfoData.CurrentScriptMode!=Script)
01446         InfoData.CurrentScriptMode = Script;
01447     else
01448         InfoData.CurrentScriptMode=NormalScript;
01449     
01450     UpdateScriptButtons();
01451 }
01452 
01453 
01454 
01455 /********************************************************************************************
01456 
01457 >BOOL TextInfoBarOp::SetCurrentPointSize(double  PointSize)
01458 
01459     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01460     Created:    13/2/95
01461     Inputs:     -
01462     Outputs:    -
01463     Returns:    FALSE if value unchanged TRUE otherwise
01464     Purpose:    Called to set the current PointSize
01465     Errors:     -
01466     SeeAlso:    -
01467 
01468 ********************************************************************************************/
01469 
01470 BOOL TextInfoBarOp::SetCurrentPointSize(MILLIPOINT PointSize)
01471 {
01472     if(InfoData.FontSize == PointSize)
01473         return FALSE;
01474     InfoData.FontSize = PointSize;
01475     return TRUE;
01476 }
01477 
01478 /********************************************************************************************
01479 
01480 >void TextInfoBarOp::SetCurrentFontBold(BOOL IsBold)
01481 
01482     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01483     Created:    13/2/95
01484     Inputs:     -
01485     Outputs:    -
01486     Returns:    -
01487     Purpose:    Called to set the current Bold State
01488     Errors:     -
01489     SeeAlso:    -
01490 
01491 ********************************************************************************************/
01492 void TextInfoBarOp::SetCurrentFontBold(BOOL IsBold)
01493 {
01494     InfoData.Bold = IsBold;
01495 }
01496 
01497 /********************************************************************************************
01498 
01499 >void TextInfoBarOp::SetCurrentFontItalic(BOOL IsItalic)
01500 
01501     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01502     Created:    13/2/95
01503     Inputs:     -
01504     Outputs:    -
01505     Returns:    -
01506     Purpose:    Called to set the current Italic State
01507     Errors:     -
01508     SeeAlso:    -
01509 
01510 ********************************************************************************************/
01511 
01512 void TextInfoBarOp::SetCurrentFontItalic(BOOL IsItalic)
01513 {
01514     InfoData.Italic = IsItalic;
01515 }
01516 
01517 /********************************************************************************************
01518 
01519 >void TextInfoBarOp::SetCurrentAutoKerning(BOOL IsAutoKerning)
01520 
01521     Author:     Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com>
01522     Created:    27/10/2000
01523     Purpose:    Called to set the current auto kerning State
01524 
01525 ********************************************************************************************/
01526 void TextInfoBarOp::SetCurrentAutoKerning(BOOL IsAutoKerning)
01527 {
01528     InfoData.AutoKerning = IsAutoKerning;
01529 }
01530 
01531 /********************************************************************************************
01532 
01533 >void TextInfoBarOp::EnableGadgets(BOOL Enable)
01534 
01535     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01536     Created:    13/2/95
01537     Inputs:     -
01538     Outputs:    -
01539     Returns:    -
01540     Purpose:    Called to GREY/ENABLE the gadgets on this bar
01541     Errors:     -
01542     SeeAlso:    -
01543 
01544 ********************************************************************************************/
01545 
01546 void TextInfoBarOp::EnableGadgets(BOOL Enable)
01547 {
01548     if(pTextInfoBar== NULL)
01549         return;
01550     if(!pTextInfoBar->HasWindow())
01551         return;
01552     pTextInfoBar->EnableGadget(_R(IDC_TRACKINGBIT) ,Enable);
01553     pTextInfoBar->EnableGadget(_R(IDC_KERNINGBIT) ,Enable);
01554 
01555 //  pTextInfoBar->EnableGadget(_R(IDC_TEXT),Enable);
01556     pTextInfoBar->EnableGadget(_R(IDC_FONT_COMBO),Enable);
01557     pTextInfoBar->EnableGadget(_R(IDC_POINT_COMBO),Enable);
01558     pTextInfoBar->EnableGadget(_R(IDC_BOLDBUTTON),Enable);
01559     pTextInfoBar->EnableGadget(_R(IDC_ITALICBUTTON),Enable);
01560 //  pTextInfoBar->EnableGadget(_R(IDC_UNDERLINEBUTTON),Enable);
01561     pTextInfoBar->EnableGadget(_R(IDC_ASPECTBIT),Enable);
01562     pTextInfoBar->EnableGadget(_R(IDC_ASPECTEDIT),Enable);
01563     pTextInfoBar->EnableGadget(_R(IDC_JUSTIFYLEFT),Enable);
01564     pTextInfoBar->EnableGadget(_R(IDC_JUSTIFYCENTRE),Enable);
01565     pTextInfoBar->EnableGadget(_R(IDC_JUSTIFYRIGHT),Enable);
01566     pTextInfoBar->EnableGadget(_R(IDC_JUSTIFYFULL),Enable);
01567     pTextInfoBar->EnableGadget(_R(IDC_KERN_EDIT_X),Enable);
01568     pTextInfoBar->EnableGadget(_R(IDC_KERN_EDIT_Y),Enable);
01569     pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_LESS),Enable);
01570     pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_MORE),Enable);
01571     pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_Y_LESS),Enable);
01572     pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_Y_MORE),Enable);
01573     pTextInfoBar->EnableGadget(_R(IDC_TRACKING_EDIT),Enable);
01574     pTextInfoBar->EnableGadget(_R(IDC_TRACKING_LESS),Enable);
01575     pTextInfoBar->EnableGadget(_R(IDC_TRACKING_MORE),Enable);
01576 
01577     pTextInfoBar->EnableGadget(_R(IDC_SPACING_EDIT),Enable);
01578     pTextInfoBar->EnableGadget(_R(IDC_SPACING_LESS),Enable);
01579     pTextInfoBar->EnableGadget(_R(IDC_SPACING_MORE),Enable);
01580 
01581     pTextInfoBar->EnableGadget(_R(IDC_AUTOKERN),Enable);
01582     //pTextInfoBar->EnableGadget(_R(IDC_KERN_EDIT_Y2),Enable);
01583 
01584 }
01585      
01586 
01587 /********************************************************************************************
01588 
01589 >void TextInfoBarOp::SetCurrentFontUnderLine(BOOL IsUnderLine)
01590 
01591     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01592     Created:    13/2/95
01593     Inputs:     -
01594     Outputs:    -
01595     Returns:    -
01596     Purpose:    Called to set the current UnderLine State
01597     Errors:     -
01598     SeeAlso:    -
01599 
01600 ********************************************************************************************/
01601 
01602 void TextInfoBarOp::SetCurrentFontUnderLine(BOOL IsUnderLine)
01603 {
01604     InfoData.UnderLine = IsUnderLine;
01605 }
01606 
01607 /********************************************************************************************
01608 
01609 >void TextInfoBarOp::SetCurrentTracking(INT32 Tracking)
01610 
01611     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01612     Created:    13/2/95
01613     Inputs:     -
01614     Purpose:    Called to set the current Tracking
01615 
01616 ********************************************************************************************/
01617 
01618 BOOL TextInfoBarOp::SetCurrentTracking(INT32 Tracking)
01619 {
01620     
01621     if(InfoData.Tracking == Tracking)
01622         return FALSE;
01623     InfoData.Tracking = Tracking;
01624     return TRUE;
01625     
01626 }    
01627      
01628 /********************************************************************************************
01629 
01630 >BOOL TextInfoBarOp::SetCurrentAspectRatio(FIXED16 AspectRatio)
01631 
01632     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01633     Created:    13/2/95
01634     Inputs:     -
01635     Returns:    FALSE if value unchanged TRUE otherwise
01636     Purpose:    Called to set the current AspectRatio
01637 
01638 ********************************************************************************************/
01639 
01640 BOOL TextInfoBarOp::SetCurrentAspectRatio(FIXED16 AspectRatio)
01641 {
01642     if(InfoData.AspectRatio == AspectRatio)
01643         return FALSE;
01644     InfoData.AspectRatio = AspectRatio;
01645     return TRUE;
01646 }    
01647 
01648 /********************************************************************************************
01649 
01650 >BOOL TextInfoBarOp::SetCurrentBaseLineShift(INT32 BaseLine)
01651 
01652     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01653     Created:    13/2/95
01654     Inputs:     -
01655     Returns:    FALSE if value unchanged TRUE otherwise
01656     Purpose:    Called to set the current BaseLineShift
01657 
01658 ********************************************************************************************/
01659 
01660 BOOL TextInfoBarOp::SetCurrentBaseLineShift(INT32 BaseLine)
01661 {
01662     if(InfoData.BaseLineShift == BaseLine)
01663         return FALSE;
01664     InfoData.BaseLineShift = BaseLine;
01665     return TRUE;
01666 
01667 }   
01668 /********************************************************************************************
01669 
01670 >BOOL TextInfoBarOp::SetCurrentLineSpace(MILLIPOINT LineSpace)
01671 
01672     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01673     Created:    13/2/95
01674     Inputs:     -
01675     Outputs:    -
01676     Returns:    FALSE if value unchanged TRUE otherwise
01677     Purpose:    Called to set the current Line Spacing absolute
01678                 Set LineSpacePercent zero to indicate which mode we are in(Relative/ABSOLUTE)
01679     Errors:     -
01680     SeeAlso:    -
01681 
01682 ********************************************************************************************/
01683 
01684 BOOL TextInfoBarOp::SetCurrentLineSpace(MILLIPOINT LineSpace)
01685 {
01686     if( InfoData.LineSpace == LineSpace)
01687         return FALSE;
01688     InfoData.LineSpace = LineSpace;
01689     InfoData.IsLineSpaceAPercent = FALSE;
01690     return TRUE;
01691 }
01692 /********************************************************************************************
01693 
01694 >BOOL TextInfoBarOp::SetCurrentLineSpacePercent(double Percent)
01695 
01696     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01697     Created:    13/2/95
01698     Inputs:     -
01699     Outputs:    -
01700     Returns:    FALSE if value unchanged TRUE otherwise
01701     Purpose:    Called to set the current Line Spacing as a relative percent
01702                 Set LineSpace zero to indicate which mode we are in(RELATIVE/Absolute)
01703     Errors:     -
01704     SeeAlso:    -
01705 
01706 ********************************************************************************************/
01707 
01708 BOOL TextInfoBarOp::SetCurrentLineSpacePercent(double Percent)
01709 {
01710     if(InfoData.LineSpacePercent == Percent)
01711         return FALSE;
01712     InfoData.LineSpacePercent = Percent;
01713     InfoData.IsLineSpaceAPercent = TRUE;
01714     return TRUE;
01715 
01716 }
01717 /********************************************************************************************
01718 
01719 >void TextInfoBarOp::SetCurrentHorizontalKern(INT32 Kern)
01720 
01721     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01722     Created:    13/2/95
01723     Inputs:     -
01724     Outputs:    -
01725     Returns:    FALSE if value unchanged TRUE otherwise
01726     Purpose:    Called to set the current HorizontalKern
01727     Errors:     -
01728     SeeAlso:    -
01729 
01730 ********************************************************************************************/
01731 
01732 BOOL TextInfoBarOp::SetCurrentHorizontalKern(INT32 Kern)
01733 {
01734     if(InfoData.HorizontalKern == Kern)
01735         return FALSE;
01736     
01737     InfoData.HorizontalKern = Kern;
01738     return TRUE;
01739 }
01740 
01741 /********************************************************************************************
01742 
01743 >void TextInfoBarOp::SetCurrentFontName(String_64 * Name, FontClass Type, BOOL Cache)
01744 
01745     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01746     Created:    13/2/95
01747     Inputs:     -
01748     Outputs:    -
01749     Returns:    -
01750     Purpose:    Called to set the current font name (and now Class as well)
01751     Errors:     -
01752     SeeAlso:    -
01753 
01754 ********************************************************************************************/
01755 
01756 BOOL TextInfoBarOp::SetCurrentFontName(String_64 * Name, FontClass Type, BOOL Cache)
01757 {
01758     ERROR2IF(Name == NULL,FALSE,"Null FontName");
01759 
01760     if(InfoData.FontName == *Name && InfoData.FontType == Type)
01761         return FALSE;
01762 
01763     InfoData.FontName = *Name;
01764     InfoData.FontType = Type;
01765 
01766     if (Cache)
01767         FONTMANAGER->CacheNamedFont(Name, Type);
01768 
01769     NameDropDown->SetTopFontName(Name, Type, FALSE);
01770     FontDropItem Dummy(*Name, Type);
01771     NameDropDown->SetSelection(&Dummy);
01772 
01773     return TRUE;
01774 }
01775 
01776 /********************************************************************************************
01777 
01778 >void TextInfoBarOp::RedrawUnitGadgets()
01779 
01780     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01781     Created:    13/2/95
01782     Inputs:     -
01783     Outputs:    -
01784     Returns:    -
01785     Purpose:    Force a redraw of all gadgets that work in units 
01786                 called on units changed message
01787     Errors:     -
01788     SeeAlso:    -
01789 
01790 ********************************************************************************************/
01791 
01792 void TextInfoBarOp::RedrawUnitGadgets()
01793 {
01794     if ((pTextInfoBar != NULL) && pTextInfoBar->HasWindow())
01795     {
01796         pTextInfoBar->SetUnitGadgetValue(_R(IDC_POINT_COMBO),CurrentFontUnits,InfoData.FontSize,0,-1);
01797         pTextInfoBar->SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1); 
01798     }
01799     SetLineSpaceGadget();
01800 
01801 }
01802 
01803 /********************************************************************************************
01804 
01805 >void TextInfoBarOp::SetLineSpaceGadget()
01806 
01807     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01808     Created:    13/2/95
01809     Inputs:     -
01810     Outputs:    -
01811     Returns:    -
01812     Purpose:    Set up the line space edit field
01813     Errors:     -
01814     SeeAlso:    -
01815 
01816 ********************************************************************************************/
01817 
01818 void TextInfoBarOp::SetLineSpaceGadget()
01819 {
01820     if ((pTextInfoBar != NULL) && pTextInfoBar->HasWindow())
01821     {
01822         if(InfoData.IsLineSpaceAPercent == FALSE)
01823         {
01824             pTextInfoBar->SetUnitGadgetValue(_R(IDC_SPACING_EDIT),CurrentFontUnits,InfoData.LineSpace,0,-1);
01825         }
01826         else
01827         {   
01828             String_256 StrValue;
01829             // Convert::DoubleToString(InfoData.LineSpacePercent, &StrValue);
01830             // StrValue += String_8(_R(IDS_TEXTINFO_PERCENT));          
01831             StrValue.MakePercent(InfoData.LineSpacePercent);
01832             pTextInfoBar->SetStringGadgetValue(_R(IDC_SPACING_EDIT), StrValue, 0,-1);
01833         }
01834     }
01835 }
01836 
01837 /********************************************************************************************
01838 
01839 >void TextInfoBarOp::DoKernBumps(UINT32 Button)
01840 
01841     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01842     Created:    13/2/95
01843     Inputs:     -
01844     Outputs:    -
01845     Returns:    -
01846     Purpose:    Called to "bump" kerning values
01847     Errors:     -
01848     SeeAlso:    -
01849 
01850 ********************************************************************************************/
01851 
01852 void TextInfoBarOp::DoKernBumps(UINT32 Button)
01853 {
01854     if (Button == _R(IDC_KERN_BUMP_X_LESS))
01855     {
01856         if(InfoData.HorizontalKern>=-(KernLimit-KernNudge))
01857         {
01858             SetCurrentHorizontalKern(InfoData.HorizontalKern-KernNudge);
01859             pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1);     
01860         }
01861     }
01862     else if (Button == _R(IDC_KERN_BUMP_X_MORE))
01863     {
01864         if(InfoData.HorizontalKern<=(KernLimit-KernNudge))
01865         {
01866             SetCurrentHorizontalKern(InfoData.HorizontalKern+KernNudge);
01867             pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1);     
01868         }
01869     }
01870     else if (Button == _R(IDC_KERN_BUMP_Y_LESS))
01871     {
01872         if ((InfoData.BaseLineShift != INVALID_ATTVAL) && (InfoData.BaseLineShift>=-(BaseLineLimit-BaseLineNudge)))
01873         {
01874             SetCurrentBaseLineShift(InfoData.BaseLineShift-BaseLineNudge);
01875             pTextInfoBar->SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1);
01876         }
01877     }
01878     else if (Button == _R(IDC_KERN_BUMP_Y_MORE))
01879     {
01880         if ((InfoData.BaseLineShift != INVALID_ATTVAL) && (InfoData.BaseLineShift<=(BaseLineLimit-BaseLineNudge)))
01881         {
01882             SetCurrentBaseLineShift(InfoData.BaseLineShift+BaseLineNudge);
01883             pTextInfoBar->SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1);
01884         }
01885     }
01886 }
01887 
01888 
01889 /********************************************************************************************
01890 
01891 >void TextInfoBarOp::DoTrackingBumps(UINT32 Button)
01892 
01893     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01894     Created:    13/2/95
01895     Inputs:     -
01896     Outputs:    -
01897     Returns:    -
01898     Purpose:    Called to "bump" tracking values
01899     Errors:     -
01900     SeeAlso:    -
01901 
01902 ********************************************************************************************/
01903 
01904 void TextInfoBarOp::DoTrackingBumps(UINT32 Button)
01905 {
01906     if (InfoData.Tracking == INVALID_ATTVAL)
01907         return;
01908 
01909     if (Button == _R(IDC_TRACKING_LESS))
01910     {
01911         if(InfoData.Tracking>=-(TrackingLimit-TrackingNudge))
01912         {
01913             SetCurrentTracking(InfoData.Tracking-TrackingNudge);
01914             pTextInfoBar->SetLongGadgetValue(_R(IDC_TRACKING_EDIT),InfoData.Tracking,0,-1);     
01915         }
01916     }
01917     else if (Button == _R(IDC_TRACKING_MORE))
01918     {
01919         if(InfoData.Tracking<=(TrackingLimit-TrackingNudge))
01920         {
01921             SetCurrentTracking(InfoData.Tracking+TrackingNudge);
01922             pTextInfoBar->SetLongGadgetValue(_R(IDC_TRACKING_EDIT),InfoData.Tracking,0,-1);     
01923         }
01924     }
01925 }
01926 
01927 /********************************************************************************************
01928 
01929 >void TextInfoBarOp::DoLineSpacingBumps(UINT32 Button)
01930 
01931     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
01932     Created:    13/2/95
01933     Inputs:     -
01934     Outputs:    -
01935     Returns:    -
01936     Purpose:    Called to "bump" Line Space values
01937     Errors:     -
01938     SeeAlso:    -
01939 
01940 ********************************************************************************************/
01941 
01942 void TextInfoBarOp::DoLineSpacingBumps(UINT32 Button)
01943 {
01944     BOOL ChangedValue = FALSE;
01945 
01946     if (Button == _R(IDC_SPACING_LESS))
01947     {
01948         if(InfoData.IsLineSpaceAPercent == FALSE)
01949         {
01950             if(InfoData.LineSpace == INVALID_ATTVAL)
01951                 return;
01952             if(InfoData.LineSpace>=-(LineSpaceLimit-LineSpaceNudge))
01953             {
01954                 SetCurrentLineSpace(InfoData.LineSpace-LineSpaceNudge);
01955                 ChangedValue = TRUE;
01956             }
01957         }
01958         else
01959         {
01960             if(InfoData.LineSpacePercent == INVALID_ATTVAL)
01961                 return;
01962             if(InfoData.LineSpacePercent>=(LineSpacePercentMin+LineSpacePercentNudge))
01963             {
01964                 SetCurrentLineSpacePercent(InfoData.LineSpacePercent - LineSpacePercentNudge);
01965                 ChangedValue = TRUE;
01966             }
01967         }
01968     }
01969     else if (Button == _R(IDC_SPACING_MORE))
01970     {
01971         if(InfoData.IsLineSpaceAPercent == FALSE)
01972         {
01973             if(InfoData.LineSpace == INVALID_ATTVAL)
01974                 return;
01975             if(InfoData.LineSpace<=(LineSpaceLimit-LineSpaceNudge))
01976             {
01977                 SetCurrentLineSpace(InfoData.LineSpace+LineSpaceNudge);
01978                 ChangedValue = TRUE;
01979             }
01980         }
01981         else
01982         {
01983             if(InfoData.LineSpacePercent == INVALID_ATTVAL)
01984                 return;
01985             if(InfoData.LineSpacePercent<=(LineSpacePercentMax - LineSpacePercentNudge))
01986             {
01987                 SetCurrentLineSpacePercent(InfoData.LineSpacePercent + LineSpacePercentNudge);
01988                 ChangedValue = TRUE;
01989             }
01990         }
01991     }
01992 
01993     if(ChangedValue)
01994         SetLineSpaceGadget();
01995 }
01996 
01997 /********************************************************************************************
01998 
01999 > static void TextInfoBarOp::DoFontChange()
02000 
02001     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
02002     Created:    13/2/95
02003     Inputs:     -
02004     Outputs:    -
02005     Returns:    -
02006     Purpose:    Called by Mainframe when a sys FontChange message is received
02007                 Validates the font cache and updates the font menu 
02008     Errors:     -
02009     SeeAlso:    -
02010 
02011 ********************************************************************************************/
02012 
02013 void TextInfoBarOp::DoFontChange()
02014 {
02015     // force a reformat and redraw of all text stories on  all documents 
02016     
02017     // Get a pointer to the StartDocument 
02018     /*
02019     
02020     Document* pDocument = (Document*) Camelot.Documents.GetHead();
02021     DocRect InvalidRgn;
02022     DocRect NewRect;
02023 
02024     while (pDocument != NULL)
02025     {
02026     
02027         // Get a pointer to the StartDocument node  
02028         Node* pStartNode = pDocument->GetFirstNode();
02029         ERROR3IF(pStartNode == NULL, "(BaseDocument::PostImport) TreeStart was NULL");
02030         BOOL ok = TRUE;
02031 
02032         // Get a pointer to the NodeDocument node
02033         if (pStartNode != NULL)
02034         {
02035             pStartNode = pStartNode->FindNext();
02036             ERROR3IF(pStartNode == NULL, "(BaseDocument::PostImport) No NodeDocument after StartDocument");
02037         }
02038 
02039         // Scan through the tree, formating and redrawing all text stories
02040         if (pStartNode != NULL)
02041         {
02042             Node* pCurrentNode = pStartNode->FindFirstDepthFirst();
02043 
02044             while (pCurrentNode != NULL)
02045             {
02046                 if(IS_A(pCurrentNode,TextStory))
02047                 {
02048                     TextStory* pTextStory=(TextStory*)pCurrentNode;
02049                     
02050                     InvalidRgn = pTextStory->GetUnionBlobBoundingRect();
02051                     pTextStory->FlagAffectedByOp();
02052                     ok=pTextStory->FormatAndChildren();
02053                 
02054                     if (ok)     
02055                     {
02056                         NewRect =  pTextStory->GetUnionBlobBoundingRect();
02057                         InvalidRgn = InvalidRgn.Union(NewRect);
02058                     }
02059                     
02060                     if (ok)
02061                         pDocument->ForceRedraw(pTextStory->FindParentSpread(), InvalidRgn, TRUE);
02062               
02063                 }
02064                 pCurrentNode = pCurrentNode->FindNextDepthFirst(pStartNode);
02065             }//  end depth first search loop
02066         }
02067 
02068         pDocument->FlushRedraw();
02069         pDocument = (Document*) Camelot.Documents.GetNext(pDocument);
02070     }// end reformat loop
02071 
02072     */
02073 
02074     OpAffectFontChange* pFontChange = new OpAffectFontChange();
02075     if (pFontChange!=NULL)
02076         pFontChange->DoAffectFontChange();
02077 
02078     // Update the text info bar font drop list (if it's there)
02079     if(NameDropDown != NULL)
02080     {
02081         NameDropDown->KillList();
02082         NameDropDown->FillInFontList();
02083         FontDropItem Dummy(InfoData.FontName, InfoData.FontType);
02084         NameDropDown->SetSelection(&Dummy);
02085     }
02086 
02087     // Update the actual combobox if the texttool is active
02088     if(pTextInfoBar!= NULL &&pTextInfoBar->HasWindow())
02089     {       
02090         pTextInfoBar->SetComboListLength(_R(IDC_FONT_COMBO));
02091         Update();
02092     }
02093 }
02094 
02095 
02096 /********************************************************************************************
02097 >   static BOOL TextInfoBarOp::StringToDouble(StringBase* pstrIn, double* pnOut,BOOL IsMultiple)
02098 
02099     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com> (thanks to JustinF)
02100     Created:    31/5/95
02101     Inputs:     pstrIn          ---     pointer to the string containing text
02102                 pnOut           ---     pointer to the number which will contain the result
02103                 pIsMultiple     ---     pointer to a BOOL which indicates a mulitple
02104     Outputs:    -
02105     Returns:    TRUE if the text is successfully parsed, FALSE otherwise.
02106     Purpose:    Parses the text within the zoom factor combo-box, checking for a percentage
02107                 factor ("%") or a multiplier factor ("x"), converting it to a number.
02108     Errors:     -
02109     SeeAlso:    OpZoomComboDescriptor::OnSelectionChange; DialogOp::GetLongGadgetValue
02110 ********************************************************************************************/
02111 
02112 BOOL TextInfoBarOp::StringToDouble(StringBase* pstrIn, double* pnOut,BOOL * pIsMultiple)
02113 {
02114     ENSURE(pstrIn != NULL && pnOut != NULL,
02115             "Null parameter(s) in TextInfoBarOp::StringToLong");
02116 
02117     // Remove any leading or trailing whitespace.  psczStart is set to point to first non-
02118     // whitespace character (or the terminating null), pszEnd points to the last.  If the
02119     // string is entirely whitespace these two will cross over, and we return FALSE.
02120     const TCHAR* psczStart = (const TCHAR*) (*pstrIn);
02121     const TCHAR* psczForward = psczStart;
02122     const TCHAR* psczBack = psczStart + pstrIn->Length() - 1;
02123     
02124     *pIsMultiple = FALSE;
02125     
02126     String_16 space(_R(IDS_TEXTINFO_PARSE_SPACE));
02127     while (*psczForward == *((TCHAR *)space)/*TEXT(' ')*/) 
02128         psczForward++;
02129     
02130     while (psczBack > psczForward && *psczBack == *((TCHAR *)space)/*TEXT(' ')*/) 
02131         psczBack--;
02132     
02133     if (psczForward > psczBack) 
02134         return FALSE;
02135 
02136     // Check if the string ends with a '%' or an 'x'.  If it is an 'x' then the number
02137     // is a multipler, eg. "2 x" (two times).  If it is a '%', or not there at all,
02138     // then it represents a percentage.
02139     String_16 smallx(_R(IDS_TEXTINFO_PARSE_SMALLX));
02140     String_16 largex(_R(IDS_TEXTINFO_PARSE_LARGEX));
02141     String_16 percent(_R(IDS_TEXTINFO_PARSE_PERCENT));
02142     BOOL bIsMultiplier = FALSE;
02143     if (    *psczBack == *((TCHAR *)smallx)/*TEXT('x')*/
02144          || *psczBack == *((TCHAR *)largex)/*TEXT('X')*/)
02145     {
02146         // Parse a multiplier.  Skip over the 'x'.
02147         psczBack--;
02148         bIsMultiplier = TRUE;
02149     }
02150     else if (*psczBack == *((TCHAR *)percent) /*TEXT('%'))*/)
02151     {
02152         // Parse a percentage.  Skip over the '%'
02153         psczBack--;
02154     }
02155     else if (!StringBase::IsNumeric(*psczBack))
02156     {
02157         // Can't recognise the format - not a number.
02158         return FALSE;
02159     }
02160 
02161     // Make a working copy of what is left of the string.
02162     String_256 strWork;
02163     pstrIn->Mid(&strWork, (INT32) (psczForward - psczStart),
02164                 (INT32) (psczBack - psczForward) + 1);
02165 
02166     if (!Convert::StringToDouble(strWork, pnOut)) 
02167         return FALSE;
02168     
02169     // Make sure it's within allowed bounds.
02170     INT32 nMaxMultiple = LineSpacePercentMax/100;
02171     INT32 nMinMultiple = LineSpacePercentMin/100;
02172 
02173     if (*pnOut > LineSpacePercentMax)
02174         *pnOut = LineSpacePercentMax;
02175     if (*pnOut < LineSpacePercentMin)
02176         *pnOut = LineSpacePercentMin;
02177     
02178     if (bIsMultiplier) 
02179     {
02180         *pIsMultiple = TRUE;
02181         if (*pnOut > nMaxMultiple)
02182             *pnOut = nMaxMultiple;
02183         if (*pnOut < nMinMultiple)
02184             *pnOut = nMinMultiple;  
02185     }
02186     return TRUE;
02187 }
02188 
02189 /********************************************************************************************
02190 
02191 >   MsgResult TextInfoBarOp::(Msg* Message) 
02192 
02193     Author:     Mark_Goodall (Xara Group Ltd) <camelotdev@xara.com>
02194     Created:    3/10/94
02195     Inputs:     Message = The message to handle
02196     Outputs:    -
02197     Returns:    -
02198     Purpose:    Text info bar dialog message handler
02199     Errors:     -
02200     SeeAlso:    -
02201 
02202 ********************************************************************************************/
02203 
02204 void TextInfoBarOp::DoInputError(UINT32 GadgetID) 
02205 {
02206     String_256 sErrString;
02207     String_64 sWarnString(_R(IDS_INVALID_FONTSIZE));
02208     String_8 sAndString(_R(IDS_AND));
02209     String_16 sMaxStr(_T("0"));
02210     String_16 sMinStr(_T("0"));
02211 
02212     if (GadgetID == _R(IDC_TRACKING_EDIT))
02213     {
02214         sMinStr._MakeMsg(TEXT("#1%dems"),-TrackingLimit);
02215         sMaxStr._MakeMsg(TEXT("#1%dems"),TrackingLimit);
02216     }
02217     else if (GadgetID == _R(IDC_KERN_EDIT_X))
02218     {
02219         sMinStr._MakeMsg(TEXT("#1%dems"),-KernLimit);
02220         sMaxStr._MakeMsg(TEXT("#1%dems"),KernLimit);
02221     }   
02222     else if (GadgetID == _R(IDC_KERN_EDIT_Y))
02223     {
02224         Convert::MillipointsToString(-BaseLineLimit, MILLIPOINTS, &sMinStr);
02225         Convert::MillipointsToString(BaseLineLimit, MILLIPOINTS, &sMaxStr);
02226     }
02227     else if (GadgetID == _R(IDC_SPACING_EDIT))
02228     {
02229         Convert::MillipointsToString(-LineSpaceLimit, MILLIPOINTS, &sMinStr);
02230         Convert::MillipointsToString(LineSpaceLimit, MILLIPOINTS, &sMaxStr);
02231     }
02232     else if (GadgetID == _R(IDC_ASPECTEDIT))
02233     {
02234         sMinStr._MakeMsg(TEXT("#1%d%"),FontAspectMin);
02235         sMaxStr._MakeMsg(TEXT("#1%d%"),FontAspectMax);
02236     }
02237     else if (GadgetID == _R(IDC_POINT_COMBO))
02238     {
02239         Convert::MillipointsToString(FontSizeMax, CurrentFontUnits, &sMaxStr);
02240         Convert::MillipointsToString(FontSizeMin, CurrentFontUnits, &sMinStr);  
02241     }
02242     else
02243     {
02244         return;
02245     }
02246 
02247     sErrString._MakeMsg(_T("#1%s #2%s #3%s #4%s\n"),
02248                         (TCHAR*)sWarnString,
02249                         (TCHAR*)sMinStr,
02250                         (TCHAR*)sAndString,
02251                         (TCHAR*)sMaxStr); 
02252             
02253     Error::SetError(0,(TCHAR* )sErrString,0);
02254     InformError();
02255 }
02256 
02257 
02258 /********************************************************************************************
02259 
02260 >   MsgResult TextInfoBarOp::Message(Msg* Message) 
02261 
02262     Author:     Mark_Goodall (Xara Group Ltd) <camelotdev@xara.com>
02263     Created:    3/10/94
02264     Inputs:     Message = The message to handle
02265     Outputs:    -
02266     Returns:    -
02267     Purpose:    Text info bar dialog message handler
02268     Errors:     -
02269     SeeAlso:    -
02270 
02271 ********************************************************************************************/
02272 
02273 MsgResult TextInfoBarOp::Message(Msg* Message) 
02274 {
02275     if (IS_OUR_DIALOG_MSG(Message))
02276     {
02277         DialogMsg* Msg = (DialogMsg*)Message;
02278 
02279         if (Msg->DlgMsg == DIM_CANCEL)
02280         {
02281             Close();  
02282         }
02283         else if (Msg->DlgMsg == DIM_CREATE)
02284         {
02285             // Initialise the infobar controls here
02286             // This is sent when you create the infobar in your tool startup code
02287             InitControls();
02288             
02289             BOOL Greyed = (OpTextKern::GetState(NULL, NULL)).Greyed;
02290             pTextInfoBar->EnableGadget(_R(IDC_KERN_EDIT_X),!Greyed);
02291             pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_LESS),!Greyed);
02292             pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_MORE),!Greyed);
02293 
02294             Greyed = (OpTextAutoKern::GetState(NULL, NULL)).Greyed;
02295             pTextInfoBar->EnableGadget(_R(IDC_AUTOKERN),!Greyed);
02296         }
02297         else
02298         {
02299             if (FALSE) {}
02300             else if (Msg->GadgetID == _R(IDC_SUPERSCRIPT))
02301             {
02302                 switch (Msg->DlgMsg)
02303                 {
02304                     case DIM_LFT_BN_CLICKED:
02305                         SetCurrentScript(SuperScript);
02306                         OnFieldChange(ScriptA);     
02307                         break;
02308                     default:
02309                         break;
02310                 }
02311             }
02312             else if (Msg->GadgetID == _R(IDC_SUBSCRIPT))
02313             {
02314                 switch (Msg->DlgMsg)
02315                 {
02316                     case DIM_LFT_BN_CLICKED:
02317                         SetCurrentScript(SubScript);
02318                         OnFieldChange(ScriptA); 
02319                         break;
02320                     default:
02321                         break;
02322                 }
02323             }
02324             else if (Msg->GadgetID == _R(IDC_KERN_EDIT_Y))
02325             {
02326                 switch (Msg->DlgMsg)
02327                 {
02328                     case DIM_SELECTION_CHANGED :
02329                         {
02330                             BOOL Valid= FALSE;
02331                             MILLIPOINT  BaseShift = GetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits, 
02332                                                 -BaseLineLimit,BaseLineLimit,0,&Valid);
02333                             if(Valid)
02334                             {
02335                                 if(SetCurrentBaseLineShift(BaseShift))
02336                                     OnFieldChange(BaseLineShiftA);
02337                             }
02338                             else
02339                             {
02340                                 DoInputError(Msg->GadgetID);
02341                                 SetUnitGadgetValue(_R(IDC_KERN_EDIT_Y),CurrentFontUnits,InfoData.BaseLineShift,0,-1);
02342                             }
02343                         }
02344                         break;
02345                     default:
02346                         break;
02347                 }
02348             }
02349             else if (Msg->GadgetID == _R(IDC_KERN_EDIT_X))
02350             {
02351                 switch (Msg->DlgMsg)
02352                 {
02353                     case DIM_SELECTION_CHANGED :
02354                     {
02355                         BOOL Valid= FALSE;
02356                         INT32 Kern = GetLongGadgetValue(_R(IDC_KERN_EDIT_X) , 
02357                                             -KernLimit,KernLimit,0,&Valid);
02358                         if(Valid)
02359                         {
02360                             if(SetCurrentHorizontalKern(Kern))
02361                                 OnFieldChange(HorizontalKernA);
02362                         }
02363                         else
02364                         {
02365                             DoInputError(Msg->GadgetID);
02366                             SetLongGadgetValue(_R(IDC_KERN_EDIT_X),InfoData.HorizontalKern,0,-1); 
02367                         }
02368                     }
02369                     break;
02370                     default:
02371                         break;
02372                 }
02373             }
02374             else if ((Msg->GadgetID == _R(IDC_SPACING_MORE)) || (Msg->GadgetID == _R(IDC_SPACING_LESS)))
02375             {
02376                 switch (Msg->DlgMsg)
02377                 {
02378                     case DIM_LFT_BN_CLICKED:
02379                     {
02380                         DoLineSpacingBumps(Msg->GadgetID);
02381                         break;
02382                     }
02383                     case DIM_LFT_BN_UP:
02384                     {
02385                         if(InfoData.IsLineSpaceAPercent == FALSE)
02386                             OnFieldChange(LineSpaceA);
02387                         else
02388                             OnFieldChange(LineSpacePercentA);
02389                         break;
02390                     }
02391                     default:
02392                         break;
02393                 }
02394             }
02395             else if ((Msg->GadgetID == _R(IDC_TRACKING_MORE)) || (Msg->GadgetID == _R(IDC_TRACKING_LESS)))
02396             {
02397                 switch (Msg->DlgMsg)
02398                 {
02399                     case DIM_LFT_BN_CLICKED:
02400                     {
02401                         DoTrackingBumps(Msg->GadgetID);
02402                         break;
02403                     }
02404                     case DIM_LFT_BN_UP:
02405                     {
02406                         OnFieldChange(TrackingA);
02407                         break;
02408                     }
02409                     default:
02410                         break;
02411                 }
02412             }
02413             else if ((Msg->GadgetID == _R(IDC_KERN_BUMP_X_MORE)) || (Msg->GadgetID == _R(IDC_KERN_BUMP_X_LESS)))
02414             {
02415                 switch (Msg->DlgMsg)
02416                 {
02417                     case DIM_LFT_BN_CLICKED:
02418                     {
02419                         DoKernBumps(Msg->GadgetID);
02420                         break;
02421                     }
02422                     case DIM_LFT_BN_UP:
02423                     {
02424                         OnFieldChange(HorizontalKernA);
02425                         break;
02426                     }
02427                     default:
02428                         break;
02429                 }
02430             }
02431             else if ((Msg->GadgetID == _R(IDC_KERN_BUMP_Y_MORE)) || (Msg->GadgetID == _R(IDC_KERN_BUMP_Y_LESS)))
02432             {
02433                 switch (Msg->DlgMsg)
02434                 {
02435                     case DIM_LFT_BN_CLICKED:
02436                     {
02437                         DoKernBumps(Msg->GadgetID);
02438                         break;
02439                     }
02440                     case DIM_LFT_BN_UP:
02441                     {
02442                         OnFieldChange(BaseLineShiftA);
02443                         break;
02444                     }
02445                     default:
02446                         break;
02447                 }
02448             }
02449             else if (Msg->GadgetID == _R(IDC_SPACING_EDIT))
02450             {
02451                 switch (Msg->DlgMsg)
02452                 {
02453                     case DIM_SELECTION_CHANGED :
02454                     {
02455                         BOOL Valid= FALSE;
02456                         
02457                         String_256 Str = GetStringGadgetValue(_R(IDC_SPACING_EDIT),&Valid);
02458                         if(!Valid)
02459                             break;
02460 
02461                         double Percentage =0;
02462                         BOOL IsMultiple = FALSE;
02463                         BOOL WasAPercent = StringToDouble(&Str, &Percentage,&IsMultiple);
02464                         if(WasAPercent )
02465                         {
02466                             // was it a multiple
02467                             if(IsMultiple)
02468                                 Percentage *= 100;
02469                             if(SetCurrentLineSpacePercent(Percentage))
02470                                 OnFieldChange(LineSpacePercentA);   
02471                         }
02472                         else
02473                         {
02474 
02475                             MILLIPOINT  Spacing = GetUnitGadgetValue(_R(IDC_SPACING_EDIT),CurrentFontUnits, 
02476                                                 -LineSpaceLimit,LineSpaceLimit,0,&Valid);
02477                             if(Valid)
02478                             {
02479                                 if(SetCurrentLineSpace(Spacing))
02480                                     OnFieldChange(LineSpaceA);
02481                             }
02482                             else
02483                             {
02484                                 DoInputError(Msg->GadgetID);
02485                                 SetLineSpaceGadget();
02486                             }
02487                         }
02488                         break;
02489                     }
02490                     default:
02491                         break;
02492                 }
02493             }
02494             else if (Msg->GadgetID == _R(IDC_TRACKING_EDIT))
02495             {
02496                 switch (Msg->DlgMsg)
02497                 {
02498                     case DIM_SELECTION_CHANGED :
02499                     {
02500                         BOOL Valid= FALSE;
02501                         INT32 TrackingVal = GetLongGadgetValue(_R(IDC_TRACKING_EDIT), 
02502                                             -TrackingLimit,TrackingLimit,0,&Valid);
02503                         if(Valid)
02504                         {
02505                             if(SetCurrentTracking(TrackingVal))
02506                                 OnFieldChange(TrackingA);
02507                         }
02508                         else
02509                         {
02510                             DoInputError(Msg->GadgetID);
02511                             SetDoubleGadgetValue(_R(IDC_TRACKING_EDIT),InfoData.Tracking,0,-1);
02512                         }
02513                         break;
02514                     }
02515                     default:
02516                         break;
02517                 }
02518             }
02519             else if (Msg->GadgetID == _R(IDC_ASPECTEDIT))
02520             {
02521                 switch (Msg->DlgMsg)
02522                 {
02523                     case DIM_SELECTION_CHANGED :
02524                     {
02525                         BOOL Valid= FALSE;
02526                         FIXED16 Ratio = GetDoubleGadgetValue(_R(IDC_ASPECTEDIT), 
02527                                             FontAspectMin,FontAspectMax,0,&Valid)/100;
02528                         if(Valid)
02529                         {
02530                             if(SetCurrentAspectRatio(Ratio))
02531                                 OnFieldChange(AspectRatioA);
02532                         }
02533                         else
02534                         {
02535                             DoInputError(Msg->GadgetID);
02536                             SetDoubleGadgetValue(_R(IDC_ASPECTEDIT),InfoData.AspectRatio.MakeDouble()*100,0,-1); 
02537                         }
02538                         break;
02539                     }
02540                     default:
02541                         break;
02542                 }
02543             }
02544             else if (
02545                 (Msg->GadgetID == _R(IDC_JUSTIFYFULL)) ||
02546                 (Msg->GadgetID == _R(IDC_JUSTIFYLEFT)) ||
02547                 (Msg->GadgetID == _R(IDC_JUSTIFYRIGHT)) ||
02548                 (Msg->GadgetID == _R(IDC_JUSTIFYCENTRE))
02549                 )
02550             {
02551                 switch (Msg->DlgMsg)
02552                 {
02553                     case DIM_LFT_BN_CLICKED:
02554                     {
02555                         SetCurrentJustify(Msg->GadgetID);
02556                         OnFieldChange(JustifyA);        
02557                         break;
02558                     }
02559                     default:
02560                         break;
02561                 }
02562             }
02563             else if (Msg->GadgetID == _R(IDC_BOLDBUTTON))
02564             {
02565                 switch (Msg->DlgMsg)
02566                 {
02567                     case DIM_LFT_BN_CLICKED:
02568                     {
02569                         SetCurrentFontBold(!InfoData.Bold);
02570                         OnFieldChange(BoldA);   
02571                         break;
02572                     }
02573                     default:
02574                         break;
02575                 }
02576             }
02577             else if (Msg->GadgetID == _R(IDC_ITALICBUTTON))
02578             {
02579                 switch (Msg->DlgMsg)
02580                 {
02581                     case DIM_LFT_BN_CLICKED:
02582                     {
02583                         SetCurrentFontItalic(!InfoData.Italic); 
02584                         OnFieldChange(ItalicA);
02585                         break;
02586                     }
02587                     default:
02588                         break;
02589                 }
02590             }
02591             else if (Msg->GadgetID == _R(IDC_AUTOKERN))
02592             {
02593                 switch (Msg->DlgMsg)
02594                 {
02595                     case DIM_LFT_BN_CLICKED:
02596                     {
02597                         SetCurrentAutoKerning(!InfoData.AutoKerning);
02598                         OnFieldChange(AutoKernText);    
02599                         break;
02600                     }
02601                     default:
02602                         break;
02603                 }
02604             }
02605             else if (Msg->GadgetID == _R(IDC_POINT_COMBO))
02606             {
02607                 switch (Msg->DlgMsg)
02608                 {
02609                     case DIM_SELECTION_CHANGED :
02610                     {
02611                         BOOL Valid= FALSE;
02612                         MILLIPOINT  Size = GetUnitGadgetValue(_R(IDC_POINT_COMBO),CurrentFontUnits, 
02613                                             FontSizeMin,FontSizeMax,0,&Valid);
02614                         if(Valid)
02615                         {
02616                             if(SetCurrentPointSize(Size))
02617                                 OnFieldChange(FontSizeA);
02618                         }
02619                         else
02620                             DoInputError(Msg->GadgetID);
02621 
02622                         SetUnitGadgetValue(_R(IDC_POINT_COMBO),CurrentFontUnits,InfoData.FontSize,0,-1);
02623                         break;
02624                     }
02625                     default:
02626                         break;
02627                 }
02628             }
02629             else if (Msg->GadgetID == _R(IDC_FONT_COMBO))
02630             {
02631                 if ((Msg->DlgMsg == DIM_SELECTION_CHANGED_COMMIT) || (Msg->DlgMsg == DIM_SELECTION_CHANGED))
02632                 {
02633                     // Handle selections in the font name menu.
02634                     INT32 SelIndex = GetSelectedValueIndex(_R(IDC_FONT_COMBO));
02635                     
02636                     if(SelIndex != -1)
02637                     {
02638                         if (NameDropDown != NULL)
02639                         {
02640                             FontDropItem *Selected = NameDropDown->DecodeSelection((INT32)SelIndex);
02641                             if (Selected)
02642                             {
02643                                 if (FONTMANAGER->IsFontInstalled(&Selected->FontName, Selected->Type))
02644                                 {
02645                                     if (SetCurrentFontName(&Selected->FontName, Selected->Type, TRUE))
02646                                         OnFieldChange(FontNameA);
02647                                 }
02648                                 else
02649                                 {
02650                                     InformWarning(_R(IDS_INVALIDFONT));
02651                                     Update();
02652                                 }
02653                             }
02654                         }
02655                     }
02656                 }
02657             }
02658         }
02659     }
02660         // Does this message mean that the selected object has changed?
02661     else if (MESSAGE_IS_A(Message, SelChangingMsg))
02662     {
02663         // Re-render the tool blobs as they may have moved
02664         if (pTextTool!=NULL && pTextTool->IsCurrent())
02665         {
02666             if (!pTextTool->SelectionHasChanged())
02667                 InformError();
02668         }
02669 
02670         if(pTextInfoBar==NULL || !pTextInfoBar->HasWindow())
02671             return(InformationBarOp::Message(Message));
02672 
02673         // update the info bar according to the selection
02674         BOOL Greyed = (OpTextKern::GetState(NULL, NULL)).Greyed;
02675         pTextInfoBar->EnableGadget(_R(IDC_KERN_EDIT_X),!Greyed);
02676         pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_LESS),!Greyed);
02677         pTextInfoBar->EnableGadget(_R(IDC_KERN_BUMP_X_MORE),!Greyed);
02678 
02679         Greyed = (OpTextAutoKern::GetState(NULL, NULL)).Greyed;
02680         pTextInfoBar->EnableGadget(_R(IDC_AUTOKERN),!Greyed);
02681 
02682         Update();
02683     }
02684 
02685     // How about a view changing message?
02686     else if (MESSAGE_IS_A(Message, DocViewMsg))
02687     {
02688         if(Document::GetSelected()== NULL)
02689             EnableGadgets(FALSE);
02690         else
02691             EnableGadgets(TRUE);
02692 
02693         DocViewMsg* msg = (DocViewMsg*) Message;
02694 
02695         // Render the tool blobs off the old view just before it changes
02696         if (msg->State == DocViewMsg::SELABOUTTOCHANGE)
02697         {
02698             if (msg->pOldDocView!=NULL && pTextTool!=NULL && !GetApplication()->CamelotIsDying())
02699             {
02700                 // Do additional checks here to avoid ensures!
02701                 CCamView* pOilView = msg->pOldDocView->GetConnectionToOilView();
02702                 BlobManager* pBlobManager = GetApplication()->GetBlobManager();
02703 
02704 PORTNOTE("text", "Removed IsScreenCamView() test");
02705                 if (pOilView!=NULL /*&& pOilView->IsScreenCamView()*/)
02706                     pBlobManager->RenderToolBlobsOff(pTextTool, msg->pOldDocView->GetVisibleSpread(), NULL);
02707             }
02708         }
02709     }
02710     
02711     // How about a document changing message?
02712     else if (MESSAGE_IS_A(Message, DocChangingMsg))
02713     {
02714         DocChangingMsg* Msg = (DocChangingMsg*)Message;
02715         pDoc = Document::GetSelected();
02716         
02717         if(pDoc)
02718             CurrentFontUnits = pDoc->GetDocFontUnits(); 
02719         
02720         if (Msg->State == DocChangingMsg::SELCHANGED)
02721         {
02722             // Clear the focus story
02723             TextStory::SetFocusStory(NULL);
02724 
02725             // Now check that we havent got a selected caret outside the text tool.
02726             if (!TextTool::IsCurrentTool())
02727             {
02728                 SelRange *pSelection = GetApplication()->FindSelection();
02729                 if (pSelection != NULL)
02730                 {
02731                     BOOL ChangedSel = FALSE;
02732                     Node* pNode = pSelection->FindFirst();
02733                     while (pNode != NULL)
02734                     {
02735                         if (pNode->IsAVisibleTextNode() && ((VisibleTextNode*)pNode)->IsACaret())
02736                         {
02737                             ((CaretNode*)pNode)->SetSelected(FALSE);
02738                             ChangedSel = TRUE;
02739                         }
02740 
02741                         pNode = pSelection->FindNext(pNode);
02742                     }
02743 
02744                     if (ChangedSel)
02745                         GetApplication()->UpdateSelection();
02746                 }
02747             }
02748             Update(TRUE);
02749         }
02750         
02751     }
02752     else if(MESSAGE_IS_A(Message,OptionsChangingMsg))
02753     {
02754 
02755         OptionsChangingMsg* Msg = (OptionsChangingMsg*)Message;
02756 
02757         if(Msg->State == OptionsChangingMsg::NEWUNITS)
02758         {
02759             pDoc = Document::GetSelected();
02760             if(pDoc)
02761                 CurrentFontUnits = pDoc->GetDocFontUnits(); 
02762             RedrawUnitGadgets();
02763         }
02764         
02765     }
02766 
02767     // or possibly an op message?
02768     else if (MESSAGE_IS_A(Message,OpMsg))
02769     {
02770         OpMsg* pOpMsg = (OpMsg*)Message;
02771 
02772         if (pOpMsg->MsgType == OpMsg::END)
02773         {
02774             // an operation has ended, was it the one we were after?
02775             if (IS_A(pOpMsg->pOp, OpCut))
02776             {
02777                 if (RegainCaretAfterOp)
02778                 {
02779                     // make sure we turn this off after the op has come through
02780                     RegainCaretAfterOp = FALSE;
02781 
02782                     if (!(pOpMsg->pOp->GetOpFlgs()).Failed)
02783                     {
02784                         TextStory* pStory = TextStory::GetFocusStory();
02785                         if (pStory != NULL)
02786                         {
02787                             CaretNode* pCaret = pStory->GetCaret();
02788                             if (pCaret != NULL)
02789                             {
02790                                 pCaret->SetSelected(TRUE);
02791                                 pStory->AttachCaretAttributes();
02792                                 GetApplication()->FindSelection()->Update();
02793                             }
02794                         }
02795                     }
02796                 }
02797             }
02798         }
02799     }
02800 
02801     else if (MESSAGE_IS_A(Message,LocaleChangedMsg))
02802     {
02803         if (pTextTool!= NULL)
02804             pTextTool->LocaleChanged();
02805     }
02806 
02807     // Pass the message on to the immediate Text class
02808     return (InformationBarOp::Message(Message));
02809 }    
02810 
02811 
02812 /********************************************************************************************
02813 
02814 >void TextInfoBarOp::InitControls()
02815 
02816     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
02817     Created:    13/2/95
02818     Inputs:     -
02819     Outputs:    -
02820     Returns:    -
02821     Purpose:    Initialise the info bar
02822     Errors:     -
02823     SeeAlso:    -
02824 
02825 ********************************************************************************************/
02826 
02827 
02828 void TextInfoBarOp::InitControls()
02829 {
02830     // current info bar public for callbacks argh..
02831     pTextInfoBar = this;
02832 
02833     // Only enum the fonts if it's the first time - should respond to font change messages now !
02834     if (NameDropDown == NULL)
02835     {
02836         NameDropDown = new FontDropDown;
02837     }
02838 
02839     if(NameDropDown != NULL)
02840     {
02841         NameDropDown->Init((CWindowID)WindowID, _R(IDC_FONT_COMBO));
02842         NameDropDown->FillInFontList();
02843     }
02844 
02845     pTextInfoBar->SetComboListLength(_R(IDC_FONT_COMBO));
02846     UpdateGadgets();
02847     
02848     // Point Size 
02849     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_8PT) );
02850     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_10PT));
02851     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_11PT));
02852     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_12PT));
02853     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_14PT));
02854     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_16PT));
02855     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_18PT));
02856     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_20PT));
02857     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_24PT));
02858     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_28PT));
02859     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_32PT));
02860     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_36PT));
02861     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_48PT));
02862     SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_72PT));
02863     SetComboListLength(_R(IDC_POINT_COMBO));
02864     
02865     
02866     if(Document::GetSelected()!= NULL)
02867         SetUnitGadgetValue(_R(IDC_POINT_COMBO),CurrentFontUnits,InfoData.FontSize,0,-1);
02868     else
02869         SetStringGadgetValue(_R(IDC_POINT_COMBO), _R(IDS_TEXTINFO_16PT),0,-1);
02870 
02871     if(Document::GetSelected()== NULL)
02872         EnableGadgets(FALSE);
02873     
02874     Update(TRUE);
02875     
02876 }      
02877 /********************************************************************************************
02878 
02879 >void TextInfoBarOp::AddFontToCombo(String_64 * FontName)
02880 
02881     Author:     Chris_Parks (Xara Group Ltd) <camelotdev@xara.com>
02882     Created:    13/2/95
02883     Inputs:     -
02884     Outputs:    -
02885     Returns:    -
02886     Purpose:    Called to add a font name to the end of the font combo box
02887     Errors:     -
02888     SeeAlso:    -
02889 
02890 ********************************************************************************************/
02891 
02892 void TextInfoBarOp::AddFontToCombo(String_64 * FontName)
02893 {
02894 //  if(pTextInfoBar)
02895 //          pTextInfoBar->SetStringGadgetValue(_R(IDC_FONT_COMBO),FontName,TRUE,0); 
02896 }
02897 
02898 
02899 /********************************************************************************************
02900 
02901 >   static void TextInfoBarOp::RegainCaretOnOpEnd()
02902 
02903     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02904     Created:    07/6/95
02905     Inputs:     -
02906     Outputs:    -
02907     Returns:    -
02908     Purpose:    Used to try to regain the caret after an operation has completed.
02909                 Currently only used from OpCut.
02910 
02911 ********************************************************************************************/
02912 
02913 void TextInfoBarOp::RegainCaretOnOpEnd()
02914 {
02915     RegainCaretAfterOp = TRUE;
02916 }
02917 
02918 
02919 
02920 /********************************************************************************************
02921 >   BOOL TextInfoBarOp::UpdateFieldsAfterTyping()
02922 
02923     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02924     Created:    25/8/95
02925     Inputs:     -
02926     Outputs:    -
02927     Returns:    TRUE/FALSE for success/failure
02928     Purpose:    Called on idle events after typing.  As simple typing does not send a
02929                 SelChanged message (in a vain attempt to make typing faster) this function is
02930                 called on idles in order to update the parts on the infobar that may have
02931                 been affected by the typing.
02932 ********************************************************************************************/
02933 
02934 BOOL TextInfoBarOp::UpdateFieldsAfterTyping()
02935 {
02936     // Skip out now if there isn't an infobar
02937     if (pTextInfoBar==NULL || !pTextInfoBar->HasWindow())
02938         return TRUE;
02939 
02940     // Update the horizontal kern field
02941     TextStory * ActiveStory = TextStory::GetFocusStory();
02942     if (ActiveStory != NULL)
02943     {
02944         CaretNode * pCaret = ActiveStory->GetCaret();
02945         if (pCaret != NULL)
02946         {
02947             VisibleTextNode * LastNode = pCaret->FindPrevAbstractTextCharInStory();
02948             if (LastNode != NULL)
02949             {
02950                 if (IS_A(LastNode, KernCode))
02951                     pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X),((KernCode*)LastNode)->GetValue().x,0,-1);
02952                 else
02953                     pTextInfoBar->SetLongGadgetValue(_R(IDC_KERN_EDIT_X), 0, 0, -1);
02954 
02955                 pTextInfoBar->PaintGadgetNow(_R(IDC_KERN_EDIT_X)); 
02956             }
02957         }
02958     }
02959 
02960     return TRUE;
02961 }
02962 
02963 
02965 // Ruler display and tab stop dragging
02966 
02967 /********************************************************************************************
02968 
02969 >void TextInfoBarOp::ForceRulerRedraw()
02970 
02971     Author:     Martin Wuerthner <xara@mw-software.com>
02972     Created:    07/07/06
02973     Purpose:    Force a ruler redraw
02974                 (called each time anything on the ruler has changed)
02975 
02976 ********************************************************************************************/
02977 
02978 void TextInfoBarOp::ForceRulerRedraw()
02979 {
02980     DocView* pDocView = DocView::GetSelected();
02981     if (pDocView)
02982     {
02983         RulerPair* pRulerPair = pDocView->GetpRulerPair();
02984         if (pRulerPair) pRulerPair->Update();
02985     }
02986 }
02987 
02988 /********************************************************************************************
02989 
02990 >void TextInfoBarOp::ReleaseRuler()
02991 
02992     Author:     Martin Wuerthner <xara@mw-software.com>
02993     Created:    07/07/06
02994     Purpose:    Release the ruler if it has been claimed and update it
02995                 (called on tool deselection)                        
02996 
02997 ********************************************************************************************/
02998 
02999 void TextInfoBarOp::ReleaseRuler()
03000 {
03001     if (RulerData.IsRulerOriginClaimed)
03002     {
03003         // release the ruler
03004         RulerData.IsRulerOriginClaimed = FALSE;
03005         // and force a redraw
03006         ForceRulerRedraw();
03007     }
03008 }
03009 
03010 /********************************************************************************************
03011 
03012 >   void TextInfoBarOp::TabStopDragStarting(TabStopDragType TheType)
03013 
03014     Author:     Martin Wuerthner <xara@mw-software.com>
03015     Created:    13/07/06
03016     Purpose:    Called when a tab stop drag starts (allows TextInfoBarOp to hide the implicit
03017                 tab stops to avoid confusion. Otherwise, if the last tab stop was dragged,
03018                 implicit tab stops would appear after the previous tab stop.
03019 
03020 ********************************************************************************************/
03021 
03022 void TextInfoBarOp::TabStopDragStarting(TabStopDragType TheType)
03023 {
03024     RulerData.TabStopDragRunning = TRUE;
03025     RulerData.CurrentDragType = TheType;
03026 }
03027 
03028 /********************************************************************************************
03029 
03030 >   void TextInfoBarOp::TabStopDragFinished()
03031 
03032     Author:     Martin Wuerthner <xara@mw-software.com>
03033     Created:    13/07/06
03034     Purpose:    Called when a tab stop drag finished, allowing TextInfoBarOp to display
03035                 implicit tab stops again.
03036 
03037 ********************************************************************************************/
03038 
03039 void TextInfoBarOp::TabStopDragFinished()
03040 {
03041     TRACEUSER("wuerthne", _T("tab stop drag finished"));
03042     RulerData.TabStopDragRunning = FALSE;
03043 }
03044 
03045 /********************************************************************************************
03046 
03047 >void TextInfoBarOp::HighlightRulerSection(RulerBase* pRuler)
03048 
03049     Author:     Martin Wuerthner <xara@mw-software.com>
03050     Created:    07/07/06
03051     Purpose:    Show the position and width of the current text story on the ruler
03052                 (called from TextTool when the ruler background is redrawn)
03053 
03054 ********************************************************************************************/
03055 
03056 void TextInfoBarOp::HighlightRulerSection(RulerBase* pRuler, UserRect& UpdateRect)
03057 {
03058     if (!pRuler->IsHorizontal()) return;
03059 
03060     // we call RulerBase::HighlightSection, which expects coordinates in user space but
03061     // knows about our tool origin
03062     INT32 SectionEnd = RulerData.CurrentRulerSectionWidth;      // user coord of end of highlight section
03063     if (SectionEnd == -1)
03064     {
03065         // infinite section
03066         SectionEnd = UpdateRect.hi.x;
03067     }
03068     pRuler->HighlightSection(0, SectionEnd);
03069 }
03070 
03071 /********************************************************************************************
03072 
03073 >void TextInfoBarOp::RenderRulerBlobs(RulerBase* pRuler, UserRect& UpdateRect)
03074 
03075     Author:     Martin Wuerthner <xara@mw-software.com>
03076     Created:    07/07/06
03077     Purpose:    Show the margin and tab stop blobs on the ruler
03078                 (called from TextTool when the ruler foreground is redrawn)
03079 
03080 ********************************************************************************************/
03081 
03082 void TextInfoBarOp::RenderRulerBlobs(RulerBase* pRuler, UserRect& UpdateRect)
03083 {
03084     if (!pRuler->IsHorizontal()) return;
03085 
03086     // draw the current tab "button" - we draw this first so the first line indent, if that far left,
03087     // is drawn on top of it
03088     // we want the button to appear to the left of the origin, but at a fixed absolute distance
03089     // no matter what the current zoom factor is, so we need to enquire about the scaled pixel size
03090     // to find out how many MILLIPOINTS one screen pixel represents
03091     DocView* pDocView = pRuler->GetpRulerPair()->GetpDocView();
03092     FIXED16 PixelSize = pDocView->GetScaledPixelWidth();
03093     MILLIPOINT Pos = CurrentTabButtonPos*PixelSize.MakeLong();
03094 
03095     ResourceID id=0;
03096     switch(RulerData.CurrentTabType)
03097     {
03098         case RightTab:
03099             id = _R(crighttab);
03100             break;
03101         case CentreTab:
03102             id = _R(ccenttab);
03103             break;
03104         case DecimalTab:
03105             id = _R(cdectab);
03106             break;
03107         case LeftTab:
03108             id = _R(clefttab);
03109             break;
03110     }
03111     pRuler->DrawBitmap(Pos, id);
03112 
03113     if (!(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragLeftMargin))
03114     {
03115         // not currently dragging the left margin, so display it if it is the same across
03116         // the selection, else show the greyed out margin icon at the origin
03117         if (RulerData.IsLeftMarginValid)
03118             pRuler->DrawBitmap(RulerData.LeftMargin, _R(leftmar));
03119         else
03120             pRuler->DrawBitmap(0, _R(gleftmar));
03121     }
03122 
03123     if (!(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragFirstIndent))
03124     {
03125         if (RulerData.IsFirstIndentValid)
03126             pRuler->DrawBitmap(RulerData.FirstIndent, _R(firstind));
03127         else
03128             pRuler->DrawBitmap(0, _R(gfirstind));
03129     }
03130 
03131     if (RulerData.CurrentRulerSectionWidth != -1
03132         && !(RulerData.TabStopDragRunning && RulerData.CurrentDragType == DragRightMargin))
03133     {
03134         // we only draw a right margin if we have a fixed formatting width
03135         if (RulerData.IsRightMarginValid)
03136             pRuler->DrawBitmap(RulerData.CurrentRulerSectionWidth - RulerData.RightMargin, _R(rightmar));
03137         else
03138             pRuler->DrawBitmap(RulerData.CurrentRulerSectionWidth, _R(grightmar));
03139     }
03140 
03141     if (RulerData.IsRulerValid)
03142     {
03143         MILLIPOINT LastPos = 0;
03144         for (TxtTabStopIterator it = RulerData.pShownRuler->begin(); it != RulerData.pShownRuler->end(); ++it)
03145         {
03146             ResourceID id=0;
03147             switch((*it).GetType())
03148             {
03149                 case LeftTab:
03150                     id = _R(lefttab);
03151                     break;
03152                 case RightTab:
03153                     id = _R(righttab);
03154                     break;
03155                 case CentreTab:
03156                     id = _R(centtab);
03157                     break;
03158                 case DecimalTab:
03159                     id = _R(dectab);
03160                     break;
03161             }
03162             pRuler->DrawBitmap((*it).GetPosition(), id);
03163             LastPos = (*it).GetPosition();
03164         }
03165 
03166         if (!(RulerData.TabStopDragRunning &&
03167               (RulerData.CurrentDragType == DragNew || RulerData.CurrentDragType == DragTabStop)))
03168         {
03169             // draw greyed out left align tab stops at equidistant positions beyond the last defined
03170             // tab stop, but only while we are not dragging
03171             while(LastPos < UpdateRect.hi.x)
03172             {
03173                 LastPos = LastPos + 36000 - (LastPos % 36000);
03174                 // if we have a fixed width text story, do not draw implicit tab stops outside the
03175                 // right hand margin (physical right margin less the logical margin, if present)
03176                 if (RulerData.CurrentRulerSectionWidth != -1
03177                     && LastPos > RulerData.CurrentRulerSectionWidth
03178                                  - (RulerData.IsRightMarginValid ? RulerData.RightMargin : 0))
03179                     break;
03180                 pRuler->DrawBitmap(LastPos, _R(imptab));
03181             }
03182         }
03183     }
03184 }
03185 
03186 /********************************************************************************************
03187 
03188 >   BOOL TextTool::GetRulerStatusLineText(String_256* pText, UserCoord PointerPos,
03189                                           Spread* pSpread, RulerBase* pRuler)
03190 
03191     Author:     Martin Wuerthner <xara@mw-software.com>
03192     Created:    25/07/06
03193     Inputs:     PointerPos  - user coordinates of click on ruler (relative to origin set by tool)
03194                 pSpread     - pointer to spread upon which click occurred
03195                 pRuler      - pointer to ruler which generated click
03196     Outputs:    Status line text written to pText (if returning TRUE)
03197     Returns:    TRUE if the text has been set
03198     Purpose:    Allows us to set the status line text for the ruler
03199 
03200 ********************************************************************************************/
03201 
03202 BOOL TextInfoBarOp::GetRulerStatusLineText(String_256* pText, UserCoord PointerPos,
03203                                            Spread* pSpread, RulerBase* pRuler)
03204 {
03205     if (!pRuler->IsHorizontal()) return FALSE;
03206 
03207     // first of all, check whether we are over the current tab type button
03208     DocView* pDocView = pRuler->GetpRulerPair()->GetpDocView();
03209     MILLIPOINT PixelSize = pDocView->GetScaledPixelWidth().MakeLong();
03210     MILLIPOINT Distance1 = ((CurrentTabButtonPos - CurrentTabButtonWidth/2)*PixelSize);
03211     MILLIPOINT Distance2 = ((CurrentTabButtonPos + CurrentTabButtonWidth/2)*PixelSize);
03212     if (PointerPos.x >= Distance1 && PointerPos.x <= Distance2)
03213     {
03214         return pText->Load(_R(IDS_TEXTTOOL_CURRENTTABHELP));
03215     }
03216 
03217     // otherwise, check whether we are within the highlighted section
03218     if (PointerPos.x >= 0 && (RulerData.CurrentRulerSectionWidth == -1
03219                               || PointerPos.x < RulerData.CurrentRulerSectionWidth))
03220     {
03221         return pText->Load(_R(IDS_TEXTTOOL_RULERHELP));
03222     }
03223     return FALSE;
03224 }
03225 
03226 /********************************************************************************************
03227 
03228 >   BOOL TextInfoBarOp::OnRulerClick(UserCoord PointerPos, ClickType Click, ClickModifiers Mods,
03229                                      Spread* pSpread, RulerBase* pRuler)
03230 
03231     Author:     Martin Wuerthner <xara@mw-software.com>
03232     Created:    07/07/06
03233     Inputs:     PointerPos  - user coordinates of click on ruler (relative to origin set by tool)
03234                 Click       - Type of click enum
03235                 Mods        - Modifier flags struct
03236                 pSpread     - pointer to spread upon which click occurred
03237                 pRuler      - pointer to ruler which generated click
03238     Returns:    TRUE to claim the click
03239     Purpose:    Called when the user has clicked on the ruler and we have claimed it
03240 
03241 ********************************************************************************************/
03242 
03243 BOOL TextInfoBarOp::OnRulerClick(UserCoord PointerPos, ClickType Click, ClickModifiers Mods,
03244                                  Spread* pSpread, RulerBase* pRuler)
03245 {
03246     if (!pRuler->IsHorizontal()) return FALSE;
03247     TRACEUSER("wuerthne", _T("ruler click (%d,%d)"), PointerPos.x, PointerPos.y);
03248 
03249     // check whether the click was within the highlight section
03250     BOOL InHighlightSection = PointerPos.x >= 0
03251         && (RulerData.CurrentRulerSectionWidth == -1
03252             || PointerPos.x < RulerData.CurrentRulerSectionWidth);
03253 
03254     DocView* pDocView = pRuler->GetpRulerPair()->GetpDocView();
03255     MILLIPOINT PixelSize = pDocView->GetScaledPixelWidth().MakeLong();
03256 
03257     BOOL bIsOverTabButton = PointerPos.x >= MILLIPOINT((CurrentTabButtonPos - CurrentTabButtonWidth/2)*PixelSize)
03258                             && PointerPos.x <= MILLIPOINT((CurrentTabButtonPos + CurrentTabButtonWidth/2)*PixelSize);
03259     // treat a double click just as another single click
03260     if (Click == CLICKTYPE_SINGLE || Click == CLICKTYPE_DOUBLE)
03261     {
03262         // check whether the user has clicked on our homegrown "current tab" button
03263         // this is displayed centered around the position CurrentTabButtonPos (in pixels)
03264         MILLIPOINT LeftMarginPos = RulerData.IsLeftMarginValid ? RulerData.LeftMargin : 0;
03265         MILLIPOINT FirstIndentPos = RulerData.IsFirstIndentValid ? RulerData.FirstIndent : 0;
03266         MILLIPOINT RightMarginPos = RulerData.CurrentRulerSectionWidth
03267                                             - (RulerData.IsRightMarginValid ? RulerData.RightMargin : 0);
03268         BOOL bIsOverFirstIndent = PointerPos.x >= FirstIndentPos - MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
03269                                   && PointerPos.x <= FirstIndentPos + MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize);
03270         BOOL bIsOverRightMargin = PointerPos.x >= RightMarginPos - MILLIPOINT(RightMarginBitmapWidth / 2 * PixelSize)
03271                                   && PointerPos.x <= RightMarginPos + MILLIPOINT(RightMarginBitmapWidth / 2 * PixelSize);
03272 
03273         // check whether the user has clicked on our homegrown "current tab" button
03274         // this is displayed centered around the position CurrentTabButtonPos (in pixels)
03275         // NB: we need to make sure that we can still drag the first line indent in case it overlaps, but even
03276         //     in that case, we still treat clicks near the bottom of the ruler as "current tab" button clicks
03277         if (bIsOverTabButton && (!bIsOverFirstIndent || PointerPos.y <= MILLIPOINT(TabBitmapHeight * PixelSize)))
03278         {
03279             // a click on our "current tab" button
03280             if (Mods.Adjust)
03281             {
03282                 // adjust click, so cycle the other way round
03283                 switch(RulerData.CurrentTabType)
03284                 {
03285                     case LeftTab:
03286                         RulerData.CurrentTabType = DecimalTab;
03287                         break;
03288                     case RightTab:
03289                         RulerData.CurrentTabType = LeftTab;
03290                         break;
03291                     case CentreTab:
03292                         RulerData.CurrentTabType = RightTab;
03293                         break;
03294                     case DecimalTab:
03295                         RulerData.CurrentTabType = CentreTab;
03296                         break;
03297                 }
03298             }
03299             else
03300             {
03301                 // standard click, so cycle the type
03302                 switch(RulerData.CurrentTabType)
03303                 {
03304                     case LeftTab:
03305                         RulerData.CurrentTabType = RightTab;
03306                         break;
03307                     case RightTab:
03308                         RulerData.CurrentTabType = CentreTab;
03309                         break;
03310                     case CentreTab:
03311                         RulerData.CurrentTabType = DecimalTab;
03312                         break;
03313                     case DecimalTab:
03314                         RulerData.CurrentTabType = LeftTab;
03315                         break;
03316                 }
03317             }
03318             Document::SetSelectedViewAndSpread(pDocView->GetDoc(), pDocView, pSpread);
03319             DialogManager::DefaultKeyboardFocus();
03320             ForceRulerRedraw();
03321             return TRUE;
03322         }
03323 
03324         // we do allow dragging tab stops outside the highlight section but we do not allow creating
03325         // new ones by clicking outside
03326 
03327         // check whether we have got a tab at the click position - if they overlap, the tab stop
03328         // to the right is on top, so the user expects that to be dragged; therefore, tab stops
03329         // to the right have priority
03330         Document::SetSelectedViewAndSpread(pDocView->GetDoc(), pDocView, pSpread);
03331         
03332         INT32 MatchedIndex = -1;
03333         TxtTabStop DraggedTabStop(RulerData.CurrentTabType, 0);
03334         if (RulerData.IsRulerValid)
03335         {
03336             INT32 Index = 0;
03337             for (TxtTabStopIterator it = RulerData.pShownRuler->begin(); it != RulerData.pShownRuler->end(); ++it)
03338             {
03339                 MILLIPOINT Pos = (*it).GetPosition();
03340                 // we check for the first indent marker being at the same position as the tab - if it is, the
03341                 // vertical position is checked to distinguish between the two. We do not generally check the
03342                 // vertical position because that would mean that dragging slightly too high would create a
03343                 // new tab rather than moving the existing tab.
03344                 if (PointerPos.x >= Pos - MILLIPOINT(TabBitmapWidth / 2 * PixelSize)
03345                     && PointerPos.x <= Pos + MILLIPOINT(TabBitmapWidth / 2 * PixelSize)
03346                     && ((!bIsOverFirstIndent && !bIsOverRightMargin)
03347                         || PointerPos.y <= MILLIPOINT(TabBitmapHeight * PixelSize)))
03348                 {
03349                     TRACEUSER("wuerthne", _T("hit tab no %d"), Index);
03350                     MatchedIndex = Index;
03351                 }
03352                 Index++;
03353             }
03354             
03355             if (MatchedIndex != -1)
03356             {
03357                 // delete the tab stop from the shown ruler list
03358                 Index = MatchedIndex;
03359                 TxtTabStopIterator it = RulerData.pShownRuler->begin();
03360                 while(it != RulerData.pShownRuler->end() && Index--) ++it;
03361                 if (it != RulerData.pShownRuler->end())
03362                 {
03363                     DraggedTabStop = *it;
03364                     RulerData.pShownRuler->erase(it);
03365                 }
03366                 else
03367                 {
03368                     // cannot really happen, but exit gracefully - we still claim the click
03369                     return TRUE;
03370                 }
03371             }
03372         }
03373         TabStopDragType DragType = (MatchedIndex == -1) ? DragNew : DragTabStop;
03374         
03375         if (MatchedIndex == -1)
03376         {
03377             // no tab stop hit, but maybe the margin markers?
03378 
03379             // We test for the left margin first because we check the vertical position to distinguish
03380             // between left margin and first indent drags even when they are at the same position
03381             if (PointerPos.x >= LeftMarginPos - MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
03382                 && PointerPos.x <= LeftMarginPos + MILLIPOINT(LeftMarginBitmapWidth / 2 * PixelSize)
03383                 && PointerPos.y <= MILLIPOINT(LeftMarginBitmapHeight * PixelSize))
03384             {
03385                 TRACEUSER("wuerthne", _T("drag left margin"));
03386                 DragType = DragLeftMargin;
03387             }
03388             else
03389             {
03390                 // we do not check the vertical position for other margin drags - if there was a tab stop
03391                 // at the same position it got priority anyway
03392                 if (bIsOverFirstIndent)
03393                 {
03394                     TRACEUSER("wuerthne", _T("drag first indent"));
03395                     DragType = DragFirstIndent;
03396                 }
03397                 else
03398                 {
03399                     if (bIsOverRightMargin)
03400                     {
03401                         TRACEUSER("wuerthne", _T("drag right margin"));
03402                         DragType = DragRightMargin;
03403                     }
03404                 }
03405             }
03406         }
03407 
03408         if (InHighlightSection || DragType != DragNew)
03409         {
03410             String_256 OpToken(OPTOKEN_TABSTOPDRAG);
03411             TRACEUSER("wuerthne", _T("starting drag"));
03412             TabStopDragOpParam* pParam = new TabStopDragOpParam(DragType, DraggedTabStop, PointerPos);
03413             
03414             if (pRuler->StartToolDrag(Mods, PointerPos, &OpToken, pParam))
03415             {
03416                 // the kernel has accepted the drag request
03417                 TextInfoBarOp::TabStopDragStarting(DragType);
03418                 // force a redraw to show the ruler without the tab stop being dragged (if any)
03419                 // and without implicit tab stops
03420                 TextInfoBarOp::ForceRulerRedraw();
03421             }
03422             else
03423             {
03424                 // we cannot drag, but we need to reinstate the ruler bar (if we tried dragging
03425                 // and existing tab stop, we have removed it from pShownRuler)
03426                 TextInfoBarOp::Update(TRUE);
03427             }
03428             return TRUE;
03429         }
03430     }
03431     // we swallow all other clicks within the highlight section and over the tab button (most notably
03432     // double clicks)
03433     return InHighlightSection || bIsOverTabButton;
03434 }
03435 
03436 /********************************************************************************************
03437 
03438 >void TextInfoBarOp::DoAddTabStop(MILLIPOINT Position)
03439 
03440     Author:     Martin Wuerthner <xara@mw-software.com>
03441     Created:    10/07/06
03442     Inputs:     Position - the position in text ruler space (millipoints)
03443     Purpose:    Create a tab stop of the currently selected type at the given position
03444                 and apply the new text ruler
03445 
03446 ********************************************************************************************/
03447 
03448 void TextInfoBarOp::DoAddTabStop(MILLIPOINT Position)
03449 {
03450     // we create a new ruler attribute
03451     RulerData.pNewRuler = new AttrTxtRuler;
03452     if (RulerData.pNewRuler == NULL) return;
03453 
03454     // copy the ruler contents from the currently shown ruler
03455     *RulerData.pNewRuler->Value.Value = *RulerData.pShownRuler;
03456     RulerData.pNewRuler->Value.AddTabStop(RulerData.CurrentTabType, Position);
03457     // OnFieldChange will use pNewRuler
03458     OnFieldChange(RulerA);
03459     // just to avoid confusion - OnFieldChange has taken control of the object, so
03460     // let us forget about it
03461     RulerData.pNewRuler = NULL;
03462 }
03463 
03464 /********************************************************************************************
03465 
03466 >void TextInfoBarOp::DoAddTabStop(MILLIPOINT Position)
03467 
03468     Author:     Martin Wuerthner <xara@mw-software.com>
03469     Created:    10/07/06
03470     Inputs:     NewTabStop - the tab stop object to add to the ruler
03471     Purpose:    Add a tab stop to the currently displayed ruler and apply it
03472 
03473 ********************************************************************************************/
03474 
03475 void TextInfoBarOp::DoAddTabStop(TxtTabStop NewTabStop)
03476 {
03477     // we create a new ruler attribute
03478     RulerData.pNewRuler = new AttrTxtRuler;
03479     if (RulerData.pNewRuler == NULL) return;
03480 
03481     // copy the ruler contents from the currently shown ruler
03482     *RulerData.pNewRuler->Value.Value = *RulerData.pShownRuler;
03483     RulerData.pNewRuler->Value.AddTabStop(NewTabStop);
03484     // OnFieldChange will use pNewRuler
03485     OnFieldChange(RulerA);
03486     // just to avoid confusion - OnFieldChange has taken control of the object, so
03487     // let us forget about it
03488     RulerData.pNewRuler = NULL;
03489 }
03490 
03491 /********************************************************************************************
03492 
03493 >   void TextInfoBarOp::DoApplyShownRuler()
03494 
03495     Author:     Martin Wuerthner <xara@mw-software.com>
03496     Created:    10/07/06
03497     Purpose:    Apply the currently shown ruler (used to remove a tab stop that has been
03498                 dragged off the ruler - the tab stop is removed from the shown ruler when
03499                 the drag starts, so to permanently delete it all we need to do is apply
03500                 the shown ruler)
03501 
03502 ********************************************************************************************/
03503 
03504 void TextInfoBarOp::DoApplyShownRuler()
03505 {
03506     // we create a new ruler attribute
03507     RulerData.pNewRuler = new AttrTxtRuler;
03508     if (RulerData.pNewRuler == NULL) return;
03509 
03510     // copy the ruler contents from the currently shown ruler
03511     *RulerData.pNewRuler->Value.Value = *RulerData.pShownRuler;
03512     // OnFieldChange will use pNewRuler
03513     OnFieldChange(RulerA);
03514     // just to avoid confusion - OnFieldChange has taken control of the object, so
03515     // let us forget about it
03516     RulerData.pNewRuler = NULL;
03517     // we just applied what we had in pShownRuler, so UpdateRuler() will think that
03518     // nothing has changed and not redraw the ruler - therefore, the caller will have
03519     // to call ForceRulerRedraw(), which is done in TabStopDragOp::DragFinished() below
03520 }
03521 
03522 /********************************************************************************************
03523 
03524 >   void TextInfoBarOp::DoChangeLeftMargin(MILLIPOINT Ordinate)
03525 
03526     Author:     Martin Wuerthner <xara@mw-software.com>
03527     Created:    18/07/06
03528     Inputs:     Ordinate - the new position
03529     Purpose:    Apply the changed left margin
03530 
03531 ********************************************************************************************/
03532 
03533 void TextInfoBarOp::DoChangeLeftMargin(MILLIPOINT Ordinate)
03534 {
03535     // Technically, we could allow the left margin to become negative, i.e., to be located
03536     // to the left of the start of the text object, but this might confuse users, so prevent
03537     // it from happening.
03538     if (Ordinate < 0) Ordinate = 0;
03539     RulerData.IsLeftMarginValid = TRUE;
03540     RulerData.LeftMargin = Ordinate;
03541     OnFieldChange(LeftMarginA);
03542     ForceRulerRedraw();
03543 }
03544 
03545 /********************************************************************************************
03546 
03547 >   void TextInfoBarOp::DoChangeFirstIndent(MILLIPOINT Ordinate)
03548 
03549     Author:     Martin Wuerthner <xara@mw-software.com>
03550     Created:    18/07/06
03551     Inputs:     Ordinate - the new position
03552     Purpose:    Apply the changed first line indent
03553 
03554 ********************************************************************************************/
03555 
03556 void TextInfoBarOp::DoChangeFirstIndent(MILLIPOINT Ordinate)
03557 {
03558     // We allow the firstindent to become negative so hanging bullets are made easy (they would
03559     // otherwise require both the left margin and the first indent to be dragged)
03560     RulerData.IsFirstIndentValid = TRUE;
03561     RulerData.FirstIndent = Ordinate;
03562     OnFieldChange(FirstIndentA);
03563     ForceRulerRedraw();
03564 }
03565 
03566 /********************************************************************************************
03567 
03568 >   void TextInfoBarOp::DoChangeRightMargin(MILLIPOINT Ordinate, BOOL bReset)
03569 
03570     Author:     Martin Wuerthner <xara@mw-software.com>
03571     Created:    18/07/06
03572     Inputs:     Ordinate - the new position
03573     Purpose:    Apply the changed right margin
03574 
03575 ********************************************************************************************/
03576 
03577 void TextInfoBarOp::DoChangeRightMargin(MILLIPOINT Ordinate, BOOL bReset)
03578 {
03579     // the right margin is actually an indent, i.e., an offset from the column width (otherwise
03580     // we could not have a default attribute that makes sense and text objects with different
03581     // widths would have to have different right margin attributes)
03582     RulerData.IsRightMarginValid = TRUE;
03583     RulerData.RightMargin = bReset ? 0 : (RulerData.CurrentRulerSectionWidth - Ordinate);
03584     // Technically, we could allow the margin to become negative, i.e., to be located to the
03585     // right of the column width, but this might confuse users, so prevent it from happening
03586     if (RulerData.RightMargin < 0) RulerData.RightMargin = 0;
03587     OnFieldChange(RightMarginA);
03588     ForceRulerRedraw();
03589 }
03590 
03591 /********************************************************************************************
03592 
03593 >   INT32 TextInfoBarOp::GetLogicalStoryWidth(TextStory* pStory)
03594 
03595     Author:     Martin Wuerthner <xara@mw-software.com>
03596     Created:    10/07/06
03597     Inputs:     pStory - a selected story
03598     Returns:    its logical width in millipoints
03599     Purpose:    Given a text story, find the width we want to display for it in the ruler bar
03600 
03601 ********************************************************************************************/
03602 
03603 INT32 TextInfoBarOp::GetLogicalStoryWidth(TextStory* pStory)
03604 {
03605     if (pStory->IsWordWrapping())
03606     {
03607         // either the width the user set or, if on a path, the length of the path
03608         // minus the left and right indents (as set in TextStory::FormatAndChildren
03609         // when formatting the story)
03610         return pStory->GetStoryWidth();
03611     }
03612     else
03613     {
03614         // text at point - infinite width
03615         return -1;
03616     }
03617 }
03618 
03619 /********************************************************************************************
03620 
03621 >BOOL TextInfoBarOp::UpdateRulerBar()
03622 
03623     Author:     Martin Wuerthner <xara@mw-software.com>
03624     Created:    06/07/06
03625     Inputs:     pSelection - the current selection range
03626                 DoUpdate - if TRUE, always update ruler display even if not changed
03627     Returns:    FALSE if failed
03628     Purpose:    Update the text ruler information shown in the ruler bar according to the
03629                 current selection 
03630                 called on selchange messages 
03631                 only update the ruler bar if something has changed
03632 
03633 ********************************************************************************************/
03634 
03635 BOOL TextInfoBarOp::UpdateRulerBar(SelRange* pSelection, BOOL DoUpdate)
03636 {
03637     BOOL changed = FALSE;
03638 
03639     // first of all, check whether we want to change the ruler origin
03640     BOOL ShouldWeClaimRuler = FALSE;
03641     INT32 RulerOrigin=0;
03642     INT32 StoryWidth=0;
03643     TextStory* pFocusStory = TextStory::GetFocusStory();
03644     if (pFocusStory)
03645     {
03646         // there is a focus story, so the ruler should adapt to it
03647         ShouldWeClaimRuler = TRUE;
03648         // DocRect StoryBounds=pFocusStory->GetBoundingRect();
03649         // DocCoord TopLeft(StoryBounds.lo.x, StoryBounds.hi.y);
03650         const Matrix* pStoryMatrix = pFocusStory->GetpStoryMatrix();
03651         DocCoord TopLeft(0,0);
03652         pStoryMatrix->transform(&TopLeft);
03653         UserCoord UserTopLeft = TopLeft.ToUser(pFocusStory->FindParentSpread());
03654         RulerOrigin = UserTopLeft.x;
03655         StoryWidth = GetLogicalStoryWidth(pFocusStory);
03656     }
03657     else
03658     {
03659         // no focus story, but maybe one or more selected text stories
03660         Node* pNode = pSelection->FindFirst();
03661         while (pNode != NULL)
03662         {
03663             // we might have text nodes selected, so find their text story
03664             while (IS_A(pNode, TextLine) || pNode->IsKindOf(CC_RUNTIME_CLASS(VisibleTextNode)))
03665             {
03666                 pNode = pNode->FindParent();
03667             }
03668             if (IS_A(pNode, TextStory))
03669             {
03670                 TextStory* pStory = (TextStory*)pNode;
03671 
03672                 const Matrix* pStoryMatrix = pStory->GetpStoryMatrix();
03673                 DocCoord TopLeft(0,0);
03674                 pStoryMatrix->transform(&TopLeft);
03675                 UserCoord UserTopLeft = TopLeft.ToUser(pStory->FindParentSpread());
03676                 
03677                 if (!ShouldWeClaimRuler || UserTopLeft.x < RulerOrigin)
03678                 {
03679                     // first found object, or further to the left than previous ones, so use this position
03680                     RulerOrigin = UserTopLeft.x;
03681                     StoryWidth = GetLogicalStoryWidth(pStory);
03682                     ShouldWeClaimRuler = TRUE;
03683                 }
03684             }
03685             pNode = pSelection->FindNext(pNode);
03686         }
03687     }
03688 
03689     if (ShouldWeClaimRuler)
03690     {
03691         if (RulerData.IsRulerOriginClaimed)
03692         {
03693             // we have already claimed the ruler, is it for the same origin?
03694             if (RulerData.CurrentRulerOrigin != RulerOrigin
03695                 || RulerData.CurrentRulerSectionWidth != StoryWidth)
03696             {
03697                 changed = TRUE;
03698             }
03699         }
03700         else
03701         {
03702             changed = TRUE;
03703         }
03704         RulerData.IsRulerOriginClaimed = TRUE;
03705         RulerData.CurrentRulerOrigin = RulerOrigin;     
03706         RulerData.CurrentRulerSectionWidth = StoryWidth;
03707     }
03708     else
03709     {
03710         if (RulerData.IsRulerOriginClaimed)
03711         {
03712             // the ruler bar has been claimed, but we do not want to claim it any more
03713             RulerData.IsRulerOriginClaimed = FALSE;
03714             changed  = TRUE;            // force ruler bar update
03715         }
03716     }
03717 
03718     if (RulerData.IsRulerOriginClaimed)
03719     {
03720         // we are claiming the ruler, so update the values
03721         SelRange::CommonAttribResult result;
03722         NodeAttribute* pAttr;
03723 
03724         // left margin
03725         CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtLeftMargin), 
03726                                              &pAttr,
03727                                              &result);
03728         AttrTxtLeftMargin* pLeftMarginAttrib = (AttrTxtLeftMargin*)pAttr;
03729         
03730         if (result == SelRange::ATTR_MANY)
03731         {
03732             if (RulerData.IsLeftMarginValid) changed = TRUE;
03733             RulerData.IsLeftMarginValid = FALSE;
03734         }
03735         else
03736         {
03737             if (RulerData.IsLeftMarginValid)
03738             {
03739                 if (RulerData.LeftMargin != pLeftMarginAttrib->Value.Value) changed = TRUE;
03740             }
03741             else
03742                 changed = TRUE;
03743             RulerData.IsLeftMarginValid = TRUE;
03744             RulerData.LeftMargin = pLeftMarginAttrib->Value.Value;
03745         }
03746 
03747         // right margin
03748         CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtRightMargin), 
03749                                              &pAttr,
03750                                              &result);
03751         AttrTxtRightMargin* pRightMarginAttrib = (AttrTxtRightMargin*)pAttr;
03752         
03753         if (result == SelRange::ATTR_MANY)
03754         {
03755             if (RulerData.IsRightMarginValid) changed = TRUE;
03756             RulerData.IsRightMarginValid = FALSE;
03757         }
03758         else
03759         {
03760             if (RulerData.IsRightMarginValid)
03761             {
03762                 if (RulerData.RightMargin != pRightMarginAttrib->Value.Value) changed = TRUE;
03763             }
03764             else
03765                 changed = TRUE;
03766             RulerData.IsRightMarginValid = TRUE;
03767             RulerData.RightMargin = pRightMarginAttrib->Value.Value;
03768         }
03769 
03770         // first indent
03771         CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtFirstIndent), 
03772                                              &pAttr,
03773                                              &result);
03774         AttrTxtFirstIndent* pFirstIndentAttrib = (AttrTxtFirstIndent*)pAttr;
03775         
03776         if (result == SelRange::ATTR_MANY)
03777         {
03778             if (RulerData.IsFirstIndentValid) changed = TRUE;
03779             RulerData.IsFirstIndentValid = FALSE;
03780         }
03781         else
03782         {
03783             if (RulerData.IsFirstIndentValid)
03784             {
03785                 if (RulerData.FirstIndent != pFirstIndentAttrib->Value.Value) changed = TRUE;
03786             }
03787             else
03788                 changed = TRUE;
03789             RulerData.IsFirstIndentValid = TRUE;
03790             RulerData.FirstIndent = pFirstIndentAttrib->Value.Value;
03791         }
03792 
03793         // ruler
03794         CommonAttrsToFindSet.FindAttrDetails(CC_RUNTIME_CLASS(AttrTxtRuler), 
03795                                              &pAttr,
03796                                              &result);
03797         AttrTxtRuler* pRulerAttrib = (AttrTxtRuler*)pAttr;
03798         
03799         if (result == SelRange::ATTR_MANY)
03800         {
03801             if (RulerData.IsRulerValid) changed = TRUE;
03802             RulerData.IsRulerValid = FALSE;
03803         }
03804         else
03805         {
03806             if (RulerData.IsRulerValid)
03807             {
03808                 if (*RulerData.pShownRuler != *pRulerAttrib->Value.Value) changed = TRUE;
03809             }
03810             else
03811                 changed = TRUE;
03812             RulerData.IsRulerValid = TRUE;
03813             // use the copy constructor
03814             *RulerData.pShownRuler = *pRulerAttrib->Value.Value;
03815         }
03816     }
03817 
03818     // if anything has changed, force a ruler redraw
03819     if (changed || DoUpdate) ForceRulerRedraw();
03820 
03821     return TRUE;
03822 }
03823 
03824 /********************************************************************************************
03825 
03826 >   static BOOL TabStopDragOp::Init()
03827 
03828     Author:     Martin Wuerthner <xara@mw-software.com>
03829     Created:    12/07/06
03830     Returns:    FALSE if failed
03831     Purpose:    Register the TabStopDragOp operation
03832 
03833 ********************************************************************************************/
03834 
03835 BOOL TabStopDragOp::Init()
03836 {
03837     return RegisterOpDescriptor(0, 
03838                                 0,
03839                                 CC_RUNTIME_CLASS(TabStopDragOp), 
03840                                 OPTOKEN_TABSTOPDRAG,
03841                                 TabStopDragOp::GetState,
03842                                 0,  /* help ID */
03843                                 0,  /* bubble ID */
03844                                 0   /* bitmap ID */);
03845 }
03846 
03847 /********************************************************************************************
03848 
03849 >   TabStopDragOp::TabStopDragOp()
03850 
03851     Author:     Martin Wuerthner <xara@mw-software.com>
03852     Created:    23/07/06
03853     Purpose:    Constructor
03854 
03855 ********************************************************************************************/
03856 
03857 TabStopDragOp::TabStopDragOp(): CursorStackID(TABSTOPDRAG_CURSORID_UNSET),
03858                                 m_pTabCursor(NULL), m_pDelCursor(NULL), m_pParam(NULL)
03859 {
03860 }
03861 
03862 /********************************************************************************************
03863 
03864 >   TabStopDragOp::~TabStopDragOp()
03865 
03866     Author:     Martin Wuerthner <xara@mw-software.com>
03867     Created:    23/07/06
03868     Purpose:    Destructor
03869 
03870 ********************************************************************************************/
03871 
03872 TabStopDragOp::~TabStopDragOp()
03873 {
03874     if (m_pTabCursor) delete m_pTabCursor;
03875     if (m_pDelCursor) delete m_pDelCursor;
03876     if (m_pParam) delete m_pParam;
03877 }
03878 
03879 /********************************************************************************************
03880 
03881 >   static OpState TabStopDragOp::GetState(String_256* Description, OpDescriptor*)
03882 
03883     Author:     Martin Wuerthner <xara@mw-software.com>
03884     Created:    12/07/06
03885     Inputs:     Description = ptr to place description of why this op can't happen
03886                 pOpDesc     = ptr to the Op Desc associated with this op
03887     Returns:    An OpState object
03888     Purpose:    Func for determining the usability of this op
03889 
03890 ********************************************************************************************/
03891 
03892 OpState TabStopDragOp::GetState(String_256* Description, OpDescriptor*)
03893 {
03894     OpState State;
03895     return State;
03896 }
03897 
03898 /********************************************************************************************
03899 
03900 >   void TabStopDragOp::DoWithParam(OpDescriptor *pOpDesc, OpParam* pParam)
03901 
03902     Author:     Martin Wuerthner <xara@mw-software.com>
03903     Created:    12/07/06
03904     Inputs:     pOpDesc = ptr to the Op Desc associated with this op
03905                 pParam = parameter block (dynamically created in TextInfoBarOp::OnRulerClick)
03906     Purpose:    Main entry point of operation.
03907 
03908 ********************************************************************************************/
03909 
03910 void TabStopDragOp::DoWithParam(OpDescriptor *pOpDesc, OpParam* pParam)
03911 {
03912     m_pParam = (TabStopDragOpParam*)pParam;
03913     DoDrag(Document::GetSelectedSpread());
03914 }
03915 
03916 /***********************************************************************************************
03917 
03918 >   void TabStopDragOp::DoDrag(Spread* pThisSpread)
03919 
03920     Author:     Martin Wuerthner <xara@mw-software.com>
03921     Created:    12/07/06
03922     Inputs:     pThisSpread       = ptr to spread drag started in (NULL means get selected spread)
03923                 PointerPos        = coord of point clicked
03924     Purpose:    Starts a drag for a new or existing tab stop
03925         
03926 ***********************************************************************************************/
03927 
03928 void TabStopDragOp::DoDrag(Spread* pThisSpread)
03929 {
03930     TRACEUSER("wuerthne", _T("DoDrag"));
03931     pSpread = pThisSpread;
03932 
03933     if (pSpread == NULL)
03934         pSpread = Document::GetSelectedSpread();
03935 
03936     ERROR3IF(pSpread == NULL,"pSpread == NULL");
03937     if (pSpread == NULL)
03938     {
03939         End();
03940         return;
03941     }
03942 
03943     Ordinate = m_pParam->StartPos.x;
03944     TRACEUSER("wuerthne", _T("starting drag at %d"), Ordinate);
03945 
03946     if (m_pTabCursor != NULL) delete m_pTabCursor;
03947 
03948     ResourceID CursorID = _R(IDCSR_TEXT_LEFTTAB);
03949     switch(m_pParam->DragType)
03950     {
03951         case DragTabStop: case DragNew:
03952             switch(m_pParam->DraggedTabStop.GetType())
03953             {
03954                 case RightTab:
03955                     CursorID = _R(IDCSR_TEXT_RIGHTTAB);
03956                     break;
03957                 case CentreTab:
03958                     CursorID = _R(IDCSR_TEXT_CENTTAB);
03959                     break;
03960                 case DecimalTab:
03961                     CursorID = _R(IDCSR_TEXT_DECTAB);
03962                     break;
03963                 default:
03964                     break;
03965             }
03966             break;
03967         case DragLeftMargin:
03968             CursorID = _R(IDCSR_TEXT_LEFTMAR);
03969             break;
03970         case DragRightMargin:
03971             CursorID = _R(IDCSR_TEXT_RIGHTMAR);
03972             break;
03973         case DragFirstIndent:
03974             CursorID = _R(IDCSR_TEXT_FIRSTIND);
03975             break;
03976         default:
03977             break;
03978     }
03979     m_pTabCursor = new Cursor(TOOLID_TEXT, CursorID);
03980     
03981     if (m_pTabCursor != NULL)
03982         CursorStackID = CursorStack::GPush(m_pTabCursor);
03983     m_TabCursorShown = TRUE;
03984 
03985     // Tell the Dragging system to start a drag operation
03986     // We would like to use DRAGTYPE_DEFERRED here, but unfortunately, that also scrolls
03987     // vertically, which is very much in the way. So, until there is something like
03988     // DRAGTYPE_DEFERRED_HORIZONTAL, disable auto-scrolling.
03989     StartDrag(DRAGTYPE_NOSCROLL);
03990 
03991     // show the mouse follower at the (possibly snapped) starting position
03992     // and update the status text
03993     m_CurrentStatusTextID = 0;
03994     UpdateStatusLineAndPos(&m_pParam->StartPos, pSpread);
03995     // Temporary fix: The status bar does not want to show this message, so at least
03996     // make sure that the text is updated after first mouse move
03997     m_CurrentStatusTextID = 0;
03998 }
03999 
04000 /***********************************************************************************************
04001 
04002 >   DocCoord TabStopDragOp::SnapAndConvert(UserCoord* DragPos, Spread* pSpread, DocView* pDocView)
04003 
04004     Author:     Martin Wuerthner <xara@mw-software.com>
04005     Created:    24/08/06
04006     Inputs:     DragPos - mouse position (in tool coords, i.e., user coords with the tool
04007                 origin applied)
04008                 pSpread - the current spread
04009                 pDocView - the current doc view
04010     Returns:    Snapped spread coordinates (ready for passing to the status line)
04011     Purpose:    Snap the tool-specific coordinates and convert to doc coords
04012 
04013 ***********************************************************************************************/
04014 
04015 DocCoord TabStopDragOp::SnapAndConvert(UserCoord* DragPos, Spread* pSpread, DocView* pDocView)
04016 {
04017     // Snapping is tricky because when snapping to the grid we do not want to snap the
04018     // absolute mouse position but instead our text ruler-specific coordinates, so that
04019     // for instance, a 1mm grid allows us to place tab stops at exact multiples of 1mm,
04020     // irrespective of where the text object happens to be located (it need not be at
04021     // an exact multiple of 1mm). When snapping to a guideline, however, we need to snap
04022     // the absolute position.
04023 
04024     // So, first try guideline snapping
04025     UserCoord AbsoluteDragPos = *DragPos;
04026     AbsoluteDragPos.x += TextInfoBarOp::GetRulerOrigin();
04027     DocCoord VirtualSpreadCoords = AbsoluteDragPos.ToSpread(pSpread);
04028     BOOL Snapped = FALSE;
04029     if (pDocView->GetSnapToGuidesState())
04030         Snapped = pDocView->ForceSnapToGuides(pSpread, &VirtualSpreadCoords, GUIDELINE_VERT);
04031     DocCoord PointerPos = VirtualSpreadCoords;
04032     if (!Snapped)
04033     {
04034         // try grid snapping
04035         // NB - to fool the snapping code we transform our user coords with origin applied
04036         //      to spread coordinates and then let it snap, then we apply the tool origin
04037         //      in the opposite direction, i.e., the origin shift is only applied for the
04038         //      snapping operation and we end up with normal spread coordinates that can
04039         //      be passed to the status line
04040         DocCoord VirtualSpreadCoords = DragPos->ToSpread(pSpread);
04041         if (pDocView->GetSnapToGridState())
04042             pDocView->ForceSnapToGrid(pSpread, &VirtualSpreadCoords);
04043         PointerPos = VirtualSpreadCoords;
04044         PointerPos.x += TextInfoBarOp::GetRulerOrigin();
04045     }
04046     return PointerPos;
04047 }
04048 
04049 /***********************************************************************************************
04050 
04051 >   void TabStopDragOp::UpdateStatusLineAndPos(UserCoord* DragPos, Spread* pSpread)
04052 
04053     Author:     Martin Wuerthner <xara@mw-software.com>
04054     Created:    25/07/06
04055     Inputs:     DragPos - mouse position (in tool coords, i.e., user coords with the tool
04056                 origin applied)
04057                 pSpread - the current spread
04058     Purpose:    Display appropriate status text and update displayed coordinates
04059 
04060 ***********************************************************************************************/
04061 void TabStopDragOp::UpdateStatusLineAndPos(UserCoord* DragPos, Spread* pSpread)
04062 {
04063     DocView *pDocView = DocView::GetCurrent();
04064     DocCoord PointerPos = SnapAndConvert(DragPos, pSpread, pDocView);
04065     StatusLine* pStatusLine=GetApplication()->GetpStatusLine();
04066     if (pStatusLine)
04067     {
04068         // always pass Snap=FALSE otherwise the pointer changes to the "snapped" pointer
04069         pStatusLine->UpdateMousePosAndSnap(&PointerPos, pSpread, pDocView, FALSE);
04070         ResourceID ID = GetStatusLineID();
04071         if (ID != m_CurrentStatusTextID)
04072         {
04073             // put up some status line help
04074             TRACEUSER("wuerthne", _T("Resource ID is %d"), ID);
04075             m_CurrentStatusTextID = ID;
04076             String_256 Str;
04077             if (Str.Load(ID))
04078             {
04079                 TRACEUSER("wuerthne", _T("updating status line %s"), (TCHAR*)Str);
04080                 pStatusLine->UpdateText(&Str, TRUE);
04081             }
04082         }
04083     }
04084 }
04085 
04086 /***********************************************************************************************
04087 
04088 >   ResourceID TabStopDragOp::GetStatusLineID()
04089 
04090     Author:     Martin Wuerthner <xara@mw-software.com>
04091     Created:    25/07/06
04092     Purpose:    Return resource ID appropriate for current drag (and mouse on/off ruler status)
04093 
04094 ***********************************************************************************************/
04095 ResourceID TabStopDragOp::GetStatusLineID()
04096 {
04097     UINT32 IDS = _R(IDS_TEXTTOOL_DRAGTABSTOP);
04098     switch(m_pParam->DragType)
04099     {
04100         case DragLeftMargin:
04101             IDS = _R(IDS_TEXTTOOL_DRAGLEFTMARGIN);
04102             break;
04103         case DragRightMargin:
04104             IDS = _R(IDS_TEXTTOOL_DRAGRIGHTMARGIN);
04105             break;
04106         case DragFirstIndent:
04107             IDS = _R(IDS_TEXTTOOL_DRAGFIRSTINDENT);
04108             break;
04109         case DragTabStop:
04110             if (m_TabCursorShown)
04111                 IDS = _R(IDS_TEXTTOOL_DRAGTABSTOP);
04112             else
04113                 IDS = _R(IDS_TEXTTOOL_DELTABSTOP);
04114             break;
04115         case DragNew:
04116             if (m_TabCursorShown)
04117                 IDS = _R(IDS_TEXTTOOL_CREATETABSTOP);
04118             else
04119                 IDS = _R(IDS_TEXTTOOL_CANCELTABSTOP);
04120             break;
04121     }
04122     return IDS;
04123 }
04124 
04125 /***********************************************************************************************
04126 
04127 >   void TabStopDragOp::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods, Spread*,
04128                                         BOOL bSolidDrag)
04129 
04130     Author:     Martin Wuerthner <xara@mw-software.com>
04131     Created:    23/07/06
04132     Inputs:     PointerPos        = current mouse coords
04133                 ClickMods         = modifiers
04134                 pSpread           = the spread
04135                 bSolidDrag        = whether the drag is solid
04136     Purpose:    Called when the mouse moves during a drag
04137 
04138 ***********************************************************************************************/
04139 
04140 void TabStopDragOp::DragPointerMove(DocCoord PointerPos, ClickModifiers ClickMods, Spread* pSpread,
04141                                     BOOL bSolidDrag)
04142 {
04143     // find out whether we need to change the mouse cursor
04144     if (m_pParam->DragType == DragNew || m_pParam->DragType == DragTabStop)
04145     {
04146         if (IsMouseOverRuler())
04147         {
04148             // the mouse is over the ruler - are we showing the correct "drag tab" cursor?
04149             if (!m_TabCursorShown && m_pTabCursor)
04150             {
04151                 // no, so show it
04152                 CursorStack::GSetTop(m_pTabCursor, CursorStackID);
04153                 m_TabCursorShown = TRUE;
04154             }
04155         }
04156         else
04157         {
04158             // the mouse is not over the ruler - are we showing the correct "delete tab" cursor?
04159             if (m_TabCursorShown)
04160             {
04161                 // no, so show it
04162                 if (!m_pDelCursor)
04163                 {
04164                     m_pDelCursor = new Cursor(TOOLID_TEXT, _R(IDCSR_TEXT_DELTAB));
04165                 }
04166                 if (m_pDelCursor)
04167                 {
04168                     CursorStack::GSetTop(m_pDelCursor, CursorStackID);
04169                     m_TabCursorShown = FALSE;
04170                 }
04171             }
04172         }
04173     }
04174     
04175     // we update the mouse follower - we need to make sure that snapping is done in
04176     // our tool space (i.e., in text ruler coordinates), not in document space
04177     UserCoord UserPos = PointerPos.ToUser(pSpread);
04178     UserPos.x -= TextInfoBarOp::GetRulerOrigin();
04179     UpdateStatusLineAndPos(&UserPos, pSpread);
04180 }
04181 
04182 /***********************************************************************************************
04183 
04184 >   virtual void TabStopDragOp::DragFinished(DocCoord PointerPos, ClickModifiers ClickMods, Spread*,
04185                                              BOOL Success, BOOL bSolidDrag)
04186 
04187     Author:     Martin Wuerthner <xara@mw-software.com>
04188     Created:    12/07/06
04189     Inputs:     PointerPos = coord of the pointer
04190                 ClickMods  = info on the click modifiers
04191                 pSpread    = ptr to spread (not used)
04192                 Success    = TRUE if drag ended successfully, FALSE if drag terminated (by pressing Escape)
04193     Purpose:    Responds to the drag of a tab stop ending
04194         
04195 ***********************************************************************************************/
04196 
04197 void TabStopDragOp::DragFinished(DocCoord PointerPos, ClickModifiers ClickMods, Spread* pSpread, BOOL Success,
04198                                  BOOL bSolidDrag)
04199 {
04200     TRACEUSER("wuerthne", _T("tab stop drag ended"));
04201 
04202     TextInfoBarOp::TabStopDragFinished();
04203     if (Success)
04204     {
04205         DocView *pDocView = DocView::GetCurrent();
04206 
04207         // we need to snap in tool space, i.e., text ruler space
04208         UserCoord UserPos = PointerPos.ToUser(pSpread);
04209         UserPos.x -= TextInfoBarOp::GetRulerOrigin();
04210         DocCoord SnappedPointerPos = SnapAndConvert(&UserPos, pSpread, pDocView);
04211         // the returned coordinate is in spread coords
04212         UserPos = SnappedPointerPos.ToUser(pSpread);
04213         Ordinate = UserPos.x - TextInfoBarOp::GetRulerOrigin();
04214         TRACEUSER("wuerthne", _T("with success at %d"), Ordinate);
04215         
04216         switch(m_pParam->DragType)
04217         {
04218             case DragNew:
04219                 if (IsMouseOverRuler())
04220                 {
04221                     TextInfoBarOp::DoAddTabStop(Ordinate);
04222                 }
04223                 // if the mouse is not over the ruler, we simply refrain from adding a tab stop
04224                 // so there is nothing to do
04225                 break;
04226             case DragTabStop:
04227                 if (IsMouseOverRuler())
04228                 {
04229                     TxtTabStop NewTabStop(m_pParam->DraggedTabStop);
04230                     NewTabStop.SetPosition(Ordinate);
04231                     TextInfoBarOp::DoAddTabStop(NewTabStop);
04232                 }
04233                 else
04234                 {
04235                     // delete the dragged tab stop; we can do that by simply applying the shown
04236                     // ruler - we have removed the tab stop from the shown ruler when the
04237                     // drag started
04238                     TextInfoBarOp::DoApplyShownRuler();
04239                 }
04240                 break;
04241             case DragLeftMargin:
04242                 // dragged off the ruler means reset to 0
04243                 if (!IsMouseOverRuler()) Ordinate = 0;
04244                 TextInfoBarOp::DoChangeLeftMargin(Ordinate);
04245                 break;
04246             case DragFirstIndent:
04247                 // dragged off the ruler means reset to 0
04248                 if (!IsMouseOverRuler()) Ordinate = 0;
04249                 TextInfoBarOp::DoChangeFirstIndent(Ordinate);
04250                 break;
04251             case DragRightMargin:
04252                 // dragged off the ruler means reset the right margin to the physical width of the object
04253                 TextInfoBarOp::DoChangeRightMargin(Ordinate, !IsMouseOverRuler());
04254                 break;
04255         }
04256     }
04257     // in any case, we redraw the ruler - this is necessary if the drag was aborted, too, because
04258     // we want to restore the dragged tab stop or margin marker and we also want to restore the
04259     // implicit tab stops
04260     TextInfoBarOp::ForceRulerRedraw();
04261     // End the Drag
04262     EndDrag();
04263 
04264     // Restore cursor
04265     if (CursorStackID != TABSTOPDRAG_CURSORID_UNSET)
04266     {
04267         CursorStack::GPop(CursorStackID);
04268         CursorStackID = TABSTOPDRAG_CURSORID_UNSET;
04269     }
04270 
04271     if (m_pTabCursor != NULL)
04272     {
04273         delete m_pTabCursor;
04274         m_pTabCursor = NULL;
04275     }
04276     if (m_pDelCursor != NULL)
04277     {
04278         delete m_pDelCursor;
04279         m_pDelCursor = NULL;
04280     }
04281     if (m_pParam != NULL)
04282     {
04283         delete m_pParam;
04284         m_pParam = NULL;
04285     }
04286     
04287     End();
04288 }
04289 
04290 /***********************************************************************************************
04291 
04292 >   BOOL TabStopDragOp::IsMouseOverRuler()
04293 
04294     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
04295     Created:    12/9/95
04296     Returns:    TRUE if mouse is over a ruler, FALSE otherwise
04297     Purpose:    Test to see where the mouse pointer is.
04298                 It will return TRUE if the mouse is over either ruler, or the origin gadget.
04299     SeeAlso:    OpGuideline::IsMouseOverRuler() - copied from there
04300         
04301 ***********************************************************************************************/
04302 
04303 BOOL TabStopDragOp::IsMouseOverRuler()
04304 {
04305     DocView* pDocView = DocView::GetSelected();
04306     if (pDocView != NULL)
04307     {
04308         CCamView* pCCamView = pDocView->GetConnectionToOilView();
04309         return (pCCamView->IsMouseOverRuler() != OVER_NO_RULERS);
04310     }
04311 
04312     return FALSE;
04313 }

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