ctrlhelp.cpp

Go to the documentation of this file.
00001 // $Id: ctrlhelp.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Code to modify the behaviour of controls on Camelot bars so that they respond
00100 // to help messages and can be dragged about etc.
00101 
00102 
00103 #include "camtypes.h"
00104 
00105 #include "ctrlhelp.h"
00106 
00107 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "opdesc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "camframe.h"
00113 #include "bblwnd.h"
00114 //#include "ops.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "tool.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "dlgmgr.h"
00117 //#include "fonts.h"
00118 #include "keypress.h"
00119 //#include "childbar.h"
00120 #include "statline.h"
00121 
00122 //#include "textres.h"  // required so we know what an _R(IDC_FONT_COMBO) is.
00123 #include "textinfo.h"   // required so we know what a TextInfoBarOp is.
00124 
00125 //#include "bitbutn.h"
00126 
00127 #define STATE_TRACE 0
00128 
00129 
00130 wxWindow* EMPTY_SLOT = NULL;
00131 extern wxWindow* LastPointerInButton; // for new flat look - last button plinthed
00132                                  // refers to the global variable defined in bitbutn.cpp
00133 
00134 /********************************************************************************************
00135 
00136 >   class BarTable : public SimpleCCObject
00137 
00138     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00139     Created:    27/04/94
00140     Purpose:    Provide an array of window handles for all the existing Camelot bars.
00141                 This enables us to get bubble help to behave correctly, i.e. when the 
00142                 cursor is over the bar, the bubble help goes away, but the delay timer
00143                 for bubble help is not restarted.
00144     SeeAlso:    ControlHelper
00145 
00146 ********************************************************************************************/
00147 
00148 class BarTable : public SimpleCCObject
00149 {
00150 public:
00151     BarTable();
00152     ~BarTable();
00153     BOOL Init();
00154 
00155     BOOL AddBar(wxWindow*);
00156     BOOL DeleteBar(wxWindow*);
00157     BOOL ChangeBar(wxWindow*, wxWindow*);
00158 
00159     BOOL IsABar(wxWindow*);
00160 
00161 private:
00162     INT32 FindBarIndex(wxWindow*);
00163 
00164     enum
00165     {
00166         NotFound = -1,
00167         EmptySlot = 0,
00168         Granularity = 5,
00169         InitialSize = 10
00170     };
00171 
00172     wxWindow** Table;
00173     INT32 TableSize;
00174 };
00175 
00176 /********************************************************************************************
00177 
00178 >   BarTable::BarTable()
00179 
00180     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00181     Created:    26/04/94
00182     Purpose:    Construct the bar table object.
00183     SeeAlso:    BarTable::Init
00184 
00185 ********************************************************************************************/
00186 
00187 BarTable::BarTable()
00188 {
00189     // No table data yet.
00190     Table = NULL;
00191     TableSize = 0;
00192 }
00193 
00194 /********************************************************************************************
00195 
00196 >   BarTable::~BarTable()
00197 
00198     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00199     Created:    26/04/94
00200     Purpose:    Destroy a BarTable object - frees up all memory used by the table data.
00201     SeeAlso:    BarTable::Init
00202 
00203 ********************************************************************************************/
00204 
00205 BarTable::~BarTable()
00206 {
00207     // Free up the table data.
00208     CCFree((void*)Table);
00209 }
00210 
00211 /********************************************************************************************
00212 
00213 >   BOOL BarTable::Init()
00214 
00215     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00216     Created:    26/04/94
00217     Returns:    TRUE if successful;
00218                 FALSE if not.
00219     Purpose:    Allocate and initialise the table of bar entries.
00220     Errors:     Out of memory.
00221     SeeAlso:    BarTable
00222 
00223 ********************************************************************************************/
00224 
00225 BOOL BarTable::Init()
00226 {
00227     // Try to get some space for our table.
00228     Table = (wxWindow**) CCMalloc(BarTable::InitialSize * sizeof(wxWindow*));
00229     if (Table == NULL)
00230         return FALSE;
00231 
00232     // Initialise the table
00233     for (INT32 i = 0; i < BarTable::InitialSize; i++)
00234     {
00235         // No control registered in this entry yet
00236         Table[i] = EMPTY_SLOT;
00237     }
00238 
00239     // Update the table size
00240     TableSize = BarTable::InitialSize;
00241 
00242     // Success!
00243     return TRUE;
00244 }
00245 
00246 /********************************************************************************************
00247 
00248 >   BOOL BarTable::AddBar(wxWindow* Window)
00249 
00250     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00251     Created:    26/04/94
00252     Inputs:     Window - the handle of the bar.
00253     Returns:    TRUE if the bar was added to the table successully;
00254                 FALSE if not.
00255     Purpose:    Add a barhandle to the table, using the data passed in.  The table
00256                 will expand to accomodate the new bar if necessary and if possible.
00257     Errors:     Out of memory, Bar already exists in the table (debug builds only).
00258     SeeAlso:    BarTable::DeleteBar; BarTable::FindBar
00259 
00260 ********************************************************************************************/
00261 
00262 BOOL BarTable::AddBar(wxWindow* Window)
00263 {
00264     // Basic sanity checks.
00265     ENSURE(Window != NULL, "NULL window handle in BarTable::AddBar");
00266     if (Window == NULL )
00267         return FALSE;
00268     ENSURE(FindBarIndex(Window) == BarTable::NotFound, "Bar already exists in BarTable::AddBar");
00269 
00270     INT32 i = 0;
00271     while ((i < TableSize) && (Table[i] != EMPTY_SLOT))
00272         i++;
00273 
00274     if (i >= TableSize)
00275     {
00276         // No free slots - extend the table.
00277         INT32 NewTableSize = TableSize + BarTable::Granularity;
00278         wxWindow* *NewTable = (wxWindow* *) CCRealloc((void*)Table, NewTableSize * sizeof(wxWindow*));
00279         if (NewTable == NULL)
00280             return FALSE;
00281 
00282         // Table extended ok - point 'i' at the first free slot, and update table variables.
00283         i = TableSize;
00284         Table = NewTable;
00285         TableSize = NewTableSize;
00286 
00287         for (INT32 j=i+1;j<TableSize;j++)
00288             Table[j] = EMPTY_SLOT;
00289     }
00290 
00291     // If we've got this far, 'i' points at a valid free slot in the table.
00292     Table[i] = Window;
00293 
00294     // Everything worked
00295     return TRUE;
00296 }
00297 
00298 /********************************************************************************************
00299 
00300 >   BOOL BarTable::DeleteBar(wxWindow* Window)
00301 
00302     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    26/04/94
00304     Inputs:     Window - the handle of the control to remove.
00305     Returns:    TRUE if the control was removed ok;
00306                 FALSE if the control could not be found in the table.
00307     Purpose:    Remove the control from the table of subclassed controls.
00308     Errors:     Control's window handle was not found in the table (ENSUREs in debug builds).
00309     SeeAlso:    BarTable::AddControl; BarTable::FindControl; ControlHelper;
00310                 ControlEntry
00311 
00312 ********************************************************************************************/
00313 
00314 BOOL BarTable::DeleteBar(wxWindow* Window)
00315 {
00316     // Basic sanity checks
00317     ENSURE(Window != 0, "NULL Window handle in BarTable::DeleteBar!");
00318     if (Window == 0)
00319         return FALSE;
00320 
00321     // Search for the specified bar.
00322     INT32 i = FindBarIndex(Window);
00323 
00324     ENSURE(i != BarTable::NotFound, "Control not found in BarTable::DeleteBar");
00325 
00326     if (i == BarTable::NotFound)
00327         // Unable to find any record of the bar
00328         return FALSE;
00329 
00330     // Found the bar - delete it
00331     Table[i] = EMPTY_SLOT;
00332 
00333     // Return success
00334     return TRUE;
00335 }
00336 
00337 /********************************************************************************************
00338 
00339 >   BOOL BarTable::ChangeBar(wxWindow* Old, wxWindow* New)
00340 
00341     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    27/04/94
00343     Inputs:     Old - the old window handle of the bar.
00344                 New - the new window handle of the bar.
00345     Returns:    TRUE if the bar was changed successfully;
00346                 FALSE if not.
00347     Purpose:    Inform the table that a bar has been deleted and recreated with a new window
00348                 handle.
00349     Errors:     The bar could not be found.
00350     SeeAlso:    BarTable::AddBar; BarTable::DeleteBar
00351 
00352 ********************************************************************************************/
00353 
00354 BOOL BarTable::ChangeBar(wxWindow* Old, wxWindow* New)
00355 {
00356     // Basic sanity checks
00357     ENSURE((Old != NULL) && (New != NULL), "NULL Window handle in BarTable::ChangeBar!");
00358     if ((Old == NULL) || (New == NULL))
00359         return FALSE;
00360 
00361     // Search for the specified bar.
00362     INT32 i = FindBarIndex(Old);
00363 
00364     ENSURE(i != BarTable::NotFound, "Control not found in BarTable::ChangeBar");
00365 
00366     if (i == BarTable::NotFound)
00367         // Unable to find any record of the bar
00368         return FALSE;
00369 
00370     // Found the bar - update the window handle.
00371     Table[i] = New;
00372 
00373     // Return success
00374     return TRUE;
00375 }
00376 
00377 
00378 /********************************************************************************************
00379 
00380 >   BOOL BarTable::IsABar(wxWindow* Window)
00381 
00382     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00383     Created:    27/04/94
00384     Inputs:     Window - the window handle to check.
00385     Returns:    TRUE if this window handle is registered as a Camelot bar;
00386                 FALSE if not.
00387     Purpose:    Find out if a given window handle is the handle of a Camelot bar, as
00388                 recorded in this BarTable object.
00389     SeeAlso:    ControlHelper
00390 
00391 ********************************************************************************************/
00392 
00393 BOOL BarTable::IsABar(wxWindow* Window)
00394 {
00395     ENSURE(Window != NULL, "NULL Window in BarTable::IsABar");
00396     if (Window == NULL)
00397         return FALSE;
00398 
00399     return (FindBarIndex(Window) != BarTable::NotFound);
00400 }
00401 
00402 /********************************************************************************************
00403 
00404 >   INT32 BarTable::FindBarIndex(wxWindow* Window)
00405 
00406     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00407     Created:    26/04/94
00408     Inputs:     Window - the handle of the control to search for.
00409     Returns:    The index into the Table array of the control's record, or
00410                 BarTable::NotFound if the control is not registered in the table.
00411     Purpose:    Given the window handle of a control, return the offset into the table
00412                 array of its record.
00413     Errors:     Not found.
00414     SeeAlso:    BarTable::FindControl; BarTable::DeleteControl
00415 
00416 ********************************************************************************************/
00417 
00418 INT32 BarTable::FindBarIndex(wxWindow* Window)
00419 {
00420     // Scane the table for this entry
00421     INT32 i = 0;
00422     while ((i < TableSize) && (Table[i] != Window))
00423         i++;
00424 
00425     // Did we find it?
00426     if (Table[i] != Window)
00427         // No - inform caller of failure.
00428         return BarTable::NotFound;
00429 
00430     // Yes, success
00431     return i;
00432 }
00433 
00434 
00435 
00436 /*****************************************************************************
00437 >   BOOL ControlEntry::ControlStatusLineText(String_256* ptext)
00438 
00439     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00440     Created:    20/11/94
00441     Returns:    TRUE if a valid string was written to the text buffer
00442     Purpose:    return the status-line text for a given ControlEntry object
00443 *****************************************************************************/
00444 
00445 BOOL ControlEntry::ControlStatusLineText(String_256* ptext)
00446 {
00447     // if valid OpDesc, load status-line text from OpDescriptor
00448     if (pOpDesc != NULL)
00449         return pOpDesc->GetText(ptext,OP_DESC_TEXT);
00450 
00451     // If there's no status-line string associated with the control then make the
00452     // string blank.
00453     if (StatusID == 0)
00454     {
00455         TRACEUSER( "JustinF", _T("ControlEntry at 0x%lX has zero status-line string ID\n"),
00456                                 (UINT32) this);
00457         ptext->Empty();
00458         return TRUE;
00459     }
00460 
00461     // else just load using string ID provided directly by caller.
00462     return ptext->Load(StatusID,ModuleID);
00463 }
00464 
00465 
00466 /********************************************************************************************
00467 
00468 >   ControlTable::ControlTable()
00469 
00470     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00471     Created:    26/04/94
00472     Purpose:    Construct the control table object.
00473     SeeAlso:    ControlTable::Init
00474 
00475 ********************************************************************************************/
00476 
00477 ControlTable::ControlTable()
00478 {
00479     // No table data yet.
00480     Table = NULL;
00481     TableSize = 0;
00482 
00483     // Initial state
00484     LastWindow = NULL;
00485     LastIndex = 0;
00486 }
00487 
00488 /********************************************************************************************
00489 
00490 >   ControlTable::~ControlTable()
00491 
00492     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00493     Created:    26/04/94
00494     Purpose:    Destroy a ControlTable object - frees up all memory used by the table data.
00495     SeeAlso:    ControlTable::Init
00496 
00497 ********************************************************************************************/
00498 
00499 ControlTable::~ControlTable()
00500 {
00501     // Free up the table data.
00502     CCFree(Table);
00503 }
00504 
00505 /********************************************************************************************
00506 
00507 >   BOOL ControlTable::Init()
00508 
00509     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00510     Created:    26/04/94
00511     Returns:    TRUE if successful;
00512                 FALSE if not.
00513     Purpose:    Allocate and initialise the table of control entries.
00514     Errors:     Out of memory.
00515     SeeAlso:    ControlTable
00516 
00517 ********************************************************************************************/
00518 
00519 BOOL ControlTable::Init()
00520 {
00521     // Try to get some space for our table.
00522     Table = (ControlEntry *) CCMalloc(ControlTable::InitialSize * sizeof(ControlEntry));
00523     if (Table == NULL)
00524         return FALSE;
00525 
00526     // Initialise the table
00527     for (INT32 i = 0; i < ControlTable::InitialSize; i++)
00528     {
00529         // No control registered in this entry yet
00530         Table[i].Window = EMPTY_SLOT;
00531     }
00532 
00533     // Update the table size
00534     TableSize = ControlTable::InitialSize;
00535 
00536     // Success!
00537     return TRUE;
00538 }
00539 
00540 /********************************************************************************************
00541 
00542 >   BOOL ControlTable::AddControl(wxWindow* Window, ControlHelpInfo *pInfo, WNDPROC WndProc)
00543 
00544     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00545     Created:    26/04/94
00546     Inputs:     Window - the handle of the control (this is used as a minimal key for the
00547                          table entries).
00548                 pInfo - information about the control to add.
00549                 WndProc - the WndProc that the control normally uses.
00550     Returns:    TRUE if the control was added to the table successully;
00551                 FALSE if not.
00552     Purpose:    Add a control record to the table, using the data passed in.  The table
00553                 will expand to accomodate the new control if necessary and if possible.
00554     Errors:     Out of memory, Control already exists in the table (debug builds only).
00555     SeeAlso:    ControlTable::DeleteControl; ControlTable::FindControl
00556 
00557 ********************************************************************************************/
00558 
00559 PORTNOTE( "dialog", "Remove function that needs WNDPROC" )
00560 #if !defined(EXCLUDE_FROM_XARALX)
00561 BOOL ControlTable::AddControl(wxWindow* Window, ControlHelpInfo* pInfo, WNDPROC WndProc)
00562 {
00563     // Basic sanity checks.
00564     ERROR3IF(pInfo == NULL, "Null ControlHelpInfo* in ControlTable::AddControl");
00565     ENSURE(Window != NULL, "NULL window handle in ControlTable::AddControl");
00566     ENSURE(WndProc != NULL, "NULL WndProc in ControlTable::AddControl");
00567 //  ERROR3IF(pInfo->StatusID == 0, "Zero string ID in ControlTable::AddControl");
00568     
00569     if ((Window == NULL ) || (WndProc == NULL))
00570         return FALSE;
00571 
00572     // Start from the end of array and search backwards (it's more efficient for large
00573     // arrays).
00574     INT32 i = TableSize - 1;
00575 
00576     while ((i >= 0) && (Table[i].Window != EMPTY_SLOT))
00577         i--;
00578 
00579     if (i < 0)
00580     {
00581         // No free slots - extend the table.
00582         INT32 NewTableSize = TableSize + ControlTable::Granularity;
00583         ControlEntry *NewTable = 
00584             (ControlEntry *) CCRealloc(Table, NewTableSize * sizeof(ControlEntry));
00585         if (NewTable == NULL)
00586             return FALSE;
00587 
00588         // Table extended ok - point 'i' at the first free slot, and update table variables.
00589         i = TableSize;
00590         Table = NewTable;
00591         TableSize = NewTableSize;
00592 
00593         for (INT32 j=i+1;j<TableSize;j++)
00594             Table[j].Window = EMPTY_SLOT;
00595     }
00596 
00597     // If we've got this far, 'i' points at a valid free slot in the table.
00598     Table[i].Window   = Window;
00599     Table[i].WndProc  = WndProc;
00600     Table[i].Parent   = pInfo->Parent;
00601     Table[i].pOpDesc  = pInfo->pOpDesc;
00602     Table[i].BubbleID = pInfo->BubbleID;
00603     Table[i].StatusID = pInfo->StatusID;
00604     Table[i].ModuleID = pInfo->ModuleID;  
00605     
00606     // If the Control being subclassed is a combo or an edit then we need to add
00607     // commit handling.
00608 
00609     String_256 ClassNameStr;  
00610     GetClassName(Window, (TCHAR*)ClassNameStr, 255);
00611     Table[i].AddCommitHandling = ( (ClassNameStr == String_8(TEXT("Edit"))) ||
00612                                    (ClassNameStr == String_8(TEXT("ComboBox"))) ||
00613 //                                 (ClassNameStr == String_64(TEXT("cc_CustomEdit"))) ||                                    
00614                                    (ClassNameStr == String_64(TEXT("cc_1dBitmapComboBoxEdit"))) ||
00615                                    (ClassNameStr == String_64(TEXT("cc_2dBitmapComboBoxEdit"))) );
00616 
00617     // Set cache back to default
00618     LastWindow = NULL;
00619     LastIndex = 0;
00620 
00621     // Everything worked
00622     return TRUE;
00623 }
00624 #endif
00625 
00626 /********************************************************************************************
00627 
00628 >   WNDPROC ControlTable::DeleteControl(wxWindow* Window, wxWindow* *RealWindow)
00629 
00630     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00631     Created:    26/04/94
00632     Inputs:     Window - the handle of the control to remove (including its child windows).
00633     Outputs:    The window handle of the entry just deleted, which for child windows will
00634                 not be the same as the 'Window' input parameter. Pass in NULL if you don't
00635                 want this window handle.
00636     Returns:    The original WNDPROC of the control that was deleted, or
00637                 NULL if the control could not be found in the table.
00638     Purpose:    Remove the control or a child of it from the table of subclassed controls, 
00639                 and return the original WndProc for that window.
00640                 This function should be called repetitively for a window handle until NULL
00641                 is returned, to ensure that all child window entries of the control are
00642                 deleted too.
00643     Errors:     ENSUREs if NULL window handle passed in.
00644     SeeAlso:    ControlTable::AddControl; ControlTable::FindControl; ControlHelper;
00645                 ControlEntry
00646 
00647 ********************************************************************************************/
00648 
00649 WNDPROC ControlTable::DeleteControl(wxWindow* Window, wxWindow* *RealWindow)
00650 {
00651     // Basic sanity checks
00652     ENSURE(Window != 0, "NULL Window handle in ControlTable::DeleteControl!");
00653     if (Window == 0)
00654         return FALSE;
00655 
00656     // Search for the specified control and its children.
00657     INT32 i = FindControlIndex(Window, FALSE);
00658 
00659     if (i == ControlTable::NotFound)
00660         // No more controls associated with this window ID...
00661         return NULL;
00662 
00663     // Found the control - delete it
00664     if (RealWindow != NULL)
00665         *RealWindow = Table[i].Window;
00666     Table[i].Window = EMPTY_SLOT;
00667     Table[i].Parent = NULL;
00668 
00669     // Return success
00670     return Table[i].WndProc;
00671 }
00672 
00673 BOOL ControlTable::ChangeControl(wxWindow* Window, ControlHelpInfo *pInfo)
00674 {
00675     INT32 i = FindControlIndex(Window);
00676 
00677     if (i == ControlTable::NotFound)
00678         return FALSE;
00679 
00680     Table[i].BubbleID = pInfo->BubbleID;
00681     Table[i].StatusID = pInfo->StatusID;
00682     Table[i].ModuleID = pInfo->ModuleID;  
00683 
00684     // Everything worked
00685     return TRUE;
00686 }
00687 
00688 /********************************************************************************************
00689 
00690 >   ControlEntry *ControlTable::FindControl(wxWindow* Window)
00691 
00692     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00693     Created:    26/04/94
00694     Inputs:     Window - the handle of the control to look for.
00695     Returns:    Pointer to the data currently registered for the control in question,
00696                 or NULL if the control could not be found.
00697     Purpose:    Given a control's window handle, return the information currently registered
00698                 for that control.  Do not free the data pointed to by the return value.
00699     SeeAlso:    ControlEntry
00700 
00701 ********************************************************************************************/
00702 
00703 ControlEntry *ControlTable::FindControl(wxWindow* Window)
00704 {
00705     INT32 i=FindControlIndex(Window);
00706 
00707     if (i==ControlTable::NotFound)
00708         return NULL;
00709 
00710     return Table + i;
00711 }
00712 
00713 
00714 /********************************************************************************************
00715 
00716 >   INT32 ControlTable::FindControlIndex(wxWindow* Window, BOOL IgnoreChildren = TRUE)
00717 
00718     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00719     Created:    26/04/94
00720     Inputs:     Window         - the handle of the control to search for.
00721                 IgnoreChildren - if TRUE, then only return the entry for the control
00722                                  itself; if FALSE then return entries for the control or
00723                                  any children of it.
00724     Returns:    The index into the Table array of the control's record, or
00725                 ControlTable::NotFound if the control is not registered in the table.
00726     Purpose:    Given the window handle of a control, return the offset into the table
00727                 array of its record, or optionally of the control's child windows.
00728     Errors:     Not found.
00729     SeeAlso:    ControlTable::FindControl; ControlTable::DeleteControl
00730 
00731 ********************************************************************************************/
00732 
00733 INT32 ControlTable::FindControlIndex(wxWindow* Window, BOOL IgnoreChildren)
00734 {
00735     // Scan the table for this entry...
00736     INT32 i;
00737 
00738     // Is this the same as the last window handle we looked for?
00739     // If so, start from the last slot we looked at.
00740     if (LastWindow == Window)
00741         i = LastIndex;
00742     else 
00743         i = 0;
00744 
00745     while ((i < TableSize) && (Table[i].Window != Window) &&
00746            (IgnoreChildren || (Table[i].Parent != Window)))
00747         i++;
00748 
00749     // Did we find it?
00750     if (i >= TableSize)
00751         // No - inform caller of failure.
00752         return ControlTable::NotFound;
00753 
00754     // Yes, success
00755     LastIndex = i;
00756     LastWindow = Window;
00757 
00758     return i;
00759 }
00760 
00761 
00763 //
00764 //                      ControlHelper Member Functions + Data
00765 //
00767 
00768 // Pointer to the table of sublassed controls we're managing at present.
00769 ControlTable *ControlHelper::Controls = NULL;
00770 
00771 // Pointer to the list of bars we currently know about.
00772 BarTable *ControlHelper::Bars = NULL;
00773 
00774 // Window handle of the last control that the cursor was over.
00775 wxWindow* ControlHelper::LastControl = NULL;
00776 
00777 // The last position of the cursor (used to defer bubble help updates).
00778 POINT ControlHelper::LastPos = {-1, -1};
00779 
00780 // Pointer to the bubble help window.
00781 BubbleHelpWnd *ControlHelper::BubbleWnd = NULL;
00782 
00783 // Timer and flag to control small delay between consecutive bubble help display.
00784 MonotonicTime ControlHelper::PendingTimer;
00785 
00786 // State of the bubble help system
00787 ControlHelper::BubbleState ControlHelper::BubbleHelpState = STATE_DEAD;
00788 
00789 // TRUE if one of our controls has focus, in which case bubble help should not appear.
00790 BOOL ControlHelper::ControlHasFocus = FALSE;
00791 
00792 // Variables for ad-hoc bubble help
00793 wxWindow* ControlHelper::AdHocWindow = NULL;
00794 UINT32 ControlHelper::AdHocControl = 0;
00795 BOOL ControlHelper::AdHocControlIsDifferent = TRUE;
00796 void *ControlHelper::AdHocReference = NULL;
00797 ControlHelper::BubbleHelpCallback ControlHelper::AdHocCallback = NULL;
00798 
00799 
00800 // Number of non-kernel modal dialogs open.
00801 INT32 ControlHelper::ModalDialogs = 0;
00802 
00803 
00804 /********************************************************************************************
00805 
00806 >   BOOL ControlHelper::Init()
00807 
00808     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00809     Created:    26/04/94
00810     Returns:    TRUE if initialised ok;
00811                 FALSE if not.
00812     Purpose:    Called to initialise the control helper system.
00813 
00814 ********************************************************************************************/
00815 
00816 BOOL ControlHelper::Init()
00817 {
00818     // Allocate and initialise a BarTable object.
00819     Bars = new BarTable;
00820     if ((Bars == NULL) || !Bars->Init())
00821         return FALSE;
00822 
00823     // Allocate and intialise ourselves a ControlTable object
00824     Controls = new ControlTable;
00825     if ((Controls == NULL) || !Controls->Init())
00826         return FALSE;
00827 
00828     // Initialise the bubble help window system
00829     return BubbleHelpWnd::Init();
00830 }
00831 
00832 /********************************************************************************************
00833 
00834 >   void ControlHelper::DeInit()
00835 
00836     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00837     Created:    26/04/94
00838     Purpose:    Deinitialise the control helper system.
00839 
00840 ********************************************************************************************/
00841 
00842 void ControlHelper::DeInit()
00843 {
00844     // Deallocate our control table and bar table objects.
00845     delete Bars;
00846     Bars = NULL;
00847     delete Controls;
00848     Controls = NULL;
00849     BubbleHelpWnd::DeInit();
00850 }
00851 
00852 /********************************************************************************************
00853 
00854 >   BOOL ControlHelper::NotifyBarCreated(wxWindow* Window)
00855 
00856     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00857     Created:    27/04/94
00858     Inputs:     Window - the handle of the bar that has just been created.
00859     Returns:    TRUE if the bar was added to ControlHelper's records successfully;
00860                 FALSE if not.
00861     Purpose:    Inform the ControlHelper class that a bar has been created with the
00862                 specified window handle.
00863     Errors:     Out of memory.
00864     SeeAlso:    ControlHelper::NotifyBarDeleted; ControlHelper::NotifyBarChanged
00865 
00866 ********************************************************************************************/
00867 
00868 BOOL ControlHelper::NotifyBarCreated(wxWindow* Window)
00869 {
00870     // Sanity checks
00871     ENSURE(Bars != NULL, "ControlHelper has not been initialised successfully");
00872     ENSURE(Window != NULL, "NULL Window handle in ControlHelper::NotifyBarCreated");
00873 
00874     // Just add the bar to our list.
00875     return Bars->AddBar(Window);
00876 }
00877 
00878 /********************************************************************************************
00879 
00880 >   BOOL ControlHelper::NotifyBarDeleted(wxWindow* Window)
00881 
00882     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00883     Created:    27/04/94
00884     Inputs:     Window - handle of the bar that has just been deleted.
00885     Returns:    TRUE if the bar handle was found;
00886                 FALSE if not.
00887     Purpose:    Notify the ControlHelper class that a bar has been deleted.
00888     SeeAlso:    ControlHelper::NotifyBarChanged; ControlHelper::NotifyBarCreated
00889 
00890 ********************************************************************************************/
00891 
00892 BOOL ControlHelper::NotifyBarDeleted(wxWindow* Window)
00893 {
00894     // Sanity checks
00895     ENSURE(Bars != NULL, "ControlHelper has not been initialised successfully");
00896     ENSURE(Window != NULL, "NULL Window handle in ControlHelper::NotifyBarDeleted");
00897 
00898     // Just remove the bar from our list.
00899     return Bars->DeleteBar(Window);
00900 }
00901 
00902 /********************************************************************************************
00903 
00904 >   BOOL ControlHelper::NotifyBarChanged(wxWindow* Old, wxWindow* New)
00905 
00906     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00907     Created:    27/04/94
00908     Inputs:     Old - the old window handle of the bar.
00909                 New - the new window handle of the bar.
00910     Returns:    TRUE if the bar's window handle was updated successfully;
00911                 FALSE if not.
00912     Purpose:    Notify the ControlHelper class that a bar's window handle has been changed.
00913     Errors:     Bar not found.
00914     SeeAlso:    ControlHelper::NotifyBarCreated; ControlHelper::NotifyBarDeleted
00915 
00916 ********************************************************************************************/
00917 
00918 BOOL ControlHelper::NotifyBarChanged(wxWindow* Old, wxWindow* New)
00919 {
00920     // Sanity checks
00921     ENSURE(Bars != NULL, "ControlHelper has not been initialised successfully");
00922     ENSURE((Old != NULL) && (New != NULL), 
00923            "NULL Window handle in ControlHelper::NotifyBarChanged");
00924 
00925     // Just update the bar in our list.
00926     return Bars->ChangeBar(Old, New);
00927 }
00928 
00929 
00930 /********************************************************************************************
00931 
00932 >   BOOL ControlHelper::AddControl(wxWindow* Window, ControlHelpInfo *pInfo)
00933 
00934     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00935     Created:    10/05/94
00936     Inputs:     Window - The window to add an entries for.
00937                 pInfo - information about the control being added.
00938     Returns:    TRUE if the window and its descendants were processed ok;
00939                 FALSE if not.
00940     Purpose:    Add entries for a window and all its descendant windows to our list of
00941                 subclassed controls.
00942                 This is a 'helper' function for ControlHelper::NotifyControlCreated.
00943     SeeAlso:    ControlTable::AddControl; ControlHelper::NotifyControlCreated
00944 
00945 ********************************************************************************************/
00946 
00947 BOOL ControlHelper::AddControl(wxWindow* Window, ControlHelpInfo *pInfo)
00948 {
00949     // Firstly, try to add this control
00950     WNDPROC WndProc = (WNDPROC) ::GetWindowLong(Window, GWL_WNDPROC);
00951     ENSURE(WndProc != 0, "NULL WndProc in ControlHelper::AddControl");
00952 
00953     if (!(Controls->AddControl(Window, pInfo, WndProc)))
00954         goto Failure;
00955 
00956     // Subclass the control.
00957     ::SetWindowLong(Window, GWL_WNDPROC, (INT32) MyWndProc);
00958 
00959     // Now try to add/subclass all the children...
00960     wxWindow* Child;
00961     Child = ::GetWindow(Window, GW_CHILD);
00962 
00963     while (Child != NULL)
00964     {
00965         // Recurse for this child window
00966         if (!(AddControl(Child, pInfo)))
00967             goto Failure;
00968 
00969         // Get the next child window, if any.
00970         Child = ::GetWindow(Child, GW_wxWindow*NEXT);
00971     }
00972 
00973     // Success!
00974     return TRUE;
00975 
00976 Failure:
00977     // Could not add all the controls for some reason - remove any we might have added
00978     // so far, but only if this call is for the parent control (cos we recurse in this
00979     // function, and we only want to do this once).
00980     if (Window == pInfo->Parent)
00981     {
00982         wxWindow* RealWindow;
00983 
00984         while ((WndProc = Controls->DeleteControl(Window, &RealWindow)) != NULL)
00985         {
00986             // De-subclass the control.
00987             WNDPROC TheWndProc = (WNDPROC) ::GetWindowLong(Window, GWL_WNDPROC);
00988             if (TheWndProc = MyWndProc)
00989                 // It really is one we've subclassed, so 'de-subclass' it!
00990                 ::SetWindowLong(Window, GWL_WNDPROC, (INT32) WndProc);
00991         }
00992     }
00993 
00994     // Failed
00995     return FALSE;
00996 }
00997 
00998 /********************************************************************************************
00999 
01000 >   BOOL ControlHelper::NotifyControlCreated(wxWindow* Window, ControlHelpInfo *pInfo)
01001 
01002     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01003     Created:    26/04/94
01004     Inputs:     Window - the handle of the control that has been created.
01005                 pInfo - information about the control neing created
01006     Returns:    TRUE if the control was added to the ControlHelper's table ok;
01007                 FALSE if not.
01008     Purpose:    Inform the Control helper system that a control has just been created.
01009     Errors:     Out of memory; NULL window handle
01010     SeeAlso:    ControlHelper::NotifyControlDeleted; ControlHelper::NotifyControlChanged;
01011                 ControlHelper::AddControl; ControInfo
01012 
01013 ********************************************************************************************/
01014 
01015 BOOL ControlHelper::NotifyControlCreated(wxWindow* Window, ControlHelpInfo *pInfo)
01016 {
01017     // Sanity checks
01018     ENSURE(Controls != NULL, "ControlHelper has not been initialised successfully");
01019     ENSURE(Window != 0, "NULL Window handle in ControlHelper::NotifyControlCreated");
01020     ENSURE(pInfo != 0, "NULL ControlHelpInfo pointer in ControlHelper::NotifyControlCreated");
01021     if ((Controls == NULL) || (Window == 0) || (pInfo == NULL))
01022         return FALSE;
01023 
01024     // Fill in the parent field
01025     pInfo->Parent = Window;
01026 
01027     // Add the control to our list of sublassed controls.
01028     if (!AddControl(Window, pInfo))
01029         // Give up!
01030         return FALSE;
01031 
01032     // Success!
01033     return TRUE;
01034 }
01035 
01036 BOOL ControlHelper::NotifyControlCreated(wxWindow* Window, OpDescriptor *pOpDesc)
01037 {
01038     ControlHelpInfo Info;
01039     Info.pOpDesc = pOpDesc;
01040     Info.BubbleID = 0;
01041     Info.StatusID = 0;
01042     Info.ModuleID = 0;
01043 
01044     return NotifyControlCreated(Window, &Info);
01045 }
01046 
01047 /********************************************************************************************
01048 
01049 >   BOOL ControlHelper::NotifyControlChanged(wxWindow* Window, ControlHelpInfo* pInfo)
01050 
01051     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01052     Created:    21/04/95
01053     Inputs:     Window - the handle of the control that is to be changed.
01054                 pInfo - information about the control
01055     Returns:    TRUE if the control was changed in the table ok;
01056                 FALSE if not.
01057     Purpose:    Allows the Bubble and Status ID's of a control to be changed.
01058     Errors:     Out of memory; NULL window handle
01059     SeeAlso:    ControlHelper::NotifyControlDeleted; ControlHelper::NotifyControlChanged;
01060                 ControlHelper::AddControl; ControInfo
01061 
01062 ********************************************************************************************/
01063 
01064 BOOL ControlHelper::NotifyControlChanged(wxWindow* Window, ControlHelpInfo* pInfo)
01065 {
01066     if (Controls == NULL)
01067         return FALSE;
01068     
01069     if (!Controls->ChangeControl(Window, pInfo))
01070         return FALSE;
01071 
01072     return TRUE;
01073 }
01074 
01075 /********************************************************************************************
01076 
01077 >   BOOL ControlHelper::NotifyControlDeleted(wxWindow* Window)
01078 
01079     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01080     Created:    26/04/94
01081     Inputs:     Window - handle of the window that has been deleted.
01082     Returns:    TRUE if the control was deleted from the ControlHelper's table ok;
01083                 FALSE if not.
01084     Purpose:    Notify the control helper system that a control has just been deleted.
01085     Errors:     ControlHelper has not been initialised; Window handle is 0.
01086     SeeAlso:    ControlHelper::NotifyControlCreated; ControlHelper::NotifyControlChanged
01087 
01088 ********************************************************************************************/
01089 
01090 BOOL ControlHelper::NotifyControlDeleted(wxWindow* Window)
01091 {
01092     ENSURE(Controls != NULL, "ControlHelper has not been initialised successfully");
01093     ENSURE(Window != NULL, "NULL Window handle in ControlHelper::NotifyControlDeleted");
01094     if ((Controls == NULL) || (Window == NULL))
01095         return FALSE;
01096 
01097     // If deleting the currently active bubble help control, then kill bubble help.
01098     if ((Window == LastControl) && (BubbleHelpState != STATE_DEAD))
01099         SetState(STATE_DEAD);
01100 
01101     wxWindow* RealWindow;
01102     WNDPROC OldWndProc;
01103 
01104     while ((OldWndProc = Controls->DeleteControl(Window, &RealWindow)) != NULL)
01105     {
01106         // De-subclass the control.
01107         WNDPROC CurrentWndProc = (WNDPROC) ::GetWindowLong(RealWindow, GWL_WNDPROC);
01108 
01109         if (CurrentWndProc == MyWndProc)
01110             // It really is one we've subclassed, so 'de-subclass' it!
01111             ::SetWindowLong(RealWindow, GWL_WNDPROC, (INT32) OldWndProc);
01112     }
01113 
01114     // If we got this far it's successful
01115     return TRUE;
01116 }
01117 
01118 
01119 /*****************************************************************************
01120 >   static BOOL ControlHelper::GetStatusLineText(String_256* ptext, wxWindow* window)
01121 
01122     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01123     Created:    20/11/94
01124     Returns:    TRUE if returning valid text
01125     Purpose:    Get status-line text for a control with given WHND
01126 *****************************************************************************/
01127 
01128 BOOL ControlHelper::GetStatusLineText(String_256* ptext, wxWindow* window)
01129 {
01130     if (window==NULL)
01131         return FALSE;
01132 
01133     ControlEntry* pEntry=Controls->FindControl(window);
01134     if (pEntry==NULL)
01135         return FALSE;
01136     String_256 strCaption;
01137     GetWindowText(window, strCaption, 255);
01138     if (strCaption == String_256("Download"))
01139     {
01140         *ptext = "Download selected resource to the local hard disk";
01141         return TRUE;
01142     }
01143     else return pEntry->ControlStatusLineText(ptext);
01144 }
01145 
01146 
01147 /********************************************************************************************
01148 
01149 >   LRESULT ControlHelper::MyWndProc(wxWindow* Window, UINT32 Msg, WPARAM wParam, LPARAM lParam)
01150 
01151     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01152     Created:    26/04/94
01153     Inputs:     The usual - see SDK documentation for "WindowProc".
01154     Returns:    As for SDK WindowProc.
01155     Purpose:    Callback function for special handling of controls on Camelot bars.
01156                 At present it does nothing - just chains to the controls usual WndProc.
01157     Errors:     
01158     SeeAlso:    ControlHelper
01159 
01160 ********************************************************************************************/
01161 
01162 LRESULT ControlHelper::MyWndProc(wxWindow* Window, UINT32 Msg, WPARAM wParam, LPARAM lParam)
01163 {
01164     ENSURE(Window != 0, "NULL Window handle in ControlHelper::MyWndProc");
01165 
01166     // Find the WindowProc for this control.
01167 
01168     ControlEntry *pEntry = Controls->FindControl(Window);
01169 
01170     ENSURE(pEntry != NULL, "Could not find subclassed control in ControlHelper::MyWndProc");
01171 
01172     if (pEntry != NULL)
01173     {
01174         switch (Msg)
01175         {
01176             case WM_MOUSEMOVE:
01177             {
01178         
01179                 // start control drag
01180                 if(KeyPress::IsAlternativePressed())
01181                 {
01182                     return TRUE;
01183                 }
01184                 // Update the status bar on MouseMove messages
01185                 String_256 Desc;
01186                 if (pEntry->ControlStatusLineText(&Desc))
01187                 {
01188                     StatusLine* pStatusLine=GetApplication()->GetpStatusLine();
01189                     if (pStatusLine->AllowControlHelp ())
01190                     {
01191                         if (pStatusLine)
01192                             pStatusLine->UpdateText(&Desc,STATUSLINE_SELDESC_BUTTONS);
01193                     }
01194                 }
01195             }
01196             break;
01197   
01198             case WM_SETFOCUS:
01199                 // This control has focus - disable the bubble help.
01200                 //ControlHasFocus = TRUE;
01201                 if (pEntry->AddCommitHandling)
01202                 {
01203                     SendMessage(GetParent(GetParent(Window)),WM_CTL_SETFOCUS,TRUE,(LPARAM)Window);  
01204                     SendMessage(GetParent(Window),WM_CTL_SETFOCUS,TRUE,(LPARAM)Window);
01205                     
01206                     // Send the control an EM_SETSEL message so the text within it is highlighted.
01207                     ::SendMessage(Window, EM_SETSEL, 0, (LPARAM) (INT32) -1);
01208                 }
01209 
01210                 // Fall through...
01211             
01212             case WM_LBUTTONDOWN:
01213                 if(KeyPress::IsAlternativePressed())
01214                 {
01215                     String_256 ClassNameStr;  // The control type
01216                     GetClassName(GetParent(Window), (TCHAR*)ClassNameStr, 255);
01217                     if (ClassNameStr == String_8(TEXT("ComboBox")))
01218                     {
01219                         SendMessage(GetParent(GetParent(Window)),WM_START_CTLDRAG,
01220                                         KeyPress::IsConstrainPressed(),(LPARAM)GetParent(Window));  
01221                     }
01222                     else
01223                     {
01224                         SendMessage(GetParent(Window),WM_START_CTLDRAG,
01225                                         KeyPress::IsConstrainPressed(),(LPARAM)Window);
01226                     }
01227                     return TRUE;
01228                 }
01229             case WM_MBUTTONDOWN:
01230             case WM_RBUTTONDOWN:
01231             case WM_LBUTTONUP:
01232             case WM_MBUTTONUP:
01233             case WM_RBUTTONUP:
01234             case WM_LBUTTONDBLCLK:
01235             case WM_MBUTTONDBLCLK:
01236             case WM_RBUTTONDBLCLK:
01237         
01238                 // start control drag
01239             
01240                 // Mouse activity - disable bubble help.
01241                 BubbleHelpDisable();
01242                 break;
01243 
01244             case WM_KILLFOCUS:
01245                 // This control has lost focus - allow the bubble help to start working again.
01246                 ControlHasFocus = FALSE;
01247                 if (pEntry->AddCommitHandling)
01248                 {
01249                     SendMessage(GetParent(GetParent(Window)),WM_CTL_SETFOCUS,FALSE,(LPARAM)Window); 
01250                     SendMessage(GetParent(Window),