coldlog.cpp

Go to the documentation of this file.
00001 // $Id: coldlog.cpp 1685 2006-08-09 19:25:40Z 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 // Implementation of the following classes
00100 //
00101 //  ColourEditDlg   Colour editor dialogue box
00102 
00103 /*
00104 */
00105 
00106 
00107 
00108 //-----------------------------------------------------------------------------------------
00109 // Include files
00110 
00111 #include "camtypes.h"
00112 
00113 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "barsdlgs.h"
00116 #include "bubbleid.h" 
00117 #include "camelot.h" 
00118 #include "ccolbar.h"
00119 #include "colcontx.h"
00120 #include "coldlog.h"
00121 #include "coldrop.h"
00122 #include "colmenu.h"
00123 #include "colormgr.h"
00124 #include "colourix.h"
00125 #include "colpick.h"
00126 #include "ctrlhelp.h"
00127 //#include "cursor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 #include "dlgmgr.h"
00129 //#include "dlgtypes.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00130 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00131 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00132 #include "dragcol.h"
00133 #include "dragmgr.h"
00134 #include "dragpick.h"
00135 //#include "ensure.h"   - in camtypes.h [AUTOMATICALLY REMOVED]
00136 //#include "errors.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00137 #include "helpuser.h"       // For HelpUser()
00138 //#include "ink.h"          // For NodeRenderableInk - in camtypes.h [AUTOMATICALLY REMOVED]
00139 //#include "jason.h"
00140 #include "keypress.h"       // For constrain, escape, and OnKeyPress stuff
00141 #include "lineattr.h"       // For AttrStrokeColour
00142 //#include "msg.h"  - in camtypes.h [AUTOMATICALLY REMOVED]
00143 #include "newcol.h"         // New colour dlg
00144 #include "nodedoc.h"
00145 #include "oilprog.h"        // For Beep()
00146 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00147 #include "optsmsgs.h"       // For OptionsChangingMsg
00148 #include "progress.h"
00149 //#include "resource.h"
00150 #include "scunit.h"         // For colour units
00151 #include "optsunit.h"       // For default colour units
00152 #include "sgcolour.h"       // For ColourNameDlg
00153 //#include "will2.h"            // For string resources (v1.1)
00154 
00155 #include "ccdc.h"           // For render-into-dialogue support
00156 #include "dlgcol.h"
00157 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00158 #include "grnddib.h"
00159 #include "palman.h"
00160 
00161 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00162 #include "objchge.h"
00163 
00164 // include files necessary for correctly supporting camelots CColourPicker custom control
00165 //#include "mainfrm.h"
00166 #include "statline.h"
00167 #include "ophist.h"
00168 #include "layer.h"
00169 
00170 const ResourceID ColourEditDlg::IDD = _R(IDD_COLOUREDITDLG);
00171 
00172 //-----------------------------------------------------------------------------------------
00173 
00174 // The kernel colour picker - called via the winoil ColourPicker class
00175 CC_IMPLEMENT_DYNCREATE(ColourEditDlg, DialogOp)
00176 CC_IMPLEMENT_DYNAMIC(ColEditorDragTarget, KernelDragTarget)
00177 CC_IMPLEMENT_DYNCREATE(ColEditorDragInfo, ColourDragInformation)
00178 CC_IMPLEMENT_DYNCREATE(OpMakeColourLocalToFrame, UndoableOperation)
00179 
00180 
00181 // CAM_DEBUG_NEW is defined a couple of pages further down...
00182 
00183 //-----------------------------------------------------------------------------------------
00184 
00185 /********************************************************************************************
00186 
00187     Preference:     ColourEditorAutoModel
00188     Section:        Displays
00189     Range:          TRUE or FALSE
00190     Purpose:        If TRUE, the colour editor will automatically switch the display colour
00191                     model whenever it switches to a new LOCAL colour (to that colour's model)
00192                     If FALSE, the only time the display colour model will change is when
00193                     the user explicitly sets a different colour model from the dialogue.
00194     Notes:          Normal preference, available from the options dialogue.
00195     SeeAlso:        ColourEditDlg
00196 
00197 ********************************************************************************************/
00198 
00199 /********************************************************************************************
00200 
00201     Preference:     ColourEditorAutoModelN
00202     Section:        Displays
00203     Range:          TRUE or FALSE
00204     Purpose:        If TRUE, the colour editor will automatically switch the display colour
00205                     model whenever it switches to a new NAMED colour (Colour STYLE) (to that
00206                     colour's model)
00207                     If FALSE, the only time the display colour model will change is when
00208                     the user explicitly sets a different colour model from the dialogue.
00209     Notes:          Normal preference, available from the options dialogue.
00210     SeeAlso:        ColourEditDlg
00211 
00212 ********************************************************************************************/
00213 
00214 /********************************************************************************************
00215 
00216     Preference:     ColourEditorDisplayModel
00217     Section:        Displays
00218     Range:          1..15 (COLOURMODEL_XXXX enum). If an invalid setting is chosen,
00219                     then COLOURMODEL_HSVT will be selected by default
00220     Purpose:        Retains a 'memory' of the last used Colour Editor display model
00221                     between sessions in Camelot. Used for LOCAL COLOURS
00222     Notes:          Internal 'memory' preference, not directly settable by the user
00223     SeeAlso:        ColourEditDlg; ColourModel
00224 
00225 ********************************************************************************************/
00226 
00227 /********************************************************************************************
00228 
00229     Preference:     ColourEditorDisplayModelN
00230     Section:        Displays
00231     Range:          1..15 (COLOURMODEL_XXXX enum). If an invalid setting is chosen,
00232                     then COLOURMODEL_HSVT will be selected by default
00233     Purpose:        Retains a 'memory' of the last used Colour Editor display model
00234                     between sessions in Camelot. used for COLOUR STYLES
00235     Notes:          Internal 'memory' preference, not directly settable by the user
00236     SeeAlso:        ColourEditDlg; ColourModel
00237 
00238 ********************************************************************************************/
00239 
00240 /********************************************************************************************
00241 
00242     Preference:     ColourEditorFolded
00243     Section:        Displays
00244     Range:          TRUE or FALSE
00245     Purpose:        Retains a 'memory' of the colour editor 'folded' state between
00246                     sessions in Camelot.
00247     Notes:          Internal 'memory' preference, not directly settable by the user
00248     SeeAlso:        ColourEditDlg
00249 
00250 ********************************************************************************************/
00251 
00252 /********************************************************************************************
00253 
00254     Preference:     ColourEditorSplitLine
00255     Section:        Displays
00256     Range:          TRUE or FALSE
00257     Purpose:        Determines if the sliders in the colour editor show a 'split line'
00258                     display. If FALSE, a simple display is given where each slider just
00259                     shows the component being set (e.g. in RGB, the Red slider shades
00260                     between black and red)
00261                     If TRUE, the split mode is enabled, where the slider shows the normal
00262                     grad-fill in the top half (black to red), but fills the bottom half
00263                     with the range of colours which will result from changing that 
00264                     component of the edited colour (i.e. at any point on the slider it
00265                     shows what colour you will get if you click on that spot)
00266     Notes:          Secret squirrel preference! THis may become available in the options
00267                     dialogue if it is decided that it is useful.
00268     SeeAlso:        ColourEditDlg
00269 
00270 ********************************************************************************************/
00271 
00272 /********************************************************************************************
00273 
00274     Preference:     ColourEditorUse3D
00275     Section:        Displays
00276     Range:          TRUE or FALSE
00277     Purpose:        If FALSE, the RGB/CMYK colour pickers in the colour editor will be
00278                     simple sliders. If TRUE, the '3d colour cube' display will be used instead
00279     SeeAlso:        ColourEditDlg
00280 
00281 ********************************************************************************************/
00282 
00283 /********************************************************************************************
00284 
00285     Preference:     ColourEditorHSVHueTop
00286     Section:        Displays
00287     Range:          TRUE or FALSE
00288     Purpose:        If TRUE, the HSV colour picker shows the SV Pane with full hue at the top
00289                     (as all version did prior to Xara X1)
00290                     If FALSE, the HSV colour picker shows the SV Pane with full hue at the bottom
00291     SeeAlso:        ColourEditDlg
00292 
00293 ********************************************************************************************/
00294 
00295 /********************************************************************************************
00296 
00297     Preference:     UsePrintCMYK
00298     Section:        Displays
00299     Range:          TRUE or FALSE
00300     Purpose:        If TRUE, use print profile to do RGB-CMYK colour conversion
00301     SeeAlso:        ColourEditDlg
00302 
00303 ********************************************************************************************/
00304 
00305 
00306 // PREFERENCES
00307 INT32 ColourEditDlg::DefaultDisplayModel  = (INT32) COLOURMODEL_HSVT;
00308 INT32 ColourEditDlg::DefaultDisplayModelN = (INT32) COLOURMODEL_HSVT;
00309 INT32 ColourEditDlg::AutoModelChange    = FALSE;            // When new colour set, change Displaymodel (LOCAL)
00310 
00311 // WEBSTER - markn 31/1/97
00312 // Don't autochange named colour display model (i.e. set to FALSE instead of TRUE
00313 #ifndef WEBSTER
00314 INT32 ColourEditDlg::AutoModelChangeN = TRUE;           // When new colour set, change Displaymodel (STYLE)
00315 #else
00316 INT32 ColourEditDlg::AutoModelChangeN = FALSE;          // When new colour set, change Displaymodel (STYLE)
00317 #endif // WEBSTER
00318 
00319 INT32 ColourEditDlg::Folded         = TRUE;             // Is the dlg folded?
00320 INT32 ColourEditDlg::SplitLineDisplay   = FALSE;            // Show sliders in split gradfill way
00321 INT32 ColourEditDlg::Use3DDisplay       = FALSE;            // Show sliders rather than colourcube
00322 
00323 // If FALSE turns the SV square upside down compared to previous versions
00324 BOOL ColourEditDlg::bHSVHueAtTop = TRUE;
00325 
00326 BOOL ColourEditDlg::bUsePrintCMYK = TRUE;
00327 
00328 //-----------------------------------------------------------------------------------------
00329 
00330 // Statics
00331 BOOL ColourEditDlg::EditingLineColour = FALSE;          // Default to editing local fill colours
00332 BOOL ColourEditDlg::UpdateOnNextIdle  = FALSE;          // Callback - Update the dialogue on the next idle event
00333 
00334 BOOL ColourEditDlg::resetColPickPos;                    // by default - we don't need to reset
00335 RECT ColourEditDlg::colPickOrigRect;                    // store the original location of
00336                                                         // custom colour picker control
00337 BOOL ColourEditDlg::needColPickHidden;
00338 BOOL ColourEditDlg::colPickHidden;
00339 
00340 AbortColourState ColourEditDlg::abortColourState;
00341 
00342 BOOL ColourEditDlg::EscapeKeyWasPressed = FALSE;        // record the fact of whether the
00343                                                         // escape key has been pressed.
00344 
00345 // NOTE:  the above variable is used as a bodge fix.  For some reason, ColourEditDlg::OnKeyPress ()
00346 //        (which internally calls SetNewValueFromMousePos ()) seems to be failing to detect that
00347 //        the escape key is pressed.  Since OnKeyPress already knows this, lets record this fact
00348 //        and take things from there.  Although this is a bodge fix, this new method actually
00349 //        appears to work better than the original (I can't find the problem) one.
00350 
00351 /***********************************************************************************************
00352 
00353 >   class ColourEditDlgParam : public OpParam
00354 
00355     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00356     Created:    14/10/94
00357 
00358     Purpose:    The OpParam to use when Invoke()ing the ColourEditDlg
00359                 You shouldn't ever need to use this - just call the static function
00360                 ColourEditDlg::InvokeDialog if you want a colour editor
00361 
00362     Scope:      private
00363     SeeAlso:    ColourEditDlg::InvokeDialog; ColourPicker::EditColour
00364 
00365 ***********************************************************************************************/
00366 
00367 class ColourEditDlgParam : public OpParam
00368 {
00369 CC_DECLARE_MEMDUMP(ColourEditDlgParam)
00370 
00371 public:
00372     ColourEditDlgParam(ColourList *TheParentList, IndexedColour *TheColourToEdit)   \
00373                     : OpParam(0, 0)                                                 \
00374             { ParentList = TheParentList; ColourToEdit = TheColourToEdit; };
00375 
00376     ColourList      *ParentList;
00377     IndexedColour   *ColourToEdit;
00378 };
00379 
00380 
00381 CC_IMPLEMENT_MEMDUMP(ColourEditDlgParam, OpParam)
00382 
00383 
00384 
00385 //-----------------------------------------------------------------------------------------
00386 // This must be defined AFTER all CC_IMPLEMENT_DYNCREATE calls
00387 #define new CAM_DEBUG_NEW
00388 
00389 
00390 //-----------------------------------------------------------------------------------------
00391 // Local (file or class scope) constants/statics
00392 
00393 const INT32 CROSSRADIUS = 6000;     // Marker cross is 1/6th of an inch across (millipoints)
00394 const INT32 PCROSSRADIUS = 3500;        // Marker cross to indicate parent position is smaller
00395 const INT32 ZSLIDERSIZE = 8000;     // Size of Z slider in 3d mode
00396 const INT32 PATCHSIZE   = 13500;        // Size of original/current colour patch square
00397 
00398 const CDlgMode ColourEditDlg::Mode = MODELESS;          // Mode of the dialog  
00399 
00400 ColourEditDlg *ColourEditDlg::TheEditor = NULL;         // THE instantiation of this dlg
00401 ColourModel ColourEditDlg::DisplayModel = COLOURMODEL_HSVT; // Default DisplayModel
00402 INT32 ColourEditDlg::ColourPickerMode = 0;              // Default picker axis orientation
00403 
00404 
00405 static CGadgetID TintGadgetIDs[] =  // NULL terminated list of special tint gadgets
00406 {
00407     _R(IDC_EDIT_TINTNAME),              // This first item is used to determine positioning
00408     _R(IDC_EDIT_TINT),
00409     _R(IDC_EDIT_TINTPERCENT),
00410 //  _R(IDC_EDIT_TINTSLIDER),
00411     _R(IDC_EDIT_SHADE),
00412     _R(IDC_EDIT_SHADEPERCENT),
00413     0
00414 };
00415 
00416 
00417 static CGadgetID LinkGadgetIDs[] =  // NULL terminated list of special linked-colour gadgets
00418 {
00419     _R(IDC_EDIT_INHERITNAME),           // This first item is used to determine positioning
00420     _R(IDC_EDIT_INHERIT1),
00421     _R(IDC_EDIT_INHERIT2),
00422     _R(IDC_EDIT_INHERIT3),
00423     _R(IDC_EDIT_INHERIT4),
00424     0
00425 };
00426 
00427 
00428 static CGadgetID OtherGadgetIDs[] = // NULL terminated list of all non tint/link gadgets
00429 {                                   // which should be shaded to shade the dialogue
00430     _R(IDC_EDIT_NAMEMENU),
00431     _R(IDC_EDIT_COMPONENT1),
00432     _R(IDC_EDIT_COMPONENT2),
00433     _R(IDC_EDIT_COMPONENT3),
00434     _R(IDC_EDIT_COMPONENT4),
00435     _R(IDC_EDIT_WEBHEX),
00436     _R(IDC_NAME_COMPONENT1),
00437     _R(IDC_NAME_COMPONENT2),
00438     _R(IDC_NAME_COMPONENT3),
00439     _R(IDC_NAME_COMPONENT4),
00440     _R(IDC_NAME_WEBHEX),
00441     _R(IDC_EDIT_COLMODEL),
00442     _R(IDC_EDIT_3D),
00443     _R(IDC_EDIT_COLTYPE),
00444     _R(IDC_EDIT_MAKESTYLE),
00445 #ifndef WEBSTER
00446     _R(IDC_EDIT_ADVANCED),  // WEBSTER - markn 11/12/96
00447 #endif // WEBSTER
00448     _R(IDC_EDIT_DROPMENU),
00449     _R(IDC_EDIT_PARENTCOL),
00450     _R(IDC_EDIT_PARENTNAME),
00451     _R(IDC_EDIT_216ONLY),
00452 //  WEBSTER-ranbirr-27/03/97
00453     _R(IDC_EDIT_NOCOLOUR),
00454     _R(IDC_EDIT_LINEFILL),
00455     _R(IDC_MAKE_LOCAL),
00456     _R(IDC_EDIT_RENAME),
00457     _R(IDC_COLOURPICKER),
00458     0
00459 };
00460 
00461 typedef struct
00462 {
00463     CGadgetID   Gadget;                     // Gadget ID
00464     UINT32      BubbleID;                   //Bubble help ID for this gadget
00465 } GadgetHelpInfo;
00466 
00467 static GadgetHelpInfo GadgetHelp[] = 
00468 {
00469     { _R(IDC_EDIT_DROPMENU),    _R(IDS_EDITBH_MENU) },
00470     { _R(IDC_EDIT_COLMODEL),    _R(IDS_EDITBH_COLMODEL) },
00471     { _R(IDC_EDIT_NAMEMENU),    _R(IDS_EDITBH_NAME) },
00472     { _R(IDC_EDIT_COLTYPE),     _R(IDS_EDITBH_COLTYPE) },
00473     { _R(IDC_EDIT_INHERIT1),    _R(IDS_EDITBH_INHERIT) },
00474     { _R(IDC_EDIT_INHERIT2),    _R(IDS_EDITBH_INHERIT) },
00475     { _R(IDC_EDIT_INHERIT3),    _R(IDS_EDITBH_INHERIT) },
00476     { _R(IDC_EDIT_INHERIT4),    _R(IDS_EDITBH_INHERIT) },
00477     { _R(IDC_EDIT_PARENTCOL),   _R(IDS_EDITBH_PARENTCOL) },
00478     { _R(IDC_EDIT_3D),          _R(IDS_EDITBH_3D) },
00479     { _R(IDC_EDIT_MAKESTYLE),   _R(IDS_EDITBH_MAKESTYLE) },
00480     { _R(IDC_EDIT_NOCOLOUR),    _R(IDS_COLBAR_HNOCOLOUR) },
00481     { _R(IDC_EDIT_LINEFILL),    _R(IDS_EDITBH_LINEFILL) },
00482     { _R(IDC_EDIT_216ONLY),     _R(IDS_EDITBH_216ONLY)  },
00483     { _R(IDC_MAKE_LOCAL),       _R(IDS_EDITBH_MAKE_LOCAL)   },
00484     { _R(IDC_EDIT_RENAME),      _R(IDS_COLBAR_HNOCOLOUR) },
00485     { _R(IDC_COLOURPICKER),     _R(IDS_STATICCOLOURPICKERTOOLHELP) },
00486     { 0, 0 }                            // List terminator
00487 };
00488 
00489 
00490 // Two utility functions to get slider sizing right
00491 
00492 INT32 GetSliderHeight(INT32 RectHeight, INT32 Num)
00493 {
00494     INT32 AvailableHeight = (RectHeight / Num) - 4000; // subtract the minimum gap size
00495     if (AvailableHeight<2000)
00496         AvailableHeight = 2000; // minimum height
00497     return (AvailableHeight>18000)?18000:AvailableHeight;
00498 }
00499 
00500 INT32 GetSliderGap(INT32 RectHeight, INT32 Num)
00501 {
00502     INT32 SliderGap = (RectHeight / Num) - GetSliderHeight(RectHeight, Num);
00503     if (SliderGap < 4000)
00504         SliderGap = 4000;
00505     return SliderGap;
00506 }
00507 
00508 
00509 /********************************************************************************************
00510 
00511 >   void ColourEditDlg::LoseKeyboardFocus(void)
00512 
00513     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00514     Created:    19/5/95
00515 
00516     Purpose:    Colour Editor focus bodge thingummy
00517                 Returns the input focus back to the selected document (mainframe window)
00518 
00519 ********************************************************************************************/
00520 
00521 static BOOL TextMayBeWrong = FALSE;                     // Flag indicating that we might need to update
00522                                                         // a component field when losing the keyboard focus
00523 
00524 static BOOL LoseKbdFocusPending = FALSE;                // Flag used to indicate to the OnIdleEvent
00525                                                         // handler that we wish to lose the kbd focus
00526 
00527 static BOOL LockLoseFocus = FALSE;                      // TRUE if focus-losing is locked (we are nto allowed
00528                                                         // to try to throw away the input focus while it's TRUE)
00529 
00530 static BOOL LoseFocusFromEditControls = FALSE;          // TRUE if we should lose the focus if it's inside an
00531                                                         // edit/writable control. Usually FALSE except on commit.
00532 
00533 void ColourEditDlg::LoseKeyboardFocus(void)
00534 {
00535 //  ControlHelper::BubbleHelpDisable();                 // Ensure any open bubble help is killed
00536 
00537     if (!LockLoseFocus)
00538     {
00539         // If we don't want to throw away the focus from edit controls, we'll check for that case
00540         if (!LoseFocusFromEditControls)
00541         {
00542             // AWOOGA! NASTY WINOIL CODE HACK NASTINESS YUCK YUCK YUCK !!!! ****
00543             CWindowID Focus = wxWindow::FindFocus();
00544             if (Focus != NULL)
00545             {
00546                 static UINT32 WritableGadgets[] = 
00547                 {
00548                     _R(IDC_EDIT_COMPONENT1),
00549                     _R(IDC_EDIT_COMPONENT2),
00550                     _R(IDC_EDIT_COMPONENT3),
00551                     _R(IDC_EDIT_COMPONENT4),
00552                     _R(IDC_EDIT_WEBHEX),
00553                     _R(IDC_EDIT_TINT),
00554                     _R(IDC_EDIT_SHADE),
00555                     _R(IDC_COLOURPICKER),
00556                     //_R(IDC_EDIT_216ONLY),
00557                     0
00558                 };
00559 
00560                 // Look to see if the input focus belonhgs to an edit control in our window.
00561                 // If it does, then we won't throw the focus away - we'll return immediately.
00562                 INT32 i = 0;
00563                 while (WritableGadgets[i])
00564                 {
00565                     if (Focus == DialogManager::GetGadget(WindowID, WritableGadgets[i]))
00566                         return;
00567 
00568                     i++;
00569                 }
00570             }
00571         }
00572 
00573         DialogManager::DefaultKeyboardFocus();
00574 
00575         // And ensure that all component gadgets are updated - if the user was editing
00576         // in one, then we need to chop it back to displaying the value to 1 d.p. with a %, etc
00577         if (EditingColour != NULL && TextMayBeWrong)
00578         {
00579             SetComponentInfo(1, _R(IDC_NAME_COMPONENT1), _R(IDC_EDIT_COMPONENT1), _R(IDC_EDIT_INHERIT1));
00580             SetComponentInfo(2, _R(IDC_NAME_COMPONENT2), _R(IDC_EDIT_COMPONENT2), _R(IDC_EDIT_INHERIT2));
00581             SetComponentInfo(3, _R(IDC_NAME_COMPONENT3), _R(IDC_EDIT_COMPONENT3), _R(IDC_EDIT_INHERIT3));
00582             SetComponentInfo(4, _R(IDC_NAME_COMPONENT4), _R(IDC_EDIT_COMPONENT4), _R(IDC_EDIT_INHERIT4));   
00583 
00584             SetAllHexComponentsInfo ((UINT32)-1, _R(IDC_NAME_WEBHEX), _R(IDC_EDIT_WEBHEX));
00585         }
00586 
00587         TextMayBeWrong = FALSE;
00588 
00589         LoseKbdFocusPending = FALSE;        // And clear the pending flag
00590     }
00591 }
00592 
00593 
00594 /********************************************************************************************
00595 
00596 > BOOL ColourEditDlg::SetUnitGroupDefaults(ColourModel ColModel)
00597 
00598     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00599     Created:    02/05/96
00600     Imputs:     ColModel = colour model we're editing (for WEBSTER - markn 9/1/97)
00601     Purpose:    Sets the default ScaleUnits for the Colour Editor (actually sets
00602                 StandardUnit groups.
00603     Errors:     ERROR3 if unable to initialize defaults
00604     Scope:      static
00605     SeeAlso:    class StandardUnit
00606 
00607 ********************************************************************************************/
00608 BOOL ColourEditDlg::SetUnitGroupDefaults(ColourModel ColModel)
00609 {
00610 // WEBSTER - markn 9/1/97
00611 // Rather than get the unit preference from the units tab (which doesn't exist in Webster)
00612 // it chooses between percent ('%') and 0-255 ('d') unit types dependant on the colour model.
00613 // HSV shows its values in '%' format
00614 // RGB shows its values in 0-255 format
00615 //
00616 
00617 #ifdef WEBSTER
00618 // WEBSTER - markn 23/1/97
00619 // We've decided to make both models use percentages as the default unit type
00620     ScaleUnit* pUnit = StandardUnit::PercentGroup.FindUnitFromIndex(0); // percentage '%'
00621 #else
00622     ScaleUnit* pUnit = UnitsTab::GetColourUnitPreference();
00623 #endif // WEBSTER
00624 
00625     if (pUnit == NULL || !pUnit->IS_KIND_OF(ScaleUnit))
00626     {
00627         ERROR3("Failed to get a default unit");
00628         return FALSE;
00629     }
00630     StandardUnit::PercentGroup.SetDefaultUnit(pUnit);
00631 
00632     StandardUnit::AngleGroup.SetDefaultUnit(&StandardUnit::UnitDegree);
00633     return TRUE;
00634 }
00635 
00636 
00637 /********************************************************************************************
00638 
00639 >   ColourEditDlg::ColourEditDlg(): DialogOp(ColourEditDlg::IDD, ColourEditDlg::Mode) 
00640 
00641     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00642     Created:    13/6/94
00643     Inputs:     -
00644     Outputs:    -
00645     Returns:    -
00646     Purpose:    Default constructor for the colour editor dialogue class
00647     Notes:      You shouldn't really use this constructor if you can avoid it
00648     Errors:     -
00649     SeeAlso:    -
00650 
00651 ********************************************************************************************/
00652 
00653 ColourEditDlg::ColourEditDlg(): DialogOp(ColourEditDlg::IDD, ColourEditDlg::Mode) 
00654 {
00655     // If there is no existing editor, make us "the" editor instantiation
00656     // Otherwise, we'll realise our mistake (in Do/DoWithParam) and kill ourself
00657     if (TheEditor == NULL)
00658         TheEditor = this;
00659 
00660     ParentList      = NULL;
00661     ResultColour    = NULL;
00662     EditingColour   = NULL;
00663     ISentTheMessage = FALSE;
00664     AmShaded        = FALSE;
00665 
00666     DragStartArea     = CEDRAG_NONE;
00667     DragUpdatedOnIdle = FALSE;
00668     FirstEdit         = TRUE;
00669 
00670     ResetState();
00671 
00672 // WEBSTER - markn 31/1/97
00673 // Bodge - uses the Named default value to keep that model preserved
00674 #ifndef WEBSTER
00675     DisplayModel    = (ColourModel) DefaultDisplayModel;
00676 #else
00677     DisplayModel    = (ColourModel) DefaultDisplayModelN;
00678 #endif // WEBSTER
00679 
00680     AbortColour = NULL;
00681 
00682     NameDropDown    = NULL;
00683     ParentDropDown  = NULL;
00684 
00685     CurrentCursorID = 0;
00686     CurrentCursor   = NULL;
00687 
00688     m_bDoingSetGadget = FALSE;
00689     m_NeedsResize = FALSE;
00690     GetApplication()->RegisterIdleProcessor(IDLEPRIORITY_LOW, this);
00691 }
00692 
00693 
00694 
00695 /********************************************************************************************
00696 
00697 >   ColourEditDlg::~ColourEditDlg()
00698 
00699     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00700     Created:    13/6/94
00701     Inputs:     -
00702     Outputs:    -
00703     Returns:    -
00704     Purpose:    Destructor for the colour editor dialogue class
00705     Errors:     -
00706     SeeAlso:    -
00707 
00708 ********************************************************************************************/
00709 
00710 ColourEditDlg::~ColourEditDlg()
00711 {
00712     GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_LOW, this);
00713     EndTimedProcessing();
00714 
00715     if (EditingColour != NULL)
00716     {
00717         // Ensure we remember the current model as the preferred default
00718         if (EditingColour->IsNamed())
00719             DefaultDisplayModelN = (INT32) DisplayModel;
00720 // But do not overwrite the preference for local colours - this must be set in the options dlg
00721 //      else
00722 //          DefaultDisplayModel = (INT32) DisplayModel;
00723 
00724         delete EditingColour;
00725     }
00726 
00727     if (AbortColour != NULL)
00728     {
00729         delete AbortColour;
00730         AbortColour = NULL;
00731     }
00732 
00733     // If we were the current active editor instantiation then we indicate there
00734     // is no longer an editor open.
00735     if (TheEditor == this)
00736         TheEditor = NULL;
00737 
00738     // Delete our drop-down colour list support objects
00739     if (NameDropDown != NULL)
00740         delete NameDropDown;
00741 
00742     if (ParentDropDown != NULL)
00743         delete ParentDropDown;
00744 
00745     if (CurrentCursor != NULL)
00746         delete CurrentCursor;
00747 }
00748 
00749 
00750 
00751 /********************************************************************************************
00752 
00753 >   void ColourEditDlg::SetColourNameList(void)
00754 
00755     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00756     Created:    13/12/94
00757     Purpose:    Initialises the colour editor dialogue name combo-box list
00758     Scope:      private
00759 
00760 ********************************************************************************************/
00761 
00762 void ColourEditDlg::SetColourNameList(void)
00763 {
00764     if (State.ParentListOK)
00765         return;
00766 
00767     // Get a description of the current local colour
00768     SelRange *Selection = GetApplication()->FindSelection();
00769 //
00770 //  String_256 SelDesc = Selection->Describe(MENU);
00771 //  String_256 ColourDesc(TEXT("(No selection colour)"));;
00772 //  if (Selection->Count() != 0)
00773 //      ColourDesc._MakeMsg("Colour of #1%s", (TCHAR *)SelDesc);
00774 
00775 
00776     Progress Hourglass;     // Start an hourglass running. On destruction it'll turn it off again
00777 
00778     BOOL OldSentState = ISentTheMessage;
00779     ISentTheMessage = TRUE;
00780 
00781     if (NameDropDown != NULL)
00782         delete NameDropDown;
00783     NameDropDown = new ColourDropDown;
00784 
00785     BOOL ok = TRUE;
00786     if (NameDropDown == NULL || !NameDropDown->Init(WindowID, _R(IDC_EDIT_NAMEMENU)))
00787         ok = FALSE;
00788 
00789     if (ok)
00790     {
00791         String_256 FillColDesc(_R(IDS_COLEDIT_FILL));
00792         String_256 LineColDesc(_R(IDS_COLEDIT_LINE));
00793 
00794         if (Selection->Count() == 0)        // No selection, so will use current colours
00795         {
00796             FillColDesc = String_256(_R(IDS_COLEDIT_CURFILL));
00797             LineColDesc = String_256(_R(IDS_COLEDIT_CURLINE));
00798         }
00799 
00800         // Ensure there are no special entries in the list, then add the 2 we want this time
00801         NameDropDown->ClearAllSpecialEntries();
00802 
00803         ColourList  *NewParentList  = NULL;
00804         DocColour   DocColourToEdit;
00805         ColourManager::FindColourOfInterestToUser(&DocColourToEdit, &NewParentList, FALSE);
00806         
00807         ok = NameDropDown->AddSpecialEntry(&FillColDesc, &DocColourToEdit);
00808         if (ok)
00809         {
00810             ColourManager::FindColourOfInterestToUser(&DocColourToEdit, &NewParentList, TRUE);
00811             ok = NameDropDown->AddSpecialEntry(&LineColDesc, &DocColourToEdit);
00812         }
00813 
00814         if (ok)
00815         {
00816             // Determine if we're editing a named colour, or a current colour
00817             IndexedColour *Ptr = NULL;
00818             if (ParentList != NULL)
00819             {
00820                 Ptr = (IndexedColour *) ParentList->GetHead();
00821                 while (Ptr != NULL)
00822                 {
00823                     if (!Ptr->IsDeleted() && Ptr->IsNamed())
00824                     {
00825                         if (Ptr == ResultColour)
00826                             break;
00827                     }
00828                     Ptr = (IndexedColour *) ParentList->GetNext(Ptr);
00829                 }
00830             }
00831 
00832             // If we aren't editing a named colour (Ptr == NULL) then we're editing fill (0) or line (1) colour
00833             INT32 SelIndex = -1;
00834             if (Ptr == NULL)
00835                 SelIndex = (EditingLineColour) ? 1 : 0;
00836 
00837             // Fill in the list
00838             ok = NameDropDown->FillInColourList(Ptr, SelIndex);
00839 
00840             // NOTE: We could do a SetComboListLength here, except that this causes awful
00841             // redraws of everything "behind" the combo-list extent. I can't stop it doing this,
00842             // other than by not setting the list length... so I don't
00843         }
00844     }
00845 
00846     // If we failed, then we shade this control so that some semblance of stability remains
00847     if (!ok)
00848         EnableGadget(_R(IDC_EDIT_NAMEMENU), FALSE);
00849 
00850 /*
00851     INT32 Index = 0;
00852     INT32 SelectedIndex = 0;
00853 
00854     // Compile a list of all editable colours into the colour name combo-list
00855     GadgetRedraw(_R(IDC_EDIT_NAMEMENU), FALSE);
00856     DeleteAllValues(_R(IDC_EDIT_NAMEMENU));
00857 
00858     String_256 FillColDesc(TEXT("Fill colour"));
00859     String_256 LineColDesc(TEXT("Line colour"));
00860     String_256 DottedLine(TEXT("---------------------------------------"));
00861 
00862     if (Selection->Count() == 0)        // No selection, so will use current colours
00863     {
00864         FillColDesc = TEXT("Current fill colour");
00865         LineColDesc = TEXT("Current line colour");
00866     }
00867 
00868     SetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), &FillColDesc, TRUE);    
00869     SetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), &LineColDesc, TRUE);
00870     SetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), &DottedLine, TRUE);
00871     Index += 3;
00872     if (EditingLineColour)
00873         SelectedIndex++;
00874 
00875     if (ParentList != NULL)
00876     {
00877         IndexedColour *Ptr = (IndexedColour *) ParentList->GetHead();
00878         while (Ptr != NULL)
00879         {
00880             if (!Ptr->IsDeleted() && Ptr->IsNamed())
00881             {
00882                 SetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), Ptr->GetName(), TRUE);
00883                 if (Ptr == ResultColour)
00884                     SelectedIndex = Index;
00885 
00886                 Index++;
00887             }
00888 
00889             Ptr = (IndexedColour *) ParentList->GetNext(Ptr);
00890         }
00891     }
00892 
00893     GadgetRedraw(_R(IDC_EDIT_NAMEMENU), TRUE);
00894 
00895     // Set the writable colour name (combo box editable) field
00896     SetSelectedValueIndex(_R(IDC_EDIT_NAMEMENU), SelectedIndex);
00897 */
00898 
00899     ISentTheMessage = OldSentState;
00900 
00901     State.ParentListOK = TRUE;
00902 }
00903 
00904 
00905 
00906 /********************************************************************************************
00907 
00908 >   void ColourEditDlg::RedrawColourNameList(void)
00909 
00910     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00911     Created:    20/10/95
00912 
00913     Purpose:    Ensures that the colour splodge in the colour name dropdown list is
00914                 redrawn using the correct new appearance of the colour. Far more
00915                 efficient than rebuilding the colour list from scratch.
00916 
00917 ********************************************************************************************/
00918 
00919 void ColourEditDlg::RedrawColourNameList(void)
00920 {
00921     if (NameDropDown == NULL)
00922         return;
00923 
00924     String_256 FillColDesc(_R(IDS_COLEDIT_FILL));
00925     String_256 LineColDesc(_R(IDS_COLEDIT_LINE));
00926 
00927     SelRange *Selection = GetApplication()->FindSelection();
00928     if (Selection->Count() == 0)        // No selection, so will use current colours
00929     {
00930         FillColDesc = String_256(_R(IDS_COLEDIT_CURFILL));
00931         LineColDesc = String_256(_R(IDS_COLEDIT_CURLINE));
00932     }
00933 
00934     ColourList  *NewParentList  = NULL;
00935     DocColour   DocColourToEdit;
00936 
00937     ColourManager::FindColourOfInterestToUser(&DocColourToEdit, &NewParentList, FALSE);
00938     NameDropDown->UpdateSpecialEntry(&FillColDesc, &DocColourToEdit);
00939 
00940     ColourManager::FindColourOfInterestToUser(&DocColourToEdit, &NewParentList, TRUE);
00941     NameDropDown->UpdateSpecialEntry(&LineColDesc, &DocColourToEdit);
00942 
00943     // And ensure that the dropdown is redrawn
00944     InvalidateGadget(_R(IDC_EDIT_NAMEMENU));
00945 }
00946 
00947 
00948 
00949 /********************************************************************************************
00950 
00951 >   void ColourEditDlg::ResetState(void)
00952 
00953     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00954     Created:    23/1/95
00955     Purpose:    Initialises the colour editor dialogue State variable to be 'unknown'.
00956                 The next SetControls() call after this will set all the controls in the
00957                 window, rather than only those which are known to have changed.
00958     Scope:      private
00959 
00960 ********************************************************************************************/
00961 
00962 // We fake a special colour type for shades for the State information *only*
00963 #define COLOURTYPE_SHADE ((IndexedColourType) 32)
00964 
00965 void ColourEditDlg::ResetState(void)
00966 {
00967     State.Folded        = 2;
00968     State.ColType       = (IndexedColourType) 99;   // An invalid value!
00969     State.DisplayModel  = MAX_COLOURMODELS;
00970     State.ResultColour  = NULL;
00971     State.Initialised   = FALSE;
00972     State.ParentListOK  = FALSE;
00973 }
00974 
00975 
00976 
00977 /********************************************************************************************
00978 
00979 >   void ColourEditDlg::SetExtent(void)
00980 
00981     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00982     Created:    23/1/95
00983 
00984     Purpose:    If necessary, changes the size of the editor window and shuffles controls
00985                 around to show folded/unfolded tint/linked information appropriately.
00986                 If the State has not been reset or changed, this may do nothing, to minimise
00987                 unnecessary redraws.
00988 
00989     Scope:      private
00990 
00991 ********************************************************************************************/
00992 
00993 void ColourEditDlg::SetExtent(void)
00994 {
00995     // Set size to small (cut off below 'more' button) or large (full-size) as appropriate
00996     // NOTE that this relies on the gadgets passed to SetWindowExtent being at the
00997     // bottom of the folded/unfolded layouts of the dialogue respectively.
00998 
00999     if (EditingColour == NULL)
01000     {
01001         // WEBSTER - markn 1/2/97
01002         #ifdef WEBSTER
01003         ColourPicker::SetWindowExtent(WindowID, _R(IDC_EDIT_PICKER), _R(IDC_EDIT_PICKER));
01004         #endif // WEBSTER
01005         HideGadget(_R(IDC_EDIT_ADVANCEDPANEL), TRUE);
01006         NeedsResize();
01007         return;
01008     }
01009 
01010     // If there has been no change in the colour type, we should return.
01011     // This is compllicated by shades, which internally are a variant of TINTs, but
01012     // externally are different "types".
01013     IndexedColourType CurrentColType = EditingColour->GetType();
01014     if (CurrentColType == COLOURTYPE_TINT && EditingColour->TintIsShade())
01015         CurrentColType = COLOURTYPE_SHADE;  // Shade is a special "Bodge" colour type
01016 
01017 #ifndef WEBSTER
01018     if (State.Folded == Folded && State.ColType == CurrentColType)
01019         return;
01020 #else
01021     // WEBSTER - markn 24/4/97
01022     // Always unfolded.
01023     Folded = FALSE; // always unfolded
01024 #endif // WEBSTER
01025 
01026     NeedsResize();
01027 
01028     if (Folded)
01029     {       
01030         // WEBSTER - markn 11/12/96
01031         // Always unfolded.
01032         // Changed folded to show ed fields
01033 #ifndef WEBSTER
01034         ColourPicker::SetWindowExtent(WindowID, _R(IDC_EDIT_PICKER), _R(IDC_EDIT_PICKER));
01035         //      SetStringGadgetValue(_R(IDC_EDIT_ADVANCED), _R(IDS_EDIT_MORE));
01036         SetBoolGadgetSelected(_R(IDC_EDIT_ADVANCED), FALSE);
01037 #else
01038         ColourPicker::SetWindowExtent(WindowID, _R(IDC_EDIT_PICKER), _R(IDC_EDIT_COLTYPE));
01039 #endif // WEBSTER
01040         HideGadget(_R(IDC_EDIT_ADVANCEDPANEL), TRUE);
01041     }           
01042     else
01043     {
01044         HideGadget(_R(IDC_EDIT_ADVANCEDPANEL), FALSE);
01045         CGadgetID Gadget = _R(IDC_EDIT_COLTYPE);
01046 
01047         if (EditingColour != NULL)  // If we have an editing colour, set tint/link controls
01048         {
01049             switch (EditingColour->GetType())
01050             {
01051                 case COLOURTYPE_TINT:
01052                     {
01053                         Gadget = _R(IDC_EDIT_TINT);
01054                         HideGadgetList(LinkGadgetIDs, TRUE);
01055                         HideGadgetList(TintGadgetIDs, FALSE);
01056                         HideGadget (_R(IDC_EDIT_PARENTNAME), FALSE);
01057                         HideGadget (_R(IDC_EDIT_PARENTCOL), FALSE);
01058                         // ColourPicker::SetGadgetPositions(WindowID, LinkGadgetIDs, 0);
01059                         // ColourPicker::SetGadgetPositions(WindowID, TintGadgetIDs, _R(IDC_EDIT_PARENTCOL));
01060 
01061                         // And if it's not a shade, hide the extra writable field
01062                         HideGadget(_R(IDC_EDIT_SHADE), !EditingColour->TintIsShade());
01063                         HideGadget(_R(IDC_EDIT_SHADEPERCENT), !EditingColour->TintIsShade());
01064                     }
01065                     break;
01066 
01067                 case COLOURTYPE_LINKED:
01068                     Gadget = _R(IDC_EDIT_INHERIT4);
01069                     HideGadgetList(LinkGadgetIDs, FALSE);
01070                     HideGadgetList(TintGadgetIDs, TRUE);
01071                     HideGadget (_R(IDC_EDIT_PARENTNAME), FALSE);
01072                     HideGadget (_R(IDC_EDIT_PARENTCOL), FALSE);
01073                     // ColourPicker::SetGadgetPositions(WindowID, TintGadgetIDs, 0);
01074                     // ColourPicker::SetGadgetPositions(WindowID, LinkGadgetIDs, _R(IDC_EDIT_PARENTCOL));
01075                     break;
01076 
01077                 default:
01078                     HideGadget (_R(IDC_EDIT_PARENTNAME), TRUE);
01079                     HideGadget (_R(IDC_EDIT_PARENTCOL), TRUE);
01080                     HideGadgetList(LinkGadgetIDs, TRUE);
01081                     HideGadgetList(TintGadgetIDs, TRUE);
01082                     break;
01083             }
01084         }
01085 
01086         ColourPicker::SetWindowExtent(WindowID, _R(IDC_EDIT_PICKER), Gadget);
01087 #ifndef WEBSTER // not included in Webster
01088         SetBoolGadgetSelected(_R(IDC_EDIT_ADVANCED), TRUE);
01089 //      SetStringGadgetValue(_R(IDC_EDIT_ADVANCED), _R(IDS_EDIT_LESS));
01090 #endif
01091     }
01092 
01093 }
01094 
01095 
01096 /********************************************************************************************
01097 
01098 >   void ColourEditDlg::HideGadgetList(CGadgetID * Gadgets, BOOL Hide=TRUE)
01099 
01100     Author:     Alex Bligh
01101     Created:    30/5/2005
01102 
01103     Inputs:     Gadgets - NULL terminated list of gadgets
01104                 Hide - TRUE to hide else FALSE to show
01105 
01106     Purpose:    Hides / shows the gadgets on the list
01107 
01108     Scope:      Protected
01109 
01110 ********************************************************************************************/
01111 
01112 void ColourEditDlg::HideGadgetList(CGadgetID * Gadgets, BOOL Hide /*=TRUE*/)
01113 {
01114     CGadgetID Gadget;
01115     while ((Gadget=*(Gadgets++))) // assignment
01116     {
01117         HideGadget(Gadget, Hide);   
01118     }
01119 }
01120 
01121 /*****************************************************************************
01122 >   BOOL ColourEditDlg::OnIdleEvent()
01123 
01124     Author:     Alex Bligh
01125     Created:    30/5/2005
01126     Purpose:    Idle event handler for the colour dialog
01127                 
01128     Returns:    FALSE (to indicate we want no more idle events)
01129                 The wakeup from the timer will create one for us
01130     Errors:     -
01131 
01132 
01133 *****************************************************************************/
01134 
01135 BOOL ColourEditDlg::OnIdleEvent()
01136 {
01137     return ColourPicker::OnIdleEvent(WindowID);
01138 }
01139 
01140 /********************************************************************************************
01141 
01142 >   void ColourEditDlg::HideOrShowColourPicker()
01143 
01144     Author:     Alex Bligh
01145     Created:    30/5/2005
01146 
01147     Inputs:     -
01148 
01149     Purpose:    Synchronize state of colour picker gadget
01150 
01151     Scope:      Protected
01152 
01153 ********************************************************************************************/
01154 
01155 void ColourEditDlg::HideOrShowColourPicker()
01156 {
01157     if (needColPickHidden != colPickHidden)
01158     {
01159         // this used to use Hide() but that was boring
01160         EnableGadget(_R(IDC_COLOURPICKER), !needColPickHidden);
01161         colPickHidden=needColPickHidden;
01162         
01163         //CheckDialogSize();
01164     }
01165 }
01166 
01167 /********************************************************************************************
01168 
01169 >   void ColourEditDlg::CheckDialogSize()
01170 
01171     Author:     Alex Bligh
01172     Created:    30/5/2005
01173     Inputs:     -
01174     Purpose:    Ensure the dialog is a sensible size
01175     Scope:      Protected
01176 
01177 ********************************************************************************************/
01178 
01179 void ColourEditDlg::CheckDialogSize()
01180 {
01181     if (!m_NeedsResize)
01182         return;
01183 
01184     m_NeedsResize=FALSE;
01185 
01186     // Set up bubble help
01187     ColourPicker::SetBubbleHelp(TintGadgetIDs);
01188     ColourPicker::SetBubbleHelp(LinkGadgetIDs);
01189     ColourPicker::SetBubbleHelp(OtherGadgetIDs);
01190 
01191     ColourPicker::RelayoutDialog(WindowID);
01192 }
01193 
01194 
01195 /********************************************************************************************
01196 
01197 >   void ColourEditDlg::SetControls(void)
01198 
01199     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01200     Created:    13/6/94
01201     Inputs:     -
01202     Outputs:    -
01203     Returns:    -
01204     Purpose:    Initialises the colour editor dialogue controls/gadgets
01205     Scope:      private
01206     Errors:     -
01207     SeeAlso:    -
01208 
01209 ********************************************************************************************/
01210 
01211 static UINT32 CurrentTypingGadget = 0;
01212 
01213 void ColourEditDlg::SetControls(void)
01214 {
01215     // If there is no colour to edit, desperately seek a new colour to edit - avoid
01216     // shading the dialogue at all costs. (We should then only shade if there are no documents)
01217     if (EditingColour == NULL)
01218     {
01219         FindUsefulColourToEdit(EditingLineColour);
01220         if (EditingColour != NULL)
01221             return;                     // Avoid infinite recursion!
01222     }
01223 
01224     SetExtent();    
01225 
01226     if (EditingColour == NULL)
01227     {
01228         ShadeMyself();          // No colour to edit - ensure we're shaded
01229         return;
01230     }
01231 
01232 
01233     BOOL OldSentState = ISentTheMessage;
01234     ISentTheMessage = TRUE;     // Try to lock out DIM_TEXT_CHANGED messages during update
01235 
01236     ShadeMyself(TRUE, TRUE);    // We have a colour - ensure we are not shaded
01237 
01238     SetColourNameList();        // Set the name writable and dropdown list of colours
01239 
01240     //Set the transparency button
01241     if( EditingColour->IsNamed() )
01242     {
01243         EnableGadget( _R(IDC_EDIT_NOCOLOUR),  FALSE);
01244     }
01245     else
01246     {
01247         EnableGadget( _R(IDC_EDIT_NOCOLOUR),  TRUE);
01248         SetBoolGadgetSelected( _R(IDC_EDIT_NOCOLOUR), NoFillButtonDown);
01249     }
01250 
01251     //Graham 16/10/97: The rename button
01252     String_256 empty;
01253     OpState opstate=GetCommandState(&ColCmd_Name, &empty);
01254     BOOL fRenameCommandIsAvailable=opstate.Greyed;
01255     EnableGadget( _R(IDC_EDIT_RENAME),  !fRenameCommandIsAvailable);
01256 
01257     // Set tint information
01258     BOOL Enable = (EditingColour->GetType() == COLOURTYPE_TINT);
01259     IndexedColourType CurrentColType = EditingColour->GetType();
01260     if (CurrentColType == COLOURTYPE_TINT && EditingColour->TintIsShade())
01261         CurrentColType = COLOURTYPE_SHADE;  // Shade is a special "Bodge" colour type
01262 
01263     if (State.ColType != CurrentColType)
01264     {
01265         NeedsResize();
01266         EnableGadget(_R(IDC_EDIT_TINT), Enable);
01267 
01268         EnableGadget(_R(IDC_EDIT_TINTNAME), Enable);
01269         EnableGadget(_R(IDC_EDIT_TINTPERCENT), Enable);
01270 
01271 //      EnableGadget(_R(IDC_EDIT_TINTSLIDER), Enable);
01272 //      SetGadgetRange(_R(IDC_EDIT_TINTSLIDER), 0, 100, 1);
01273 //      SetGadgetBitmaps(_R(IDC_EDIT_TINTSLIDER), _R(IDB_SLIDERBASE), _R(IDB_SLIDERSLIDER));
01274 
01275         if (CurrentColType == COLOURTYPE_SHADE)
01276         {
01277             EnableGadget(_R(IDC_EDIT_SHADE), Enable);
01278             EnableGadget(_R(IDC_EDIT_SHADEPERCENT), Enable);
01279         }
01280     
01281         // The Colour model dropdown and 3d button are not available while editing a tint/shade
01282         // (The 3d button is set below, but we need to enable it here too just in case the code below
01283         //  is not called (when we only change the colour model)
01284         EnableGadget(_R(IDC_EDIT_COLMODEL), !Enable);
01285         EnableGadget(_R(IDC_EDIT_3D), !Enable);
01286     }
01287     
01288     if (Enable)
01289     {
01290         // It's a tint/shade. Set the "Tint:" or "Shade:" text as appropriate
01291         if (EditingColour->TintIsShade())
01292             SetStringGadgetValue(_R(IDC_EDIT_TINTNAME), _R(IDS_EDIT_TEXTSHADE));
01293         else
01294             SetStringGadgetValue(_R(IDC_EDIT_TINTNAME), _R(IDS_EDIT_TEXTTINT));
01295 
01296         // If we're not currently typing into this field and it is displaying the wrong thing,
01297         // we'd better update it to be correct.
01298         if (CurrentTypingGadget != _R(IDC_EDIT_TINT))
01299         {
01300             String_256 CurrentValue = GetStringGadgetValue(_R(IDC_EDIT_TINT));
01301             String_8 NewValue;
01302 
01303             if (CurrentColType == COLOURTYPE_SHADE)
01304                 ColourPicker::GetShadeValueAsString(EditingColour, 1, &NewValue);
01305             else
01306                 ColourPicker::GetTintAsString(EditingColour, &NewValue);
01307 
01308             if (NewValue != CurrentValue)
01309                 SetStringGadgetValue(_R(IDC_EDIT_TINT), NewValue);
01310         }
01311 
01312         if (CurrentColType == COLOURTYPE_SHADE && CurrentTypingGadget != _R(IDC_EDIT_SHADE))
01313         {
01314             String_256 CurrentValue = GetStringGadgetValue(_R(IDC_EDIT_SHADE));
01315             String_8 NewValue;
01316 
01317             ColourPicker::GetShadeValueAsString(EditingColour, 2, &NewValue);
01318 
01319             if (NewValue != CurrentValue)
01320                 SetStringGadgetValue(_R(IDC_EDIT_SHADE), NewValue);
01321         }
01322                 
01323         // And set the slider to the nearest position to this value
01324         INT32 SliderValue = (INT32) ((100.0 * (EditingColour->GetTintValue().MakeDouble())) + 0.5);
01325         if (SliderValue > 100)      // Just ensure rounding doesn't give a 101%!
01326             SliderValue = 100;
01327 
01328 //      SetLongGadgetValue(_R(IDC_EDIT_TINTSLIDER), 100-SliderValue);
01329     }
01330 //  else
01331 //      SetLongGadgetValue(_R(IDC_EDIT_TINTSLIDER), 100-0);
01332 
01333     // Set up the combo box of available colour models
01334     if (State.DisplayModel != DisplayModel)
01335     {
01336         NeedsResize();
01337         // Shift around the component name and writable gadgets until Windows doesn't
01338         // know if it's coming or going. 
01339         static CGadgetID CompGadgetIDs[10] =
01340         {
01341             _R(IDC_NAME_COMPONENT1),
01342             _R(IDC_EDIT_COMPONENT1),
01343             _R(IDC_NAME_COMPONENT2),
01344             _R(IDC_EDIT_COMPONENT2),
01345             _R(IDC_NAME_COMPONENT3),
01346             _R(IDC_EDIT_COMPONENT3),
01347             _R(IDC_NAME_COMPONENT4),
01348             _R(IDC_EDIT_COMPONENT4),
01349             _R(IDC_NAME_WEBHEX),
01350             _R(IDC_EDIT_WEBHEX)
01351         };// CGS CGS CGS
01352 
01353         // Special case for certain colour models but fall back to general formatter for everything else
01354         switch (DisplayModel)
01355         {
01356             case COLOURMODEL_RGBT:
01357                 {
01358                     INT32 TextWidth[5] = {7, 7, 7, 0, 7};
01359                     INT32 EditWidth[5] = {35, 35, 35, 0, 48};
01360                     ColourPicker::SetFixedComponentGadgets(WindowID, CompGadgetIDs, _R(IDC_EDIT_PICKER), DisplayModel, TextWidth, EditWidth);
01361                 }
01362                 break;
01363             case COLOURMODEL_HSVT:
01364                 {
01365                     INT32 TextWidth[5] = {7, 7, 7, 0, 7};
01366                     INT32 EditWidth[5] = {35, 35, 35, 0, 48};
01367                     ColourPicker::SetFixedComponentGadgets(WindowID, CompGadgetIDs, _R(IDC_EDIT_PICKER), DisplayModel, TextWidth, EditWidth);
01368                 }
01369                 break;
01370             default:
01371                 ColourPicker::SetComponentGadgets(WindowID, CompGadgetIDs, _R(IDC_EDIT_PICKER), DisplayModel);
01372                 break;
01373         }
01374 
01375         // Enable the '3d display' button if it is relevant (CMYK, RGB or WebRGB mode, and not showing a tint/shade
01376         EnableGadget(_R(IDC_EDIT_3D),   (DisplayModel == COLOURMODEL_CMYK || DisplayModel == COLOURMODEL_RGBT || DisplayModel == COLOURMODEL_WEBRGBT) &&
01377                                     (CurrentColType != COLOURTYPE_TINT && CurrentColType != COLOURTYPE_SHADE));
01378         SetBoolGadgetSelected(_R(IDC_EDIT_3D), Use3DDisplay);
01379 
01380         GadgetRedraw(_R(IDC_EDIT_COLMODEL), FALSE);
01381         DeleteAllValues(_R(IDC_EDIT_COLMODEL));
01382         ColourContextArray ColContexts;
01383         ColourContext::GetGlobalDefaults(&ColContexts);
01384 
01385         String_64 NameString;
01386         INT32 Index = 0;
01387         INT32 SelectedIndex = 0;
01388 
01389         for (INT32 i = 0; i < MAX_COLOURMODELS; i++)
01390         {
01391             if (ColContexts.Context[i] != NULL)
01392             {
01393                 String_32 ModelName;
01394                 ColContexts.Context[i]->GetModelName(&ModelName);
01395 
01396                 NameString.MakeMsg(_R(IDS_COLCONTEXTNAME), (TCHAR *) ModelName);
01397                 SetStringGadgetValue(_R(IDC_EDIT_COLMODEL), NameString, FALSE, Index);
01398 
01399                 if (i == (INT32)DisplayModel)
01400                     SelectedIndex = Index;
01401 
01402                 Index++;
01403             }
01404         }       
01405 
01406         GadgetRedraw(_R(IDC_EDIT_COLMODEL), TRUE);
01407         SetSelectedValueIndex(_R(IDC_EDIT_COLMODEL), SelectedIndex);
01408         SetComboListLength(_R(IDC_EDIT_COLMODEL));
01409     }
01410 
01411     if (DisplayModel == COLOURMODEL_RGBT || DisplayModel == COLOURMODEL_HSVT)
01412     {
01413         //HideGadget (_R(IDC_NAME_COMPONENT4), TRUE);
01414         //HideGadget (_R(IDC_EDIT_COMPONENT4), TRUE);
01415         HideGadget (_R(IDC_NAME_WEBHEX), FALSE);
01416         HideGadget (_R(IDC_EDIT_WEBHEX), FALSE);
01417     }
01418     else
01419     {
01420         //HideGadget (_R(IDC_NAME_COMPONENT4), FALSE);
01421         //HideGadget (_R(IDC_EDIT_COMPONENT4), FALSE);
01422 
01423         HideGadget (_R(IDC_NAME_WEBHEX), TRUE);
01424         HideGadget (_R(IDC_EDIT_WEBHEX), TRUE);
01425     }
01426 
01427     // Set component name strings & writables, and inheritance gadgets
01428     // Note: This MUST occur AFTER the call to ColourPicker::SetComponentGadgets (up 1 page)
01429     SetComponentInfo(1, _R(IDC_NAME_COMPONENT1), _R(IDC_EDIT_COMPONENT1), _R(IDC_EDIT_INHERIT1));
01430     SetComponentInfo(2, _R(IDC_NAME_COMPONENT2), _R(IDC_EDIT_COMPONENT2), _R(IDC_EDIT_INHERIT2));
01431     SetComponentInfo(3, _R(IDC_NAME_COMPONENT3), _R(IDC_EDIT_COMPONENT3), _R(IDC_EDIT_INHERIT3));
01432     SetComponentInfo(4, _R(IDC_NAME_COMPONENT4), _R(IDC_EDIT_COMPONENT4), _R(IDC_EDIT_INHERIT4));
01433 
01434     if (DisplayModel == COLOURMODEL_WEBRGBT || DisplayModel==COLOURMODEL_RGBT || DisplayModel==COLOURMODEL_HSVT)
01435     {
01436         SetAllHexComponentsInfo ((UINT32)-1, _R(IDC_NAME_WEBHEX), _R(IDC_EDIT_WEBHEX));
01437     }
01438 
01439     // Find a safe parent for the colour to link to. If we can't find one, then
01440     // we remove the linking options from the drop down list.
01441     IndexedColour *SafeParent;
01442     SafeParent = FindSafeParent(EditingColour->FindLastLinkedParent(),
01443                                 (CurrentColType == COLOURTYPE_TINT));
01444 
01445     // Ensure the editing colour has a parent which is safe to link to
01446     if (SafeParent != EditingColour->FindLastLinkedParent())
01447         EditingColour->SetLinkedParent(SafeParent, EditingColour->GetType());
01448 
01449     // And make sure CurrentColType is still correct!
01450     CurrentColType = EditingColour->GetType();
01451     if (CurrentColType == COLOURTYPE_TINT && EditingColour->TintIsShade())
01452         CurrentColType = COLOURTYPE_SHADE;  // Shade is a special "Bodge" colour type
01453 
01454     // Set up the colour type combo-box gadget whenever the type or the colour itself is changed,
01455     // or if we've not initialised it before
01456     if (State.ColType != CurrentColType || State.ResultColour != ResultColour || !State.Initialised)
01457     {
01458         GadgetRedraw(_R(IDC_EDIT_COLTYPE), FALSE);
01459         DeleteAllValues(_R(IDC_EDIT_COLTYPE));
01460 
01461         INT32 Index = 0;                // Compute an index for each item as we build the list
01462         INT32 SelIndex = 0;         // Default SelIndex, for COLOURTYPE_NORMAL
01463 
01464         SetStringGadgetValue(_R(IDC_EDIT_COLTYPE), _R(IDS_COLTYPE_NORMAL),  FALSE, Index++);
01465 
01466 //      if (ResultColour->IsNamed())        // "Spot colour" only available for named colours
01467 //      This option is now still shown in the list, but when the user tries to select it,
01468 //      we force them to cancel or make a new named spot colour.
01469 #ifndef WEBSTER
01470         {
01471             if (CurrentColType == COLOURTYPE_SPOT)
01472                 SelIndex = Index;
01473 
01474             SetStringGadgetValue(_R(IDC_EDIT_COLTYPE), _R(IDS_COLTYPE_SPOT),    FALSE, Index++);
01475         }
01476 #endif //WEBSTER
01477 
01478         if (SafeParent != NULL)     // We can make the colour linked
01479         {
01480             if (CurrentColType == COLOURTYPE_TINT)
01481                 SelIndex = Index;
01482             SetStringGadgetValue(_R(IDC_EDIT_COLTYPE), _R(IDS_COLTYPE_TINT),    FALSE, Index++);
01483 
01484             if (CurrentColType == COLOURTYPE_SHADE)
01485                 SelIndex = Index;
01486             SetStringGadgetValue(_R(IDC_EDIT_COLTYPE), _R(IDS_COLTYPE_SHADE),   FALSE, Index++);
01487 
01488             if (CurrentColType == COLOURTYPE_LINKED)
01489                 SelIndex = Index;
01490             SetStringGadgetValue(_R(IDC_EDIT_COLTYPE), _R(IDS_COLTYPE_LINKED),  FALSE, Index++);
01491         }
01492 
01493         GadgetRedraw(_R(IDC_EDIT_COLTYPE), TRUE);
01494         SetComboListLength(_R(IDC_EDIT_COLTYPE));
01495 
01496         SetSelectedValueIndex(_R(IDC_EDIT_COLTYPE), SelIndex);
01497     }
01498 
01499     // Enable/Disable extra options gadgets as appropriate to EditingColour settings
01500     // and set up the list of potential parent colours
01501     if (State.ColType != CurrentColType)
01502     {
01503         Enable = (EditingColour->GetType() == COLOURTYPE_TINT ||
01504                     EditingColour->GetType() == COLOURTYPE_LINKED);
01505 
01506 
01507         EnableGadget(_R(IDC_EDIT_PARENTNAME), Enable);
01508         EnableGadget(_R(IDC_EDIT_PARENTCOL), Enable);
01509     }
01510     CompileParentColourList(_R(IDC_EDIT_PARENTCOL));        // Set the combo box list
01511 
01512     if ((EditingColour != NULL) && (EditingColour->IsNamed()))
01513         EnableGadget(_R(IDC_MAKE_LOCAL), TRUE);
01514     else
01515         EnableGadget(_R(IDC_MAKE_LOCAL), FALSE);
01516     
01517     // And finish   
01518     ISentTheMessage = OldSentState;     // Unlock the message handler again
01519 
01520     // And remember the new state of the controls/extent etc so we don't have to redraw
01521     // next time where these things have not changed
01522     State.Folded        = (Folded) ? 1 : 0;
01523     State.ColType       = CurrentColType;
01524     State.DisplayModel  = DisplayModel;
01525     State.ResultColour  = ResultColour;
01526     State.Initialised   = TRUE;
01527 
01528     CheckDialogSize();
01529 }
01530 
01531 
01532 
01533 /********************************************************************************************
01534 
01535 >   void ColourEditDlg::SetComponentInfo(UINT32 ComponentID, UINT32 NameGadget,
01536                                          UINT32 WritableGadget, UINT32 InheritGadget)
01537 
01538     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01539     Created:    26/7/94
01540     Inputs:     ComponentID - Which component name is being set (1..4)
01541                 NameGadget - Gadget ID for gadget displaying the name text
01542                 WritableGadget - Writable gadget to also be shaded/unshaded
01543                 InheritGadget - The checkbox gadget for linked-colour inheritance
01544 
01545     Purpose:    Finds and sets the component name for one gadget. If the component
01546                 is not used in the EditingColours colour model, then the name is
01547                 blanked and the related writable gadget is shaded.
01548                 
01549     Scope:      private
01550 
01551 ********************************************************************************************/
01552 
01553 void ColourEditDlg::SetComponentInfo(UINT32 ComponentID, UINT32 Gadget,
01554                                      UINT32 WritableGadget, UINT32 InheritGadget)
01555 {
01556     if (EditingColour == NULL)      // This should never happen
01557     {
01558         ERROR3("Unexpectedly NULL EditingColour in ColourEditDlg::SetComponentInfo");
01559         return;
01560     }
01561 
01562     if (CurrentTypingGadget != WritableGadget)
01563     {
01564 //      ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
01565         ColourContext *cc = NULL;
01566         BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
01567         String_32 CompName;
01568 
01569         if (cc != NULL && cc->GetComponentName(ComponentID, &CompName))
01570         {
01571             if (DisplayModel != COLOURMODEL_WEBRGBT)
01572             {
01573                 SetStringGadgetValue(Gadget, CompName);
01574                 SetStringGadgetValue(InheritGadget, CompName);
01575                 EnableGadget(Gadget, TRUE);
01576                 HideGadget(Gadget, FALSE);
01577 
01578                 String_8 NewText;
01579                 ColourPicker::GetComponentAsString(EditingColour, cc, ComponentID, &NewText);
01580                 EnteredSetGadgetValue();
01581                 SetStringGadgetValue(WritableGadget, NewText);
01582                 ExitedSetGadgetValue();
01583 
01584                 BOOL InheritsComponent = EditingColour->InheritsComponent(ComponentID);
01585 
01586                 EnableGadget(WritableGadget, (!InheritsComponent) &&
01587                                             (EditingColour->GetType() != COLOURTYPE_TINT));
01588                 HideGadget(WritableGadget, FALSE);
01589 
01590                 // Set up the inheritance gadget
01591                 EnableGadget(InheritGadget, EditingColour->GetType() == COLOURTYPE_LINKED);
01592                 HideGadget(InheritGadget, EditingColour->GetType() != COLOURTYPE_LINKED);
01593                 SetBoolGadgetSelected(InheritGadget, InheritsComponent);
01594             }
01595             else
01596             {
01597                 //SetStringGadgetValue(Gadget, &CompName);
01598                 SetStringGadgetValue(InheritGadget, CompName);
01599                 //EnableGadget(Gadget, TRUE);
01600                 //HideGadget(Gadget, FALSE);
01601 
01602                 BOOL InheritsComponent = EditingColour->InheritsComponent(ComponentID);
01603 
01604                 // Set up the inheritance gadget
01605                 EnableGadget(InheritGadget, EditingColour->GetType() == COLOURTYPE_LINKED);
01606                 HideGadget(InheritGadget, EditingColour->GetType() != COLOURTYPE_LINKED);
01607                 SetBoolGadgetSelected(InheritGadget, InheritsComponent);
01608             }
01609         }
01610         else
01611         {
01612             HideGadget(Gadget, TRUE);
01613             HideGadget(WritableGadget, TRUE);
01614             HideGadget(InheritGadget, TRUE);
01615         }
01616 
01617         // Delete the colour context if necessary
01618         if (bDeleteCC)
01619             ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
01620 
01621     }
01622     //CheckDialogSize();
01623 }
01624 
01625 
01626 
01627 /********************************************************************************************
01628 
01629 >   void ColourEditDlg::SetAllHexComponentsInfo(UINT32 ComponentID, UINT32 NameGadget,
01630                                             UINT32 WritableGadget)
01631 
01632     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01633     Created:    15/11/99
01634     Inputs:     ComponentID - Which component name is being set (must be set at -1).
01635                 NameGadget - Gadget ID for gadget displaying the name text (must be
01636                              _R(IDC_NAME_WEBHEX)).
01637                 WritableGadget - Writable gadget to also be shaded/unshaded (must be
01638                                  _R(IDC_EDIT_WEBHEX))
01639 
01640     Purpose:    Finds and sets all component names for the hex gadget.  This actually
01641                 gets the individual rgb values, and concatenates into a single string
01642                 of the form rrggbb for display.
01643                 
01644     Scope:      private
01645 
01646     Note:       Should only be called in a: if (DisplayModel == COLOURMODEL_WEBRGBT) ....
01647                 SetComponentInfo should also be called for all colour components before
01648                 this function, since SetComponentInfo sets up all of the colour component
01649                 inheritace stuff.
01650 
01651 ********************************************************************************************/
01652 
01653 void ColourEditDlg::SetAllHexComponentsInfo(UINT32 ComponentID, UINT32 NameGadget,
01654                                             UINT32 WritableGadget)
01655 {
01656     if (EditingColour == NULL)      // This should never happen
01657     {
01658         ERROR3("Unexpectedly NULL EditingColour in ColourEditDlg::SetComponentInfo");
01659         return;
01660     }
01661 
01662     if (!(ComponentID == (UINT32)-1) && (NameGadget == _R(IDC_NAME_WEBHEX)) &&
01663          (WritableGadget == _R(IDC_EDIT_WEBHEX)))
01664     {
01665         ERROR3("Calling ColourEditDlg::SetAllHexComponentsInfo for incorrect control");
01666         return;
01667     }
01668 
01669     if (CurrentTypingGadget != WritableGadget)
01670     {
01671         // We know that GetComponentsAsHexString only works if the colour context is RGBT
01672         // So why get anything else???
01673         ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
01674         String_32 CompName (_R(IDS_COLCOMPL_WEBHEX));
01675 
01676         if (cc != NULL)
01677         {
01678             if (DisplayModel == COLOURMODEL_RGBT || DisplayModel == COLOURMODEL_HSVT)
01679             {
01680                 SetStringGadgetValue(NameGadget, CompName);
01681                 EnableGadget(NameGadget, TRUE);
01682                 HideGadget(NameGadget, FALSE);
01683 
01684                 String_16 NewText;
01685                 ColourPicker::GetComponentsAsHexString(EditingColour, cc, ComponentID, &NewText);
01686                 EnteredSetGadgetValue();
01687                 SetStringGadgetValue(WritableGadget, NewText);
01688                 ExitedSetGadgetValue();
01689 
01690                 EnableGadget(WritableGadget, /*(!InheritsComponent) &&*/
01691                              (EditingColour->GetType() != COLOURTYPE_TINT));
01692                 HideGadget(WritableGadget, FALSE);
01693             }
01694         }
01695     }
01696     //CheckDialogSize();
01697 }
01698 
01699 
01700 
01701 /********************************************************************************************
01702 
01703 >   void ColourEditDlg::SetColour(BOOL SetComponents = TRUE)
01704 
01705     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01706     Created:    13/6/94
01707 
01708     Inputs:     SetComponents - TRUE if you wish to read all information, including the
01709                 component values - this may change the appearance of the colour, and thus
01710                 causes much of the dialogue to be redrawn (and may also coerce the colour
01711                 model). If the only thing which has changed is the name (for example) we
01712                 don't want to change the model and/or redraw stuff, so we set this value
01713                 to FALSE to stop it faffing around.
01714                 This parameter is ignored for Tints, for which the components are read-only
01715 
01716     Purpose:    Reads the colour definition from the window into the colour which
01717                 is currently being edited, and broadcasts a colour changing message
01718                 so everybody knows about the change.
01719 
01720     Scope:      private
01721 
01722 ********************************************************************************************/
01723 
01724 void ColourEditDlg::SetColour(BOOL SetComponents)
01725 {
01726     if (EditingColour == NULL)
01727         return;
01728 
01729     // Did we just get the gadget's value?
01730     if (IsSetGadgetValueCalled())
01731         return;
01732 
01733     BOOL Clipped = FALSE;
01734 
01735 //  ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
01736     ColourContext *cc = NULL;
01737     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
01738     if (cc == NULL)
01739         return;
01740 
01741     // Make sure any chnage to the display colour model is committed
01742     ColourPicker::ForceColourModel(EditingColour, cc);
01743 
01744     // Read back the new component values. This is not done for tints, as their components
01745     // rely entirely upon the parent colour - reading out components is just going to
01746     // corrupt tinting values and stuff, and generally be a bad thing (tm).
01747     // Just does the set for the CurrentTypingGadget
01748     if (SetComponents && EditingColour->GetType() != COLOURTYPE_TINT)
01749     {
01750         String_32 CompName;
01751 
01752         if (cc == NULL)
01753             return;
01754 
01755         String_256 NewValue;
01756 
01757         if (CurrentTypingGadget!=_R(IDC_EDIT_WEBHEX))
01758         {
01759             // Work out the index number
01760             INT32 nIndex=0;
01761             if (CurrentTypingGadget  == _R(IDC_EDIT_COMPONENT1))
01762                 nIndex=1;
01763             else if (CurrentTypingGadget  == _R(IDC_EDIT_COMPONENT2))
01764                 nIndex=2;
01765             else if (CurrentTypingGadget  == _R(IDC_EDIT_COMPONENT3))
01766                 nIndex=3;
01767             else if (CurrentTypingGadget  == _R(IDC_EDIT_COMPONENT4))
01768                 nIndex=4;
01769 
01770             ERROR3IF(nIndex < 1 || nIndex > 4, "ColourEditDlg::SetColour - nIndex invalid");
01771             if (!nIndex)
01772                 nIndex=1;
01773 
01774             if (cc->GetComponentName(nIndex, &NewValue))
01775             {
01776                 NewValue = GetStringGadgetValue(CurrentTypingGadget);
01777             
01778                 Clipped |= ColourPicker::SetComponentFromString(EditingColour, cc, nIndex, (String_8 *) &NewValue);
01779             }
01780         }
01781         else
01782         {
01783             NewValue = GetStringGadgetValue(CurrentTypingGadget);
01784             
01785             // we need to set all of the components ....
01786             cc = ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
01787             Clipped |= ColourPicker::SetComponentsFromHexString(EditingColour, cc, (String_16 *) &NewValue);
01788         }
01789         
01790 /*
01791         if (cc->GetComponentName(2, &NewValue) != NULL)
01792         {
01793             NewValue = GetStringGadgetValue(_R(IDC_EDIT_COMPONENT2));
01794             Clipped |= ColourPicker::SetComponentFromString(EditingColour, cc, 2, (String_8 *) &NewValue);
01795         }
01796 
01797         if (cc->GetComponentName(3, &NewValue) != NULL)
01798         {
01799             NewValue = GetStringGadgetValue(_R(IDC_EDIT_COMPONENT3));
01800             Clipped |= ColourPicker::SetComponentFromString(EditingColour, cc, 3, (String_8 *) &NewValue);
01801         }
01802 
01803         if (cc->GetComponentName(4, &NewValue) != NULL)
01804         {
01805             NewValue = GetStringGadgetValue(_R(IDC_EDIT_COMPONENT4));
01806             Clipped |= ColourPicker::SetComponentFromString(EditingColour, cc, 4, (String_8 *) &NewValue);
01807         }
01808 */
01809     }
01810 
01811     // Delete the colour context if necessary
01812     if (bDeleteCC)
01813         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
01814 
01815 
01816 /*
01817     // Set the new name of the colour - this is not done if the colour is unnamed,
01818     // because we don't want to accidentally convert an unnamed colour into a named one!
01819     BOOL NameMadeUnique = FALSE;        // Have we had to change the name that was entered?
01820     BOOL NameHasChanged = FALSE;        // Has the name been changed at all?
01821     if (EditingColour->IsNamed())
01822     {
01823         String_256 NewName = GetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), NULL);
01824 
01825         // If the name is not any different, then we must not try to update it
01826         NameHasChanged = (NewName.CompareTo(*((StringBase *)ResultColour->GetName())) != 0);
01827         if (NameHasChanged)
01828         {
01829             String_64 UniqueName;
01830             NameMadeUnique = ColourManager::GetCurrentColourList()->
01831                                     GenerateUniqueColourName(&NewName, &UniqueName);
01832 
01833             EditingColour->SetName(UniqueName);
01834         }
01835     }
01836 */
01837 
01838     switch(EditingColour->GetType())
01839     {
01840         case COLOURTYPE_TINT:
01841             {
01842                 if (EditingColour->TintIsShade())
01843                 {
01844                     String_256 XValue = GetStringGadgetValue(_R(IDC_EDIT_TINT));
01845                     String_256 YValue = GetStringGadgetValue(_R(IDC_EDIT_SHADE));
01846                     ColourPicker::SetShadeFromStrings(EditingColour, &XValue, &YValue);
01847                 }
01848                 else
01849                 {
01850                     String_256 NewValue = GetStringGadgetValue(_R(IDC_EDIT_TINT));
01851                     ColourPicker::SetTintFromString(EditingColour, &NewValue);
01852                 }
01853 
01854                 Clipped = TRUE;     // Ensure controls are updated too
01855             }
01856             break;
01857 
01858         case COLOURTYPE_LINKED:         
01859             EditingColour->SetInheritsComponent(1, GetBoolGadgetSelected(_R(IDC_EDIT_INHERIT1)));
01860             EditingColour->SetInheritsComponent(2, GetBoolGadgetSelected(_R(IDC_EDIT_INHERIT2)));
01861             EditingColour->SetInheritsComponent(3, GetBoolGadgetSelected(_R(IDC_EDIT_INHERIT3)));
01862             EditingColour->SetInheritsComponent(4, GetBoolGadgetSelected(_R(IDC_EDIT_INHERIT4)));
01863             break;
01864 
01865         default:
01866             break;
01867     }
01868 
01869     if (EditingColour->IsDifferent(*ResultColour))
01870         EditingColourHasChanged((SetComponents && Clipped), SetComponents);
01871 /*
01872     else if (NameHasChanged)
01873     {
01874         EditingColourHasChanged(FALSE, FALSE);
01875 
01876         SetColourNameList();    // The name has changed, so update the name list
01877         
01878 //      if (NameMadeUnique)     // We read the name and then changed it to ensure it was
01879 //          SetControls();      // a unique name, so we must ensure the control is updated
01880     }
01881 */
01882 }
01883 
01884 
01885 
01886 /********************************************************************************************
01887 
01888 >   void ColourEditDlg::EditThisColour(ColourList *NewParentList,
01889                                         IndexedColour *ColourToEdit,
01890                                         BOOL TheWindowIsOpen = TRUE)
01891 
01892     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01893     Created:    14/11/94
01894     Inputs:     NewParentList - The list in which the ColourToEdit resides
01895 
01896                 ColourToEdit - The colour to be edited
01897 
01898                 TheWindowIsOpen - TRUE if the window is believed to be open now, FALSE
01899                 if it is not. Used by the create handler to stop us from poking at the
01900                 window when it isn't actually open yet!
01901     Outputs:    -
01902     Returns:    -
01903     Purpose:    Switches the colour editor, when it is open, to edit a different colour
01904                 If the ColourToEdit is the colour currently being edited, nothing happens
01905     Scope:      protected
01906     Errors:     -
01907     SeeAlso:    -
01908 
01909 ********************************************************************************************/
01910 
01911 void ColourEditDlg::EditThisColour(ColourList *NewParentList, IndexedColour *ColourToEdit,
01912                                     BOOL TheWindowIsOpen)
01913 {
01914     if (ColourToEdit == ResultColour)                   // We're already editing it!
01915         return;
01916 
01917     if (Document::GetSelected() == NULL || Document::GetSelected()->GetIndexedColours() != NewParentList)
01918     {
01919         ERROR3("Colour editor: No selected doc or Colour not in selected doc");
01920         return;
01921     }
01922 
01923     if (ColourToEdit == NULL)
01924     {
01925         ERROR3("Colour editor EditThisColour: What colour?! It's NULL!");
01926         return;
01927     }
01928 
01929     // Check that the colour given really truly is in the parent list
01930     if (NewParentList != NULL &&                                                    // Have valid pointers
01931             NewParentList->FindPosition(ColourToEdit) < 0 &&                        // Isn't in named colours
01932             NewParentList->GetUnnamedColours()->FindPosition(ColourToEdit) < 0 )    // Isn't in unnamed colours
01933     {
01934         ERROR3("Colour editor: attempt to edit colour with bogus parent list pointer");
01935         return;
01936     }
01937 
01938     State.ParentListOK = FALSE;     // Swapping colours - ensure we update parent list
01939 
01940     if (TheWindowIsOpen)    // Only poke at the window if it's actually open!
01941     {
01942         if (NewParentList == NULL || ColourToEdit == NULL || ColourToEdit->IsDeleted())
01943         {
01944             // It's DELETED! Shade the window and exit
01945             ShadeMyself();
01946             return;
01947         }
01948 
01949         ShadeMyself(TRUE, TRUE);                // Unshade the window contents
01950     }
01951 
01952     ParentList = NewParentList;
01953 
01954     if (EditingColour != NULL)
01955         delete EditingColour;
01956 
01957     FirstEdit = TRUE;                   // Remember that we haven't applied this colour yet
01958 
01959     EditingColour   = new IndexedColour(*ColourToEdit); // The colour we're working on for now
01960     if (EditingColour == NULL)
01961     {
01962         InformError();
01963         ShadeMyself();
01964         return;
01965     }
01966 
01967     ResultColour    = ColourToEdit;                     // Where the result goes when 'OK'd
01968 
01969     // Copy the original colour into the OriginalColour.
01970     // We only need the colour definition, but we do need the full accuracy of an
01971     // IndexedColour to ensure rounding errors (and thus slight dither differences in
01972     // redraw) do not occur.
01973     OriginalColour = *ResultColour;
01974 
01975     StatusLine* pStatusLine = StatusLine::Get();
01976 
01977     if (EditingColour->IsNamed())
01978     {
01979         if (!pStatusLine || !pStatusLine->IsRestrictedAccessToColourPicker ())
01980         {
01981             if (AutoModelChangeN)
01982                 DisplayModel = OriginalColour.GetColourModel();
01983             else
01984                 DisplayModel = (ColourModel) DefaultDisplayModelN;
01985         }
01986     }
01987     else
01988     {   
01989         if (!pStatusLine || !pStatusLine->IsRestrictedAccessToColourPicker ())
01990         {
01991             if (AutoModelChange)
01992                 DisplayModel = OriginalColour.GetColourModel();
01993             else
01994                 DisplayModel = (ColourModel) DefaultDisplayModel;
01995         }
01996     }
01997 // WEBSTER - markn 14/1/97
01998 // Make sure the display model is either HSV or RGB
01999 // If it's neither RGB or HSV, force it to HSV
02000 #ifdef WEBSTER
02001     if (DisplayModel != COLOURMODEL_RGBT && DisplayModel != COLOURMODEL_HSVT)
02002         DisplayModel = COLOURMODEL_HSVT;
02003 #endif // WEBSTER
02004                                                    
02005     // Ensure the OriginalColour does not reference any other colour
02006     OriginalColour.SetLinkedParent(NULL, COLOURTYPE_NORMAL);
02007 
02008     if (TheWindowIsOpen)
02009         InvalidateAndSetControls();
02010 }
02011 
02012 
02013 
02014 /********************************************************************************************
02015 
02016 >   static void ColourEditDlg::SetEditingColour (IndexedColour* newEditingColour, Node* pSourceNode = NULL)
02017 
02018     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02019     Created:    3/11/99
02020     Inputs:     newEditingColour - the IndexedColour that is to be set as EditingColour
02021     Outputs:    -
02022     Returns:    -
02023     Purpose:    Camelots new custom colour picker control (also written by me) needs to be
02024                 able to change the value EditingColour on the fly (based upon the
02025                 IndexedColour that is has just read/generated) so that we do not generate
02026                 infinite amounts of undo information (which would be so if we always applied
02027                 the supplied colour).  This function allows us to achieve this functionality.
02028                 Since this function is static, to access non-static member functions from
02029                 within, we need to use TheEditor->function () otherwise VC6 complains.
02030     Scope:      public
02031     Errors:     -
02032     SeeAlso:    ColourEditDlg::ApplyEditingColourNow ()
02033 
02034 ********************************************************************************************/
02035 
02036 void ColourEditDlg::SetEditingColour (IndexedColour* newEditingColour, Node* pSourceNode)
02037 {   
02038     // if we havn't saved an abort colour yet - then we save one here
02039     // otherwise we use the colour that weve already saved as our abort colour ....
02040     if (TheEditor->abortColourState == SAVE_ABORTCOLOUR)
02041     {
02042         if (TheEditor->EditingColour != NULL)
02043         {
02044             if (TheEditor->AbortColour != NULL)
02045             {
02046                 if (!(TheEditor->AbortColour->IsNamed ()))
02047                 {
02048                     delete (TheEditor->AbortColour);
02049                 }
02050             }
02051             TheEditor->AbortColour = new IndexedColour (*(TheEditor->EditingColour));
02052             TheEditor->abortColourState = SAVED_ABORTCOLOUR;
02053         }
02054     }
02055     
02056     if (!(TheEditor->OriginalColour.IsNamed ()))
02057     {
02058         if (!(newEditingColour->IsNamed()))
02059         {   
02060             if (TheEditor->EditingColour != NULL)
02061             {
02062                 delete (TheEditor->EditingColour);
02063             }
02064 
02065             TheEditor->EditingColour = new IndexedColour (*newEditingColour);
02066         }
02067         else
02068         {   
02069             if (TheEditor->EditingColour != NULL)
02070             {
02071                 delete (TheEditor->EditingColour);
02072             }
02073 
02074             // we do some nasty stuff here - we use an unnamed colour to represent named colours
02075             // internally; and then convert (well actually we don't ever convert back again
02076             // cause this makes things more difficult - and I have more important things to be
02077             // doing with my time than working out why applying a named colour from this stuff
02078             // is such a pain in the but!)
02079             
02080             TheEditor->EditingColour = new IndexedColour (*newEditingColour);
02081             TheEditor->EditingColour->SetUnnamed ();
02082         }
02083     }
02084     else
02085     {
02086         if (TheEditor->EditingColour != NULL)
02087         {
02088             delete (TheEditor->EditingColour);
02089         }
02090 
02091         TheEditor->EditingColour = new IndexedColour (*newEditingColour);
02092         TheEditor->EditingColour->SetName (*(TheEditor->OriginalColour.GetName ()));
02093     }
02094 
02095     if (TheEditor->EditingColour == NULL)
02096     {
02097         InformError();
02098         TheEditor->ShadeMyself();
02099         return;
02100     }
02101 
02102     TheEditor->EditingColourHasChanged (TRUE, TRUE, TRUE, pSourceNode);     // force everything to redraw
02103 }
02104 
02105 
02106 /********************************************************************************************
02107 
02108 >   void ColourEditDlg::CloseColourEditor()
02109 
02110     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02111     Created:    5/5/2000
02112     Inputs:     -
02113     Outputs:    -
02114     Returns:    -
02115     Purpose:    A public method to close the colour editor dialog
02116     Scope:      public
02117     Errors:     -
02118     SeeAlso:
02119 
02120 ********************************************************************************************/
02121 
02122 void ColourEditDlg::CloseColourEditor()
02123 {
02124     CloseMyself();
02125 }
02126 
02127 
02128 /********************************************************************************************
02129 
02130 >   void ColourEditDlg::SetDoTimeProcessing(BOOL Value)
02131 
02132     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02133     Created:    5/5/2000
02134     Inputs:     boolean
02135     Outputs:    -
02136     Returns:    -
02137     Purpose:    sets a flag which indicates whether or not the colour picker will do idle 
02138                 processing.  If this is set to false the colour picker is effectively disabled.
02139     Scope:      public
02140     Errors:     -
02141     SeeAlso:
02142 
02143 ********************************************************************************************/
02144 
02145 void ColourEditDlg::SetDoTimerProcessing(BOOL Value)
02146 {
02147     m_bDoTimerProcessing = Value;
02148     if (!Value)
02149         EndTimedProcessing();
02150     else
02151         BeginTimedProcessing();
02152 }
02153 
02154 
02155 
02156 /********************************************************************************************
02157 
02158 >   BOOL ColourEditDlg::GetDoTimeProcessing()
02159 
02160     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02161     Created:    5/5/2000
02162     Inputs:     -
02163     Outputs:    -
02164     Returns:    Whether or not timer processing is currently enabled
02165     Purpose:    Access fn.
02166     Scope:      public
02167     Errors:     -
02168     SeeAlso:
02169 
02170 ********************************************************************************************/
02171 
02172 BOOL ColourEditDlg::GetDoTimerProcessing()
02173 {
02174     return m_bDoTimerProcessing;
02175 }
02176 
02177 /********************************************************************************************
02178 
02179 >   static void ColourEditDlg::ApplyEditingColourNow ()
02180 
02181     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02182     Created:    3/11/99
02183     Inputs:     -
02184     Outputs:    -
02185     Returns:    -
02186     Purpose:    Camelots new custom colour picker control (also written by me) needs to be
02187                 able to change the value EditingColour on the fly (based upon the
02188                 IndexedColour that is has just read/generated) so that we do not generate
02189                 infinite amounts of undo information (which would be so if we always applied
02190                 the supplied colour).  But we also need to be able to apply the edited colour
02191                 to the selection when the user has finished dragging my colour picker control.
02192                 This function allows us to achieve this functionality.
02193 
02194                 The function also (directly) applies named colours because of some nastiness
02195                 that I have found it necessary to treat named colours as unnamed colours; and
02196                 then revert at the end.
02197     Scope:      public
02198     Errors:     -
02199     SeeAlso:    ColourEditDlg::SetEditingColour ()
02200 
02201 ********************************************************************************************/
02202 
02203 void ColourEditDlg::ApplyEditingColourNow (BOOL UseAbortColour)
02204 {
02205     if (TheEditor->EditingColour != NULL)
02206     {
02207         TheEditor->SetColour (FALSE);
02208     }
02209 }
02210 
02211 
02212 
02213 /********************************************************************************************
02214 
02215 >   static void AbortColourPickerDrag
02216 
02217     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02218     Created:    10/03/2004
02219     Inputs:     -
02220     Outputs:    -
02221     Returns:    -
02222     Purpose:    Terminate the colour picker drag with extreme prejudice
02223                 (I.e. pass non-zero WPARAM to prevent it calling us back)
02224     Errors:     -
02225     SeeAlso:    -
02226 
02227 ********************************************************************************************/
02228 
02229 void ColourEditDlg::AbortColourPickerDrag()
02230 {
02231     if (TheEditor)
02232         TheEditor->ColourPickerAbort(_R(IDC_COLOURPICKER), 1);
02233 }
02234 
02235 
02236 
02237 /********************************************************************************************
02238 
02239 >   static BOOL DoAbortColourNow (CWindowID colourPicker)
02240 
02241     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02242     Created:    1/2/2000
02243     Inputs:     -
02244     Outputs:    -
02245     Returns:    -
02246     Purpose:    Allows camelots new custom colour picker control to abort the changing of
02247                 a colour (by way of the user pressing the escape key).  This function simply
02248                 applies the abort colour (which was already 'saved' within SetEditingColour ().
02249     Scope:      public
02250     Errors:     -
02251     SeeAlso:    ColourEditDlg::SetEditingColour ()
02252 
02253 ********************************************************************************************/
02254 
02255 BOOL ColourEditDlg::DoAbortColourNow (CWindowID colourPicker)
02256 {
02257     // firstly, lets check for obvious insanity
02258     
02259     String_256 ClassNameStr;  // The control type
02260 
02261     // Check passed a sensible window ID
02262     if (TheEditor && (TheEditor->WindowID == colourPicker))
02263     {       
02264         // only reset colour if we have a prior one to select (AbortColour). fixes #10649 - 
02265         // crash when escape is pressed before the dropper has selected a colour...
02266         if (TheEditor->AbortColour != NULL)
02267         {
02268             if (TheEditor->EditingColour != NULL)
02269             {
02270                 delete (TheEditor->EditingColour);
02271             }
02272             TheEditor->EditingColour = new IndexedColour (*(TheEditor->AbortColour));
02273             ApplyEditingColourNow (TRUE);       // this generates two bits of undo - which is undesirable!
02274         }
02275         return (TRUE);
02276     }
02277 
02278     ENSURE(FALSE, "DoColourPickerColour called for invalid colour picker control");
02279     return (FALSE);
02280 }
02281 
02282 
02283 
02284 /********************************************************************************************
02285 
02286 >   static void ColourEditDlg::SetDefaultDisplayModel (INT32 newDisplayModel)
02287 
02288     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
02289     Created:    3/11/99
02290     Inputs:     -
02291     Outputs:    -
02292     Returns:    -
02293     Purpose:    Camelots new custom colour picker control has changed the way in which the
02294                 old default colour space stuff worked.  If a user selects a colour space on
02295                 the combobox - then we SHOULD remember this - and NOT jump straight back
02296                 into the default (i.e. we should now set the selection as the default).
02297                 We need to do this in two places:  1) internally from within
02298                 ColourEditDlg::Message (); and 2) when the user sets the defaut model
02299                 for (local colours) from within the camelot options dialog.
02300                 This function allows us to achieve the second of these.
02301     Scope:      public
02302     Errors:     -
02303     SeeAlso:    ColourEditDlg::Message () (if (Msg->GadgetID == _R(IDC_EDIT_COLMODEL)) stuff)
02304 
02305 ********************************************************************************************/
02306 
02307 void ColourEditDlg::SetDefaultDisplayModel (INT32 newDisplayModel)
02308 {
02309     TheEditor->DefaultDisplayModel = TheEditor->DisplayModel = (ColourModel) newDisplayModel;
02310     TheEditor->InvalidateAndSetControls ();
02311 }
02312 
02313 
02314 
02315 /********************************************************************************************
02316 
02317 >   void ColourEditDlg::InvalidateAndSetControls(void)
02318 
02319     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02320     Created:    24/11/94
02321     Purpose:    Invalidates all of the GDraw colour-display areas (picker, patch,
02322                 parent patch) and also calls SetControls to set up all the controls.
02323                 Called whenever the colour has changed so significantly that the entire
02324                 window needs to be updated.
02325 
02326 ********************************************************************************************/
02327 
02328 void ColourEditDlg::InvalidateAndSetControls(void)
02329 {
02330     InvalidateGadget(_R(IDC_EDIT_PICKER));                  // Redraw picker and colour patches
02331     RedrawColourNameList();                             // Redraw colour name dropdown
02332 
02333     SetControls();                                      // Re-init the window controls
02334 }
02335 
02336 
02337 
02338 /********************************************************************************************
02339 
02340 >   inline INT32 HalfGridLock(INT32 Position, INT32 GridSize)
02341 
02342     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02343     Created:    16/11/94
02344 
02345     Inputs:     Position - The X/Y position, in millipoints
02346                 GridSize - the size of the grid to lock to, in millipoints
02347 
02348     Returns:    Position, locked (by rounding) to a grid of the given size, and offset by
02349                 half a grid.
02350 
02351     Purpose:    Grid-locks a given plotting poisition to lie over a grid (usually the
02352                 output device-pixel grid). The result is shifted by half the grid size to
02353                 grid-lock to the _center_ of a pixel rather than the edges.
02354 
02355     Scope:      private (to ColourEditDlg rendering routines)
02356 
02357 ********************************************************************************************/
02358 
02359 inline INT32 HalfGridLock(INT32 Position, INT32 GridSize)
02360 {
02361     // By truncating down to the nearest grid point, and adding half the grid value,
02362     // we achieve rounding to the nearest offset-grid position. 
02363 
02364     // NOTE:
02365     // The original algorithm incorrectly rounded negative numbers towards
02366     // zero. Negative numbers should be rounded towards negative infinity.
02367     // The algorithm has been corrected by always rounding a positive number
02368     // and restoring the original sign of the number after rounding.
02369 
02370     BOOL bNegative = FALSE;             // Assume the number is positive
02371 
02372     if (Position < 0)                   // If the number if not positive
02373     {                                   // note the fact and make positive
02374         bNegative   = TRUE;
02375         Position    = -Position;
02376     }
02377 
02378     Position -= Position % GridSize;
02379     Position += GridSize / 2;
02380 
02381     if (bNegative)                      // If the number was negative
02382         Position = -Position;           // restore the sign
02383 
02384     return (Position);
02385 }
02386 
02387 
02388 
02389 /********************************************************************************************
02390 
02391 >   static void GridLockRect(DocRect *TheRect, INT32 GridSize)
02392 
02393     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02394     Created:    16/11/94
02395 
02396     Inputs:     TheRect - A MILLIPOINT DocRect to be grid-locked
02397                 GridSize - the size of the grid to lock to, in millipoints
02398 
02399     Outputs:    TheRect is updated as appropriate
02400 
02401     Purpose:    GridLocks all 4 coordinates of the rectangle using HalfGridLock
02402 
02403     Scope:      private (to ColourEditDlg rendering routines)
02404 
02405 ********************************************************************************************/
02406 
02407 static void GridLockRect(DocRect *TheRect, INT32 GridSize)
02408 {
02409     TheRect->lo.x = HalfGridLock(TheRect->lo.x, GridSize);
02410     TheRect->lo.y = HalfGridLock(TheRect->lo.y, GridSize);
02411     TheRect->hi.x = HalfGridLock(TheRect->hi.x, GridSize);
02412     TheRect->hi.y = HalfGridLock(TheRect->hi.y, GridSize);
02413 }
02414 
02415 
02416 
02417 /********************************************************************************************
02418 
02419 >   void ColourEditDlg::InvalidatePatchGadget(ReDrawInfoType *Info = NULL)
02420 
02421     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02422     Created:    27/9/95
02423 
02424     Inputs:     Info - if non-NULL, points to the redraw info for the picker gadget
02425                 (If NULL, this method will find out the info for itself)
02426 
02427     Purpose:    Invalidates the current colour patch to ensure it is redrawn
02428 
02429 ********************************************************************************************/
02430 
02431 void ColourEditDlg::InvalidatePatchGadget(ReDrawInfoType *Info)
02432 {
02433     ReDrawInfoType LocalInfo;
02434 
02435     if (Info == NULL)
02436         GetKernelRenderedGadgetInfo(_R(IDC_EDIT_PICKER), &LocalInfo);
02437     else
02438         memcpy(&LocalInfo, Info, sizeof(ReDrawInfoType));
02439 
02440     INT32 PixelSize = 72000 / LocalInfo.Dpi;        // Size of output pixel in millipoints
02441 
02442     DocRect PatchRect(0, 0, LocalInfo.dx, LocalInfo.dy);
02443     PatchRect.Inflate(-PixelSize * 4);          // Allow for the indented border
02444 
02445     // Now draw the original/current colour patch in the top right corner
02446     PatchRect.lo.x = PatchRect.hi.x - PATCHSIZE;
02447     PatchRect.lo.y = PatchRect.hi.y - PATCHSIZE;
02448     GridLockRect(&PatchRect, PixelSize);
02449 
02450     // Patches are horizontal if the colour model is not HSV
02451     BOOL HorzPatch = (DisplayModel != COLOURMODEL_HSVT);
02452     
02453     // But this setting is overridden for the special tint and shade modes
02454     if (EditingColour != NULL && EditingColour->GetType() == COLOURTYPE_TINT)
02455     {
02456         if (EditingColour->TintIsShade())
02457             HorzPatch = FALSE;
02458         else
02459             HorzPatch = TRUE;
02460     }
02461 
02462     // Translate the rect across or down as appropriate to 'HorzPatch'
02463     if (!HorzPatch)
02464         PatchRect.Translate(0, -PATCHSIZE);
02465 
02466     InvalidateGadget(_R(IDC_EDIT_PICKER), &LocalInfo, &PatchRect);
02467 }
02468 
02469 
02470 
02471 /********************************************************************************************
02472 
02473 >   void ColourEditDlg::CloseMyself(void)
02474 
02475     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02476     Created:    15/11/94
02477     Inputs:     -
02478     Outputs:    -
02479     Returns:    -
02480     Purpose:    Cleans up, discards data on the colour being edited, and closes the
02481                 editor window. Used to close the editor in response to different messages,
02482                 e.g. when the selected document changes, or when the colour is deleted.
02483     Errors:     -
02484     SeeAlso:    -
02485 
02486 ********************************************************************************************/
02487 
02488 void ColourEditDlg::CloseMyself(void)
02489 {
02490     if (EditingColour != NULL)
02491     {
02492         // Ensure we remember the current model as the preferred default
02493         if (EditingColour->IsNamed())
02494             DefaultDisplayModelN = (INT32) DisplayModel;
02495 // But do not overwrite the preference for local colours - this must be set in the options dlg
02496 //      else
02497 //          DefaultDisplayModel = (INT32) DisplayModel;
02498 
02499         delete EditingColour;
02500         EditingColour = NULL;
02501     }
02502     ParentList = NULL;
02503     State.ParentListOK = FALSE;     // Swapping colours - ensure we update parent list
02504 
02505     Close();
02506     End();
02507 }
02508 
02509 
02510 
02511 
02512 /********************************************************************************************
02513 
02514 >   void ColourEditDlg::ShadeMyself(BOOL UnShade = FALSE, BOOL OtherGadgetsOnly = FALSE)
02515 
02516     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02517     Created:    6/12/94
02518     Inputs:     UnShade - FALSE to shade, TRUE to un-shade the dialogue
02519                 OtherGadgetsOnly - FALSE to shade all gadgets. TRUE to only shade the
02520                 'ordinary' gadgets (those which are nothing to do with tint/link stuff)
02521     Outputs:    -
02522     Returns:    -
02523     Purpose:    Shades/Unshades the colour editor dialogue.
02524                 Used to shade the dialogue while there is nothing available to edit,
02525                 and return it to a useful state when something becomes available for
02526                 editing.
02527 
02528 ********************************************************************************************/
02529 
02530 void ColourEditDlg::ShadeMyself(BOOL UnShade, BOOL OtherGadgetsOnly)
02531 {
02532     if (AmShaded != UnShade)        // Already in the required state. Leave it alone
02533         return;
02534 
02535     State.ParentListOK = FALSE;     // Ensure we update parent list
02536 
02537     AmShaded = (UnShade) ? FALSE : TRUE;
02538 
02539     if (AmShaded)
02540     {
02541         if (EditingColour != NULL)
02542             delete EditingColour;
02543 
02544         EditingColour = NULL;
02545         ResultColour = NULL;
02546         ParentList = NULL;
02547 
02548         if (NameDropDown != NULL)
02549         {
02550             NameDropDown->ClearList();
02551             NameDropDown->ClearAllSpecialEntries();
02552         }
02553 
02554         if (ParentDropDown != NULL)
02555             ParentDropDown->ClearList();
02556     }
02557 
02558     INT32 i = 0;
02559     while (OtherGadgetIDs[i])
02560     {
02561         EnableGadget(OtherGadgetIDs[i], UnShade);
02562         i++;
02563     }
02564                     // Force-redraw the colour patches and picker
02565     InvalidateGadget(_R(IDC_EDIT_PICKER));
02566 
02567 //  if (AmShaded)   // If we are shading the dialogue, set the colour name to 'No colour'
02568 //      SetStringGadgetValue(_R(IDC_EDIT_NAMEMENU), _R(IDS_NOCOLOUR), FALSE, -1);
02569 
02570     if (OtherGadgetsOnly)           // Don't do tint/link gadgets - return now
02571         return; 
02572 
02573     i = 0;
02574     while (TintGadgetIDs[i])
02575     {
02576         EnableGadget(TintGadgetIDs[i], UnShade);
02577         i++;
02578     }
02579 
02580     i = 0;
02581     while (LinkGadgetIDs[i])
02582     {
02583         EnableGadget(LinkGadgetIDs[i], UnShade);
02584         i++;
02585     }
02586 }
02587 
02588 
02589 /********************************************************************************************
02590 
02591 >   void ColourEditDlg::ApplyNoColour(BOOL LineColour)
02592 
02593     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02594     Created:    14/12/96
02595 
02596     Inputs:     LineColour - TRUE if you want to set the line colour, FALSE if you want to set the fill colour
02597 
02598     Purpose:    Sets either the fill or the line colour to "No colour"
02599 
02600                 Needed for WEBSTER
02601 
02602     SeeAlso:    -
02603 
02604 ********************************************************************************************/
02605 
02606 void ColourEditDlg::ApplyNoColour(BOOL LineColour)
02607 {
02608     DocColour ColourToApply(COLOUR_TRANS);
02609 
02610     if (LineColour)
02611     {
02612         // Line colour selected so create a line colour attribute
02613         AttrStrokeColourChange* pAttrib = new AttrStrokeColourChange;
02614         if (pAttrib == NULL)
02615             return;
02616 
02617         pAttrib->SetStartColour(&ColourToApply);
02618 
02619         // AttributeSelected knows what to do with a selected attribute
02620         AttributeManager::AttributeSelected(NULL, pAttrib); 
02621     }
02622     else
02623     {   
02624         // Rather than setting the flat fill colour, we do an AttrColourChange, which
02625         // (I assume) will handle things like selected grad fill points, etc.
02626         AttrColourChange* pAttrib = new AttrColourChange;
02627         if (pAttrib == NULL)
02628             return;
02629 
02630         pAttrib->SetStartColour(&ColourToApply);
02631 
02632         // AttributeSelected knows what to do with a selected attribute
02633         AttributeManager::AttributeSelected(NULL, pAttrib); 
02634     }
02635 }
02636 
02637 /********************************************************************************************
02638 
02639 >   FIXED24 ColourEditDlg::Nearest20Percent(FIXED24 n)
02640 
02641     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02642     Created:    19/12/96
02643     Inputs:     n = the colour component (number between 0.0 & 1.0 inclusive
02644     Returns:    The colour component value that is a multiple of 20%, nearest to the inout value
02645     Purpose:    Finds the nearest 20% value for this component, e.g. if n=0.23, the result will be 0.2
02646                 as this is the closest 20% value.
02647 
02648                 Needed for WEBSTER
02649 
02650     SeeAlso:    -
02651 
02652 ********************************************************************************************/
02653 
02654 /* Not needed anymore (Markn 16/7/97)
02655 // Superceded by PaletteManager::FindNearestBrowserColour()
02656 
02657 FIXED24 ColourEditDlg::Nearest20Percent(FIXED24 n)
02658 {
02659     double d = n.MakeDouble();
02660 
02661     ERROR3IF(d > 1.0 || d < 0.0,"I thought this value should be between 0.0 and 1.0 inclusive");
02662 
02663     double r = fmod(d,0.2);
02664 
02665     if (r > 0.1)
02666         d += (0.2-r);
02667     else
02668         d -= r;
02669 
02670     return (FIXED24(d));
02671 }
02672 */
02673 
02674 /********************************************************************************************
02675 
02676 >   void ColourEditDlg::LimitTo216Only()
02677 
02678     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02679     Created:    14/12/96
02680 
02681     Inputs:     -
02682 
02683     Purpose:    Snaps the current colour to the closest colour in the web browseer palette.
02684 
02685                 Needed for WEBSTER
02686 
02687     SeeAlso:    -
02688 
02689 ********************************************************************************************/
02690 
02691 void ColourEditDlg::LimitTo216Only()
02692 {
02693     if (EditingColour == NULL)
02694         return;
02695 
02696     ColourContext *CCrgbt = ColourManager::GetColourContext(COLOURMODEL_RGBT);
02697 
02698     ColourRGBT RGBColour,result;
02699     CCrgbt->ConvertColour(EditingColour, (ColourGeneric *)&RGBColour);
02700 
02701     PaletteManager::FindNearestBrowserColour(RGBColour,&result);
02702 
02703 //  IndexedColour NewRGBIndexedColour(COLOURMODEL_RGBT, (ColourGeneric *)&result);
02704 //
02705 //  *EditingColour = NewRGBIndexedColour;
02706 
02707     if (EditingColour->GetColourModel() == COLOURMODEL_RGBT)
02708     {
02709         ColourPicker::SetComponentFromDouble(EditingColour, CCrgbt, 1, result.Red.MakeDouble());
02710         ColourPicker::SetComponentFromDouble(EditingColour, CCrgbt, 2, result.Green.MakeDouble());
02711         ColourPicker::SetComponentFromDouble(EditingColour, CCrgbt, 3, result.Blue.MakeDouble());
02712     }
02713     else
02714     {
02715         IndexedColour NewRGBIndexedColour(COLOURMODEL_RGBT, (ColourGeneric *)&result);
02716 
02717         ColourContext *CChsvt = ColourManager::GetColourContext(COLOURMODEL_HSVT);
02718 
02719         ColourHSVT hsv;
02720         CChsvt->ConvertColour(&NewRGBIndexedColour, (ColourGeneric *)&hsv);
02721 
02722         ColourPicker::SetComponentFromDouble(EditingColour, CChsvt, 1, hsv.Hue.MakeDouble());
02723         ColourPicker::SetComponentFromDouble(EditingColour, CChsvt, 2, hsv.Saturation.MakeDouble());
02724         ColourPicker::SetComponentFromDouble(EditingColour, CChsvt, 3, hsv.Value.MakeDouble());
02725     }
02726 
02727     EditingColourHasChanged(TRUE,TRUE,TRUE);
02728 
02729 //  InvalidateAndSetControls(); // And redraw the picker, and put the new values in the writables
02730 
02732 //search for "DisplayModel =" to find where it sets the display colour model
02733 //search for "Command" to find all the menu handling code
02734 }
02735 
02736 /********************************************************************************************
02737 
02738 >   void ColourEditDlg::FindUsefulColourToEdit(BOOL WantLineColour = FALSE,
02739                                                 BOOL TheWindowIsOpen = TRUE)
02740 
02741     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02742     Created:    3/1/95
02743 
02744     Inputs:     WantLineColour - TRUE if you want  line colour, FALSE if you want a fill colour
02745                 
02746                 TheWindowIsOpen - FALSE if the window is closed, TRUE if it's open
02747                 (used by the create code to stop us poking at the window when it's closed!
02748 
02749     Purpose:    Calls the ColourManager method (cf SeeAlso) to determine which colour should
02750                 be displayed in the editor, and swaps to editing this colour (or if no
02751                 colour is available, shades the editor)
02752 
02753     SeeAlso:    ColourManager::FindColourOfInterestToUser; ColourEditDlg::EditThisColour;
02754                 ColourEditDlg::ShadeMyself
02755 
02756 ********************************************************************************************/
02757 
02758 void ColourEditDlg::FindUsefulColourToEdit(BOOL WantLineColour, BOOL TheWindowIsOpen)
02759 {
02760     State.ParentListOK = FALSE;     // Swapping colours - ensure we update parent list
02761 
02762     ColourList      *NewParentList  = NULL;
02763     IndexedColour   *IxColourToEdit = NULL;
02764     DocColour       DocColourToEdit;
02765 
02766     EditingLineColour = WantLineColour;     // Remember whether editing line or fill
02767 
02768     ColourManager::FindColourOfInterestToUser(&DocColourToEdit, &NewParentList, WantLineColour);
02769 
02770     if (NewParentList == NULL)
02771     {
02772         if (TheWindowIsOpen)
02773             ShadeMyself();
02774     }
02775     else
02776     {
02777         NoFillButtonDown = DocColourToEdit.IsTransparent();
02778 
02779         if (NoFillButtonDown)
02780         {
02781             AttributeManager &AttrMgr = Document::GetSelected()->GetAttributeMgr();
02782 
02783             DocColour LineCol;
02784             DocColour FillCol;
02785                 
02786             AttrMgr.GetCurrentLineAndFillColour(CC_RUNTIME_CLASS(NodeRenderableInk),
02787                                                     &LineCol, &FillCol);
02788             if (WantLineColour)
02789                 DocColourToEdit = LineCol;
02790             else
02791                 DocColourToEdit = FillCol;
02792 
02793             // if the default is no fill DON'T set that because this is the colour we get
02794             // when we are explicitly removing no fill
02795             if ( DocColourToEdit.IsTransparent() )
02796                 DocColourToEdit = DocColour(COLOUR_WHITE);//prob should set to page colour
02797         }
02798         IxColourToEdit = ColourManager::GenerateNewUnnamedColour(NewParentList, &DocColourToEdit);
02799 
02800         if (EditingColour == NULL || IxColourToEdit != NULL)
02801             EditThisColour(NewParentList, IxColourToEdit, TheWindowIsOpen);
02802         else
02803         {
02804             if (TheWindowIsOpen)
02805                 ShadeMyself();
02806         }
02807     }
02808 }
02809 
02810 
02811 
02812 /********************************************************************************************
02813 
02814 >   MsgResult ColourEditDlg::Message( Msg* Message)
02815 
02816     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02817     Created:    13/6/94
02818     Inputs:     Msg - The dialogue manager message to handle
02819     Outputs:    -
02820     Returns:    A MsgResult
02821     Purpose:    Standard DialogOp message handler, for the Colour Editor dialogue
02822 
02823     Notes:      All code in this method must be able to handle being called when
02824                 EditingColour == NULL (the window is shaded)
02825 
02826     Errors:     -
02827     SeeAlso:    -
02828 
02829 ********************************************************************************************/
02830 
02831 MsgResult ColourEditDlg::Message( Msg* Message )
02832 {
02833     // DY 5/5/2000 this is really ugly but I'm in a hurry.  Basically I need to disable background processing
02834     // whilst a brush stroke is in progress, at the end of the drag normal servive will be resumed
02835     if (!m_bDoTimerProcessing)
02836         return(DialogOp::Message(Message));
02837 
02838     if (MESSAGE_IS_A(Message, ColourChangingMsg))
02839     {
02840         ColourChangingMsg *TheMsg = (ColourChangingMsg *) Message;
02841 
02842         switch ( TheMsg->State )
02843         {
02844             case ColourChangingMsg::COLOURUPDATED:
02845             case ColourChangingMsg::COLOURUPDATEDINVISIBLE:
02846                 // If I didn't send the message and the colour is the one I'm editing,
02847                 // reset the controls to reflect whatever the change was.
02848                 // (This mainly happens as a result of undo)
02849                 if (!ISentTheMessage && TheMsg->ChangedColour == ResultColour)
02850                 {
02851                     // Delete our current copy of the EditingColour, and get a fresh one
02852                     // as a copy of the newly-changed ResultColour
02853                     if (EditingColour != NULL)
02854                         delete EditingColour;
02855 
02856                     EditingColour = new IndexedColour(*ResultColour);
02857                     if (EditingColour == NULL)
02858                         InformError();  // Report the memory error and continue
02859 
02860                     InvalidateAndSetControls();
02861                 }
02862                 else if (ResultColour != NULL && ResultColour->IsADescendantOf(TheMsg->ChangedColour))
02863                 {
02864                     // If an ancestor of the colour being edited has changed, redraw the editor
02865                     // to take on board the change in appearance
02866                     InvalidateAndSetControls();
02867                 }
02868                 break;
02869 
02870             case ColourChangingMsg::LISTPAGED:      // May have swapped to another list
02871                 if (TheMsg->NewColourList != ParentList)
02872                 {
02873                     ResultColour = NULL;                        // Lose this colour
02874                     if (EditingColour != NULL)
02875                         delete EditingColour;
02876                     EditingColour = NULL;
02877 
02878                     UpdateOnNextIdle = TRUE;
02879                     UpdateColourEditor ();
02880                 }
02881 /*
02882                 if (TheMsg->NewColourList != ParentList)
02883                 {
02884                     ResultColour = NULL;                        // Lose this colour
02885                     if (EditingColour != NULL)
02886                         delete EditingColour;
02887                     EditingColour = NULL;
02888 
02889                     FindUsefulColourToEdit(EditingLineColour);  // Try to find a replacement
02890                     
02891                     if (EditingColour == NULL)                  // We failed - shade the dialogue
02892                         ShadeMyself();
02893                 }
02894 */
02895                 break;
02896 
02897             case ColourChangingMsg::LISTDELETED:    // May have deleted this colour
02898                 // The ColourList we're editing in has been deleted from under us!
02899                 if (TheMsg->NewColourList == ParentList)
02900                     ShadeMyself();
02901                 break;
02902 
02903             case ColourChangingMsg::LISTDESELECTED:// No document available
02904                 ShadeMyself();
02905                 break;
02906 
02907             case ColourChangingMsg::LISTUPDATED:    // Colour may have been deleted
02908                 {
02909                     //BOOL SetControls = FALSE;
02910     
02911                     // If the colour is deleted out from under us, try to find another one to edit
02912                     if (ResultColour != NULL && ResultColour->IsDeleted())
02913                     {
02914                         ResultColour = NULL;                        // Lose this colour
02915                         if (EditingColour != NULL)
02916                             delete EditingColour;
02917                         EditingColour = NULL;
02918 
02919                         FindUsefulColourToEdit(EditingLineColour);  // Try to find a replacement
02920                     
02921                         if (EditingColour == NULL)                  // We failed - shade the dialogue
02922                             ShadeMyself();
02923                     }
02924 
02925                     if (EditingColour != NULL)
02926                     {
02927                         if (EditingColour->FindLastLinkedParent() != NULL &&
02928                             EditingColour->FindLastLinkedParent()->IsDeleted())
02929                         {
02930                             // If the parent of EditingColour has been deleted, then make standalone
02931                             IndexedColourType Type = EditingColour->GetType();
02932                             if (Type != COLOURTYPE_SPOT)
02933                                 Type = COLOURTYPE_NORMAL;
02934 
02935                             EditingColour->SetLinkedParent(NULL, Type);
02936                             //SetControls = TRUE;
02937                         }
02938                         else if (EditingColour->GetType() == COLOURTYPE_NORMAL &&
02939                                  ResultColour != NULL && ResultColour->FindLinkedParent() != NULL)
02940                         {
02941                             // ResultColour's parent may have just become un-deleted (by an UNDO).
02942                             // If this could be the case, and EditingColour has no parent, then
02943                             // we must have set EditingColour to have no parent just above (i.e. the
02944                             // user deleted the parent and then hit UNDO)
02945                             // In this case, set EditingColour back to the values in ResultColour
02946                             EditingColour->SetLinkedParent(ResultColour->FindLinkedParent(), ResultColour->GetType());
02947                             //SetControls = TRUE;
02948                         }
02949                     }
02950 
02951                     // Ensure the colour name and type dropdowns are updated to offer sensible options
02952                     State.ParentListOK = FALSE;
02953                     State.Initialised = FALSE;
02954                     InvalidateAndSetControls();
02955                 }
02956                 break;
02957 
02958             case ColourChangingMsg::SELVIEWCONTEXTCHANGE:
02959                 // The selected view's colour context has chnaged, which probably affects the
02960                 // colour correction/separation options. We redraw using these options, so we
02961                 // need to redraw to reflect the new settings.
02962                 InvalidateAndSetControls();
02963                 break;
02964 
02965             default:
02966                 break;
02967         }
02968 
02969         return(DialogOp::Message(Message));
02970     }
02971 
02972     if (MESSAGE_IS_A(Message, SelChangingMsg))      // Selection changed - edit new colour
02973     {
02974         SelChangingMsg *Msg = (SelChangingMsg *) Message;
02975         switch ( Msg->State )
02976         {
02977             case SelChangingMsg::COLOURATTCHANGED:
02978             case SelChangingMsg::SELECTIONCHANGED:
02979             case SelChangingMsg::NODECHANGED:
02980                 if (!ISentTheMessage)
02981                 {
02982                     UpdateOnNextIdle = TRUE;
02983                     UpdateColourEditor ();
02984                 }
02985 //                  FindUsefulColourToEdit(EditingLineColour);
02986                 break;
02987 
02988             default:
02989                 break;
02990         }
02991     }
02992     else if (MESSAGE_IS_A(Message, CurrentAttrChangedMsg))  // Current attrs changed - edit new colour
02993     {
02994         if (!ISentTheMessage)
02995         {
02996             UpdateOnNextIdle = TRUE;
02997             UpdateColourEditor ();
02998         }
02999 //          FindUsefulColourToEdit(EditingLineColour);
03000     }
03001     else if (MESSAGE_IS_A(Message, DragMessage))
03002     {
03003         // If a drag starting message comes around, pass it on to the tree
03004         DragMessage *Msg = (DragMessage *) Message;
03005         if (Msg->State == DragMessage::DRAGSTARTED)
03006         {
03007             // If it's a colour drag which did NOT originate from the editor, then attach
03008             // a drag target so it can be dropped into the editor.
03009             if (Msg->pInfo->IsKindOf(CC_RUNTIME_CLASS(ColourDragInformation)) &&
03010                 !IS_A(Msg->pInfo, ColEditorDragInfo))
03011             {
03012                 ColourDragInformation *CDI = (ColourDragInformation *)Msg->pInfo;
03013                 
03014                 // Check if it's a library colour, or else it must be a colour in the selected doc
03015                 if (CDI->GetParentDoc() == NULL || CDI->GetParentDoc() == Document::GetSelected())
03016                 {
03017                     // Create targets for all the interesting bits of the window
03018                     // **** !!!! ToDo (maybe) Targets for colour picker and colour patches
03019 
03020                     // Last, add one for the whole window - this is lower priority than the
03021                     // others, so will only be active for any areas which are not claimed by
03022                     // the above targets
03023                     /*ColEditorDragTarget * NewTarget = */ new ColEditorDragTarget(this, 0);
03024                 }
03025                 // We don't really care if this failed...
03026             }           
03027         }
03028     }
03029 
03030 // WEBSTER - markn 9/1/97
03031 // This message shouldn't need servicing in Webster.
03032 //#ifndef WEBSTER
03033     else if (MESSAGE_IS_A(Message, OptionsChangingMsg))
03034     {
03035         OptionsChangingMsg *Msg = (OptionsChangingMsg *) Message;
03036         if (Msg->State == OptionsChangingMsg::NEWUNITS)
03037         {
03038             // A unit has changed. This can include the decimal point character, so we need
03039             // to set the values in all writable fields again & get the default.
03040             SetUnitGroupDefaults(DisplayModel);
03041             SetControls();
03042         }
03043     }
03044 //#endif // WEBSTER
03045     else if (MESSAGE_IS_A(Message, DocViewMsg))
03046     {
03047         DocViewMsg *Msg = (DocViewMsg *) Message;
03048 
03049         if (Msg->State == DocViewMsg::SELCHANGED)
03050         {
03051             // Selected DocView is changing - redraw to use the new DocView's colour context
03052             BOOL DoRedraw = TRUE;
03053             if (Msg->pOldDocView != NULL && Msg->pNewDocView != NULL)
03054             {
03055                 // If we know the old & new views, then see if they have the same colour
03056                 // context attached - if they do, there's no need to redraw. This eliminates
03057                 // flicker when swapping normal views (the most common view-swap action)
03058                 // We only check the RGB context because we assume the screen is always RGB
03059                 ColourContext *OldCC = Msg->pOldDocView->GetColourContext(COLOURMODEL_RGBT, TRUE);
03060                 ColourContext *NewCC = Msg->pNewDocView->GetColourContext(COLOURMODEL_RGBT, TRUE);
03061 
03062                 if (OldCC == NewCC)
03063                     DoRedraw = FALSE;
03064             }
03065 
03066             if (DoRedraw)
03067             {
03068                 UpdateOnNextIdle = TRUE;
03069                 UpdateColourEditor ();
03070             }
03071 //              InvalidateAndSetControls();
03072         }
03073     }
03074 
03075 
03076     if (!(IS_OUR_DIALOG_MSG(Message)))
03077         return(DialogOp::Message(Message));
03078 
03079     DialogMsg* Msg = (DialogMsg*)Message;
03080 
03081 #if _DEBUG
03082 /*
03083     if ((INT32)Msg->DlgMsg == (INT32)DIM_TITLEFOCUSWARN + 1)
03084     {
03085         if (CurrentCursor != NULL)
03086         {
03087             delete CurrentCursor;
03088             CurrentCursor = NULL;
03089         }
03090 
03091         if (CurrentCursorID != NULL)
03092         {
03093             CurrentCursor = new Cursor(CurrentCursorID);
03094             if (CurrentCursor != NULL)
03095                 CurrentCursor->SetActive();
03096         }
03097         else
03098         {
03099             if (Cursor::Arrow != NULL)
03100                 Cursor::Arrow->SetActive();
03101         }
03102         return(DialogOp::Message(Message));
03103     }
03104 */
03105 #endif
03106 
03107     switch(Msg->DlgMsg)
03108     {
03109         case DIM_TITLEFOCUSWARN:
03110             // --- Input focus bodge ---
03111             // The window has been moved or the titlebar clicked. This means we've been given
03112             // the input focus, and we don't want that. So we throw the focus away again.
03113             // Unfortunately this does not work as we immediately get the focus again! Thus,
03114             // we set up an idle processor to be called back once all the moving has been
03115             // finished, so that we lose the focus shortly after the drag completes, and
03116             // the effect is more permanent!            
03117             DragStartArea = CEDRAG_NONE;    // Tell idle system we're not in the middle of a picker drag
03118 
03119             //LoseKbdFocusPending = TRUE;       // And flag the fact that we want to lose the focus
03120             //BeginTimedProcessing();
03121             //LoseKeyboardFocus ();
03122             DialogManager::DefaultKeyboardFocus();
03123             break;
03124 
03125         case DIM_CREATE:
03126             ColourPicker::OnCreate(WindowID);
03127             SetGadgetBitmaps(_R(IDC_EDIT_DROPMENU), 0, 0);
03128             #ifndef WEBSTER
03129             SetGadgetBitmaps(_R(IDC_EDIT_MAKESTYLE), 0, 0);
03130             SetGadgetBitmaps(_R(IDC_EDIT_ADVANCED), 0, 0);
03131             #endif
03132             // WEBSTER - markn 11/12/96
03133             // Changes to the bitmap buttons at the top of the colour editor
03134             // Set up our bitmap button gadgets with appropriate bitmaps
03135             //SetGadgetBitmaps(_R(IDC_EDIT_LINEFILL), 0, 0);    
03136             SetGadgetBitmaps(_R(IDC_EDIT_NOCOLOUR), 0, 0);  
03137             SetGadgetBitmaps(_R(IDC_EDIT_216ONLY), 0, 0);   
03138             SetGadgetBitmaps(_R(IDC_MAKE_LOCAL), 0, 0);
03139             SetGadgetBitmaps(_R(IDC_EDIT_RENAME), 0, 0);    
03140             
03141             
03142             // WEBSTER - markn 31/1/97
03143             // Make sure the line/fill switch is set correctly
03144             //#ifdef WEBSTER
03145             //SetBoolGadgetSelected(_R(IDC_EDIT_LINEFILL), EditingLineColour);
03146             //#endif // WEBSTER
03147 
03148             ResetState();               // Ensure all controls and window extent are updated
03149             SetUnitGroupDefaults(DisplayModel); // and defaults are set
03150             SetControls();              // ...and update them
03151 
03152             ColourPicker::RelayoutDialog(WindowID);
03153 
03154             // And then lob away the input focus again - put it back into the mainframe
03155             LockLoseFocus = FALSE;      // Ensure the focus lock is reset to off whenever we open
03156             LoseFocusFromEditControls = FALSE;
03157             LoseKeyboardFocus();
03158 
03159             {
03160                 INT32 i = 0;
03161                 while (GadgetHelp[i].Gadget)
03162                 {
03163                     SetGadgetHelp(GadgetHelp[i].Gadget, GadgetHelp[i].BubbleID, GadgetHelp[i].BubbleID);
03164                     i++;
03165                 }
03166             }
03167             BeginTimedProcessing();
03168             break;
03169 
03170         case DIM_COMMIT:
03171 //          // NOTE - this dialogue does NOT have an 'OK' (commit) button
03172 //          // The only way that we can therefore recieve this message is if return
03173 //          // is pressed. If this is done in the name text field, we must update
03174 //          // the name list to show this colour's name correctly
03175             if (!ISentTheMessage)
03176             {
03177                 SetColour(FALSE);       // Update the colour
03178 
03179                 LoseFocusFromEditControls = TRUE;
03180                 LoseKeyboardFocus();    // And we've committed, so lose the keyboard focus
03181                 LoseFocusFromEditControls = FALSE;
03182 //
03183 //              State.ParentListOK = FALSE;
03184 //              SetColourNameList();    // Update the parent list
03185             }
03186             break;
03187 
03188         case DIM_CANCEL:                // Cancel clicked
03189         {
03190             StatusLine* pStatusLine = StatusLine::Get();
03191             if (!pStatusLine || !pStatusLine->IsRestrictedAccessToColourPicker())
03192             {
03193                 CloseMyself();          // And close the window
03194             }
03195             else
03196             {
03197                 ColourPickerAbort (_R(IDC_COLOURPICKER));
03198             }
03199         }
03200         return(OK);                 // ... making sure the base class handler is NOT called (it blows up)
03201 
03202         case DIM_CTRL_RESIZED:
03203         {
03204             if (Msg->GadgetID == _R(IDC_EDIT_PICKER))
03205                 ColourPicker::OnSize(WindowID);
03206         }
03207         break;
03208 
03209         case DIM_REDRAW:                // Kernel-redraw of colour patch or picker controls
03210         {
03211             RenderControl(Msg->GadgetID, (ReDrawInfoType*) Msg->DlgMsgParam);
03212         }
03213         break;
03214 
03215         case DIM_LFT_BN_CLICKED:
03216             // Remove bubble help whenever the user clicks
03217 PORTNOTE("other", "Disabled BubbleHelp stuff")
03218 #ifndef EXCLUDE_FROM_XARALX
03219             ControlHelper::BubbleHelpDisable();
03220 #endif
03221 
03222             if (FALSE) {}
03223 #if 0
03224             else if (Msg->GadgetID == _R(IDC_NATIVEPICKER))
03225             {
03226                 if (EditingColour != NULL)
03227                 {
03228                     Close();        // Close ourself, and replace with the native colour picker
03229 
03230                     ColourPicker NewPicker;
03231                     NewPicker.EditColour(ParentList, ResultColour, TRUE);
03232 
03233                     if (EditingColour != NULL)
03234                     {
03235                         delete EditingColour;
03236                         EditingColour = NULL;
03237                     }
03238                     End();
03239                 }
03240             }
03241 #endif
03242 
03243 // WEBSTER - markn 11/12/96
03244 #ifndef WEBSTER
03245             else if (Msg->GadgetID == _R(IDC_EDIT_ADVANCED))
03246             {
03247                 // Toggling size is allowed even when we're shaded
03248                 Folded = !Folded;           // Toggle the folded state of the window
03249                 SetControls();              // And re-set the window size
03250             }
03251 #endif // WEBSTER
03252 
03253 #if 0 // WEBSTER - markn 11/12/96
03254             else if (Msg->GadgetID == _R(IDC_EDIT_LINEFILL))
03255             {
03256                 FindUsefulColourToEdit(GetBoolGadgetSelected(_R(IDC_EDIT_LINEFILL)));
03257             }
03258 #endif
03259             
03260             // WEBSTER - markn 14/12/96 
03261             else if (Msg->GadgetID == _R(IDC_EDIT_NOCOLOUR))
03262             {
03263                 if ( NoFillButtonDown )
03264                 {
03265                     NoFillButtonDown = FALSE;   // remember it's up
03266                     EditingColourHasChanged( TRUE, FALSE );
03267                 }
03268                 else
03269                     ApplyNoColour(EditingLineColour);//push it down
03270             }
03271             else if (Msg->GadgetID == _R(IDC_EDIT_RENAME))
03272             {
03273                 DoCommand(&ColCmd_Name);
03274             }
03275             // WEBSTER - markn 14/12/96 
03276             else if (Msg->GadgetID == _R(IDC_EDIT_216ONLY))
03277             {
03278                 LimitTo216Only();
03279                 DialogManager::DefaultKeyboardFocus();  // remove the input focus from the button (yuk!)
03280             }
03281             else if (Msg->GadgetID == _R(IDC_EDIT_DROPMENU))
03282             {
03283                 // Show drop-down menu
03284                 // Chuck up a context sensitive menu
03285                 ColEditContextMenu *Bob = new ColEditContextMenu;
03286                 if (Bob != NULL)
03287                     Bob->Show();
03288             }
03289             else if ((Msg->GadgetID == _R(IDC_EDIT_INHERIT1)) ||
03290                      (Msg->GadgetID == _R(IDC_EDIT_INHERIT2)) ||
03291                      (Msg->GadgetID == _R(IDC_EDIT_INHERIT3)) ||
03292                      (Msg->GadgetID == _R(IDC_EDIT_INHERIT4)))
03293             {
03294                 SetColour(FALSE);           // Read the new settings from the window
03295                 SetControls();              // Ensure controls shade/unshade as appropriate
03296             }
03297 // WEBSTER - markn 14/1/97
03298 // Removed click handling on unused buttons
03299             else if (Msg->GadgetID == _R(IDC_EDIT_3D))
03300             {
03301                 // 3D display mode turned on/off. Redraw the picker control to show it
03302                 // in the new mode.
03303                 Use3DDisplay = GetBoolGadgetSelected(_R(IDC_EDIT_3D));
03304                 InvalidateGadget(_R(IDC_EDIT_PICKER));
03305             }
03306             else if (Msg->GadgetID == _R(IDC_EDIT_MAKESTYLE))
03307             {
03308                 MakeNewNColour();
03309             }
03310 // can make named colours in webster #endif // WEBSTER
03311             else if (Msg->GadgetID == _R(IDC_MAKE_LOCAL))
03312             {
03313                 // handles the webster only "Make Local to Frame" button
03314                 OnMakeLocalToFrame();
03315             }
03316 
03317             // And then lob away the input focus again - put it back into the mainframe
03318             LoseKeyboardFocus();
03319             break;
03320 
03321         case DIM_LFT_BN_DOWN:
03322 //      case DIM_RGT_BN_DOWN:
03323             // Remove bubble help whenever the user clicks
03324 PORTNOTE("other", "Disabled BubbleHelp stuff")
03325 #ifndef EXCLUDE_FROM_XARALX
03326             ControlHelper::BubbleHelpDisable();
03327 #endif
03328             if (Msg->GadgetID == _R(IDC_COLOURPICKER))
03329             {
03330                 // This little wheeze is enough to remove hover
03331                 EnableGadget(_R(IDC_COLOURPICKER), FALSE);
03332                 EnableGadget(_R(IDC_COLOURPICKER), TRUE);
03333                 SetBoolGadgetSelected(_R(IDC_COLOURPICKER), FALSE);
03334                 InvalidateGadget(_R(IDC_COLOURPICKER));
03335 
03336                 ColourPickerDragInformation * DragCol = new ColourPickerDragInformation();
03337                 DragManagerOp::StartDrag(DragCol, GetReadWriteWindowID());
03338                 break;
03339             }
03340 
03341             // Drag methods all cope with shaded condition (EditingColour == NULL)
03342             if (Msg->DlgMsgParam)
03343             {
03344                 if (Msg->GadgetID == _R(IDC_EDIT_PICKER))
03345                 {
03346                     StartDrag((ReDrawInfoType*) Msg->DlgMsgParam);
03347                     NoFillButtonDown = FALSE;
03348                 }
03349 #if FALSE
03350 /*
03351                 else if (Msg->GadgetID == _R(IDC_EDIT_PATCH) && EditingColour != NULL && ParentList != NULL)
03352                 {
03353                     ReDrawInfoType* Info = (ReDrawInfoType *) Msg->DlgMsgParam;
03354                     INT32 PatchHeight = Info->dy / 3;
03355 
03356                     IndexedColour *TheColour = ResultColour;    // Middle patch/default
03357                     if (Info->pMousePos->y < PatchHeight)
03358                     {
03359                         // Bottom patch - parent colour
03360                         if (EditingColour->FindLinkedParent() != NULL)
03361                             TheColour = EditingColour->FindLinkedParent();
03362                     }
03363                     else if (Info->pMousePos->y > PatchHeight * 2)
03364                     {
03365                         // Top patch - OriginalColour
03366                         TheColour = new IndexedColour(OriginalColour);
03367                         if (TheColour != NULL)
03368                         {
03369                             TheColour->SetUnnamed();
03370 
03371                             // Ensure we don't get a memory leak
03372                             ParentList->AddItem(TheColour);
03373                         }
03374                     }
03375 
03376                     if (TheColour != NULL)
03377                     {
03378                         ColourDragInformation *DragCol;
03379                         DragCol = new ColourDragInformation(TheColour, FALSE, (Document *)ParentList->GetParentDocument());
03380                         DragManagerOp::StartDrag(DragCol, GetReadWriteWindowID());
03381                     }
03382                 }
03383 */
03384 #endif
03385             }
03386             
03387             break;
03388 
03389         case DIM_MOUSE_DRAG:
03390             // Drag methods all cope with shaded condition (EditingColour == NULL)
03391             if (Msg->GadgetID == _R(IDC_EDIT_PICKER) && DragStartArea != CEDRAG_NONE)
03392                 UpdateDrag((ReDrawInfoType*) Msg->DlgMsgParam);
03393             break;
03394 
03395 
03396 /*
03397         case DIM_MOUSE_MOVE:
03398             ColourPicker::UpdateBubbleHelpAndPointer();
03399             break;
03400 */
03401 
03402         case DIM_LFT_BN_UP:
03403             // Drag methods all cope with shaded condition (EditingColour == NULL)
03404             if (Msg->GadgetID == _R(IDC_EDIT_PICKER) && DragStartArea != CEDRAG_NONE)
03405                 EndDrag((ReDrawInfoType*) Msg->DlgMsgParam);
03406             else if (Msg->GadgetID != _R(IDC_EDIT_DROPMENU))    // Don't lose focus if dropping a menu!
03407                 LoseKeyboardFocus();
03408             break;
03409 
03410 
03411         case DIM_RGT_BN_UP:
03412             if (EditingColour != NULL && !AmShaded)
03413             {
03414                 // Chuck up a context sensitive menu
03415                 ColEditContextMenu *Bob = new ColEditContextMenu;
03416                 if (Bob != NULL)
03417                     Bob->Show();
03418             }
03419             break;
03420 
03421     
03422         case DIM_TEXT_CHANGED:                  // Text in a writable icon has changed
03423             if (!ISentTheMessage && EditingColour != NULL)
03424             {
03425                 // If we are editing a colour, and we are not responsible for the
03426                 // change, we update the EditingColour, and possibly force-redraw the
03427                 // current-colour indicator patch, as appropriate to the change
03428 
03429                 if (( Msg->GadgetID == _R(IDC_EDIT_COMPONENT1)) ||
03430                     ( Msg->GadgetID == _R(IDC_EDIT_COMPONENT2)) ||
03431                     ( Msg->GadgetID == _R(IDC_EDIT_COMPONENT3)) ||
03432                     ( Msg->GadgetID == _R(IDC_EDIT_COMPONENT4)) ||
03433                     ( Msg->GadgetID == _R(IDC_EDIT_WEBHEX)))
03434                 {
03435                     // While setting the colour, make sure we don't try to update the
03436                     // field that the user is currently typing into!
03437                     CurrentTypingGadget = Msg->GadgetID;
03438                     SetColour();
03439                     CurrentTypingGadget = 0;
03440 
03441                     // We have to set the transparency button manually here 'cos SetColour
03442                     // does not write the gadgets when we're typing (it would over write 
03443                     // whatever we are typing!)
03444                     if (NoFillButtonDown)   // if it's up already don't bother redrawing
03445                     {
03446                         NoFillButtonDown = FALSE;
03447                         SetBoolGadgetSelected( _R(IDC_EDIT_NOCOLOUR), NoFillButtonDown);
03448                     }
03449 
03450 
03451                     // Set flag to tell the 'lose focus' function to also update the
03452                     // text components once while it's at it - this just tidies up the
03453                     // appearance of the controls as soon as we lose focus.
03454                     TextMayBeWrong = TRUE;
03455                 }
03456                 else if (Msg->GadgetID == _R(IDC_EDIT_TINT))
03457                 {
03458                     INT32 MinValue = (EditingColour->TintIsShade()) ? -100 : 0;
03459                     INT32 NewValue = GetLongGadgetValue(_R(IDC_EDIT_TINT), MinValue, 100);
03460                     if (NewValue < MinValue) NewValue = MinValue;
03461                     if (NewValue > 100)      NewValue = 100;
03462 
03463                     CurrentTypingGadget = _R(IDC_EDIT_TINT);
03464                     SetColour(FALSE);
03465                     CurrentTypingGadget = 0;
03466                 }
03467                 else if (Msg->GadgetID == _R(IDC_EDIT_SHADE))
03468                 {
03469                     INT32 NewValue = GetLongGadgetValue(_R(IDC_EDIT_SHADE), -100, 100);
03470                     if (NewValue < -100) NewValue = -100;
03471                     if (NewValue > 100)  NewValue = 100;
03472 
03473                     CurrentTypingGadget = _R(IDC_EDIT_SHADE);
03474                     SetColour(FALSE);
03475                     CurrentTypingGadget = 0;
03476                 }
03477             }
03478             break;
03479 
03480 //      case DIM_FOCUS_LOST:
03481 //          // This message is sent from the Name Combo box when it loses the input focus.
03482 //          // This occurs when we move to a different field, close the dialogue, press
03483 //          // return, etc. It means any change to the name is only set when the user
03484 //          // finishes editing the text, at which point it is reasonable to ensure the
03485 //          // name is unique
03486 //
03487 //          if (Msg->GadgetID == _R(IDC_EDIT_NAMEMENU))
03488 //              SetColour(FALSE);       // Update the colour
03489 //          break;
03490 
03491 
03492 /*
03493         case DIM_SLIDER_POS_CHANGING:
03494         case DIM_SLIDER_POS_SET:
03495             if (EditingColour != NULL && !ISentTheMessage)
03496             {
03497                 INT32 NewValue = GetLongGadgetValue(_R(IDC_EDIT_TINTSLIDER), 0, 100);
03498                 if (NewValue < 0)    NewValue = 0;
03499                 if (NewValue > 100)  NewValue = 100;
03500                 NewValue = 100-NewValue;
03501 
03502                 INT32 WritableValue = GetLongGadgetValue(_R(IDC_EDIT_TINT), 0, 100);
03503                 if (WritableValue != NewValue)
03504                 {
03505                     BOOL LastSentState = ISentTheMessage;   // Lock: Ignore DIM_TEXT_CHANGED
03506                     ISentTheMessage = TRUE;
03507                     SetLongGadgetValue(_R(IDC_EDIT_TINT), NewValue);
03508                     ISentTheMessage = LastSentState;
03509                     
03510                     SetColour();
03511                 }
03512             }
03513 
03514             // And then lob away the input focus again - put it back into the mainframe
03515             LoseKeyboardFocus();
03516             break;
03517 */
03518 
03519         case DIM_LISTDROPPED:
03520             // A dropdown list is about to drop down- turn on our focus-losing lock
03521             LockLoseFocus = TRUE;
03522             break;
03523 
03524         case DIM_TIMER:
03525             if(Msg->DlgMsgParam == COLED_TIMER_ID)
03526                     //
03527             //UpdateOnNextIdle = TRUE;
03528         
03529             TimedProcessing();
03530             //UpdateColourEditor ();
03531         
03532             break;
03533 
03534         
03535         case DIM_SELECTION_CHANGED:                 // Combo-box selection
03536         case DIM_SELECTION_CHANGED_COMMIT:          // Combo-box selection
03537             if (ISentTheMessage)
03538                 break;
03539 
03540             if ((Msg->GadgetID == _R(IDC_EDIT_NAMEMENU)) ||
03541                 (Msg->GadgetID == _R(IDC_EDIT_COLMODEL)) ||
03542                 (Msg->GadgetID == _R(IDC_EDIT_COLTYPE)) ||
03543                 (Msg->GadgetID == _R(IDC_EDIT_PARENTCOL)))
03544             {
03545                 // A dropdown list has been closed up again - turn off our focus-losing lock
03546                 LockLoseFocus = FALSE;
03547             }
03548 
03549 // WEBSTER - markn 14/1/97
03550 // Commented out the combo box handling
03551 //#ifndef WEBSTER
03552             // Handle selections in the colour name combobox. This will switch to
03553             // editing the chosen colour
03554             if (Msg->GadgetID == _R(IDC_EDIT_NAMEMENU) && ParentList != NULL)
03555             {
03556                 WORD SelIndex;
03557                 GetValueIndex(_R(IDC_EDIT_NAMEMENU), &SelIndex);
03558 
03559                 if (NameDropDown != NULL)
03560                 {
03561                     IndexedColour *Selected = NameDropDown->DecodeSelection((INT32)SelIndex);
03562 
03563                     if (Selected == NULL)
03564                     {
03565                         if (SelIndex < 2)           // Have chosen a valid special item
03566                         {
03567                             // Edit fill colour or line colour
03568                             FindUsefulColourToEdit((SelIndex == 1));
03569                         }
03570                         else
03571                         {
03572                             // Must have selected the separator line. Re-jig the list to make
03573                             // sure the selection is shown correctly
03574                             State.ParentListOK = FALSE;
03575                             SetColourNameList();
03576                         }
03577                     }
03578                     else
03579                     {
03580                         // Have selected an IndexedColour
03581                         if (!Selected->IsDeleted() && Selected->IsNamed())  // Safety check
03582                             EditThisColour(ParentList, Selected);
03583                     }
03584                 }
03585 
03586                 // And then lob away the input focus again - put it back into the mainframe
03587                 LoseKeyboardFocus();
03588                 break;
03589             }
03590 //#endif
03591             if (EditingColour == NULL)
03592                 break;
03593 
03594             if (Msg->GadgetID == _R(IDC_EDIT_COLMODEL))
03595             {
03596                 // A colour model has been selected. If it is different from the
03597                 // current model, we convert the colour into the new model, and set
03598                 // up the window to edit the colour in this new model
03599 
03600                 WORD Index;
03601                 GetValueIndex(_R(IDC_EDIT_COLMODEL), &Index);
03602 
03603                 if (Index < MAX_COLOURMODELS)
03604                 {
03605                     ColourContextArray ColContexts;
03606                     ColourContext::GetGlobalDefaults(&ColContexts);
03607 
03608                     INT32 NewModelNum;
03609 
03610                     for (NewModelNum = 0; NewModelNum < MAX_COLOURMODELS; NewModelNum++)
03611                     {
03612                         if (ColContexts.Context[NewModelNum] != NULL)
03613                         {
03614                             if ((Index--) <= 0)
03615                                 break;
03616                         }
03617                     }
03618 
03619                     INT32 OldModelNum = (INT32) DisplayModel;
03620                     if (NewModelNum < MAX_COLOURMODELS && NewModelNum != OldModelNum)
03621                     {
03622                         DefaultDisplayModel = DisplayModel = (ColourModel) NewModelNum;     // Switch display to the new model
03623                         
03624                         if (EditingColour->IsNamed())
03625                             DefaultDisplayModelN = NewModelNum;         // And remember preference
03626 // But do not overwrite the preference for local colours - this must be set in the options dlg
03627 //                      else
03628 //                          DefaultDisplayModel = NewModelNum;          // And remember preference
03629 
03630                         // And set up the controls as appropriate. If we did not make the
03631                         // change, we still need to ensure the colour model setting is
03632                         // returned to displaying the current model name.
03633                         // We also invalidate the colour picker to redraw it in the new display model
03634                         InvalidateAndSetControls();
03635                     }
03636                 }
03637             }
03638             else if (Msg->GadgetID == _R(IDC_EDIT_COLTYPE))
03639             {
03640                 // A colour model as been selected. If it is different from the
03641                 // current model, we convert the colour into the new model, and set
03642                 // up the window to edit the colour in this new model
03643 
03644                 WORD Index;
03645                 GetValueIndex(_R(IDC_EDIT_COLTYPE), &Index);
03646 
03647 #ifdef WEBSTER 
03648                 // "spot colour" option is not present in Webster - adjust the index appropriately
03649                 // Index now 0-normal, 1-tint, 2-shade, 3-linked
03650                 if (Index > 0)
03651                     Index++;
03652                 // Index now 0-normal, 2-tint, 3-shade, 4-linked
03653 #endif // WEBSTER
03654 
03655                 IndexedColour *LastParent = EditingColour->FindLastLinkedParent();
03656 
03657                 // Check if any safe parent colours are available
03658                 LastParent = FindSafeParent(LastParent, (Index == 2));
03659 
03660 
03661                 // Correct index to allow for Shade colour entry (we handle tint/shade in the same 'case')
03662                 BOOL IsShadeColour = (Index == 3) ? TRUE : FALSE;
03663                 if (Index >= 3)
03664                     Index--;
03665                 // Index now 0-normal, 1-spot, 2-tint, 2-shade, 3-linked
03666 
03667 
03668                 // If it's tint/shade(2) or linked(3) and there's no parent, scream blue murder
03669                 if (LastParent == NULL && (Index == 2 || Index == 3))
03670                 {
03671                     // No suitable parents are available! Disallow change to tint/linked
03672                     InformMessage(_R(IDS_EDIT_NOPARENT), _R(IDS_OK));
03673                     SetControls();      // Revert the gadget to the previous type
03674                     break;
03675                 }
03676 
03677                 // Get the colour definition so that we can make a sensible attempt
03678                 // at converting it into the desired colour type without losing its appearance
03679                 ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
03680                 ColourHSVT ParentDef;
03681                 ColourHSVT ColourDef;
03682                 cc->ConvertColour((LastParent == NULL) ? EditingColour : LastParent, (ColourGeneric *)&ParentDef);
03683                 cc->ConvertColour(EditingColour, (ColourGeneric *)&ColourDef);
03684 
03685                 // we need to hide/show camelots custom colour picker control depending upon what we get here ....
03686 
03687                 if (Index != 0)     // != Normal colour
03688                 {
03689                     needColPickHidden = TRUE;
03690                 }
03691                 else
03692                 {
03693                     needColPickHidden = FALSE;
03694                 }
03695 
03696                 HideOrShowColourPicker();
03697 
03698                 BOOL Changed = FALSE;
03699 
03700                 switch (Index)
03701                 {
03702                     case 1:     // Spot
03703                         Changed = MakeColourASpot();
03704 
03705                         if (!Changed)
03706                         {
03707                             // The colour hasn't changed - make sure that the list does not show
03708                             // "Spot colour" when it's not allowed
03709                             State.ColType = (IndexedColourType) 99; // Invalid! Make sure it updates
03710                             SetControls();
03711                         }
03712                         break;
03713 
03714                     case 2:     // Tint (or Shade)
03715                         // Determine if this will change the colour - attempts to change
03716                         // a tint to a tint or a shade to a shade must be ignored.
03717 
03718                         if (EditingColour->GetType() != COLOURTYPE_TINT)
03719                             Changed = TRUE;         // It was not a tint or a shade, so we must change it
03720                         else
03721                         {
03722                             if (IsShadeColour && !EditingColour->TintIsShade())
03723                                 Changed = TRUE;     // We're changing a Tint into a Shade
03724 
03725                             if (!IsShadeColour && EditingColour->TintIsShade())
03726                                 Changed = TRUE;     // We're chnaging a Shade into a Tint
03727                         }
03728 
03729                         if (Changed)        // If the type needs to be changed, do it
03730                         {
03731                             // Not already a tint/shade, so make it so
03732                             EditingColour->SetLinkedParent(LastParent, COLOURTYPE_TINT);
03733 
03734                             if (IsShadeColour)
03735                             {
03736                                 // Not already the right kind (tint/shade) of tint, so make it so
03737                                 EditingColour->SetTintOrShade(IsShadeColour);
03738                                 Changed = TRUE;
03739 
03740                                 FIXED24 NewX(0.0);
03741                                 FIXED24 NewY(0.0);
03742 
03743                                 double ParentVal = ParentDef.Saturation.MakeDouble();
03744                                 double ColourVal = ColourDef.Saturation.MakeDouble();
03745 
03746                                 if (ParentVal > ColourVal)
03747                                 {
03748                                     if (ParentVal > 0.0)
03749                                         NewX = -((ParentVal - ColourVal) / ParentVal);
03750                                 }
03751                                 else
03752                                 {
03753                                     if (ParentVal < 1.0)
03754                                         NewX = (ColourVal - ParentVal) / (1.0 - ParentVal);
03755                                 }
03756 
03757                                 // Work out Value scaling factor
03758                                 ParentVal = ParentDef.Value.MakeDouble();
03759                                 ColourVal = ColourDef.Value.MakeDouble();
03760                                 if (ParentVal > ColourVal)
03761                                 {
03762                                     if (ParentVal > 0.0)
03763                                         NewY = -((ParentVal - ColourVal) / ParentVal);
03764                                 }
03765                                 else
03766                                 {
03767                                     if (ParentVal < 1.0)
03768                                         NewY = (ColourVal - ParentVal) / (1.0 - ParentVal);
03769                                 }
03770 
03771                                 // And make the colour a shade (a special type of tint)
03772                                 EditingColour->SetShadeValues(NewX, NewY);
03773                             }
03774                             else
03775                             {
03776                                 double TintValue = 1.0;
03777 
03778                                 if (ParentDef.Saturation.MakeDouble() != 0.0)
03779                                     TintValue = ColourDef.Saturation.MakeDouble() / ParentDef.Saturation.MakeDouble();
03780 
03781                                 EditingColour->SetTintValue(FIXED24(TintValue));
03782                             }
03783                         }
03784                         break;
03785 
03786                     case 3:     // Linked
03787                         if (EditingColour->GetType() != COLOURTYPE_LINKED)
03788                         {
03789                             EditingColour->SetLinkedParent(LastParent, COLOURTYPE_LINKED);
03790                             EditingColour->SetInheritsComponent(1, TRUE);
03791                             EditingColour->SetInheritsComponent(2, TRUE);
03792                             EditingColour->SetInheritsComponent(3, TRUE);
03793                             EditingColour->SetInheritsComponent(4, TRUE);
03794                             Changed = TRUE;
03795                         }
03796                         break;
03797 
03798                     default:    // Normal
03799                         if (EditingColour->GetType() != COLOURTYPE_NORMAL)
03800                         {
03801                             EditingColour->SetLinkedParent(LastParent, COLOURTYPE_NORMAL);
03802                             Changed = TRUE;
03803                         }
03804                         break;
03805                 }
03806 
03807                 if (Changed)
03808                     EditingColourHasChanged();  // Inform world and reset/redraw our window
03809             }
03810             else if (Msg->GadgetID == _R(IDC_EDIT_PARENTCOL))
03811             {
03812                 WORD Index;
03813                 GetValueIndex(_R(IDC_EDIT_PARENTCOL), &Index);
03814 
03815                 // If the old parent is now 'not in use' then we'd better broadcast a message
03816                 // to ensure that the colour gallery redraws if necessary. Remember the old
03817                 // parent for later on...
03818                 IndexedColour *OldParent = EditingColour->FindLinkedParent();
03819 
03820                 // Find the new parent colour
03821                 IndexedColour *NewParent = DecodeParentColourListSelection((INT32)Index);
03822 
03823                 // And broadcast for the new parent, if it is now about to become in-use!
03824                 if (NewParent != NULL && !NewParent->HasLinkedChildren())
03825                     ColourManager::ColourHasChangedInvisible((Document *)ParentList->GetParentDocument(), ParentList, NewParent);
03826 
03827                 // Finally, set the new parent of this colour, and inform the world and fix up our window
03828                 EditingColour->SetLinkedParent(NewParent, EditingColour->GetType());
03829                 EditingColourHasChanged();
03830 
03831                 // Now do the broadcast for the old parent (we waited until after SetLinkedParent so we
03832                 // only bother with the broadcast if this has removed the *last* child of that parent)
03833                 if (OldParent != NULL && !OldParent->HasLinkedChildren())
03834                     ColourManager::ColourHasChangedInvisible((Document *)ParentList->GetParentDocument(), ParentList, OldParent);
03835             }
03836 
03837             // And then lob away the input focus again - put it back into the mainframe
03838             LoseKeyboardFocus();
03839 
03840             break;
03841 
03842         default:
03843             break;
03844     }
03845 
03846     return(DialogOp::Message(Message));
03847 }
03848 
03849 
03850 
03851 /********************************************************************************************
03852 
03853 >   BOOL ColourEditDlg::MakeNewNColour(void)
03854 
03855     Author:     Martin_Bell (Xara Group Ltd) <camelotdev@xara.com>
03856     Created:    11/7/97
03857 
03858     Returns:    TRUE if EditingColour has changed
03859 
03860     Purpose:    Moves a lump of code out of the switch statement in the message handler, so
03861                 it can be executed by the button in Camelot and the menu item in Webster
03862 
03863                 Makes a new named colour or shade.
03864 
03865     See also:   ColourEditDlg::MakeColourASpot for stuff about reentrancy
03866 
03867 ********************************************************************************************/
03868 
03869 BOOL ColourEditDlg::MakeNewNColour(void)
03870 {
03871     // We might be about to show an InformError dialogue. This causes the dropdown list to
03872     // close, and that in turn causes a re-entrant call to this message handler,
03873     // the net result being that we create the new colour twice, once before
03874     // the user has even decided which button to press!!! AAAAARARRRRGGH!
03875     // Nasty sounding buglet there. But let's fix the symptom...
03876     static BOOL GoneReentrant = FALSE;
03877 
03878     if (GoneReentrant)              // Eek! Reentrancy! Oh, no you don't, matey!
03879         return(FALSE);
03880 
03881     // Create a colour (style or local) from the current EditingColour
03882     if (EditingColour != NULL && ParentList != NULL)// && !EditingColour->IsNamed())
03883     {
03884         // Make sure the new colour has a suitable parent colour
03885         if (EditingColour->FindLastLinkedParent() == NULL ||
03886             (EditingColour->GetType() != COLOURTYPE_TINT && EditingColour->GetType() != COLOURTYPE_LINKED))
03887         {
03888             // Make sure we don't try to make an unnamed/deleted colour our parent!
03889             IndexedColour *NewParent = ResultColour;
03890 
03891             if (NewParent != NULL && !NewParent->IsNamed())
03892                 NewParent = NewParent->FindLastLinkedParent();
03893 
03894             // Ensure the parent is legal
03895             if (NewParent != NULL && (!NewParent->IsNamed() || NewParent->IsDeleted()))
03896                 NewParent = NULL;
03897 
03898             // And set a legal parent, or NULL if we didn't find one
03899             EditingColour->SetLinkedParent(NewParent, EditingColour->GetType());
03900         }
03901 
03902         // EditingColour will now be put into use as an undo record, so we must get
03903         // a new one for our own use... We do this first in case re-entrant calls (to
03904         // Message !) occur which might make us delete EditingColour or something. We
03905         // must handle the other reentrancy problem of closing the menu if an error
03906         // dialog pops up as well by setting GoneReentrant.
03907         IndexedColour *OldResultColour = ResultColour;
03908         IndexedColour *NewColour = new IndexedColour(*EditingColour);
03909         if (NewColour == NULL)
03910         {
03911             GoneReentrant = TRUE;
03912             InformError();
03913             GoneReentrant = FALSE;
03914             return(FALSE);
03915         }
03916 
03917         // Ask the user for new-colour settings, and allow them to cancel the
03918         // make-style if they like
03919         if (!NewColourDlg::InvokeDialog(ParentList, NewColour))
03920         {
03921             // They've cancelled the operation. Go back to editing what they were
03922             // editing before.
03923             EditThisColour(ParentList, OldResultColour);
03924             return(FALSE);
03925         }
03926 
03927         if (NewColour->IsNamed())
03928         {
03929             // Add it to the colour list, with undo
03930             ParentList->AddItem(NewColour);
03931 
03932             IndexedColour *NewCols[2];
03933             NewCols[0] = NewColour;
03934             NewCols[1] = NULL;
03935 
03936             ColourManager::UnHideColours(ParentList, NewCols);
03937         }
03938         else
03939         {
03940             // This should now never happen. However, if it does, we might
03941             // as well add it to the unnamed colours so we don't memory leak it.
03942             ERROR3("'New named colour' dialogue returned an UNNAMED colour");
03943 
03944             // Just add it to the colour list
03945             ParentList->GetUnnamedColours()->AddTail(NewColour);
03946             FirstEdit = FALSE;
03947         }
03948 
03949         // Force the new colour into the currently displayed colour model (wysiwyg)
03950 //      ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
03951         ColourContext *cc = NULL;
03952         BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
03953         ERROR3IF(cc == NULL, "Necessary document default colour context not defined?!");
03954         ColourPicker::ForceColourModel(NewColour, cc);
03955 
03956         // Delete the colour context if necessary
03957         if (bDeleteCC)
03958             ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
03959 
03960         // Apply it to the selection
03961         ApplyColourNow(NewColour);
03962 
03963         DisplayModel = NewColour->GetColourModel();
03964         EditThisColour(ParentList, NewColour);
03965     }
03966 
03967     GoneReentrant = FALSE;
03968 
03969     return TRUE;
03970 }
03971 
03972 
03973 /********************************************************************************************
03974 
03975 >   BOOL ColourEditDlg::MakeColourASpot(void)
03976 
03977     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03978     Created:    4/9/96
03979 
03980     Returns:    TRUE if EditingColour has changed
03981 
03982     Purpose:    Moves a lump of code out of the switch statement in the message handler
03983 
03984                 Simply changes this colour's colour type to be COLOURTYPE_SPOT.
03985                 However, there is a complication in that local colours can't be spots,
03986                 so we prompt the user to see if they really want a spot, in which case 
03987                 we have to convert their colour into a named colour before setting
03988                 the type to spot. They have the chance to cancel and act as if nothing
03989                 happened.
03990 
03991 ********************************************************************************************/
03992 
03993 BOOL ColourEditDlg::MakeColourASpot(void)
03994 {
03995     // We might be about to show an InformError dialogue. This causes the dropdown list to
03996     // close, and that in turn causes a re-entrant call to this message handler,
03997     // the net result being that we create the new colour twice, once before
03998     // the user has even decided which button to press!!! AAAAARARRRRGGH!
03999     // Nasty sounding buglet there. But let's fix the symptom...
04000     static BOOL GoneReentrant = FALSE;
04001 
04002     if (GoneReentrant)              // Eek! Reentrancy! Oh, no you don't, matey!
04003         return(FALSE);
04004 
04005     if (IndexedColour::AreSpotsForcedToProcess())
04006     {
04007         // Hey, you can't create spots now - they're all process colours!
04008         GoneReentrant = TRUE;
04009         InformError(_R(IDE_SPOTSAREPROCESS), _R(IDS_OK));
04010         GoneReentrant = FALSE;
04011         return(FALSE);
04012     }
04013 
04014     if (EditingColour == NULL || ParentList == NULL || ResultColour == NULL)
04015         return(FALSE);
04016 
04017     BOOL Changed = FALSE;
04018 
04019     if (!ResultColour->IsNamed())   // Unnamed colour - must convert to a named colour
04020     {
04021         GoneReentrant = TRUE;
04022         LoseKeyboardFocus();
04023 
04024         // This is an unnamed (local) colour, so it can't be a spot colour.
04025         // Ask the user if they want to cancel or convert the colour to be a named spot
04026         if (InformError(_R(IDE_LOCALCANTBESPOT), _R(IDS_MAKENAMEDSPOT), _R(IDS_CANCEL)) == 1)
04027         {
04028             // Rightoh, we should be safe from the reentrancy demon now
04029             GoneReentrant = FALSE;
04030 
04031             // Create a colour (style or local) from the current EditingColour
04032             // Make sure the new colour has a suitable parent hint colour
04033             // Make sure we don't try to make an unnamed/deleted colour our parent!
04034             IndexedColour *NewParent = ResultColour;
04035             if (NewParent != NULL && !NewParent->IsNamed())
04036                 NewParent = NewParent->FindLastLinkedParent();
04037 
04038             // Ensure the parent is legal
04039             if (NewParent != NULL && (!NewParent->IsNamed() || NewParent->IsDeleted()))
04040                 NewParent = NULL;
04041 
04042             // EditingColour will now be put into use as an undo record, so we must get
04043             // a new one for our own use... We do this first in case re-entrant calls
04044             // occur which might make us delete EditingColour or something.
04045             IndexedColour *OldResultColour = ResultColour;
04046             IndexedColour *NewColour = new IndexedColour(*EditingColour);
04047             if (NewColour == NULL)
04048             {
04049                 InformError();
04050                 return(FALSE);
04051             }
04052 
04053             // And set a legal parent, or NULL if we didn't find one
04054             NewColour->SetLinkedParent(NewParent, COLOURTYPE_SPOT);
04055 
04056             // Ask the user for new-colour settings, and allow them to cancel the
04057             // make-style if they like
04058             if (!NewColourDlg::InvokeDialog(ParentList, NewColour))
04059             {
04060                 // They've cancelled the operation. Go back to editing what they were
04061                 // editing before.
04062                 EditThisColour(ParentList, OldResultColour);
04063                 return(FALSE);
04064             }
04065 
04066             if (NewColour->IsNamed())
04067             {
04068                 // Add it to the colour list, with undo
04069                 ParentList->AddItem(NewColour);
04070 
04071                 IndexedColour *NewCols[2];
04072                 NewCols[0] = NewColour;
04073                 NewCols[1] = NULL;
04074 
04075                 ColourManager::UnHideColours(ParentList, NewCols);
04076             }
04077             else
04078             {
04079                 // This should now never happen. However, if it does, we might
04080                 // as well add it to the unnamed colours so we don't memory leak it.
04081                 ERROR3("'New named colour' dialogue returned an UNNAMED colour");
04082 
04083                 // Just add it to the colour list
04084                 ParentList->GetUnnamedColours()->AddTail(NewColour);
04085                 FirstEdit = FALSE;
04086             }
04087 
04088             // Apply it to the selection
04089             ApplyColourNow(NewColour);
04090             EditThisColour(ParentList, NewColour);
04091 
04092             // And make sure we know the colour changed in some way
04093             Changed = TRUE;
04094         }
04095         // else
04096         //     user cancelled, so just drop through to return FALSE
04097     }
04098     else
04099     {
04100         // It's a named colour, so we can just make it a spot with no fuss
04101         IndexedColour *LastParent = EditingColour->FindLastLinkedParent();
04102 
04103         // Check if any safe parent colours are available
04104         LastParent = FindSafeParent(LastParent, FALSE);
04105 
04106         if (EditingColour->GetType() != COLOURTYPE_SPOT)
04107         {
04108             EditingColour->SetLinkedParent(LastParent, COLOURTYPE_SPOT);
04109             Changed = TRUE;
04110         }
04111     }
04112 
04113     GoneReentrant = FALSE;
04114 
04115     return(Changed);
04116 }
04117 
04118 
04119 
04120 /********************************************************************************************
04121 
04122 >   void ColourEditDlg::RenderCross(RenderRegion *pRender, DocRect *CrossRect,
04123                                     INT32 PixelSize, BOOL Shaded = FALSE)
04124 
04125     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04126     Created:    15/11/94
04127 
04128     Inputs:     pRender - The RenderRegion to render the marker cross into
04129                 CrossRect - The rectangle (in millipoints, within the RenderRegion) in which
04130                 to draw the cross. This should be a square, CROSSRADIUS*2 millipoints wide/high.
04131                 PixelSize - The size of a device pixel, in millipoints
04132                 Shaded - TRUE if the cross should be drawn 'shaded' (not draggable)
04133 
04134     Purpose:    Renders a colour picker marker cross (a 'plus' shape)
04135 
04136 ********************************************************************************************/
04137 
04138 void ColourEditDlg::RenderCross(RenderRegion *pRender, DocRect *CrossRect,
04139                                 INT32 PixelSize, BOOL Shaded)
04140 {
04141     pRender->SaveContext();     // Save the current rendering context
04142 
04143     DocColour Trans(COLOUR_TRANS);
04144     DocColour Black(COLOUR_BLACK);
04145     DocColour White(COLOUR_WHITE);
04146 
04147     if (Shaded)     // Cross becomes more faint if it can't be dragged
04148     {
04149 //      Black = DocColour(80L, 80L, 80L);
04150 //      White = DocColour(176L, 176L, 176L);
04151 
04152         // Now it just gets a constraint circle around it
04153         DocCoord Center((CrossRect->lo.x + CrossRect->hi.x) / 2, (CrossRect->lo.y + CrossRect->hi.y) / 2);
04154         RenderConstraint(pRender, Center, Center);
04155     }
04156 
04157     pRender->SetLineWidth(0);
04158     pRender->SetLineColour(White);
04159 
04160     // Render a crosshair shape
04161     pRender->SetFillColour(Black);
04162 
04163     DocRect CrossLine;
04164 
04165     INT32 LineWidth  = CrossRect->Width() / 2;
04166     INT32 LineHeight = CrossRect->Height() / 2;
04167 
04168     CrossLine.lo.y  = CrossRect->lo.y + LineHeight - PixelSize;
04169     CrossLine.hi.y  = CrossRect->lo.y + LineHeight + PixelSize;
04170 
04171     CrossLine.lo.x = CrossRect->lo.x;
04172     CrossLine.hi.x = CrossRect->lo.x + LineWidth/2;
04173     pRender->DrawRect(&CrossLine);
04174 
04175     CrossLine.lo.x = CrossRect->hi.x - LineWidth/2;
04176     CrossLine.hi.x = CrossRect->hi.x;
04177     pRender->DrawRect(&CrossLine);
04178 
04179     CrossLine.lo.x = CrossRect->lo.x + LineWidth - PixelSize;
04180     CrossLine.hi.x = CrossRect->lo.x + LineWidth + PixelSize;
04181 
04182     CrossLine.lo.y = CrossRect->lo.y;
04183     CrossLine.hi.y = CrossRect->lo.y + LineHeight/2;
04184     pRender->DrawRect(&CrossLine);
04185 
04186     CrossLine.lo.y = CrossRect->hi.y - LineHeight/2;
04187     CrossLine.hi.y = CrossRect->hi.y;
04188     pRender->DrawRect(&CrossLine);
04189 
04190     pRender->RestoreContext();      // Restore the previous rendering context
04191 }
04192 
04193 
04194 
04195 /********************************************************************************************
04196 
04197 >   void ColourEditDlg::RenderParentCross(RenderRegion *pRender, DocRect *CrossRect,
04198                                     INT32 PixelSize)
04199     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04200     Created:    14/10/95
04201 
04202     Inputs:     pRender - The RenderRegion to render the marker cross into
04203                 CrossRect - The rectangle (in millipoints, within the RenderRegion) in which
04204                 to draw the cross. This should be a square, CROSSRADIUS*2 millipoints wide/high.
04205                 PixelSize - The size of a device pixel, in millipoints
04206 
04207     Purpose:    Renders a colour picker marker cross (an 'x' shape) to indicate the position
04208                 of the PARENT colour on the colour's picker. Used for shades and maybe for
04209                 linked colours if they ever become relative.
04210 
04211 ********************************************************************************************/
04212 
04213 void ColourEditDlg::RenderParentCross(RenderRegion *pRender, DocRect *CrossRect,
04214                                 INT32 PixelSize)
04215 {
04216     pRender->SaveContext();     // Save the current rendering context
04217 
04218     pRender->SetLineWidth(0);
04219     pRender->SetLineColour(COLOUR_WHITE);
04220     pRender->SetFillColour(COLOUR_TRANS);
04221 
04222     pRender->DrawLine(CrossRect->lo, CrossRect->hi);
04223 
04224     pRender->DrawLine(DocCoord(CrossRect->lo.x, CrossRect->hi.y),
04225                         DocCoord(CrossRect->hi.x, CrossRect->lo.y));
04226 
04227     pRender->RestoreContext();      // Restore the previous rendering context
04228 }
04229 
04230 
04231 
04232 /********************************************************************************************
04233 
04234 >   void ColourEditDlg::RenderConstraint(RenderRegion *pRender, DocCoord End1, DocCoord End2)
04235     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04236     Created:    30/9/95
04237 
04238     Inputs:     pRender - The RenderRegion to render the constraint into
04239                 End1 - The point at one end of the constraint bubble
04240                 End2 - The point at the other end of the constraint bubble
04241 
04242     Purpose:    Renders a colour picker constraint bubble. This is a "sausage" in a
04243                 straight line around two endpoints, used to mark drag constraints
04244                 on screen. 
04245 
04246     Notes:      if (End1 == End2) a circle will be drawn at that point
04247 
04248                 This may draw the semicircular caps the wrong way around. It works
04249                 for the cases I've needed so far, so I couldn't be bothered tidying it up.
04250 
04251 ********************************************************************************************/
04252 
04253 void ColourEditDlg::RenderConstraint(RenderRegion *pRender, DocCoord End1, DocCoord End2)
04254 {
04255     if (End1 == End2)
04256     {
04257         const INT32 CircleSize = CROSSRADIUS + 1000;
04258         const INT32 CPDist = (const INT32) ( ((double)CircleSize) * 0.552 );
04259 
04260         // The constraint bubble is a circle. Special-case the redraw
04261         pRender->SetLineColour(COLOUR_WHITE);
04262 
04263         Path Bubble;
04264         Bubble.Initialise(12, 12);
04265         Bubble.FindStartOfPath();
04266 
04267         Bubble.InsertMoveTo(DocCoord(End1.x+CircleSize, End1.y));
04268         Bubble.InsertCurveTo(DocCoord(End1.x+CircleSize, End1.y+CPDist),
04269                                 DocCoord(End1.x+CPDist, End1.y+CircleSize),
04270                                 DocCoord(End1.x, End1.y+CircleSize));
04271         Bubble.InsertCurveTo(DocCoord(End1.x-CPDist, End1.y+CircleSize),
04272                                 DocCoord(End1.x-CircleSize, End1.y+CPDist),
04273                                 DocCoord(End1.x-CircleSize, End1.y));
04274         Bubble.InsertCurveTo(DocCoord(End1.x-CircleSize, End1.y-CPDist),
04275                                 DocCoord(End1.x-CPDist, End1.y-CircleSize),
04276                                 DocCoord(End1.x, End1.y-CircleSize));
04277         Bubble.InsertCurveTo(DocCoord(End1.x+CPDist, End1.y-CircleSize),
04278                                 DocCoord(End1.x+CircleSize, End1.y-CPDist),
04279                                 DocCoord(End1.x+CircleSize, End1.y));
04280 
04281         Bubble.IsFilled = FALSE;
04282         pRender->DrawPath(&Bubble);     // Render the value square
04283     }
04284     else
04285     {
04286         const INT32 CircleSize = (CROSSRADIUS + 1000) / 2;
04287 //      const INT32 CPDist = (const INT32) ( ((double)CircleSize) * 0.552 );
04288 
04289         DocCoord Dist = End1 - End2;
04290         double Angle = 0.0;
04291 
04292         if (Dist.x == 0)
04293         {
04294             if (Dist.y < 0)
04295                 Angle = PI;
04296         }
04297         else
04298             Angle = atan2((double)Dist.y, (double)Dist.x) - (PI/2);
04299 
04300         Dist.x = (INT32) ((double)CircleSize * cos(Angle));
04301         Dist.y = (INT32) ((double)CircleSize * sin(Angle));
04302 
04303         DocCoord ArcStart1(End2 + Dist);
04304         DocCoord ArcEnd1(End2 - Dist);
04305 
04306         DocCoord ArcStart2(End1 - Dist);
04307         DocCoord ArcEnd2(End1 + Dist);
04308 
04309 
04310         pRender->SetLineColour(COLOUR_WHITE);
04311 
04312         Path Bubble;
04313         Bubble.Initialise(12, 12);
04314         Bubble.FindStartOfPath();
04315 
04316         DocCoord RevDist(Dist.y, Dist.x);
04317 
04318         // BODGE to fix vertical case - only horizontal/vertical cases are guaranteed to work
04319         if (End1.y != End2.y)
04320             RevDist = DocCoord(-Dist.y, -Dist.x);
04321 
04322         Bubble.InsertMoveTo(ArcStart1);
04323         Bubble.InsertCurveTo(ArcStart1 + RevDist, ArcEnd1 + RevDist, ArcEnd1);
04324 
04325         Bubble.InsertLineTo(ArcStart2);
04326         Bubble.InsertCurveTo(ArcStart2 - RevDist, ArcEnd2 - RevDist, ArcEnd2);
04327 
04328         Bubble.InsertLineTo(ArcStart1); // Close the path
04329 
04330         Bubble.IsFilled = FALSE;
04331         pRender->DrawPath(&Bubble);     // Render the value square
04332     }
04333 }
04334 
04335 
04336 
04337 /********************************************************************************************
04338 
04339 >   static void CalculateHSVPickerRects(DocRect *VirtualSize, INT32 PixelSize,
04340                                         DocRect *HueRect, DocRect *ValSatSquare)
04341 
04342     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04343     Created:    17/2/95
04344 
04345     Inputs:     VirtualSize - The rectangle defining the coordinate space to draw into
04346                 
04347                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
04348                 coordinate space; ensures things line up on display pixel boundaries.
04349 
04350     Outputs:    HueRect - The rectangle (a strip along the bottom of VirtualSize) in
04351                 which the Hue slider should be displayed
04352 
04353                 ValSatSquare - The Square (above the hue strip) in which the value vs. Satn.
04354                 square should be displayed.
04355 
04356     Purpose:    Calculates where the important regions are in the square HSV picker
04357 
04358 ********************************************************************************************/
04359 
04360 static void CalculateHSVPickerRects(DocRect *VirtualSize, INT32 PixelSize,
04361                                         DocRect *HueRect, DocRect *ValSatSquare)
04362 {
04363     *HueRect = *VirtualSize;
04364     HueRect->hi.y = HueRect->lo.y + (CROSSRADIUS+PixelSize)*2;
04365     GridLockRect(HueRect, PixelSize);
04366 
04367     *ValSatSquare = *VirtualSize;
04368     ValSatSquare->lo.y = HueRect->hi.y + 4000;  // Above the hue slider, with a gap
04369     ValSatSquare->hi.x -= PATCHSIZE; // center within the area left by the patches
04370 
04371     INT32 SquareSize = ValSatSquare->Height();
04372     if (SquareSize > ValSatSquare->Width())
04373     {
04374         SquareSize = ValSatSquare->Width();
04375     
04376         // Center it vertically
04377         ValSatSquare->lo.y += (ValSatSquare->Height() - SquareSize) / 2;
04378         ValSatSquare->hi.y = ValSatSquare->lo.y + SquareSize;
04379     }
04380     else
04381     {
04382         // Center it horizontally
04383         ValSatSquare->lo.x += (ValSatSquare->Width() - SquareSize) / 2;
04384         ValSatSquare->hi.x = ValSatSquare->lo.x + SquareSize;
04385     }
04386 
04387     GridLockRect(ValSatSquare, PixelSize);
04388 }
04389 
04390 
04391 
04392 /********************************************************************************************
04393 
04394 >   void ColourEditDlg::RenderPickerHSV(RenderRegion *pRender, DocRect *VirtualSize,
04395                             INT32 PixelSize, DialogColourInfo *RedrawColours,
04396                             DocRect *pClipRect)
04397 
04398     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04399     Created:    13/12/94
04400 
04401     Inputs:     pRender - The render region to render the picker in
04402                 
04403                 VirtualSize - The rectangle defining the coordinate space to draw into
04404                 
04405                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
04406                 coordinate space; ensures things line up on display pixel boundaries.
04407                 
04408                 RedrawColours - A pointer to a DialogColourInfo object describing
04409                 OS-friendly drawing colours to be used in redrawing the control.
04410 
04411                 pClipRect - The area to be redrawn, in (0,0)->(dx,dy) dialog millipoint coords
04412 
04413     Purpose:    Redraws a colour picker control for the colour editor dialogue.
04414                 This is used in the given display mode to display the colour information
04415                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
04416 
04417     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
04418 
04419 ********************************************************************************************/
04420 
04421 void ColourEditDlg::RenderPickerHSV(RenderRegion *pRender, DocRect *VirtualSize,
04422                                     INT32 PixelSize, DialogColourInfo *RedrawColours,
04423                                     DocRect *pClipRect)
04424 {
04425     pRender->SaveContext();     // Save the current rendering context
04426 
04427     // Set defaults: Fill paths only, and fill background with window grey
04428     DocColour Trans(COLOUR_TRANS);
04429 
04430     pRender->SetLineWidth(0);
04431     pRender->SetLineColour(Trans);
04432 //  pRender->SetFillColour(RedrawColours->DialogBack());
04433 //  pRender->DrawRect(VirtualSize);
04434 
04435     // First, do a Hue slider (a rainbow grad filled rectangle along the bottom)
04436     DocRect HueRect;
04437     DocRect ValSatSquare;
04438     CalculateHSVPickerRects(VirtualSize, PixelSize, &HueRect, &ValSatSquare);
04439 
04440     // Draw the Saturation vs. Value square
04441     Path SquarePath;
04442     LinearFillAttribute ValueGradFill;
04443     LinearTranspFillAttribute TransFill;
04444 
04445     ColourHSVT ColourDef;
04446     if (EditingColour != NULL)
04447     {
04448         BaseDocument *ScopeDocument = ParentList->GetParentDocument();
04449         ColourContextArray *Contexts = ScopeDocument->GetDefaultColourContexts();
04450         ERROR3IF(Contexts == NULL, "Document default contexts not defined?!");
04451 
04452         ColourContextHSVT *ccHSV = (ColourContextHSVT *)
04453                                         Contexts->Context[COLOURMODEL_HSVT];
04454         ERROR3IF(ccHSV == NULL, "Document default context for HSV not defined?!");
04455         ccHSV->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
04456     }
04457     else
04458     {
04459         // No colour - default to white
04460         ColourDef.Hue = 0;
04461         ColourDef.Saturation = ColourDef.Value = FIXED24(1.0);
04462     }
04463 
04464     if (pClipRect->IsIntersectedWith(ValSatSquare))     // If we need to redraw this bit...
04465     {       
04466         // Copy the colour def, and force it's Value & Sat components to 1.0
04467         ColourHSVT TempColourDef;
04468         TempColourDef.Hue   = ColourDef.Hue;
04469         TempColourDef.Value = TempColourDef.Saturation = FIXED24(1.0);
04470 
04471         pRender->SaveContext();
04472         
04473         ValueGradFill.Colour    = DOCCOLOUR_HSVT(&TempColourDef);
04474         ValueGradFill.EndColour = DocColour(255L, 255L, 255L);
04475 
04476         DocCoord ThePoint;
04477         ThePoint = DocCoord(ValSatSquare.lo.x, ValSatSquare.hi.y);
04478         ValueGradFill.SetStartPoint(&ThePoint);
04479         ThePoint = DocCoord(ValSatSquare.hi.x, ValSatSquare.hi.y);
04480         ValueGradFill.SetEndPoint(&ThePoint);
04481         ValueGradFill.SetEndPoint2(NULL);
04482 
04483         pRender->SetFillGeometry(&ValueGradFill, FALSE);            // Set Grad-filled
04484 
04485         SquarePath.Initialise(12, 12);
04486         SquarePath.FindStartOfPath();
04487 
04488         SquarePath.InsertMoveTo(ValSatSquare.lo);
04489         SquarePath.InsertLineTo(DocCoord(ValSatSquare.hi.x, ValSatSquare.lo.y));
04490         SquarePath.InsertLineTo(ValSatSquare.hi);
04491         SquarePath.InsertLineTo(DocCoord(ValSatSquare.lo.x, ValSatSquare.hi.y));
04492         SquarePath.IsFilled = TRUE;
04493 
04494         pRender->DrawPath(&SquarePath);     // Render the value square
04495 
04496         // Render a white linear-grad-transparency square over the top to get the
04497         // effect of the Saturation gradient
04498         DocColour black(0,0,0);
04499         pRender->SetFillColour(black);
04500 
04501         // Set transparency to circular 0% at center, 100% at radius, && plot it
04502         if (bHSVHueAtTop)
04503         {
04504             TransFill.SetStartPoint(&ValSatSquare.hi);
04505             ThePoint = DocCoord(ValSatSquare.hi.x, ValSatSquare.lo.y);
04506             TransFill.SetEndPoint(&ThePoint);
04507             TransFill.SetEndPoint2(NULL);
04508         }
04509         else
04510         {
04511             TransFill.SetStartPoint(&ValSatSquare.lo);
04512             ThePoint = DocCoord(ValSatSquare.lo.x, ValSatSquare.hi.y);
04513             TransFill.SetEndPoint(&ThePoint);
04514             TransFill.SetEndPoint2(NULL);
04515         }
04516         TransFill.Transp        = 255;
04517         TransFill.EndTransp     = 0;
04518         TransFill.TranspType    = TT_StainGlass;        // 'Stained glass' transparency
04519 
04520         pRender->SetTranspFillGeometry(&TransFill, FALSE);
04521 
04522         pRender->DrawPath(&SquarePath);     // Render the saturation square
04523 
04524         pRender->RestoreContext();
04525     }
04526 
04527     // (Declare variables now to stop render region going tits up)
04528     Path HuePath;
04529     FillEffectAltRainbowAttribute AltRainbow;
04530     LinearFillAttribute HueGradFill;
04531 
04532     if (pClipRect->IsIntersectedWith(HueRect))      // If we need to redraw this bit...
04533     {
04534         pRender->SaveContext();
04535 
04536         HueGradFill.Colour      = DocColour(255L, 0L, 0L);      // Red to Red, alt-rainbow
04537         HueGradFill.EndColour   = DocColour(255L, 0L, 0L);
04538 
04539         HueGradFill.SetStartPoint(&HueRect.hi);
04540         DocCoord ThePoint(HueRect.lo.x, HueRect.hi.y);
04541         HueGradFill.SetEndPoint(&ThePoint);
04542         HueGradFill.SetEndPoint2(NULL);
04543 
04544         pRender->SetFillGeometry(&HueGradFill, FALSE);          // Set Grad-filled
04545 
04546         pRender->SetFillEffect(&AltRainbow, FALSE);             // Set alt-rainbow fill
04547 
04548         // Draw the rectangle - done as a path so we can draw with grad-fill
04549         HuePath.Initialise(12, 12);
04550         HuePath.FindStartOfPath();
04551 
04552         HuePath.InsertMoveTo(HueRect.lo);
04553         HuePath.InsertLineTo(DocCoord(HueRect.hi.x, HueRect.lo.y));
04554         HuePath.InsertLineTo(HueRect.hi);
04555         HuePath.InsertLineTo(DocCoord(HueRect.lo.x, HueRect.hi.y));
04556         HuePath.IsFilled = TRUE;
04557 
04558         pRender->DrawPath(&HuePath);        // Render the hue strip
04559 
04560         pRender->RestoreContext();
04561     }
04562 
04563     if (EditingColour != NULL)
04564     {
04565         // Render marker crosses in the appropriate places for the definition
04566         // of the current editing colour - First, the Hue cross
04567         DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
04568 
04569         INT32 TransX = (INT32) ((double) HueRect.Width() * ColourDef.Hue.MakeDouble());
04570 
04571         CrossRect.Translate(HalfGridLock(HueRect.lo.x + TransX, PixelSize),
04572                             HalfGridLock((HueRect.lo.y + HueRect.hi.y) / 2, PixelSize));
04573     
04574         BOOL CrossShaded = (EditingColour->GetType() == COLOURTYPE_TINT) ||
04575                         (EditingColour->GetType() == COLOURTYPE_LINKED &&
04576                          EditingColour->InheritsComponent(1));
04577 
04578         RenderCross(pRender, &CrossRect, PixelSize, CrossShaded);
04579 
04580         // And the Sat/Val cross
04581         CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
04582         TransX = ValSatSquare.hi.x - (INT32)
04583                     ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
04584         INT32 TransY;
04585 if (bHSVHueAtTop)
04586 {
04587         TransY = ValSatSquare.lo.y + (INT32)
04588                     ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
04589 }
04590 else
04591 {
04592         TransY = ValSatSquare.hi.y - (INT32)
04593                     ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
04594 }
04595 
04596         CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
04597 
04598         CrossShaded = (EditingColour->GetType() == COLOURTYPE_TINT) ||
04599                             (EditingColour->GetType() == COLOURTYPE_LINKED &&
04600                              EditingColour->InheritsComponent(2) &&
04601                              EditingColour->InheritsComponent(3));
04602         RenderCross(pRender, &CrossRect, PixelSize, CrossShaded);
04603 
04604         if (!CrossShaded && EditingColour->GetType() == COLOURTYPE_LINKED)
04605         {
04606             if (EditingColour->InheritsComponent(2))
04607             {
04608                 // Saturation is locked, so constrain to Value axis
04609                 RenderConstraint(pRender, DocCoord(TransX, ValSatSquare.hi.y), 
04610                                             DocCoord(TransX, ValSatSquare.lo.y));
04611             }
04612             else if (EditingColour->InheritsComponent(3))
04613             {
04614                 // Value is locked, so constrain to Saturation axis
04615                 RenderConstraint(pRender, DocCoord(ValSatSquare.lo.x, TransY), 
04616                                             DocCoord(ValSatSquare.hi.x, TransY));
04617             }
04618         }
04619     }
04620     return;
04621 
04622 #if FALSE
04623     // Replacement code (developmental) to do a 3-d HSV colour cone display
04624 
04625     // Diameter is the width of the gadget - the value rectangle - a gap
04626     const INT32 MaxDiameter = (VirtualSize->Height() * 100) / 128;
04627     const INT32 MaxRadius = HalfGridLock(MaxDiameter/2, PixelSize);
04628     const INT32 TopMidY = HalfGridLock(VirtualSize->hi.y - MaxRadius, PixelSize);
04629     const INT32 TopMidX = HalfGridLock(VirtualSize->hi.x - MaxRadius, PixelSize);
04630 
04631     // The tip of the cone is 45 degrees down & to the left of the center.
04632     // It occurs just far enough away from the edge of the gadget to accomodate a Z Slider box
04633     const INT32 TipY = VirtualSize->lo.y + ZSLIDERSIZE;
04634     const INT32 TipX = TopMidX - (TopMidY - TipY);
04635 
04636     // Get the colour we want to display as an HSV colour definition
04637     ColourHSVT ColourDef;                   
04638     ColourHSVT TempColourDef;
04639     if (EditingColour != NULL)
04640     {
04641         BaseDocument *ScopeDocument = ParentList->GetParentDocument();
04642         ColourContextArray *Contexts = ScopeDocument->GetDefaultColourContexts();
04643         ERROR3IF(Contexts == NULL, "Document default contexts not defined?!");
04644 
04645         ColourContextHSVT *ccHSV = (ColourContextHSVT *)
04646                                         Contexts->Context[COLOURMODEL_HSVT];
04647         ERROR3IF(ccHSV == NULL, "Document default context for HSV not defined?!");
04648         ccHSV->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
04649 
04650         // --- Draw the value slider rectangle
04651     
04652         // Create a colour from this, but with Value = 1.0
04653         memcpy(&TempColourDef, &ColourDef, sizeof(ColourHSVT));
04654     }
04655     else
04656         TempColourDef.Value = FIXED24(1.0);
04657 
04658     const INT32 Diameter = (const INT32) ((double) MaxDiameter * TempColourDef.Value.MakeDouble());
04659     const INT32 Radius = HalfGridLock(Diameter/2, PixelSize);
04660 
04661     INT32 Offset = (const INT32) ( ((double) (TopMidY - TipY)) * 
04662                                  (1.0 - TempColourDef.Value.MakeDouble()) );
04663 
04664     const INT32 MidY = HalfGridLock(TopMidY - Offset, PixelSize);
04665     const INT32 MidX = HalfGridLock(TopMidX - Offset, PixelSize);
04666 
04667     // --- Draw the HSV colour wheel - two semicircles with conical rainbow
04668     //     fills (this will be overlaid with a transparent-filled white
04669     //     circle to get the final colour wheel image)
04670     //     The entire HSV picker is now drawn on top of a '3d cone shadow' display
04671 
04672     // Draw the cone 'shadow' (A triangle with a circle over one end)
04673     Path ShadowT;
04674     ShadowT.Initialise(12, 12);
04675     ShadowT.InsertMoveTo(DocCoord(TipX, TipY));
04676 
04677     Offset = (INT32) (0.866025403 * (double)MaxRadius);         // MaxRadius * sin(60)
04678     INT32 Offset2 =  (INT32) (0.50 * (double)MaxRadius);            // MaxRadius * cos(60)
04679 
04680     ShadowT.InsertLineTo(DocCoord(TopMidX-Offset, TopMidY+Offset2));
04681     ShadowT.InsertLineTo(DocCoord(TopMidX+Offset2, TopMidY-Offset));
04682     ShadowT.InsertLineTo(DocCoord(TipX, TipY));
04683     ShadowT.IsFilled = TRUE;
04684 
04685     DocColour ShadowTFill(176L, 176L, 176L);
04686     pRender->SetFillColour(ShadowTFill);
04687     pRender->DrawPath(&ShadowT);
04688 
04689     // CPDist = the distance of the bezier control points from the line
04690     // endpoints to give us a circle
04691     const INT32 TopCPDist = (const INT32) ( ((double)MaxRadius) * 0.552 );
04692 
04693     Path ShadowC;
04694     ShadowC.Initialise(12, 12);
04695     ShadowC.FindStartOfPath();
04696     ShadowC.InsertMoveTo(DocCoord(TopMidX+MaxRadius, TopMidY));
04697     ShadowC.InsertCurveTo(DocCoord(TopMidX+MaxRadius, TopMidY+TopCPDist),
04698                             DocCoord(TopMidX+TopCPDist, TopMidY+MaxRadius),
04699                             DocCoord(TopMidX, TopMidY+MaxRadius));
04700     ShadowC.InsertCurveTo(DocCoord(TopMidX-TopCPDist, TopMidY+MaxRadius),
04701                             DocCoord(TopMidX-MaxRadius, TopMidY+TopCPDist),
04702                             DocCoord(TopMidX-MaxRadius, TopMidY));
04703     ShadowC.InsertCurveTo(DocCoord(TopMidX-MaxRadius, TopMidY-TopCPDist),
04704                             DocCoord(TopMidX-TopCPDist, TopMidY-MaxRadius),
04705                             DocCoord(TopMidX, TopMidY-MaxRadius));
04706     ShadowC.InsertCurveTo(DocCoord(TopMidX+TopCPDist, TopMidY-MaxRadius),
04707                             DocCoord(TopMidX+MaxRadius, TopMidY-TopCPDist),
04708                             DocCoord(TopMidX+MaxRadius, TopMidY));
04709     ShadowC.IsFilled = TRUE;
04710 
04711     DocColour ShadowCFill(168L, 168L, 168L);
04712     pRender->SetFillColour(ShadowCFill);
04713     pRender->DrawPath(&ShadowC);
04714     
04715 
04716     // CPDist = the distance of the bezier control points from the line
04717     // endpoints to give us a circle
04718     const INT32 CPDist = (const INT32) ( ((double)Radius) * 0.552 );
04719 
04720     // Generate the fill attribute for the HSV rainbow fill
04721     ConicalFillAttribute Conical;
04722 
04723     Conical.SetStartPoint(DocCoord(MidX, MidY));
04724     Conical.SetEndPoint(DocCoord(MidX-Radius, MidY));
04725     Conical.SetEndPoint2(NULL);
04726 
04727     // Fill: conical, (alt)rainbow, Hue 0.25 to 0.75, Value == SourceColour Value
04728     TempColourDef.Hue = FIXED24(0.25);
04729     TempColourDef.Saturation = FIXED24(1.0);
04730     Conical.Colour = DOCCOLOUR_HSVT(&TempColourDef);
04731 
04732     TempColourDef.Hue = FIXED24(0.75);
04733     Conical.EndColour = DOCCOLOUR_HSVT(&TempColourDef);
04734 
04735     pRender->SetFillGeometry(&Conical, FALSE);
04736 
04737     // Build and draw the Top (CircleT) and Bottom (CircleB) Semicircles
04738     Path CircleT;
04739     CircleT.Initialise(12, 12);
04740     CircleT.FindStartOfPath();
04741     CircleT.InsertMoveTo(DocCoord(MidX+Radius, MidY));
04742     CircleT.InsertCurveTo(DocCoord(MidX+Radius, MidY+CPDist), DocCoord(MidX+CPDist, MidY+Radius), DocCoord(MidX, MidY+Radius));
04743     CircleT.InsertCurveTo(DocCoord(MidX-CPDist, MidY+Radius), DocCoord(MidX-Radius, MidY+CPDist), DocCoord(MidX-Radius, MidY));
04744     CircleT.InsertLineTo(DocCoord(MidX+Radius, MidY));
04745     CircleT.IsFilled = TRUE;
04746     
04747     FillEffectAltRainbowAttribute AltRainbow;
04748     pRender->SetFillEffect(&AltRainbow, FALSE); // Set alt-rainbow fill
04749     pRender->DrawPath(&CircleT);                // And draw topmost semicircle
04750 
04751     Path CircleB;
04752     CircleB.Initialise(12, 12);
04753     CircleB.FindStartOfPath();
04754     CircleB.InsertMoveTo(DocCoord(MidX+Radius, MidY));
04755     CircleB.InsertCurveTo(DocCoord(MidX+Radius, MidY-CPDist), DocCoord(MidX+CPDist, MidY-Radius), DocCoord(MidX, MidY-Radius));
04756     CircleB.InsertCurveTo(DocCoord(MidX-CPDist, MidY-Radius), DocCoord(MidX-Radius, MidY-CPDist), DocCoord(MidX-Radius, MidY));
04757     CircleB.InsertLineTo(DocCoord(MidX+Radius, MidY));
04758     CircleB.IsFilled = TRUE;
04759 
04760     FillEffectRainbowAttribute Rainbow;
04761     pRender->SetFillEffect(&Rainbow, FALSE);    // Set rainbow fill
04762     pRender->DrawPath(&CircleB);                // And draw bottom semicircle
04763 
04764     pRender->RestoreContext();                  // Get attrs back to normality!
04765     pRender->SaveContext();
04766     
04767     // --- Finally, draw a (rectangle) over the colour wheel, filled with
04768     //     a grey of the same intensity/Value as the source colour (e.g
04769     //     if source Value == 1.0, then fill with white). This is overlaid
04770     //     using a circular transparent fill which is 0% transparent in the
04771     //     center (white) and 100% at the edge of the wheel (wheel-colour)
04772     Path TransPath;
04773     TransPath.Initialise(12, 12);
04774     TransPath.FindStartOfPath();
04775     TransPath.InsertMoveTo(DocCoord(MidX-Radius, MidY-Radius));
04776     TransPath.InsertLineTo(DocCoord(MidX-Radius, MidY+Radius));
04777     TransPath.InsertLineTo(DocCoord(MidX+Radius, MidY+Radius));
04778     TransPath.InsertLineTo(DocCoord(MidX+Radius, MidY-Radius));
04779     TransPath.InsertLineTo(DocCoord(MidX-Radius, MidY-Radius));
04780     TransPath.IsFilled = TRUE;
04781 
04782     // Render the transpath
04783     TempColourDef.Hue = 0;
04784     TempColourDef.Saturation = 0;
04785     TempColourDef.Value = (EditingColour == NULL) ?
04786                                      FIXED24(1.0) : ColourDef.Value;                    
04787     DocColour MaxWhiteness = DOCCOLOUR_HSVT(&TempColourDef);
04788 
04789     pRender->SetLineWidth(0);           // Ensure fill-only
04790     pRender->SetLineColour(Trans);
04791     pRender->SetFillColour(MaxWhiteness);
04792 
04793     // Set transparency to circular 0% at center, 100% at radius, && plot it
04794     RadialTranspFillAttribute TransFill;
04795     TransFill.SetStartPoint(DocCoord(MidX, MidY));
04796     TransFill.SetEndPoint(DocCoord(MidX, MidY+Radius));
04797     TransFill.SetEndPoint2(DocCoord(MidX+Radius, MidY));
04798     TransFill.Transp        = 0;
04799     TransFill.EndTransp     = 255;
04800     TransFill.TranspType    = TT_Mix;       // 'Mix' transparency
04801 
04802     pRender->SetTranspFillGeometry(&TransFill, FALSE);
04803     pRender->DrawPath(&TransPath);
04804 
04805     
04806 
04807     // Finally, render an outlined circle over the top, to give the 'jelly cone' appearance
04808     pRender->SetFillColour(Trans);
04809     pRender->SetLineColour(ShadowCFill);
04810     pRender->DrawPath(&ShadowC);
04811 
04812 
04813     pRender->RestoreContext();          // Restore original attribute context
04814 
04815     
04816     if (EditingColour != NULL)
04817     {
04818         // And draw a drag icon on the current Z position **** !!!! ToDo: Should be a bitmap icon
04819         DocRect ZButton(TipX-ZSLIDERSIZE+PixelSize, TipY-ZSLIDERSIZE+PixelSize,
04820                         TipX-PixelSize, TipY-PixelSize);
04821 
04822         // The drag icon should touch the edge of the HSV circle (at 45 degrees)
04823         Offset = (INT32) (((double) (TopMidY - TipY) - (0.707106781 * (double) MaxRadius)) *
04824                             TempColourDef.Value.MakeDouble());
04825         
04826         ZButton.Translate(Offset, Offset);
04827         GridLockRect(&ZButton, PixelSize);
04828 
04829 
04830         DocColour MidGrey(128L, 128L, 128L);
04831         pRender->SetFillColour(MidGrey);
04832         pRender->DrawRect(&ZButton);
04833 
04834 
04835         // Render marker crosses in the appropriate places for the definition
04836         // of the current editing colour
04837         DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
04838     
04839         // Convert Hue (0.0 -> 1.0) into an angle in radians (0 -> 2Pi)
04840         const double theta  = 2.0 * PI * ColourDef.Hue.MakeDouble();
04841     
04842         // Convert Saturation into a distance from the center of the colour wheel
04843         const double length = (double)Radius * ColourDef.Saturation.MakeDouble();
04844 
04845         // Translate the cross to the polar coordinate (theta, length)
04846         CrossRect.Translate(HalfGridLock(MidX + (INT32)(length * sin(theta)), PixelSize),
04847                             HalfGridLock(MidY + (INT32)(length * cos(theta)), PixelSize));
04848         RenderCross(pRender, &CrossRect, PixelSize);
04849     }
04850 
04851 //#else
04852 
04853     // Calculate where the colour wheel circle & brightness slider rect will go
04854     // Note that we always try for an even number of pixels wide, to ensure that
04855     // the marker cross appears exactly centered (rather than 1 pixel more space
04856     // on one side of it)
04857     DocRect ValueRect;
04858     ValueRect.hi.x = HalfGridLock(VirtualSize->hi.x, PixelSize);
04859     ValueRect.lo.x = HalfGridLock(ValueRect.hi.x - (VirtualSize->Width() / 8), PixelSize * 2);
04860 
04861 
04862     // Diameter is the width of the gadget - the value rectangle - a gap
04863     INT32 Diameter = VirtualSize->Width() - ValueRect.Width() - (ValueRect.Width() / 3);
04864     if (Diameter > VirtualSize->Height())
04865         Diameter = VirtualSize->Height();
04866 
04867     const INT32 Radius = HalfGridLock(Diameter/2, PixelSize);
04868     const INT32 MidY = HalfGridLock(VirtualSize->Height() / 2, PixelSize);
04869     const INT32 MidX = HalfGridLock(VirtualSize->lo.x + Radius, PixelSize);
04870 
04871     ValueRect.lo.y = MidY - Radius; // Rect only as high as the circle
04872     ValueRect.hi.y = MidY + Radius;
04873 
04874     // Get the colour we want to display as an HSV colour definition
04875     ColourHSVT ColourDef;                   
04876     ColourHSVT TempColourDef;
04877     if (EditingColour != NULL)
04878     {
04879         BaseDocument *ScopeDocument = ParentList->GetParentDocument();
04880         ColourContextArray *Contexts = ScopeDocument->GetDefaultColourContexts();
04881         ERROR3IF(Contexts == NULL, "Document default contexts not defined?!");
04882 
04883         ColourContextHSVT *ccHSV = (ColourContextHSVT *)
04884                                         Contexts->Context[COLOURMODEL_HSVT];
04885         ERROR3IF(ccHSV == NULL, "Document default context for HSV not defined?!");
04886         ccHSV->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
04887 
04888         // --- Draw the value slider rectangle
04889     
04890         // Create a colour from this, but with Value = 1.0
04891         memcpy(&TempColourDef, &ColourDef, sizeof(ColourHSVT));
04892         TempColourDef.Value = FIXED24(1.0);
04893     }
04894 
04895     // Create a grad fill from this colour (V=1.0) to black (V=0.0)
04896     // (Declare variables now to stop render region going tits up)
04897     LinearFillAttribute ValueGradFill;
04898     Path ValuePath;
04899 
04900     if (pClipRect->IsIntersectedWith(ValueRect))
04901     {
04902         if (EditingColour != NULL)
04903             ValueGradFill.Colour = DOCCOLOUR_HSVT(&TempColourDef);  
04904         else
04905             ValueGradFill.Colour = DocColour(255L, 255L, 255L);
04906 
04907         ValueGradFill.EndColour  = DocColour(0L, 0L, 0L);
04908         ValueGradFill.SetStartPoint(DocCoord((ValueRect.lo.x + ValueRect.hi.x) / 2,
04909                                             ValueRect.hi.y));
04910         ValueGradFill.SetEndPoint(DocCoord((ValueRect.lo.x + ValueRect.hi.x) / 2,
04911                                             ValueRect.lo.y));
04912         ValueGradFill.SetEndPoint2(NULL);
04913 
04914         pRender->SetFillGeometry(&ValueGradFill, FALSE);
04915 
04916         // Draw the rectangle - done as a path so we can draw with grad-fill
04917         ValuePath.Initialise(12, 12);
04918         ValuePath.FindStartOfPath();
04919 
04920         ValuePath.InsertMoveTo(ValueRect.lo);
04921         ValuePath.InsertLineTo(DocCoord(ValueRect.hi.x, ValueRect.lo.y));
04922         ValuePath.InsertLineTo(ValueRect.hi);
04923         ValuePath.InsertLineTo(DocCoord(ValueRect.lo.x, ValueRect.hi.y));
04924         ValuePath.IsFilled = TRUE;
04925 
04926         pRender->DrawPath(&ValuePath);      // Render the value/brightness strip
04927     }
04928 
04929     // --- Draw the HSV colour wheel - two semicircles with conical rainbow
04930     //     fills (this will be overlaid with a transparent-filled white
04931     //     circle to get the final colour wheel image)
04932 
04933     // CPDist = the distance of the bezier control points from the line
04934     // endpoints to give us a circle
04935     const INT32 CPDist = (const INT32) ( ((double)Radius) * 0.552 );
04936 
04937     // Generate the fill attribute for the HSV rainbow fill
04938     // Again, create all the objects at this scope level to keep render region alive
04939     ConicalFillAttribute Conical;
04940     FillEffectAltRainbowAttribute AltRainbow;
04941     Path CircleT;
04942     Path CircleB;
04943     Path TransPath;
04944     RadialTranspFillAttribute TransFill;
04945 
04946     DocRect WheelRect(MidX - Radius, MidY - Radius, MidX + Radius, MidY + Radius);
04947     if (pClipRect->IsIntersectedWith(WheelRect))
04948     {
04949         Conical.SetStartPoint(DocCoord(MidX, MidY));
04950         Conical.SetEndPoint(DocCoord(MidX-Radius, MidY));
04951         Conical.SetEndPoint2(NULL);
04952 
04953         // Fill: conical, (alt)rainbow, Hue 0.25 to 0.75, Value == SourceColour Value
04954         TempColourDef.Hue = FIXED24(0.25);
04955         TempColourDef.Saturation = FIXED24(1.0);
04956         if (EditingColour != NULL)
04957             TempColourDef.Value = ColourDef.Value;
04958         else
04959             TempColourDef.Value = FIXED24(1.0);
04960 
04961         Conical.Colour = DOCCOLOUR_HSVT(&TempColourDef);
04962 
04963         TempColourDef.Hue = FIXED24(0.75);
04964         Conical.EndColour = DOCCOLOUR_HSVT(&TempColourDef);
04965 
04966         pRender->SetFillGeometry(&Conical, FALSE);
04967 
04968         // Build and draw the Top (CircleT) and Bottom (CircleB) Semicircles
04969         CircleT.Initialise(12, 12);
04970         CircleT.FindStartOfPath();
04971         CircleT.InsertMoveTo(DocCoord(MidX+Radius, MidY));
04972         CircleT.InsertCurveTo(DocCoord(MidX+Radius, MidY+CPDist), DocCoord(MidX+CPDist, MidY+Radius), DocCoord(MidX, MidY+Radius));
04973         CircleT.InsertCurveTo(DocCoord(MidX-CPDist, MidY+Radius), DocCoord(MidX-Radius, MidY+CPDist), DocCoord(MidX-Radius, MidY));
04974         CircleT.InsertLineTo(DocCoord(MidX+Radius, MidY));
04975         CircleT.IsFilled = TRUE;
04976     
04977         pRender->SetFillEffect(&AltRainbow, FALSE); // Set alt-rainbow fill
04978         pRender->DrawPath(&CircleT);                // And draw topmost semicircle
04979 
04980         CircleB.Initialise(12, 12);
04981         CircleB.FindStartOfPath();
04982         CircleB.InsertMoveTo(DocCoord(MidX+Radius, MidY));
04983         CircleB.InsertCurveTo(DocCoord(MidX+Radius, MidY-CPDist), DocCoord(MidX+CPDist, MidY-Radius), DocCoord(MidX, MidY-Radius));
04984         CircleB.InsertCurveTo(DocCoord(MidX-CPDist, MidY-Radius), DocCoord(MidX-Radius, MidY-CPDist), DocCoord(MidX-Radius, MidY));
04985         CircleB.InsertLineTo(DocCoord(MidX+Radius, MidY));
04986         CircleB.IsFilled = TRUE;
04987 
04988         FillEffectRainbowAttribute Rainbow;
04989         pRender->SetFillEffect(&Rainbow, FALSE);    // Set rainbow fill
04990         pRender->DrawPath(&CircleB);                // And draw bottom semicircle
04991 
04992         pRender->RestoreContext();                  // Get attrs back to normality!
04993         pRender->SaveContext();
04994     
04995         // --- Finally, draw a (rectangle) over the colour wheel, filled with
04996         //     a grey of the same intensity/Value as the source colour (e.g
04997         //     if source Value == 1.0, then fill with white). This is overlaid
04998         //     using a circular transparent fill which is 0% transparent in the
04999         //     center (white) and 100% at the edge of the wheel (wheel-colour)
05000         TransPath.Initialise(12, 12);
05001         TransPath.FindStartOfPath();
05002         TransPath.InsertMoveTo(DocCoord(MidX-Radius, MidY-Radius));
05003         TransPath.InsertLineTo(DocCoord(MidX-Radius, MidY+Radius));
05004         TransPath.InsertLineTo(DocCoord(MidX+Radius, MidY+Radius));
05005         TransPath.InsertLineTo(DocCoord(MidX+Radius, MidY-Radius));
05006         TransPath.InsertLineTo(DocCoord(MidX-Radius, MidY-Radius));
05007         TransPath.IsFilled = TRUE;
05008 
05009         // Render the transpath
05010         TempColourDef.Hue = 0;
05011         TempColourDef.Saturation = 0;
05012         TempColourDef.Value = (EditingColour == NULL) ?
05013                                          FIXED24(1.0) : ColourDef.Value;                    
05014         DocColour MaxWhiteness = DOCCOLOUR_HSVT(&TempColourDef);
05015 
05016         pRender->SetLineWidth(0);           // Ensure fill-only
05017         pRender->SetLineColour(Trans);
05018         pRender->SetFillColour(MaxWhiteness);
05019 
05020         // Set transparency to circular 0% at center, 100% at radius, && plot it
05021         TransFill.SetStartPoint(DocCoord(MidX, MidY));
05022         TransFill.SetEndPoint(DocCoord(MidX, MidY+Radius));
05023         TransFill.SetEndPoint2(DocCoord(MidX+Radius, MidY));
05024         TransFill.Transp        = 0;
05025         TransFill.EndTransp     = 255;
05026         TransFill.TranspType    = TT_Mix;       // 'Mix' transparency
05027 
05028         pRender->SetTranspFillGeometry(&TransFill, FALSE);
05029         pRender->DrawPath(&TransPath);
05030     }
05031 
05032     pRender->RestoreContext();          // Restore original attribute context
05033 
05034     
05035     if (EditingColour != NULL)
05036     {
05037         // Render marker crosses in the appropriate places for the definition
05038         // of the current editing colour
05039         DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
05040     
05041         // Convert Hue (0.0 -> 1.0) into an angle in radians (0 -> 2Pi)
05042         const double theta  = 2.0 * PI * ColourDef.Hue.MakeDouble();
05043     
05044         // Convert Saturation into a distance from the center of the colour wheel
05045         const double length = (double)Radius * ColourDef.Saturation.MakeDouble();
05046 
05047         // Translate the cross to the polar coordinate (theta, length)
05048         CrossRect.Translate(HalfGridLock(MidX + (INT32)(length * sin(theta)), PixelSize),
05049                             HalfGridLock(MidY + (INT32)(length * cos(theta)), PixelSize));
05050         RenderCross(pRender, &CrossRect, PixelSize);
05051 
05052         CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
05053         INT32 TransX = (ValueRect.lo.x + ValueRect.hi.x) / 2;
05054         INT32 TransY = ValueRect.lo.y + (INT32) ((double)ValueRect.Height() *
05055                                                 ColourDef.Value.MakeDouble());
05056         CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
05057         RenderCross(pRender, &CrossRect, PixelSize);
05058     }
05059 
05060 #endif
05061 }
05062 
05063 
05064 
05065 
05066 /********************************************************************************************
05067 
05068 >   static void RenderPickerSquare(RenderRegion *pRender, DocRect *SquareRect,
05069                         ColourGeneric *BaseCol, ColourGeneric *MidCol, ColourGeneric *TopCol,
05070                         ColourModel TheColourModel, UINT32 TransType)
05071 
05072     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05073     Created:    23/12/94
05074 
05075     Inputs:     pRender - The render region to render the picker in
05076                 SquareRect - The rectangle to fill with the RGB/CMYK cube slice
05077                 BaseCol - The colour to use on the base (Z axis)
05078                 MidCol - The second colour (X axis)
05079                 TopCol - The third colour (Y axis)
05080                 TheColourModel - COLOURMODEL_RGBT or COLOURMODEL_CMYK
05081                 TransType - 3 (stain/additive) for RGB, 2 (stain/filtering) for CMY
05082 
05083     Purpose:    Redraws the front face of the RGB/CMY colour cube pickers.
05084                 This can redraw an axis-aligned planar cut through the RGB/CMY colourspaces,
05085                 if the input parameters are correct.
05086 
05087     Scope:      private (to kernel\coldlog.cpp)
05088 
05089     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
05090 
05091 ********************************************************************************************/
05092 
05093 static void RenderPickerSquare(RenderRegion *pRender, DocRect *SquareRect,
05094                         ColourGeneric *BaseCol, ColourGeneric *MidCol, ColourGeneric *TopCol,
05095                         ColourModel TheColourModel, UINT32 TransType)
05096 {
05097     pRender->SaveContext();     // Save the current rendering context
05098 
05099     // First, render the BaseSquare in BaseColour
05100     DocColour BaseFillCol(TheColourModel, BaseCol);
05101     pRender->SetFillColour(BaseFillCol);
05102     pRender->DrawRect(SquareRect);
05103 
05104 
05105     // Next, create a path for the rectangle so we can fill it with grad fills
05106     Path SquarePath;
05107     SquarePath.Initialise(12, 12);
05108     SquarePath.FindStartOfPath();
05109 
05110     SquarePath.InsertMoveTo(SquareRect->lo);
05111     SquarePath.InsertLineTo(DocCoord(SquareRect->hi.x, SquareRect->lo.y));
05112     SquarePath.InsertLineTo(SquareRect->hi);
05113     SquarePath.InsertLineTo(DocCoord(SquareRect->lo.x, SquareRect->hi.y));
05114     SquarePath.IsFilled = TRUE;
05115 
05116     // Create a vertical transparent fill from 100% transparent to 0% transparent
05117     LinearTranspFillAttribute SquareTransFill1;
05118     SquareTransFill1.Transp     = 0;
05119     SquareTransFill1.EndTransp  = 255;
05120     SquareTransFill1.TranspType = TransType;
05121     DocCoord ThePoint(SquareRect->hi.x, (SquareRect->lo.y + SquareRect->hi.y) / 2);
05122     SquareTransFill1.SetStartPoint(&ThePoint);
05123     ThePoint = DocCoord(SquareRect->lo.x, (SquareRect->lo.y + SquareRect->hi.y) / 2);
05124     SquareTransFill1.SetEndPoint(&ThePoint);
05125     SquareTransFill1.SetEndPoint2(NULL);
05126 
05127     DocColour MidFillCol(TheColourModel, MidCol);       // And flat-fill with the trans fill
05128     pRender->SetFillColour(MidFillCol);
05129 
05130     pRender->SetTranspFillGeometry(&SquareTransFill1, FALSE);
05131 
05132     pRender->DrawPath(&SquarePath);     // Render the Square
05133 
05134 
05135     LinearTranspFillAttribute SquareTransFill2;
05136     SquareTransFill2.Transp     = 0;
05137     SquareTransFill2.EndTransp  = 255;
05138     SquareTransFill2.TranspType = TransType;
05139 
05140     ThePoint = DocCoord((SquareRect->lo.x + SquareRect->hi.x) / 2, SquareRect->hi.y);
05141     SquareTransFill2.SetStartPoint(&ThePoint);
05142     ThePoint = DocCoord((SquareRect->lo.x + SquareRect->hi.x) / 2, SquareRect->lo.y);
05143     SquareTransFill2.SetEndPoint(&ThePoint);
05144     SquareTransFill2.SetEndPoint2(NULL);
05145 
05146     DocColour TopFillCol(TheColourModel, TopCol);       // And flat-fill with the trans fill
05147     pRender->SetFillColour(TopFillCol);
05148 
05149     pRender->SetTranspFillGeometry(&SquareTransFill2, FALSE);
05150     
05151     pRender->DrawPath(&SquarePath);     // Render the Square
05152 
05153 
05154     pRender->RestoreContext();
05155 }
05156 
05157 
05158 
05159 /********************************************************************************************
05160 
05161 >   static void DrawCubeShadowAndCalcValues(RenderRegion *pRender, DocRect *VirtualSize,
05162                                             INT32 PixelSize, DialogColourInfo *RedrawColours,
05163                                             DocRect *ResultRect, INT32 *ResultSizeZ);
05164 
05165     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05166     Created:    27/12/94
05167 
05168     Inputs:     pRender - The render region to render the picker in, or NULL if you want to
05169                 just calc the values without rendering anything.
05170                 VirtualSize - The rectangle defining the coordinate space to draw into
05171                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
05172                 coordinate space; ensures things line up on display pixel boundaries.
05173                 RedrawColours - A pointer to a DialogColourInfo object describing
05174                 OS-friendly drawing colours to be used in redrawing the control (or NULL if
05175                 pRender is also NULL)
05176 
05177     Outputs:    ResultRect - On return will contain the cube face rectangle
05178                 ResultSizeZ - On return will contain the projected size of the Z axis
05179 
05180     Purpose:    Clears the background of the picker control, and draws the 'shadow' of the
05181                 colour cube into the control, in preparation for RGB/CMYK colour slices
05182                 and stuff to be drawn on top. For convenience, returns the screen area
05183                 square of the cube face and the size of the Z axis as projected onscreen.
05184 
05185     Scope:      private (static in coldlog.cpp)
05186 
05187     SeeAlso:    ColourEditDlg::RenderPickerRGB; ColourEditDlg::RenderPickerCMYK
05188 
05189 ********************************************************************************************/
05190 
05191 static void DrawCubeShadowAndCalcValues(RenderRegion *pRender, DocRect *VirtualSize,
05192                                         INT32 PixelSize, DialogColourInfo *RedrawColours,
05193                                         DocRect *ResultRect, INT32 *ResultSizeZ)
05194 {
05195     DocColour Trans(COLOUR_TRANS);
05196 
05197     // Calculate the basic cube shape
05198     INT32 MaxSize = VirtualSize->Height();
05199     if (VirtualSize->Width() < MaxSize)
05200         MaxSize = VirtualSize->Width();
05201 
05202     const INT32 SizeXY = (100 * MaxSize) / 135;     // Size of the X and Y projections
05203     INT32 SizeZ  = MaxSize - SizeXY;                    // Size of the Z projection
05204 
05205     // Ensure it's a square, aligned in the left side of the available area
05206     DocRect SquareRect;
05207     SquareRect.lo.x = HalfGridLock(VirtualSize->lo.x,                   PixelSize);
05208     SquareRect.hi.x = HalfGridLock(VirtualSize->lo.x + SizeXY,          PixelSize);
05209     SquareRect.lo.y = HalfGridLock(VirtualSize->lo.y + SizeZ,           PixelSize);
05210     SquareRect.hi.y = HalfGridLock(VirtualSize->lo.y + SizeXY + SizeZ,  PixelSize);
05211 
05212     if (VirtualSize->Height() > MaxSize)
05213     {
05214         // The area we're in is higher than it is wide, so center the square vertically
05215         SquareRect.Translate(0, (VirtualSize->Height() - MaxSize) / 2);
05216     }
05217 
05218     GridLockRect(&SquareRect, PixelSize);
05219 
05220     SizeZ = HalfGridLock(SizeZ-ZSLIDERSIZE, PixelSize); // Gridlock & Leave gap at bot-rt for Z-slider drag icon
05221 
05222     if (pRender != NULL)
05223     {
05224         pRender->SaveContext();
05225 #if FALSE
05226 /*
05227         // Draw the cube 'shadow'
05228         DocColour CubeFaceGrey(168L, 168L, 168L);
05229         pRender->SetFillColour(CubeFaceGrey);
05230         pRender->DrawRect(&SquareRect);
05231 
05232         DocColour CubeFillGrey1(176L, 176L, 176L);      // **** !!!! Perhaps we should use transparent black!
05233         pRender->SetFillColour(CubeFillGrey1);
05234 
05235         // Draw the Z extent of the 'cube' - right side
05236         DocCoord BottomRight(HalfGridLock(SquareRect.hi.x + SizeZ, PixelSize),
05237                              HalfGridLock(SquareRect.lo.y - SizeZ, PixelSize));
05238 
05239         Path ZPath1;
05240         ZPath1.Initialise(12, 12);
05241         ZPath1.FindStartOfPath();
05242         ZPath1.InsertMoveTo(BottomRight);
05243         ZPath1.InsertLineTo(DocCoord(SquareRect.hi.x, SquareRect.lo.y));
05244         ZPath1.InsertLineTo(DocCoord(SquareRect.hi.x, SquareRect.hi.y));
05245         ZPath1.InsertLineTo(DocCoord(SquareRect.hi.x + SizeZ, SquareRect.hi.y - SizeZ));
05246         ZPath1.IsFilled = TRUE;
05247 
05248         pRender->DrawPath(&ZPath1);
05249 
05250 
05251         DocColour CubeFillGrey2(160L, 160L, 160L);      // **** !!!! Perhaps we should use transparent black!
05252         pRender->SetFillColour(CubeFillGrey2);
05253 
05254         // Draw the Z extent of the 'cube' - bottom side
05255         Path ZPath2;
05256         ZPath2.Initialise(12, 12);
05257         ZPath2.FindStartOfPath();
05258         ZPath2.InsertMoveTo(BottomRight);
05259         ZPath2.InsertLineTo(DocCoord(SquareRect.lo.x + SizeZ, SquareRect.lo.y - SizeZ));
05260         ZPath2.InsertLineTo(SquareRect.lo);
05261         ZPath2.InsertLineTo(DocCoord(SquareRect.hi.x, SquareRect.lo.y));
05262         ZPath2.IsFilled = TRUE;
05263 
05264         pRender->DrawPath(&ZPath2);
05265 
05266         // Draw the 3 inside-edge lines at the back of the cube
05267         DocRect BackFaceRect(SquareRect);
05268         BackFaceRect.Translate(SizeZ, -SizeZ);
05269 
05270         // Draw the 3 back edges of the cube (The front edges are added by the caller,
05271         // on top of the the colour slice square)
05272         DocColour BackEdgeGrey(144L, 144L, 144L);
05273         pRender->SetLineColour(BackEdgeGrey);
05274         pRender->SetFillColour(Trans);
05275 
05276         DocCoord TLBPoint(BackFaceRect.lo.x, BackFaceRect.hi.y);
05277         pRender->DrawLine(TLBPoint, BackFaceRect.hi);
05278         pRender->DrawLine(TLBPoint, BackFaceRect.lo);
05279         pRender->DrawLine(TLBPoint, DocCoord(SquareRect.lo.x, SquareRect.hi.y));
05280 */
05281 #else
05282         // Draw the Back Face
05283         DocRect BackFaceRect(SquareRect);
05284         BackFaceRect.Translate(SizeZ, -SizeZ);
05285 
05286         DocColour CubeFaceGrey(136L, 136L, 136L);
05287         pRender->SetFillColour(CubeFaceGrey);
05288         pRender->DrawRect(&BackFaceRect);
05289 
05290         // Draw the (Back-)Left face
05291         DocCoord BackTopLeft(HalfGridLock(SquareRect.lo.x + SizeZ, PixelSize),
05292                              HalfGridLock(SquareRect.hi.y - SizeZ, PixelSize));
05293         Path ZPath1;
05294         ZPath1.Initialise(12, 12);
05295         ZPath1.FindStartOfPath();
05296         ZPath1.InsertMoveTo(BackTopLeft);
05297         ZPath1.InsertLineTo(DocCoord(SquareRect.lo.x, SquareRect.hi.y));
05298         ZPath1.InsertLineTo(SquareRect.lo);
05299         ZPath1.InsertLineTo(DocCoord(SquareRect.lo.x + SizeZ, SquareRect.lo.y - SizeZ));
05300         ZPath1.IsFilled = TRUE;
05301 
05302         LinearFillAttribute DepthFill1;
05303         DepthFill1.Colour       = DocColour(180L, 180L, 180L);
05304         DepthFill1.EndColour    = DocColour(144L, 144L, 144L);
05305         DocCoord ThePoint(SquareRect.lo.x, BackTopLeft.y);
05306         DepthFill1.SetStartPoint(&ThePoint);
05307         DepthFill1.SetEndPoint(&BackTopLeft);
05308         DepthFill1.SetEndPoint2(NULL);
05309         pRender->SetFillGeometry(&DepthFill1, FALSE);
05310 
05311         pRender->DrawPath(&ZPath1);
05312 
05313 
05314         // Draw the (Back-)Top face
05315         Path ZPath2;
05316         ZPath2.Initialise(12, 12);
05317         ZPath2.FindStartOfPath();
05318         ZPath2.InsertMoveTo(BackTopLeft);
05319         ZPath2.InsertLineTo(DocCoord(SquareRect.hi.x + SizeZ, BackTopLeft.y));
05320         ZPath2.InsertLineTo(SquareRect.hi);
05321         ZPath2.InsertLineTo(DocCoord(SquareRect.lo.x, SquareRect.hi.y));
05322         ZPath2.IsFilled = TRUE;
05323 
05324         LinearFillAttribute DepthFill2;
05325         DepthFill2.Colour       = DocColour(182L, 182L, 182L);
05326         DepthFill2.EndColour    = DocColour(144L, 144L, 144L);
05327         ThePoint = DocCoord(BackTopLeft.x, SquareRect.hi.y);
05328         DepthFill2.SetStartPoint(&ThePoint);
05329         DepthFill2.SetEndPoint(&BackTopLeft);
05330         DepthFill2.SetEndPoint2(NULL);
05331         pRender->SetFillGeometry(&DepthFill2, FALSE);
05332 
05333         pRender->DrawPath(&ZPath2);
05334 #endif
05335 
05336         pRender->RestoreContext();
05337     }
05338 
05339     // And finally, return the useful values we've calculated
05340     *ResultRect  = SquareRect;
05341     *ResultSizeZ = SizeZ;
05342 }
05343 
05344 
05345 
05346 /********************************************************************************************
05347 
05348 >   CrossConstraint ColourEditDlg::CalcCrossRectRGB(ColourRGBT *SourceColour, DocRect *SquareRect,
05349                                             INT32 PixelSize, DocRect *Result)
05350 
05351     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05352     Created:    23/12/94
05353 
05354     Inputs:     SourceColour - the colour definition for which the cross rect must be calc'd
05355                 SquareRect - The rect containing th 3-d cube 'slice' to plot the cross in
05356                 PixelSize - the usual (size of a pixel in millipoints)
05357     
05358     Outputs:    Result will be returned containing the CrossRect (in which to draw the cross)
05359 
05360     Returns:    A value indicating how the cross is constrained, so you can draw constraint
05361                 bubbles as appropriate.
05362 
05363     Purpose:    Determines the 3-D RGB picker cross position for the 2-component picker
05364                 slice-through-the-cube display
05365 
05366     SeeAlso:    ColourEditDlg::SetNewValueRGB; ColourEditDlg::RenderPickerRGB
05367 
05368 ********************************************************************************************/
05369 
05370 CrossConstraint ColourEditDlg::CalcCrossRectRGB(ColourRGBT *SourceColour, DocRect *SquareRect,
05371                                         INT32 PixelSize, DocRect *Result)
05372 {
05373     DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
05374 
05375     FIXED24 XComponent;
05376     FIXED24 YComponent;
05377 
05378     CrossConstraint ReturnVal = CROSSCONSTRAINED_NONE;
05379 
05380     switch(ColourPickerMode)
05381     {
05382         case 1:     // XYZ = R,B,G
05383             XComponent = SourceColour->Red;
05384             YComponent = SourceColour->Blue;
05385 
05386             if (EditingColour->InheritsComponent(3))
05387                 ReturnVal = CROSSCONSTRAINED_HORZ;
05388                  
05389             if (EditingColour->InheritsComponent(1))
05390             {
05391                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05392                     ReturnVal = CROSSCONSTRAINED_VERT;
05393                 else
05394                     ReturnVal = CROSSCONSTRAINED_BOTH;
05395             }
05396             break;
05397 
05398         case 2:     // XYZ = B,G,R
05399             XComponent = SourceColour->Blue;
05400             YComponent = SourceColour->Green;
05401 
05402             if (EditingColour->InheritsComponent(2))
05403                 ReturnVal = CROSSCONSTRAINED_HORZ;
05404                  
05405             if (EditingColour->InheritsComponent(3))
05406             {
05407                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05408                     ReturnVal = CROSSCONSTRAINED_VERT;
05409                 else
05410                     ReturnVal = CROSSCONSTRAINED_BOTH;
05411             }
05412             break;
05413 
05414         default:    // XYZ = G,R,B
05415             XComponent = SourceColour->Green;
05416             YComponent = SourceColour->Red;
05417 
05418             if (EditingColour->InheritsComponent(1))
05419                 ReturnVal = CROSSCONSTRAINED_HORZ;
05420                  
05421             if (EditingColour->InheritsComponent(2))
05422             {
05423                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05424                     ReturnVal = CROSSCONSTRAINED_VERT;
05425                 else
05426                     ReturnVal = CROSSCONSTRAINED_BOTH;
05427             }
05428             break;
05429     }
05430 
05431     INT32 SizeXY = SquareRect->Height();
05432     INT32 XTrans = (INT32) ((double)SizeXY * XComponent.MakeDouble());
05433     INT32 YTrans = (INT32) ((double)SizeXY * YComponent.MakeDouble());
05434 
05435     // Translate the cross to the appropriate position
05436     CrossRect.Translate(HalfGridLock(SquareRect->lo.x + XTrans, PixelSize),
05437                         HalfGridLock(SquareRect->lo.y + YTrans, PixelSize));
05438 
05439     *Result = CrossRect;
05440 
05441     if (EditingColour->GetType() == COLOURTYPE_TINT)
05442         return(CROSSCONSTRAINED_BOTH);
05443 
05444     return(ReturnVal);
05445 }
05446 
05447 
05448 
05449 /********************************************************************************************
05450 
05451 >   void ColourEditDlg::RenderPickerRGB(RenderRegion *pRender, DocRect *VirtualSize,
05452                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
05453 
05454     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05455     Created:    23/12/94
05456 
05457     Inputs:     pRender - The render region to render the picker in
05458                 VirtualSize - The rectangle defining the coordinate space to draw into
05459                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
05460                 coordinate space; ensures things line up on display pixel boundaries.
05461                 RedrawColours - A pointer to a DialogColourInfo object describing
05462                 OS-friendly drawing colours to be used in redrawing the control.
05463 
05464     Purpose:    Redraws a colour picker control for the colour editor dialogue.
05465                 This is used in the given display mode to display the colour information
05466                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
05467 
05468     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
05469 
05470 ********************************************************************************************/
05471 
05472 void ColourEditDlg::RenderPickerRGB(RenderRegion *pRender, DocRect *VirtualSize,
05473                                     INT32 PixelSize, DialogColourInfo *RedrawColours)
05474 {
05475     pRender->SaveContext();     // Save the current rendering context
05476     DocColour Trans(COLOUR_TRANS);
05477 
05478     // First, set up the render region, and fill the background with Dialogue BG colour
05479     pRender->SetLineWidth(0);
05480     pRender->SetLineColour(Trans);
05481 //  pRender->SetFillColour(RedrawColours->DialogBack());
05482 //  pRender->DrawRect(VirtualSize);
05483 
05484     // Draw the cube 'shadow', and calculate where the cube sits
05485     DocRect SquareRect;
05486     INT32 SizeZ;
05487     DrawCubeShadowAndCalcValues(pRender, VirtualSize, PixelSize, RedrawColours,
05488                                 /* TO */ &SquareRect, &SizeZ);
05489 
05490     DocRect FrontFaceRect(SquareRect);      // Remember the old squarerect for later
05491 
05492 #if FALSE
05493 /*
05494     Old code. Works fine normally, but due to using bleach trnsparency, fails to work
05495     properly in "show printer colours" preview mode. Also, the new 4-colour fill
05496     method below is faster, as it only does one path fill rather than 3 (plus transparency)
05497 
05498     // Find the source colour definition in RGB space
05499     ColourRGBT SourceColour;
05500     if (EditingColour != NULL)
05501     {
05502         ColourContextRGBT *ccRGB = (ColourContextRGBT *)
05503                                     ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
05504         ERROR3IF(ccRGB == NULL, "Can't get an RGB colour context");
05505 
05506         ccRGB->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
05507     }
05508     else
05509     {
05510         SourceColour.Red =SourceColour.Green = SourceColour.Blue = FIXED24(1.0);
05511         SourceColour.Transparent = 0;
05512     }
05513 
05514     // Now, Move the 'SquareRect' down and right so its bottom corner touches the Z axis
05515     // at the appropriate point for the current Z value. (i.e. slice the cube through at
05516     // the place where the slice really is)
05517     if (EditingColour != NULL)
05518     {
05519         FIXED24 ZComponent = SourceColour.Blue;
05520         if (ColourPickerMode == 1)
05521             ZComponent = SourceColour.Green;
05522         else if (ColourPickerMode == 2)
05523             ZComponent = SourceColour.Red;
05524 
05525         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
05526         SquareRect.Translate(-ZTrans, ZTrans);
05527         GridLockRect(&SquareRect, PixelSize);
05528     }
05529 
05530     // Now, composite up the picker square, which is made of 3 squares on top of each
05531     // other, all flat-filled in primary colours, the top 2 having horz/vert trans fills
05532     ColourRGBT BaseColour;
05533     ColourRGBT MidColour;
05534     ColourRGBT TopColour;
05535 
05536     BaseColour.Red = BaseColour.Green = BaseColour.Blue = BaseColour.Transparent = 0;
05537     memcpy(&MidColour, &BaseColour, sizeof(ColourRGBT));
05538     memcpy(&TopColour, &BaseColour, sizeof(ColourRGBT));
05539 
05540     switch(ColourPickerMode)
05541     {
05542         case 1:     // XYZ = R,B,G
05543             MidColour.Red       = FIXED24(1.0);
05544             TopColour.Blue      = FIXED24(1.0);
05545             BaseColour.Green    = SourceColour.Green;
05546             break;
05547 
05548         case 2:     // XYZ = B,G,R
05549             MidColour.Blue      = FIXED24(1.0);
05550             TopColour.Green     = FIXED24(1.0);
05551             BaseColour.Red      = SourceColour.Red;
05552             break;
05553 
05554         default:    // XYZ = G,R,B
05555             MidColour.Green = FIXED24(1.0);
05556             TopColour.Red   = FIXED24(1.0);
05557             BaseColour.Blue = SourceColour.Blue;
05558 
05559             ColourPickerMode = 0;       // Ensure any out of value setting is made valid
05560             break;
05561     }
05562 
05563     RenderPickerSquare(pRender, &SquareRect,
05564                         (ColourGeneric *) &BaseColour, (ColourGeneric *) &MidColour,
05565                         (ColourGeneric *) &TopColour,
05566                         COLOURMODEL_RGBT, 3);   // Use RGB + 'bleach' (additive) transparency
05567 */
05568 #else
05569     // Find the source colour definition in RGB space
05570     PColourRGBT SourceColour;
05571     if (EditingColour != NULL)
05572     {
05573         ColourContextRGBT *ccRGB = (ColourContextRGBT *)
05574                                     ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
05575         ERROR3IF(ccRGB == NULL, "Can't get an RGB colour context");
05576 
05577         DocColour TempRef;
05578         TempRef.MakeRefToIndexedColour(EditingColour);
05579         ccRGB->ConvertColour(&TempRef, (ColourPacked *) &SourceColour);
05580     }
05581     else
05582     {
05583         SourceColour.Red =SourceColour.Green = SourceColour.Blue = 255;
05584         SourceColour.Transparent = 0;
05585     }
05586 
05587     // Now, Move the 'SquareRect' down and right so its bottom corner touches the Z axis
05588     // at the appropriate point for the current Z value. (i.e. slice the cube through at
05589     // the place where the slice really is)
05590 
05591     if (EditingColour != NULL)
05592     {
05593         INT32 ZComponent = SourceColour.Blue;
05594         if (ColourPickerMode == 1)
05595             ZComponent = SourceColour.Green;
05596         else if (ColourPickerMode == 2)
05597             ZComponent = SourceColour.Red;
05598 
05599         INT32 ZTrans = (INT32) (((double)SizeZ * ZComponent) / 255.0) - SizeZ;
05600         SquareRect.Translate(-ZTrans, ZTrans);
05601         GridLockRect(&SquareRect, PixelSize);
05602     }
05603 
05604     // Draw a 4-colour fill for the cube face
05605     FourColFillAttribute Fill;
05606 
05607     // Set the points to be in the corners of the square rect
05608     Fill.SetStartPoint(&SquareRect.lo);                             // Bottom left
05609     DocCoord Corner = DocCoord(SquareRect.hi.x, SquareRect.lo.y);
05610     Fill.SetEndPoint(&Corner);                                      // Bottom right
05611     Corner = DocCoord(SquareRect.lo.x, SquareRect.hi.y);
05612     Fill.SetEndPoint2(&Corner);                                     // Top left
05613     Fill.SetEndPoint3(&SquareRect.hi);                              // Top right
05614 
05615     // And set the corner colours
05616     DocColour CornerCol;
05617     switch(ColourPickerMode)
05618     {
05619         case 1:     // XYZ = R,B,G
05620             CornerCol = DocColour(0L, SourceColour.Green, 0L);              // Bottom left
05621             Fill.SetStartColour(&CornerCol);
05622             CornerCol = DocColour(255L, SourceColour.Green, 0L);            // Bottom right
05623             Fill.SetEndColour(&CornerCol);
05624             CornerCol = DocColour(0L, SourceColour.Green, 255L);            // Top left
05625             Fill.SetEndColour2(&CornerCol);
05626             CornerCol = DocColour(255L, SourceColour.Green, 255L);          // Top right
05627             Fill.SetEndColour3(&CornerCol);
05628             break;
05629 
05630         case 2:     // XYZ = B,G,R
05631             CornerCol = DocColour(SourceColour.Red, 0L, 0L);                // Bottom left
05632             Fill.SetStartColour(&CornerCol);
05633             CornerCol = DocColour(SourceColour.Red, 0L, 255L);              // Bottom right
05634             Fill.SetEndColour(&CornerCol);
05635             CornerCol = DocColour(SourceColour.Red, 255L, 0L);              // Top left
05636             Fill.SetEndColour2(&CornerCol);
05637             CornerCol = DocColour(SourceColour.Red, 255L, 255L);            // Top right
05638             Fill.SetEndColour3(&CornerCol);
05639             break;
05640 
05641         default:    // XYZ = G,R,B
05642             CornerCol = DocColour(0L, 0L, SourceColour.Blue);               // Bottom left
05643             Fill.SetStartColour(&CornerCol);
05644             CornerCol = DocColour(0L, 255L, SourceColour.Blue);             // Bottom right
05645             Fill.SetEndColour(&CornerCol);
05646             CornerCol = DocColour(255L, 0L, SourceColour.Blue);             // Top left
05647             Fill.SetEndColour2(&CornerCol);
05648             CornerCol = DocColour(255L, 255L, SourceColour.Blue);           // Top right
05649             Fill.SetEndColour3(&CornerCol);
05650             break;
05651     }
05652 
05653     // Build a path for the rectangle (DrawRect doesn't do grad fills)
05654     Path SquarePath;
05655     SquarePath.Initialise(12, 12);
05656     SquarePath.FindStartOfPath();
05657     SquarePath.InsertMoveTo(SquareRect.lo);
05658     SquarePath.InsertLineTo(DocCoord(SquareRect.lo.x, SquareRect.hi.y));
05659     SquarePath.InsertLineTo(SquareRect.hi);
05660     SquarePath.InsertLineTo(DocCoord(SquareRect.hi.x, SquareRect.lo.y));
05661     SquarePath.IsFilled = TRUE;
05662 
05663     pRender->SetLineColour(Trans);
05664     pRender->SetFillGeometry(&Fill, FALSE);
05665 
05666     // And render it
05667     pRender->DrawPath(&SquarePath);
05668 #endif
05669 
05670     // Place the outline of the front of the cube on top
05671     DocColour CubeFaceGrey(180L, 180L, 180L);
05672     pRender->SetLineColour(CubeFaceGrey);
05673     pRender->SetFillColour(Trans);
05674 
05675     DocCoord BotRightFront(FrontFaceRect.hi.x, FrontFaceRect.lo.y);
05676     pRender->DrawLine(BotRightFront, FrontFaceRect.lo);
05677     pRender->DrawLine(BotRightFront, FrontFaceRect.hi);
05678     pRender->DrawLine(BotRightFront,
05679                     DocCoord(FrontFaceRect.hi.x + SizeZ, FrontFaceRect.lo.y - SizeZ));
05680 
05681     // Draw the swap-axes button
05682     DocCoord BitmapPos;
05683     BitmapPos.x = HalfGridLock(FrontFaceRect.hi.x + SizeZ/2, PixelSize);
05684     BitmapPos.y = HalfGridLock(FrontFaceRect.hi.y - SizeZ/2, PixelSize);
05685 
05686     const INT32 BitmapSize = 14 * PixelSize;
05687     DocRect SwapAxesStrip(BitmapPos.x + BitmapSize, BitmapPos.y,
05688                             BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
05689 
05690     GridLockRect(&SwapAxesStrip, PixelSize);
05691 
05692     DocColour SwapAxesFore(0L, 0L, 0L);
05693     DocColour SwapAxesFill(0L, 0L, 255L);
05694     if (ColourPickerMode == 1)
05695         SwapAxesFill = DocColour(0L, 255L, 0L);
05696     else if (ColourPickerMode == 2)
05697         SwapAxesFill = DocColour(255L, 0L, 0L);
05698 
05699     pRender->SetFillColour(SwapAxesFill);
05700     pRender->SetLineColour(SwapAxesFore);
05701     pRender->DrawRect(&SwapAxesStrip);
05702 
05703     // Render the bitmap last, to ensure we don't overwrite it
05704     pRender->DrawBitmap(BitmapPos, _R(IDB_PICKER_SWAPAXIS));
05705 
05706 
05707     DocColour MidGrey(128L, 128L, 128L);
05708 
05709     if (EditingColour != NULL)
05710     {
05711         // And draw a drag icon on the current Z position
05712         DocRect ZButton(SquareRect);
05713         ZButton.lo.x = ZButton.hi.x;
05714         ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
05715         ZButton.hi.y = ZButton.lo.y;
05716         ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
05717         GridLockRect(&ZButton, PixelSize);
05718         
05719         pRender->DrawBitmap(ZButton.lo, _R(IDB_PICKER_ZSLIDER));
05720 
05721         DocRect CrossRect;
05722         ColourRGBT SourceDef;
05723         if (EditingColour != NULL)
05724         {
05725             ColourContextRGBT *ccRGB = (ColourContextRGBT *)
05726                                         ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
05727             ERROR3IF(ccRGB == NULL, "Can't get an RGB colour context");
05728 
05729             ccRGB->ConvertColour(EditingColour, (ColourGeneric *) &SourceDef);
05730         }
05731         else
05732         {
05733             SourceDef.Red =SourceDef.Green = SourceDef.Blue = FIXED24(1.0);
05734             SourceDef.Transparent = 0;
05735         }
05736 
05737         CrossConstraint Constraint = CalcCrossRectRGB(&SourceDef, &SquareRect, PixelSize, &CrossRect);
05738         RenderCross(pRender, &CrossRect, PixelSize, (Constraint == CROSSCONSTRAINED_BOTH));
05739 
05740         if (Constraint == CROSSCONSTRAINED_HORZ)
05741         {
05742             INT32 MidY = (CrossRect.lo.y + CrossRect.hi.y) / 2;
05743             RenderConstraint(pRender, DocCoord(SquareRect.lo.x, MidY), DocCoord(SquareRect.hi.x, MidY));
05744         }
05745         else if (Constraint == CROSSCONSTRAINED_VERT)
05746         {
05747             INT32 MidX = (CrossRect.lo.x + CrossRect.hi.x) / 2;
05748             RenderConstraint(pRender, DocCoord(MidX, SquareRect.lo.y), DocCoord(MidX, SquareRect.hi.y));
05749         }
05750     }
05751 
05752     pRender->RestoreContext();
05753 }
05754 
05755 
05756 
05757 /********************************************************************************************
05758 
05759 >   CrossConstraint ColourEditDlg::CalcCrossRectCMYK(ColourCMYK *SourceColour, DocRect *SquareRect,
05760                                             INT32 PixelSize, DocRect *Result)
05761 
05762     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05763     Created:    23/12/94
05764 
05765     Inputs:     SourceColour - the colour definition for which the cross rect must be calc'd
05766                 SquareRect - The rect containing th 3-d cube 'slice' to plot the cross in
05767                 PixelSize - the usual (size of a pixel in millipoints)
05768     
05769     Outputs:    Result will be returned containing the CrossRect (in which to draw the cross)
05770 
05771     Returns:    A value indicating how the cross is constrained, so you can draw constraint
05772                 bubbles as appropriate.
05773 
05774     Purpose:    Determines the 3-D CMYK picker cross position for the 2-component picker
05775                 slice-through-the-cube display
05776 
05777     SeeAlso:    ColourEditDlg::SetNewValueCMYK; ColourEditDlg::RenderPickerCMYK
05778 
05779 ********************************************************************************************/
05780 
05781 CrossConstraint ColourEditDlg::CalcCrossRectCMYK(ColourCMYK *SourceColour, DocRect *SquareRect,
05782                                         INT32 PixelSize, DocRect *Result)
05783 {
05784     DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
05785 
05786     FIXED24 XComponent;
05787     FIXED24 YComponent;
05788     CrossConstraint ReturnVal = CROSSCONSTRAINED_NONE;
05789 
05790     switch(ColourPickerMode)
05791     {
05792         case 1:     // XYZ = Y,M,C
05793             XComponent = SourceColour->Yellow;
05794             YComponent = SourceColour->Magenta;
05795 
05796             if (EditingColour->InheritsComponent(2))
05797                 ReturnVal = CROSSCONSTRAINED_HORZ;
05798                  
05799             if (EditingColour->InheritsComponent(3))
05800             {
05801                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05802                     ReturnVal = CROSSCONSTRAINED_VERT;
05803                 else
05804                     ReturnVal = CROSSCONSTRAINED_BOTH;
05805             }
05806             break;
05807 
05808         case 2:     // XYZ = M,C,Y
05809             XComponent = SourceColour->Magenta;
05810             YComponent = SourceColour->Cyan;
05811 
05812             if (EditingColour->InheritsComponent(1))
05813                 ReturnVal = CROSSCONSTRAINED_HORZ;
05814                  
05815             if (EditingColour->InheritsComponent(2))
05816             {
05817                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05818                     ReturnVal = CROSSCONSTRAINED_VERT;
05819                 else
05820                     ReturnVal = CROSSCONSTRAINED_BOTH;
05821             }
05822             break;
05823 
05824         default:    // XYZ = C,Y,M
05825             XComponent = SourceColour->Cyan;
05826             YComponent = SourceColour->Yellow;
05827 
05828             if (EditingColour->InheritsComponent(3))
05829                 ReturnVal = CROSSCONSTRAINED_HORZ;
05830                  
05831             if (EditingColour->InheritsComponent(1))
05832             {
05833                 if (ReturnVal == CROSSCONSTRAINED_NONE)
05834                     ReturnVal = CROSSCONSTRAINED_VERT;
05835                 else
05836                     ReturnVal = CROSSCONSTRAINED_BOTH;
05837             }
05838             break;
05839     }
05840 
05841     INT32 SizeXY = SquareRect->Height();
05842     INT32 XTrans = (INT32) ((double)SizeXY * XComponent.MakeDouble());
05843     INT32 YTrans = (INT32) ((double)SizeXY * YComponent.MakeDouble());
05844 
05845     // Translate the cross to the appropriate position
05846     CrossRect.Translate(HalfGridLock(SquareRect->lo.x + XTrans, PixelSize),
05847                         HalfGridLock(SquareRect->lo.y + YTrans, PixelSize));
05848 
05849     *Result = CrossRect;
05850 
05851     if (EditingColour->GetType() == COLOURTYPE_TINT)
05852         return(CROSSCONSTRAINED_BOTH);
05853 
05854     return(ReturnVal);
05855 }
05856 
05857 
05858 
05859 /********************************************************************************************
05860 
05861 >   void ColourEditDlg::RenderPickerCMYK(RenderRegion *pRender, DocRect *VirtualSize,
05862                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
05863 
05864     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
05865     Created:    23/12/94
05866 
05867     Inputs:     pRender - The render region to render the picker in
05868                 VirtualSize - The rectangle defining the coordinate space to draw into
05869                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
05870                 coordinate space; ensures things line up on display pixel boundaries.
05871                 RedrawColours - A pointer to a DialogColourInfo object describing
05872                 OS-friendly drawing colours to be used in redrawing the control.
05873 
05874     Purpose:    Redraws a colour picker control for the colour editor dialogue.
05875                 This is used in the given display mode to display the colour information
05876                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
05877 
05878     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
05879 
05880 ********************************************************************************************/
05881 
05882 void ColourEditDlg::RenderPickerCMYK(RenderRegion *pRender, DocRect *VirtualSize,
05883                                     INT32 PixelSize, DialogColourInfo *RedrawColours)
05884 {
05885     pRender->SaveContext();     // Save the current rendering context
05886     DocColour Trans(COLOUR_TRANS);
05887 
05888     // Determine how much space is left over after the key slider has been placed
05889     INT32 KeySliderLeft = VirtualSize->hi.x - (CROSSRADIUS+PixelSize)*2;
05890 
05891     ERROR3IF(KeySliderLeft < VirtualSize->lo.x,
05892                 "Not enough room to render the colour picker!");
05893 
05894     // First, set up the render region, and fill the background with Dialogue BG colour
05895     pRender->SetLineWidth(0);
05896     pRender->SetLineColour(Trans);
05897 //  pRender->SetFillColour(RedrawColours->DialogBack());
05898 //  pRender->DrawRect(VirtualSize);
05899 
05900     // Draw the cube 'shadow', and calculate where the cube sits
05901     DocRect CubeAvailableSpace(*VirtualSize);
05902     CubeAvailableSpace.hi.x = KeySliderLeft - 2000;
05903 
05904     DocRect SquareRect;
05905     INT32 SizeZ;
05906     DrawCubeShadowAndCalcValues(pRender, &CubeAvailableSpace, PixelSize, RedrawColours,
05907                                 /* TO */ &SquareRect, &SizeZ);
05908 
05909     // Find the source colour definition in RGB space
05910     ColourCMYK SourceColour;
05911     if (EditingColour != NULL)
05912     {
05913 //      ColourContextCMYK *ccCMYK = (ColourContextCMYK*)ColourContext::GetGlobalDefault(COLOURMODEL_CMYK);
05914         ColourContext *ccCMYK = NULL;
05915         BOOL bDeleteCC = GetColourContext(COLOURMODEL_CMYK, &ccCMYK);   
05916         ERROR3IF(ccCMYK == NULL, "Can't get a CMYK colour context");
05917 
05918         ccCMYK->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
05919 
05920         // Delete the colour context if necessary
05921         if (bDeleteCC)
05922             ColourContextList::GetList()->RemoveContext(&ccCMYK);           // Have finished with it
05923     }
05924     else
05925     {
05926         SourceColour.Cyan =SourceColour.Magenta = SourceColour.Yellow = SourceColour.Key = 0;
05927     }
05928 
05929     DocRect FrontFaceRect(SquareRect);      // Remember the old squarerect for later
05930 
05931     // Now, Move the 'SquareRect' down and left so its bottom corner touches the Z axis
05932     // at the appropriate point for the current Z value. (i.e. slice the cube through at
05933     // the place where the slice really is)
05934     if (EditingColour != NULL)
05935     {
05936         FIXED24 ZComponent = SourceColour.Magenta;
05937         if (ColourPickerMode == 1)
05938             ZComponent = SourceColour.Cyan;
05939         else if (ColourPickerMode == 2)
05940             ZComponent = SourceColour.Yellow;
05941 
05942         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
05943         SquareRect.Translate(-ZTrans, ZTrans);
05944         GridLockRect(&SquareRect, PixelSize);
05945     }
05946 
05947 
05948     // Now, composite up the picker square, which is made of 3 squares on top of each
05949     // other, all flat-filled in primary colours, the top 2 having horz/vert trans fills
05950     ColourCMYK BaseColour;
05951     ColourCMYK MidColour;
05952     ColourCMYK TopColour;
05953 
05954     BaseColour.Cyan = BaseColour.Magenta = BaseColour.Yellow = 0;
05955     BaseColour.Key = SourceColour.Key;
05956     memcpy(&MidColour, &BaseColour, sizeof(ColourCMYK));
05957     memcpy(&TopColour, &BaseColour, sizeof(ColourCMYK));
05958 
05959     switch(ColourPickerMode)
05960     {
05961         case 1:     // XYZ = Y,M,C
05962             MidColour.Yellow    = FIXED24(1.0);
05963             TopColour.Magenta   = FIXED24(1.0);
05964             BaseColour.Cyan     = SourceColour.Cyan;
05965             break;
05966 
05967         case 2:     // XYZ = M,C,Y
05968             MidColour.Magenta   = FIXED24(1.0);
05969             TopColour.Cyan      = FIXED24(1.0);
05970             BaseColour.Yellow   = SourceColour.Yellow;
05971             break;
05972 
05973         default:    // XYZ = C,Y,M
05974             MidColour.Cyan      = FIXED24(1.0);
05975             TopColour.Yellow    = FIXED24(1.0);
05976             BaseColour.Magenta  = SourceColour.Magenta;
05977 
05978             ColourPickerMode = 0;       // Ensure any out of value setting is made valid
05979             break;
05980     }
05981 
05982     RenderPickerSquare(pRender, &SquareRect,
05983                         (ColourGeneric *) &BaseColour, (ColourGeneric *) &MidColour,
05984                         (ColourGeneric *) &TopColour,
05985                         COLOURMODEL_CMYK, 2);   // Use CMYK + 'Stain' (Filtering) transparency
05986 
05987     // Place the outline of the front of the cube on top
05988     DocColour CubeFaceGrey(180L, 180L, 180L);
05989     pRender->SetLineColour(CubeFaceGrey);
05990     pRender->SetFillColour(Trans);
05991 
05992     DocCoord BotRightFront(FrontFaceRect.hi.x, FrontFaceRect.lo.y);
05993     pRender->DrawLine(BotRightFront, FrontFaceRect.lo);
05994     pRender->DrawLine(BotRightFront, FrontFaceRect.hi);
05995     pRender->DrawLine(BotRightFront,
05996                     DocCoord(FrontFaceRect.hi.x + SizeZ, FrontFaceRect.lo.y - SizeZ));
05997 
05998 
05999     // Render the Key slider - a white->black grad filled rectangle
06000     LinearFillAttribute KeyGradFill;
06001     KeyGradFill.Colour      = DocColour(0L, 0L, 0L);
06002     KeyGradFill.EndColour   = DocColour(255L, 255L, 255L);
06003     DocCoord ThePoint(VirtualSize->hi.x, VirtualSize->hi.y - (PATCHSIZE + PixelSize*2));
06004     KeyGradFill.SetStartPoint(&ThePoint);
06005     ThePoint = DocCoord(VirtualSize->hi.x, VirtualSize->lo.y);
06006     KeyGradFill.SetEndPoint(&ThePoint);
06007     KeyGradFill.SetEndPoint2(NULL);
06008     pRender->SetFillGeometry(&KeyGradFill, FALSE);
06009     pRender->SetLineColour(Trans);
06010 
06011     Path KeyPath;
06012     KeyPath.Initialise(12, 12);
06013     KeyPath.FindStartOfPath();
06014 
06015     KeyPath.InsertMoveTo(DocCoord(KeySliderLeft, VirtualSize->lo.y));
06016     KeyPath.InsertLineTo(DocCoord(VirtualSize->hi.x, VirtualSize->lo.y));
06017     KeyPath.InsertLineTo(DocCoord(VirtualSize->hi.x, VirtualSize->hi.y - (PATCHSIZE + PixelSize*2)));
06018     KeyPath.InsertLineTo(DocCoord(KeySliderLeft, VirtualSize->hi.y - (PATCHSIZE + PixelSize*2)));
06019     KeyPath.IsFilled = TRUE;
06020     pRender->DrawPath(&KeyPath);        // Render the value/brightness strip
06021 
06022 
06023     // Draw the swap-axes button
06024     DocCoord BitmapPos;
06025     BitmapPos.x = HalfGridLock(FrontFaceRect.hi.x + SizeZ/2, PixelSize);
06026     BitmapPos.y = HalfGridLock(FrontFaceRect.hi.y - SizeZ/2, PixelSize);
06027 
06028     const INT32 BitmapSize = 14 * PixelSize;
06029     DocRect SwapAxesStrip(BitmapPos.x + BitmapSize, BitmapPos.y,
06030                             BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
06031 
06032     GridLockRect(&SwapAxesStrip, PixelSize);
06033 
06034     DocColour SwapAxesFore(0L, 0L, 0L);
06035     DocColour SwapAxesFill(255L, 0L, 255L);
06036     if (ColourPickerMode == 1)
06037         SwapAxesFill = DocColour(0L, 255L, 255L);
06038     else if (ColourPickerMode == 2)
06039         SwapAxesFill = DocColour(255L, 255L, 0L);
06040 
06041     pRender->SetFillColour(SwapAxesFill);
06042     pRender->SetLineColour(SwapAxesFore);
06043     pRender->DrawRect(&SwapAxesStrip);
06044 
06045     // Render the bitmap last, to ensure we don't overwrite it
06046     pRender->DrawBitmap(BitmapPos, _R(IDB_PICKER_SWAPAXIS));
06047 
06048 
06049     DocColour MidGrey(128L, 128L, 128L);
06050     if (EditingColour != NULL)
06051     {
06052         // And draw a drag icon on the current Z position **** !!!! ToDo: Should be a bitmap icon
06053         DocRect ZButton(SquareRect);
06054         ZButton.lo.x = ZButton.hi.x;
06055         ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
06056         ZButton.hi.y = ZButton.lo.y;
06057         ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
06058         GridLockRect(&ZButton, PixelSize);
06059         
06060         pRender->DrawBitmap(ZButton.lo, _R(IDB_PICKER_ZSLIDER));
06061 
06062         // Render marker cross in the appropriate X-Y place for the definition
06063         // of the current editing colour
06064         DocRect CrossRect;
06065         CrossConstraint Constraint = CalcCrossRectCMYK(&SourceColour, &SquareRect, PixelSize, &CrossRect);
06066         RenderCross(pRender, &CrossRect, PixelSize, (Constraint == CROSSCONSTRAINED_BOTH));
06067 
06068         // And render constraint bubbles if necessary
06069         if (Constraint == CROSSCONSTRAINED_HORZ)
06070         {
06071             INT32 MidY = (CrossRect.lo.y + CrossRect.hi.y) / 2;
06072             RenderConstraint(pRender, DocCoord(SquareRect.lo.x, MidY), DocCoord(SquareRect.hi.x, MidY));
06073         }
06074         else if (Constraint == CROSSCONSTRAINED_VERT)
06075         {
06076             INT32 MidX = (CrossRect.lo.x + CrossRect.hi.x) / 2;
06077             RenderConstraint(pRender, DocCoord(MidX, SquareRect.lo.y), DocCoord(MidX, SquareRect.hi.y));
06078         }
06079 
06080         // And a cross on the Key slider too
06081         INT32 YTrans = (INT32) ((double)(VirtualSize->Height() - (PATCHSIZE + PixelSize*2)) *
06082                                             SourceColour.Key.MakeDouble());
06083         CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
06084         CrossRect.Translate(HalfGridLock(VirtualSize->hi.x - (CROSSRADIUS+PixelSize), PixelSize),
06085                             HalfGridLock(VirtualSize->lo.y + YTrans, PixelSize));
06086 
06087         BOOL Shaded = (EditingColour->GetType() == COLOURTYPE_TINT) ||
06088                         (EditingColour->InheritsComponent(4));
06089         RenderCross(pRender, &CrossRect, PixelSize, Shaded);
06090     }
06091 
06092     pRender->RestoreContext();
06093 }
06094 
06095 
06096 
06097 /********************************************************************************************
06098 
06099     void ColourEditDlg::RenderPickerSliderH(RenderRegion *pRender, DocRect *SliderRect,
06100                                             INT32 PixelSize, FIXED24 DisplayValue,
06101                                             DocColour *LeftCol, DocColour *RightCol
06102                                             DocColour *TopLeftCol, DocColour *TopRightCol,
06103                                             BOOL Shaded = FALSE)
06104 
06105     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06106     Created:    13/12/94
06107 
06108     Inputs:     pRender - The render region to render the picker in
06109                 SliderRect - The rectangle in which the slider is to be rendered
06110                 DisplayValue - The value (0.0 - 1.0) to display on the slider
06111                 LeftCol - NULL or The colour to pot at the (bottom) left end of the slider
06112                 RightCol - NULL or The colour to plot at the (bottom) right end of the slider
06113                 TopLeftCol - The colour to pot at the (top) left end of the slider
06114                 TopRightCol - The colour to plot at the (top) right end of the slider
06115                 Shaded - TRUE if the marker cross should be shown shaded
06116 
06117     Purpose:    Redraws a horizontal slider in a colour picker control.
06118                 This generic method is used to draw a slider for a colour component.
06119                 Generally, the slider will be a linear grad filled rectangle which
06120                 shades from a colour with that component = 0.0 to 1.0   
06121 
06122     Notes:      The slider is a split-display.
06123                 It shows two horizontal grad-fills: The top half shows a fill from
06124                 TopLeftCol to TopRight Col, while the bottom half shows a fill from
06125                 LeftCol to RightCol. If LeftCol and/or RightCol are NULL, the strip
06126                 will be filled with a single fill, from TopLeft to TopRight colours.
06127 
06128                 This will use the line width/colour as set on entry, so you should
06129                 set line width = 0 and line colour = COLOUR_TRANS before calling this fn
06130 
06131                 The marker cross will only be rendered if EditingColour != NULL
06132 
06133     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
06134 
06135 ********************************************************************************************/
06136 
06137 void ColourEditDlg::RenderPickerSliderH(RenderRegion *pRender, DocRect *SliderRect,
06138                                         INT32 PixelSize, FIXED24 DisplayValue,
06139                                         DocColour *LeftCol, DocColour *RightCol,
06140                                         DocColour *TopLeftCol, DocColour *TopRightCol,
06141                                         BOOL Shaded)
06142 {
06143     ERROR3IF(pRender == NULL || SliderRect == NULL ||
06144              TopLeftCol == NULL || TopRightCol == NULL,
06145              "ColourEditDlg::RenderPickerSliderH - NULL parameters are illegal");
06146 
06147     pRender->SaveContext();     // Save the current rendering context
06148 
06149     INT32 MidY = (SliderRect->lo.y + SliderRect->hi.y) / 2;
06150 
06151     LinearFillAttribute BottomGradFill;
06152     Path RectPath;
06153     if (LeftCol != NULL && RightCol != NULL)
06154     {
06155         // Are in strip mode, so... create a grad fill for the bottom strip
06156         BottomGradFill.Colour       = *LeftCol;
06157         BottomGradFill.EndColour    = *RightCol;
06158         DocCoord ThePoint(SliderRect->lo.x, (SliderRect->lo.y + SliderRect->hi.y) / 2);
06159         BottomGradFill.SetStartPoint(&ThePoint);
06160         ThePoint = DocCoord(SliderRect->hi.x, (SliderRect->lo.y + SliderRect->hi.y) / 2);
06161         BottomGradFill.SetEndPoint(&ThePoint);
06162         BottomGradFill.SetEndPoint2(NULL);
06163         pRender->SetFillGeometry(&BottomGradFill, FALSE);
06164 
06165         // Draw the rectangle - done as a path so we can draw with grad-fill
06166         RectPath.Initialise(12, 12);
06167         RectPath.FindStartOfPath();
06168 
06169         RectPath.InsertMoveTo(SliderRect->lo);
06170         RectPath.InsertLineTo(DocCoord(SliderRect->hi.x, SliderRect->lo.y));
06171         RectPath.InsertLineTo(DocCoord(SliderRect->hi.x, MidY));
06172         RectPath.InsertLineTo(DocCoord(SliderRect->lo.x, MidY));
06173         RectPath.IsFilled = TRUE;
06174 
06175         pRender->DrawPath(&RectPath);           // Render the bottom strip
06176     }
06177 
06178     // Create a grad fill for the top strip
06179     LinearFillAttribute TopGradFill;
06180     TopGradFill.Colour      = *TopLeftCol;
06181     TopGradFill.EndColour   = *TopRightCol;
06182     DocCoord ThePoint(SliderRect->lo.x, (SliderRect->lo.y + SliderRect->hi.y) / 2);
06183     TopGradFill.SetStartPoint(&ThePoint);
06184     ThePoint = DocCoord(SliderRect->hi.x, (SliderRect->lo.y + SliderRect->hi.y) / 2);
06185     TopGradFill.SetEndPoint(&ThePoint);
06186     TopGradFill.SetEndPoint2(NULL);
06187 
06188     pRender->SetFillGeometry(&TopGradFill, FALSE);
06189 
06190     Path TopRectPath;
06191     TopRectPath.Initialise(12, 12);
06192     TopRectPath.FindStartOfPath();
06193 
06194     if (LeftCol != NULL && RightCol != NULL)
06195     {
06196         // Doing split-line display, so rect is bottom half of slider
06197         TopRectPath.InsertMoveTo(DocCoord(SliderRect->lo.x, MidY));
06198         TopRectPath.InsertLineTo(DocCoord(SliderRect->hi.x, MidY));
06199         TopRectPath.InsertLineTo(SliderRect->hi);
06200         TopRectPath.InsertLineTo(DocCoord(SliderRect->lo.x, SliderRect->hi.y));
06201     }
06202     else
06203     {
06204         // Not doing split-line display, so rect is entire slider
06205         TopRectPath.InsertMoveTo(SliderRect->lo);
06206         TopRectPath.InsertLineTo(DocCoord(SliderRect->hi.x, SliderRect->lo.y));
06207         TopRectPath.InsertLineTo(SliderRect->hi);
06208         TopRectPath.InsertLineTo(DocCoord(SliderRect->lo.x, SliderRect->hi.y));
06209     }
06210 
06211     TopRectPath.IsFilled = TRUE;
06212     pRender->DrawPath(&TopRectPath);        // Render the top strip
06213 
06214 
06215     pRender->RestoreContext();              // Restore original attribute context
06216 
06217     
06218     if (EditingColour != NULL)
06219     {
06220         if (DisplayValue < FIXED24(0.0))    // Clip the value to 0-1 range
06221             DisplayValue = 0;
06222 
06223         if (DisplayValue > FIXED24(1.0))
06224             DisplayValue = FIXED24(1.0);
06225 
06226         DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
06227         INT32 TransX = SliderRect->lo.x + (INT32) ((double)SliderRect->Width() *
06228                                                   DisplayValue.MakeDouble());
06229         INT32 TransY = (SliderRect->lo.y + SliderRect->hi.y) / 2;
06230         CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
06231         RenderCross(pRender, &CrossRect, PixelSize, Shaded);
06232     }
06233 }
06234 
06235 
06236 
06237 /********************************************************************************************
06238 
06239 >   void ColourEditDlg::RenderPickerDefault(RenderRegion *pRender, DocRect *VirtualSize,
06240                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
06241 
06242     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06243     Created:    13/12/94
06244 
06245     Inputs:     pRender - The render region to render the picker in
06246                 VirtualSize - The rectangle defining the coordinate space to draw into
06247                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
06248                 coordinate space; ensures things line up on display pixel boundaries.
06249                 RedrawColours - A pointer to a DialogColourInfo object describing
06250                 OS-friendly drawing colours to be used in redrawing the control.
06251 
06252     Purpose:    Redraws a colour picker control for the colour editor dialogue.
06253                 This is used in the given display mode to display the colour information
06254                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
06255 
06256     Notes:      This is called as a default method for all colour models which are not
06257                 specifically provided for by the editor. It shows generic horizontal
06258                 sliders for each of the available colour components. Some colour models
06259                 (e.g. Greyscale) will always use this default, as it is fine for them.
06260 
06261     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
06262 
06263 ********************************************************************************************/
06264 
06265 void ColourEditDlg::RenderPickerDefault(RenderRegion *pRender, DocRect *VirtualSize,
06266                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
06267 {
06268     pRender->SaveContext();     // Save the current rendering context
06269 
06270     // Set rendering defaults: Fill paths only, and fill background with window grey
06271     DocColour Trans(COLOUR_TRANS);
06272     pRender->SetLineWidth(0);
06273     pRender->SetLineColour(Trans);
06274 //  pRender->SetFillColour(RedrawColours->DialogBack());
06275 //  pRender->DrawRect(VirtualSize);
06276 
06277     ColourGeneric GradFillDef;              // Colour for slider gradfill endpoint
06278     GradFillDef.Component1 =                // Initialise to all components = 0
06279         GradFillDef.Component2 = 
06280         GradFillDef.Component3 = 
06281         GradFillDef.Component4 = 0;
06282 
06283     ColourGeneric EditingColDef;            // Colour holding the current component values
06284     EditingColDef.Component1 =              // Default to all comps=0 in case of error
06285         EditingColDef.Component2 =          // (and in case EditingCOlour == NULL)
06286         EditingColDef.Component3 = 
06287         EditingColDef.Component4 = 0;
06288 
06289 //  ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
06290     ColourContext *cc = NULL;
06291     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
06292     if (cc == NULL)
06293     {
06294         pRender->RestoreContext();
06295         ERROR2RAW("Can't get a colour context for the DisplayModel!");
06296         return;
06297     }
06298 
06299     // Convert the editing colour (if any) into the current display model
06300     if (EditingColour != NULL)
06301         cc->ConvertColour(EditingColour, &EditingColDef);
06302 
06303     // Get a sneaky 'array of 4 components' to allow array-access into the colour definition
06304     ColourValue *ECComponent = (ColourValue *) &EditingColDef;  // EC =  EditingColour
06305     ColourValue *GFComponent = (ColourValue *) &GradFillDef;    // GF = GradFill Colour
06306 
06307     // Create a colour in the current DisplayModel with all components zero (probably
06308     // black (RGB/Grey) or white (CMYK))
06309     DocColour LeftColour(DisplayModel, &GradFillDef);
06310     DocColour TopLeftColour(DisplayModel, &GradFillDef);
06311     DocColour RightColour;
06312     DocColour TopRightColour;
06313 
06314     // Get the slider rectangle widths. The height is fixed/moved during the loop below
06315     DocRect SliderRect(*VirtualSize);
06316     SliderRect.hi.y -= PATCHSIZE + (PixelSize * 2);     // Allow space for the current colour patch
06317 
06318     // Count how many components we have to display
06319     INT32 NumComponents = 0;
06320     INT32 ComponentIndex;
06321     for (ComponentIndex = 1; ComponentIndex <= 4; ComponentIndex++)
06322     {
06323         if (cc->GetComponentName(ComponentIndex, NULL))
06324             NumComponents++;
06325     }
06326 
06327     // Calculate slider sizes and spacing
06328     INT32 SliderHeight = GetSliderHeight(SliderRect.Height(), NumComponents);
06329     INT32 SliderGap = GetSliderGap(SliderRect.Height(), NumComponents);
06330 
06331     // And move the top down by half a SliderGap, so the sliders are centered vertically
06332     SliderRect.hi.y -= SliderGap / 2;
06333 
06334     // Draw a slider for each component supplied in the current DisplayModel
06335     for (ComponentIndex = 0; ComponentIndex <= 3; ComponentIndex++)
06336     {
06337         // Ensure slider rect is the correct height
06338         SliderRect.lo.y = SliderRect.hi.y - SliderHeight;
06339 
06340         // If this component is available/used in this colour model, render it
06341         if (cc->GetComponentName(ComponentIndex+1, NULL))
06342         {
06343             // TopLeft colour is static (always all zeros)
06344             // We calculate the other 3 colours here: 
06345             //   TopRight is all zeros except this component is 1.0
06346             //   Left/Right go from EditingColour with this component = 0.0 to this = 1.0
06347             GradFillDef.Component1 =        // Initialise to all components = 0
06348                 GradFillDef.Component2 = 
06349                 GradFillDef.Component3 = 
06350                 GradFillDef.Component4 = 0;
06351             GFComponent[ComponentIndex] = FIXED24(1.0);
06352             TopRightColour = DocColour(DisplayModel, &GradFillDef);
06353 
06354             // Make the slider use the colour definition with this component from 0 to 1
06355             // (e.g. a red will give a green slider which shades from red to yellow)
06356             memcpy(&GradFillDef, &EditingColDef, sizeof(ColourGeneric));
06357             GFComponent[ComponentIndex] = FIXED24(0.0);
06358             LeftColour = DocColour(DisplayModel, &GradFillDef);
06359 
06360             GFComponent[ComponentIndex] = FIXED24(1.0);
06361             RightColour = DocColour(DisplayModel, &GradFillDef);
06362 
06363             BOOL Shaded = EditingColour == NULL ||
06364                             ((EditingColour->GetType() == COLOURTYPE_TINT) ||
06365                             EditingColour->InheritsComponent(ComponentIndex+1));
06366 
06367             // Render the slider
06368             if (SplitLineDisplay && NumComponents > 1)
06369             {
06370                 // We want a split display for each line, with a gradfill showing
06371                 // only this component (on top), and a gradfill showing the range of
06372                 // colours you can get by changing only this component (below).
06373                 RenderPickerSliderH(pRender, &SliderRect,
06374                                     PixelSize, ECComponent[ComponentIndex],
06375                                     &LeftColour, &RightColour,
06376                                     &TopLeftColour, &TopRightColour,
06377                                     Shaded);
06378             }
06379             else
06380             {
06381                 // We want a non-split display. This redraws faster, as it only shows
06382                 // the grad fill for this component. If there is only one colour component
06383                 // (e.g. Greyscale) then the split display will look identical, so we
06384                 // use the faster redraw method.
06385                 RenderPickerSliderH(pRender, &SliderRect,
06386                                     PixelSize, ECComponent[ComponentIndex],
06387                                     NULL, NULL,
06388                                     &TopLeftColour, &TopRightColour,
06389                                     Shaded);
06390             }
06391         }
06392 
06393         // Move down to the next slider rectangle position
06394         SliderRect.hi.y = SliderRect.lo.y - SliderGap;
06395     }
06396 
06397     // Finally, return the render region context to its original state
06398     pRender->RestoreContext();
06399 
06400     // Delete the colour context if necessary
06401     if (bDeleteCC)
06402     {
06403         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
06404     }
06405 }
06406 
06407 
06408 
06409 /********************************************************************************************
06410 
06411 >   void ColourEditDlg::RenderPickerTint(RenderRegion *pRender, DocRect *VirtualSize,
06412                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
06413 
06414     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06415     Created:    2/10/95
06416 
06417     Inputs:     pRender - The render region to render the picker in
06418                 VirtualSize - The rectangle defining the coordinate space to draw into
06419                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
06420                 coordinate space; ensures things line up on display pixel boundaries.
06421                 RedrawColours - A pointer to a DialogColourInfo object describing
06422                 OS-friendly drawing colours to be used in redrawing the control.
06423 
06424     Purpose:    Redraws a colour picker control for the colour editor dialogue.
06425                 This is used in the given display mode to display the colour information
06426                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
06427 
06428     Notes:      This is called to render the picker for link and shade colours
06429                 It simply gives a single slider which goes between the parent colour and
06430                 white/black.
06431 
06432     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
06433 
06434 ********************************************************************************************/
06435 
06436 void ColourEditDlg::RenderPickerTint(RenderRegion *pRender, DocRect *VirtualSize,
06437                                         INT32 PixelSize, DialogColourInfo *RedrawColours)
06438 {
06439     ERROR3IF(EditingColour->GetType() != COLOURTYPE_TINT,
06440                 "ColourEditDlg::RenderPickerTint called on non-tint/shade colour!");
06441 
06442     pRender->SaveContext();     // Save the current rendering context
06443 
06444     // Set rendering defaults: Fill paths only, and fill background with window grey
06445     pRender->SetLineWidth(0);
06446     pRender->SetLineColour(COLOUR_TRANS);
06447 
06448     // Calculate the slider rectangle
06449     const INT32 SliderHeight = 18000;
06450     DocRect SliderRect(*VirtualSize);
06451     SliderRect.Inflate(0, -(VirtualSize->Height() - SliderHeight) / 2);
06452 
06453     // And the grad fill colours, and the text to be drawn
06454     String_64 SliderText;
06455 
06456     DocColour LeftColour;
06457 //  if (EditingColour->TintIsShade())
06458 //  {
06459 //      LeftColour = DocColour(COLOUR_BLACK);
06460 //      SliderText.MakeMsg(_R(IDS_SHADEOFCOLOUR), (TCHAR *) *(EditingColour->FindLinkedParent()->GetName()));
06461 //  }
06462 //  else
06463     {
06464         LeftColour = DocColour(255L, 255L, 255L);
06465         SliderText.MakeMsg(_R(IDS_TINTOFCOLOUR), (TCHAR *) *(EditingColour->FindLinkedParent()->GetName()));
06466     }
06467 
06468     DocColour RightColour;
06469     RightColour.MakeRefToIndexedColour(EditingColour->FindLinkedParent());
06470 
06471     DocRect TextRect(SliderRect);
06472     TextRect.Translate(0, SliderHeight);
06473     pRender->SetFixedSystemTextColours(&RedrawColours->TextFore(), &RedrawColours->DialogBack());
06474     pRender->DrawFixedSystemText((StringBase *) &SliderText, TextRect);
06475 
06476     FIXED24 DisplayValue = (EditingColour->TintIsShade()) ?
06477                                 EditingColour->GetShadeValueY() : EditingColour->GetTintValue();
06478 
06479     // And render the slider
06480     RenderPickerSliderH(pRender, &SliderRect,
06481                         PixelSize, DisplayValue,
06482                         NULL, NULL,
06483                         &LeftColour, &RightColour,
06484                         FALSE);
06485 
06486     // Finally, return the render region context to its original state
06487     pRender->RestoreContext();
06488 }
06489 
06490 
06491 
06492 /********************************************************************************************
06493 
06494 >   void ColourEditDlg::RenderPickerShade(RenderRegion *pRender, DocRect *VirtualSize,
06495                             INT32 PixelSize, DialogColourInfo *RedrawColours,
06496                             DocRect *pClipRect)
06497 
06498     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06499     Created:    13/10/95
06500 
06501     Inputs:     pRender - The render region to render the picker in
06502                 
06503                 VirtualSize - The rectangle defining the coordinate space to draw into
06504                 
06505                 PixelSize - The size of a pixel as mapped into the MILLIPOINT VirtualSize
06506                 coordinate space; ensures things line up on display pixel boundaries.
06507                 
06508                 RedrawColours - A pointer to a DialogColourInfo object describing
06509                 OS-friendly drawing colours to be used in redrawing the control.
06510 
06511                 pClipRect - The area to be redrawn, in (0,0)->(dx,dy) dialog millipoint coords
06512 
06513     Purpose:    Redraws a colour picker control for the colour editor dialogue.
06514                 This is used in the given display mode to display the colour information
06515                 in a useful format. e.g. in HSV mode, a wheel and slider arrangement.
06516 
06517     SeeAlso:    ColourEditDlg::RenderControl; ColourEditDlg::RenderPickerDefault
06518 
06519 ********************************************************************************************/
06520 
06521 void ColourEditDlg::RenderPickerShade(RenderRegion *pRender, DocRect *VirtualSize,
06522                                     INT32 PixelSize, DialogColourInfo *RedrawColours,
06523                                     DocRect *pClipRect)
06524 {
06525     pRender->SaveContext();     // Save the current rendering context
06526 
06527     // Set defaults: Fill paths only, and fill background with window grey
06528     DocColour Trans(COLOUR_TRANS);
06529 
06530     pRender->SetLineWidth(0);
06531     pRender->SetLineColour(Trans);
06532 
06533     // First, do a Hue slider (a rainbow grad filled rectangle along the bottom)
06534     DocRect HueRect;
06535     DocRect ValSatSquare;
06536     CalculateHSVPickerRects(VirtualSize, PixelSize, &HueRect, &ValSatSquare);
06537 
06538     // Draw the Saturation vs. Value square
06539     Path SquarePath;
06540     LinearFillAttribute ValueGradFill;
06541     LinearTranspFillAttribute TransFill;
06542 
06543     ColourHSVT ColourDef;
06544     BaseDocument *ScopeDocument = ParentList->GetParentDocument();
06545     ColourContextArray *Contexts = ScopeDocument->GetDefaultColourContexts();
06546     ERROR3IF(Contexts == NULL, "Document default contexts not defined?!");
06547 
06548     ColourContextHSVT *ccHSV = (ColourContextHSVT *)
06549                                         Contexts->Context[COLOURMODEL_HSVT];
06550     ERROR3IF(ccHSV == NULL, "Document default context for HSV not defined?!");
06551 
06552     // We need to use the PARENT's Hue as a basis for our shade display, because otherwise
06553     // as we change the child colour to a greyscale/black, it loses its Hue and the picker
06554     // flashes different colours. We also use this definition below to show the parent "cross"
06555     ColourHSVT ParentDef;
06556     ParentDef.Hue = 0;
06557     ParentDef.Saturation = ParentDef.Value = FIXED24(1.0);
06558 
06559     if (EditingColour != NULL)
06560     {
06561         ccHSV->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
06562 
06563         if (EditingColour->FindLastLinkedParent() != NULL)
06564             ccHSV->ConvertColour(EditingColour->FindLastLinkedParent(), (ColourGeneric *) &ParentDef);
06565     }
06566     else
06567     {
06568         // No colour - default to white
06569         ColourDef.Hue = 0;
06570         ColourDef.Saturation = ColourDef.Value = FIXED24(1.0);
06571     }
06572 
06573     if (pClipRect->IsIntersectedWith(ValSatSquare))     // If we need to redraw this bit...
06574     {
06575         // Copy the colour def, and force it's Value & Sat components to 1.0
06576         ColourHSVT TempColourDef;
06577         TempColourDef.Hue   = ParentDef.Hue;
06578         TempColourDef.Value = TempColourDef.Saturation = FIXED24(1.0);
06579 
06580         pRender->SaveContext();
06581         
06582         ValueGradFill.Colour    = DOCCOLOUR_HSVT(&TempColourDef);
06583         ValueGradFill.EndColour = DocColour(255L, 255L, 255L);
06584 
06585         DocCoord ThePoint(ValSatSquare.lo.x, ValSatSquare.hi.y);
06586         ValueGradFill.SetStartPoint(&ThePoint);
06587         ThePoint = DocCoord(ValSatSquare.hi.x, ValSatSquare.hi.y);
06588         ValueGradFill.SetEndPoint(&ThePoint);
06589         ValueGradFill.SetEndPoint2(NULL);
06590 
06591         pRender->SetFillGeometry(&ValueGradFill, FALSE);            // Set Grad-filled
06592 
06593         SquarePath.Initialise(12, 12);
06594         SquarePath.FindStartOfPath();
06595 
06596         SquarePath.InsertMoveTo(ValSatSquare.lo);
06597         SquarePath.InsertLineTo(DocCoord(ValSatSquare.hi.x, ValSatSquare.lo.y));
06598         SquarePath.InsertLineTo(ValSatSquare.hi);
06599         SquarePath.InsertLineTo(DocCoord(ValSatSquare.lo.x, ValSatSquare.hi.y));
06600         SquarePath.IsFilled = TRUE;
06601 
06602         pRender->DrawPath(&SquarePath);     // Render the value square
06603 
06604         // Render a white linear-grad-transparency square over the top to get the
06605         // effect of the Saturation gradient
06606         DocColour black(0,0,0);
06607         pRender->SetFillColour(black);
06608 
06609         // Set transparency to circular 0% at center, 100% at radius, && plot it
06610         TransFill.SetStartPoint(&ValSatSquare.hi);
06611         ThePoint = DocCoord(ValSatSquare.hi.x, ValSatSquare.lo.y);
06612         TransFill.SetEndPoint(&ThePoint);
06613         TransFill.SetEndPoint2(NULL);
06614         TransFill.Transp        = 255;
06615         TransFill.EndTransp     = 0;
06616         TransFill.TranspType    = TT_StainGlass;        // 'Stained glass' transparency
06617 
06618         pRender->SetTranspFillGeometry(&TransFill, FALSE);
06619 
06620         pRender->DrawPath(&SquarePath);     // Render the saturation square
06621 
06622         pRender->RestoreContext();
06623     }
06624 
06625     if (EditingColour != NULL)
06626     {
06627         // Render a parent colour marker to remind the user where the parent definition is
06628 
06629         DocRect CrossRect = DocRect(-PCROSSRADIUS, -PCROSSRADIUS, PCROSSRADIUS, PCROSSRADIUS);
06630         INT32 TransX = ValSatSquare.hi.x - (INT32)
06631                     ((double)ValSatSquare.Width() * ParentDef.Saturation.MakeDouble());
06632         INT32 TransY = ValSatSquare.lo.y + (INT32)
06633                     ((double)ValSatSquare.Height() * ParentDef.Value.MakeDouble());
06634         CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
06635 
06636         RenderParentCross(pRender, &CrossRect, PixelSize);
06637 
06638 
06639         // Render marker crosses in the appropriate places for the definition
06640         // of the current editing colour - the shade Sat/Val crosses
06641         CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
06642         TransX = ValSatSquare.hi.x - (INT32)
06643                     ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
06644         TransY = ValSatSquare.lo.y + (INT32)
06645                     ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
06646 
06647         CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
06648 
06649         RenderCross(pRender, &CrossRect, PixelSize, FALSE);
06650     }
06651     return;
06652 }
06653 
06654 
06655 
06656 /********************************************************************************************
06657 
06658 >   void ColourEditDlg::RenderControl(UINT32 GadgetToRender, ReDrawInfoType* RedrawInfo)
06659 
06660     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06661     Created:    1/11/94
06662 
06663     Inputs:     GadgetToRender - The gadget that needs to be redrawn
06664                 ExtraInfo - The structure that has the extra data we need to start rendering
06665 
06666     Purpose:    Renders the controls that are kernel-redrawn (The colour 'picker' section,
06667                 and the two (original and new colour definitions) colour patches)
06668 
06669     Notes:      If EditingColour is NULL (as is the case when the window is shaded) the
06670                 redraw is changed appropriately (pickers show values appropriate to 
06671                 display of 'white', position marker crosses are not drawn, an colour
06672                 patches show mid grey).
06673 
06674 ********************************************************************************************/
06675 
06676 void ColourEditDlg::RenderControl(UINT32 GadgetToRender, ReDrawInfoType* RedrawInfo)
06677 {
06678     // Use a virtual coord space of (0,0) to (dx, dy)
06679     DocRect VirtualSize(0, 0, RedrawInfo->dx, RedrawInfo->dy);
06680 
06681     // Get a render region to use. The TRUE parameter specifies that we want to use
06682     // the same colour correction/separation contexts as the currently selected DocView,
06683     // so that we display "document colour" in an appropriate manner.
06684     RenderRegion *pRender;
06685     if (GadgetToRender == _R(IDC_EDIT_PICKER))
06686         pRender = CreateGRenderRegion(&VirtualSize, RedrawInfo, TRUE);
06687     else
06688         pRender = CreateOSRenderRegion(&VirtualSize, RedrawInfo, TRUE);
06689     // I would ENSURE pRender != NULL, but it's perfectly legal if we get a 0-width
06690     // redraw cliprect, etc, so we basically have to ignore NULL returns.
06691 
06692     INT32 PixelSize = 72000 / RedrawInfo->Dpi;      // Size of output pixel in millipoints
06693 
06694     if (pRender != NULL)
06695     {
06696         // Interlock redraw with the drag manager to ensure we don't redraw over any drag blobs
06697         DragManagerOp::RedrawStarting(WindowID, GadgetToRender);
06698 
06699         DialogColourInfo RedrawColours;         // Object supplying Host OS redraw colours
06700 
06701         if (GadgetToRender == _R(IDC_EDIT_PICKER))
06702         {
06703             // Draw a narrow plinth around the edge of the control
06704             pRender->SaveContext();
06705 
06706             pRender->SetLineWidth(0);
06707             pRender->SetFillColour(RedrawColours.DialogBack());
06708             pRender->SetLineColour(RedrawColours.ButtonShadow());
06709             pRender->DrawRect(&VirtualSize);
06710 
06711             pRender->SetLineColour(RedrawColours.ButtonHighlight());
06712             pRender->DrawLine(VirtualSize.hi, DocCoord(VirtualSize.hi.x, VirtualSize.lo.y));
06713             pRender->DrawLine(DocCoord(VirtualSize.hi.x, VirtualSize.lo.y), VirtualSize.lo);
06714 
06715             // And deflate the rect by 2 pixels
06716             VirtualSize.Inflate(-PixelSize * 4);
06717 
06718             // Now draw the original/current colour patch in the top right corner
06719             DocRect PatchRect(VirtualSize);
06720             PatchRect.lo.x = PatchRect.hi.x - PATCHSIZE;
06721             PatchRect.lo.y = PatchRect.hi.y - PATCHSIZE;
06722             GridLockRect(&PatchRect, PixelSize);
06723 
06724             DocColour Orig;
06725             if (EditingColour == NULL)
06726                 Orig = DocColour(128, 128, 128);
06727             else
06728                 Orig.MakeRefToIndexedColour(&OriginalColour);
06729 
06730             DocColour PatchCol;
06731             if (EditingColour == NULL)
06732                 PatchCol = DocColour(128, 128, 128);
06733             else
06734                 PatchCol.MakeRefToIndexedColour(EditingColour);
06735 
06736             // Patches are horizontal if the colour model is not HSV
06737             BOOL HorzPatch = (DisplayModel != COLOURMODEL_HSVT);
06738             
06739             // But this setting is overridden for the special tint and shade modes
06740             if (EditingColour != NULL && EditingColour->GetType() == COLOURTYPE_TINT)
06741             {
06742                 if (EditingColour->TintIsShade())
06743                     HorzPatch = FALSE;
06744                 else
06745                     HorzPatch = TRUE;
06746             }
06747 
06748             pRender->SetLineWidth(0);
06749             pRender->SetLineColour(COLOUR_BLACK);
06750             if (HorzPatch)
06751                 pRender->SetFillColour(PatchCol);
06752             else
06753                 pRender->SetFillColour(Orig);
06754             pRender->DrawRect(&PatchRect);
06755 
06756             if (HorzPatch)
06757             {
06758                 // Move the patch to the left for the second square
06759                 PatchRect.Translate(-PATCHSIZE, 0);
06760                 pRender->SetFillColour(Orig);
06761             }
06762             else
06763             {
06764                 // Move the patch down for the second square
06765                 PatchRect.Translate(0, -PATCHSIZE);
06766                 pRender->SetFillColour(PatchCol);
06767             }
06768 
06769             pRender->DrawRect(&PatchRect);
06770 /*
06771 //          DocColour Trans(COLOUR_TRANS);
06772 //          pRender->SetLineColour(Trans);
06773             pRender->SetFillColour(Orig);
06774             Path TriPath;
06775             TriPath.Initialise(12, 12);
06776             TriPath.FindStartOfPath();
06777             TriPath.InsertMoveTo(PatchRect.lo);
06778             TriPath.InsertLineTo(DocCoord(PatchRect.lo.x, PatchRect.hi.y));
06779             TriPath.InsertLineTo(PatchRect.hi);
06780             TriPath.IsFilled = TRUE;
06781             pRender->DrawPath(&TriPath);        // Render the value square
06782 */
06783             pRender->RestoreContext();
06784         
06785 
06786             if (EditingColour != NULL && EditingColour->GetType() == COLOURTYPE_TINT)   // Tint or shade
06787             {
06788                 if (EditingColour->TintIsShade())
06789                 {
06790                     RenderPickerShade(pRender, &VirtualSize, PixelSize, &RedrawColours,
06791                                             RedrawInfo->pClipRect);
06792                 }
06793                 else
06794                     RenderPickerTint(pRender, &VirtualSize, PixelSize, &RedrawColours);
06795             }
06796             else
06797             {
06798                 switch (DisplayModel)
06799                 {
06800                     case COLOURMODEL_RGBT:
06801                     case COLOURMODEL_WEBRGBT:
06802                         if (Use3DDisplay)
06803                             RenderPickerRGB(pRender, &VirtualSize, PixelSize, &RedrawColours);
06804                         else
06805                             RenderPickerDefault(pRender, &VirtualSize, PixelSize, &RedrawColours);
06806                         break;
06807     
06808                     case COLOURMODEL_CMYK:
06809                         if (Use3DDisplay)
06810                             RenderPickerCMYK(pRender, &VirtualSize, PixelSize, &RedrawColours);
06811                         else
06812                             RenderPickerDefault(pRender, &VirtualSize, PixelSize, &RedrawColours);
06813                         break;
06814     
06815                     case COLOURMODEL_HSVT:
06816                         RenderPickerHSV(pRender, &VirtualSize, PixelSize, &RedrawColours,
06817                                             RedrawInfo->pClipRect);
06818                         break;
06819     
06820                     default:
06821                         RenderPickerDefault(pRender, &VirtualSize, PixelSize, &RedrawColours);
06822                         break;
06823                 }
06824             }
06825         }
06826 #if 0
06827         else if (GadgetToRender == _R(IDC_EDIT_PATCH))                      // Old/New/Parent-colour patch
06828         {
06829             pRender->SaveContext();
06830 
06831             DocColour Trans(COLOUR_TRANS);
06832             DocColour Orig;
06833             if (EditingColour == NULL)
06834                 Orig = DocColour(128, 128, 128);
06835             else
06836                 Orig.MakeRefToIndexedColour(&OriginalColour);
06837 
06838             pRender->SetLineWidth(0);
06839             pRender->SetLineColour(Trans);
06840 
06841             DocColour PatchCol;
06842             if (EditingColour == NULL)
06843                 PatchCol = DocColour(128, 128, 128);
06844             else
06845                 PatchCol.MakeRefToIndexedColour(EditingColour);
06846 
06847             pRender->SetFillColour(PatchCol);
06848             pRender->DrawRect(&VirtualSize);
06849 
06850             pRender->SetFillColour(Orig);
06851             Path TriPath;
06852             TriPath.Initialise(12, 12);
06853             TriPath.FindStartOfPath();
06854             TriPath.InsertMoveTo(VirtualSize.lo);
06855             TriPath.InsertLineTo(DocCoord(VirtualSize.lo.x, VirtualSize.hi.y));
06856             TriPath.InsertLineTo(DocCoord(VirtualSize.hi.x, VirtualSize.lo.y));
06857             TriPath.IsFilled = TRUE;
06858             pRender->DrawPath(&TriPath);        // Render the value square
06859 
06860 
06861 #if 0
06862             INT32 PatchHeight = VirtualSize.Height() / 3;
06863 
06864             DocRect TheRect(VirtualSize);
06865             TheRect.lo.y = TheRect.hi.y - PatchHeight;
06866             pRender->DrawRect(&TheRect);
06867 
06868             DocColour PatchCol;
06869             if (EditingColour == NULL)
06870                 PatchCol = DocColour(128, 128, 128);
06871             else
06872                 PatchCol.MakeRefToIndexedColour(EditingColour);
06873 
06874             pRender->SetFillColour(PatchCol);
06875             TheRect.Translate(0, -PatchHeight); // Move the patch rect down and plot
06876             pRender->DrawRect(&TheRect);
06877 
06878             if (EditingColour != NULL && EditingColour->FindLinkedParent() != NULL)
06879                 PatchCol.MakeRefToIndexedColour(EditingColour->FindLinkedParent());
06880 
06881             pRender->SetFillColour(PatchCol);
06882             TheRect.Translate(0, -PatchHeight); // Move the patch rect down and plot
06883             pRender->DrawRect(&TheRect);
06884 #endif
06885 
06886             pRender->RestoreContext();
06887         }
06888 #endif
06889         else
06890         {
06891             ERROR3("Render request for unsupported kernel-rendered control!");
06892         }
06893 
06894 
06895         // Get rid of the render region
06896         if (GadgetToRender == _R(IDC_EDIT_PICKER))
06897             DestroyGRenderRegion(pRender);
06898         else
06899             DestroyOSRenderRegion(pRender);
06900 
06901         // And turn off the drag redraw interlock
06902         DragManagerOp::RedrawFinished();
06903     }
06904 }
06905 
06906 
06907 
06908 /********************************************************************************************
06909 
06910 >   inline BOOL CanSetColour(IndexedColour *EditingColour)
06911 
06912     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06913     Created:    23/11/94
06914     Inputs:     EditingColour - the colour to check
06915     Returns:    TRUE if you may chnage the colour, FALSE if you may not
06916 
06917     Purpose:    Called by the SetNewValue methods to determine if they are allowed to
06918                 set a new value for the EditingColour. This is so they may have display-only
06919                 click/drag handling when the colour is non-editable (for example, when it's
06920                 a tint). This method just makes it easier for us to modify the allow-edit
06921                 rulesat a later date.
06922 
06923     Scope:      private (ColourEditDlg, kernel\coldlog.cpp)
06924 
06925 ********************************************************************************************/
06926 
06927 inline BOOL CanSetColour(IndexedColour *EditingColour)
06928 {
06929     return(EditingColour != NULL && EditingColour->GetType() != COLOURTYPE_TINT);
06930 }
06931 
06932 
06933 
06934 /********************************************************************************************
06935 
06936 >   void ColourEditDlg::StartDrag(ReDrawInfoType *Info)
06937 
06938     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
06939     Created:    30/11/94
06940     Inputs:     Info - The mouse-position information from the control
06941     Purpose:    Starts a drag from the colour picker control in the colour editor window
06942 
06943     Notes:      May be called when EditingColour is NULL (the window is shaded)
06944 
06945 ********************************************************************************************/
06946 
06947 //DocCoord OldMousePos;
06948 
06949 void ColourEditDlg::StartDrag(ReDrawInfoType *Info)
06950 {
06951     if (DragStartArea != CEDRAG_NONE)   // We are already dragging! Ignore it
06952         return;
06953 
06954     // Lob away the input focus again - put it back into the mainframe
06955     LoseFocusFromEditControls = TRUE;
06956     LoseKeyboardFocus();
06957     LoseFocusFromEditControls = FALSE;
06958 
06959     // Check if the drag is starting from a colour patch
06960     if (ParentList != NULL && EditingColour != NULL && ResultColour != NULL && !AmShaded)
06961     {   
06962         //OldMousePos = *(Info->pMousePos);
06963         //HideGadget (_R(IDC_COLOURPICKER), TRUE);
06964         //CWindowID hwndColPick = DialogManager::GetGadget (GetReadWriteWindowID (), _R(IDC_COLOURPICKER));
06965         //ASSERT (hwndColPick);
06966                 
06967         //ShowWindow (hwndColPick, SW_HIDE);
06968         
06969         INT32 PixelSize = 72000 / Info->Dpi;            // Size of output pixel in millipoints
06970 
06971         DocRect VirtualSize(0, 0, Info->dx, Info->dy);
06972         VirtualSize.Inflate(-PixelSize * 4);
06973 
06974         // Now draw the original/current colour patch in the top right corner
06975         DocRect PatchRect(VirtualSize);
06976         PatchRect.lo.x = PatchRect.hi.x - PATCHSIZE;
06977         PatchRect.lo.y = PatchRect.hi.y - PATCHSIZE;
06978         GridLockRect(&PatchRect, PixelSize);
06979 
06980         BOOL HorzPatch = (DisplayModel != COLOURMODEL_HSVT);
06981 
06982         // But this setting is overridden for the special tint and shade modes
06983         if (EditingColour != NULL && EditingColour->GetType() == COLOURTYPE_TINT)
06984         {
06985             if (EditingColour->TintIsShade())
06986                 HorzPatch = FALSE;
06987             else
06988                 HorzPatch = TRUE;
06989         }
06990 
06991         INT32 InPatch = 0;
06992         if (PatchRect.ContainsCoord(*(Info->pMousePos)))
06993             InPatch = 1;
06994         else
06995         {
06996             if (HorzPatch)
06997                 PatchRect.Translate(-PATCHSIZE, 0);
06998             else
06999                 PatchRect.Translate(0, -PATCHSIZE);
07000 
07001             if (PatchRect.ContainsCoord(*(Info->pMousePos)))
07002                 InPatch = 2;
07003         }
07004 
07005         if (InPatch != 0)
07006         {
07007             // Invert the logic of Horz in 1 case, so it is FALSE (original colour) or TRUE (current colour)
07008             if (InPatch == 1)
07009                 HorzPatch = !HorzPatch;
07010 
07011             // It was in one of the 2 patches
07012             IndexedColour *TheColour = ResultColour;            // Default to current colour
07013             if (HorzPatch)
07014             {
07015                 TheColour = new IndexedColour(OriginalColour);  // They are dragging original colour
07016                 if (TheColour != NULL)
07017                 {
07018                     TheColour->SetUnnamed();
07019 
07020                     // Ensure we don't get a memory leak
07021                     ParentList->AddItem(TheColour);
07022                 }
07023             }
07024 
07025             if (TheColour != NULL)                              // If have colour to drag, drag it
07026             {
07027                 ColEditorDragInfo *DragCol;
07028                 DragCol = new ColEditorDragInfo(TheColour, FALSE, (Document *)ParentList->GetParentDocument());
07029                 DragManagerOp::StartDrag(DragCol, GetReadWriteWindowID());
07030             }
07031 
07032             return;                                             // Don't pass the call on to the picker
07033         }
07034     }
07035 
07036     // Pass the click/drag onto the appropriate colour picker, and start a picker drag
07037     DragUpdatedOnIdle = FALSE;
07038     if (EditingColour != NULL && !AmShaded)
07039     {
07040 //      SetColour(FALSE);           // Ensure name updated (the name control doesn't lose
07041                                     // kbd focus in this case, so we must force it)
07042         SetNewValueFromMousePos(Info, TRUE);
07043 
07044         // If we started dragging, then register for idle-event updates
07045         // (first, ensuring that we are not already on the list)
07046 
07047         EndTimedProcessing();
07048         if (DragStartArea != CEDRAG_NONE)
07049             BeginTimedProcessing();
07050     }
07051 }
07052 
07053 
07054 
07055 /********************************************************************************************
07056 
07057 >   void ColourEditDlg::UpdateDrag(ReDrawInfoType *Info)
07058 
07059     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07060     Created:    30/11/94
07061     Inputs:     Info - The mouse-position information from the control
07062     Purpose:    Updates during a drag from the colour picker control in the colour
07063                 editor window
07064 
07065     Notes:      May be called when EditingColour is NULL (the window is shaded)
07066 
07067 ********************************************************************************************/
07068 
07069 void ColourEditDlg::UpdateDrag(ReDrawInfoType *Info)
07070 {
07071     DragUpdatedOnIdle = FALSE;
07072     if (DragStartArea != CEDRAG_NONE && EditingColour != NULL && !AmShaded)
07073     {
07074         SetNewValueFromMousePos(Info, FALSE);
07075     }
07076 }
07077 
07078 
07079 BOOL ColourEditDlg::TimedProcessing(void)
07080 {
07081     return (UpdateColourEditor ());
07082 }
07083 
07084 
07085 /********************************************************************************************
07086 
07087 >   virtual BOOL ColourEditDlg::UpdateColourEditor ()
07088 
07089     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07090     Created:    1/12/94
07091     Inputs:     -
07092     Returns:    
07093 
07094     Purpose:    This function was originally was a override of the virtual OnIdle() 
07095                 function and was called whist the process had idle time to spare, which
07096                 slowed down every other process on the computer. This function was modified
07097                 and renamed so that it is now called by timer messages at fixed periods.
07098                 
07099                 Used during drags to detect when the mouse has stopped moving (we won't
07100                 get idle events unless we have finished updating displays, etc)
07101                 When we find idle time, we start a complete update of the colour window
07102                 and the document, rather than the normal during-drag minimal updates.
07103 
07104     Notes:      May be called when EditingColour is NULL (the window is shaded).
07105                 See also: ColourEditDlg::BeginTimedProcessing, ColourEditDlg::EndTimedProcessing
07106 
07107 ********************************************************************************************/
07108 
07109 BOOL ColourEditDlg::UpdateColourEditor ()//TimedProcessing(void)
07110 {
07111 
07112     // Ensure the focus is shunted back to the document (during a drag, and also after
07113     // the window has been moved)
07114 //  if (LoseKbdFocusPending)
07115 //      LoseKeyboardFocus();
07116 
07117     // If something has changed while the program was busy, we will have flagged the fact
07118     // that we should update as soon as the busy job is finished and we start getting idles
07119     // once again. We find a safe colour to edit. (This usually happens when we load or swap
07120     // docs. This mechanism allows many changes to occur during loading while only triggering
07121     // one final colour editor redraw)
07122     if (UpdateOnNextIdle)
07123     {
07124         UpdateOnNextIdle = FALSE;
07125 
07126         FindUsefulColourToEdit(EditingLineColour);  // Try to find a new colour to edit
07127         
07128         if (EditingColour == NULL)                  // We failed - shade the dialogue
07129             ShadeMyself();
07130         
07131         return(FALSE);
07132     }
07133 
07134     // If we're not dragging, then update bubble help and stuff, and return
07135     if (DragStartArea == CEDRAG_NONE)
07136     {
07137         ColourPicker::UpdateBubbleHelpAndPointer();
07138         return(FALSE);      // Let low-priority idle handlers get a look in
07139     }
07140 
07141     // Otherwise we are dragging...
07142 
07143     // Check for escape being pressed
07144     if (AbortColour != NULL)
07145     {
07146         // Call SetNewValueFromMousePos to handle escape being pressed
07147         SetNewValueFromMousePos(NULL, FALSE);
07148 
07149         if (DragStartArea == CEDRAG_NONE)   // Has the drag now been aborted?
07150             return(FALSE);                  // Yup, so exit
07151     }
07152 
07153     // If we've already updated on an idle and the mouse has not yet moved again, then
07154     // we won't bother with unnecessary redraws and suchlike.
07155     if (DragUpdatedOnIdle)
07156         return(FALSE);      // Let low-priority idle handlers get a look in
07157 
07158     if (DragStartArea != CEDRAG_NONE && EditingColour != NULL)
07159     {
07160         // Flag that we have updated on an idle event - we won't respond to idles
07161         // again until another drag update occurs (as until a drag update occurs, there
07162         // can be no change in the colour)
07163         DragUpdatedOnIdle = TRUE;
07164 
07165         // Force complete update of the window and document, etc
07166         EditingColourHasChanged(TRUE, TRUE, TRUE);
07167 
07168         // The above call explicitly does not redraw the picker - it should be up to
07169         // date anyway, so why bother? However, the parent patch does need redrawing.
07170         InvalidatePatchGadget();
07171 
07172         return(TRUE);   // Don't waste any time on low-priority idle handlers this time around
07173     }
07174 
07175     // Deregister for idles, because we should not be getting them now
07176 //  GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_HIGH, this);     // Leave idles on for bubble help
07177 
07178     return(FALSE);      // And let the low-priority idle handlers do their stuff
07179 }
07180 
07181 
07182 
07183 /********************************************************************************************
07184 
07185 >   OpState ColourEditDlg::GetCommandState(StringBase *Command, StringBase *ShadeReason)
07186 
07187     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07188     Created:    3/10/95
07189 
07190     Inputs:     Command - String indicating the command to apply (see colmenu.h)
07191 
07192     Outputs:    ShadeReason - if OpState.Greyed is returned TRUE, this describes why
07193                 the op is greyed.
07194 
07195     Returns:    An OpState indicating the state of this command (shaded etc)
07196 
07197     Purpose:    Upcall from the menu system to determine te state of a menu command
07198 
07199 ********************************************************************************************/
07200 
07201 OpState ColourEditDlg::GetCommandState(StringBase *Command, StringBase *ShadeReason)
07202 {
07203     OpState State;
07204 
07205     if (*Command == ColCmd_Name)                                // Name only available for named colour
07206     {
07207         if (ResultColour == NULL || ParentList == NULL || !ResultColour->IsNamed())
07208         {
07209             State.Greyed = TRUE;
07210             ShadeReason->MakeMsg(_R(IDS_K_COLDLOG_NONAMELOCCOLS));
07211         }
07212     }
07213     else if (*Command == ColCmd_EditParent)                     // Edit parent only available if have parent
07214     {
07215         if (ResultColour == NULL || ParentList == NULL || ResultColour->FindLinkedParent() == NULL)
07216         {
07217             State.Greyed = TRUE;
07218             ShadeReason->MakeMsg(_R(IDS_COLMENU_NOPARENT));
07219         }
07220     }
07221     else if (*Command == ColCmd_HSV)                            // Tick appropriate colour model
07222         State.Ticked = (DisplayModel == COLOURMODEL_HSVT);
07223     else if (*Command == ColCmd_RGB)
07224         State.Ticked = (DisplayModel == COLOURMODEL_RGBT);
07225     else if (*Command == ColCmd_CMYK)
07226         State.Ticked = (DisplayModel == COLOURMODEL_CMYK);
07227     else if (*Command == ColCmd_Grey)
07228         State.Ticked = (DisplayModel == COLOURMODEL_GREYT);
07229 
07230     return(State);
07231 }
07232 
07233 
07234 
07235 /********************************************************************************************
07236 
07237 >   void ColourEditDlg::DoCommand(StringBase *Command)
07238 
07239     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07240     Created:    3/10/95
07241 
07242     Inputs:     Command - String indicating the command to apply (see colmenu.h)
07243 
07244     Purpose:    Applies a given editor menu command
07245 
07246 ********************************************************************************************/
07247 
07248 void ColourEditDlg::DoCommand(StringBase *Command)
07249 {
07250     ColourModel NewColourModel = COLOURMODEL_INDEXED;
07251 
07252     if (*Command == ColCmd_Help)
07253         HelpUser(*this);
07254     else if (*Command == ColCmd_Name)
07255     {
07256         if (ResultColour != NULL && ParentList != NULL && ResultColour->IsNamed())
07257         {
07258             // Lock ourselves so we don't update on any message broadcasts
07259             BOOL ISentState = ISentTheMessage;
07260             ISentTheMessage = TRUE;
07261 
07262 // Nasty, but ColourNameDlg is in sgcolour
07263 #ifndef EXCLUDE_GALS
07264                 // Rename the result colour
07265                 if (ColourNameDlg::InvokeDialog(ParentList, ResultColour))
07266                 {
07267                     // Commit any colour model change to this colour now
07268 //                  ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
07269                     ColourContext *cc = NULL;
07270                     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
07271                     if (cc != NULL)
07272                     {
07273                         ColourPicker::ForceColourModel(ResultColour, cc);
07274 
07275                         // Delete the colour context if necessary
07276                         if (bDeleteCC)
07277                             ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
07278                     }
07279 
07280                     // Make sure the editor swaps (it'll ignore us if ResultColour == ColToEdit)
07281                     IndexedColour *ColToEdit = ResultColour;
07282                     ResultColour = NULL;
07283 
07284                     // And start the editor up again on the original colour
07285                     EditThisColour(ParentList, ColToEdit);
07286                 }
07287 #endif
07288             ISentTheMessage = ISentState;
07289         }
07290     }
07291     else if (*Command == ColCmd_EditParent)                     // Edit parent only available if have parent
07292     {
07293         if (ResultColour != NULL && ParentList != NULL && ResultColour->FindLinkedParent() != NULL)
07294             EditThisColour(ParentList, ResultColour->FindLinkedParent());
07295     }
07296     else if (*Command == ColCmd_HSV)
07297         NewColourModel = COLOURMODEL_HSVT;
07298     else if (*Command == ColCmd_RGB)
07299         NewColourModel = COLOURMODEL_RGBT;
07300     else if (*Command == ColCmd_CMYK)
07301         NewColourModel = COLOURMODEL_CMYK;
07302     else if (*Command == ColCmd_Grey)
07303         NewColourModel = COLOURMODEL_GREYT;
07304 #ifdef WEBSTER // Martin 16/07/97
07305     else if (*Command == ColCmd_NewNColour)
07306         MakeNewNColour(); //do the same thing as pressing the button!
07307 #endif //WEBSTER
07308 
07309     if (NewColourModel != COLOURMODEL_INDEXED && NewColourModel != DisplayModel)
07310     {
07311         DisplayModel = (ColourModel) NewColourModel;        // Switch display to the new model
07312         
07313 // WEBSTER - markn 31/1/97
07314 // Always set the default colour models to the display mode
07315 #ifndef WEBSTER
07316         if (EditingColour->IsNamed())
07317             DefaultDisplayModelN = NewColourModel;          // And remember preference
07318 #else
07319         DefaultDisplayModelN = NewColourModel;
07320         DefaultDisplayModel = NewColourModel;
07321 #endif // WEBSTER
07322 
07323         ColourEditDlg::SetUnitGroupDefaults(DisplayModel);
07324 
07325         InvalidateAndSetControls();                         // And update the displays
07326     }   
07327 }
07328 
07329 
07330 
07331 /********************************************************************************************
07332 
07333 >   static BOOL ColourEditDlg::OnKeyPress(KeyPress* pKeyPress)
07334 
07335     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07336     Created:    5/2/95
07337     Inputs:     pKeyPress - points to a keypress object describing the key press
07338 
07339     Returns:    TRUE if it has processed the keypress (claimed it)
07340                 FALSE if it has not used the keypress, in which case it may be passed on
07341 
07342     Purpose:    To handle keypresses. This is called by Application::OnKeyPress before
07343                 all other keypress handling. Normally the colour editor will just return
07344                 FALSE as fast as possible, but during drags in the editor, it will 
07345                 return TRUE to stop keypresses getting through to the rest of camelot.
07346 
07347     Notes:      Not intended to be called by anyone other than Application::OnKeypress
07348 
07349                 May be called at any time
07350 
07351     SeeAlso:    Application::OnKeyPress; ColourEditDlg::StartDrag
07352 
07353 ********************************************************************************************/
07354 
07355 BOOL ColourEditDlg::OnKeyPress(KeyPress* pKeyPress)
07356 {
07357     ERROR3IF(pKeyPress == NULL, "Illegal NULL param!");
07358 
07359     if (TheEditor == NULL || TheEditor->DragStartArea == CEDRAG_NONE)
07360         return(FALSE);      // No current drag, so leave the key alone
07361 
07362     // We are dragging...
07363     
07364     // Check for escape being pressed
07365     if ((TheEditor->AbortColour != NULL) && ((pKeyPress->GetVirtKey () == CAMKEY(ESCAPE)) || (pKeyPress->GetVirtKey () == CAMKEY(CANCEL))))
07366     {
07367         EscapeKeyWasPressed = TRUE;
07368         TheEditor->SetNewValueFromMousePos(NULL, FALSE);
07369     }
07370 
07371     // Sit on all keypresses to make sure nobody else gets them
07372     return(TRUE);
07373 }
07374 
07375 
07376 
07377 
07378 /********************************************************************************************
07379 
07380 >   void ColourEditDlg::EndDrag(ReDrawInfoType *Info)
07381 
07382     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07383     Created:    30/11/94
07384     Inputs:     Info - The mouse-position information from the control
07385     Purpose:    Ends a drag from the colour picker control in the colour editor window
07386 
07387     Notes:      May be called when EditingColour is NULL (the window is shaded)
07388 
07389 ********************************************************************************************/
07390 
07391 void ColourEditDlg::EndDrag(ReDrawInfoType *Info)
07392 {
07393     // Only update if we think we're dragging (as for the other Drag methods)
07394     // However, if the last update was on an idle event, then the mouse has not moved
07395     // and so the colour has not changed since we last broadcast, so there is no
07396     // need to broadcast again, with all the flickery redraw etc. that will cause
07397     if (DragStartArea != CEDRAG_NONE && EditingColour != NULL && !DragUpdatedOnIdle)
07398     {
07399 //      EndTimedProcessing ();
07400         
07401         SetNewValueFromMousePos(Info, FALSE);       // Update colour one last time
07402 
07403         if (CanSetColour(EditingColour) || EditingColour->GetType() == COLOURTYPE_TINT)
07404             EditingColourHasChanged(TRUE, TRUE, TRUE);  // Ensure window etc fully updated
07405     }
07406 
07407     DragUpdatedOnIdle = FALSE;
07408 //  GetApplication()->RemoveIdleProcessor(IDLEPRIORITY_HIGH, this);     // Leave idles on for bubblehelp
07409     DragStartArea = CEDRAG_NONE;                    // We aren't dragging any more
07410 
07411     if (AbortColour != NULL)
07412     {
07413         delete AbortColour;
07414         AbortColour= NULL;
07415     }
07416 }
07417 
07418 
07419 
07420 /********************************************************************************************
07421 
07422 >   void ColourEditDlg::SetNewValueFromMousePos(ReDrawInfoType *Info, BOOL StartingNewDrag)
07423 
07424     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07425     Created:    30/11/94
07426     Inputs:     Info -  The redraw info for the kernel-drawn control's mouse event
07427                         
07428                         This may be NULL if you merely want to check for escape being
07429                         pressed to abort the drag, but note that if this is the case,
07430                         all that will be done is the escape check. NOTE that StartingNewDrag
07431                         MUST also be FALSE in this case.
07432 
07433                 StartingNewDrag - TRUE if this is the first call to this function for a
07434                 new drag operation (in which case, the DragStartArea is set appropriately)
07435 
07436     Purpose:    Handles drag updates - determines the new colour values from the current
07437                 mouse position, and sets the colour as appropriate.
07438 
07439                 Will also check for escape being pressed, in which case the drag will
07440                 be aborted, and the colour will return to its pre-drag state.
07441 
07442     Notes:      This will generate an ERROR3 if called with EditingColour==NULL
07443 
07444                 For those who haven't followed the progress of the colour editor,
07445                 you will soon realise that it is one huge non-OO bodge, which grew
07446                 from a tiny little thing in fits and starts and design retrofits.
07447                 One day, I'll be allowed to write it properly, from scratch, instead
07448                 of just bolting on more and more bits of ticky tacky.
07449 
07450 ********************************************************************************************/
07451 
07452 void ColourEditDlg::SetNewValueFromMousePos(ReDrawInfoType *Info, BOOL StartingNewDrag)
07453 {
07454     if (EditingColour == NULL)      // We are shaded - spurious call - shouldn't happen
07455     {
07456         ERROR3("ColourEditDlg::SetNewValueFromMousePos called when EditingColour == NULL");
07457         return;
07458     }
07459 
07460     if (StartingNewDrag)
07461     {
07462         DragStartArea = CEDRAG_NONE;        // For now, we are not dragging
07463 
07464         // And copy the original colour in case of an abort
07465         // NOTE: If new fails, then this pointer will be NULL, which merely disables abort checks.
07466         if (AbortColour != NULL)
07467         {
07468             delete AbortColour;
07469             AbortColour = NULL;
07470         }
07471         AbortColour = new IndexedColour(*EditingColour);
07472     }
07473     else
07474     {
07475         // Continuing a drag we've already started - check for escape being pressed
07476         if ((AbortColour != NULL && KeyPress::IsEscapePressed()) || (AbortColour != NULL && EscapeKeyWasPressed))
07477         {
07478             // Beep to make user aware they've succeeded in aborting the drag
07479             Beep();
07480 
07481             // Reset the definition of the EditingColour
07482             *EditingColour = *AbortColour;
07483 
07484             // And reset the drag state variables
07485             delete AbortColour;
07486             AbortColour = NULL;
07487 
07488             DragUpdatedOnIdle = FALSE;
07489             DragStartArea = CEDRAG_NONE;
07490 
07491             // Inform the editor of the change, and redraw everything (document and editor)
07492             EditingColourHasChanged(TRUE, TRUE, TRUE);
07493             InvalidatePatchGadget();
07494 //          EndTimedProcessing ();
07495             EscapeKeyWasPressed = FALSE;
07496             return;
07497         }
07498     }
07499 
07500     // If Info was NULL, the caller only wanted to check for the abort (escape) key being pressed
07501     if (Info == NULL)
07502         return;
07503 
07504     // Finally, call the appropriate colour model update routine to get the job done...
07505     // Yeah, yeah, I know. Where's the objects? Where's the virtual functions?
07506 
07507     INT32 PixelSize = 72000 / Info->Dpi;        // Size of output pixel in millipoints
07508 
07509     if (EditingColour->GetType() == COLOURTYPE_TINT)
07510     {
07511         if (EditingColour->TintIsShade())
07512             SetNewValueShade(Info, PixelSize, StartingNewDrag);
07513         else
07514             SetNewValueTint(Info, PixelSize, StartingNewDrag);
07515     }
07516     else
07517     {
07518         switch (DisplayModel)
07519         {
07520             case COLOURMODEL_HSVT:
07521                 if (CanSetColour(EditingColour))
07522                     SetNewValueHSV(Info, PixelSize, StartingNewDrag);
07523                 break;
07524 
07525             case COLOURMODEL_RGBT:
07526             case COLOURMODEL_WEBRGBT:
07527                 // RGB has the ability to change display modes, even when the colour is uneditable
07528                 // so we call the handler even when CanSetColour() == FALSE
07529                 if (Use3DDisplay)
07530                     SetNewValueRGB(Info, PixelSize, StartingNewDrag);
07531                 else
07532                 {
07533                     if (CanSetColour(EditingColour))
07534                         SetNewValueDefault(Info, PixelSize, StartingNewDrag);
07535                 }
07536                 break;
07537 
07538             case COLOURMODEL_CMYK:
07539                 // CMYK has the ability to change display modes, even when the colour is uneditable
07540                 // so we call the handler even when CanSetColour() == FALSE
07541                 if (Use3DDisplay)
07542                     SetNewValueCMYK(Info, PixelSize, StartingNewDrag);
07543                 else
07544                 {
07545                     if (CanSetColour(EditingColour))
07546                         SetNewValueDefault(Info, PixelSize, StartingNewDrag);
07547                 }
07548                 break;
07549 
07550             default:
07551                 if (CanSetColour(EditingColour))
07552                     SetNewValueDefault(Info, PixelSize, StartingNewDrag);
07553                 break;
07554         }
07555     }
07556 }
07557 
07558 
07559 
07560 /********************************************************************************************
07561 
07562 >   static FIXED24 GetComponent(ColourGeneric *SourceDef, const INT32 ComponentID)
07563 
07564     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07565     Created:    26/12/94
07566     Inputs:     SourceDef - A Generic colour definition to extract a component from
07567                 ComponentID - The component to extract [1..4]
07568 
07569     Purpose:    Extracts the given component from a colour definition.
07570 
07571     Scope:      private (static in kernel\coldlog.cpp)
07572 
07573 ********************************************************************************************/
07574 
07575 static FIXED24 GetComponent(ColourGeneric *SourceDef, const INT32 ComponentID)
07576 {
07577     switch(ComponentID)
07578     {
07579         case 1:
07580             return(SourceDef->Component1);
07581 
07582         case 2:
07583             return(SourceDef->Component2);
07584 
07585         case 3:
07586             return(SourceDef->Component3);
07587     }
07588 
07589     // Assume any other componentID value is for component 4
07590     return(SourceDef->Component4);
07591 }
07592 
07593 
07594 
07595 /********************************************************************************************
07596 
07597 >   static BOOL MousePosInCross(DocCoord *MousePos, DocRect *Area, FIXED24 *XPos, FIXED24 *YPos)
07598 
07599     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07600     Created:    18/10/95
07601     Inputs:     MousePos - Points to the mouse position
07602 
07603                 Area - Points to the picker area in which the cross resides
07604 
07605                 XPos - A value between 0.0 and 1.0 indicating the center position of the
07606                 cross in the X direction across the given area.
07607                 If NULL, the value 0.5 will be used
07608 
07609                 YPos - A value between 0.0 and 1.0 indicating the center position of the
07610                 cross in the Y direction up the given area.
07611                 If NULL, the value 0.5 will be used
07612 
07613     Purpose:    To check if a click near a given area has "hit" a marker cross sticking
07614                 out of a side of the area.
07615 
07616 ********************************************************************************************/
07617 
07618 static BOOL MousePosInCross(DocCoord *MousePos, DocRect *Area, FIXED24 *XPos, FIXED24 *YPos)
07619 {
07620     FIXED24 HalfWay(0.5);
07621 
07622     if (XPos == NULL)   XPos = &HalfWay;
07623     if (YPos == NULL)   YPos = &HalfWay;
07624 
07625     DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
07626 
07627     INT32 TransX = Area->lo.x + (INT32) ((double)Area->Width() * XPos->MakeDouble());
07628     INT32 TransY = Area->lo.y + (INT32) ((double)Area->Height() * YPos->MakeDouble());
07629 
07630     CrossRect.Translate(TransX, TransY);
07631 
07632     return(CrossRect.ContainsCoord(*MousePos));
07633 }
07634 
07635 
07636 
07637 /********************************************************************************************
07638 
07639 >   void ColourEditDlg::SetNewValueHSV(ReDrawInfoType *Info, INT32 PixelSize,
07640                                         BOOL StartingNewDrag)
07641 
07642     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
07643     Created:    13/12/94
07644     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
07645                 PixelSize - The size of display pixels as they appear when mapped into
07646                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
07647                 methods)
07648                 StartingNewDrag - TRUE if this is the first call to this function for a
07649                 new drag operation (in which case, the DragStartArea is set appropriately)
07650 
07651     Purpose:    Handles drag updates - determines the new colour values from the current
07652                 mouse position, and sets the colour as appropriate. Just how it interprets
07653                 the mouse position is dependant upon which region the drag was started
07654                 within, and which DisplayMode is in operation. A different routine like
07655                 this one will be called for each DisplayMode.
07656 
07657     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault
07658 
07659 ********************************************************************************************/
07660 
07661 void ColourEditDlg::SetNewValueHSV(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
07662 {
07663 #if TRUE
07664     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
07665     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
07666 
07667     // Calculate the two important rectangles - the hue slider, and Val/Sat square
07668     DocRect HueRect;
07669     DocRect ValSatSquare;
07670     CalculateHSVPickerRects(&VirtualSize, PixelSize, &HueRect, &ValSatSquare);
07671 
07672     // Get a colour context for our conversions and stuff
07673     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
07674 
07675     // Remember the old cross-position values from EditingColour
07676     ColourHSVT ColourDef;
07677     cc->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
07678 
07679     // If starting a new drag, determine which area the drag is in...
07680     if (StartingNewDrag)
07681     {
07682         if (HueRect.ContainsCoord(*(Info->pMousePos)))
07683             DragStartArea = CEDRAG_HSVPICKER_HSLIDER;
07684         else if (ValSatSquare.ContainsCoord(*(Info->pMousePos)))
07685         {
07686             DragStartArea = CEDRAG_HSVPICKER_VSSQUARE;
07687         }
07688         else
07689         {
07690             // The user didn't hit inside a picker area, but have they tried to drag
07691             // a region outside that lies under a protuding marker cross?
07692             FIXED24 ReverseSat = FIXED24(1.0) - ColourDef.Saturation;
07693 
07694             if (MousePosInCross(Info->pMousePos, &ValSatSquare, &ReverseSat, &ColourDef.Value))
07695                 DragStartArea = CEDRAG_HSVPICKER_VSSQUARE;
07696             else if (MousePosInCross(Info->pMousePos, &HueRect, &ColourDef.Hue, NULL))
07697                 DragStartArea = CEDRAG_HSVPICKER_HSLIDER;
07698             else
07699                 return;     // Nope - just ignore the click
07700         }
07701 
07702         // Remember what the colour was as we started the drag
07703         cc->ConvertColour(ResultColour, &ColourBeforeDrag);
07704     }
07705 
07706 
07707     BOOL ColourHasChanged = FALSE;
07708     INT32 XPos=0;
07709     INT32 YPos=0;
07710 
07711     // Handle the new mouse position, using the area the drag started in (rather than
07712     // the area it may now be over) to determine which components to alter
07713     switch(DragStartArea)
07714     {
07715         case CEDRAG_HSVPICKER_HSLIDER:
07716         {
07717             XPos = Info->pMousePos->x - HueRect.lo.x;
07718             if (XPos < 0)               XPos = 0;
07719             if (XPos > HueRect.Width()) XPos = HueRect.Width();
07720 
07721             double NewValue = ((double) XPos) / ((double) HueRect.Width());
07722             ColourPicker::SetComponentFromDouble(EditingColour, cc, 1, NewValue);
07723 
07724             DisplayModel = COLOURMODEL_HSVT;    // Force display back to HSV model
07725 
07726             if (XPos != LastDragPos.x)
07727                 ColourHasChanged = TRUE;
07728             break;
07729         }
07730 
07731 
07732         case CEDRAG_HSVPICKER_VSSQUARE:
07733         {
07734             INT32 Size = ValSatSquare.Width();
07735 
07736             XPos = ValSatSquare.hi.x - Info->pMousePos->x;
07737             if (XPos < 0)       XPos = 0;
07738             if (XPos > Size)    XPos = Size;
07739 
07740             if (bHSVHueAtTop)
07741             {
07742                 YPos = Info->pMousePos->y - ValSatSquare.lo.y;
07743                 if (YPos < 0)       YPos = 0;
07744                 if (YPos > Size)    YPos = Size;
07745             }
07746             else
07747             {
07748                 YPos = ValSatSquare.hi.y - Info->pMousePos->y;
07749                 if (YPos < 0)       YPos = 0;
07750                 if (YPos > Size)    YPos = Size;
07751             }
07752 
07753             double NewSat = ((double)XPos) / ((double) Size);
07754             double NewVal = ((double)YPos) / ((double) Size);
07755 
07756             if (KeyPress::IsConstrainPressed())
07757             {
07758                 // If we should constrain this value, then we check the original
07759                 // values for Sat/Val, and we only change the one which is furthest
07760                 // away from the original value (i.e. if you drag near the old
07761                 // Saturation value, only the Value will change & vice versa)
07762                 ColourHSVT *ConstrainDef = (ColourHSVT *) &ColourBeforeDrag;
07763 
07764                 double TempSat = ConstrainDef->Saturation.MakeDouble() - NewSat;
07765                 if (TempSat < 0.0) TempSat = -TempSat;
07766 
07767                 double TempVal = ConstrainDef->Value.MakeDouble() - NewVal;
07768                 if (TempVal < 0.0) TempVal = -TempVal;
07769 
07770                 if (TempSat < TempVal)
07771                     NewSat = ConstrainDef->Saturation.MakeDouble();
07772                 else
07773                     NewVal = ConstrainDef->Value.MakeDouble();
07774             }
07775 
07776             DisplayModel = COLOURMODEL_HSVT;    // Force display back to HSV model
07777 
07778             ColourPicker::SetComponentFromDouble(EditingColour, cc, 2, NewSat);
07779             ColourPicker::SetComponentFromDouble(EditingColour, cc, 3, NewVal);
07780 
07781             if (StartingNewDrag)
07782                 ColourHasChanged = TRUE;    // Always do full redraw when drag starts
07783             else
07784             {
07785                 // --- Invalidate the old cross position
07786                 DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
07787 
07788                 INT32 TransX = ValSatSquare.hi.x - (INT32)
07789                             ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
07790                 INT32 TransY = ValSatSquare.lo.y + (INT32)
07791                             ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
07792 
07793                 CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
07794 
07795                 // Inflate by 2 pixels (the cross can actually draw marginally outside the crossrect ;-(
07796                 CrossRect.Inflate(4*PixelSize);
07797                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
07798 
07799 
07800                 // --- And invalidate the new cross position
07801                 CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
07802 
07803                 cc->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
07804                 TransX = ValSatSquare.hi.x - (INT32)
07805                             ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
07806                 TransY = ValSatSquare.lo.y + (INT32)
07807                             ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
07808 
07809                 CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
07810 
07811                 // Inflate by 2 pixels (the cross can actually draw marginally outside the crossrect ;-(
07812                 CrossRect.Inflate(4*PixelSize);
07813                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
07814 
07815                 PaintGadgetNow(_R(IDC_EDIT_PICKER));
07816     
07817                 InvalidatePatchGadget(Info);
07818 
07819                 // And leave ColourHasChanged as FALSE so that the code below does not do a ful redraw!
07820             }
07821             break;
07822         }
07823 
07824 
07825         default:
07826             return;     // Illegal drag -= just ignore it
07827     }
07828 
07829 
07830     // If necessary, redraw the picker and the colour patch
07831     if (ColourHasChanged || StartingNewDrag)
07832     {
07833         InvalidateGadget(_R(IDC_EDIT_PICKER));
07834         PaintGadgetNow(_R(IDC_EDIT_PICKER));
07835     }
07836 
07837     // Remember the last position at which we updated
07838     LastDragPos.y = YPos;
07839     LastDragPos.x = XPos;
07840 
07841 #else
07842 /*
07843     DocRect ValueRect(0, 0, Info->dx, Info->dy);
07844     ValueRect.hi.x = HalfGridLock(ValueRect.hi.x, PixelSize);
07845     ValueRect.lo.x = HalfGridLock(ValueRect.hi.x - (ValueRect.Width() / 8), PixelSize * 2);
07846 
07847 
07848     // Diameter is the width of the gadget - the value rectangle - a gap
07849     INT32 Diameter = Info->dx - ValueRect.Width() - (ValueRect.Width() / 3);
07850     if (Diameter > abs(Info->dy))
07851         Diameter = abs(Info->dy);
07852 
07853     const INT32 Radius = HalfGridLock(Diameter/2, PixelSize);
07854     const INT32 MidY = HalfGridLock(abs(Info->dy) / 2, PixelSize);
07855     const INT32 MidX = HalfGridLock(0 + Radius, PixelSize);
07856 
07857     ValueRect.lo.y = MidY - Radius; // Rect only as high as the circle
07858     ValueRect.hi.y = MidY + Radius;
07859 
07860     // Get a colour context for our conversions and stuff
07861     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
07862 
07863     // If starting a new drag, determine which area the drag is in...
07864     if (StartingNewDrag)
07865     {
07866         if (ValueRect.ContainsCoord(*(Info->pMousePos)))
07867             DragStartArea = CEDRAG_HSVPICKER_VSLIDER;
07868         else
07869         {
07870             DocRect HSRect (ValueRect);
07871             HSRect.lo.x = MidX - Radius;
07872             HSRect.hi.x = MidX + Radius;
07873             
07874             // Not in the square containing the HS circle either, so ignore it
07875             if (!HSRect.ContainsCoord(*(Info->pMousePos)))
07876                 return;
07877             
07878             DragStartArea = CEDRAG_HSVPICKER_HSWHEEL;
07879         }
07880 
07881         // Remember what the colour was as we started the drag
07882         cc->ConvertColour(ResultColour, &ColourBeforeDrag);
07883     }
07884 
07885 
07886     BOOL ColourHasChanged = FALSE;
07887     INT32 XPos;
07888     INT32 YPos;
07889 
07890     // Handle the new mouse position, using the area the drag started in (rather than
07891     // the area it may now be over) to determine which components to alter
07892     switch(DragStartArea)
07893     {
07894         case CEDRAG_HSVPICKER_VSLIDER:
07895         {
07896             YPos = Info->pMousePos->y - ValueRect.lo.y;
07897             if (YPos < 0)           YPos = 0;
07898             if (YPos > Diameter)    YPos = Diameter;
07899 
07900             double NewValue = ((double) YPos) / ((double) Diameter);
07901             ColourPicker::SetComponentFromDouble(EditingColour, cc, 3, NewValue);
07902 
07903             DisplayModel = COLOURMODEL_HSVT;    // Force display back to HSV model
07904 
07905             if (YPos != LastDragPos.y)
07906                 ColourHasChanged = TRUE;
07907             break;
07908         }
07909 
07910 
07911         case CEDRAG_HSVPICKER_HSWHEEL:
07912         {
07913             YPos = Info->pMousePos->y - MidY;
07914             if (YPos < -Radius) YPos = -Radius;
07915             if (YPos > Radius)  YPos = Radius;
07916 
07917             XPos = Info->pMousePos->x - MidX;
07918             if (XPos < -Radius) XPos = -Radius;
07919             if (XPos > Radius)  XPos = Radius;
07920 
07921             double Temp = (double) XPos;        // NewSat = sqrt(X^2 + Y^2)
07922             double NewSat = Temp * Temp;
07923             Temp = (double) YPos;
07924             NewSat += Temp * Temp;
07925             NewSat = sqrt(NewSat) / Radius;
07926             if (NewSat > 1.0)                   // Clip to within gamut
07927                 NewSat = 1.0;
07928 
07929             double NewHue = 0.25;               // (90 degrees of hue) in 0.0-1.0 space
07930             if (YPos == 0)
07931             {
07932                 if (XPos < 0) NewHue = 0.75;    // (270 degrees of hue) in 0.0-1.0 space
07933                 // (else it is 0.25, the default from above)
07934             }
07935             else
07936             {
07937                 // Get angle (in radians) within the 0 to (PI/2) quadrant
07938                 NewHue = atan( fabs( ((double)XPos) / ((double)YPos) ) );
07939 
07940                 // And fix the angle into the appropriate quadrant...
07941                 if (YPos < 0)
07942                     NewHue = PI - NewHue;
07943 
07944                 if (XPos < 0)
07945                     NewHue = (2.0 * PI) - NewHue;
07946 
07947                 // And convert 0 to 2PI radians value into a 0.0 to 1.0 Hue value
07948                 NewHue /= 2.0 * PI;
07949             }
07950 
07951             if (KeyPress::IsConstrainPressed())
07952             {
07953                 // If we should constrain this value, then we check the original
07954                 // values for Hue/Sat, and we only change the one which is furthest
07955                 // away from the original value (i.e. if you drag near the old
07956                 // Saturation value, only the Hue will change & vice versa)
07957                 ColourHSVT *ConstrainDef = (ColourHSVT *) &ColourBeforeDrag;
07958 
07959                 // NOTE:
07960                 // The desired behaviour has several strange consequences
07961                 // The "distance" from the old value should be the same on-screen
07962                 // distance (e.g. 5 pixels around the circular Hue arc should be
07963                 // the same as 5 pixels along the linear saturation radial. 
07964                 // Also, Hue wraps back around (1.0 is adjacent to 0.0) so we need to
07965                 // take the "closest" direction around the circle!
07966                 // Thus, we find the difference in hue, taking the shortest route, and
07967                 // turn it into the (0 to PI) range.
07968                 // This is compared to a value of (0 to 1.0) for saturation
07969 
07970                 // Get Hue distance in terms of 0..PI
07971                 Temp = NewHue - ConstrainDef->Hue.MakeDouble();
07972                 if (Temp < 0.0)
07973                     Temp = -Temp;           // Ensure difference is positive
07974 
07975                 if (Temp > 1.0)             // "Out of Gamut", so make distance = 0
07976                     Temp = 0.0;
07977                 else
07978                 {
07979                     if (Temp >= 0.5)        // Ensure difference is shortest distance
07980                         Temp = 1.0 - Temp;  // around the circle
07981 
07982                     Temp *= PI;             // And get as a 0..PI value
07983                 }
07984 
07985                 // Get Saturation in the range 0.0 to 1.0
07986                 double TempSat = NewSat - ConstrainDef->Saturation.MakeDouble();
07987                 if (TempSat < 0.0)
07988                     TempSat = -TempSat;     // Ensure difference is positive
07989 
07990                 if (TempSat > 1.0)          // Ensure it is clipped at 1.0
07991                     TempSat = 1.0;
07992 
07993                 // Finally, if the saturation difference is larger than the Hue
07994                 // difference, then lock the hue, else lock the saturation
07995                 if (TempSat > Temp)
07996                     NewHue = ConstrainDef->Hue.MakeDouble();
07997                 else
07998                     NewSat = ConstrainDef->Saturation.MakeDouble();
07999             }
08000 
08001             DisplayModel = COLOURMODEL_HSVT;    // Force display back to HSV model
08002 
08003             if (!StartingNewDrag)   // When starting a new drag we always do a complete redraw
08004             {
08005                 // Get the old cross-position values from EditingColour
08006                 ColourHSVT ColourDef;
08007                 cc->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
08008 
08009                 // Set the new values
08010                 ColourPicker::SetComponentFromDouble(EditingColour, cc, 1, NewHue);
08011                 ColourPicker::SetComponentFromDouble(EditingColour, cc, 2, NewSat);
08012 
08013 
08014                 // --- Invalidate the old cross position
08015                 // RedrawSize gives the 'radius' of the cross rectangle to redraw. NOTE however,
08016                 // that the cross lines can move up to 1 pixel outside the CrossRect, so we have to
08017                 // invalidate one pixel more, just to make sure we always get the bugger!
08018                 INT32 RedrawSize = CROSSRADIUS + (PixelSize * 2);
08019                 DocRect CrossRect(-RedrawSize, -RedrawSize, RedrawSize, RedrawSize);
08020     
08021                 // Convert Hue (0.0 -> 1.0) into an angle in radians (0 -> 2Pi)
08022                 double theta  = 2.0 * PI * ColourDef.Hue.MakeDouble();
08023     
08024                 // Convert Saturation into a distance from the center of the colour wheel
08025                 double length = (double)Radius * ColourDef.Saturation.MakeDouble();
08026 
08027                 // Translate the cross to the polar coordinate (theta, length)
08028                 CrossRect.Translate(HalfGridLock(MidX + (INT32)(length * sin(theta)), PixelSize),
08029                                     HalfGridLock(MidY + (INT32)(length * cos(theta)), PixelSize));
08030 
08031                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08032 
08033 
08034                 // --- Now invalidate the new cross position
08035                 CrossRect = DocRect(-RedrawSize, -RedrawSize, RedrawSize, RedrawSize);
08036 
08037                 // Convert Hue (0.0 -> 1.0) into an angle in radians (0 -> 2Pi)
08038                 theta  = 2.0 * PI * NewHue;
08039     
08040                 // Convert Saturation into a distance from the center of the colour wheel
08041                 length = (double)Radius * NewSat;
08042 
08043                 // Translate the cross to the polar coordinate (theta, length)
08044                 CrossRect.Translate(HalfGridLock(MidX + (INT32)(length * sin(theta)), PixelSize),
08045                                     HalfGridLock(MidY + (INT32)(length * cos(theta)), PixelSize));
08046 
08047                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08048 
08049                 // And finally, invalidate the value slider rectangle
08050                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &ValueRect);
08051                 PaintGadgetNow(_R(IDC_EDIT_PICKER));
08052     
08053                 InvalidatePatchGadget(Info);
08054 
08055                 // We leave "ColourHasChanged" FALSE here so that it doesn't force redraw
08056                 // everything again, below!
08057             }
08058             else
08059             {
08060                 ColourPicker::SetComponentFromDouble(EditingColour, cc, 1, NewHue);
08061                 ColourPicker::SetComponentFromDouble(EditingColour, cc, 2, NewSat);
08062                 ColourHasChanged = TRUE;
08063             }
08064             break;
08065         }
08066 
08067 
08068         default:
08069             return;     // Illegal drag -= just ignore it
08070     }
08071 
08072 
08073     // If necessary, redraw the picker and the colour patch
08074     if (ColourHasChanged || StartingNewDrag)
08075     {
08076         InvalidateGadget(_R(IDC_EDIT_PICKER));
08077         PaintGadgetNow(_R(IDC_EDIT_PICKER));
08078     }
08079 
08080     // Remember the last position at which we updated
08081     LastDragPos.y = YPos;
08082     LastDragPos.x = XPos;
08083 */
08084 #endif
08085 }
08086 
08087 
08088 
08089 /********************************************************************************************
08090 
08091 >   void ColourEditDlg::SetNewValueRGB(ReDrawInfoType *Info, INT32 PixelSize,
08092                                         BOOL StartingNewDrag)
08093 
08094     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
08095     Created:    23/12/94
08096     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
08097                 PixelSize - The size of display pixels as they appear when mapped into
08098                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
08099                 methods)
08100                 StartingNewDrag - TRUE if this is the first call to this function for a
08101                 new drag operation (in which case, the DragStartArea is set appropriately)
08102 
08103     Purpose:    Handles drag updates - determines the new colour values from the current
08104                 mouse position, and sets the colour as appropriate. Just how it interprets
08105                 the mouse position is dependant upon which region the drag was started
08106                 within, and which DisplayMode is in operation. A different routine like
08107                 this one will be called for each DisplayMode.
08108 
08109     Notes:      The RGB and CMYK pickers are almost identical in operation. It should be
08110                 possible to tidy up the code considerably and make a generic routine
08111                 for handling most of the common stuff.
08112 
08113     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault
08114 
08115 ********************************************************************************************/
08116 
08117 void ColourEditDlg::SetNewValueRGB(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
08118 {
08119     // Fill the control background, and calculate the cube params (without redraw)
08120     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
08121     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
08122 
08123     DocRect SquareRect;
08124     INT32 SizeZ;
08125     DrawCubeShadowAndCalcValues(NULL, &VirtualSize, PixelSize, NULL,
08126                                 /* TO */ &SquareRect, &SizeZ);
08127 
08128     DocRect CubeFaceRect(SquareRect);       // Remember the rect of the front face for below
08129 
08130     // Now, shift the square down from the front of the cube by an amount appropriate to
08131     // the Z-axis component of the colour
08132     ColourContextRGBT *cc = (ColourContextRGBT *)
08133                             ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
08134     ColourRGBT SourceColour;
08135     if (EditingColour != NULL)
08136         cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
08137 
08138     if (CanSetColour(EditingColour))
08139     {
08140         FIXED24 ZComponent = SourceColour.Blue;
08141         if (ColourPickerMode == 1)
08142             ZComponent = SourceColour.Green;
08143         else if (ColourPickerMode == 2)
08144             ZComponent = SourceColour.Red;
08145 
08146         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
08147         SquareRect.Translate(-ZTrans, ZTrans);
08148         GridLockRect(&SquareRect, PixelSize);
08149     }
08150 
08151     if (StartingNewDrag)
08152     {
08153         // Remember what the colour was as we started the drag
08154         cc->ConvertColour(ResultColour, &ColourBeforeDrag);
08155 
08156         DocCoord BitmapPos;
08157         BitmapPos.x = HalfGridLock(CubeFaceRect.hi.x + SizeZ/2, PixelSize);
08158         BitmapPos.y = HalfGridLock(CubeFaceRect.hi.y - SizeZ/2, PixelSize);
08159 
08160         const INT32 BitmapSize = 14 * PixelSize;
08161         DocRect SwapAxesRect(BitmapPos.x, BitmapPos.y,
08162                                 BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
08163         GridLockRect(&SwapAxesRect, PixelSize);
08164 
08165         if (SwapAxesRect.ContainsCoord(*(Info->pMousePos)))
08166         {
08167             // Swap the axes around - this is treated as a click (the rest of the drag ignored)
08168             DragStartArea = CEDRAG_NONE;
08169             ColourPickerMode = (ColourPickerMode + 1) % 3;
08170             InvalidateGadget(_R(IDC_EDIT_PICKER));
08171             return;
08172         }
08173 
08174         if (SquareRect.ContainsCoord(*(Info->pMousePos)))
08175             DragStartArea = CEDRAG_RGBPICKER_XY;
08176         else
08177         {
08178             // Check if the pointer is in the Z 'drag button'
08179             DocRect ZButton(SquareRect);
08180             ZButton.lo.x = ZButton.hi.x;
08181             ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
08182             ZButton.hi.y = ZButton.lo.y;
08183             ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
08184             GridLockRect(&ZButton, PixelSize);
08185 
08186             if (ZButton.ContainsCoord(*(Info->pMousePos)))
08187             {
08188                 DragStartArea = CEDRAG_RGBPICKER_Z;
08189 
08190                 // And remember the offset from the bottom right of the handle to the dragged point
08191                 DragAnchor.x = Info->pMousePos->x - ZButton.lo.x;
08192                 DragAnchor.y = Info->pMousePos->y - ZButton.hi.y;
08193             }
08194             else
08195             {
08196                 // OK, then. Is the click in a protuding bit of the marker cross?
08197                 DocRect CrossRect;
08198                 CalcCrossRectRGB(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08199 
08200                 if (CrossRect.ContainsCoord(*(Info->pMousePos)))
08201                     DragStartArea = CEDRAG_RGBPICKER_XY;
08202             }
08203         }
08204     }
08205 
08206     if (!CanSetColour(EditingColour))       // We can't change the colour - abort
08207     {
08208         DragStartArea = CEDRAG_NONE;
08209         return;
08210     }
08211 
08212     BOOL ColourHasChanged = TRUE;
08213 
08214     INT32 XPos = Info->pMousePos->x;
08215     INT32 YPos = Info->pMousePos->y;
08216 
08217     switch(DragStartArea)
08218     {
08219         case CEDRAG_RGBPICKER_XY:
08220             {
08221                 if (XPos < SquareRect.lo.x)  XPos = SquareRect.lo.x;
08222                 if (XPos > SquareRect.hi.x)  XPos = SquareRect.hi.x;
08223 
08224                 if (YPos < SquareRect.lo.y)  YPos = SquareRect.lo.y;
08225                 if (YPos > SquareRect.hi.y)  YPos = SquareRect.hi.y;
08226 
08227                 INT32 XComponent = 2;       // XYZ = G,R,B
08228                 INT32 YComponent = 1;
08229 
08230                 switch(ColourPickerMode)
08231                 {
08232                     case 1:             // XYZ = R,B,G
08233                         XComponent = 1;
08234                         YComponent = 3;
08235                         break;
08236 
08237                     case 2:             // XYZ = B,G,R
08238                         XComponent = 3;
08239                         YComponent = 2;
08240                         break;
08241                 }
08242             
08243                 double NewX = ((double) (XPos - SquareRect.lo.x)) / 
08244                                 ((double) SquareRect.Width());
08245                 if (NewX < 0.0)
08246                     NewX = 0.0;
08247                 if (NewX > 1.0)
08248                     NewX = 1.0;
08249 
08250                 double NewY = ((double) (YPos - SquareRect.lo.y)) / 
08251                                 ((double) SquareRect.Height());
08252                 if (NewY < 0.0)
08253                     NewY = 0.0;
08254                 if (NewY > 1.0)
08255                     NewY = 1.0;
08256 
08257                 if (KeyPress::IsConstrainPressed())
08258                 {
08259 //                  ColourRGBT *ConstrainDef = (ColourRGBT *) &ColourBeforeDrag;
08260 
08261                     double XDiff = GetComponent(&ColourBeforeDrag, XComponent).MakeDouble() - NewX;
08262                     double YDiff = GetComponent(&ColourBeforeDrag, YComponent).MakeDouble() - NewY;
08263 
08264                     if (XDiff < 0)  XDiff = -XDiff;
08265                     if (YDiff < 0)  YDiff = -YDiff;
08266 
08267                     if (XDiff < YDiff)
08268                         NewX = GetComponent(&ColourBeforeDrag, XComponent).MakeDouble();
08269                     else
08270                         NewY = GetComponent(&ColourBeforeDrag, YComponent).MakeDouble();
08271                 }
08272 
08273                 // Set the new values
08274                 ColourPicker::SetComponentFromDouble(EditingColour, cc, XComponent, NewX);
08275                 ColourPicker::SetComponentFromDouble(EditingColour, cc, YComponent, NewY);
08276 
08277                 DisplayModel = COLOURMODEL_RGBT;    // Force display back to RGB model
08278 
08279                 if (!StartingNewDrag)
08280                 {
08281                     // Redraw the area where the cross used to be shown
08282                     DocRect CrossRect;
08283                     CalcCrossRectRGB(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08284                     CrossRect.Inflate(4*PixelSize);     // Inflate to ensure we redraw all of the cross
08285                     InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08286 
08287                     // And force redraw the new cross position
08288                     cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
08289                     CalcCrossRectRGB(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08290                     CrossRect.Inflate(4*PixelSize);     // Inflate to ensure we redraw all of the cross
08291                     InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08292 
08293                     // Redraw the controls...
08294                     InvalidatePatchGadget(Info);
08295                     PaintGadgetNow(_R(IDC_EDIT_PICKER));
08296 
08297                     // And clear this flag so that the redraw below (of entire gadget) is not done.                 
08298                     ColourHasChanged = FALSE;
08299                 }
08300             }
08301             break;
08302 
08303 
08304         case CEDRAG_RGBPICKER_Z:
08305             {
08306                 XPos -= DragAnchor.x;   // Correct the mouse position for anchoring
08307                 YPos -= DragAnchor.y;
08308 
08309                 INT32 ZComponent = 3;       // XYZ = G,R,B
08310 
08311                 switch(ColourPickerMode)
08312                 {
08313                     case 1:             // XYZ = R,B,G
08314                         ZComponent = 2;
08315                         break;
08316 
08317                     case 2:             // XYZ = B,G,R
08318                         ZComponent = 1;
08319                         break;
08320                 }
08321 
08322                 INT32 Offset = CubeFaceRect.hi.x + SizeZ - XPos;
08323                 if (Offset > YPos - (CubeFaceRect.lo.y - SizeZ))
08324                     Offset = YPos - (CubeFaceRect.lo.y - SizeZ);
08325 
08326                 double NewZ =  ((double) Offset) / ((double) SizeZ);
08327                 if (NewZ < 0.0)
08328                     NewZ = 0.0;
08329                 if (NewZ > 1.0)
08330                     NewZ = 1.0;
08331 
08332                 DisplayModel = COLOURMODEL_RGBT;    // Force display back to RGB model
08333 
08334                 ColourPicker::SetComponentFromDouble(EditingColour, cc, ZComponent, NewZ);
08335             }
08336             break;
08337 
08338 
08339         default:
08340             return;     // Not a legal drag, so we ignore it
08341     }
08342 
08343     // If necessary, redraw the entire colour picker control and the colour patch
08344     if (ColourHasChanged)
08345     {
08346         if (StartingNewDrag || YPos != LastDragPos.y || XPos != LastDragPos.x)
08347         {
08348             InvalidateGadget(_R(IDC_EDIT_PICKER));
08349             PaintGadgetNow(_R(IDC_EDIT_PICKER));
08350         }
08351     }
08352 
08353     // Remember the last position at which we updated
08354     LastDragPos.y = YPos;
08355     LastDragPos.x = XPos;
08356 }
08357 
08358 
08359 
08360 /********************************************************************************************
08361 
08362 >   void ColourEditDlg::SetNewValueCMYK(ReDrawInfoType *Info, INT32 PixelSize,
08363                                         BOOL StartingNewDrag)
08364 
08365     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
08366     Created:    23/12/94
08367     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
08368                 PixelSize - The size of display pixels as they appear when mapped into
08369                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
08370                 methods)
08371                 StartingNewDrag - TRUE if this is the first call to this function for a
08372                 new drag operation (in which case, the DragStartArea is set appropriately)
08373 
08374     Purpose:    Handles drag updates - determines the new colour values from the current
08375                 mouse position, and sets the colour as appropriate. Just how it interprets
08376                 the mouse position is dependant upon which region the drag was started
08377                 within, and which DisplayMode is in operation. A different routine like
08378                 this one will be called for each DisplayMode.
08379 
08380     Notes:      The RGB and CMYK pickers are almost identical in operation. It should be
08381                 possible to tidy up the code considerably and make a generic routine
08382                 for handling most of the common stuff.
08383 
08384     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault
08385 
08386 ********************************************************************************************/
08387 
08388 void ColourEditDlg::SetNewValueCMYK(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
08389 {
08390     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
08391     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
08392 
08393     // Determine how much space is left over after the key slider has been placed
08394     INT32 KeySliderLeft = VirtualSize.hi.x - (CROSSRADIUS+PixelSize)*2;
08395     ERROR3IF(KeySliderLeft < VirtualSize.lo.x,
08396                 "Not enough room to render the colour picker!");
08397 
08398     // Fill the control background, and draw the cube 'shadow'
08399     DocRect CubeAvailableSpace(VirtualSize);
08400     CubeAvailableSpace.hi.x = KeySliderLeft - 2000;
08401 
08402     DocRect SquareRect;
08403     INT32 SizeZ;
08404     DrawCubeShadowAndCalcValues(NULL, &CubeAvailableSpace, PixelSize, NULL,
08405                                 /* TO */ &SquareRect, &SizeZ);
08406 
08407 
08408     DocRect CubeFaceRect(SquareRect);       // Remember the rect of the front face for below
08409 
08410     // Now, shift the square down from the front of the cube by an amount appropriate to
08411     // the Z-axis component of the colour
08412 //  ColourContextCMYK *cc = (ColourContextCMYK*)ColourContext::GetGlobalDefault(COLOURMODEL_CMYK);
08413     ColourContext *cc = NULL;
08414     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
08415     ColourCMYK SourceColour;
08416 
08417     if (CanSetColour(EditingColour))
08418     {
08419         cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
08420         FIXED24 ZComponent = SourceColour.Magenta;
08421         if (ColourPickerMode == 1)
08422             ZComponent = SourceColour.Cyan;
08423         else if (ColourPickerMode == 2)
08424             ZComponent = SourceColour.Yellow;
08425 
08426         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
08427         SquareRect.Translate(-ZTrans, ZTrans);
08428         GridLockRect(&SquareRect, PixelSize);
08429     }
08430 
08431     if (StartingNewDrag)
08432     {
08433         // Remember what the colour was as we started the drag
08434         cc->ConvertColour(ResultColour, &ColourBeforeDrag);
08435 
08436         DocCoord BitmapPos;
08437         BitmapPos.x = HalfGridLock(CubeFaceRect.hi.x + SizeZ/2, PixelSize);
08438         BitmapPos.y = HalfGridLock(CubeFaceRect.hi.y - SizeZ/2, PixelSize);
08439 
08440         const INT32 BitmapSize = 14 * PixelSize;
08441         DocRect SwapAxesRect(BitmapPos.x, BitmapPos.y,
08442                                 BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
08443         GridLockRect(&SwapAxesRect, PixelSize);
08444 
08445         if (SwapAxesRect.ContainsCoord(*(Info->pMousePos)))
08446         {
08447             // Swap the axes around - this is treated as a click (the rest of the drag ignored)
08448             DragStartArea = CEDRAG_NONE;
08449             ColourPickerMode = (ColourPickerMode + 1) % 3;
08450             InvalidateGadget(_R(IDC_EDIT_PICKER));
08451             return;
08452         }
08453 
08454         if (SquareRect.ContainsCoord(*(Info->pMousePos)))
08455             DragStartArea = CEDRAG_CMYKPICKER_XY;
08456         else
08457         {
08458             // Check if the pointer is in the Z 'drag button'
08459             DocRect ZButton(SquareRect);
08460             ZButton.lo.x = ZButton.hi.x;
08461             ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
08462             ZButton.hi.y = ZButton.lo.y;
08463             ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
08464             GridLockRect(&ZButton, PixelSize);
08465 
08466             if (ZButton.ContainsCoord(*(Info->pMousePos)))
08467             {
08468                 DragStartArea = CEDRAG_CMYKPICKER_Z;
08469 
08470                 // And remember the offset from the bottom right of the handle to the dragged point
08471                 DragAnchor.x = Info->pMousePos->x - ZButton.lo.x;
08472                 DragAnchor.y = Info->pMousePos->y - ZButton.hi.y;
08473             }
08474             else
08475             {
08476                 // Check if the pointer is in the Key slider
08477                 DocRect KeyRect(KeySliderLeft, 0, Info->dx, Info->dy - (PATCHSIZE + PixelSize*2));
08478                 if (KeyRect.ContainsCoord(*(Info->pMousePos)))
08479                     DragStartArea = CEDRAG_CMYKPICKER_KEY;
08480                 else
08481                 {
08482                     // OK, then. Is the click in a protuding bit of the marker cross?
08483                     DocRect CrossRect;
08484                     CalcCrossRectCMYK(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08485 
08486                     if (CrossRect.ContainsCoord(*(Info->pMousePos)))
08487                         DragStartArea = CEDRAG_CMYKPICKER_XY;
08488                 }
08489             }
08490         }
08491     }
08492 
08493     if (!CanSetColour(EditingColour))       // We can't change the colour - abort
08494     {
08495         DragStartArea = CEDRAG_NONE;
08496         return;
08497     }
08498 
08499     BOOL ColourHasChanged = TRUE;
08500 
08501     INT32 XPos = Info->pMousePos->x;
08502     INT32 YPos = Info->pMousePos->y;
08503 
08504     switch(DragStartArea)
08505     {
08506         case CEDRAG_CMYKPICKER_XY:
08507             {
08508                 if (XPos < SquareRect.lo.x)  XPos = SquareRect.lo.x;
08509                 if (XPos > SquareRect.hi.x)  XPos = SquareRect.hi.x;
08510 
08511                 if (YPos < SquareRect.lo.y)  YPos = SquareRect.lo.y;
08512                 if (YPos > SquareRect.hi.y)  YPos = SquareRect.hi.y;
08513 
08514                 INT32 XComponent = 1;       // XYZ = C,Y,M
08515                 INT32 YComponent = 3;
08516 
08517                 switch(ColourPickerMode)
08518                 {
08519                     case 1:             // XYZ = Y,M,C
08520                         XComponent = 3;
08521                         YComponent = 2;
08522                         break;
08523 
08524                     case 2:             // XYZ = M,C,Y
08525                         XComponent = 2;
08526                         YComponent = 1;
08527                         break;
08528                 }
08529             
08530                 double NewX = ((double) (XPos - SquareRect.lo.x)) / 
08531                                 ((double) SquareRect.Width());
08532                 if (NewX < 0.0)
08533                     NewX = 0.0;
08534                 if (NewX > 1.0)
08535                     NewX = 1.0;
08536 
08537                 double NewY = ((double) (YPos - SquareRect.lo.y)) / 
08538                                 ((double) SquareRect.Height());
08539                 if (NewY < 0.0)
08540                     NewY = 0.0;
08541                 if (NewY > 1.0)
08542                     NewY = 1.0;
08543 
08544                 if (KeyPress::IsConstrainPressed())
08545                 {
08546 //                  ColourCMYK *ConstrainDef = (ColourCMYK *) &ColourBeforeDrag;
08547 
08548                     double XDiff = GetComponent(&ColourBeforeDrag, XComponent).MakeDouble() - NewX;
08549                     double YDiff = GetComponent(&ColourBeforeDrag, YComponent).MakeDouble() - NewY;
08550 
08551                     if (XDiff < 0)  XDiff = -XDiff;
08552                     if (YDiff < 0)  YDiff = -YDiff;
08553 
08554                     if (XDiff < YDiff)
08555                         NewX = GetComponent(&ColourBeforeDrag, XComponent).MakeDouble();
08556                     else
08557                         NewY = GetComponent(&ColourBeforeDrag, YComponent).MakeDouble();
08558                 }
08559 
08560                 ColourPicker::SetComponentFromDouble(EditingColour, cc, XComponent, NewX);
08561                 ColourPicker::SetComponentFromDouble(EditingColour, cc, YComponent, NewY);
08562 
08563                 DisplayModel = COLOURMODEL_CMYK;    // Force display back to CMYK model
08564 
08565                 if (!StartingNewDrag)
08566                 {
08567                     // Redraw the area where the cross used to be shown
08568                     DocRect CrossRect;
08569                     CalcCrossRectCMYK(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08570                     CrossRect.Inflate(4*PixelSize);     // Inflate to ensure we redraw all of the cross
08571                     InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08572 
08573                     // And force redraw the new cross position
08574                     cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
08575                     CalcCrossRectCMYK(&SourceColour, &SquareRect, PixelSize, &CrossRect);
08576                     CrossRect.Inflate(4*PixelSize);     // Inflate to ensure we redraw all of the cross
08577                     InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
08578 
08579                     // Redraw the controls...
08580                     InvalidatePatchGadget(Info);
08581                     PaintGadgetNow(_R(IDC_EDIT_PICKER));
08582 
08583                     // And clear this flag so that the redraw below (of entire gadget) is not done.                 
08584                     ColourHasChanged = FALSE;
08585                 }
08586             }
08587             break;
08588 
08589 
08590         case CEDRAG_CMYKPICKER_Z:
08591             {
08592                 XPos -= DragAnchor.x;   // Correct the mouse position for anchoring
08593                 YPos -= DragAnchor.y;
08594 
08595                 INT32 ZComponent = 2;       // XYZ = C,Y,M
08596 
08597                 switch(ColourPickerMode)
08598                 {
08599                     case 1:             // XYZ = Y,M,C
08600                         ZComponent = 1;
08601                         break;
08602 
08603                     case 2:             // XYZ = M,C,Y
08604                         ZComponent = 3;
08605                         break;
08606                 }
08607 
08608                 INT32 Offset = CubeFaceRect.hi.x + SizeZ - XPos;
08609                 if (Offset > YPos - (CubeFaceRect.lo.y - SizeZ))
08610                     Offset = YPos - (CubeFaceRect.lo.y - SizeZ);
08611 
08612                 double NewZ =  ((double) Offset) / ((double) SizeZ);
08613                 if (NewZ < 0.0)
08614                     NewZ = 0.0;
08615                 if (NewZ > 1.0)
08616                     NewZ = 1.0;
08617 
08618                 DisplayModel = COLOURMODEL_CMYK;    // Force display back to CMYK model
08619                 ColourPicker::SetComponentFromDouble(EditingColour, cc, ZComponent, NewZ);
08620             }
08621             break;
08622 
08623 
08624         case CEDRAG_CMYKPICKER_KEY:
08625             {
08626                 XPos = LastDragPos.x = 0;           // Make sure X move does not cause redraw
08627 
08628                 if (YPos < 0)
08629                     YPos = 0;
08630                 if (YPos > Info->dy - (PATCHSIZE + PixelSize*2))
08631                     YPos = Info->dy - (PATCHSIZE + PixelSize*2);
08632 
08633                 double NewValue = ((double)YPos) / ((double)(Info->dy - (PATCHSIZE + PixelSize*2)));
08634                 DisplayModel = COLOURMODEL_CMYK;    // Force display back to CMYK model
08635                 ColourPicker::SetComponentFromDouble(EditingColour, cc, 4, NewValue);
08636             }
08637             break;
08638 
08639 
08640         default:
08641             return;     // Not a legal drag, so we ignore it
08642     }
08643 
08644     // Delete the colour context if necessary
08645     if (bDeleteCC)
08646         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
08647 
08648     // If necessary, redraw the colour picker control and the colour patch
08649     if (ColourHasChanged)
08650     {
08651         if (StartingNewDrag || YPos != LastDragPos.y || XPos != LastDragPos.x)
08652         {
08653             InvalidateGadget(_R(IDC_EDIT_PICKER));
08654             PaintGadgetNow(_R(IDC_EDIT_PICKER));
08655         }
08656     }
08657 
08658     // Remember the last position at which we updated
08659     LastDragPos.y = YPos;
08660     LastDragPos.x = XPos;
08661 }
08662 
08663 
08664 
08665 /********************************************************************************************
08666 
08667 >   void ColourEditDlg::SetNewValueDefault(ReDrawInfoType *Info, INT32 PixelSize,
08668                                         BOOL StartingNewDrag)
08669 
08670     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
08671     Created:    13/12/94
08672     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
08673                 PixelSize - The size of display pixels as they appear when mapped into
08674                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
08675                 methods)
08676                 StartingNewDrag - TRUE if this is the first call to this function for a
08677                 new drag operation (in which case, the DragStartArea is set appropriately)
08678 
08679     Purpose:    Handles drag updates - determines the new colour values from the current
08680                 mouse position, and sets the colour as appropriate. Just how it interprets
08681                 the mouse position is dependant upon which region the drag was started
08682                 within, and which DisplayMode is in operation. A different routine like
08683                 this one will be called for each DisplayMode.
08684 
08685     Notes:      The default method is called for all DisplayModes which are not
08686                 specifically handled: It interprets mouse positions within the display
08687                 drawn by its sister redraw method, which provides up to 4 horizontal
08688                 component sliders.
08689 
08690     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault;
08691                 ColourEditDlg::RenderPickerDefault
08692 
08693 ********************************************************************************************/
08694 
08695 void ColourEditDlg::SetNewValueDefault(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
08696 {
08697 //  ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
08698     ColourContext *cc = NULL;
08699     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
08700     if (cc == NULL)
08701     {
08702         ERROR2RAW("Can't get a colour context for the DisplayModel!");
08703         return;
08704     }
08705 
08706     INT32 CurrentComponentIndex = 0;        // Work out the index of the slider being dragged
08707     if (!StartingNewDrag)
08708     {
08709         switch (DragStartArea)
08710         {
08711             case CEDRAG_DEFAULT_COMPONENT2:
08712                 CurrentComponentIndex = 1;
08713                 break;
08714 
08715             case CEDRAG_DEFAULT_COMPONENT3:
08716                 CurrentComponentIndex = 2;
08717                 break;
08718 
08719             case CEDRAG_DEFAULT_COMPONENT4:
08720                 CurrentComponentIndex = 3;
08721                 break;
08722 
08723             default:
08724                 break;
08725         }
08726     }
08727 
08728     // Get the slider rectangle widths. The height is fixed/moved during the loop below
08729     DocRect SliderRect(0, 0, Info->dx, Info->dy);
08730     SliderRect.hi.y -= PATCHSIZE + (PixelSize * 2);     // Allow space for the current colour patch
08731 
08732     // Count how many components we have to display
08733     INT32 NumComponents = 0;
08734     INT32 ComponentIndex;
08735     for (ComponentIndex = 1; ComponentIndex <= 4; ComponentIndex++)
08736     {
08737         if (cc->GetComponentName(ComponentIndex, NULL))
08738             NumComponents++;
08739     }
08740 
08741     // Calculate slider sizes and spacing
08742     INT32 SliderHeight = GetSliderHeight(SliderRect.Height(), NumComponents);
08743     INT32 SliderGap = GetSliderGap(SliderRect.Height(), NumComponents);
08744 
08745     // And move the top down by half a SliderGap, so the sliders are centered vertically
08746     SliderRect.hi.y -= SliderGap / 2;
08747 
08748     // Check the slider for each component supplied in the current DisplayModel
08749     for (ComponentIndex = 0; ComponentIndex <= 3; ComponentIndex++)
08750     {
08751         // Ensure slider rect is the correct height
08752         SliderRect.lo.y = SliderRect.hi.y - SliderHeight;
08753 
08754         // If we are just starting a new drag, we must determine which slider the mouse is
08755         // dragging. Otherwise, we need just go round the loop until we find the position
08756         // of the correct slider to use (so we can redraw only the changed slider)
08757         if (StartingNewDrag)
08758         {
08759             // If this component is available/used in this colour model, see if we are dragging it
08760             if (cc->GetComponentName(ComponentIndex+1, NULL))
08761             {
08762                 if (SliderRect.ContainsCoord(*(Info->pMousePos)))
08763                     break;
08764             }
08765         }
08766         else
08767         {
08768             // We've calculated where the slider rect is now, so we can continue on
08769             if (ComponentIndex == CurrentComponentIndex)
08770                 break;
08771         }
08772 
08773         // Move down to the next slider rectangle position
08774         SliderRect.hi.y = SliderRect.lo.y - SliderGap;
08775     }
08776 
08777     // ComponentIndex now contains the index of the component currently being
08778     // dragged (or it has the value 4 if no match was found)
08779     CurrentComponentIndex = ComponentIndex;
08780 
08781     if (StartingNewDrag)        // Work out which slider we are dragging
08782     {
08783         switch (CurrentComponentIndex)
08784         {
08785             case 0:
08786                 DragStartArea = CEDRAG_DEFAULT_COMPONENT1;
08787                 break;
08788 
08789             case 1:
08790                 DragStartArea = CEDRAG_DEFAULT_COMPONENT2;
08791                 break;
08792 
08793             case 2:
08794                 DragStartArea = CEDRAG_DEFAULT_COMPONENT3;
08795                 break;
08796 
08797             case 3:
08798                 DragStartArea = CEDRAG_DEFAULT_COMPONENT4;
08799                 break;
08800 
08801             default:
08802                 return;     // Not dragging anything draggable, so ignore them
08803         }
08804     }
08805 
08806 
08807     // Now, if the mouse position has changed, calculate the new component value, and
08808     // set it, as appropriate for the CurrentComponentIndex component
08809     if (StartingNewDrag || Info->pMousePos->x != LastDragPos.x)
08810     {
08811         INT32 Offset = Info->pMousePos->x;
08812         if (Offset < 0)
08813             Offset = 0;
08814 
08815         if (Offset > Info->dx)
08816             Offset = Info->dx;
08817 
08818         ERROR3IF(Info->dx == 0, "Control width is zero! Divide by zero about to occur!");
08819         double NewValue = (double)Offset / (double)Info->dx;
08820 
08821         ColourPicker::SetComponentFromDouble(EditingColour, cc, CurrentComponentIndex+1, NewValue);
08822 
08823         // If we are starting a new drag, or if we are in split-slider mode, we redraw everything
08824         if (StartingNewDrag || SplitLineDisplay)
08825             InvalidateGadget(_R(IDC_EDIT_PICKER));                      // Invalidate all sliders
08826         else
08827         {
08828             InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &SliderRect);   // Only invalidate changed slider
08829             InvalidatePatchGadget(Info);
08830         }
08831         PaintGadgetNow(_R(IDC_EDIT_PICKER));    
08832     }
08833 
08834     LastDragPos.x = Info->pMousePos->x;
08835     LastDragPos.y = 0;
08836 
08837     // Delete the colour context if necessary
08838     if (bDeleteCC)
08839         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
08840 }
08841 
08842 
08843 
08844 /********************************************************************************************
08845 
08846 >   void ColourEditDlg::SetNewValueTint(ReDrawInfoType *Info, INT32 PixelSize,
08847                                         BOOL StartingNewDrag)
08848 
08849     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
08850     Created:    2/10/95
08851 
08852     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
08853                 PixelSize - The size of display pixels as they appear when mapped into
08854                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
08855                 methods)
08856                 StartingNewDrag - TRUE if this is the first call to this function for a
08857                 new drag operation (in which case, the DragStartArea is set appropriately)
08858 
08859     Purpose:    Handles drag updates - determines the new colour values from the current
08860                 mouse position, and sets the colour as appropriate. 
08861 
08862                 Handles drags when editing Tints and Shades.
08863 
08864     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault;
08865                 ColourEditDlg::RenderPickerDefault
08866 
08867 ********************************************************************************************/
08868 
08869 void ColourEditDlg::SetNewValueTint(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
08870 {
08871     ERROR3IF(EditingColour->GetType() != COLOURTYPE_TINT,
08872                 "ColourEditDlg::SetNewValuTint called on non-tint/shade colour!");
08873 
08874     // Calculate the slider rectangle
08875     const INT32 SliderHeight = 18000;
08876     DocRect SliderRect(0, 0, Info->dx, Info->dy);
08877     SliderRect.Inflate(0, -(Info->dy - SliderHeight) / 2);
08878 
08879     if (StartingNewDrag)        // Work out which slider we are dragging
08880     {
08881         if (!SliderRect.ContainsCoord(*(Info->pMousePos)))
08882             return;
08883 
08884         DragStartArea = CEDRAG_TINTORSHADE;
08885     }
08886 
08887     // Now, if the mouse position has changed, calculate the new component value, and
08888     // set it, as appropriate for the CurrentComponentIndex component
08889     if (StartingNewDrag || Info->pMousePos->x != LastDragPos.x)
08890     {
08891         INT32 Offset = Info->pMousePos->x;
08892         if (Offset < 0)
08893             Offset = 0;
08894 
08895         if (Offset > Info->dx)
08896             Offset = Info->dx;
08897 
08898         ERROR3IF(Info->dx == 0, "Control width is zero! Divide by zero about to occur!");
08899         double NewValue = (double)Offset / (double)Info->dx;
08900         NewValue += 1.0 / ((double) (1<<25));
08901 
08902         // Clip to lie within gamut
08903         if (NewValue < 0.0)
08904             NewValue = 0.0;
08905 
08906         if (NewValue > 1.0)
08907             NewValue = 1.0;
08908 
08909         FIXED24 NewValue24(NewValue);
08910         EditingColour->SetTintValue(NewValue24);
08911 
08912         // If we are starting a new drag, or if we are in split-slider mode, we redraw everything
08913         if (StartingNewDrag)
08914             InvalidateGadget(_R(IDC_EDIT_PICKER));                      // Invalidate all sliders
08915         else
08916         {
08917             InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &SliderRect);   // Only invalidate changed slider area
08918             InvalidatePatchGadget(Info);
08919         }
08920         PaintGadgetNow(_R(IDC_EDIT_PICKER));    
08921     }
08922 
08923     LastDragPos.x = Info->pMousePos->x;
08924     LastDragPos.y = 0;
08925 }
08926 
08927 
08928 
08929 /********************************************************************************************
08930 
08931 >   void ColourEditDlg::SetNewValueShade(ReDrawInfoType *Info, INT32 PixelSize,
08932                                         BOOL StartingNewDrag)
08933 
08934     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
08935     Created:    13/10/95
08936     Inputs:     Info - The redraw info for the kernel-drawn control's mouse event
08937                 PixelSize - The size of display pixels as they appear when mapped into
08938                 the MILLIPOINT VirtualRect coordinate space (as used in the RenderControl
08939                 methods)
08940                 StartingNewDrag - TRUE if this is the first call to this function for a
08941                 new drag operation (in which case, the DragStartArea is set appropriately)
08942 
08943     Purpose:    Handles drag updates - determines the new colour values from the current
08944                 mouse position, and sets the colour as appropriate. Just how it interprets
08945                 the mouse position is dependant upon which region the drag was started
08946                 within, and which DisplayMode is in operation. A different routine like
08947                 this one will be called for each DisplayMode.
08948 
08949     SeeAlso:    ColourEditDlg::SetNewValueFromMousePos; ColourEditDlg::SetNewValueDefault
08950 
08951 ********************************************************************************************/
08952 
08953 void ColourEditDlg::SetNewValueShade(ReDrawInfoType *Info, INT32 PixelSize, BOOL StartingNewDrag)
08954 {
08955     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
08956     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
08957 
08958     // Calculate the two important rectangles - the hue slider, and Val/Sat square
08959     DocRect HueRect;
08960     DocRect ValSatSquare;
08961     CalculateHSVPickerRects(&VirtualSize, PixelSize, &HueRect, &ValSatSquare);
08962 
08963     // Get a colour context for our conversions and stuff
08964     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
08965 
08966     // Remember the old cross-position values from EditingColour
08967     ColourHSVT ColourDef;
08968     cc->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
08969 
08970     // If starting a new drag, determine which area the drag is in...
08971     if (StartingNewDrag)
08972     {
08973         if (!ValSatSquare.ContainsCoord(*(Info->pMousePos)))
08974         {
08975             // The user didn't hit inside a picker area, but have they tried to drag
08976             // a region outside that lies under a protuding marker cross?
08977             FIXED24 ReverseSat = FIXED24(1.0) - ColourDef.Saturation;
08978 
08979             if (!MousePosInCross(Info->pMousePos, &ValSatSquare, &ReverseSat, &ColourDef.Value))
08980                 return;     // Nope - just ignore the click
08981         }
08982 
08983         DragStartArea = CEDRAG_HSVPICKER_VSSQUARE;
08984 
08985         // Remember what the colour was as we started the drag
08986         cc->ConvertColour(ResultColour, &ColourBeforeDrag);
08987     }
08988 
08989 
08990     BOOL ColourHasChanged = FALSE;
08991     INT32 XPos;
08992     INT32 YPos;
08993 
08994     // Handle the new mouse position, using the area the drag started in (rather than
08995     // the area it may now be over) to determine which components to alter
08996     switch(DragStartArea)
08997     {
08998         case CEDRAG_HSVPICKER_VSSQUARE:
08999         {
09000             INT32 Size = ValSatSquare.Width();
09001 
09002             XPos = ValSatSquare.hi.x - Info->pMousePos->x;
09003             if (XPos < 0)       XPos = 0;
09004             if (XPos > Size)    XPos = Size;
09005 
09006             YPos = Info->pMousePos->y - ValSatSquare.lo.y;
09007             if (YPos < 0)       YPos = 0;
09008             if (YPos > Size)    YPos = Size;
09009 
09010             double NewSat = ((double)XPos) / ((double) Size);
09011             double NewVal = ((double)YPos) / ((double) Size);
09012 
09013             ColourHSVT ParentDef;
09014             cc->ConvertColour(EditingColour->FindLastLinkedParent(), (ColourGeneric *) &ParentDef);
09015 
09016             if (KeyPress::IsConstrainPressed())
09017             {
09018                 // If we should constrain this value, then we check the original
09019                 // values for Sat/Val, and we only change the one which is furthest
09020                 // away from the original value (i.e. if you drag near the old
09021                 // Saturation value, only the Value will change & vice versa)
09022 
09023                 // Shades constrain to their *parent* colour rather than their last definition
09024                 ColourHSVT *ConstrainDef = &ParentDef; //(ColourHSVT *) &ColourBeforeDrag;
09025 
09026                 double TempSat = ConstrainDef->Saturation.MakeDouble() - NewSat;
09027                 if (TempSat < 0.0) TempSat = -TempSat;
09028 
09029                 double TempVal = ConstrainDef->Value.MakeDouble() - NewVal;
09030                 if (TempVal < 0.0) TempVal = -TempVal;
09031 
09032                 if (TempSat < TempVal)
09033                     NewSat = ConstrainDef->Saturation.MakeDouble();
09034                 else
09035                     NewVal = ConstrainDef->Value.MakeDouble();
09036             }
09037 
09038             FIXED24 NewX(0.0);
09039             FIXED24 NewY(0.0);
09040 
09041             // Work out saturation scaling factor
09042             double ParentVal = ParentDef.Saturation.MakeDouble();
09043 
09044             if (ParentVal > NewSat)
09045             {
09046                 if (ParentVal > 0.0)
09047                     NewX = -((ParentVal - NewSat) / ParentVal);
09048             }
09049             else
09050             {
09051                 if (ParentVal < 1.0)
09052                     NewX = (NewSat - ParentVal) / (1.0 - ParentVal);
09053             }
09054 
09055             // Work out Value scaling factor
09056             ParentVal = ParentDef.Value.MakeDouble();
09057             if (ParentVal > NewVal)
09058             {
09059                 if (ParentVal > 0.0)
09060                     NewY = -((ParentVal - NewVal) / ParentVal);
09061             }
09062             else
09063             {
09064                 if (ParentVal < 1.0)
09065                     NewY = (NewVal - ParentVal) / (1.0 - ParentVal);
09066             }
09067 
09068 
09069             EditingColour->SetShadeValues(NewX, NewY);
09070 
09071             if (StartingNewDrag)
09072                 ColourHasChanged = TRUE;    // Always do full redraw when drag starts
09073             else
09074             {
09075                 // --- Invalidate the old cross position
09076                 DocRect CrossRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
09077 
09078                 INT32 TransX = ValSatSquare.hi.x - (INT32)
09079                             ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
09080                 INT32 TransY = ValSatSquare.lo.y + (INT32)
09081                             ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
09082 
09083                 CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
09084 
09085                 // Inflate by 2 pixels (the cross can actually draw marginally outside the crossrect ;-(
09086                 CrossRect.Inflate(4*PixelSize);
09087                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
09088 
09089 
09090                 // --- And invalidate the new cross position
09091                 CrossRect = DocRect(-CROSSRADIUS, -CROSSRADIUS, CROSSRADIUS, CROSSRADIUS);
09092 
09093                 cc->ConvertColour(EditingColour, (ColourGeneric *) &ColourDef);
09094                 TransX = ValSatSquare.hi.x - (INT32)
09095                             ((double)ValSatSquare.Width() * ColourDef.Saturation.MakeDouble());
09096                 TransY = ValSatSquare.lo.y + (INT32)
09097                             ((double)ValSatSquare.Height() * ColourDef.Value.MakeDouble());
09098 
09099                 CrossRect.Translate(HalfGridLock(TransX, PixelSize), HalfGridLock(TransY, PixelSize));
09100 
09101                 // Inflate by 2 pixels (the cross can actually draw marginally outside the crossrect ;-(
09102                 CrossRect.Inflate(4*PixelSize);
09103                 InvalidateGadget(_R(IDC_EDIT_PICKER), Info, &CrossRect);
09104 
09105                 PaintGadgetNow(_R(IDC_EDIT_PICKER));
09106     
09107                 InvalidatePatchGadget(Info);
09108 
09109                 // And leave ColourHasChanged as FALSE so that the code below does not do a ful redraw!
09110             }
09111             break;
09112         }
09113 
09114 
09115         default:
09116             return;     // Illegal drag -= just ignore it
09117     }
09118 
09119 
09120     // If necessary, redraw the picker and the colour patch
09121     if (ColourHasChanged || StartingNewDrag)
09122     {
09123         InvalidateGadget(_R(IDC_EDIT_PICKER));
09124         PaintGadgetNow(_R(IDC_EDIT_PICKER));
09125     }
09126 
09127     // Remember the last position at which we updated
09128     LastDragPos.y = YPos;
09129     LastDragPos.x = XPos;
09130 }
09131 
09132 
09133 
09134 /********************************************************************************************
09135 
09136 >   BOOL ColourEditDlg::HandleIdlePointer(ReDrawInfoType *Info, String_128 *BubbleHelp,
09137                                             String_256 *StatusHelp)
09138 
09139     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09140     Created:    16/10/95
09141     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09142                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09143 
09144     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09145                 mouse position.
09146 
09147                 StatusHelp - Returned containing appropriate status-line help.
09148 
09149                 ControlID - Returned with a unique "control" ID number for the "control" which
09150                 the pointer is over. Currently this means _R(IDC_EDIT_PATCH1) or _R(IDC_EDIT_PATCH2),
09151                 which are not real controls, but fake ones just to get a unique ID number for
09152                 the current/original colour patches.
09153 
09154     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09155                 (Bubble help will always be set to a valid string, possibly blank)
09156 
09157     Purpose:    Called when the mouse is idling over the colour picker control.
09158                 Sets appropriate pointer shapes, and also returns bubble help for
09159                 appropriate regions (probably only the original/current colour patches)
09160 
09161 ********************************************************************************************/
09162 
09163 BOOL ColourEditDlg::HandleIdlePointer(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp,
09164                                         UINT32 *ControlID)
09165 {
09166     BOOL Result = FALSE;
09167 
09168     ERROR3IF(Info == NULL || BubbleHelp == NULL || ControlID == NULL, "Illegal NULL params");
09169 
09170     // Return a valid string no matter what happens
09171     *BubbleHelp = String_128(_T(""));
09172     *StatusHelp = String_256(_T(""));
09173     *ControlID = 0;                         // No bubble help "control"
09174 
09175     if (EditingColour == NULL || AmShaded)      // We are shaded - abort
09176         return(FALSE);
09177 
09178     // Reset the cursor ID to none. If nobody changes this before the end of this function,
09179     // then the cursor will reset to the default (arrow or whatever). See SetCursor
09180 //  UINT32 OldCurrentCursor = CurrentCursorID;
09181     CurrentCursorID = 0;    
09182 
09183     // First, calculate all the regions and stuff...
09184     INT32 PixelSize = 72000 / Info->Dpi;        // Size of output pixel in millipoints
09185 
09186 
09187     // If the pointer is over the colour patches then handle it and return immediately, without
09188     // passing the call onto the specific picker.
09189 //  if (pointer in the current/original colour patches)
09190 //      Set up bubble help
09191 //      Change pointer?
09192 //      return(TRUE);
09193     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
09194     VirtualSize.Inflate(-PixelSize * 4);
09195 
09196     // Now draw the original/current colour patch in the top right corner
09197     DocRect PatchRect(VirtualSize);
09198     PatchRect.lo.x = PatchRect.hi.x - PATCHSIZE;
09199     PatchRect.lo.y = PatchRect.hi.y - PATCHSIZE;
09200     GridLockRect(&PatchRect, PixelSize);
09201 
09202     // Patches are horizontal if the colour model is not HSV
09203     BOOL HorzPatch = (DisplayModel != COLOURMODEL_HSVT);
09204 
09205     // But this setting is overridden for the special tint and shade modes
09206     if (EditingColour != NULL && EditingColour->GetType() == COLOURTYPE_TINT)
09207     {
09208         if (EditingColour->TintIsShade())
09209             HorzPatch = FALSE;
09210         else
09211             HorzPatch = TRUE;
09212     }
09213 
09214     {
09215         INT32 OverWhat = 0;
09216 
09217         if (PatchRect.ContainsCoord(*(Info->pMousePos)))
09218         {
09219             if (HorzPatch)
09220                 OverWhat = 1;
09221             else
09222                 OverWhat = 2;
09223         }
09224         else
09225         {
09226             if (HorzPatch)
09227                 PatchRect.Translate(-PATCHSIZE, 0);
09228             else
09229                 PatchRect.Translate(0, -PATCHSIZE);
09230 
09231             if (PatchRect.ContainsCoord(*(Info->pMousePos)))
09232             {
09233                 if (HorzPatch)
09234                     OverWhat = 2;
09235                 else
09236                     OverWhat = 1;
09237             }
09238         }
09239 
09240         if (OverWhat != 0)
09241         {
09242             if (OverWhat == 1)
09243             {
09244                 BubbleHelp->MakeMsg(_R(IDS_K_COLDLOG_CURRCOLBBL));
09245                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CURRCOLSTAT));
09246                 *ControlID = _R(IDC_EDIT_PATCH1);
09247             }
09248             else
09249             {
09250                 BubbleHelp->MakeMsg(_R(IDS_K_COLDLOG_ORIGCOLBBL));
09251                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_ORIGCOLSTAT));
09252                 *ControlID = _R(IDC_EDIT_PATCH2);
09253             }
09254 
09255             Result = TRUE;
09256         }
09257     }
09258 
09259     // Finally, if we haven't sorted ourselves out, call the relevant colour picker handler
09260     // for the current display mode etc
09261 
09262     if (BubbleHelp->IsEmpty())
09263     {
09264         if (EditingColour->GetType() == COLOURTYPE_TINT)
09265         {
09266             if (EditingColour->TintIsShade())
09267                 Result = HandleIdlePointerShade(Info, BubbleHelp, StatusHelp);
09268             else
09269                 Result = HandleIdlePointerTint(Info, BubbleHelp, StatusHelp);
09270         }
09271         else
09272         {
09273             switch (DisplayModel)
09274             {
09275                 case COLOURMODEL_HSVT:
09276                     Result = HandleIdlePointerHSV(Info, BubbleHelp, StatusHelp);
09277                     break;
09278 
09279                 case COLOURMODEL_RGBT:
09280                 case COLOURMODEL_WEBRGBT:
09281                     // RGB has the ability to change display modes, even when the colour is uneditable
09282                     // so we call the handler even when CanSetColour() == FALSE
09283                     if (Use3DDisplay)
09284                         Result = HandleIdlePointerRGB(Info, BubbleHelp, StatusHelp);
09285                     else
09286                         Result = HandleIdlePointerDefault(Info, BubbleHelp, StatusHelp);
09287                     break;
09288 
09289                 case COLOURMODEL_CMYK:
09290                     // CMYK has the ability to change display modes, even when the colour is uneditable
09291                     // so we call the handler even when CanSetColour() == FALSE
09292                     if (Use3DDisplay)
09293                         Result = HandleIdlePointerCMYK(Info, BubbleHelp, StatusHelp);
09294                     else
09295                         Result = HandleIdlePointerDefault(Info, BubbleHelp, StatusHelp);
09296                     break;
09297 
09298                 default:
09299                     Result = HandleIdlePointerDefault(Info, BubbleHelp, StatusHelp);
09300                     break;
09301             }
09302         }
09303     }
09304 
09305     // Last, set the appropriate cursor shape
09306 /*
09307     if (OldCurrentCursor != CurrentCursorID)
09308     {
09309 TRACEUSER( "Jason", _T("Cursor Change=%ld to %ld\n"), OldCurrentCursor, CurrentCursorID);
09310         if (CurrentCursor != NULL)
09311         {
09312             delete CurrentCursor;
09313             CurrentCursor = NULL;
09314         }
09315 
09316         if (CurrentCursorID != NULL)
09317         {
09318             CurrentCursor = new Cursor(CurrentCursorID);
09319             if (CurrentCursor != NULL)
09320                 CurrentCursor->SetActive();
09321         }
09322         else
09323         {
09324             if (Cursor::Arrow != NULL)
09325                 Cursor::Arrow->SetActive();
09326         }
09327     }
09328 */
09329     return(Result);
09330 }
09331 
09332 
09333 
09334 /********************************************************************************************
09335 
09336 >   void ColourEditDlg::SetCursor(UINT32 CursorResID)
09337 
09338     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09339     Created:    19/10/95
09340     Inputs:     CursorResID - NULL (arrow pointer), or a resource ID that specifies a cursor
09341 
09342     Purpose:    Called by HandleIdlePointerXXX functions to set the cursor shape they desire.
09343 
09344 
09345     Notes:      The base HandleIdlePointer function always resets the desired cursor ID to
09346                 a standard Arrow cursor before calling the picker-specific code. If the
09347                 called function does not set a cursor, then it will immediately revert.
09348 
09349                 This function does *not* set the cursor, just remembers what cursor is wanted
09350                 (Cursor setting is done in HandleIdlepointer)
09351 
09352 ********************************************************************************************/
09353 
09354 void ColourEditDlg::SetCursor(UINT32 CursorResID)
09355 {
09356 //  CurrentCursorID = CursorResID;
09357 
09358 //TRACEUSER( "Jason", _T("Cursor=%ld\n"), CursorResID);
09359 }
09360 
09361 
09362 
09363 /********************************************************************************************
09364 
09365 >   BOOL ColourEditDlg::HandleIdlePointerHSV(ReDrawInfoType *Info, String_128 *BubbleHelp,
09366                                             String_256 *StatusHelp)
09367 
09368     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09369     Created:    16/10/95
09370     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09371                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09372 
09373     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09374                 mouse position.
09375 
09376                 StatusHelp - Returned containing appropriate status-line help.
09377 
09378     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09379 
09380     Purpose:    Called when the mouse is idling over the colour picker control.
09381                 Sets appropriate pointer shapes, and also returns bubble help for
09382                 appropriate regions (probably only the original/current colour patches)
09383 
09384 ********************************************************************************************/
09385 
09386 BOOL ColourEditDlg::HandleIdlePointerHSV(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09387 {
09388     if (EditingColour->GetType() != COLOURTYPE_LINKED)
09389         return(FALSE);
09390 
09391     INT32 PixelSize = 72000 / Info->Dpi;            // Size of output pixel in millipoints
09392     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
09393     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
09394 
09395     // Calculate the two important rectangles - the hue slider, and Val/Sat square
09396     DocRect HueRect;
09397     DocRect ValSatSquare;
09398     CalculateHSVPickerRects(&VirtualSize, PixelSize, &HueRect, &ValSatSquare);
09399 
09400     if (HueRect.ContainsCoord(*(Info->pMousePos)) && EditingColour->InheritsComponent(1))
09401     {
09402         // SetCursor(No_can_drag_me_mate);
09403         StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_NOHUECHANGE));
09404     }
09405     else if (ValSatSquare.ContainsCoord(*(Info->pMousePos)))
09406     {
09407         if (EditingColour->InheritsComponent(2))
09408         {
09409             if (EditingColour->InheritsComponent(3))
09410                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_NOSATVALCHANGE));
09411             else
09412                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_NOSATCHANGE));
09413         }
09414         else if (EditingColour->InheritsComponent(3))
09415         {
09416             StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_NOVALCHANGE));
09417         }
09418     }
09419 
09420     return(StatusHelp->IsEmpty());
09421 }
09422 
09423 
09424 
09425 /********************************************************************************************
09426 
09427 >   BOOL ColourEditDlg::HandleIdlePointerRGB(ReDrawInfoType *Info, String_128 *BubbleHelp,
09428                                             String_256 *StatusHelp)
09429 
09430     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09431     Created:    16/10/95
09432     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09433                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09434 
09435     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09436                 mouse position.
09437 
09438                 StatusHelp - Returned containing appropriate status-line help.
09439 
09440     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09441 
09442     Purpose:    Called when the mouse is idling over the colour picker control.
09443                 Sets appropriate pointer shapes, and also returns bubble help for
09444                 appropriate regions (probably only the original/current colour patches)
09445 
09446 ********************************************************************************************/
09447 
09448 BOOL ColourEditDlg::HandleIdlePointerRGB(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09449 {
09450     INT32 PixelSize = 72000 / Info->Dpi;            // Size of output pixel in millipoints
09451 
09452     // Fill the control background, and calculate the cube params (without redraw)
09453     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
09454     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
09455 
09456     DocRect SquareRect;
09457     INT32 SizeZ;
09458     DrawCubeShadowAndCalcValues(NULL, &VirtualSize, PixelSize, NULL,
09459                                 /* TO */ &SquareRect, &SizeZ);
09460 
09461     DocRect CubeFaceRect(SquareRect);       // Remember the rect of the front face for below
09462 
09463     // Now, shift the square down from the front of the cube by an amount appropriate to
09464     // the Z-axis component of the colour
09465     ColourContextRGBT *cc = (ColourContextRGBT *)
09466                             ColourContext::GetGlobalDefault(COLOURMODEL_RGBT);
09467     ColourRGBT SourceColour;
09468     if (EditingColour != NULL)
09469         cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
09470 
09471     if (CanSetColour(EditingColour))
09472     {
09473         FIXED24 ZComponent = SourceColour.Blue;
09474         if (ColourPickerMode == 1)
09475             ZComponent = SourceColour.Green;
09476         else if (ColourPickerMode == 2)
09477             ZComponent = SourceColour.Red;
09478 
09479         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
09480         SquareRect.Translate(-ZTrans, ZTrans);
09481         GridLockRect(&SquareRect, PixelSize);
09482     }
09483 
09484     DocCoord BitmapPos;
09485     BitmapPos.x = HalfGridLock(CubeFaceRect.hi.x + SizeZ/2, PixelSize);
09486     BitmapPos.y = HalfGridLock(CubeFaceRect.hi.y - SizeZ/2, PixelSize);
09487 
09488     const INT32 BitmapSize = 14 * PixelSize;
09489     DocRect SwapAxesRect(BitmapPos.x, BitmapPos.y,
09490                             BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
09491     GridLockRect(&SwapAxesRect, PixelSize);
09492 
09493     if (SwapAxesRect.ContainsCoord(*(Info->pMousePos)))
09494     {
09495         StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CLICKTOCYCLE));
09496         return(TRUE);
09497     }
09498 
09499     if (EditingColour->GetType() != COLOURTYPE_LINKED)
09500         return(FALSE);
09501 
09502     if (SquareRect.ContainsCoord(*(Info->pMousePos)))
09503     {
09504         INT32 C1 = 1;
09505         INT32 C2 = 2;
09506         if (ColourPickerMode == 1)
09507             C1 = 3;
09508         else if (ColourPickerMode == 2)
09509             C2 = 3;
09510 
09511         INT32 Count = 0;
09512 
09513         if (EditingColour->InheritsComponent(C1))
09514             Count++;
09515 
09516         if (EditingColour->InheritsComponent(C2))
09517             Count++;
09518 
09519         if (Count == 1)
09520             StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_DRAGINONEDIR));
09521         else if (Count == 2)
09522             StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAG));
09523     }
09524     else
09525     {
09526         // Check if the pointer is in the Z 'drag button'
09527         DocRect ZButton(SquareRect);
09528         ZButton.lo.x = ZButton.hi.x;
09529         ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
09530         ZButton.hi.y = ZButton.lo.y;
09531         ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
09532         GridLockRect(&ZButton, PixelSize);
09533 
09534         if (ZButton.ContainsCoord(*(Info->pMousePos)))
09535         {
09536             INT32 ComponentID = ColourPickerMode;
09537             if (ComponentID == 0)
09538                 ComponentID = 3;
09539 
09540             if (EditingColour->InheritsComponent(ComponentID))
09541                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAG2));
09542         }
09543     }
09544 
09545     return(StatusHelp->IsEmpty());
09546 }
09547 
09548 
09549 
09550 /********************************************************************************************
09551 
09552 >   BOOL ColourEditDlg::HandleIdlePointerCMYK(ReDrawInfoType *Info, String_128 *BubbleHelp,
09553                                             String_256 *StatusHelp)
09554 
09555     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09556     Created:    16/10/95
09557     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09558                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09559 
09560     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09561                 mouse position.
09562 
09563                 StatusHelp - Returned containing appropriate status-line help.
09564 
09565     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09566 
09567     Purpose:    Called when the mouse is idling over the colour picker control.
09568                 Sets appropriate pointer shapes, and also returns bubble help for
09569                 appropriate regions (probably only the original/current colour patches)
09570 
09571 ********************************************************************************************/
09572 
09573 BOOL ColourEditDlg::HandleIdlePointerCMYK(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09574 {
09575     INT32 PixelSize = 72000 / Info->Dpi;            // Size of output pixel in millipoints
09576 
09577     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
09578     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
09579 
09580     // Determine how much space is left over after the key slider has been placed
09581     INT32 KeySliderLeft = VirtualSize.hi.x - (CROSSRADIUS+PixelSize)*2;
09582     ERROR3IF(KeySliderLeft < VirtualSize.lo.x,
09583                 "Not enough room to render the colour picker!");
09584 
09585     // Fill the control background, and draw the cube 'shadow'
09586     DocRect CubeAvailableSpace(VirtualSize);
09587     CubeAvailableSpace.hi.x = KeySliderLeft - 2000;
09588 
09589     DocRect SquareRect;
09590     INT32 SizeZ;
09591     DrawCubeShadowAndCalcValues(NULL, &CubeAvailableSpace, PixelSize, NULL,
09592                                  &SquareRect, &SizeZ);
09593 
09594     DocRect CubeFaceRect(SquareRect);       // Remember the rect of the front face for below
09595 
09596 
09597     // Now, shift the square down from the front of the cube by an amount appropriate to
09598     // the Z-axis component of the colour
09599 //  ColourContextCMYK *cc = (ColourContextCMYK *)ColourContext::GetGlobalDefault(COLOURMODEL_CMYK);
09600     ColourContext *cc = NULL;
09601     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
09602     ColourCMYK SourceColour;
09603 
09604     if (EditingColour != NULL)
09605         cc->ConvertColour(EditingColour, (ColourGeneric *) &SourceColour);
09606 
09607     // Delete the colour context if necessary
09608     if (bDeleteCC)
09609         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
09610 
09611     if (CanSetColour(EditingColour))
09612     {
09613         FIXED24 ZComponent = SourceColour.Magenta;
09614         if (ColourPickerMode == 1)
09615             ZComponent = SourceColour.Cyan;
09616         else if (ColourPickerMode == 2)
09617             ZComponent = SourceColour.Yellow;
09618 
09619         INT32 ZTrans = (INT32) ((double)SizeZ * ZComponent.MakeDouble()) - SizeZ;
09620         SquareRect.Translate(-ZTrans, ZTrans);
09621         GridLockRect(&SquareRect, PixelSize);
09622     }
09623 
09624     DocCoord BitmapPos;
09625     BitmapPos.x = HalfGridLock(CubeFaceRect.hi.x + SizeZ/2, PixelSize);
09626     BitmapPos.y = HalfGridLock(CubeFaceRect.hi.y - SizeZ/2, PixelSize);
09627 
09628     const INT32 BitmapSize = 14 * PixelSize;
09629     DocRect SwapAxesRect(BitmapPos.x, BitmapPos.y,
09630                             BitmapPos.x + BitmapSize + PixelSize * 3, BitmapPos.y + BitmapSize);
09631     GridLockRect(&SwapAxesRect, PixelSize);
09632 
09633     if (SwapAxesRect.ContainsCoord(*(Info->pMousePos)))
09634     {
09635         StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CLICKTOCYCLE2));
09636         return(TRUE);
09637     }
09638 
09639     if (EditingColour->GetType() != COLOURTYPE_LINKED)
09640         return(FALSE);
09641 
09642     if (SquareRect.ContainsCoord(*(Info->pMousePos)))
09643     {
09644         INT32 C1 = 1;
09645         INT32 C2 = 3;
09646         if (ColourPickerMode == 1)
09647             C1 = 2;
09648         else if (ColourPickerMode == 2)
09649             C2 = 2;
09650 
09651         INT32 Count = 0;
09652 
09653         if (EditingColour->InheritsComponent(C1))
09654             Count++;
09655 
09656         if (EditingColour->InheritsComponent(C2))
09657             Count++;
09658 
09659         if (Count == 1)
09660             StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_DRAGINONEDIR));
09661         else if (Count == 2)
09662             StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAG));
09663     }
09664     else
09665     {
09666         // Check if the pointer is in the Z 'drag button'
09667         DocRect ZButton(SquareRect);
09668         ZButton.lo.x = ZButton.hi.x;
09669         ZButton.hi.x += ZSLIDERSIZE - (PixelSize * 2);
09670         ZButton.hi.y = ZButton.lo.y;
09671         ZButton.lo.y -= ZSLIDERSIZE - (PixelSize * 2);
09672         GridLockRect(&ZButton, PixelSize);
09673 
09674         if (ZButton.ContainsCoord(*(Info->pMousePos)))
09675         {
09676             // How on earth did all of this get so out of hand?!
09677             INT32 ComponentID = 2;
09678             if (ColourPickerMode == 1)
09679                 ComponentID = 1;
09680             else if (ColourPickerMode == 2)
09681                 ComponentID = 3;
09682 
09683             if (EditingColour->InheritsComponent(ComponentID))
09684                 StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAG2));
09685         }
09686         else
09687         {
09688             // Check if the pointer is in the Key slider
09689             DocRect KeyRect(KeySliderLeft, 0, Info->dx, Info->dy - (PATCHSIZE + PixelSize*2));
09690             if (KeyRect.ContainsCoord(*(Info->pMousePos)))
09691             {
09692                 if (EditingColour->InheritsComponent(4))
09693                     StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAGKEY));
09694             }
09695         }
09696     }
09697 
09698     return(StatusHelp->IsEmpty());
09699 }
09700 
09701 
09702 
09703 /********************************************************************************************
09704 
09705 >   BOOL ColourEditDlg::HandleIdlePointerDefault(ReDrawInfoType *Info, String_128 *BubbleHelp,
09706                                                     String_256 *StatusHelp)
09707 
09708     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09709     Created:    16/10/95
09710     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09711                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09712 
09713     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09714                 mouse position.
09715 
09716                 StatusHelp - Returned containing appropriate status-line help.
09717 
09718     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09719 
09720     Purpose:    Called when the mouse is idling over the colour picker control.
09721                 Sets appropriate pointer shapes, and also returns bubble help for
09722                 appropriate regions (probably only the original/current colour patches)
09723 
09724 ********************************************************************************************/
09725 
09726 BOOL ColourEditDlg::HandleIdlePointerDefault(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09727 {
09728     if (EditingColour->GetType() != COLOURTYPE_LINKED)
09729         return(FALSE);
09730 
09731 //  ColourContext *cc = ColourContext::GetGlobalDefault(DisplayModel);
09732     ColourContext *cc = NULL;
09733     BOOL bDeleteCC = GetColourContext(DisplayModel, &cc);   
09734     if (cc == NULL)
09735         return(FALSE);
09736 
09737     // Get the slider rectangle widths. The height is fixed/moved during the loop below
09738     INT32 PixelSize = 72000 / Info->Dpi;                    // Size of output pixel in millipoints
09739     DocRect SliderRect(0, 0, Info->dx, Info->dy);
09740     SliderRect.hi.y -= PATCHSIZE + (PixelSize * 2);     // Allow space for the current colour patch
09741 
09742     // Count how many components we have to display
09743     INT32 NumComponents = 0;
09744     INT32 ComponentIndex;
09745     for (ComponentIndex = 1; ComponentIndex <= 4; ComponentIndex++)
09746     {
09747         if (cc->GetComponentName(ComponentIndex, NULL))
09748             NumComponents++;
09749     }
09750 
09751     // Calculate slider sizes and spacing
09752     INT32 SliderHeight = GetSliderHeight(SliderRect.Height(), NumComponents);
09753     INT32 SliderGap = GetSliderGap(SliderRect.Height(), NumComponents);
09754 
09755     // And move the top down by half a SliderGap, so the sliders are centered vertically
09756     SliderRect.hi.y -= SliderGap / 2;
09757 
09758     // Check the slider for each component supplied in the current DisplayModel
09759     for (ComponentIndex = 0; ComponentIndex <= 3; ComponentIndex++)
09760     {
09761         // Ensure slider rect is the correct height
09762         SliderRect.lo.y = SliderRect.hi.y - SliderHeight;
09763 
09764         // If this component is available/used in this colour model, see if we are dragging it
09765         if (cc->GetComponentName(ComponentIndex+1, NULL))
09766         {
09767             if (SliderRect.ContainsCoord(*(Info->pMousePos)))
09768             {
09769                 if (EditingColour->InheritsComponent(ComponentIndex+1))
09770                     StatusHelp->MakeMsg(_R(IDS_K_COLDLOG_CANTDRAG2));
09771                 return(StatusHelp->IsEmpty());
09772             }
09773         }
09774 
09775         // Move down to the next slider rectangle position
09776         SliderRect.hi.y = SliderRect.lo.y - SliderGap;
09777     }
09778 
09779     // Delete the colour context if necessary
09780     if (bDeleteCC)
09781         ColourContextList::GetList()->RemoveContext(&cc);           // Have finished with it
09782 
09783     return(FALSE);
09784 }
09785 
09786 
09787 
09788 /********************************************************************************************
09789 
09790 >   BOOL ColourEditDlg::HandleIdlePointerTint(ReDrawInfoType *Info, String_128 *BubbleHelp,
09791                                             String_256 *StatusHelp)
09792 
09793 
09794     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09795     Created:    16/10/95
09796     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09797                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09798 
09799     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09800                 mouse position.
09801 
09802                 StatusHelp - Returned containing appropriate status-line help.
09803 
09804     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09805 
09806     Purpose:    Called when the mouse is idling over the colour picker control.
09807                 Sets appropriate pointer shapes, and also returns bubble help for
09808                 appropriate regions (probably only the original/current colour patches)
09809 
09810 ********************************************************************************************/
09811 
09812 BOOL ColourEditDlg::HandleIdlePointerTint(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09813 {
09814     return(FALSE);
09815 }
09816 
09817 
09818 
09819 /********************************************************************************************
09820 
09821 >   BOOL ColourEditDlg::HandleIdlePointerShade(ReDrawInfoType *Info, String_128 *BubbleHelp,
09822                                             String_256 *StatusHelp)
09823 
09824 
09825     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09826     Created:    16/10/95
09827     Inputs:     Info - Kernel-rendered gadget info indicating where the mouse pointer is
09828                 over the colour picker (_R(IDC_EDIT_PICKER)) control
09829 
09830     Outputs:    BubbleHelp - Returned containing the new bubble help string to use for this
09831                 mouse position.
09832 
09833     Returns:    TRUE if the bubble help is valid, FALSE if there is no new bubble help
09834 
09835                 StatusHelp - Returned containing appropriate status-line help.
09836 
09837     Purpose:    Called when the mouse is idling over the colour picker control.
09838                 Sets appropriate pointer shapes, and also returns bubble help for
09839                 appropriate regions (probably only the original/current colour patches)
09840 
09841 ********************************************************************************************/
09842 
09843 BOOL ColourEditDlg::HandleIdlePointerShade(ReDrawInfoType *Info, String_128 *BubbleHelp, String_256 *StatusHelp)
09844 {
09845 /*
09846     DocRect VirtualSize(0, 0, Info->dx, Info->dy);
09847     VirtualSize.Inflate(-PixelSize * 4);        // And exclude the border
09848 
09849     // Calculate the two important rectangles - the hue slider, and Val/Sat square
09850     DocRect HueRect;
09851     DocRect ValSatSquare;
09852     CalculateHSVPickerRects(&VirtualSize, PixelSize, &HueRect, &ValSatSquare);
09853 
09854     if (!ValSatSquare.ContainsCoord(*(Info->pMousePos)))
09855         return;
09856 
09857     */
09858 
09859     return(FALSE);
09860 }
09861 
09862 
09863 
09864 
09865 
09866 /********************************************************************************************
09867 
09868 >   OpState ColourEditDlg::GetState(String_256*, OpDescriptor*)
09869 
09870     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09871     Created:    13/6/94
09872     Inputs:     -
09873     Outputs:    -
09874     Returns:    -
09875     Purpose:    Get the state of the Colour editor dialogue op
09876     Errors:     -
09877     SeeAlso:    -
09878 
09879 ********************************************************************************************/
09880 
09881 OpState ColourEditDlg::GetState(String_256*, OpDescriptor*)
09882 {    
09883     OpState OpSt;
09884 
09885     // Tick the menu while the editor is open
09886     if (TheEditor != NULL)
09887         OpSt.Ticked = TRUE;
09888 
09889     return(OpSt);
09890 }
09891 
09892 
09893 
09894 /********************************************************************************************
09895 
09896 >   static BOOL ColourEditDlg::Init()
09897 
09898     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09899     Created:    13/6/94
09900     Inputs:     -
09901     Outputs:    -
09902     Returns:    -
09903     Purpose:    Initialises the colour editor dialogue op
09904     Errors:     -
09905     SeeAlso:    -
09906 
09907 ********************************************************************************************/
09908 
09909 BOOL ColourEditDlg::Init()
09910 {
09911     Camelot.DeclareSection(TEXT("Displays"), 9);
09912     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorDisplayModel"), &DefaultDisplayModel);
09913     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorDisplayModelS"), &DefaultDisplayModelN);
09914     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorAutoModel"), &AutoModelChange);
09915     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorAutoModelS"), &AutoModelChangeN);
09916     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorFolded"), &Folded);
09917     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorSplitLine"), &SplitLineDisplay);
09918     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorUse3D"), &Use3DDisplay);
09919     Camelot.DeclarePref(TEXT("Displays"), TEXT("ColourEditorHSVHueTop"), &bHSVHueAtTop);
09920     Camelot.DeclarePref(TEXT("Displays"), TEXT("UsePrintCMYK"), &bUsePrintCMYK);
09921 
09922     DisplayModel = (ColourModel) DefaultDisplayModel;
09923     ColourContext *DefCC = NULL;
09924     BOOL bDeleteCC = GetColourContext(DisplayModel, &DefCC);
09925     if (DefCC == NULL)
09926     {
09927         DisplayModel = COLOURMODEL_HSVT;
09928         DefaultDisplayModel = (INT32) COLOURMODEL_HSVT;
09929     }
09930     // Delete the colour context if necessary
09931     if (bDeleteCC)
09932         ColourContextList::GetList()->RemoveContext(&DefCC);            // Have finished with it
09933 
09934     bDeleteCC = GetColourContext((ColourModel)DefaultDisplayModelN, &DefCC);
09935     if (DefCC == NULL)
09936         DefaultDisplayModelN = (INT32) COLOURMODEL_HSVT;
09937 
09938     // Delete the colour context if necessary
09939     if (bDeleteCC)
09940         ColourContextList::GetList()->RemoveContext(&DefCC);            // Have finished with it
09941 
09942 #ifdef DISABLE_WEBHEXRGBT
09943     if (DisplayModel==COLOURMODEL_WEBHEXRGBT)
09944         DisplayModel = COLOURMODEL_RGBT;
09945 #endif
09946 
09947     // Initialise all of our menu command Ops
09948     if (!OpColEditCommand::Init())
09949         return(FALSE);
09950 
09951     // And initialise our own op
09952     return(RegisterOpDescriptor(0,                                  // Tool ID 
09953                                 _R(IDS_COLOUREDITDLG),                  // String resource ID
09954                                 CC_RUNTIME_CLASS(ColourEditDlg),    // Runtime class
09955                                 OPTOKEN_COLOUREDITDLG,              // Token string
09956                                 ColourEditDlg::GetState,            // GetState function
09957                                 0,                                  // help ID
09958                                 _R(IDBBL_COLOUREDITOR),                 // bubble help
09959                                 _R(IDD_BARCONTROLSTORE),                // resource ID
09960                                 _R(IDC_COLOUREDITOR),                   // control ID
09961                                 SYSTEMBAR_UTILITIES,                // Bar ID
09962                                 TRUE,                               // Recieve system messages
09963                                 FALSE,                              // Smart duplicate operation
09964                                 TRUE,                               // Clean operation
09965                                 0,                                  // No vertical counterpart
09966                                 0,                                  // String for one copy only error
09967                                 DONT_GREY_WHEN_SELECT_INSIDE,       // Auto state flags
09968                                 TRUE                                // Tickable
09969                                 ));
09970 }
09971 
09972 
09973 
09974 /********************************************************************************************
09975 
09976 >   BOOL ColourEditDlg::Create()
09977 
09978     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
09979     Created:    13/6/94
09980     Inputs:     -
09981     Outputs:    -
09982     Returns:    FALSE if it fails
09983     Purpose:    Creates a colour editor dialogue box. Fails if DialogOp::Create
09984                 fails to create the box.
09985     Errors:     -
09986     SeeAlso:    -
09987 
09988 ********************************************************************************************/
09989 
09990 BOOL ColourEditDlg::Create()
09991 {
09992     ISentTheMessage = FALSE;    // Ensure our message lock is disabled
09993     AmShaded        = FALSE;    // We are not currently in a shaded state
09994     m_bDoTimerProcessing = TRUE;
09995     if (TheEditor != this)      // Allow only one instance of this dialogue open at once
09996         return(FALSE);
09997 
09998 
09999     if (EditingColour != NULL && ParentList == NULL)
10000     {
10001         ERROR3("ColourEditDlg not correctly initialised before call to Create()");
10002         return(FALSE);
10003     }
10004 
10005     if (DialogOp::Create())
10006     { 
10007 //      SetControls();      -- now done by DIM_CREATE handler
10008         return(TRUE);
10009     }
10010 
10011     return(FALSE);
10012 }
10013 
10014 
10015 
10016 /********************************************************************************************
10017 
10018 >   void ColourEditDlg::Do(OpDescriptor*)
10019 
10020     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10021     Created:    13/6/94
10022 
10023     Purpose:    Toggles the colour editor, and if opening it, finds a useful colour to edit
10024 
10025     SeeAlso:    ColourEditDlg::DoWithParam
10026 
10027 ********************************************************************************************/
10028 
10029 void ColourEditDlg::Do(OpDescriptor*)
10030 {
10031     if (TheEditor != NULL && TheEditor != this)
10032     {
10033         // If there is an editor open, just ask it to die then kill ourself off, as
10034         // we don't want another editor to then pop up!
10035         TheEditor->Close();
10036         TheEditor->End();   // Kill existing editor
10037 
10038         End();              // Kill ourself
10039         return;
10040     }
10041 
10042 
10043     if (EditingColour != NULL)
10044     {
10045         delete EditingColour;
10046         EditingColour = NULL;
10047     }
10048     
10049     // WEBSTER - markn 31/1/97
10050     // Bodge - uses the Named default value to keep that model preserved
10051 #ifndef WEBSTER
10052     DisplayModel = (ColourModel) DefaultDisplayModel;
10053 #else
10054     DisplayModel = (ColourModel) DefaultDisplayModelN;
10055 #endif // WEBSTER
10056 
10057     FindUsefulColourToEdit(EditingLineColour, FALSE);
10058 
10059     Progress Hourglass;     // Start an hourglass running
10060 
10061     if (Create())
10062     {
10063         Open();                             // Open the dialogue (& set the controls etc)
10064         PaintGadgetNow(_R(IDC_EDIT_PICKER));    // Redraw picker while hourglass is still up
10065     }
10066     else
10067         End();
10068 }
10069 
10070 
10071 
10072 /********************************************************************************************
10073 
10074 >   void ColourEditDlg::DoWithParam(OpDescriptor *MyOpDesc, OpParam *Param)
10075 
10076     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10077     Created:    13/6/94
10078     Inputs:     MyOpDesc - as usual, the opdescriptor of this thingo
10079                 Param - points to a ColourEditDlgParam object
10080     Outputs:    -
10081     Returns:    -
10082     Purpose:    'Does' a colour editor dialogue op. Shows the dialogue.
10083     Scope:      private
10084     Errors:     -
10085     SeeAlso:    ColourEditDlgParam::ColourEditDlgParam
10086 
10087 ********************************************************************************************/
10088 
10089 void ColourEditDlg::DoWithParam(OpDescriptor *MyOpDedsc, OpParam *Param)
10090 {
10091     ERROR3IF(Param == NULL, "ColourEditDlg::DoWithParam - NULL Param passed in");
10092     ERROR3IF(!Param->IsKindOf(CC_RUNTIME_CLASS(ColourEditDlgParam)),
10093                 "ColourEditDlg::DoWithParam - Param is illegal");
10094 
10095     // Initialise ourselves from the supplied parameters
10096     ColourEditDlgParam *Info = (ColourEditDlgParam *) Param;
10097 
10098     if (Info->ParentList == NULL)
10099         Info->ParentList = ColourManager::GetColourList();
10100 
10101     // Determine if we can safely edit this colour
10102     // NOTE that the TRUE is used to cause side effects on the EditingLineColour flag,
10103     // and we will always edit a colour, even if this function returns FALSE. (But if
10104     // it is FALSE, we will edit a "useful" colour)
10105     if (!CanYouEditThis(Info->ParentList, Info->ColourToEdit, TRUE))
10106         Info->ColourToEdit = NULL;  // You can't do that! Choose a "useful" colour to edit instead
10107 
10108     if (TheEditor != NULL && TheEditor != this)
10109     {
10110         // If there is an editor open, bring it to the top of the window stack, and ask it
10111         // to swap to the ColourToEdit, or a useful local colour if ColourToEdit is NULL
10112         TheEditor->BringToTop();
10113 
10114         if (Info->ColourToEdit == NULL)
10115             TheEditor->FindUsefulColourToEdit(TheEditor->EditingLineColour, TRUE);
10116         else
10117             TheEditor->EditThisColour(Info->ParentList, Info->ColourToEdit);
10118 
10119         // And kill ourself off, as we don't want multiple instantiations of the editor open
10120         End();
10121         return;
10122     }
10123 
10124     if (Document::GetSelected() == NULL ||
10125         (Info->ParentList != NULL && Document::GetSelected()->GetIndexedColours() != Info->ParentList))
10126     {
10127         ERROR3("Colour editor: No selected doc or Colour not in selected doc");
10128         End();
10129         return;
10130     }
10131 
10132     // Check that the colour given really truly is in the parent list, but only if we've got a colour/list
10133     if (Info->ColourToEdit != NULL && Info->ParentList != NULL &&                                                           // Have a valid pointer
10134             Info->ParentList->FindPosition(Info->ColourToEdit) < 0 &&                       // Isn't in named colours
10135             Info->ParentList->GetUnnamedColours()->FindPosition(Info->ColourToEdit) < 0 )   // Isn't in unnamed colours
10136     {
10137         ERROR3("Colour editor: attempt to edit colour with bogus parent list pointer");
10138         End();
10139         return;
10140     }
10141 
10142     ParentList      = Info->ParentList;                 // The list in which the edited colour resides
10143     ResultColour    = Info->ColourToEdit;               // The colour to recieve the result
10144 
10145     if (EditingColour != NULL)
10146     {
10147         delete EditingColour;
10148         EditingColour = NULL;
10149     }
10150     
10151     if (ResultColour != NULL)
10152     {
10153         FirstEdit = TRUE;
10154         EditingColour   = new IndexedColour(*ResultColour); // The colour we're working on for now
10155             
10156         if (EditingColour == NULL)
10157         {
10158             InformError();
10159             End();
10160             return;
10161         }
10162 
10163         // Copy the original colour into the OriginalColour.
10164         // We only need the colour definition, but we do need the full accuracy of an
10165         // IndexedColour to ensure rounding errors (and thus slight dither differences in
10166         // redraw) do not occur.
10167         OriginalColour = *ResultColour;
10168 
10169         // Ensure the OriginalColour does not reference any other colour
10170         OriginalColour.SetLinkedParent(NULL, COLOURTYPE_NORMAL);
10171     }
10172     else
10173     {
10174         FindUsefulColourToEdit(EditingLineColour, FALSE);
10175     }
10176 
10177     if (EditingColour != NULL)
10178     {
10179         StatusLine* pStatusLine = StatusLine::Get();
10180         
10181         if (EditingColour->IsNamed())
10182         {
10183             if (!pStatusLine || (pStatusLine->IsRestrictedAccessToColourPicker () == FALSE))
10184             {
10185                 if (AutoModelChangeN)
10186                 {
10187                     DisplayModel = OriginalColour.GetColourModel();
10188                     // WEBSTER - markn 14/1/97
10189                     // Make sure the display model is either HSV or RGB
10190                     // If it's neither RGB or HSV, force it to HSV
10191                     #ifdef WEBSTER
10192                     if (DisplayModel != COLOURMODEL_RGBT && DisplayModel != COLOURMODEL_HSVT)
10193                         DisplayModel = COLOURMODEL_HSVT;
10194                     #endif // WEBSTER
10195 #ifdef DISABLE_WEBHEXRGBT
10196                     if (DisplayModel == COLOURMODEL_WEBHEXRGBT)
10197                         DisplayModel == COLOURMODEL_RGBT;
10198 #endif
10199                 }
10200             }
10201         }
10202         else
10203         {
10204             if (pStatusLine->IsRestrictedAccessToColourPicker () == FALSE)
10205             {
10206                 if (AutoModelChange)
10207                     DisplayModel = OriginalColour.GetColourModel();
10208 #ifdef DISABLE_WEBHEXRGBT
10209                     if (DisplayModel == COLOURMODEL_WEBHEXRGBT)
10210                         DisplayModel == COLOURMODEL_RGBT;
10211 #endif
10212             }
10213         }
10214     }
10215 
10216     Progress Hourglass;         // Start an hourglass running
10217 
10218     if (Create())
10219     {
10220         Open();                             // Open the dialogue (& set the controls etc)
10221         PaintGadgetNow(_R(IDC_EDIT_PICKER));    // Redraw picker while hourglass is still up
10222     }
10223     else
10224         End();
10225 }
10226 
10227 
10228 
10229 /********************************************************************************************
10230 
10231 >   static void ColourEditDlg::InvokeDialog(ColourList *ParentList,
10232                                             IndexedColour *ColourToEdit)
10233 
10234     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10235     Created:    14/6/94
10236     Inputs:     ParentList - the ColourList in which the colour to be edited resides
10237                 May be NULL to use the Selected Document's colour list
10238 
10239                 ColourToEdit - the IndexedColour which you wish to edit. May be NULL
10240                 in which case the editor will try to find a useful local colour to
10241                 edit, or shade itself.
10242 
10243     Purpose:    Causes a modeless colour editor to appear for the given colour. Some time
10244                 down the track, if the user commits a change to that colour, the system
10245                 will be notified of that change via a ColourChangingMsg broadcast.
10246 
10247     SeeAlso:    ColourEditDlg::CanYouEditThis; ColourPicker::EditColour
10248 
10249 ********************************************************************************************/
10250 
10251 void ColourEditDlg::InvokeDialog(ColourList *ParentList, IndexedColour *ColourToEdit)
10252 {   
10253     if (ParentList == NULL)
10254         ParentList = ColourManager::GetColourList();
10255 
10256     // Determine if we can safely edit this colour
10257     // NOTE that the TRUE is used to cause side effects on the EditingLineColour flag,
10258     // and we will always edit a colour, even if this function returns FALSE. (But if
10259     // it is FALSE, we will edit a "useful" colour)
10260     if (!CanYouEditThis(ParentList, ColourToEdit, TRUE))
10261         ColourToEdit = NULL;    // You can't do that! Choose a "useful" colour to edit instead
10262 
10263     if (TheEditor != NULL)
10264     {
10265         // If there is an editor open, bring it to the top of the window stack, and ask it
10266         // to swap to the ColourToEdit, or a useful local colour if ColourToEdit is NULL
10267         TheEditor->BringToTop();
10268 
10269         if (ColourToEdit == NULL)
10270             TheEditor->FindUsefulColourToEdit(TheEditor->EditingLineColour, TRUE);
10271         else
10272             TheEditor->EditThisColour(ParentList, ColourToEdit);
10273         return;
10274     }
10275 
10276     // need to set/reset static variables that control where my (as in Chris Snook) custom
10277     // colour picker control appears .....
10278 
10279     resetColPickPos = FALSE;
10280     needColPickHidden = FALSE;
10281     colPickHidden = FALSE;
10282 
10283     // Otherwise, invoke the dialogue to bring it up
10284     ColourEditDlgParam EditInfo(ParentList, ColourToEdit);
10285     OpDescriptor *EditDlg = OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(ColourEditDlg));
10286 
10287     ERROR3IF(EditDlg == NULL,
10288              "ColourEditDlg::InvokeDialog is unable to find the ColourEditDlg OpDescriptor");
10289 
10290     if (EditDlg != NULL)
10291         EditDlg->Invoke(&EditInfo);
10292 }
10293 
10294 
10295 
10296 /********************************************************************************************
10297 
10298 >   static BOOL ColourEditDlg::CanYouEditThis(ColourList *ParentList, IndexedColour *ColourToEdit,
10299                                                 BOOL ForceNewMode = FALSE)
10300 
10301     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10302     Created:    26/3/96
10303 
10304     Inputs:     ParentList - the ColourList in which the colour to be edited resides
10305                 May be NULL to use the Selected Document's colour list
10306 
10307                 ColourToEdit - the IndexedColour which you wish to edit. May be NULL
10308                 if you just want it to find a useful local colour to edit, in which
10309                 case it will return TRUE unless there are no documents open.
10310 
10311                 ForceNewMode - DO NOT USE - this is an internal flag causing side effects
10312                 (if TRUE, and the colour is local, the return value will be FALSE, and
10313                 the EditingLineColour member flag will be changed to indicate which
10314                 colour should be edited - see the InvokeDialog code)
10315 
10316     Returns:    TRUE if the colour can be edited. If this returns FALSE, then a call
10317                 to InvokeDialog with these parameters will fail (specifically, it will
10318                 revert to editing a "useful" local colour)
10319 
10320     Purpose:    Determines if the colour editor will be happy with you calling
10321                 InvokeDialog with the given parameters. Allows you to enable/disable
10322                 any UI mechanism that links onto this method. (e.g. colour line
10323                 edit colour button uses this to determine if drags can be dropped 
10324                 onto it)
10325 
10326     Notes:      The colour must be in the ParentList
10327                 Named colours in the ParentList can always be edited
10328                 Unnamed colours can only be edited if they happen to coincide with
10329                 the current line or fill colour - otherwise it makes no sense to edit
10330                 a local colour (because you can only edit a local colour _on_ an object)
10331 
10332     SeeAlso:    ColourEditDlg::InvokeDialog
10333 
10334 ********************************************************************************************/
10335 
10336 BOOL ColourEditDlg::CanYouEditThis(ColourList *ParentList, IndexedColour *ColourToEdit,
10337                                     BOOL ForceNewMode)
10338 {
10339     // If no list specified, assume the one in the selected doc
10340     if (ParentList == NULL)
10341         ParentList = ColourManager::GetColourList();
10342 
10343     // If they specified no colour, then we need to find a "useful" colour to edit.
10344     // This is always possible, except when there are no documents (SelDoc == NULL)
10345     if (ColourToEdit == NULL)
10346         return(Document::GetSelected() != NULL);
10347 
10348     if (ParentList != NULL)
10349     {
10350         if (ColourToEdit->IsNamed())
10351         {
10352             // Named colour
10353             // Check that the colour resides in the given colour list
10354             if (ParentList->FindPosition(ColourToEdit) >= 0)
10355                 return(TRUE);
10356 
10357             ERROR3("CanYouEditThis - Named IndexedColour not in provided ParentList!");
10358         }
10359         else
10360         {
10361             // Local colour
10362             // It is deeply scary to allow local colours to be dragged to the editor.
10363             // Local colours do not exist on their own - they can only be edited ON
10364             // an object. The only objects we know of like this are the current selection,
10365             // so we can only edit local line and fill colours.
10366 
10367             StatusLine* pStatusLine = StatusLine::Get();
10368 
10369             if (!pStatusLine || (pStatusLine->IsRestrictedAccessToColourPicker () == FALSE))
10370             {
10371                 // Get the current line/fill colours, and see if they match the colour we were asked for
10372                 DocColour DocColourToCheck;
10373 
10374                 // Try for current fill colour
10375                 ColourManager::FindColourOfInterestToUser(&DocColourToCheck, NULL, FALSE);
10376                 if (DocColourToCheck.FindParentIndexedColour() == ColourToEdit)
10377                 {
10378                     if (ForceNewMode)
10379                         ForceLineOrFillMode(FALSE);     // If appropriate, set line/fill mode and return FALSE
10380                     else
10381                         return(TRUE);
10382                 }
10383 
10384                 // Try for current line colour
10385                 ColourManager::FindColourOfInterestToUser(&DocColourToCheck, NULL, TRUE);
10386                 if (DocColourToCheck.FindParentIndexedColour() == ColourToEdit)
10387                 {
10388                     if (ForceNewMode)
10389                         ForceLineOrFillMode(TRUE);      // If appropriate, set line/fill mode and return FALSE
10390                     else
10391                         return(TRUE);
10392                 }
10393             }
10394             else
10395             {
10396                 // the above code may have been valid BEFORE camelots custom colour picker
10397                 // control, but NOW we need to allow the colour editor to display/edit
10398                 // local index colours ....
10399 
10400                 return (TRUE);
10401             }
10402         }
10403     }
10404 
10405     // For whatever reason, we can't allow this to be edited
10406     return(FALSE);
10407 }
10408 
10409 
10410 
10411 /********************************************************************************************
10412 
10413 >   static void ColourEditDlg::ForceLineOrFillMode(BOOL PreferLineColour = FALSE);
10414 
10415     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10416     Created:    4/4/95
10417 
10418     Inputs:     PreferLineColour - TRUE to set the colour to defaulting to editing
10419                 local line colours, FALSE to make it default to editing fill colours
10420 
10421     Purpose:    Sets the editing mode for local colours in the future. Whenever a new
10422                 colour is chosen for editing, this will specify whether a line or
10423                 fill colour should be chosen by preference.
10424 
10425 ********************************************************************************************/
10426 
10427 void ColourEditDlg::ForceLineOrFillMode(BOOL PreferLineColour)
10428 {
10429     EditingLineColour = PreferLineColour;
10430 }
10431 
10432 
10433 
10434 /********************************************************************************************
10435 
10436 >   void ColourEditDlg::ApplyColourNow(IndexedColour *IxColourToApply)
10437 
10438     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10439     Created:    2/4/95
10440 
10441     Inputs:     IxColourToApply- the colour to be applied
10442 
10443     Purpose:    Applies the EditingColour to the document selection. Whether named
10444                 or unnamed, it is applied as a new colour attribute, thus changing
10445                 the colour used by the selected objects (rather than just redrawing
10446                 static references to a colour which has been modified)
10447 
10448                 Make sure that EditingColour is in either the named or unnamed colour
10449                 list when it is applied, so that the reference is not left pointing
10450                 a something which can be easily deleted out from under it.
10451 
10452 ********************************************************************************************/
10453 
10454 void ColourEditDlg::ApplyColourNow(IndexedColour *IxColourToApply)
10455 {
10456     // Apply it to the selection as a colour attrib mutator - this will thus affect
10457     // selected objects through selected grad-fill blobs etc
10458     NodeAttribute *Attrib = NULL;
10459     DocColour ColourToApply;
10460     ColourToApply.MakeRefToIndexedColour(IxColourToApply);
10461     if (EditingLineColour)
10462     {
10463         // Apply it as a Line colour mutator
10464         Attrib = new AttrStrokeColourChange;
10465         if (Attrib == NULL)
10466             return;
10467 
10468         ((AttrStrokeColourChange *)Attrib)->SetStartColour(&ColourToApply);
10469     }
10470     else
10471     {
10472         // Apply it as a fill mutator
10473         Attrib = new AttrColourChange;
10474         if (Attrib == NULL)
10475             return;
10476 
10477         ((AttrColourChange *)Attrib)->SetStartColour(&ColourToApply);
10478     }
10479 
10480 
10481     // Apply the attribute. While applying, we lock ourselves so we don't respond to the
10482     // attribute-changing messages, and also ensure that the attribute manager doesn't
10483     // ask the user if they want to set the current attribute (if you're editing the current
10484     // colour, you kindof expect the current colour to change!)
10485     BOOL OldSentState = ISentTheMessage;
10486     ISentTheMessage = TRUE;
10487 
10488         BOOL OldAskState = AttributeManager::AskBeforeSettingCurrentAttr;
10489         AttributeManager::AskBeforeSettingCurrentAttr = FALSE;
10490 
10491             // AttributeSelected knows what to do with a selected attribute
10492             AttributeManager::AttributeSelected(NULL, Attrib); 
10493 
10494         AttributeManager::AskBeforeSettingCurrentAttr = OldAskState;
10495     ISentTheMessage = OldSentState;
10496 }
10497 
10498 
10499 
10500 /********************************************************************************************
10501 
10502 >   void ColourEditDlg::EditingColourHasChanged(BOOL RedrawControls = TRUE,
10503                                                 BOOL RedrawPicker   = TRUE,
10504                                                 BOOL FastTrackPicker = FALSE,
10505                                                 Node* pSourceNode = NULL)
10506 
10507     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10508     Created:    21/6/94
10509     Inputs:     RedrawControls - TRUE to update the editor controls (name, components etc)
10510                 to show the new values for this colour
10511                 
10512                 RedrawPicker - TRUE if the colour picker area should be redrawn to display
10513                 the change. (NOTE that this determines whether the message broadcast is
10514                 a COLOURUPDATED (TRUE) or a COLOURUPDATEDINVISIBLE (FALSE))
10515 
10516                 FastTrackPicker - TRUE if you want the picker section to redraw immediately
10517                 to get instant-effect on the update.
10518 
10519     Returns:    -
10520 
10521     Purpose:    Generic code to handle changes to EditingColour. 
10522 
10523     Notes:      Quietly ignores calls when EditingColour == NULL
10524 
10525 ********************************************************************************************/
10526 
10527 void ColourEditDlg::EditingColourHasChanged(BOOL RedrawControls, BOOL RedrawPicker,
10528                                             BOOL FastTrackPicker,
10529                                             Node* pSourceNode)
10530 {
10531     if (EditingColour == NULL)
10532         return;
10533 
10534     if (RedrawControls)
10535     {
10536         SetControls();
10537         RedrawColourNameList();     // And ensure the colour list redraws its colour patch
10538     }
10539 
10540     if (RedrawPicker)
10541     {
10542         InvalidateGadget(_R(IDC_EDIT_PICKER)); 
10543 
10544         if (FastTrackPicker)
10545             PaintGadgetNow(_R(IDC_EDIT_PICKER));
10546     }
10547 
10548     if (EditingColour->IsNamed())
10549     {
10550         // Apply the change, generating UNDO. This uses 'EditingColour' for an UNDO
10551         // record, so we must not touch/delete EditingColour after this call.
10552         //
10553         // Thus, during processing of the ChangeColour call, it is highly advisable that
10554         // EditingColour does not point at the UndoRecord that we passed in, as any
10555         // re-entrant call to our code could potentially delete EditingColour or apply
10556         // another ChangeColour with the same UNDO buffer! Bad!
10557         // 
10558         // NOTE that we copy UndoRecord into the new EditingColour buffer, because
10559         // ResultColour is out of date (it will shortly be changed to be the same as
10560         // the UndoRecord). Obviously, we don't want to suddenly swap the
10561         // definition back to the previous (undo) state of ResultColour; we want it
10562         // to effectively stay exactly as it is now.
10563         IndexedColour *UndoRecord = EditingColour;
10564         EditingColour = new IndexedColour(*UndoRecord);
10565         if (EditingColour == NULL)
10566         InformError();
10567 
10568         // Set the new colour definition, locking out ColourChangingMsgs while it happens
10569         BOOL OldSentState = ISentTheMessage;
10570         ISentTheMessage = TRUE;
10571         ColourManager::ChangeColour(ParentList, UndoRecord, ResultColour, !RedrawPicker);
10572         ISentTheMessage = OldSentState;
10573     }
10574     else
10575     {
10576         if (FirstEdit)
10577         {
10578             // We have not yet changed this colour, so we must add the unnamed colour to
10579             // the colour list, and apply it to the selection.
10580 
10581             // Remember the colour to apply, and make a new copy to continue editing
10582             IndexedColour *IxColourToApply = EditingColour;
10583             EditingColour = new IndexedColour(*IxColourToApply);
10584             if (EditingColour == NULL)
10585                 InformError();
10586 
10587             // Add the new colour to the list of unnamed colours
10588             ParentList->GetUnnamedColours()->AddTail(IxColourToApply);
10589 
10590             // And apply the colour to the selection as a new attribute
10591             ApplyColourNow(IxColourToApply);
10592 
10593             // And now remember that we've applied it once, and remember the new resultcol
10594             FirstEdit = FALSE;
10595             ResultColour = IxColourToApply;
10596 
10597             // Make the colour list redraw the first time we change a local colour.
10598             // This is necessary because on the first edit, the colour in the list
10599             // (the physical colour pointer, not just the appearance) is changed.
10600             RedrawColourNameList();
10601         }
10602         else
10603         {
10604             // We are changing the same unnamed colour as last time. Rather than
10605             // applying it to the selection and causing another undo record, we
10606             // want to poke at the first new unnamed colour we added, which conveniently
10607             // happens to be pointed at by 'ResultColour'.
10608 
10609             // Copy the new definition into ResultColour
10610             *ResultColour = *EditingColour;
10611 
10612             // And redraw the affected parts of the document tree
10613             ColourManager::ColourHasChanged((Document *)ParentList->GetParentDocument(), ParentList, ResultColour);
10614         }
10615     }
10616 }
10617 
10618 
10619 
10620 /********************************************************************************************
10621 
10622 >   IndexedColour *ColourEditDlg::FindSafeParent(IndexedColour *SuggestedParent,
10623                                                  BOOL ChildIsATint)
10624 
10625     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10626     Created:    21/6/94
10627     Inputs:     SuggestedParent - NULL, or a pointer to a suggested parent colour
10628                 ChildIsATint - TRUE if the prospective child colour is (or will be)
10629                 a tint colour. (FALSE if it's normal/spot/shade/linked)
10630 
10631     Returns:    NULL if there is no safe parent, else a pointer to the colour to use.
10632 
10633     Purpose:    Determines a safe parent colour to use for a tint/link colour.
10634                 If the suggested parent will do, it is returned, otherwise the first
10635                 safe parent in the ParentList ColourList will be returned.
10636 
10637     Notes:      A colour is declared safe if it is alive, named, and will not result in a
10638                 circular parent reference chain.
10639 
10640                 Quietly ignores calls when EditingColour == NULL
10641 
10642 ********************************************************************************************/
10643 
10644 IndexedColour *ColourEditDlg::FindSafeParent(IndexedColour *SuggestedParent, BOOL ChildIsATint)
10645 {
10646     if (ParentList == NULL || EditingColour == NULL || ResultColour == NULL)
10647         return(NULL);
10648 
10649     if (SuggestedParent != NULL)
10650     {
10651         // The caller has suggested a colour - is it safe to use it?
10652         // Conditions are:
10653         //  Not deleted
10654         //  Must be a named colour
10655         //  Must not be a descendant of the ResultColour (avoid circular references)
10656         //  Spot colours may only have tints as children
10657         if (SuggestedParent->IsDeleted() || !SuggestedParent->IsNamed() ||
10658             SuggestedParent->IsADescendantOf(ResultColour))
10659         {
10660             SuggestedParent = NULL;
10661         }
10662     }
10663 
10664     if (SuggestedParent != NULL)        // SuggestedParent passed the test: let 'em use it
10665         return(SuggestedParent);
10666 
10667     IndexedColour *Ptr = (IndexedColour *) ParentList->GetHead();
10668     while (Ptr != NULL)
10669     {
10670         if (!Ptr->IsDeleted() && Ptr->IsNamed() && !Ptr->IsADescendantOf(ResultColour))
10671             return(Ptr);
10672 
10673         Ptr = (IndexedColour *) ParentList->GetNext(Ptr);
10674     }
10675 
10676     return(NULL);
10677 }
10678 
10679 
10680 
10681 /********************************************************************************************
10682 
10683 >   void ColourEditDlg::CompileParentColourList(CGadgetID TargetGadget)
10684 
10685     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10686     Created:    21/6/94
10687     Inputs:     TargetGadget - The list gadget to write the list into
10688 
10689     Purpose:    Sets up the given combo box gadget to provide a list of all the colours
10690                 which can be used as a parent of an IndexedColour.
10691                 This creates the list in the dialogue gadget specified, and selects
10692                 the appropriate parent (of EditingColour) by default.
10693 
10694     Notes:      Quietly ignores calls when EditingColour == NULL
10695 
10696     SeeAlso:    ColourEditDlg::DecodeParentColourListSelection
10697 
10698 ********************************************************************************************/
10699 
10700 void ColourEditDlg::CompileParentColourList(CGadgetID TargetGadget)
10701 {
10702     if (ParentList == NULL || EditingColour == NULL)
10703         return;
10704 
10705     if (ParentDropDown != NULL)
10706         delete ParentDropDown;
10707 
10708     ParentDropDown = new ColourDropDown;
10709 
10710     if (ParentDropDown != NULL)
10711     {
10712         if (ParentDropDown->Init(WindowID, TargetGadget))
10713         {
10714             if (ParentDropDown->FillInColourList(EditingColour->FindLastLinkedParent(), -1, ResultColour))
10715                 return;
10716 
10717             // NOTE: We could do a SetComboListLength here, except that this causes awful
10718             // redraws of everything "behind" the combo-list extent. I can't stop it doing this,
10719             // other than by not setting the list length.
10720         }
10721     }
10722 
10723     // We must have failed in order to reach here, so shade the gadget and hang our head in shame
10724     EnableGadget(TargetGadget, FALSE);
10725 }
10726 
10727 
10728 
10729 /********************************************************************************************
10730 
10731 >   IndexedColour *ColourEditDlg::DecodeParentColourListSelection(INT32 Index)
10732 
10733     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10734     Created:    21/6/94
10735     Inputs:     Index - the index of the item in the list gadget which was selected
10736     Returns:    A pointer to the IndexedColour to be used as the new parent of the
10737                 EditingColour, or NULL if the item wasn't found(!?)
10738 
10739     Purpose:    Shared code used by ColourTint and CoourLink Dlgs to decode selctions
10740                 in the list of colours created by CompileParentColourList
10741 
10742     Notes:      Quietly ignores calls when EditingColour == NULL
10743 
10744     SeeAlso:    ColourEditDlg::CompileParentColourList
10745 
10746 |********************************************************************************************/
10747 
10748 IndexedColour *ColourEditDlg::DecodeParentColourListSelection(INT32 Index)
10749 {
10750     if (ParentList == NULL || EditingColour == NULL)
10751         return(NULL);
10752 
10753     if (ParentDropDown != NULL)
10754         return(ParentDropDown->DecodeSelection(Index));
10755 
10756 /*
10757     IndexedColour *Ptr = (IndexedColour *) ParentList->GetHead();
10758     while (Ptr != NULL)
10759     {
10760         // If this colour is a possible parent:
10761         //   * Not deleted
10762         //   * Named
10763         //   * Not a Spot colour if EditingColour is LINKED
10764         //   * Is not a child/descendant of the ResultColour (circular reference! no!)
10765         //      (Note that this includes it being the ResultColour)
10766         // then we will add it to the list
10767 
10768         if (!Ptr->IsDeleted() && Ptr->IsNamed() && !Ptr->IsADescendantOf(ResultColour))
10769         {
10770             if (EditingColour->GetType() != COLOURTYPE_LINKED || Ptr->GetType() != COLOURTYPE_SPOT)
10771             {
10772                 Index--;
10773 
10774                 if (Index < 0)
10775                     return(Ptr);
10776             }
10777         }
10778         Ptr = (IndexedColour *) ParentList->GetNext(Ptr);
10779     }
10780 */
10781     return(NULL);       // Not found?!
10782 }
10783 
10784 
10785 
10786 
10787 
10788 BOOL ColourEditDlg::IsSetGadgetValueCalled() const
10789 {
10790     return m_bDoingSetGadget;
10791 }
10792 
10793 BOOL ColourEditDlg::EnteredSetGadgetValue()
10794 {
10795     m_bDoingSetGadget = TRUE;
10796     return FALSE;
10797 }
10798 
10799 BOOL ColourEditDlg::ExitedSetGadgetValue()
10800 {
10801     m_bDoingSetGadget = FALSE;
10802     return TRUE;
10803 }
10804 
10805 
10806 
10807 
10808 
10809 /********************************************************************************************
10810 
10811 >   ColEditorDragTarget::ColEditorDragTarget(CWindowID TheWindow, CRect *ClientArea)
10812                         : WinoilDragTarget(TheWindow, ClientArea)
10813      
10814     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10815     Created:    25/3/95       
10816     Inputs:     TheDilaog   - The window for which this target is active
10817                 ClientArea  - NULL, or the gadget ID of the area in the window to target
10818 
10819     Purpose:    Constructs and registers this drag target with the current drag manager
10820 
10821 ********************************************************************************************/
10822 
10823 ColEditorDragTarget::ColEditorDragTarget(DialogOp *TheDialog, CGadgetID TheGadget)
10824                     : KernelDragTarget(TheDialog, TheGadget)
10825 {
10826     
10827 }
10828 
10829 
10830 
10831 /********************************************************************************************
10832 
10833 >   void ColEditorDragTarget::ProcessEvent(DragEventType Event,
10834                                             DragInformation *pDragInfo,
10835                                             OilCoord *pMousePos, KeyPress* pKeyPress) 
10836     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10837     Created:    25/3/95       
10838 
10839     Inputs:     Event       - The drag event to be processed
10840                 pDragInfo   - Information describing the current drag
10841                 pMousePos   - The current mouse pos, in client coords
10842                 pKeyPress   - NULL, or keypress event info
10843 
10844     Returns:    TRUE to claim the event (in which case it will not be passed on)
10845 
10846     Purpose:    Event Handler for dragging colours over the colour editor
10847 
10848 ********************************************************************************************/
10849 
10850 BOOL ColEditorDragTarget::ProcessEvent(DragEventType Event,
10851                                         DragInformation *pDragInfo,
10852                                         OilCoord *pMousePos, KeyPress* pKeyPress)
10853 {
10854     // Not a colour drag? That is kindof unexpected, but lets exit before
10855     // we embarrass ourselves
10856     if (pDragInfo == NULL || !pDragInfo->IsKindOf(CC_RUNTIME_CLASS(ColourDragInformation)))
10857         return(FALSE);
10858 
10859     ColourDragInformation *ColDragInfo = (ColourDragInformation *) pDragInfo;
10860 
10861     BOOL IsLibColour = ColDragInfo->IsLibraryColour();
10862 
10863     IndexedColour *Col = ColDragInfo->GetInitiallyDraggedColour();
10864     if (!IsLibColour && Col == NULL)                // Don't allow dropping of "No colour"
10865         return(FALSE);
10866 
10867     switch(Event)
10868     {
10869         case DRAGEVENT_COMPLETED:
10870             if (ColourEditDlg::TheEditor != NULL && CanDropHere(pDragInfo))
10871             {
10872                 Document *ParentDoc = NULL;
10873                 if (!IsLibColour)
10874                     ParentDoc = ColDragInfo->GetParentDoc();
10875 
10876                 if (ParentDoc == NULL)
10877                     ParentDoc = Document::GetSelected();
10878 
10879                 if (ParentDoc != NULL)
10880                 {
10881                     ColourList *ColList = ParentDoc->GetIndexedColours();
10882 
10883                     if (IsLibColour)
10884                     {
10885                         Col = NULL;     // Just to be on the safe side
10886 
10887                         // We must copy the library colour into the document, but first check with
10888                         // the user that this is what they intended.
10889                         // WEBSTER - markn 30/1/97
10890                         // Don't ask in webster, just copy it over
10891                         #ifndef WEBSTER
10892                         if (InformError(_R(IDE_CANTEDITLIBCOLOUR), _R(IDS_COPYLIBCOLOUR), _R(IDS_CANCEL)) == 1)
10893                             Col = ColDragInfo->GetColourForDocument(ParentDoc);
10894                         #else
10895                             Col = ColDragInfo->GetColourForDocument(ParentDoc);
10896                         #endif // WEBSTER
10897                     }
10898 
10899                     if (Col != NULL && ColourEditDlg::CanYouEditThis(ColList, Col))
10900                         ColourEditDlg::InvokeDialog(ColList, Col);
10901                 }
10902 
10903                 return(TRUE);
10904             }
10905             break;
10906 
10907 
10908         case DRAGEVENT_MOUSESTOPPED:
10909         case DRAGEVENT_MOUSEMOVED:
10910         case DRAGEVENT_MOUSEIDLE:
10911             // Return TRUE to claim the mouse while over our target area, so that
10912             // our cursor shape is used
10913             return(TRUE);
10914 
10915         default:
10916             break;
10917     }
10918 
10919     // Allow unknown/unwanted events to pass on to other targets
10920     return(FALSE);
10921 }
10922 
10923 
10924 
10925 /********************************************************************************************
10926 
10927 >   void ColEditorDragTarget::GetCursorID()
10928 
10929     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10930     Created:    10/1/95
10931 
10932     Purpose:    Base Method to set cursor over this target
10933 
10934 ********************************************************************************************/
10935 
10936 UINT32 ColEditorDragTarget::GetCursorID()
10937 {
10938     if (CanDropHere(DragManagerOp::GetCurrentDragInfo()))
10939         return _R(IDC_CANDROP_EDITBUTTON);
10940 
10941     return 0;
10942 }
10943 
10944 
10945 
10946 /********************************************************************************************
10947 
10948 >   virtual BOOL ColEditorDragTarget::GetStatusLineText(String_256 * TheText)
10949 
10950     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10951     Created:    25/3/95
10952 
10953     Returns:    TRUE if TheText has been filled in with a valid help string
10954 
10955     Purpose:    provide status line text for this target
10956    
10957 ********************************************************************************************/
10958 
10959 BOOL ColEditorDragTarget::GetStatusLineText(String_256 * TheText)
10960 {
10961     ERROR2IF(TheText==NULL,FALSE,"NULL string in GetStatusLineText()");
10962 
10963     if (CanDropHere(DragManagerOp::GetCurrentDragInfo()))
10964     {
10965         String_256 DragString(_R(IDS_K_COLDLOG_DROPTOEDIT));
10966         *TheText = DragString;
10967         return TRUE;
10968     }
10969 
10970     return FALSE;
10971 }
10972 
10973 
10974 
10975 /********************************************************************************************
10976 
10977 >   BOOL ColEditorDragTarget::CanDropHere(DragInformation *pDragInfo)
10978 
10979     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
10980     Created:    26/3/96
10981 
10982     Inputs:     pDragInfo - info on the drag (it's safe if this is NULL)
10983 
10984     Returns:    TRUE if we'll accept this dragged thing dropped on us
10985 
10986     Purpose:    To determine if we should accept the given drag on this target
10987 
10988 ********************************************************************************************/
10989 
10990 BOOL ColEditorDragTarget::CanDropHere(DragInformation *pDragInfo)
10991 {
10992     if (pDragInfo != NULL && pDragInfo->IsKindOf(CC_RUNTIME_CLASS(ColourDragInformation)))
10993     {
10994         ColourDragInformation *CDInfo = (ColourDragInformation *) pDragInfo;
10995 
10996         // Library colours can always be edited, as they're copied into the document first
10997         if (CDInfo->IsLibraryColour())
10998             return(TRUE);
10999 
11000         // Get the dragged colour and the current colour list
11001         IndexedColour *Col = CDInfo->GetInitiallyDraggedColour();
11002 
11003         if (Col != NULL)    // If it's not "no colour", see if we're happy to edit it
11004         {
11005             ColourList *ColList = NULL;
11006             if (CDInfo->GetParentDoc() != NULL)
11007                 ColList = CDInfo->GetParentDoc()->GetIndexedColours();
11008 
11009             return(ColourEditDlg::CanYouEditThis(ColList, Col));
11010         }   
11011     }
11012 
11013     return(FALSE);
11014 }
11015 
11016 
11017 
11018 
11019 
11020 
11021 
11022 /********************************************************************************************
11023 
11024 >   ColEditorDragInfo::ColEditorDragInfo(IndexedColour *Colour, BOOL IsAdjust, Document* pParent)
11025 
11026     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
11027     Created:    15/10/95
11028 
11029     Purpose:    constructor
11030 
11031     Notes:      This is a completely normal ColourDragInformation class, but overridden
11032                 so that we can detect drags from the editor and make sure they can't be
11033                 dropped back into the editor
11034 
11035 ********************************************************************************************/
11036 
11037 ColEditorDragInfo::ColEditorDragInfo()
11038 {
11039 }
11040 
11041 ColEditorDragInfo::ColEditorDragInfo(IndexedColour *Colour, BOOL IsAdjust, Document* pParent)
11042                   : ColourDragInformation(Colour, IsAdjust, pParent)
11043 {
11044 }
11045 
11046 
11047 
11048 
11049 
11050 
11051 
11052 
11053 
11054 /********************************************************************************************
11055 
11056 >   OpMakeColourLocalToFrame::OpMakeColourLocalToFrame()
11057 
11058     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11059     Created:    31/7/97
11060     Inputs:     -
11061     Outputs:    -
11062     Returns:    -
11063     Purpose:    OpMakeColourLocalToFrame constructor (Creates an undoable operation)
11064     Errors:     -
11065     SeeAlso:    -
11066 
11067 ********************************************************************************************/
11068 
11069 OpMakeColourLocalToFrame::OpMakeColourLocalToFrame() : UndoableOperation()
11070 {
11071 }
11072 
11073 
11074 
11075 /********************************************************************************************
11076 
11077 >   OpMakeColourLocalToFrame::OpMakeColourLocalToFrame()
11078 
11079     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11080     Created:    31/7/97
11081     Inputs:     -
11082     Outputs:    -
11083     Returns:    -
11084     Purpose:    OpMakeColourLocalToFrame destructor
11085     Errors:     -
11086     SeeAlso:    -
11087 
11088 ********************************************************************************************/
11089 
11090 OpMakeColourLocalToFrame::~OpMakeColourLocalToFrame()
11091 {
11092 }
11093 
11094 
11095 
11096 /********************************************************************************************
11097 
11098 >   BOOL OpMakeColourLocalToFrame::Init()
11099 
11100     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11101     Created:    31/7/97
11102     Inputs:     -
11103     Outputs:    -
11104     Returns:    TRUE if the operation could be successfully initialised 
11105                 FALSE if no more memory could be allocated 
11106                 
11107     Purpose:    OpMakeColourLocalToFrame initialiser method
11108 
11109 ********************************************************************************************/
11110 #define OPTOKEN_MAKECOLOURLOCALTOFRAME _T("MakeColourLocalToFrame") // Optoken for the operation
11111 
11112 BOOL OpMakeColourLocalToFrame::Init()
11113 {
11114     return (RegisterOpDescriptor(
11115                                     0,
11116                                     _R(IDS_MAKECOLOURLOCALTOFRAMEOP),
11117                                     CC_RUNTIME_CLASS(OpMakeColourLocalToFrame),
11118                                     OPTOKEN_MAKECOLOURLOCALTOFRAME,
11119                                     OpMakeColourLocalToFrame::GetState,
11120                                     0,  /* help ID */
11121                                     0,  /* Bubble help ID */
11122                                     0   /* bitmap ID */
11123                                 ));
11124 }
11125     
11126 
11127 
11128 /********************************************************************************************
11129 
11130 >   OpState OpMakeColourLocalToFrame::GetState(String_256*, OpDescriptor*)
11131 
11132     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11133     Created:    31/7/97
11134     Inputs:     -
11135     Outputs:    -
11136     Returns:    The state of the OpMakeColourLocalToFrame operation
11137     Purpose:    For finding the OpMakeColourLocalToFrame's state. 
11138 
11139 ********************************************************************************************/
11140 
11141 OpState OpMakeColourLocalToFrame::GetState(String_256* UIDescription, OpDescriptor*)
11142 {
11143     OpState OpSt;
11144     return(OpSt);
11145 }
11146 
11147 
11148 
11149 /********************************************************************************************
11150 
11151 >   void OpMakeColourLocalToFrame::PerformMergeProcessing()
11152 
11153     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11154     Created:    31/7/97
11155     Inputs:     -
11156     Outputs:    -
11157     Returns:    -
11158     Purpose:    Called during EndOp to perform merging with the previous operation.
11159 
11160 ********************************************************************************************/
11161 
11162 void OpMakeColourLocalToFrame::PerformMergeProcessing()
11163 {
11164     // Obtain a pointer to the operation history for the operation's document
11165     OperationHistory* pOpHist = &GetWorkingDoc()->GetOpHistory();
11166     if (pOpHist == NULL)
11167     {
11168         ERROR3("There's no OpHistory!?");
11169         return;
11170     }
11171 
11172     // Ensure that we are the last operation added to the operation history
11173     if (pOpHist->FindLastOp() != this)
11174     {
11175         ERROR3("Last Op should be this op");
11176         return;
11177     }
11178     
11179     // obtain a pointer to the previous operation
11180     Operation* pPrevOp = pOpHist->FindPrevToLastOp();
11181 
11182     // do the merging only if we have a previous op, different then the operation before 
11183     // us in the history list at the start of this operation, and that operation
11184     // is a OpHideColours operation
11185     if ((pPrevOp != NULL) && (pPrevOp != m_pPreviousOp) && IS_A(pPrevOp, OpHideColours))
11186     {   
11187         // Copy all the actions from us to the end of the action list in the previous op.
11188         ActionList* pPrevActions = pPrevOp->GetUndoActionList();
11189         ActionList* pPrevOtherActions = pPrevOp->GetRedoActionList();
11190         if ((pPrevActions == NULL) || (pPrevOtherActions == NULL))
11191         {
11192             ERROR3("Previous actions list pointer was NULL");
11193             return;
11194         }
11195 
11196         // Copy actions across
11197         Action* pCurrentAction = (Action*)pPrevActions->RemoveHead();
11198         while (pCurrentAction != NULL)
11199         {
11200             pCurrentAction->TransferToOtherOp(this, &UndoActions, &RedoActions);
11201             pCurrentAction = (Action*)pPrevActions->RemoveHead();
11202         }
11203 
11204         // And remove the previous operation
11205         pOpHist->DeletePrevToLastOp(); 
11206     }
11207 
11208 }
11209 
11210 /********************************************************************************************
11211 
11212 >   void OpMakeColourLocalToFrame::Do(OpDescriptor*)
11213 
11214     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11215     Created:    31/7/97
11216     Inputs:     OpDescriptor (unused)
11217     Outputs:    -
11218     Returns:    -
11219     Purpose:    OpMakeColourLocalToFrame has a special overloaded DoWithParam operator which takes
11220                 parameters describing what is to be done - that version of Do must be used
11221     Errors:     Always generates an ENSURE failure because this Do doesn't.
11222     SeeAlso:    -
11223 
11224 ********************************************************************************************/
11225             
11226 void OpMakeColourLocalToFrame::Do(OpDescriptor *NotUsed)
11227 {
11228     ENSURE(FALSE, "OpMakeColourLocalToFrame does not provide a Do() function - Use DoWithParam");
11229     End();
11230 }
11231 
11232 
11233 
11234 /********************************************************************************************
11235 
11236 >   void OpMakeColourLocalToFrame::DoWithParam(OpDescriptor *pOp, OpParam *Param)
11237 
11238     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11239     Created:    31/7/97
11240     Inputs:     pOp - OpDescriptor as for all Do() functions
11241                 Param - points to a ColourChangeInfo structure with parameters:
11242                     ParentList - The List in which the colours reside
11243                     Target - The colour to be changed
11244                     NewDefn - The returned copy of Target
11245                     InvisibleChange - unused
11246                     colour - unused
11247     Outputs:    -
11248     Returns:    -
11249     Purpose:    Performs the Make colour local to frame operation, which makes copies of Target 
11250                 and all the children of it and replaces the references to them with references 
11251                 to the copies, but only on the active frame.
11252 
11253 ********************************************************************************************/
11254             
11255 void OpMakeColourLocalToFrame::DoWithParam(OpDescriptor *pOp, OpParam *Param)
11256 {
11257     // get our info from the operation parameter
11258     ColourChangeInfo *Info = (ColourChangeInfo *) Param;
11259 
11260     // Set our scope variables
11261     pOurDoc = (Document *)Info->ParentList->GetParentDocument();
11262     pOurView = NULL;
11263     if (!pOurDoc->IsKindOf(CC_RUNTIME_CLASS(Document)))
11264     {
11265         pOurDoc = NULL;     // Arrrgh! It must be a basedoc or something!
11266         End();
11267         return;
11268     }
11269     
11270     // remember the previous operation
11271     OperationHistory* pOpHist = &GetWorkingDoc()->GetOpHistory();
11272     if (pOpHist == NULL)
11273         m_pPreviousOp = NULL;
11274     else
11275         m_pPreviousOp = pOpHist->FindLastOp();
11276     
11277     // Get the colour list component
11278     ColComp = (ColourListComponent *)
11279                 pOurDoc->GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent));
11280 
11281     // Start the copy
11282     if (ColComp != NULL && ColComp->StartComponentCopy())
11283     {
11284     
11285         // get the parent list
11286         ParentList = Info->ParentList;
11287 
11288         // get the spread
11289         Spread *pSpread = pOurDoc->GetSelectedSpread();
11290         if (pSpread != NULL)
11291         {
11292             // find the active layer
11293             pActiveLayer = pSpread->FindActiveLayer();
11294             if (pActiveLayer != NULL)
11295             {
11296                 // do the work
11297                 Info->NewDefn = MakeColourLocalToFrame(Info->Target);
11298             }
11299         }
11300 
11301         // And clean up, merging the new colours into the document's colour list
11302         ColComp->EndComponentCopy(NULL, FALSE);
11303     }
11304 
11305     End();
11306 }
11307 
11308 
11309 
11310 /********************************************************************************************
11311 
11312 >   void OpMakeColourLocalToFrame::Undo()
11313 
11314     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11315     Created:    31/7/97
11316     Inputs:     -
11317     Outputs:    -
11318     Returns:    -
11319     Purpose:    Undoes whatever Do() or Redo() did
11320 
11321 ********************************************************************************************/
11322 
11323 BOOL OpMakeColourLocalToFrame::Undo() 
11324 {
11325     if (Operation::Undo() == FALSE) 
11326         return FALSE;
11327 
11328     // send the colour changing message
11329     ColourManager::ColourListHasChanged(ParentList);
11330 
11331     return TRUE;
11332 }       
11333 
11334 
11335 
11336 /********************************************************************************************
11337 
11338 >   void OpMakeColourLocalToFrame::Redo()
11339 
11340     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11341     Created:    31/7/97
11342     Inputs:     -
11343     Outputs:    -
11344     Returns:    -
11345     Purpose:    Redoes whatever Undo() undid
11346 
11347 ********************************************************************************************/
11348 
11349 BOOL OpMakeColourLocalToFrame::Redo()
11350 {
11351     if (!Operation::Redo())
11352         return FALSE;
11353 
11354     // send the colour changing message
11355     ColourManager::ColourListHasChanged(ParentList);
11356 
11357     return TRUE;
11358 }
11359 
11360 
11361 
11362 
11363 /********************************************************************************************
11364 
11365 >   BOOL OpMakeColourLocalToFrame::ReplaceColourOnActiveLayer(IndexedColour *pOld, 
11366                                                                 IndexedColour *pNew)
11367 
11368     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11369     Created:    31/7/97
11370     Inputs:     pOld - the old indexed colour 
11371                 pNew - the new indexed colour
11372     Outputs:    -
11373     Returns:    -
11374     Purpose:    Replaces all the references to pOld with references to pNew on the active frame.
11375 
11376 ********************************************************************************************/
11377 
11378 BOOL OpMakeColourLocalToFrame::ReplaceColourOnActiveLayer(IndexedColour *pOld, IndexedColour *pNew)
11379 {
11380     // sanity checks
11381     if ((pOld == NULL) || (pNew == NULL)) 
11382         return FALSE;
11383 
11384     ERROR3IF(pOurDoc == NULL, "No doc");
11385     if (pOurDoc == NULL)
11386         return FALSE;
11387 
11388     // start the attribute changing
11389     ObjChangeFlags ChangeFlags;
11390     ChangeFlags.Attribute = TRUE;
11391 
11392     ObjChangeParam ChangeParam(OBJCHANGE_STARTING, ChangeFlags, NULL, NULL);
11393 
11394     // get the first child of the active layer
11395     Node *CurNode = pActiveLayer->FindFirstDepthFirst();
11396 
11397     while (CurNode != NULL) // for all the nodes on the active layer
11398     {
11399         if (CurNode->IsAnAttribute()) // check only attribute nodes
11400         {
11401             // Have found a NodeAttribute. Scan it to see if it contains colours matching the old colour.
11402 
11403             NodeAttribute *pNodeAttr = (NodeAttribute *) CurNode;
11404             DocColour *pColour;
11405             DocColour *pColourCopy;
11406             UINT32 Context = 0;
11407 
11408             BOOL Found = FALSE; // whether our colour was referenced on this node
11409 
11410             // scan the attribute for the colour
11411             do
11412             {
11413                 // scan all the colour fields
11414                 pColour = pNodeAttr->EnumerateColourFields(Context++);
11415         
11416                 // get to the indexed colour
11417                 IndexedColour *pColourIx = (pColour == NULL) ? NULL : pColour->FindParentIndexedColour();
11418 
11419                 // Check if this colour matches our colour
11420                 if (pColourIx == pOld)
11421                 {
11422                     Found = TRUE; // found it
11423                     break;
11424                 }
11425             } while (pColour != NULL);  // Check the next colour attribute
11426 
11427             
11428             if (Found) // we have found a our colour in this attribute
11429             {
11430                 // make a copy of the attribute
11431                 NodeAttribute *Clone = NULL;
11432                 NodeAttribute *NodeToClone = (NodeAttribute *) CurNode;
11433                 ALLOC_WITH_FAIL(Clone, ((NodeAttribute *)NodeToClone->SimpleCopy()), this);
11434                 if (Clone == NULL) // failed
11435                     break;
11436 
11437                 Context = 0;
11438 
11439                 // for all the colour fields which match our old colour, 
11440                 // replace them with references to the new colour
11441                 do
11442                 {
11443                     // Get the next colour field from the attribute, and find the
11444                     // IndexedColour (if any) to which it refers
11445                     pColour = pNodeAttr->EnumerateColourFields(Context);
11446                     pColourCopy = Clone->EnumerateColourFields(Context);
11447                     Context++;
11448         
11449                     // get the indexed colour
11450                     IndexedColour *pColourIx = (pColour == NULL) ? NULL : pColour->FindParentIndexedColour();
11451 
11452                     // Check if this colour matches our colour
11453                     if (pColourIx == pOld)
11454                     {
11455                         // set the new indexed colour
11456                         pColourCopy->MakeRefToIndexedColour(pNew);
11457                     }
11458                 } while (pColour != NULL);  // Check the next colour attribute
11459 
11460 
11461                 // we need to hide the current attribute node and add the coped node to the tree
11462 
11463                 // find the parent of the node
11464                 Node *Parent = CurNode->FindParent();  
11465                 if (Parent != NULL && Parent->IsBounded())
11466                 {
11467                     // Invoke AllowOp on the node to tag it so that parents such as blends
11468                     // and moulds will also redraw if necessary. 
11469                     if (CurNode->AllowOp(&ChangeParam))
11470                     {
11471                         // Hide the original Attribute
11472                         DoHideNode(CurNode, TRUE);
11473 
11474                         // Add the clone into the tree
11475                         Clone->AttachNode(Parent, FIRSTCHILD);
11476                         HideNodeAction* TheUndoAction; 
11477 
11478                         // Create an action to hide the attribute when we undo
11479                         if (HideNodeAction::Init(this, &UndoActions, Clone, TRUE,
11480                                                  (Action**)(&TheUndoAction)) == AC_FAIL)
11481                         {   
11482                             Clone->CascadeDelete();     // Delink the node/subtree from the
11483                             delete Clone;               // document tree and delete it
11484                         }
11485 
11486                         // make the clone the current node so we can carry on walking the tree
11487                         CurNode = Clone;
11488                     }
11489                 }
11490             }
11491         }
11492 
11493         // go to the next node in the layer
11494         CurNode = CurNode->FindNextDepthFirst(pActiveLayer);
11495     }
11496     
11497     // finished changing the tree
11498     ChangeParam.Define(OBJCHANGE_FINISHED, ChangeParam.GetChangeFlags(), NULL, NULL);
11499     UpdateAllChangedNodes(&ChangeParam);
11500 
11501     return TRUE;
11502 }
11503 
11504 
11505 
11506 /********************************************************************************************
11507 
11508 >   IndexedColour *OpMakeColourLocalToFrame::MakeColourLocalToFrame(IndexedColour *pCol)
11509 
11510     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11511     Created:    31/7/97
11512     Inputs:     pCol - pointer to an indexed colour 
11513     Outputs:    -
11514     Returns:    The created copy of pCol, local to the active frame
11515     Purpose:    Creates a new colour, which is a copy of the pCol. The name of the new colour 
11516                 is <FrameName> (<ColourName>), where FrameName is the name of the active frame, 
11517                 and ColurName is the name of pCol. ReplaceColourOnActiveLayer is called to 
11518                 replace pCol with the new copy on the active frame. Afterthat the colour list 
11519                 for the current document is to find all the children of this colour and this 
11520                 function is recursivelly called for them.
11521 
11522 ********************************************************************************************/
11523 
11524 IndexedColour *OpMakeColourLocalToFrame::MakeColourLocalToFrame(IndexedColour *pCol)
11525 {
11526     // sanity check
11527     if ((pActiveLayer == NULL) || (pCol == NULL))
11528         return NULL;
11529 
11530     // generate the name for the new colour
11531     String_256 DefName;
11532 
11533     // get the layer name
11534     DefName = pActiveLayer->GetLayerID();
11535 
11536     // add the name of the colour
11537     DefName += _T(" (");
11538     DefName += (TCHAR *)(*(pCol->GetName()));
11539     DefName += _T(")");
11540 
11541     String_64 OrigName;
11542     String_64 NewName;
11543 
11544     // use the first 63 chars only
11545     DefName.Left(&OrigName, 63);
11546 
11547     // ask for a unique name
11548     ParentList->GenerateUniqueColourName(&OrigName, &NewName);
11549 
11550     // create a copy of the original colour
11551     IndexedColour *Copy = new IndexedColour(*pCol); // make a copy of current
11552     if (Copy == NULL)
11553         return NULL;
11554 
11555     // set the new name
11556     Copy->SetName(NewName);
11557 
11558     //Add the colour to the document
11559     // Copy the colour into the destination document (merging it with existing
11560     // colours so we won't keep creating new copies of the same colour as it's applied)
11561     DocColour ColourToApply;
11562     ColourToApply.MakeRefToIndexedColour(Copy);
11563     ColComp->CopyColourAcross(&ColourToApply, TRUE);
11564 
11565     delete Copy; // delete the temp copy
11566     
11567     // get the new colour (now part of the document colours)
11568     Copy = ColourToApply.FindParentIndexedColour();
11569 
11570     // Replace the references of the original colour with the new colour in the active layer
11571     ReplaceColourOnActiveLayer(pCol, Copy);
11572 
11573     // now create local copies for all the children
11574 
11575     // scan the listto find all the children
11576     IndexedColour *C = ParentList->GetUndeletedHead();
11577     while (C != NULL)
11578     {
11579         // a child found
11580         if ((C->FindLinkedParent() == pCol) && (C->IsDeleted() == FALSE))
11581         {
11582             // make local copy (recursive call)
11583             IndexedColour *pResult = MakeColourLocalToFrame(C);
11584 
11585             // set the new parent to it
11586             if (pResult != NULL)
11587                 pResult->SetLinkedParent(Copy, C->GetType());
11588         }
11589 
11590         // go to the next colour in the list
11591         C = ParentList->GetUndeletedNext(C);
11592     }
11593 
11594     return Copy;
11595 }
11596 
11597 
11598 /********************************************************************************************
11599 
11600 >   BOOL ColourEditDlg::OnMakeLocalToFrame()
11601 
11602     Author:     Stefan_Stoykov (Xara Group Ltd) <camelotdev@xara.com>
11603     Created:    31/7/97
11604     Inputs:     -
11605     Outputs:    -
11606     Returns:    -
11607     Purpose:    Invokes the OpMakeColourLocalToFrame operation to make local copy of the current 
11608                 edited colour.
11609 
11610 ********************************************************************************************/
11611 
11612 BOOL ColourEditDlg::OnMakeLocalToFrame()
11613 {
11614 #if !defined(EXCLUDE_FROM_RALPH) && !defined(EXCLUDE_FROM_XARALX)
11615     // find our operation
11616     OpDescriptor* OpDesc =
11617                 OpDescriptor::FindOpDescriptor(CC_RUNTIME_CLASS(OpMakeColourLocalToFrame));
11618 
11619     if (OpDesc != NULL)
11620     {
11621         // set up the info to pass to the operation
11622         ColourChangeInfo Param;
11623         Param.ParentList = ParentList;
11624         Param.Target     = ResultColour;
11625 
11626         // invoke the operation
11627         OpDesc->Invoke((OpParam *) &Param);
11628 
11629         // set the colour in the colour editor
11630         EditThisColour(ParentList, Param.NewDefn, TRUE);
11631         return TRUE;
11632     }
11633 #endif
11634 
11635     return FALSE;
11636 }
11637 
11638 
11639 
11640 #if FALSE
11641 BOOL OpMakeColourLocalToFrame::IsColourLocalToFrame(Layer *pTheLayer, IndexedColour *pCol)
11642 {
11643     if (pOurDoc == NULL)
11644         return TRUE;
11645     
11646     // get the selected spread
11647     Spread *pSpread = pOurDoc->GetSelectedSpread();
11648     ERROR2IF(pSpread == NULL, FALSE, "Doc with no spread found");
11649     
11650     // get the first frame/layer
11651     Layer *pLayer = pSpread->FindFirstLayer();
11652     ERROR2IF(pLayer == NULL, FALSE, "Spread with no layer found");
11653 
11654     // for all the layers
11655     while (pLayer != NULL)
11656     {
11657         if (pLayer != pTheLayer) // if not our layer
11658         {
11659             Node *CurNode = pLayer->FindFirstDepthFirst();
11660             while (CurNode != NULL)
11661             {
11662                 if (CurNode->IsAnAttribute())
11663                 {
11664                     // Have found a NodeAttribute. Scan it to see if it contains any colours.
11665                     // If any of these match any in our Colours list, then force a redraw of
11666                     // our parent node, and return.
11667                     NodeAttribute *pNodeAttr = (NodeAttribute *) CurNode;
11668                     DocColour *pColour;
11669                     UINT32 Context = 0;
11670 
11671                     do
11672                     {
11673                         // Get the next colour field from the attribute, and find the
11674                         // IndexedColour (if any) to which it refers
11675                         pColour = pNodeAttr->EnumerateColourFields(Context++);
11676                 
11677                         IndexedColour *pColourIx = (pColour == NULL) ? NULL : pColour->FindParentIndexedColour();
11678                         if (pColourIx != NULL)
11679                         {
11680                             // Check if this colour matches our colour
11681                             INT32 i = 0;
11682                             if (pColourIx == pCol)
11683                             {
11684                                 // There is no need to check further colour attributes for this node
11685 
11686                                 return FALSE;
11687                             }
11688                         }
11689                     } while (pColour != NULL);  // Check the next colour attribute
11690                 }
11691 
11692                 CurNode = CurNode->FindNextDepthFirst(pLayer); // get the next node
11693             }
11694         }
11695 
11696         pLayer = pLayer->FindNextLayer(); // go to the next layer
11697     }
11698 
11699     return TRUE;
11700 }
11701 #endif
11702 
11703 /********************************************************************************************
11704 
11705 >   void ColourEditDlg::BeginTimedProcessing()
11706 
11707     Author:     Noel_Someone (Xara Group Ltd) <camelotdev@xara.com>
11708     Created:    14/6/99
11709     Inputs:     -
11710     Outputs:    -
11711     Returns:    -
11712     Purpose:    Sets a message based timer which indirectly calls 
11713                 ColourEditDlg::TimedProcessing.
11714 
11715 ********************************************************************************************/
11716 
11717 void ColourEditDlg::BeginTimedProcessing()
11718 {
11719     KillTimer(COLED_TIMER_ID);
11720     SetTimer(COLED_TIMER_ID, COLED_TIMER_FREQUENCY, NULL);
11721 }
11722 
11723 /********************************************************************************************
11724 
11725 >   void ColourEditDlg::EndTimedProcessing()
11726 
11727     Author:     Noel_Someone (Xara Group Ltd) <camelotdev@xara.com>
11728     Created:    14/6/99
11729     Inputs:     -
11730     Outputs:    -
11731     Returns:    -
11732     Purpose:    Kills the message based timer which is used to call
11733                 ColourEditDlg::TimedProcessing.
11734 
11735 ********************************************************************************************/
11736 
11737 void ColourEditDlg::EndTimedProcessing()
11738 {
11739     KillTimer(COLED_TIMER_ID);
11740 }
11741 
11742 
11743 
11744 
11745 /********************************************************************************************
11746 
11747 >   static BOOL ColourEditDlg::GetColourContext(ColourModel ColModel, ColourContext** ppContext)
11748 
11749     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
11750     Created:    27/02/04
11751     Inputs:     ColModel - the colour model to get a context for
11752     Outputs:    ppContext - location to write the context pointer
11753     Returns:    TRUE if context should be delete'd after use 
11754     Purpose:    Gets an appropriate colour context for displaying the colour picker
11755                 This is so that CMYK can use the printer profile
11756 
11757 ********************************************************************************************/
11758 
11759 BOOL ColourEditDlg::GetColourContext(ColourModel ColModel, ColourContext** ppContext)
11760 {
11761     // If we want a CMYK context then try to set one up with the printer profile
11762     if (ColourEditDlg::bUsePrintCMYK && ColModel == COLOURMODEL_CMYK)
11763     {
11764 PORTNOTE("other", "Disabled CMS usage")
11765 #ifndef EXCLUDE_FROM_XARALX
11766         ColourContext *pContext;
11767 
11768         XaraCMS* ptheCMS = GetApplication()->GetCMSManager();
11769 
11770         if (ptheCMS != NULL)
11771         {
11772             // First try to set the printer context specified in the ini file read
11773             // when we started up
11774             String_256 PrintProfile;
11775             ptheCMS->GetPrinterProfile(&PrintProfile);
11776             pContext = new ColourContextCMYK(NULL, &PrintProfile);
11777         
11778             if (pContext == NULL || !(pContext->IsDeviceContext()))
11779             {
11780                 // Eeek, we failed to build the physical device context
11781                 // which means something rather nasty went on.
11782 
11783                 delete pContext;
11784                 pContext=NULL;
11785 
11786                 // Now try with the default printer profile
11787                 ptheCMS->GetDefaultPrinterProfile(&PrintProfile);
11788                 pContext = new ColourContextCMYK(NULL, &PrintProfile);
11789 
11790                 if (pContext == NULL || !(pContext->IsDeviceContext()))
11791                 {
11792                     // We failed to get the default printer profile so delete the context and fall through
11793                     delete pContext;
11794                     pContext=NULL;
11795                 }
11796             }
11797 
11798             if (pContext)
11799             {
11800                 ColourContextList::GetList()->AddContext(&pContext);        // Add it to the list so it works properly
11801                 *ppContext = pContext;
11802                 return(TRUE);
11803             }
11804         }
11805 #endif
11806     }
11807 
11808     // Otherwise just fall back to getting a default context for the required model
11809     *ppContext = ColourContext::GetGlobalDefault(ColModel);
11810     return(FALSE);
11811 }
11812 

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