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),