colpick.cpp

Go to the documentation of this file.
00001 // $Id: colpick.cpp 1350 2006-06-22 13:20:47Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // colpick.cpp - Colour picker dialogue
00100 
00101 /*
00102 */
00103 
00104 
00105 #include "camtypes.h"
00106 
00107 #include "dlgmgr.h"
00108 #include "colcontx.h"
00109 #include "coldlog.h"
00110 #include "collist.h"
00111 #include "colormgr.h"
00112 #include "colourix.h"
00113 #include "colpick.h"
00114 //#include "convert.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "scunit.h"
00116 #include "ctrlhelp.h"
00117 //#include "jason.h"
00118 //#include "reshlpid.h"
00119 //#include "richard3.h"
00120 //#include "ed.h"
00121 
00122 wxSize ColourPicker::s_LastSize = wxDefaultSize;
00123 wxSize ColourPicker::s_UserSize = wxSize(245,245);
00124 wxSize ColourPicker::s_MinSize = wxSize(180,100);
00125 BOOL ColourPicker::s_InColourDialogLayout = FALSE;
00126 BOOL ColourPicker::s_JustCreated = FALSE;
00127 INT32 ColourPicker::s_IdleCounter = 0;
00128 
00129 CC_IMPLEMENT_MEMDUMP(ColourPicker, CCObject)
00130 
00131 #define new CAM_DEBUG_NEW
00132 
00133 
00134 // The colour picker can supply two types of picker - the standard OS picker
00135 // or a special Camelot picker. The latter allows true editing of colours in
00136 // several colour models, while the former may (does under windows) force the
00137 // colour to RGB or something. The OS picker is included so a) finikity users
00138 // can use a crap picker if they are shy of meeting new dialogues, and b) so
00139 // we can pick new colours/edit existing colours without having to wait for
00140 // a complete picker implementation to roll up...
00141 //static BOOL UseOSPicker = FALSE;
00142 
00143 
00144 // Static buffer for storing bubble help from the colour editor's picker area
00145 // until the bubble-help callback mechanism is called back.
00146 static String_128 PickerBubbleBuffer("");
00147 static String_256 StatusHelpBuffer("");
00148 
00149 
00150 /********************************************************************************************
00151 
00152 >   ColourPicker::ColourPicker()
00153 
00154     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00155     Created:    13/5/94
00156     Inputs:     -
00157     Outputs:    -
00158     Returns:    -
00159     Purpose:    Creates a colourpicker object
00160     Scope:      private
00161     Errors:     -
00162     SeeAlso:    -
00163 
00164 ********************************************************************************************/
00165 
00166 ColourPicker::ColourPicker()
00167 {
00168 }
00169 
00170 
00171 
00172 /********************************************************************************************
00173 
00174 >   ColourPicker::~ColourPicker()
00175 
00176     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    13/5/94
00178     Inputs:     -
00179     Outputs:    -
00180     Returns:    -
00181     Purpose:    Destructor for a Colour Picker
00182     Scope:      private
00183     Errors:     -
00184     SeeAlso:    -
00185 
00186 ********************************************************************************************/
00187 
00188 ColourPicker::~ColourPicker()
00189 {
00190 }
00191 
00192 
00193 /********************************************************************************************
00194 
00195 >   static INT32 ColourValueToByte(const ColourValue &Col)
00196 
00197     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00198     Created:    13/5/94
00199     Inputs:     -
00200     Outputs:    -
00201     Returns:    -
00202     Purpose:    Converts a ColourValue (0.0 to 1.0) into a byte (0..255) with clipping
00203                 to handle out-of-gamut values.
00204 
00205     Notes:      This function is not as efficient as it could be. If it ever becomes
00206                 critical in any way, it should be optimised. See comments in the function.
00207 
00208     Scope:      private
00209     Errors:     -
00210     SeeAlso:    -
00211 
00212 ********************************************************************************************/
00213 /*
00214     === This code has been rewritten to use centralised functions. It is UNTESTED ===
00215 
00216 static INT32 ColourValueToByte(const ColourValue &Col)
00217 {
00218     // We want to use the centralised ColourContext::PackColour function to do this for us
00219     // However, it's protected. The easiest way of accessing the functionality is to
00220     // create a DocColour containing the value, then read back the 0..255 value.
00221     // This is more work than strictly necessary, but then again, this function is non critical.
00222 
00223     DocColour Dummy(Col, Col, Col);
00224 
00225     INT32 Red;
00226     INT32 Green;
00227     INT32 Blue;
00228     Dummy.GetRGBValue(&Red, &Green, &Blue);
00229 
00230     return(Red);
00231 }
00232 */
00233 
00234 
00235 /********************************************************************************************
00236 
00237 >   BOOL ColourPicker::EditColour(ColourList *ParentList, IndexedColour *SourceAndResult,
00238                                     BOOL PreferLineColour = FALSE)
00239 
00240     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00241     Created:    13/5/94
00242     Inputs:     ParentList - The list in which the colour resides
00243                     May be NULL if you want to just show the picker for whatever
00244                     local colour is appropriate.
00245                     SourceAndResult must also be NULL in this case
00246 
00247                 SourceAndResult - The colour to be edited. If the user changes
00248                 the colour, this will be set to the new definition.
00249                     May be NULL if you want to just show the picker for whatever
00250                     local colour is appropriate.
00251                     ParentList must also be NULL in this case
00252 
00253                 PreferLineColour - TRUE if you'd like to edit line colours rather than
00254                 fill colours in local mode, FALSE to edit fill colours. This flag is
00255                 ignored unless ParentList == SourceAndResult == NULL. (Implementation
00256                 note: This calls ColourEditDlg::ForceLineOrFillMode)
00257 
00258     Outputs:    -
00259     Returns:    -
00260     Purpose:    The main colour picker function. Given an IndexedColour, sets up
00261                 a colour picker showing that colour, allows the user to edit it,
00262                 and returns the new colour in said IndexedColour. If the colour is
00263                 changed, an appropriate ColourChangingMsg will be broadcast.
00264 
00265     Notes:      The IndexedColour is actually copied into another for editing. The
00266                 change, if OK'd is then applied using the ColourManager::ChangeColour
00267                 function, which provides an undo record of the event.
00268 
00269     Scope:      private
00270     Errors:     -
00271     SeeAlso:    ColourEditDlg::InvokeDialog
00272 
00273 ********************************************************************************************/
00274 
00275 void ColourPicker::EditColour(ColourList *ParentList, IndexedColour *SourceAndResult,
00276                                 BOOL PreferLineColour)
00277 {
00278 #if FALSE
00279 /*
00280 // **** DEBUG - use Windows Picker if SHIFT NOT held down on entry,
00281 //              else use the Camelot Picker
00282     if (ForceNativePicker)
00283         UseOSPicker = TRUE;
00284     else
00285         UseOSPicker = (::GetAsyncKeyState(CAMKEY(SHIFT)) & 0x8000) ? TRUE : FALSE;
00286 // ****
00287     if (UseOSPicker)
00288     {
00289         IndexedColour *UndoBuffer = new IndexedColour(*SourceAndResult);
00290         if (UndoBuffer == NULL)     // Fail gracefully. Well... Don't crash, anyway
00291             return;
00292 
00293         ColourGeneric *TheColour = UndoBuffer->SourceColourPtr();
00294 
00295         Document *ScopeDoc = Document::GetSelected();
00296         if (ScopeDoc == NULL)
00297             return;
00298 
00299         ColourContext *ccRGB = ScopeDoc->GetDefaultColourContexts()->Context[COLOURMODEL_RGBT];
00300         ENSURE(ccRGB != NULL, "Default RGBT context can't be found!");
00301 
00302         ColourContext *ccSource = ScopeDoc->GetDefaultColourContexts()->Context[UndoBuffer->GetColourModel()];
00303         if (ccSource == NULL)
00304         {
00305             ENSURE(FALSE, "Unsupported source colour context - I can't edit that colour");
00306             return;
00307         }
00308 
00309         // Convert the given colour into RGB, using 'pure' contexts (logical rather than physica
00310         // conversion, i.e. no colour correction en-route)
00311         ColourRGBT TheColourRGB;
00312         ccRGB->ConvertColour(ccSource, TheColour, (ColourGeneric *) &TheColourRGB);
00313 
00314 
00315         // Now set up, and call the Windows colour picker to edit the colour...
00316         CHOOSECOLOR cc;
00317 
00318         // Set initial colour for the colour picker to use
00319         cc.rgbResult = RGB( ColourValueToByte(TheColourRGB.Red),
00320                             ColourValueToByte(TheColourRGB.Green),
00321                             ColourValueToByte(TheColourRGB.Blue) );
00322 
00323 
00324         // Set the default set of available colours (a greyscale for the time being)
00325         // (it is static so that if the user changes any of the colours they will get
00326         // the changed palette back next time around)
00327         static COLORREF acrCustClr[16] =
00328             {
00329                 RGB(255, 255, 255), RGB(239, 239, 239),
00330                 RGB(223, 223, 223), RGB(207, 207, 207),
00331                 RGB(191, 191, 191), RGB(175, 175, 175),
00332                 RGB(159, 159, 159), RGB(143, 143, 143),
00333                 RGB(127, 127, 127), RGB(111, 111, 111),
00334                 RGB(95, 95, 95),    RGB(79, 79, 79),
00335                 RGB(63, 63, 63),    RGB(47, 47, 47),
00336                 RGB(31, 31, 31),    RGB(15, 15, 15)
00337             };
00338 
00339         cc.lStructSize = sizeof(CHOOSECOLOR);
00340         cc.hwndOwner = AfxGetApp()->m_pMainWnd->m_hWnd; // 'owner' window
00341         cc.lpCustColors = (LPDWORD) acrCustClr;         // List of default colours
00342         cc.Flags = CC_RGBINIT | CC_FULLOPEN;            // Use cc.rgbResult to init picker...
00343                                                         // and picker appears fully opened - Geez that
00344                                                         // 'define wossnames' button is a pain in the butt!!!
00345 
00346         if (ChooseColor(&cc))       // Invoke Windows colour picker (if it qualifies as a colour picker!)
00347         {
00348             // User chose a colour and hit OK - read out the return value (always RGB)
00349             UndoBuffer->SetSourceColourModel(COLOURMODEL_RGBT);
00350             ((ColourRGBT *)TheColour)->Red   = ((double) GetRValue(cc.rgbResult)) / 256.0;
00351             ((ColourRGBT *)TheColour)->Green = ((double) GetGValue(cc.rgbResult)) / 256.0;
00352             ((ColourRGBT *)TheColour)->Blue  = ((double) GetBValue(cc.rgbResult)) / 256.0;
00353             ((ColourRGBT *)TheColour)->Transparent = 0;
00354 
00355             Document::GetSelected()->SetCurrent();      // Make this document the current one
00356 
00357             // This swallows UndoBuffer into the undo system - we must NOT delete it
00358             ColourManager::ChangeColour(ParentList, UndoBuffer, SourceAndResult);
00359         }
00360         else
00361             delete UndoBuffer;  // UndoBuffer not used - delete it
00362     }
00363     else
00364 */
00365 #endif
00366     {
00367 #ifndef STANDALONE
00368         // If we are asking to edit an appropriate local colour, state our preference
00369         // for either fill or line colour.
00370         if (SourceAndResult == NULL)
00371             ColourEditDlg::ForceLineOrFillMode(PreferLineColour);
00372 
00373         ColourEditDlg::InvokeDialog(ParentList, SourceAndResult);
00374 #endif
00375     }
00376 }
00377 
00378 
00379 
00380 /********************************************************************************************
00381 
00382 >   static BOOL ColourPicker::GetStatusLineText(ColourEditDlg *Editor, UINT32 GadgetID,
00383                                                     String_256 *Result)
00384 
00385     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00386     Created:    25/5/95
00387 
00388     Inputs:     Editor - points to the current editor
00389                 GadgetID - indicates the gadget for which you desire help
00390 
00391     Outputs:    If return value is TRUE, Result is updated with an appropriate help string
00392 
00393     Returns:    TRUE if it changed Result, FALSE if it can offer no help
00394 
00395     Purpose:    Bodge to get around the fact that DialogOps don't plug into the status
00396                 line help system. Returns help for the colour editor. Must go via the
00397                 winoil, as we have to read the mouse position and find the window it's in.
00398 
00399     SeeAlso:    ColourEditDlg::GetStatusLineText
00400 
00401 ********************************************************************************************/
00402 
00403 BOOL ColourPicker::GetStatusLineText(ColourEditDlg *Editor, UINT32 GadgetID, String_256 *Result)
00404 {
00405 #ifndef STANDALONE
00406 
00407     IndexedColour *Bob = Editor->EditingColour;
00408     if (Bob == NULL)
00409     {
00410         *Result = String_256(_R(IDS_EDITST_NOCOLOUR));
00411         return(TRUE);
00412     }
00413 
00414     ColourContext *cc = ColourContext::GetGlobalDefault(ColourEditDlg::DisplayModel);
00415 
00416     // Set the default help
00417     *Result = String_256(_R(IDS_EDITST_DEFAULT));
00418 
00419     if (FALSE) {}
00420 //  else if (GadgetID == _R(IDCANCEL))
00421 //  {
00422 //      *Result = String_256(_R(IDS_EDITST_CANCEL));
00423 //  }
00424     else if (GadgetID == _R(IDC_EDIT_DROPMENU))
00425     {
00426         *Result = String_256(_R(IDS_EDITST_MENU));
00427     }
00428     else if (GadgetID == _R(IDC_EDIT_COMPONENT1))
00429     {
00430         if (ColourEditDlg::DisplayModel == COLOURMODEL_HSVT)
00431         {
00432             *Result = String_256(_R(IDS_EDITST_COMP1));
00433         }
00434         else
00435         {
00436             if (cc != NULL)
00437             {
00438                 String_64 CompName;
00439                 cc->GetComponentName(1, &CompName, TRUE);
00440                 Result->MakeMsg(_R(IDS_EDITST_COMP234), (TCHAR *)CompName);
00441             }
00442         }
00443     }
00444     else if (GadgetID == _R(IDC_EDIT_COMPONENT2))
00445     {
00446         if (cc != NULL)
00447         {
00448             String_64 CompName;
00449             cc->GetComponentName(2, &CompName, TRUE);
00450             Result->MakeMsg(_R(IDS_EDITST_COMP234), (TCHAR *)CompName);
00451         }
00452     }
00453     else if (GadgetID == _R(IDC_EDIT_COMPONENT3))
00454     {
00455         if (cc != NULL)
00456         {
00457             String_64 CompName;
00458             cc->GetComponentName(3, &CompName, TRUE);
00459             Result->MakeMsg(_R(IDS_EDITST_COMP234), (TCHAR *)CompName);
00460         }
00461     }
00462 // WEBSTER - markn 14/12/96
00463 #ifndef WEBSTER
00464     else if (GadgetID == _R(IDC_EDIT_COMPONENT4))
00465     {
00466         if (cc != NULL)
00467         {
00468             String_64 CompName;
00469             cc->GetComponentName(4, &CompName, TRUE);
00470             Result->MakeMsg(_R(IDS_EDITST_COMP234), (TCHAR *)CompName);
00471         }
00472     }
00473     else if (GadgetID == _R(IDC_EDIT_COLMODEL))
00474     {
00475         *Result = String_256(_R(IDS_EDITST_COLMODEL));
00476     }
00477     else if (GadgetID == _R(IDC_EDIT_NAMEMENU))
00478     {
00479         *Result = String_256(_R(IDS_EDITST_NAME));
00480     }
00481     else if (GadgetID == _R(IDC_EDIT_COLTYPE))
00482     {
00483         *Result = String_256(_R(IDS_EDITST_COLTYPE));
00484     }
00485     else if ((GadgetID == _R(IDC_EDIT_INHERIT1)) ||
00486              (GadgetID == _R(IDC_EDIT_INHERIT2)) ||
00487              (GadgetID == _R(IDC_EDIT_INHERIT3)) ||
00488              (GadgetID == _R(IDC_EDIT_INHERIT4)))
00489     {
00490         *Result = String_256(_R(IDS_EDITST_INHERIT));
00491     }
00492 //  else if ((GadgetID == _R(IDC_EDIT_PATCH)) ||
00493 //           (GadgetID == _R(IDC_EDIT_PARENTPATCH)))
00494 //  {
00495 //      *Result = String_256(_R(IDS_EDITST_PARENTPATCH));
00496 //  }
00497     else if ((GadgetID == _R(IDC_EDIT_PARENTCOL)) ||
00498              (GadgetID == _R(IDC_EDIT_PARENTNAME)))
00499     {
00500         *Result = String_256(_R(IDS_EDITST_PARENTCOL));
00501     }
00502     else if ((GadgetID == _R(IDC_EDIT_TINT)) ||
00503              (GadgetID == _R(IDC_EDIT_TINTSLIDER)))
00504     {
00505         if (Bob->GetType() == COLOURTYPE_TINT && !Bob->TintIsShade())
00506             *Result = String_256(_R(IDS_EDITST_TINT1));     // It's a tint
00507         else
00508             *Result = String_256(_R(IDS_EDITST_TINT2));     // It's a shade
00509     }
00510     else if (GadgetID == _R(IDC_EDIT_SHADE))
00511     {
00512         *Result = String_256(_R(IDS_EDITST_TINT2));         // It's a shade
00513     }
00514     else if (GadgetID == _R(IDC_EDIT_ADVANCED))
00515     {
00516         if (Editor->Folded)
00517             *Result = String_256(_R(IDS_EDITST_ADVANCED1));
00518         else
00519             *Result = String_256(_R(IDS_EDITST_ADVANCED2));
00520     }
00521     else if (GadgetID == _R(IDC_EDIT_3D))
00522     {
00523         *Result = String_256(_R(IDS_EDITST_3D));
00524     }
00525     else if (GadgetID == _R(IDC_EDIT_MAKESTYLE))
00526     {
00527         *Result = String_256(_R(IDS_EDITST_MAKESTYLE));
00528     }
00529 #endif // WEBSTER
00530     else if (GadgetID == _R(IDC_EDIT_PICKER))
00531     {
00532         if (!StatusHelpBuffer.IsEmpty())
00533             *Result = StatusHelpBuffer;
00534         else
00535         {
00536             switch(Bob->GetType())
00537             {
00538             // WEBSTER - markn 14/12/96
00539             #ifndef WEBSTER
00540                 case COLOURTYPE_TINT:
00541                     if (Editor->Folded)
00542                         *Result = String_256(_R(IDS_EDITST_PICKER1));
00543                     else
00544                         *Result = String_256(_R(IDS_EDITST_PICKER2));
00545                     break;
00546 
00547                 case COLOURTYPE_LINKED:
00548                     *Result = String_256(_R(IDS_EDITST_PICKER3));
00549                     break;
00550             #endif // WEBSTER
00551 
00552                 case COLOURTYPE_NORMAL:
00553                 case COLOURTYPE_SPOT:
00554                 default:
00555                     *Result = String_256(_R(IDS_EDITST_PICKER4));
00556                     break;
00557             }
00558         }
00559     }   
00560     else if (GadgetID == _R(IDC_EDIT_216ONLY))
00561     {
00562         *Result = String_256(_R(IDS_EDITST_216ONLY));
00563     }   
00564     else if (GadgetID == _R(IDC_COLOURPICKER))
00565     {
00566         *Result = String_256(_R(IDS_STATICCOLOURPICKERTOOLHELP));
00567     }
00568     else if (GadgetID == _R(IDC_MAKE_LOCAL))
00569     {
00570         *Result = String_256(_R(IDS_EDITST_MAKE_LOCAL));
00571     }
00572     else if (GadgetID == _R(IDC_EDIT_NOCOLOUR))
00573     {
00574         *Result = String_256(_R(IDS_EDITST_SETNOCOLOUR));
00575     }
00576     else if (GadgetID == _R(IDC_EDIT_RENAME))
00577     {
00578         *Result = String_256(_R(IDS_EDITST_RENAME));
00579     }
00580     else if (GadgetID == _R(IDC_EDIT_LINEFILL))
00581     {
00582         *Result = String_256(_R(IDS_EDITST_LINEFILL));
00583     }
00584 #endif
00585     return(TRUE);
00586 }
00587 
00588 
00589 
00590 /********************************************************************************************
00591 
00592 >   static BOOL ColourPicker::GetStatusLineText(String_256 *Result)
00593 
00594     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00595     Created:    25/5/95
00596 
00597     Outputs:    If return value is TRUE, Result is updated with an appropriate help string
00598 
00599     Returns:    TRUE if it changed Result, FALSE if it can offer no help
00600 
00601     Purpose:    Bodge to get around the fact that DialogOps don't plug into the status
00602                 line help system. Returns help for the colour editor. Must go via the
00603                 winoil, as we have to read the mouse position and find the window it's in.
00604 
00605     Notes:      This is a huge bodge:
00606                     1) DialogOp should do this for us
00607                     2) I'm on holiday in a day's time, I don't have time to do it properly
00608                     3) It only gives help for the picker control because I can't work out
00609                         a quick & easy way ofgetting WindowID and GadgetID
00610 
00611     SeeAlso:    ColourEditDlg::GetStatusLineText
00612 
00613 ********************************************************************************************/
00614 
00615 #ifndef STANDALONE
00616 static UINT32 GadgetList[] = 
00617     {
00618 //      IDCANCEL,
00619         _R(IDC_EDIT_DROPMENU),
00620         _R(IDC_EDIT_COMPONENT1),
00621         _R(IDC_EDIT_COMPONENT2),
00622         _R(IDC_EDIT_COMPONENT3),
00623         _R(IDC_EDIT_COMPONENT4),
00624         _R(IDC_EDIT_COLMODEL),
00625         _R(IDC_EDIT_NAMEMENU),
00626         _R(IDC_EDIT_COLTYPE),
00627         _R(IDC_EDIT_INHERIT1),
00628         _R(IDC_EDIT_INHERIT2),
00629         _R(IDC_EDIT_INHERIT3),
00630         _R(IDC_EDIT_INHERIT4),
00631         _R(IDC_EDIT_PICKER),
00632         _R(IDC_EDIT_PATCH),
00633         _R(IDC_EDIT_PARENTPATCH),
00634         _R(IDC_EDIT_PARENTCOL),
00635         _R(IDC_EDIT_TINT),
00636         _R(IDC_EDIT_SHADE),
00637         _R(IDC_EDIT_ADVANCED),
00638         _R(IDC_EDIT_PARENTNAME),
00639 //      _R(IDC_EDIT_TINTSLIDER),
00640 //      _R(IDC_EDIT_PICKERBORDER),
00641         _R(IDC_EDIT_3D),
00642         _R(IDC_EDIT_MAKESTYLE),
00643 
00644         _R(IDC_EDIT_NOCOLOUR),
00645         _R(IDC_EDIT_LINEFILL),
00646         _R(IDC_EDIT_216ONLY),
00647         _R(IDC_MAKE_LOCAL),
00648         _R(IDC_EDIT_RENAME),
00649         _R(IDC_COLOURPICKER),
00650         0
00651     };
00652 #endif
00653 
00654 
00655 BOOL ColourPicker::GetStatusLineText(String_256 *Result)
00656 {
00657 #ifndef STANDALONE
00658 
00659     ERROR3IF(Result == NULL, "Illegal NULL param");
00660     
00661     ColourEditDlg *Editor = ColourEditDlg::TheEditor;
00662     if (Editor == NULL)
00663         return(FALSE);
00664 
00665     // Find the main editor window
00666     CWindowID TheWindow = (CWindowID)Editor->WindowID;
00667     if (TheWindow == NULL)
00668         return(FALSE);
00669 
00670     wxPoint mousepos = ::wxGetMousePosition();
00671     wxWindow * window=::wxChildWindowFromPoint(TheWindow, mousepos, FALSE, -1);
00672     if ((!window) || (window!=::wxChildWindowFromPoint(mousepos, FALSE, -1))) // second check to ensure it is not obscured
00673         return FALSE;
00674 
00675     return GetStatusLineText(Editor, window->GetId(), Result);
00676 #else
00677     return(TRUE);
00678 #endif
00679 }
00680 
00681 
00682 
00683 /********************************************************************************************
00684 
00685 >   TCHAR *ColourPicker::HelpCallbackHandler(CWindowID Window, UINT32 Item, void *UserData)
00686 
00687     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00688     Created:    27/9/95
00689 
00690     Inputs:     Window - identifies the window to get help for
00691                 Item   - identifies the control to get help for
00692                 UserData - User-supplied data (not used)
00693 
00694     Returns:    The bubble help string to use, or NULL if no help is available
00695 
00696     Purpose:    Help callback handler to provide bubble help for the colour editor
00697 
00698     SeeAlso:    ColourPicker::UpdateBubbleHelpAndPointer
00699 
00700 ********************************************************************************************/
00701 
00702 TCHAR *ColourPicker::HelpCallbackHandler(CWindowID Window, UINT32 Item, void *UserData)
00703 {
00704 #ifndef STANDALONE
00705     static String_256 HelpStringStore;
00706     BOOL ReturnVal = FALSE;
00707 
00708     ColourEditDlg *Editor = ColourEditDlg::TheEditor;
00709     if (Editor == NULL)
00710         return(NULL);
00711 
00712     IndexedColour *Bob = Editor->EditingColour;
00713 
00714     ColourContext *cc = NULL;
00715     if (Bob != NULL)
00716         cc = ColourContext::GetGlobalDefault(ColourEditDlg::DisplayModel);
00717 
00718     if (FALSE) {}
00719     else if (Item == _R(IDC_EDIT_DROPMENU))
00720     {
00721         HelpStringStore = String_256(_R(IDS_EDITBH_MENU));
00722         ReturnVal = TRUE;
00723     }
00724     else if ((Item == _R(IDC_EDIT_PATCH1))  ||  // Fake ID for current colour patch to give it a unique ID
00725              (Item == _R(IDC_EDIT_PATCH2)) ||   // Fake ID for current colour patch to give it a unique ID
00726              (Item == _R(IDC_EDIT_PATCH)) ||
00727              (Item == _R(IDC_EDIT_PICKER)))
00728     {
00729         // NOTE: This gives help for "Original/Current colour" patch
00730         // We will only get called for this if it is necessary (pointer in correct region of control)
00731         HelpStringStore = PickerBubbleBuffer; //String_256(_R(IDS_EDITBH_PARENTPATCH));
00732         ReturnVal = TRUE;
00733     }   
00734 
00735     else if (Item == _R(IDC_EDIT_COMPONENT1))
00736     {
00737         if (cc)
00738             ReturnVal = GetComponentHelp(cc, 1, HelpStringStore);
00739     }
00740     else if (Item == _R(IDC_EDIT_COMPONENT2))
00741     {
00742         if (cc)
00743             ReturnVal = GetComponentHelp(cc, 2, HelpStringStore);
00744     }
00745     else if (Item == _R(IDC_EDIT_COMPONENT3))
00746     {
00747         if (cc)
00748             ReturnVal = GetComponentHelp(cc, 3, HelpStringStore);
00749     }
00750     else if (Item == _R(IDC_EDIT_COMPONENT4))
00751     {
00752         if (cc)
00753             ReturnVal = GetComponentHelp(cc, 4, HelpStringStore);
00754     }
00755 #if 0
00756     {
00757         if (ColourEditDlg::DisplayModel == COLOURMODEL_HSVT)
00758         {
00759             HelpStringStore = String_256(_R(IDS_EDITBH_COMP1));
00760             ReturnVal = TRUE;
00761         }
00762         else
00763         {
00764             if (cc != NULL)
00765             {
00766                 String_64 CompName;
00767                 cc->GetComponentName(1, &CompName, TRUE);
00768                 HelpStringStore.MakeMsg(_R(IDS_EDITBH_COMP234), (TCHAR *)CompName);
00769                 ReturnVal = TRUE;
00770             }
00771         }
00772     }
00773 
00774     else if (Item == _R(IDC_EDIT_COMPONENT2))
00775     {
00776         if (cc != NULL)
00777         {
00778             String_64 CompName;
00779             cc->GetComponentName(2, &CompName, TRUE);
00780             HelpStringStore.MakeMsg(_R(IDS_EDITBH_COMP234), (TCHAR *)CompName);
00781             ReturnVal = TRUE;
00782         }
00783     }   
00784 
00785     else if (Item == _R(IDC_EDIT_COMPONENT3))
00786     {
00787         if (cc != NULL)
00788         {
00789             String_64 CompName;
00790             cc->GetComponentName(3, &CompName, TRUE);
00791             HelpStringStore.MakeMsg(_R(IDS_EDITBH_COMP234), (TCHAR *)CompName);
00792             ReturnVal = TRUE;
00793         }
00794     }   
00795 
00796     else if (Item == _R(IDC_EDIT_COMPONENT4))
00797     {
00798         if (cc != NULL)
00799         {
00800             String_64 CompName;
00801             cc->GetComponentName(4, &CompName, TRUE);
00802             HelpStringStore.MakeMsg(_R(IDS_EDITBH_COMP234), (TCHAR *)CompName);
00803             ReturnVal = TRUE;
00804         }
00805     }   
00806 
00807 #endif
00808     else if (Item == _R(IDC_EDIT_COLMODEL))
00809     {
00810         HelpStringStore = String_256(_R(IDS_EDITBH_COLMODEL));
00811         ReturnVal = TRUE;
00812     }   
00813     else if (Item == _R(IDC_EDIT_NAMEMENU))
00814     {
00815         HelpStringStore = String_256(_R(IDS_EDITBH_NAME));
00816         ReturnVal = TRUE;
00817     }
00818     else if (Item == _R(IDC_EDIT_WEBHEX))
00819     {
00820         HelpStringStore = String_256(_R(IDS_EDITBH_WEBHEX));
00821         ReturnVal = TRUE;
00822     }
00823     else if (Item == _R(IDC_EDIT_COLTYPE))
00824     {
00825         HelpStringStore = String_256(_R(IDS_EDITBH_COLTYPE));
00826         ReturnVal = TRUE;
00827     }
00828     else if ((Item == _R(IDC_EDIT_INHERIT1)) ||
00829              (Item == _R(IDC_EDIT_INHERIT2)) ||
00830              (Item == _R(IDC_EDIT_INHERIT3)) ||
00831              (Item == _R(IDC_EDIT_INHERIT4)) )
00832     {
00833         HelpStringStore = String_256(_R(IDS_EDITBH_INHERIT));
00834         ReturnVal = TRUE;
00835     }
00836     else if ((Item == _R(IDC_EDIT_PARENTCOL)) ||
00837              (Item == _R(IDC_EDIT_PARENTNAME)))
00838     {
00839         HelpStringStore = String_256(_R(IDS_EDITBH_PARENTCOL));
00840         ReturnVal = TRUE;
00841     }
00842     else if ((Item == _R(IDC_EDIT_TINT)) ||
00843              (Item == _R(IDC_EDIT_TINTSLIDER)))
00844     {
00845         if (Bob != NULL && Bob->GetType() == COLOURTYPE_TINT && !Bob->TintIsShade())
00846             HelpStringStore = String_256(_R(IDS_EDITBH_TINT1));     // It's a tint
00847         else
00848             HelpStringStore = String_256(_R(IDS_EDITBH_TINT2));     // It's a shade
00849         ReturnVal = TRUE;
00850     }   
00851     else if (Item == _R(IDC_EDIT_SHADE))
00852     {
00853         HelpStringStore = String_256(_R(IDS_EDITBH_TINT2));         // It's a shade
00854         ReturnVal = TRUE;
00855     }   
00856     else if (Item == _R(IDC_EDIT_ADVANCED))
00857     {
00858         if (Editor->Folded)
00859             HelpStringStore = String_256(_R(IDS_EDITBH_ADVANCED1));
00860         else
00861             HelpStringStore = String_256(_R(IDS_EDITBH_ADVANCED2));
00862         ReturnVal = TRUE;
00863     }
00864     else if (Item == _R(IDC_EDIT_3D))
00865     {
00866         HelpStringStore = String_256(_R(IDS_EDITBH_3D));
00867         ReturnVal = TRUE;
00868     }
00869     else if (Item == _R(IDC_EDIT_MAKESTYLE))
00870     {
00871         HelpStringStore = String_256(_R(IDS_EDITBH_MAKESTYLE));
00872         ReturnVal = TRUE;
00873     }
00874     else if (Item == _R(IDC_EDIT_NOCOLOUR))
00875     {
00876         HelpStringStore = String_256(_R(IDS_COLBAR_HNOCOLOUR));
00877         ReturnVal = TRUE;
00878     }
00879     else if (Item == _R(IDC_MAKE_LOCAL))
00880     {
00881         HelpStringStore = String_256(_R(IDS_EDITBH_MAKE_LOCAL));
00882         ReturnVal = TRUE;
00883     }
00884     else if (Item == _R(IDC_EDIT_RENAME))   
00885     {
00886         HelpStringStore = String_256(_R(IDS_EDITBH_RENAME));
00887         ReturnVal = TRUE;
00888     }
00889     else if (Item == _R(IDC_EDIT_LINEFILL))
00890     {
00891         HelpStringStore = String_256(_R(IDS_EDITBH_LINEFILL));
00892         ReturnVal = TRUE;
00893     }
00894     else if (Item == _R(IDC_EDIT_216ONLY))
00895     {
00896         HelpStringStore = String_256(_R(IDS_EDITBH_216ONLY));
00897         ReturnVal = TRUE;
00898     }   
00899     else if (Item == _R(IDC_COLOURPICKER))
00900     {
00901         HelpStringStore = String_256(_R(IDS_STATICCOLOURPICKERTOOLHELP));
00902         ReturnVal = TRUE;
00903     }
00904 
00905     if (ReturnVal)
00906         return((TCHAR *) HelpStringStore);
00907 
00908 #endif
00909 
00910     return(NULL);
00911 }
00912 
00913 /********************************************************************************************
00914 
00915 >   void ColourPicker::SetBubbleHelp(CGadgetID * GadgetList)
00916 
00917     Author:     Alex Bligh <alex@alex.org.uk>
00918     Created:    31/5/2006
00919 
00920     Inputs:     GadgetList - NULL terminated list of gadgets
00921 
00922     Returns:    -
00923 
00924     Purpose:    Set all the bubble help up for the colour picker
00925 
00926     SeeAlso:    -
00927 
00928 ********************************************************************************************/
00929 
00930 void ColourPicker::SetBubbleHelp(CGadgetID * GadgetList)
00931 {
00932     ColourEditDlg *Editor = ColourEditDlg::TheEditor;
00933     if (Editor == NULL)
00934         return;
00935 
00936     CGadgetID i;
00937     while ((i=*(GadgetList++))) // assignment
00938     {
00939         wxWindow * pGadget = DialogManager::GetGadget(Editor->WindowID, i);
00940         wxString s;
00941         if (pGadget)
00942         {
00943             if (pGadget->IsEnabled() && pGadget->IsShown())
00944             {
00945                 // This is OK because HelpCallbackHandler uses a disgusting static. Not my doing
00946                 TCHAR * pHelp = HelpCallbackHandler(Editor->WindowID, i, NULL);
00947                 if (pHelp)
00948                     s=wxString(pHelp);
00949             }
00950             if (!s.IsEmpty())
00951                 pGadget->SetToolTip(s);
00952             else
00953                 pGadget->SetToolTip(NULL);
00954         }
00955     }
00956 }
00957 
00958 /********************************************************************************************
00959 
00960 >   BOOL ColourPicker::GetComponentHelp(ColourContext* const pSourceContext, 
00961                 const UINT32 ComponentIndex, StringBase& HelpString)
00962 
00963     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00964     Created:    31/05/96
00965 
00966     Inputs:     pSourceContext - the ColourContext in which the component is
00967                 ComponentIndex - the index of the component in the colour context
00968                 (1..GetComponentCount())
00969     Outputs:    HelpString - a string to be displayed as help for the given component
00970     Returns:    TRUE : If help string constructed correctly
00971                 FALSE : otherwise
00972     Purpose:    Subprocedure for HelpCallbackHandler providing help for each of the colour
00973                 components.
00974     Errors:     ERROR2IF's if invalid paramters given
00975                 ERROR3IF's for corrupt data structures
00976     SeeAlso:    ColourPicker::HelpCallbackHandler
00977 
00978 ********************************************************************************************/
00979 BOOL ColourPicker::GetComponentHelp(ColourContext* const pSourceContext, const UINT32 ComponentIndex, StringBase& HelpString)
00980 {
00981     ERROR2IF(pSourceContext == NULL, FALSE, "NULL parameters not allowed");
00982     ERROR3IF(!pSourceContext->IS_KIND_OF(ColourContext), "ColourPicker::GetComponentHelp() - pSourceContext isn't");
00983     ERROR2IF((ComponentIndex < 1) || (ComponentIndex > pSourceContext->GetComponentCount()), FALSE,
00984                 "Component index out of bounds");
00985 
00986     // Create a string of the form "Red (0..100%)" using the colour component's name and the limits defined for
00987     // the component's unit
00988     UnitGroup* pUnitGroup = pSourceContext->GetComponentUnitGroup(ComponentIndex);
00989     if (pUnitGroup == NULL)
00990     {
00991         ERROR3("ColourPicker::GetComponentHelp - Model has no units");
00992         return FALSE;
00993     }
00994     ERROR3IF(!pUnitGroup->IS_KIND_OF(UnitGroup), "ColourPicker::GetComponentHelp() - pUnitGroup isn't");
00995     ScaleUnit* pUnit = pUnitGroup->GetDefaultUnit();
00996     if (pUnit == NULL)
00997     {
00998         ERROR3("ColourPicker::GetComponentHelp - No default units");
00999         return FALSE;
01000     }
01001     ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "ColourPicker::GetComponentHelp() - pUnit isn't");
01002 
01003     String_64 CompName;
01004     pSourceContext->GetComponentName(ComponentIndex, &CompName, TRUE);
01005 
01006     String_32 LowerLimit;
01007     Convert::DoubleToString(pUnit->GetMin(), (StringBase*)&LowerLimit, pUnit->GetDPtoShow());
01008 
01009     String_32 UpperLimit;
01010     Convert::DoubleToString(pUnit->GetMax(), (StringBase*)&UpperLimit, pUnit->GetDPtoShow());
01011 
01012     String_32 QualifierToken;
01013     const Qualifier* pQualifier = pUnit->GetQualifier();
01014     if (pQualifier == NULL)
01015     {
01016         ERROR3("ColourPicker::GetComponentHelp - No qualifier");
01017         return FALSE;
01018     }
01019     ERROR3IF(!pQualifier->IS_KIND_OF(Qualifier), "ColourPicker::GetComponentHelp - Qualifier isn't");
01020 
01021     if (pQualifier->IsShown())
01022     {
01023         QualifierToken = pQualifier->GetToken();
01024     }
01025 
01026     HelpString.MakeMsg(_R(IDS_EDITBH_COMP234), (TCHAR *)CompName, (TCHAR *)LowerLimit, (TCHAR *)UpperLimit, 
01027                         (TCHAR *)QualifierToken);
01028 
01029     return TRUE;
01030 }
01031 
01032 
01033 /********************************************************************************************
01034 
01035 >   static void ColourPicker::UpdateBubbleHelpAndPointer(void)
01036 
01037     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01038     Created:    28/9/95
01039 
01040     Purpose:    Called on Idle (or MouseMove) events to provide bubble help and update
01041                 the mouse pointer while it is over the colour editor dialogue.
01042 
01043     Notes:      This is basically a bodge until a proper dialogue bubblehelp system is
01044                 available to do everything I need to do in the colour editor.
01045 
01046     SeeAlso:    ColourEditDlg::GetStatusLineText
01047 
01048 ********************************************************************************************/
01049 
01050 void ColourPicker::UpdateBubbleHelpAndPointer(void)
01051 {
01052 PORTNOTE("other", "Disabled ColourPicker::UpdateBubbleHelpAndPointer()")
01053 #ifndef EXCLUDE_FROM_XARALX
01054 #ifndef STANDALONE
01055     ColourEditDlg *Editor = ColourEditDlg::TheEditor;
01056     if (Editor == NULL)
01057         return;
01058 
01059     static CWindowID TheWindow = NULL;
01060     
01061     if (TheWindow == NULL)
01062         TheWindow = (CWindowID)Editor->WindowID;
01063 
01064     if (TheWindow == NULL)
01065         return;
01066 
01067     // We will update the bubble help every time we are called. However, we will only
01068     // bother checking through all the gadgets in the window a maximum of 10 times
01069     // per second. This stops the colour editor making a CPU interference buzzing noise
01070     // in my headphones while the pointer is idling over it!!
01071     static MonotonicTime LastUpdate;
01072     static UINT32 MousePos = 0;
01073 
01074     if (LastUpdate.Elapsed(100))
01075     {
01076         // Remember when we last checked
01077         LastUpdate.Sample();
01078 
01079         // Default to the mouse being "nowhere special" again
01080         TheWindow = (CWindowID)Editor->WindowID;
01081         MousePos = 0;
01082 
01083         POINT MouseScreenPos;
01084         if (::GetCursorPos(&MouseScreenPos))
01085         {
01086             // Only continue processing if the window under the pointer is the colour editor
01087             // or a child thereof. My machine makes a funny CPU buzz in my earphones when the
01088             // pointer is in the editor window, and it was doing this even when I had another
01089             // application maximised in front of camelot! ChildWindowFromPoint does not
01090             // determine if the child window is actually *visible*!
01091 
01092             CWindowID WindowUnder = ::WindowFromPoint(MouseScreenPos);
01093 
01094             if (WindowUnder != NULL &&
01095                 (WindowUnder == TheWindow || ::GetParent(WindowUnder) == TheWindow))
01096             {
01097                 POINT TempPos;
01098                 TempPos.x = MouseScreenPos.x;
01099                 TempPos.y = MouseScreenPos.y;
01100 
01101                 // Convert to client coords in the main window
01102                 ::ScreenToClient(TheWindow, &TempPos);
01103 
01104                 CPoint Pos(TempPos);
01105                 CWindowID WindowUnderPointer = ::ChildWindowFromPoint(TheWindow, Pos);
01106                 if (WindowUnderPointer != NULL && IsWindowVisible(WindowUnderPointer))
01107                 {
01108                     // Make sure that hidden windows do not provide status help!
01109                     INT32 WindowStyle = ::GetWindowLong(WindowUnderPointer, GWL_STYLE);
01110                     if ((WindowStyle & WS_VISIBLE) != 0)
01111                     {
01112                         CWindowID hGadget;
01113                         INT32 i = 0;
01114                         while (GadgetList[i] && MousePos)
01115                         {
01116                             hGadget = DialogManager::GetGadget(TheWindow, GadgetList[i]);
01117                             if (WindowUnderPointer == hGadget)
01118                             {
01119                                 MousePos = (UINT32)GadgetList[i];
01120                                 TheWindow = hGadget;
01121                             }
01122                             i++;
01123                         }
01124                     }
01125                 }
01126 
01127                 // Special check for Picker control (BODGE is a more accurate term!)
01128                 // We look to see if the pointer is vaguely over the area of the picker used
01129                 // to display the current/original colour patch, and only give help for that
01130                 // region!
01131 
01132                 if (MousePos == _R(IDC_EDIT_PICKER))
01133                 {
01134                     MousePos =0;    // Default to no help if anything goes wrong
01135 
01136                     // Set up a ReDrawInfoType containing the click position info, and information
01137                     // that will come in handy (size of the gadget, and screen DPI)
01138                     ReDrawInfoType ExtraInfo;
01139 
01140                     ExtraInfo.pDC = NULL;       // No redraw info for mouse events
01141                     ExtraInfo.pClipRect = NULL;
01142 
01143                     // Get the screen DPI
01144                     HDC ScreenDC = CreateCompatibleDC(NULL);
01145                     if (ScreenDC == NULL)
01146                     {
01147                         ERROR3("ColourPicker: Unable to create screen DC");
01148                         return;
01149                     }
01150                     ExtraInfo.Dpi = GetDeviceCaps(ScreenDC, LOGPIXELSY);
01151                     DeleteDC(ScreenDC);
01152 
01153                     // Calculate how big the window is, in MILLIPOINTS
01154                     RECT WindowSize;
01155                     if (!GetClientRect(TheWindow, &WindowSize))
01156                     {
01157                         ERROR3("GetClientRect failed in ColourPicker");
01158                         return;
01159                     }
01160 
01161                     ExtraInfo.dx = (((INT32)WindowSize.right)*72000) / ExtraInfo.Dpi;
01162                     ExtraInfo.dy = (((INT32)WindowSize.bottom)*72000) / ExtraInfo.Dpi;
01163 
01164                     // Work out the MILLIPOINT coordinates of the mouse position
01165                     // Note that the Y value is flipped, as the kernel-origin is at the bottom left
01166                     // and we have to first convert the screen mouse position into client coords
01167                     ScreenToClient(TheWindow, &MouseScreenPos);
01168 
01169                     INT32 XPos = (INT32) MouseScreenPos.x;
01170                     INT32 YPos = (INT32) MouseScreenPos.y;
01171 
01172                     DocCoord MouseInfo;
01173                     MouseInfo.x = (XPos * 72000) / ExtraInfo.Dpi;
01174                     MouseInfo.y = ExtraInfo.dy - ((YPos * 72000) / ExtraInfo.Dpi);
01175                     ExtraInfo.pMousePos = &MouseInfo;
01176 
01177                     // Now call the colour editor to handle the mouse position - it will
01178                     // set the pointer shape as appropriate and also return us some bubble help.
01179                     PickerBubbleBuffer = String_128("");
01180                     StatusHelpBuffer = String_256("");
01181                     Editor->HandleIdlePointer(&ExtraInfo, &PickerBubbleBuffer, &StatusHelpBuffer, &MousePos);
01182 
01183                     if (MousePos)
01184                         ControlHelper::BubbleHelpDisable();     // On non-helpful bit of picker - cancel bubble help
01185                 }
01186             }
01187         }
01188     }
01189 
01190     // Finally, tell the bubble help system what help we want, if any
01191     if (MousePos)
01192     {
01193         // Set up our callback handler to show the help if/when necessary
01194         ControlHelper::DoBubbleHelpOn(TheWindow, MousePos, ColourPicker::HelpCallbackHandler, NULL);
01195     }
01196 #endif
01197 #endif
01198 }
01199 
01200 
01201 
01202 
01203 
01204 
01205 /********************************************************************************************
01206 
01207 >   static BOOL ColourPicker::GetComponentAsString(IndexedColour *Source,
01208                                                 ColourContext *DestContext, INT32 ComponentIndex,
01209                                                 String_8 *Result)
01210 
01211     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01212     Created:    11/11/94
01213     Inputs:     Source - The colour from which you wish to extract the component
01214                 DestContext - The colour context in which you want the resulting component
01215                 ComponentIndex - The component you wish to extract (1..4)
01216                 
01217     Outputs:    Result - returns containing a decimal (0.0 .. 100.0) string representing
01218                 the value of the given component of the colour as it is defined in the
01219                 given colour model (Note: HSV Hue is done as 0..360).
01220 
01221     Returns:    TRUE if the value converted was out of gamut.
01222 
01223     Purpose:    Retrieves the colour definition of the given colour, converts it to the
01224                 given colour model, and returns the desired component of the definition
01225                 in that model as a decimal string appropriate for placing into a colour
01226                 editor dialogue gadget.
01227 
01228     Notes:      At present, this function clips the value to lie within the legal 0.0 to 1.0
01229                 gamut range.
01230 
01231     Scope:      private
01232 
01233     SeeAlso:    ColourPicker::SetComponentFromDouble;
01234                 ColourPicker::SetComponentFromString
01235 
01236 ********************************************************************************************/
01237 
01238 BOOL ColourPicker::GetComponentAsString(IndexedColour *Source,
01239                                         ColourContext *DestContext, INT32 ComponentIndex,
01240                                         String_8 *Result)
01241 {
01242     ERROR2IF(Source == NULL || DestContext == NULL || Result == NULL, FALSE,
01243                 "NULL parameters are illegal");
01244 
01245     ERROR2IF(ComponentIndex < 1 || (UINT32)ComponentIndex > DestContext->GetComponentCount(), FALSE,
01246                 "ComponentIndex not in range");
01247 
01248     BOOL OutOfGamut = FALSE;
01249     ColourGeneric Defn;
01250 
01251     DestContext->ConvertColour(Source, &Defn);
01252     
01253     // Sneakily get the component from the ColourGeneric by treating it as an array
01254     // of 4 ColourValue components.
01255     ColourValue *CompPtr = (ColourValue *) &Defn;       
01256     double CompValue = CompPtr[ComponentIndex-1].MakeDouble();
01257 
01258     if (CompValue < 0.0)
01259     {
01260         CompValue = 0.0;        // **** Clip out-of-gamut values.
01261         OutOfGamut = TRUE;      // Remember that this was out of gamut
01262     }
01263 
01264     if (CompValue > 1.0)
01265     {
01266         CompValue = 1.0;        // **** Clip out-of-gamut values.
01267         OutOfGamut = TRUE;      // Remember that this was out of gamut
01268     }
01269 
01270     // Generate a 0..100 value, except for Hue, in which case it's 0..360
01271     UnitGroup* pPossibleUnits = DestContext->GetComponentUnitGroup(ComponentIndex);
01272     if (pPossibleUnits == NULL)
01273     {
01274         ERROR3("ColourPicker::GetComponentAsString - pPossibleUnits NULL");
01275         return FALSE;
01276     }
01277     ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "pPossibleUnits aren't");
01278     ScaleUnit* pUnit = pPossibleUnits->GetDefaultUnit();
01279     if (pUnit == NULL)
01280     {
01281         ERROR3("ColourPicker::GetComponentAsString - Default units NULL");
01282         return FALSE;
01283     }
01284     ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "pUnits isn't");
01285     pUnit->StringFromScale(CompValue, Result, 6);
01286 
01287     // Convert to a 1 d.p. string using the global conversion function
01288 /*  String_32 TempString;
01289     Convert::DoubleToString(CompValue, (StringBase *) &TempString, pUnit->GetDPtoShow());
01290     TempString.Left(Result, 6);
01291 
01292     const Qualifier* pQualifier = pUnit->GetQualifier();
01293     if (pQualifier == NULL || !pQualifier->IS_KIND_OF(Qualifier))
01294     {
01295         ERROR3("ColourPicker::GetComponentAsString - not a Qualifier!");
01296         return FALSE;
01297     }
01298     if (pQualifier->IsShown())
01299         *Result += pQualifier->GetToken();
01300 */
01301     return(OutOfGamut);
01302 }
01303 
01304 
01305 
01306 /********************************************************************************************
01307 
01308 >   static BOOL ColourPicker::GetComponentsAsHexString(IndexedColour *Source,
01309                                             ColourContext *DestContext, INT32 ComponentIndex,
01310                                             String_16 *Result)
01311 
01312     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01313     Created:    11/11/99
01314     Inputs:     Source - The colour from which you wish to extract the component
01315                 DestContext - The colour context in which you want the resulting component
01316                 ComponentIndex - This should be set to -1 at present (cause we are getting
01317                 all components; and not one in the range 1-4)
01318                 
01319     Outputs:    Result - returns containing a hexadecimal string representation (rrggbb)
01320 
01321     Returns:    TRUE if the value converted was out of gamut.
01322 
01323     Purpose:    Retrieves the colour definition of the given colour, converts it to the
01324                 given colour model, and returns the combined value of all components
01325                 of the definition in that model as a hexadecimal string appropriate for
01326                 placing into a colour editor dialogue gadget.
01327 
01328     Notes:      At present, this function clips the value to lie within the legal 0.0 to 1.0
01329                 gamut range.
01330 
01331     Scope:      private
01332 
01333     SeeAlso:    ColourPicker::GetComponentsAsString;
01334                 ColourPicker::SetComponentsFromHexString
01335 
01336 ********************************************************************************************/
01337 
01338 BOOL ColourPicker::GetComponentsAsHexString(IndexedColour *Source,
01339                                             ColourContext *DestContext, INT32 ComponentIndex,
01340                                             String_16 *Result)
01341 {
01342     ERROR2IF(Source == NULL || DestContext == NULL || Result == NULL, FALSE,
01343                 "NULL parameters are illegal");
01344 //  ERROR2IF(!DestContext->IS_KIND_OF(ColourContextWebRGBT), FALSE,
01345 //              "SourceContext parameter is not of type ColourContextWebRGBT");
01346 
01347     if (ComponentIndex == -1)
01348     {
01349         BOOL OutOfGamut = FALSE;
01350         ColourGeneric Defn;
01351 
01352         DestContext->ConvertColour(Source, &Defn);
01353 
01354         // Sneakily get the component from the ColourGeneric by treating it as an array
01355         // of 4 ColourValue components ....
01356 
01357         ColourValue *CompPtr = (ColourValue *) &Defn;       
01358         
01359         String_8 ResultR, ResultG, ResultB;
01360 
01361         for (INT32 i = 1; i < 4; i++)
01362         {
01363             double CompValue = CompPtr[i-1].MakeDouble();
01364 
01365             if (CompValue < 0.0)
01366             {
01367                 CompValue = 0.0;        // **** Clip out-of-gamut values.
01368                 OutOfGamut = TRUE;      // Remember that this was out of gamut
01369             }
01370 
01371             if (CompValue > 1.0)
01372             {
01373                 CompValue = 1.0;        // **** Clip out-of-gamut values.
01374                 OutOfGamut = TRUE;      // Remember that this was out of gamut
01375             }
01376 
01377             // Generate a 0..100 value, except for Hue, in which case it's 0..360
01378             UnitGroup* pPossibleUnits = DestContext->GetComponentUnitGroup(i);
01379             if (pPossibleUnits == NULL)
01380             {
01381                 ERROR3("ColourPicker::GetComponentAsString - pPossibleUnits NULL");
01382                 return FALSE;
01383             }
01384             ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "pPossibleUnits aren't");
01385             ScaleUnit* pUnit = pPossibleUnits->FindUnitFromIndex (1);//GetDefaultUnit();
01386             if (pUnit == NULL)
01387             {
01388                 ERROR3("ColourPicker::GetComponentAsString - Default units NULL");
01389                 return FALSE;
01390             }
01391             ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "pUnits isn't");
01392             
01393             switch (i)
01394             {
01395                 case 1:
01396                     pUnit->StringFromScale(CompValue, &ResultR, 6);
01397                 break;
01398                 case 2:
01399                     pUnit->StringFromScale(CompValue, &ResultG, 6);
01400                 break;
01401                 case 3:
01402                     pUnit->StringFromScale(CompValue, &ResultB, 6);
01403                 break;
01404             }
01405         }
01406 
01407         // convert strings into integers ....
01408         
01409         INT32 rVal = camAtoi ((const TCHAR*) ResultR);
01410         INT32 gVal = camAtoi ((const TCHAR*) ResultG);
01411         INT32 bVal = camAtoi ((const TCHAR*) ResultB);
01412 
01413         // convert integers to base 16 ....
01414         
01415         camSprintf((TCHAR*)ResultR, _T("%X"), rVal);
01416         camSprintf((TCHAR*)ResultG, _T("%X"), gVal);
01417         camSprintf((TCHAR*)ResultB, _T("%X"), bVal);
01418 
01419         String_8 Builder;//FinalResultR, FinalResultG, FinalResultB;
01420 
01421         // I don't want an _itoa one length rr's, gg's or bb's thankyou very much!
01422         // AND glue the results together (== rrggbb) at the same time
01423 
01424         if (ResultR.Length () == 1)
01425         {
01426             Builder += (String_8 (TEXT ("0"))) += ResultR;
01427         }
01428         else
01429         {
01430             Builder += ResultR;
01431         }
01432 
01433         if (ResultG.Length () == 1)
01434         {
01435             Builder += (String_8 (TEXT ("0"))) += ResultG;
01436         }
01437         else
01438         {
01439             Builder += ResultG;
01440         }
01441 
01442         if (ResultB.Length () == 1)
01443         {
01444             Builder += (String_8 (TEXT ("0"))) += ResultB;
01445         }
01446         else
01447         {
01448             Builder += ResultB;
01449         }
01450 
01451         *Result = Builder;      // take that edit box - a correctly built hex string!
01452         
01453         //if ((ResultR.Length () == 1) || (ResultG.Length () == 1) || (ResultB.Length () == 1))
01454         //{
01455         //  *Result += /*(String_8 (TEXT ("0x"))) +=*/ FinalResultR += FinalResultG += FinalResultB;
01456         //}
01457         //else
01458         //{
01459         //  *Result += /*(String_8 (TEXT ("0x"))) +=*/ ResultR += ResultG += ResultB;
01460         //}
01461 
01462         return(OutOfGamut);
01463     }
01464 
01465     return (FALSE);     // stop that annoying warning about not all paths return a value!
01466 }
01467 
01468 
01469 
01470 /********************************************************************************************
01471 
01472 >   static BOOL ColourPicker::SetComponentFromString(IndexedColour *Dest,
01473                                     ColourContext *SourceContext, INT32 ComponentIndex,
01474                                     String_8 *NewValue)
01475 
01476     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01477     Created:    11/11/94
01478     
01479     Inputs:     Dest - the colour to be set
01480                 SourceContext - the context in which the new component value is defined
01481                 ComponentIndex - the index [1..4] of the component being set, in that context
01482                 NewValue - new value (decimal, as 0..100 or 0..360 for Hue) of the component
01483     Outputs:    Dest is updated appropriately
01484     Returns:    TRUE if the value was out of gamut and had to be clipped
01485 
01486     Purpose:    Converts AND COERCES the colour into the destination context.
01487                 Assumes that the string will be 0..100 (or 0..360 for HSV)
01488                 Clips the string value into a 0.0 to 1.0 in-gamut range, and then sets the
01489                 given component of the converted colour to that value.
01490                 This thus changes the colour model in which the colour is defined as well
01491                 as the component value.
01492 
01493     Scope:      private
01494 
01495     SeeAlso:    ColourPicker::SetComponentFromDouble;
01496                 ColourPicker::GetComponentAsString
01497 
01498 ********************************************************************************************/
01499 
01500 BOOL ColourPicker::SetComponentFromString(IndexedColour *Dest,
01501                                     ColourContext *SourceContext, INT32 ComponentIndex,
01502                                     String_8 *NewValue)
01503 {
01504     ERROR2IF(Dest == NULL ||  SourceContext == NULL || NewValue == NULL, FALSE, 
01505                 "NULL Parameters are illegal");
01506     ERROR3IF(!Dest->IS_KIND_OF(IndexedColour) || !SourceContext->IS_KIND_OF(ColourContext),
01507                 "Parameters incorrect classes");
01508     ERROR2IF(ComponentIndex < 1 || (UINT32)ComponentIndex > SourceContext->GetComponentCount(), 
01509                 FALSE, "ComponentIndex not in range");
01510 
01511     UnitGroup* pPossibleUnits = SourceContext->GetComponentUnitGroup(ComponentIndex);
01512     if (pPossibleUnits == NULL)
01513     {
01514         ERROR3("ColourPicker::SetComponentFromString - SourceContext has NULL units");
01515         return FALSE;
01516     }
01517     ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "ColourPicker::SetComponentFromString - pPossibleUnits aren't");
01518 
01519     double dNewVal;
01520     if (pPossibleUnits->ScaleFromString(*NewValue, dNewVal) == FALSE)
01521         return FALSE;
01522 
01523     // And set the new value
01524     return(SetComponentFromDouble(Dest, SourceContext, ComponentIndex, dNewVal));
01525 }
01526 
01527 
01528 
01529 /********************************************************************************************
01530 
01531 >   static BOOL ColourPicker::IsValidHexString (String_16 Hex)
01532 
01533     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01534     Created:    11/11/99
01535     
01536     Inputs:     Hex - the string to interrogate to see if all characters are trully
01537                 hexadecimal.
01538     Returns:    TRUE if success (i.e.  all characters in string were hexadecimal)
01539 
01540     Purpose:    Internal helper function for ColourPicker::SetComponentsFromHexString ()
01541                 UNLESS YOU KNOW WHAT YOUR DOING - DON'T CALL THIS AS IT ONLY EXISTS
01542                 TO HELP THE FORE-MENTIONED FUNCTION - AND I CANNOT SEE WHY YOUR CALLING
01543                 THIS FROM ELSEWHERE ANYWAY !!!!
01544 
01545     Scope:      private
01546 
01547     SeeAlso:    ColourPicker::GetComponentAsHexString
01548 
01549 ********************************************************************************************/
01550 
01551 BOOL ColourPicker::IsValidHexString (String_16 Hex)
01552 {
01553     for (INT32 i = 0; i < Hex.Length(); i++)
01554     {
01555         char x = Hex[i];
01556         
01557         if (x >= '0' && x <= '9') {}
01558         else if (x >= 'A' && x <= 'F') {}
01559         else if (x >= 'a' && x <= 'f') {}
01560         else
01561         {
01562             return (FALSE);
01563         }
01564     }
01565     return (TRUE);
01566 }
01567 
01568 
01569 
01570 /********************************************************************************************
01571 
01572 >   static BOOL ColourPicker::SetComponentsFromHexString(IndexedColour *Dest,
01573                                               ColourContext *SourceContext,
01574                                               String_16 *NewValue)
01575 
01576     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01577     Created:    11/11/99
01578     
01579     Inputs:     Dest - the colour to be set
01580                 SourceContext - the context in which the new component value is defined
01581                 NewValue - new value (hexadecimal) of the components (i.e.  rrggbb or
01582                 0xrrggbb)
01583     Outputs:    Dest is updated appropriately
01584     Returns:    TRUE if success (i.e.  valid input and we could do things)
01585 
01586     Purpose:    Converts AND COERCES the colour into the destination context.
01587                 Assumes that the string will in hex format (i.e  rrggbb or 0xrrggbb)
01588                 Clips the string value into 0.0 to 1.0 in-gamut ranges, and then sets the
01589                 components of the converted colour to those values.
01590                 This thus changes the colour model in which the colour is defined as well
01591                 as the component value.
01592 
01593     Scope:      private
01594 
01595     SeeAlso:    ColourPicker::SetComponentFromDouble;
01596                 ColourPicker::GetComponentAsHexString
01597 
01598 ********************************************************************************************/
01599 
01600 BOOL ColourPicker::SetComponentsFromHexString(IndexedColour *Dest,
01601                                               ColourContext *SourceContext,
01602                                               String_16 *NewValue)
01603 {
01604     ERROR2IF(Dest == NULL ||  SourceContext == NULL || NewValue == NULL, FALSE, 
01605                 "NULL Parameters are illegal");
01606     ERROR3IF(!Dest->IS_KIND_OF(IndexedColour) || !SourceContext->IS_KIND_OF(ColourContext),
01607                 "Parameters incorrect classes");
01608 //  ERROR2IF(!SourceContext->IS_KIND_OF(ColourContextWebRGBT), FALSE,
01609 //              "SourceContext parameter is not of type ColourContextWebRGBT");
01610 
01611     // take a copy of the string - since were going to have to interrogate/parse it ....
01612     String_16 CopyNewValue (*NewValue);
01613     // convert to lower case (avoid trouble with caps etc.)
01614     CopyNewValue.toLower ();
01615 
01616     INT32 StringLength = CopyNewValue.Length ();//camStrlen ((TCHAR*) CopyNewValue);
01617 
01618     BOOL ValidStringParseSoFar = TRUE;
01619     BOOL Single0xPrefix = FALSE;
01620     BOOL SingleHashPrefix = FALSE;
01621     BOOL More0xPrefixs = FALSE;
01622     BOOL MoreHashPrefixs = FALSE;
01623 
01624     // decide if we have a 0x prefix, or a # prefix ....
01625 
01626     const TCHAR* PtrPrefix = cc_lstrstr (CopyNewValue, _T("0x"));
01627     Single0xPrefix = (PtrPrefix != NULL) ? TRUE : FALSE;
01628     const TCHAR* PtrPrefix2 = cc_lstrstr (CopyNewValue, _T("#"));
01629     SingleHashPrefix = (PtrPrefix2 != NULL) ? TRUE : FALSE;
01630 
01631     if (Single0xPrefix == TRUE)
01632     {
01633         CopyNewValue = PtrPrefix += 2;
01634 
01635         // not quite and simple as this - since we now need to see if theres (at least) one
01636         // other 0x - and if there is, ABORT (since that cannot be a valid hex number)
01637 
01638         PtrPrefix = cc_lstrstr (CopyNewValue, _T("0x"));
01639         More0xPrefixs = (PtrPrefix != NULL) ? TRUE : FALSE;
01640 
01641         ValidStringParseSoFar = More0xPrefixs ? FALSE : TRUE;
01642 
01643         if (ValidStringParseSoFar)
01644         {
01645             // scan for # ....
01646 
01647             PtrPrefix2 = cc_lstrstr ((const TCHAR*) CopyNewValue, _T("#"));
01648             SingleHashPrefix = (PtrPrefix2 != NULL) ? TRUE : FALSE;
01649             ValidStringParseSoFar = SingleHashPrefix ? FALSE : TRUE;
01650         }
01651 
01652         if (!ValidStringParseSoFar)
01653         {
01654             return (FALSE);
01655         }
01656     }
01657     else if (SingleHashPrefix == TRUE)
01658     {
01659         CopyNewValue = PtrPrefix2 += 1;
01660 
01661         // not quite and simple as this - since we now need to see if theres (at least) one
01662         // other # - and if there is, ABORT (since that cannot be a valid hex number)
01663 
01664         PtrPrefix2 = cc_lstrstr ((const TCHAR*) CopyNewValue, _T("#"));
01665         MoreHashPrefixs = (PtrPrefix2 != NULL) ? TRUE : FALSE;
01666 
01667         ValidStringParseSoFar = MoreHashPrefixs ? FALSE : TRUE;
01668 
01669         if (ValidStringParseSoFar)
01670         {
01671             // scan for 0x ....
01672 
01673             PtrPrefix = cc_lstrstr ((const TCHAR*) CopyNewValue, _T("0x"));
01674             Single0xPrefix = (PtrPrefix != NULL) ? TRUE : FALSE;
01675             ValidStringParseSoFar = Single0xPrefix ? FALSE : TRUE;
01676         }
01677 
01678         if (!ValidStringParseSoFar)
01679         {
01680             return (FALSE);
01681         }
01682     }
01683 
01684     if (ValidStringParseSoFar == FALSE) return (FALSE);
01685 
01686     // weve made it this far - and have removed the trailing 0x
01687     // so now take a copy of the this new (copied) string and lets try to break
01688     // the string into components ....
01689 
01690     String_16 No0xPrefixNewValue (CopyNewValue);
01691     StringLength = No0xPrefixNewValue.Length ();
01692 
01693     BOOL rComponent = FALSE;
01694     BOOL bComponent = FALSE;
01695     BOOL gComponent = FALSE;
01696 
01697     String_8 rValStr;
01698     String_8 gValStr;
01699     String_8 bValStr;
01700 
01701     if ((StringLength <= 0) || (StringLength > 6)) return (FALSE);
01702 
01703     switch (StringLength)
01704     {
01705         case 2: rComponent = TRUE; break;
01706         case 4: rComponent = TRUE; gComponent = TRUE; break;
01707         case 6: rComponent = TRUE; gComponent = TRUE; bComponent = TRUE; break;
01708     }
01709 
01710     BOOL returnVal = FALSE;
01711 
01712     // now break the string and do conversions ....
01713 
01714     // NOTE - I could have made use of a for/while loop to reduce code size here; BUT
01715     // when I tried the BLOODY thing kept falling over - and it didn't seem worth it
01716     // for all the hastle ....
01717 
01718     if (IsValidHexString (No0xPrefixNewValue))
01719     {
01720         if (rComponent == TRUE)     // deal with the red component
01721         {   
01722             No0xPrefixNewValue.Split (&rValStr, &No0xPrefixNewValue, 2, FALSE);
01723            INT32 convertedVal;
01724            camSscanf(rValStr, _T("%X"), &convertedVal);
01725            camSprintf(rValStr, _T("%d"), convertedVal);
01726            //INT32 convertedVal = (INT32) strtol ((TCHAR*) rValStr, (TCHAR**) "\0", 16);//ToDec (rValStr);//atoi ((TCHAR*) rValStr);
01727            //_itoa (convertedVal, (TCHAR*) rValStr, 10);
01728 
01729             UnitGroup* pPossibleUnits = SourceContext->GetComponentUnitGroup(1);
01730             if (pPossibleUnits == NULL)
01731             {
01732                 ERROR3("ColourPicker::SetComponentFromString - SourceContext has NULL units");
01733                 return FALSE;
01734             }
01735             ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "ColourPicker::SetComponentFromString - pPossibleUnits aren't");
01736 
01737             ScaleUnit* pUnit = pPossibleUnits->FindUnitFromIndex (1);//GetDefaultUnit();
01738             if (pUnit == NULL)
01739             {
01740                 ERROR3("ColourPicker::GetComponentAsString - Default units NULL");
01741                 return FALSE;
01742             }
01743             ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "pUnits isn't");
01744 
01745             double dNewVal;
01746            Convert::StringToDouble(rValStr, &dNewVal);
01747             pUnit->ConvertTo0to1 (dNewVal);
01748 
01749             // And set the new value
01750             returnVal = SetComponentFromDouble(Dest, SourceContext, 1, dNewVal);
01751         }
01752 
01753         if (gComponent == TRUE)     // deal with the green component
01754         {
01755             No0xPrefixNewValue.Split (&gValStr, &No0xPrefixNewValue, 2, FALSE);
01756            INT32 convertedVal;
01757            camSscanf(gValStr, _T("%X"), &convertedVal);
01758            camSprintf(gValStr, _T("%d"), convertedVal);
01759            //INT32 convertedVal = (INT32) strtol ((TCHAR*) gValStr, (TCHAR**) "\0", 16);//ToDec (rValStr);//atoi ((TCHAR*) rValStr);
01760            //_itoa (convertedVal, (TCHAR*) gValStr, 10);
01761 
01762             UnitGroup* pPossibleUnits = SourceContext->GetComponentUnitGroup(2);
01763             if (pPossibleUnits == NULL)
01764             {
01765                 ERROR3("ColourPicker::SetComponentFromString - SourceContext has NULL units");
01766                 return FALSE;
01767             }
01768             ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "ColourPicker::SetComponentFromString - pPossibleUnits aren't");
01769 
01770             ScaleUnit* pUnit = pPossibleUnits->FindUnitFromIndex (1);//GetDefaultUnit();
01771             if (pUnit == NULL)
01772             {
01773                 ERROR3("ColourPicker::GetComponentAsString - Default units NULL");
01774                 return FALSE;
01775             }
01776             ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "pUnits isn't");
01777 
01778             double dNewVal;
01779            Convert::StringToDouble(gValStr, &dNewVal);
01780             pUnit->ConvertTo0to1 (dNewVal);
01781 
01782             // And set the new value
01783             returnVal = SetComponentFromDouble(Dest, SourceContext, 2, dNewVal);
01784         }
01785 
01786         if (bComponent == TRUE)     // deal with the blue component
01787         {
01788             No0xPrefixNewValue.Split (&bValStr, &No0xPrefixNewValue, 2, FALSE);
01789            INT32 convertedVal;
01790            camSscanf(bValStr, _T("%X"), &convertedVal);
01791            camSprintf(bValStr, _T("%d"), convertedVal);
01792            //INT32 convertedVal = (INT32) strtol ((TCHAR*) bValStr, (TCHAR**) "\0", 16);//ToDec (rValStr);//atoi ((TCHAR*) rValStr);
01793            //_itoa (convertedVal, (TCHAR*) bValStr, 10);
01794 
01795             UnitGroup* pPossibleUnits = SourceContext->GetComponentUnitGroup(3);
01796             if (pPossibleUnits == NULL)
01797             {
01798                 ERROR3("ColourPicker::SetComponentFromString - SourceContext has NULL units");
01799                 return FALSE;
01800             }
01801             ERROR3IF(!pPossibleUnits->IS_KIND_OF(UnitGroup), "ColourPicker::SetComponentFromString - pPossibleUnits aren't");
01802 
01803             ScaleUnit* pUnit = pPossibleUnits->FindUnitFromIndex (1);//GetDefaultUnit();
01804             if (pUnit == NULL)
01805             {
01806                 ERROR3("ColourPicker::GetComponentAsString - Default units NULL");
01807                 return FALSE;
01808             }
01809             ERROR3IF(!pUnit->IS_KIND_OF(ScaleUnit), "pUnits isn't");
01810 
01811             double dNewVal;
01812             Convert::StringToDouble(bValStr, &dNewVal);
01813             pUnit->ConvertTo0to1 (dNewVal);
01814 
01815             // And set the new value
01816             returnVal = SetComponentFromDouble(Dest, SourceContext, 3, dNewVal);
01817         }
01818 
01819         return (returnVal);
01820     }
01821     else
01822     {
01823         return (FALSE);     // that don't look like hex to me!
01824     }
01825 }
01826 
01827 
01828 
01829 /********************************************************************************************
01830 
01831 >   static BOOL ColourPicker::SetComponentFromDouble(IndexedColour *Dest,
01832                                     ColourContext *SourceContext, INT32 ComponentIndex,
01833                                     double NewValue)
01834 
01835     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01836     Created:    30/11/94
01837     
01838     Inputs:     Dest - the colour to be set
01839                 SourceContext - the context in which the new component value is defined
01840                 ComponentIndex - the index [1..4] of the component being set, in that context
01841                 NewValue - the new value (0.0 - 1.0) of the component
01842     Outputs:    Dest is updated appropriately
01843     Returns:    TRUE if the value was out of gamut and had to be clipped
01844 
01845     Purpose:    Converts AND COERCES the colour into the destination context.
01846                 Clips the new value into a 0.0 to 1.0 in-gamut range, and then sets the
01847                 given component of the converted colour to that value.
01848 
01849                 This thus changes the colour model in which the colour is defined as well
01850                 as the component value.
01851 
01852                 The value is rounded as it is squeezed into the Fixed24 format used in
01853                 colour definitions.
01854 
01855     Scope:      private
01856 
01857     SeeAlso:    ColourPicker::SetComponentFromString;
01858                 ColourPicker::GetComponentAsString
01859 
01860 ********************************************************************************************/
01861 
01862 BOOL ColourPicker::SetComponentFromDouble(IndexedColour *Dest,
01863                                     ColourContext *SourceContext, INT32 ComponentIndex,
01864                                     double NewValue)
01865 {
01866     BOOL OutOfGamut = FALSE;
01867 
01868     ERROR3IF(Dest == NULL || SourceContext == NULL,
01869                 "ColourPicker::SetComponentFromDouble - NULL Parameters are illegal");
01870 
01871     ERROR3IF(ComponentIndex < 1 || ComponentIndex > 4,
01872                 "ColourPicker::SetComponentFromDouble- Index should be in range 1..4!");
01873     
01874     // Ensure it is in the correct colour model, and flush its output cache
01875     ForceColourModel(Dest, SourceContext);
01876 
01877     // Add half of the least-significant-bit-value to round the new value
01878     NewValue += 1.0 / ((double) (1<<25));
01879 
01880     // Clip to lie within gamut
01881     if (NewValue < 0.0)
01882     {
01883         NewValue = 0.0;
01884         OutOfGamut = TRUE;
01885     }
01886 
01887     if (NewValue > 1.0)
01888     {
01889         NewValue = 1.0;
01890         OutOfGamut = TRUE;
01891     }
01892 
01893     // Sneakily place the component back into the ColourGeneric by treating it as an array
01894     // of 4 ColourValue components.
01895     ColourValue *CompPtr = (ColourValue *) Dest->SourceColourPtr();
01896     CompPtr[ComponentIndex-1] = FIXED24(NewValue);
01897 
01898     return(OutOfGamut);
01899 }
01900 
01901 
01902 
01903 /********************************************************************************************
01904 
01905 >   void ColourPicker::ForceColourModel(IndexedColour *Dest, ColourContext *SourceContext)
01906 
01907     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01908     Created:    11/11/94
01909     
01910     Inputs:     Dest - the colour to be set
01911                 SourceContext - the context in which the new colour value should be defined
01912 
01913     Outputs:    Dest is updated appropriately
01914     Returns:    -
01915 
01916     Purpose:    COERCES the colour into the destination context.
01917                 This ensures that the colour is defined in the given context's colour model,
01918                 converting its definition if necessary.
01919 
01920     Notes:      This method always flushes the colour's output cache.
01921 
01922     Scope:      private
01923 
01924 ********************************************************************************************/
01925 
01926 void ColourPicker::ForceColourModel(IndexedColour *Dest, ColourContext *SourceContext)
01927 {
01928     ERROR3IF(Dest == NULL || SourceContext == NULL,
01929                 "ColourPicker::ForceColourModel - NULL Parameters are illegal");
01930 
01931     // Invalidate the colour's output cache (even if it hasn't really changed - in this
01932     // case we're only causing one weeny little colour conversion, so it's no big deal)
01933     // This is also needed because the above functions expect this call to flush the cache.
01934     Dest->InvalidateCache();
01935 
01936     if (Dest->GetColourModel() != SourceContext->GetColourModel())
01937     {
01938         ColourContext *OldContext = ColourContext::GetGlobalDefault(Dest->GetColourModel());
01939         if (OldContext == NULL)
01940         {
01941             ERROR2RAW("Unable to get colour context for ForceColourModel");
01942             return;
01943         }
01944 
01945         // The colour must be coerced into the new model using secret squirrel private
01946         // methods which we can access only because we are a friend of IndexedColour
01947         ColourGeneric NewDefn;
01948 
01949         Dest->GetSourceColour(&NewDefn);    // Copy into temp space & convert back into the colour
01950         SourceContext->ConvertColour(OldContext, &NewDefn, Dest->SourceColourPtr());
01951 
01952         Dest->SetSourceColourModel(SourceContext->GetColourModel());
01953 
01954         // and once again, flush the cache to make sure the change in model has been noticed
01955         Dest->InvalidateCache();
01956     }
01957 }
01958 
01959 
01960 
01961 /********************************************************************************************
01962 
01963 >   static BOOL ColourPicker::GetTintAsString(IndexedColour *Source, StringBase *Result)
01964 
01965     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01966     Created:    23/8/95
01967 
01968     Inputs:     Source - The colour from which you wish to extract the tint
01969                 
01970     Outputs:    Result - returns containing a decimal (0.0 .. 100.0) string representing
01971                 the value of the tint component of the colour
01972 
01973     Returns:    TRUE if the value converted was out of gamut.
01974 
01975     Purpose:    Retrieves the tint of the given colour as a decimal string appropriate 
01976                 for placing into a colour editor dialogue gadget.
01977 
01978     Notes:      At present, this function clips the value to lie within the legal 0.0 to 1.0
01979                 gamut range.
01980 
01981                 If the colour is not a tint, will ENSURE and return "0%"
01982 
01983     Scope:      private
01984 
01985     SeeAlso:    ColourPicker::SetTintFromString
01986 
01987 ********************************************************************************************/
01988 
01989 BOOL ColourPicker::GetTintAsString(IndexedColour *Source, StringBase *Result)
01990 {
01991     ERROR3IF(Source == NULL || Result == NULL,
01992                 "ColourPicker::GetComponentAsString - NULL parameters are illegal");
01993 
01994     if (Source->GetType() != COLOURTYPE_TINT)
01995     {
01996         ERROR3("ColourPicker::GetTintAsString: Source colour isn't a tint");
01997         *Result = String_8(_R(IDS_CONVERT_ZERO_CHAR)); //TEXT("0");
01998         return(FALSE);
01999     }
02000 
02001     BOOL OutOfGamut = FALSE;
02002     
02003     double CompValue;
02004     if (Source->TintIsShade())
02005         CompValue = Source->GetShadeValueY().MakeDouble();
02006     else
02007         CompValue = Source->GetTintValue().MakeDouble();
02008 
02009     if (CompValue < 0.0)
02010     {
02011         CompValue = 0.0;        // **** Clip out-of-gamut values.
02012         OutOfGamut = TRUE;      // Remember that this was out of gamut
02013     }
02014 
02015     if (CompValue > 1.0)
02016     {
02017         CompValue = 1.0;        // **** Clip out-of-gamut values.
02018         OutOfGamut = TRUE;      // Remember that this was out of gamut
02019     }
02020 
02021     CompValue *= 100.0;
02022 
02023     String_32 TempString;
02024     Convert::DoubleToString(CompValue, (StringBase *) &TempString, 1);
02025 
02026     TempString.Left(Result, 7);
02027 
02028     return(OutOfGamut);
02029 }
02030 
02031 
02032 
02033 /********************************************************************************************
02034 
02035 >   static BOOL ColourPicker::SetTintFromString(IndexedColour *Dest, StringBase *NewValue)
02036 
02037     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02038     Created:    23/8/95
02039     
02040     Inputs:     Dest - the colour to be set
02041                 NewValue - new value (decimal, as 0..100) of the tint
02042 
02043     Outputs:    Dest is updated appropriately
02044     Returns:    TRUE if the value was out of gamut and had to be clipped
02045 
02046     Purpose:    Assumes that the string will be 0..100
02047                 Clips the string value into a 0.0 to 1.0 in-gamut range, and then sets the
02048                 tint component of the converted colour to that value.
02049 
02050     Notes:      ENSUREs and does nothing if the colour is not already a Tint
02051 
02052     Scope:      private
02053 
02054     SeeAlso:    ColourPicker::GetTintAsString
02055 
02056 ********************************************************************************************/
02057 
02058 BOOL ColourPicker::SetTintFromString(IndexedColour *Dest, StringBase *NewValue)
02059 {
02060     ERROR3IF(Dest == NULL || NewValue == NULL,
02061                 "ColourPicker::SetTintFromString - NULL Parameters are illegal");
02062     
02063     if (Dest->GetType() != COLOURTYPE_TINT)
02064     {
02065         ERROR3("ColourPicker::SetTintFromString - colour isn't a tint");
02066         return(FALSE);
02067     }
02068 
02069     // Turn all percent signs in the number to spaces so the StringToDouble doesn't yell and scream
02070     String_8 TempString;
02071     NewValue->Left(&TempString, 7);
02072     TempString.SwapChar(_T('%'), _T(' '));
02073 
02074     // Convert the string to a double using the global conversion routine
02075     // Note that we ignore failure, because the number is validated below, and it
02076     // only seems to retun false if crap was typed on the end of the number anyway
02077     double NewVal;
02078     Convert::StringToDouble(TempString, &NewVal);
02079 
02080     // Convert from percentage to 0.0-1.0 range
02081     NewVal /= 100.0;
02082 
02083     BOOL OutOfGamut = FALSE;
02084 
02085     // Add half of the least-significant-bit-value to round the new value
02086     NewVal += 1.0 / ((double) (1<<25));
02087 
02088     // Clip to lie within gamut
02089     if (NewVal < 0.0)
02090     {
02091         NewVal = 0.0;
02092         OutOfGamut = TRUE;
02093     }
02094 
02095     if (NewVal > 1.0)
02096     {
02097         NewVal = 1.0;
02098         OutOfGamut = TRUE;
02099     }
02100 
02101     // And set the new value
02102     if (Dest->TintIsShade())
02103     {
02104 //      Dest->SetShadeValue(NewVal);
02105     }
02106     else
02107         Dest->SetTintValue(NewVal);
02108 
02109     return(OutOfGamut);
02110 }
02111 
02112 
02113 
02114 /********************************************************************************************
02115 
02116 >   static BOOL ColourPicker::GetShadeValueAsString(IndexedColour *Source, INT32 ValueIndex, StringBase *Result)
02117 
02118     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02119     Created:    24/10/95
02120 
02121     Inputs:     Source - The colour from which you wish to extract the shade value
02122                 ValueIndex - 1 to extract the X component
02123                              2 to extract the Y component
02124 
02125     Outputs:    Result - returns containing a decimal (-100.0 .. 100.0) string representing
02126                 the value of the given shade component of the colour
02127 
02128     Returns:    TRUE if the value converted was out of gamut.
02129 
02130     Purpose:    Retrieves the shade of the given colour as a decimal string appropriate 
02131                 for placing into a colour editor dialogue gadget.
02132 
02133     Notes:      At present, this function clips the value to lie within the legal -1.0 to 1.0
02134                 gamut range.
02135 
02136                 If the colour is not a shade, will ENSURE and return "0%"
02137 
02138     Scope:      private
02139 
02140     SeeAlso:    ColourPicker::SetShadeFromStrings
02141 
02142 ********************************************************************************************/
02143 
02144 BOOL ColourPicker::GetShadeValueAsString(IndexedColour *Source, INT32 ValueIndex, StringBase *Result)
02145 {
02146     ERROR3IF(Source == NULL || Result == NULL,
02147                 "ColourPicker::GetShadeValueAsString - NULL parameters are illegal");
02148 
02149     ERROR3IF(ValueIndex != 1 && ValueIndex != 2, "ColourPicker::GetShadeValueAsString - Illegal ValueIndex parameter");
02150 
02151     if (Source->GetType() != COLOURTYPE_TINT)
02152     {
02153         ERROR3("ColourPicker::GetShadeValueAsString - Source colour isn't a tint");
02154         *Result = String_8(_R(IDS_CONVERT_ZERO_CHAR)); // TEXT("0");
02155         return(FALSE);
02156     }
02157 
02158     BOOL OutOfGamut = FALSE;
02159     
02160     double CompValue;
02161     if (ValueIndex == 1)
02162         CompValue = -Source->GetShadeValueX().MakeDouble();
02163     else
02164         CompValue = Source->GetShadeValueY().MakeDouble();
02165 
02166     if (CompValue < -1.0)
02167     {
02168         CompValue = -1.0;       // **** Clip out-of-gamut values.
02169         OutOfGamut = TRUE;      // Remember that this was out of gamut
02170     }
02171 
02172     if (CompValue > 1.0)
02173     {
02174         CompValue = 1.0;        // **** Clip out-of-gamut values.
02175         OutOfGamut = TRUE;      // Remember that this was out of gamut
02176     }
02177 
02178     CompValue *= 100.0;
02179 
02180     String_32 TempString;
02181     Convert::DoubleToString(CompValue, (StringBase *) &TempString, 1);
02182 
02183     TempString.Left(Result, 7);
02184 
02185     return(OutOfGamut);
02186 }
02187 
02188 
02189 
02190 /********************************************************************************************
02191 
02192 >   static BOOL ColourPicker::SetShadeFromStrings(IndexedColour *Dest, StringBase *NewValueX, StringBase *NewValueY)
02193 
02194     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02195     Created:    24/10/95
02196     
02197     Inputs:     Dest - the colour to be set
02198                 NewValueX - new value (decimal, as -100..100) of the shade X component
02199                 NewValueY - new value (decimal, as -100..100) of the shade Y component
02200 
02201     Outputs:    Dest is updated appropriately
02202     Returns:    TRUE if the value was out of gamut and had to be clipped
02203 
02204     Purpose:    Assumes that the string will be -100..100
02205                 Clips the string value into a -1.0 to 1.0 in-gamut range, and then sets the
02206                 shade components of the converted colour to those values.
02207 
02208     Notes:      ENSUREs and does nothing if the colour is not already a Shade
02209 
02210     Scope:      private
02211 
02212     SeeAlso:    ColourPicker::GetShadeValueAsString
02213 
02214 ********************************************************************************************/
02215 
02216 BOOL ColourPicker::SetShadeFromStrings(IndexedColour *Dest, StringBase *NewValueX, StringBase *NewValueY)
02217 {
02218     ERROR3IF(Dest == NULL || NewValueX == NULL || NewValueY == NULL,
02219                 "ColourPicker::SetShadeFromStrings - NULL Parameters are illegal");
02220     
02221     if (Dest->GetType() != COLOURTYPE_TINT)
02222     {
02223         ERROR3("ColourPicker::SetShadeFromStrings - colour isn't a tint/shade");
02224         return(FALSE);
02225     }
02226 
02227 
02228     // Turn all percent signs in the number to spaces so the StringToDouble doesn't yell and scream
02229     String_8 TempString;
02230     NewValueX->Left(&TempString, 7);
02231     TempString.SwapChar(_T('%'),_T(' '));
02232 
02233     // Convert the string to a double using the global conversion routine
02234     // Note that we ignore failure, because the number is validated below, and it
02235     // only seems to retun false if crap was typed on the end of the number anyway
02236     double NewValX;
02237     Convert::StringToDouble(TempString, &NewValX);
02238 
02239     // Convert from percentage to -1.0-1.0 range
02240     NewValX = (-NewValX) / 100.0;
02241 
02242     BOOL OutOfGamut = FALSE;
02243 
02244     // Add half of the least-significant-bit-value to round the new value
02245     NewValX += 1.0 / ((double) (1<<25));
02246 
02247     // Clip to lie within gamut
02248     if (NewValX < -1.0)
02249     {
02250         NewValX = -1.0;
02251         OutOfGamut = TRUE;
02252     }
02253 
02254     if (NewValX > 1.0)
02255     {
02256         NewValX = 1.0;
02257         OutOfGamut = TRUE;
02258     }
02259 
02260 
02261     // Turn all percent signs in the number to spaces so the StringToDouble doesn't yell and scream
02262     NewValueY->Left(&TempString, 7);
02263     TempString.SwapChar(_T('%'),_T(' '));
02264 
02265     // Convert the string to a double using the global conversion routine
02266     // Note that we ignore failure, because the number is validated below, and it
02267     // only seems to retun false if crap was typed on the end of the number anyway
02268     double NewValY;
02269     Convert::StringToDouble(TempString, &NewValY);
02270 
02271     // Convert from percentage to -1.0-1.0 range
02272     NewValY /= 100.0;
02273 
02274     // Add half of the least-significant-bit-value to round the new value
02275     NewValY += 1.0 / ((double) (1<<25));
02276 
02277     // Clip to lie within gamut
02278     if (NewValY < -1.0)
02279     {
02280         NewValY = -1.0;
02281         OutOfGamut = TRUE;
02282     }
02283 
02284     if (NewValY > 1.0)
02285     {
02286         NewValY = 1.0;
02287         OutOfGamut = TRUE;
02288     }
02289 
02290     Dest->SetShadeValues(FIXED24(NewValX), FIXED24(NewValY));
02291 
02292     return(OutOfGamut);
02293 }
02294 
02295 
02296 
02297 /********************************************************************************************
02298 
02299 >   static void ColourPicker::SetWindowExtent(CWindowID WindowID,
02300                                                 CGadgetID XGadgetID, CGadgetID YGadgetID)
02301 
02302     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02303     Created:    14/11/94
02304     
02305     Inputs:     WindowID - The DialogOp->WindowID member variable of the Dialogue
02306                 XGadgetID - The Gadget ID of the gadget to be at the right side of the dlg
02307                 YGadgetID - The Gadget ID of the gadget to be at the bottom of the dlg
02308 
02309     Purpose:    Private function used by the kernel ColourEditDlg editor.
02310                 Given a WindowID and GadgetID (cf DialogOp->DialogMgr interface), this
02311                 sets the window extent of the window to a short distance outside the right/
02312                 bottom edges of the X/Y named gadgets respectively.
02313 
02314                 The colour editor uses this to 'fold' and 'unfold' its window to hide/show
02315                 the advanced editing options.
02316 
02317     Scope:      private
02318 
02319 ********************************************************************************************/
02320 
02321 void ColourPicker::SetWindowExtent(CWindowID WindowID,
02322                                     CGadgetID XGadgetID, CGadgetID YGadgetID)
02323 {
02324 PORTNOTE("other", "Disable Colourpicker::SetWindowExtent")
02325 #ifndef EXCLUDE_FROM_XARALX
02326     CWindowID hXGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)XGadgetID);
02327     CWindowID hYGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)YGadgetID);
02328 
02329     RECT MainWinPos;
02330     RECT XGadgetPos;
02331     RECT YGadgetPos;
02332     BOOL ok = TRUE;
02333 
02334     // We can't use GetWindowRect() for the gadgets then use these values when adjusting
02335     // the values you get from GetWindowPlacement() for the main window, because they use two
02336     // different origins.
02337     //
02338     // Basically, using the above calls will result in errors if the task bar is at the top of the
02339     // screen, because one call uses the actual screen top-left coord, the other uses the top-ledt coord
02340     // of the desk top excluding the task bar.
02341     //
02342     // The method used here uses GetWindowRect() for all three gadgets to work out a relative difference
02343     // between the gadgets.  It then uses GetWindowPosition() & SetWindowPosition() which work consistantly
02344     // because they use the same coord space.
02345 
02346     // Collect the screen positions of the three items
02347     if (ok) ok = GetWindowRect((CWindowID)WindowID,&MainWinPos);
02348     if (ok) ok = GetWindowRect(hXGadget,&XGadgetPos);
02349     if (ok) ok = GetWindowRect(hYGadget,&YGadgetPos);
02350 
02351     if (ok)
02352     {
02353         // dx & dy are calculated to be the amount we need to adjust the right & bottom of the
02354         // dlg to come in line with the two gadgets given
02355         INT32 dx = MainWinPos.right  - XGadgetPos.right;
02356         INT32 dy = MainWinPos.bottom - YGadgetPos.bottom;
02357 
02358         // Get the window's screen position
02359         if (DialogManager::GetWindowPosition(WindowID, &MainWinPos))
02360         {
02361             // Adjust it (with added help from a bodge value)
02362             MainWinPos.right  -= dx - 6;
02363             MainWinPos.bottom -= dy - 6;
02364 
02365             // Set it back again
02366             DialogManager::SetWindowPosition(WindowID, MainWinPos);
02367         }
02368     }
02369 #endif
02370 }
02371 
02372 
02373 /********************************************************************************************
02374 
02375 >   static void ColourPicker::SetGadgetPositions(CWindowID WindowID,
02376                                                 CGadgetID *Gadgets, CGadgetID MoveUnder)
02377 
02378     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02379     Created:    23/11/94
02380     
02381     Inputs:     WindowID - The DialogOp->WindowID member variable of the Dialogue
02382                 
02383                 Gadgets - A NULL-terminated list of Gadget IDs of the gadgets to be
02384                 moved. The first entry in this list is the anchor gadget - it will be
02385                 moved just under 'MoveUnder', and the others will stay in the same position
02386                 relative to the first gadget in the list.
02387 
02388                 MoveUnder - The gadget ID of the gadget under which all these gadgets
02389                 should be positioned, or NULL to 'hide' the gadgets well off the window
02390 
02391     Purpose:    Private function used by the kernel ColourEditDlg editor.
02392                 Given a WindowID and GadgetIDs (cf DialogOp->DialogMgr interface), this
02393                 moves all the gadgets such that (a) All the gadgets in the group remain
02394                 in the same relative positions, and (b) the Gadgets[0] gadget is moved
02395                 to lie just underneath the MoveUnder gadget.
02396 
02397                 The X positions of the gadgets are unaffected by this call.
02398 
02399                 If MoveUnder == NULL, then the gadgets are moved a large distance away so
02400                 that they will not appear in the visible portion of the window.
02401 
02402                 This is used to move tint/link options to the bottom of the editor window,
02403                 while hiding the link/tint options gadgtes respectively.
02404 
02405     Scope:      private
02406 
02407 ********************************************************************************************/
02408 
02409 void ColourPicker::SetGadgetPositions(CWindowID WindowID,
02410                                         CGadgetID *Gadgets, CGadgetID MoveUnder)
02411 {
02412 PORTNOTE("other", "Disabled ColourPicker::SetGadgetPositions");
02413 #ifndef EXCLUDE_FROM_XARALX
02414     if (Gadgets == NULL || !Gadgets[0])
02415         return;
02416 
02417     CWindowID hGadget;
02418     RECT MoveRect;
02419     POINT TopLeft;
02420     INT32 YShift = 10000;       // If MoveUnder == NULL, move out of the way
02421 
02422     if (MoveUnder)
02423     {
02424         // Get the positions of the MoveUnder and Gadgets[0] gadgets, and work out
02425         // the Y Shift to move Gadgets[0] just under the MoveUnder gadget.
02426         // All calculations are done in Client coords (not screen coords)
02427         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)MoveUnder);
02428         if (!GetWindowRect(hGadget, &MoveRect))
02429             return;
02430 
02431         TopLeft.x = MoveRect.left;
02432         TopLeft.y = MoveRect.bottom;
02433         ScreenToClient((CWindowID)WindowID, &TopLeft);
02434         YShift = -(TopLeft.y + 8);      // Remember first part of the shift
02435 
02436         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[0]);
02437         if (!GetWindowRect(hGadget, &MoveRect))
02438             return;
02439 
02440         TopLeft.x = MoveRect.left;
02441         TopLeft.y = MoveRect.top;
02442         ScreenToClient((CWindowID)WindowID, &TopLeft);
02443 
02444         YShift += TopLeft.y;            // Complete the shift calculation
02445     }
02446     else
02447     {
02448         // Move the gadgets out of view: Check if we need to bother to do this
02449         // (are they aready out of view?)
02450 
02451         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[0]);
02452         if (!GetWindowRect(hGadget, &MoveRect))
02453             return;
02454 
02455         TopLeft.x = MoveRect.left;
02456         TopLeft.y = MoveRect.top;
02457         ScreenToClient((CWindowID)WindowID, &TopLeft);
02458 
02459         if (abs(TopLeft.y) > 8000)      // Is it already out of the way?
02460             YShift = 0;                 // Yes - so don't shift it
02461     }
02462 
02463     if (YShift == 0)                    // No shift needed!
02464         return;
02465 
02466     INT32 Index = 0;
02467     while (Gadgets[Index] != 0)
02468     {
02469         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[Index]);
02470 
02471         if (GetWindowRect(hGadget, &MoveRect))
02472         {
02473             TopLeft.x = MoveRect.left;      // Convert TopLeft coord into client coords
02474             TopLeft.y = MoveRect.top;
02475             ScreenToClient((CWindowID)WindowID, &TopLeft);
02476             TopLeft.y -= YShift;
02477 
02478             SetWindowPos(hGadget, NULL,
02479                             TopLeft.x, TopLeft.y, 0, 0,
02480                             SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
02481         }
02482 
02483         Index++;
02484     }
02485 #endif
02486 }
02487 
02488 
02489 
02490 /********************************************************************************************
02491 
02492 >   static void ColourPicker::SetComponentGadgets(CWindowID WindowID, CGadgetID *Gadgets,
02493                                                     CGadgetID PickerGadget,
02494                                                     ColourModel ModelToDisplay)
02495 
02496     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02497     Created:    5/4/95
02498     
02499     Inputs:     WindowID - The DialogOp->WindowID member variable of the Dialogue
02500                 
02501                 Gadgets - A NULL-terminated list of Gadget IDs of the gadgets to be
02502                 moved/resized. There MUST be 8 gadget IDs, paired up into (name,writable)
02503                 sets.
02504 
02505                 PickerGadget - specifies the gadget under which the controls are spaced.
02506                 If they can be fitted, they will maybe be centered under this control
02507                 in order to look neater.
02508 
02509                 ModelToDisplay - Indicates the model you're going to put into the controls
02510                 This is used to determine how many components should be shown and stuff.
02511 
02512     Purpose:    Private function used by the kernel ColourEditDlg editor.
02513 
02514                 This takes the 4 component names and component writable fields and spreads
02515                 them out within the window to allow the names to go next to the writables.
02516                 The name fileds are resized to fill the available spaces, so you should
02517                 make them right-aligned to keep the text a set disatnce from the writable
02518                 for all colour models.
02519 
02520                 It's still up to you to set the contents of the controls, and hide any extra
02521                 ones (so as much of this crap goes into the kernel as possible). This only
02522                 changes the positions of the first NumComponents control-pairs.
02523 
02524                 It also hides ALL of the windows. This means that while swapping models
02525                 they go off and on, but it looks a lot better than the user seeing all
02526                 the faffing arounf as they are moved, resized, and have their contents
02527                 changed.
02528 
02529     Scope:      private
02530 
02531 ********************************************************************************************/
02532 
02533 void ColourPicker::SetComponentGadgets(CWindowID WindowID, CGadgetID *Gadgets,
02534                                                     CGadgetID PickerGadget,
02535                                                     ColourModel ModelToDisplay)
02536 {
02537 PORTNOTE("other", "Disabled ColourPicker::SetComponentGadgets")
02538 #ifndef EXCLUDE_FROM_XARALX
02539     // Find out how many visible components we're dealing with...
02540     ColourContext *cc = ColourContext::GetGlobalDefault(ModelToDisplay);
02541     INT32 NumComponents = 0;
02542     INT32 i;
02543     if (cc != NULL)
02544     {
02545         for (i = 1; i <= 4; i++)
02546         {
02547             if (cc->GetComponentName(i, NULL))
02548                 NumComponents++;
02549         }
02550     }
02551 
02552     if (NumComponents < 1)
02553         return;
02554 
02555 
02556     RECT TheRect;
02557 
02558     CWindowID hGadget;
02559     INT32 Left = 8;
02560     INT32 MaxWidth = 0;
02561 //  if (NumComponents < 3)
02562     {
02563         // Use width of colour picker control
02564         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)PickerGadget);
02565         if (hGadget && GetWindowRect(hGadget, &TheRect))
02566         {
02567             // convert screen rect to client position within the parent wnd
02568             ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &TheRect, 2);
02569 
02570             MaxWidth = TheRect.right - TheRect.left;
02571             Left = TheRect.left;
02572         }
02573     }
02574 /*
02575     else
02576     {
02577         // Use width of the window
02578         if (GetClientRect((CWindowID)WindowID, &TheRect))
02579         {
02580             MaxWidth = TheRect.right - TheRect.left;
02581             MaxWidth -= 2 * Left;
02582         }
02583     }
02584 */
02585     if (MaxWidth < 1)
02586         return;
02587 
02588 
02589     // We must now fit NumComponents items into MaxWidth pixels
02590     INT32 PairWidth = MaxWidth / NumComponents;
02591 
02592     // Read the writable control size and y position
02593     static INT32 BaseWritableWidth = 0;
02594     hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[1]);
02595     
02596     if (GetWindowRect(hGadget, &TheRect))
02597     {
02598         // Only read the static writable width the first time we do this,
02599         // so that we remember the original size before we started resizing these controls
02600         if (BaseWritableWidth == 0)
02601             BaseWritableWidth = TheRect.right - TheRect.left;
02602     }
02603 
02604     INT32 WritableWidth = BaseWritableWidth;
02605     if (WritableWidth < 1)
02606         return; 
02607 
02608     // If doing 4 components, we use the width of the original writable controls
02609     // If doing fewer components, we make the writables a bit bigger, as there
02610     // is some spare room around to absorb.
02611     if (NumComponents < 4)
02612         WritableWidth += 4;
02613 
02614 // WEBSTER - markn 9/1/97
02615 // We make the room available to the ed fields for HSV be the same as RGB
02616 // The WritableWidth used to only be adjusted for RGB 
02617 //
02618     // The RGBT model has even more room availble ...
02619     if (ModelToDisplay == COLOURMODEL_RGBT || ModelToDisplay == COLOURMODEL_HSVT)
02620         WritableWidth += 8;
02621 
02622 
02623     const INT32 Gap = 3;            // Min. gap between adjacent fields
02624     if (PairWidth - (2*Gap + WritableWidth) > 64)
02625     {
02626         // There is heaps of space. Limit to the max size, and shift the left
02627         // and maxwidth to keep the controls centered.
02628         PairWidth = 64 + 2*Gap + WritableWidth;
02629 
02630         Left += (MaxWidth - (NumComponents * PairWidth)) / 2;
02631         MaxWidth  = NumComponents * PairWidth;
02632     }
02633 
02634 
02635     // Convert the rect from screen to client coords within the parent wnd.
02636     ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &TheRect, 2);
02637 
02638 
02639     // Find the top/bottom position for the text gadgets, in client coords
02640     RECT TextRect;
02641     hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[0]);
02642     if (hGadget == NULL || !GetWindowRect(hGadget, &TextRect))
02643         return;
02644     ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &TextRect, 2);
02645 
02646 
02647     // For each component, place the controls
02648     const INT32 NewWidth  = PairWidth - (2*Gap + WritableWidth);
02649     const INT32 NewHeight = ABS(TheRect.bottom - TheRect.top);  // Don't change the height
02650     INT32 LeftEnd;
02651 
02652     for (i = 0; i < NumComponents; i++)
02653     {
02654         LeftEnd = Left + (i * PairWidth);
02655 
02656         // Move and resize (in x axis only) the text gadget
02657         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[i*2]);
02658         if (hGadget)
02659         {
02660             if (i < NumComponents)
02661             {
02662                 SetWindowPos(hGadget, NULL,
02663                                 LeftEnd, TextRect.top, NewWidth, NewHeight,
02664                                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER |
02665                                 SWP_NOCOPYBITS | SWP_NOREDRAW);
02666             }
02667             else
02668                 ShowWindow(hGadget, SW_HIDE);
02669         }
02670 
02671         LeftEnd += NewWidth + Gap;
02672 
02673         // Move (in x axis only) the writable gadget
02674         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[(i*2)+1]);
02675         if (hGadget)
02676         {
02677             if (i < NumComponents)
02678             {
02679                 SetWindowPos(hGadget, NULL,
02680                                 LeftEnd, TheRect.top, WritableWidth, NewHeight,
02681                                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER |
02682                                 SWP_NOCOPYBITS | SWP_NOREDRAW);
02683             }
02684             else
02685                 ShowWindow(hGadget, SW_HIDE);
02686         }
02687     }
02688 
02689     // Finally, redraw the affected strip of the window, because the controls won't
02690     TheRect.left = 0;       // Left edge of window
02691     TheRect.right = 0x1000; // Infinity as far as the window is concerned
02692     ::InvalidateRect((CWindowID)WindowID, &TheRect, TRUE);
02693 #endif
02694 }
02695 
02696 
02697 
02698 
02699 /********************************************************************************************
02700 
02701 >   static void ColourPicker::SetFixedComponentGadgets(CWindowID WindowID, CGadgetID *Gadgets,
02702                                                     CGadgetID PickerGadget,
02703                                                     ColourModel ModelToDisplay)
02704 
02705     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02706     Created:    23/02/2004
02707     
02708     Inputs:     WindowID - The DialogOp->WindowID member variable of the Dialogue
02709                 
02710                 Gadgets - A NULL-terminated list of Gadget IDs of the gadgets to be
02711                 moved/resized. There MUST be 8 gadget IDs, paired up into (name,writable)
02712                 sets.
02713 
02714                 PickerGadget - specifies the gadget under which the controls are spaced.
02715                 If they can be fitted, they will maybe be centered under this control
02716                 in order to look neater.
02717 
02718                 ModelToDisplay - Indicates the model you're going to put into the controls
02719                 This is used to determine how many components should be shown and stuff.
02720 
02721     Purpose:    Private function used by the kernel ColourEditDlg editor.
02722 
02723                 This takes the 5 component names and component writable fields and spreads
02724                 them out within the window to allow the names to go next to the writables.
02725                 The name fileds are resized to fill the available spaces, so you should
02726                 make them right-aligned to keep the text a set disatnce from the writable
02727                 for all colour models.
02728 
02729                 It's still up to you to set the contents of the controls, and hide any extra
02730                 ones (so as much of this crap goes into the kernel as possible). This only
02731                 changes the positions of the first NumComponents control-pairs.
02732 
02733                 It also hides ALL of the windows. This means that while swapping models
02734                 they go off and on, but it looks a lot better than the user seeing all
02735                 the faffing arounf as they are moved, resized, and have their contents
02736                 changed.
02737 
02738     Scope:      private
02739 
02740 ********************************************************************************************/
02741 
02742 void ColourPicker::SetFixedComponentGadgets(CWindowID WindowID, CGadgetID *Gadgets,
02743                                                     CGadgetID PickerGadget,
02744                                                     ColourModel ModelToDisplay,
02745                                                     INT32 TextWidth[],
02746                                                     INT32 EditWidth[]
02747                                                     )
02748 {
02749 PORTNOTE("other", "Disabled ColourPicker::SetFixedComponentGadgets")
02750 #ifndef EXCLUDE_FROM_XARALX
02751     RECT TheRect;
02752 
02753     CWindowID hGadget;
02754     INT32 Left = 0;
02755     INT32 MaxWidth = 0;
02756 //  if (NumComponents < 3)
02757     {
02758         // Use width of colour picker control
02759         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)PickerGadget);
02760         if (hGadget && GetWindowRect(hGadget, &TheRect))
02761         {
02762             // convert screen rect to client position within the parent wnd
02763             ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &TheRect, 2);
02764 
02765             MaxWidth = TheRect.right - TheRect.left;
02766             Left = TheRect.left;
02767         }
02768     }
02769 
02770     // Use width of the window
02771 //  if (GetClientRect((CWindowID)WindowID, &TheRect))
02772 //  {
02773 //      MaxWidth = TheRect.right - TheRect.left;
02774 //      MaxWidth -= 2 * Left;
02775 //      Left = 0;
02776 //  }
02777 
02778 //  if (MaxWidth < 1)
02779 //      return;
02780 //
02781 
02782     // Find the top/bottom position for the text gadgets, in client coords
02783     RECT TextRect;
02784     hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[0]);
02785     if (hGadget == NULL || !GetWindowRect(hGadget, &TextRect))
02786         return;
02787     ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &TextRect, 2);
02788     INT32 TextHeight = TextRect.bottom-TextRect.top;
02789 
02790     // Get the current position of the first Editable control
02791     RECT EditRect;
02792     hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[1]);
02793     GetWindowRect(hGadget, &EditRect);
02794     ::MapWindowPoints(NULL, (CWindowID)WindowID, (LPPOINT) &EditRect, 2);
02795     INT32 EditHeight = EditRect.bottom-EditRect.top;
02796 
02797     // For each component, place the controls
02798     INT32 LeftEnd = Left;
02799     INT32 i=0;
02800     const INT32 Gap = 4;            // Min. gap between adjacent fields
02801     const INT32 LabelGap = 1;
02802 
02803     for (i = 0; i < 5; i++)
02804     {
02805         // Move and resize (in x axis only) the text gadget
02806         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[i*2]);
02807         if (hGadget)
02808         {
02809             if (TextWidth[i]!=0)
02810             {
02811                 SetWindowPos(hGadget, NULL,
02812                                 LeftEnd, TextRect.top, TextWidth[i], TextHeight,
02813                                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER |
02814                                 SWP_NOCOPYBITS | SWP_NOREDRAW);
02815 
02816                 LeftEnd += TextWidth[i] + LabelGap;
02817             }
02818             else
02819                 ShowWindow(hGadget, SW_HIDE);
02820 
02821         }
02822 
02823         // Move (in x axis only) the writable gadget
02824         hGadget = DialogManager::GetGadget((CWindowID)WindowID, (INT32)Gadgets[(i*2)+1]);
02825         if (hGadget)
02826         {
02827             if (EditWidth[i]!=0)
02828             {
02829                 SetWindowPos(hGadget, NULL,
02830                                 LeftEnd, EditRect.top, EditWidth[i], EditHeight,
02831                                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOZORDER |
02832                                 SWP_NOCOPYBITS | SWP_NOREDRAW);
02833 
02834                 LeftEnd += EditWidth[i] + Gap;
02835             }
02836             else
02837                 ShowWindow(hGadget, SW_HIDE);
02838 
02839         }
02840 
02841     }
02842 
02843     // Finally, redraw the affected strip of the window, because the controls won't
02844     EditRect.left = 0;      // Left edge of window
02845     EditRect.right = 0x1000;    // Infinity as far as the window is concerned
02846     ::InvalidateRect((CWindowID)WindowID, &EditRect, TRUE);
02847 #endif
02848 }
02849 
02850 
02851 /********************************************************************************************
02852 
02853 >   static void ColourPicker::RecursiveBestSize(wxWindow * pwxWindow)
02854 
02855 
02856     Author:     Alex_Bligh <alex@alex.org.uk>
02857     Created:    02/12/2005
02858     Inputs:     pWindow - pointer to window to process
02859     Outputs:    None
02860     Returns:    None
02861     Purpose:    Initialize platform dependent resources
02862     Errors:     -
02863     SeeAlso:    -
02864 
02865 ********************************************************************************************/
02866 
02867 void ColourPicker::RecursiveBestSize(wxWindow * pwxWindow)
02868 {
02869     if (pwxWindow->IsShown())
02870     {
02871         // Now process children if any
02872         wxWindowList::Node * pNode = pwxWindow->GetChildren().GetFirst();
02873         while (pNode)
02874         {
02875             RecursiveBestSize(pNode->GetData());
02876             pNode = pNode->GetNext();
02877         }
02878     }
02879 
02880     pwxWindow->InvalidateBestSize();
02881 
02882     wxSizer * s=pwxWindow->GetSizer();
02883 
02884     // Shrink this window around any sizer it contains
02885     pwxWindow->Layout();
02886     pwxWindow->Fit();
02887     if (s)
02888         s->SetSizeHints(pwxWindow);
02889 
02890     if (pwxWindow->IsShown())
02891         if ((s_UserSize != wxDefaultSize) && ((ResourceID)(pwxWindow->GetId()) == _R(IDC_EDIT_PICKER)))
02892             pwxWindow->SetSize(s_UserSize);
02893         else
02894             pwxWindow->SetSize(pwxWindow->GetMinSize());
02895     else
02896         pwxWindow->SetSize(wxSize(1,1));
02897 
02898     return;
02899 }
02900 
02901 /********************************************************************************************
02902 
02903 >   void ColourPicker::RelayoutDialog(CWindowID WindowID)
02904 
02905     Author:     Alex Bligh
02906     Created:    30/5/2005
02907     Inputs:     -
02908     Purpose:    Ensure the dialog is a sensible size
02909     Scope:      Protected
02910 
02911 ********************************************************************************************/
02912 
02913 void ColourPicker::RelayoutDialog(CWindowID WindowID)
02914 {
02915     static INT32 flag=0;
02916 
02917     if (s_InColourDialogLayout)
02918     {
02919         TRACEUSER("amb", _T("Recursive colour dialog layout"));
02920         return; // this should not happen
02921     }
02922 
02923     s_InColourDialogLayout = TRUE;
02924 
02925     wxWindow * pPicker=DialogManager::GetGadget(WindowID, _R(IDC_EDIT_PICKER));
02926     if (pPicker)
02927         pPicker->Freeze();
02928     WindowID->Freeze();
02929 
02930     if (pPicker && (s_UserSize != wxDefaultSize))
02931     {
02932         // Ensure no amount of sizing uses a different size for the picker to the one we want
02933         pPicker->SetSize(pPicker->GetSize().GetWidth()+1, pPicker->GetSize().GetHeight()+1); // cause a resize
02934         WindowID->Layout();
02935         WindowID->Fit();
02936         wxSizer * pSizer = WindowID->GetSizer();
02937         if (pSizer)
02938             pSizer->SetSizeHints(WindowID);
02939         pPicker->SetMinSize(s_UserSize);
02940         pPicker->SetMaxSize(s_UserSize);
02941         pPicker->SetSize(s_UserSize);
02942     }
02943 
02944     RecursiveBestSize(WindowID);
02945 
02946     ArtificialSizeEvents(WindowID);
02947     if (!flag)
02948     {
02949         flag++;
02950         wxPlatformDependent::Get()->RealYield();
02951         flag--;
02952     }
02953 
02954     // And now do it again with the minimum size for the colour picker restored so the dialog
02955     // can shrink
02956 
02957     if (pPicker && (s_UserSize != wxDefaultSize))
02958     {
02959         // If s_JustCreated is set, use s_UserSize
02960         pPicker->SetMinSize((s_JustCreated && (s_UserSize != wxDefaultSize))?s_UserSize:s_MinSize);
02961         pPicker->SetMaxSize(wxDefaultSize);
02962     }
02963 
02964     RecursiveBestSize(WindowID);
02965 
02966     ArtificialSizeEvents(WindowID);
02967     if (!flag)
02968     {
02969         flag++;
02970         wxPlatformDependent::Get()->RealYield();
02971         flag--;
02972     }
02973 
02974     WindowID->Thaw();
02975     if (pPicker)
02976     {
02977         pPicker->Thaw();
02978         pPicker->Refresh();
02979     }
02980 
02981     // Now, even having done the above, believe it or not some of the GTK sizing code seems
02982     // to run off idles. So we have to ignore some OnSize events because the idle events
02983     // may not be out the system yet. Sigh... Why can't GTK resize sychronously?
02984 
02985     s_IdleCounter = 3; // 3 more idle counts before we use an OnSize (somewhat arbitrary)
02986     GetApplication()->NeedMoreIdles(); // wake up idle system
02987     s_InColourDialogLayout = FALSE;
02988 }
02989 
02990 /********************************************************************************************
02991 
02992 >   void ColourPicker::ArtificialSizeEvents(CWindowID WindowID)
02993 
02994     Author:     Alex Bligh
02995     Created:    30/5/2005
02996     Inputs:     -
02997     Purpose:    Produce artificial size events recursively
02998     Scope:      Protected
02999 
03000 On GTK at least, sizing does not occur synchronously. Some of it happens on size
03001 events from a gtk_window_size_callback. For various reasons (like the necessity
03002 for a wxyield) this is not great). So we produce them ourselves.
03003 
03004 ********************************************************************************************/
03005 
03006 void ColourPicker::ArtificialSizeEvents(CWindowID WindowID)
03007 {
03008     if (!WindowID->IsShown())
03009         return;
03010 
03011     // size children first
03012     wxWindowList::Node * pNode = WindowID->GetChildren().GetFirst();
03013     while (pNode)
03014     {
03015         ArtificialSizeEvents(pNode->GetData());
03016         pNode = pNode->GetNext();
03017     }
03018 
03019     wxSizeEvent event( WindowID->GetSize(), WindowID->GetId() );
03020     event.SetEventObject( WindowID );
03021     WindowID->GetEventHandler()->ProcessEvent( event );
03022 }
03023 
03024 /********************************************************************************************
03025 
03026 >   void ColourPicker::OnSize(CWindowID WindowID)
03027 
03028     Author:     Alex Bligh
03029     Created:    30/5/2005
03030     Inputs:     -
03031     Purpose:    Respond to size events
03032     Scope:      Protected
03033 
03034 ********************************************************************************************/
03035 
03036 void ColourPicker::OnSize(CWindowID WindowID)
03037 {
03038     wxWindow * pGadget = DialogManager::GetGadget(WindowID, _R(IDC_EDIT_PICKER));
03039     if (pGadget)
03040     {
03041         wxSize NewSize = pGadget->GetSize();
03042         
03043         if (s_LastSize != NewSize)
03044         {
03045             // Record the new size
03046             s_LastSize = NewSize;
03047             if (!s_InColourDialogLayout && !s_IdleCounter && WindowID->IsShown())
03048             {
03049                 // It must have been user initiated
03050                 s_UserSize = NewSize;
03051             }
03052         }
03053     }
03054 }
03055 
03056 /********************************************************************************************
03057 
03058 >   BOOL ColourPicker::OnIdleEvent(CWindowID WindowID)
03059 
03060     Author:     Alex Bligh
03061     Created:    30/5/2005
03062     Inputs:     -
03063     Purpose:    Respond idle events
03064     Scope:      Protected
03065 
03066 ********************************************************************************************/
03067 
03068 BOOL ColourPicker::OnIdleEvent(CWindowID WindowID)
03069 {
03070     if (s_InColourDialogLayout)
03071         return FALSE; // That's not a real idle
03072 
03073     if (s_IdleCounter>0)
03074     {
03075         s_IdleCounter--;
03076     }
03077 
03078     if (s_JustCreated && !s_IdleCounter)
03079     {
03080         // We've just been created so we need to do a post open resize
03081         s_JustCreated=FALSE;
03082         RelayoutDialog(WindowID);
03083     }
03084 
03085     return (s_IdleCounter!=0); // we want more events
03086 }
03087 
03088 /********************************************************************************************
03089 
03090 >   void ColourPicker::OnCreate(CWindowID WindowID)
03091 
03092     Author:     Alex Bligh
03093     Created:    30/5/2005
03094     Inputs:     -
03095     Purpose:    Respond to size events
03096     Scope:      Protected
03097 
03098 ********************************************************************************************/
03099 
03100 void ColourPicker::OnCreate(CWindowID WindowID)
03101 {
03102     s_IdleCounter=0;
03103     s_JustCreated=TRUE;
03104 
03105     // Fix the window size so Open doesn't overwrite it (grrrr)
03106     wxWindow * pPicker=DialogManager::GetGadget(WindowID, _R(IDC_EDIT_PICKER));
03107     if (pPicker && (s_UserSize != wxDefaultSize))
03108     {
03109         // Ensure no amount of sizing uses a different size for the picker to the one we want
03110         pPicker->SetSize(pPicker->GetSize().GetWidth()+1, pPicker->GetSize().GetHeight()+1); // cause a resize
03111         WindowID->Layout();
03112         WindowID->Fit();
03113         wxSizer *pSizer = WindowID->GetSizer();
03114         if (pSizer)
03115             pSizer->SetSizeHints(WindowID);
03116         pPicker->SetMinSize(s_UserSize);
03117         pPicker->SetMaxSize(s_UserSize);
03118         pPicker->SetSize(s_UserSize);
03119     }
03120 }

Generated on Sat Nov 10 03:48:17 2007 for Camelot by  doxygen 1.4.4