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),WM_CTL_SETFOCUS,FALSE,(LPARAM)Window); 01251 } 01252 break; 01253 default: 01254 01255 if (pEntry->AddCommitHandling) 01256 { 01257 // Is commit processing required, this should be the case if the control 01258 // is an edit or ComboBox 01259 01260 // Determine the control type 01261 switch (Msg) 01262 { 01263 case WM_CHAR: 01264 // Process this message to avoid message beeps. 01265 if ((wParam == CAMKEY(RETURN)) || (wParam == CAMKEY(TAB))) 01266 { 01267 ControlHasFocus = FALSE; 01268 return FALSE; 01269 } 01270 break; 01271 01272 case WM_GETDLGCODE: 01273 return DLGC_WANTALLKEYS; 01274 01275 case WM_KEYDOWN: 01276 // escape should return the focus back to the main frame 01277 if (wParam == CAMKEY(ESCAPE)) 01278 { 01279 ControlHasFocus = FALSE; 01280 DialogManager::DefaultKeyboardFocus(); 01281 return FALSE; 01282 } 01283 else if (wParam == CAMKEY(RETURN) || wParam == CAMKEY(TAB)) 01284 { 01285 wxWindow* BarWnd; 01286 wxWindow* CtlWnd; 01287 01288 String_256 ClassNameStr; // The control type 01289 01290 BOOL camelotCustomComboBox = FALSE; 01291 01293 01294 // need to do things slightly differently if the control is a 01295 // cc_1dBitmapComboBoxEdit or cc_2dBitmapComboBoxEdit 01296 01297 GetClassName (Window, (TCHAR*)ClassNameStr, 255); 01298 01299 if ((ClassNameStr == String_64(TEXT("cc_1dBitmapComboBoxEdit"))) || 01300 (ClassNameStr == String_64(TEXT("cc_2dBitmapComboBoxEdit")))) 01301 { 01302 camelotCustomComboBox = TRUE; 01303 } 01304 01306 01307 if (camelotCustomComboBox == FALSE) 01308 { 01309 GetClassName(GetParent(Window), (TCHAR*)ClassNameStr, 255); 01310 01311 if (ClassNameStr == String_8(TEXT("ComboBox")) || ClassNameStr == String_16(TEXT("cc_CustomEdit"))) 01312 { 01313 // edit controls of these classes are children of the controls. 01314 BarWnd = GetParent(GetParent(Window)); // Because combo edit control 01315 // is a child of the combo 01316 // control itself 01317 CtlWnd = GetParent(Window); 01318 } 01319 else 01320 { 01321 // It's an Edit control 01322 BarWnd = GetParent(Window); // Bar is the edit's parent 01323 CtlWnd = Window; 01324 } 01325 } 01326 else 01327 { 01328 BarWnd = GetParent (Window); 01329 CtlWnd = Window; 01330 01331 // the following sendmessage is actually so that when CAMKEY(RETURN) is hit, 01332 // (which actually goes through the WM_KEYDOWN in ctrlhelp.cpp); that we can actually 01333 // set the selected item BEFORE dialog manager continues ! 01334 01335 if (wParam == CAMKEY(RETURN)) 01336 { 01337 SendMessage (CtlWnd, CB_SETTOPINDEX, 1, 0); 01338 } 01339 else 01340 { 01341 SendMessage (CtlWnd, CB_SETTOPINDEX, 0, 0); 01342 } 01343 } 01344 01345 if (wParam == CAMKEY(RETURN) ) 01346 { 01347 ControlHasFocus = FALSE; 01348 SendMessage(BarWnd, WM_CTL_SETFOCUS, COMMIT, (LPARAM) Window); 01349 } 01350 01351 // Send commit message to parent, passing the key code (TAB or ENTER) which 01352 // it might be useful to know. 01353 SendMessage(BarWnd, WM_CTL_COMMIT, GetWindowID(CtlWnd), (LPARAM) wParam); 01354 01355 // To fix various bugs this code is a little bodged. The problems 01356 // that this code tries to address are: 01357 // 1) Clicking in one of the size edit controls in the selector info bar, 01358 // entering some text, pressing enter and then clicking in the same edit 01359 // control a second time (this was refusing to take the focus a second 01360 // time) 01361 // 2) Typing a font name in the font drop down box box and then pressing 01362 // enter (this was returning to the font the user had selected before 01363 // they started typeing) 01364 if (::GetDlgCtrlID(Window) != _R(IDC_FONT_COMBO)) 01365 { 01366 if (wParam == CAMKEY(RETURN)) 01367 { 01368 GetMainFrame()->SetFocus(); 01369 } 01370 else 01371 { 01372 // Move focus to the next (previous) control, just like Windows. 01373 wxWindow* wxWindow*NewFocus = ::GetNextDlgTabItem(BarWnd, Window, ::GetKeyState(CAMKEY(SHIFT)) < 0); 01374 if (wxWindow*NewFocus != NULL) ::SetFocus(wxWindow*NewFocus); 01375 } 01376 return FALSE; 01377 } 01378 } 01379 // added by Karim 30/9/99, to allow a more intelligent font-combo 01380 else if (wParam >= 'A' && wParam <= 'Z' && ::GetDlgCtrlID(Window) == _R(IDC_FONT_COMBO)) 01381 { 01382 // pass the message on to the combo-box's parent, to be 01383 // processed in DialogManager::SendDialogMessage. 01384 ::SendMessage(GetParent(Window), WM_KEYDOWN, wParam, lParam); 01385 } 01386 break; 01387 } 01388 01389 } 01390 } 01391 } 01392 01393 // For any other messages, kill bubble help before passing them on. 01394 // if (BubbleHelpActive) 01395 // BubbleHelpKill(); 01396 01397 // Default to chaining to the normal WndProc 01398 return ::CallWindowProc(pEntry->WndProc, Window, Msg, wParam, lParam); 01399 } 01400 01401 01402 /******************************************************************************************** 01403 01404 > void ControlHelper::ServiceBubbleHelp() 01405 01406 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01407 Created: 26/04/94 01408 Purpose: Updates the bubble help for our controls. Should be called on idle or 01409 timer events. 01410 01411 ********************************************************************************************/ 01412 01413 void ControlHelper::ServiceBubbleHelp() 01414 { 01415 // Find out which window the cursor is over. 01416 POINT Pos; 01417 ::GetCursorPos(&Pos); 01418 wxWindow* ThisControl = ::WindowFromPoint(Pos); 01419 01420 if ((ThisControl != NULL) /*&& (IsWindowVisible (ThisControl))*/) 01421 { 01422 // This code copes with disabled controls... 01423 01424 // To look at the child windows of wxWindow*, screen coordinates 01425 // need to be converted to client coordinates. 01426 POINT ClientPos = Pos; 01427 ScreenToClient(ThisControl, &ClientPos); 01428 01429 // Search through all child windows at this point. This 01430 // will continue until no child windows remain. 01431 while (TRUE) 01432 { 01433 wxWindow* Child = ChildWindowFromPoint(ThisControl, ClientPos); 01434 01435 if ((Child != NULL) && (Child != ThisControl)) 01436 ThisControl = Child; 01437 else 01438 break; 01439 } 01440 } 01441 01442 01443 WNDPROC WndProc; 01444 01445 if (ThisControl == AdHocWindow) 01446 // Special ad-hoc bubble help - bodge the WndProc to fool the state machine. 01447 WndProc = ControlHelper::MyWndProc; 01448 else 01449 { 01450 // *** BODGE FIX by JustinF. 01451 // For some reason GetWindowLong GP-faults , so check the params to the call below. 01452 // IsWindow clears the error state so get it now just in case... 01453 DWORD LastError = ::GetLastError(); 01454 if (!::IsWindow(ThisControl)) 01455 { 01456 TRACE( _T("BubbleHelp wxWindow* bug - ThisControl is invalid (0x%p), GetLastError is 0x%lX\n"), 01457 (LPVOID) ThisControl, LastError); 01458 return; 01459 } 01460 01461 // Find out the WndProc for this window. 01462 WndProc = (WNDPROC) ::GetWindowLong(ThisControl, GWL_WNDPROC); 01463 01464 // If it's one of ours, find out if this is a child window of a control. 01465 // Only bother if this is different to the last control we looked at (because 01466 // we will have done this same check for the last control, so it must be a proper 01467 // parent control if it's the same as the last control). 01468 if ((ThisControl != LastControl) && (WndProc == MyWndProc)) 01469 { 01470 ControlEntry *pEntry = Controls->FindControl(ThisControl); 01471 ENSURE(pEntry != NULL, "Catastrophic failure in bubble help"); 01472 01473 // Just use the main parent handle of this control (may actually be the 01474 // same as the value ThisControl currently holds anyway). 01475 ThisControl = pEntry->Parent; 01476 } 01477 } 01478 01479 // 01480 // Enter state machine event processor... 01481 // 01482 BubbleHelpStateMachine(Pos, ThisControl, WndProc); 01483 } 01484 01485 /******************************************************************************************** 01486 01487 > void ControlHelper::BubbleHelpStateMachine(POINT Pos, wxWindow* ThisControl, WNDPROC WndProc) 01488 01489 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01490 Created: 30/06/94 01491 Inputs: Pos - the current cursor position; used to detect how long the mouse has 01492 been stationary for. Currently this is not used as Charles doesn't 01493 like it if bubble doesn't come up if you continuously jaggle the 01494 pointer about. 01495 ThisControl - window handle of the control that the pointer is over. 01496 WndProc - WindowProc of the control specified by ThisControl (this enables 01497 this routine to work out if this control has been subclassed by 01498 the ControlHelper system). 01499 Purpose: Service the bubble help state machine. Given the input parameters it 01500 works out whether it needs to change state, and which state to change to. 01501 State changing also depends on timers elapsing and so on. 01502 SeeAlso: - 01503 01504 ********************************************************************************************/ 01505 01506 void ControlHelper::BubbleHelpStateMachine(POINT Pos, wxWindow* ThisControl, WNDPROC WndProc) 01507 { 01508 // can sometimes be called with a NULL handle if pointer has found its way offscreen 01509 if(ThisControl== NULL) 01510 return; 01511 01512 switch (BubbleHelpState) 01513 { 01514 case STATE_DEAD: 01515 if (WndProc == ControlHelper::MyWndProc) 01516 { 01517 // It's one of our controls - set update pending 01518 SetState(STATE_INITIAL_PENDING); 01519 } 01520 else if (Bars->IsABar(ThisControl)) 01521 { 01522 // It's a Camelot bar - set to initial disabled. 01523 SetState(STATE_INITIAL_DISABLED); 01524 } 01525 else 01526 { 01527 // this means that the cursor has left all the bars alone 01528 // so now is a good time to remove that button plinth if we were 01529 // using the flat style buttons with active plinth/bevelling (sjk 24/2/00) 01530 if (LastPointerInButton) 01531 { 01532 INT32 value = GetWindowLong(LastPointerInButton, GWL_STYLE); 01533 if (value & BS_POINTEROVER) 01534 { 01535 // extra tests on position since the export dlg appears to use the 01536 // help system slightly differently!!! 01537 RECT r; 01538 GetWindowRect(LastPointerInButton, &r); 01539 POINT p; 01540 GetCursorPos(&p); 01541 01542 if (p.x < r.left || p.x > r.right || p.y < r.top || p.y > r.bottom) 01543 { 01544 SetWindowLong(LastPointerInButton, GWL_STYLE, value & ~BS_POINTEROVER); 01545 ::InvalidateRect(LastPointerInButton, NULL, FALSE); 01546 ::UpdateWindow(LastPointerInButton); 01547 LastPointerInButton = NULL; 01548 } 01549 } 01550 } 01551 } 01552 break; 01553 01554 case STATE_INITIAL_PENDING: 01555 if (WndProc == ControlHelper::MyWndProc) 01556 { 01557 // User is over our control - if delay has passed and none of our controls 01558 // have focus, set to active 01559 if (PendingTimer.Elapsed(800) && !ControlHasFocus) 01560 { 01561 SetState(STATE_ACTIVE, ThisControl); 01562 } 01563 } 01564 else if (Bars->IsABar(ThisControl)) 01565 { 01566 // User is on a control bar - disable help. 01567 SetState(STATE_INITIAL_DISABLED); 01568 } 01569 else 01570 { 01571 // User is not on a control or a bar - kill bubble help. 01572 SetState(STATE_DEAD); 01573 } 01574 break; 01575 01576 case STATE_INITIAL_DISABLED: 01577 if (WndProc == ControlHelper::MyWndProc) 01578 { 01579 // User is over our control - is it different to the last control 01580 // we looked at? 01581 if (ThisControl != LastControl) 01582 { 01583 // Yes - start the delay timer for displaying bubble help 01584 SetState(STATE_INITIAL_PENDING); 01585 } 01586 else 01587 { 01588 // No - bubble help must be disabled for this control so do nothing. 01589 } 01590 } 01591 else if (!Bars->IsABar(ThisControl)) 01592 { 01593 // User is not on a control or a bar - kill bubble help. 01594 SetState(STATE_DEAD); 01595 } 01596 break; 01597 01598 case STATE_UPDATE_PENDING: 01599 if (WndProc == ControlHelper::MyWndProc) 01600 { 01601 // User is over our control - if delay has passed, set to active (but only 01602 // if none of our controls have focus). 01603 if (PendingTimer.Elapsed(100) && !ControlHasFocus) 01604 { 01605 SetState(STATE_ACTIVE, ThisControl); 01606 } 01607 } 01608 else if (Bars->IsABar(ThisControl)) 01609 { 01610 // User is on a control bar - disable help. 01611 SetState(STATE_DISABLED); 01612 } 01613 else 01614 { 01615 // User is not on a control or a bar - kill bubble help. 01616 SetState(STATE_DEAD); 01617 } 01618 break; 01619 01620 case STATE_ACTIVE: 01621 if (BubbleWnd->GetSafewxWindow*() == ThisControl) 01622 { 01623 // We're over our own bubble window - disable it for a bit. 01624 SetState(STATE_UPDATE_PENDING); 01625 01626 // We don't want to update LastControl or LastPos. 01627 return; 01628 } 01629 else if (WndProc == ControlHelper::MyWndProc) 01630 { 01631 // User is over our control - if a different one, set delayed update, 01632 // otherwise no change. 01633 // NB. if ad-hoc is active, we check different variables 01634 if (ThisControl == AdHocWindow) 01635 { 01636 // Ad-hoc window - check the flag set by DoBubbleHelpOn(). 01637 if (AdHocControlIsDifferent) 01638 SetState(STATE_UPDATE_PENDING); 01639 } 01640 else if (LastControl != ThisControl) 01641 { 01642 SetState(STATE_UPDATE_PENDING); 01643 } 01644 } 01645 else if (Bars->IsABar(ThisControl)) 01646 { 01647 // User is on a control bar - disable help. 01648 SetState(STATE_DISABLED); 01649 } 01650 else 01651 { 01652 // User is not on a control or a bar - kill bubble help. 01653 SetState(STATE_DEAD); 01654 } 01655 break; 01656 01657 case STATE_DISABLED: 01658 if (WndProc == ControlHelper::MyWndProc) 01659 { 01660 // User is over our control - is it different to the last control 01661 // we looked at? 01662 // NB. if ad-hoc is active, we check different variables 01663 if (ThisControl == AdHocWindow) 01664 { 01665 // Ad-hoc window - check the flag set by DoBubbleHelpOn(). 01666 if (AdHocControlIsDifferent) 01667 SetState(STATE_UPDATE_PENDING); 01668 } 01669 else if (LastControl != ThisControl) 01670 { 01671 // Yes - start the delay timer for displaying bubble help 01672 SetState(STATE_UPDATE_PENDING); 01673 } 01674 else 01675 { 01676 // No - bubble help must be disabled for this control so do nothing. 01677 } 01678 } 01679 else if (!Bars->IsABar(ThisControl)) 01680 { 01681 // User is not on a control or a bar - kill bubble help. 01682 SetState(STATE_DEAD); 01683 } 01684 break; 01685 01686 default: 01687 ENSURE(FALSE, "Bad current state in bubble help"); 01688 break; 01689 } 01690 01691 // Update the cursor position for pending updates, and the last control position 01692 // for display updates. 01693 LastPos = Pos; 01694 LastControl = ThisControl; 01695 } 01696 01697 01698 01699 /******************************************************************************************** 01700 01701 > void ControlHelper::SetState(BubbleState NewState, wxWindow* Window) 01702 01703 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01704 Created: 30/06/94 01705 Inputs: NewState - the state to change the state machine to. 01706 Window - window handle of the control the pointer is currently over (only 01707 used when setting the state to STATE_ACTIVE, when it is used to 01708 get the bubble help text). 01709 Purpose: Change the state of the bubble help state machine to the specified state. 01710 Calls the appropriate state change handler to process the event. 01711 SeeAlso: ControlHelper::DeadHandler; ControlHelper::ActiveHandler; 01712 ControlHelper::InitialPendingHandler; ControlHelper::InitialDisabledHandler; 01713 ControlHelper::DisabledHandler; ControlHelper::UpdatePendingHandler 01714 01715 ********************************************************************************************/ 01716 01717 void ControlHelper::SetState(BubbleState NewState, wxWindow* Window) 01718 { 01719 // Find out which state to change to. 01720 switch (NewState) 01721 { 01722 case STATE_DEAD: DeadHandler(); break; 01723 case STATE_ACTIVE: ActiveHandler(Window); break; 01724 case STATE_INITIAL_PENDING: InitialPendingHandler(); break; 01725 case STATE_INITIAL_DISABLED: InitialDisabledHandler(); break; 01726 case STATE_UPDATE_PENDING: UpdatePendingHandler(); break; 01727 case STATE_DISABLED: DisabledHandler(); break; 01728 } 01729 } 01730 01731 01732 /******************************************************************************************** 01733 01734 > void ControlHelper::DeadHandler() 01735 01736 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01737 Created: 30/06/94 01738 Purpose: Kill off the bubble help by setting the bubble help state machine to the 01739 STATE_DEAD state. 01740 SeeAlso: ControlHelper::ActiveHandler; ControlHelper::InitialPendingHandler; 01741 ControlHelper::InitialDisabledHandler; ControlHelper::DisabledHandler; 01742 ControlHelper::UpdatePendingHandler 01743 01744 ********************************************************************************************/ 01745 01746 void ControlHelper::DeadHandler() 01747 { 01748 #if STATE_TRACE 01749 if (IsUserName("Tim")) 01750 TRACE( _T("STATE_DEAD\n")); 01751 #endif 01752 01753 switch (BubbleHelpState) 01754 { 01755 case STATE_ACTIVE: 01756 // Kill the bubble help window and fall through. 01757 ENSURE(BubbleWnd != NULL, "No bubble help window!"); 01758 BubbleHelpKill(); 01759 01760 case STATE_INITIAL_PENDING: 01761 case STATE_INITIAL_DISABLED: 01762 case STATE_DISABLED: 01763 case STATE_UPDATE_PENDING: 01764 BubbleHelpState = STATE_DEAD; 01765 break; 01766 01767 default: 01768 ENSURE(FALSE, "Wrong state in bubble help"); 01769 break; 01770 } 01771 } 01772 01773 /******************************************************************************************** 01774 01775 > void ControlHelper::ActiveHandler(wxWindow* Window) 01776 01777 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01778 Created: 30/06/94 01779 Inputs: Window - handle of the control the cursor is currently over. 01780 Purpose: Activate the bubble help system by moving to the STATE_ACTIVE state. 01781 This causes a bubble help window to appear under the cursor, but not is 01782 there are any keys down, or if there is a drag going on, or if our app 01783 is not active. At some time in the future we should also refuse to put 01784 up bubble help if the user has the menu up. 01785 SeeAlso: ControlHelper::DeadHandler; ControlHelper::InitialPendingHandler; 01786 ControlHelper::InitialDisabledHandler; ControlHelper::DisabledHandler; 01787 ControlHelper::UpdatePendingHandler 01788 01789 ********************************************************************************************/ 01790 01791 void ControlHelper::ActiveHandler(wxWindow* Window) 01792 { 01793 // Sanity checks 01794 ENSURE(Window != NULL, "Bad handle in control helper ActiveHandler()"); 01795 ENSURE(BubbleWnd == NULL, "Bubble window already exists in BubbleHelpStart()"); 01796 01797 // No bubble help during drags, or if any mouse buttons are down. 01798 01799 // Get mouse keys - top bit is set if the button is down. 01800 INT8 MouseStatus = (::GetKeyState(CAMKEY(LBUTTON)) | 01801 ::GetKeyState(CAMKEY(MBUTTON)) | 01802 ::GetKeyState(CAMKEY(RBUTTON))); 01803 01804 if ((MouseStatus & 0x8000) || 01805 (Operation::GetCurrentDragOp() != NULL)) 01806 { 01807 // Revert to pending 01808 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01809 SetState(STATE_INITIAL_PENDING); 01810 return; 01811 } 01812 01813 // Don't do bubble help if we're iconised. 01814 CWnd *pMainWnd = AfxGetApp()->m_pMainWnd; 01815 if (pMainWnd->IsIconic()) 01816 { 01817 // Revert to pending 01818 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01819 SetState(STATE_INITIAL_PENDING); 01820 return; 01821 } 01822 01823 // Only do bubble help if our application is active. 01824 wxWindow* Active = ::GetActiveWindow(); 01825 wxWindow* MainWnd = pMainWnd->m_wxWindow*; 01826 01827 if ((Active != MainWnd) && (::GetParent(Active) != MainWnd)) 01828 { 01829 // Revert to pending 01830 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01831 SetState(STATE_INITIAL_PENDING); 01832 return; 01833 } 01834 01835 // Don't do bubble help if modal dialog is open. 01836 if (DialogManager::ModalDialogOpen() || (ModalDialogs > 0)) 01837 { 01838 // Revert to pending 01839 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01840 SetState(STATE_INITIAL_PENDING); 01841 return; 01842 } 01843 01844 // Don't do bubble help if a menu is up - Windows captures the mouse during a menu 01845 // processing loop. 01846 if (::GetCapture() != NULL) 01847 { 01848 // Revert to pending 01849 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01850 SetState(STATE_INITIAL_PENDING); 01851 return; 01852 } 01853 01854 // also only do bubble help if the control were over is actually visible 01855 if (::IsWindowVisible (Window) == FALSE) 01856 { 01857 // Revert to pending 01858 BubbleHelpState = STATE_ACTIVE; // Very important else state machine gets upset! 01859 SetState(STATE_INITIAL_PENDING); 01860 return; 01861 } 01862 01863 // Ok - we're allowed to display bubble help - work out what to do: 01864 01865 #if STATE_TRACE 01866 if (IsUserName("Tim")) 01867 TRACE( _T("STATE_ACTIVE\n")); 01868 #endif 01869 01870 switch (BubbleHelpState) 01871 { 01872 case STATE_INITIAL_PENDING: 01873 case STATE_UPDATE_PENDING: 01874 BubbleHelpState = STATE_ACTIVE; 01875 01876 // Create and show a bubble help window 01877 ENSURE(BubbleWnd == NULL, "Bubble window already exists!"); 01878 01879 // Make a new bubble help window 01880 TRY 01881 { 01882 BubbleWnd = new BubbleHelpWnd; 01883 } 01884 CATCH(CMemoryException, e) 01885 { 01886 TRACEALL( _T("Unable to create bubble help window!\n")); 01887 return; 01888 } 01889 END_CATCH 01890 01891 // Create the actual window 01892 if (!BubbleWnd->Create()) 01893 { 01894 TRACEALL( _T("Could not Init bubble help window\n")); 01895 return; 01896 } 01897 01898 // If ad-hoc bubble help, call provider to get required text, otherwise 01899 // get resource IDs out of the OpDescriptor in our table of controls. 01900 if ((AdHocCallback != NULL) && (Window == AdHocWindow)) 01901 { 01902 char *BubbleText = AdHocCallback(AdHocWindow, AdHocControl, AdHocReference); 01903 if (BubbleWnd->SetText(BubbleText)) 01904 BubbleWnd->Show(); 01905 } 01906 else 01907 { 01908 // Find the record for this control. 01909 ControlEntry *pEntry; 01910 pEntry = Controls->FindControl(Window); 01911 01912 ENSURE(pEntry != NULL, "Bad Entry in ActiveHandler"); 01913 01914 // If we have an OpDescriptor, then get the bubble help/module IDs from that, 01915 // otherwise get them directly out of the ControlEntry. 01916 UINT32 BubbleID; 01917 UINT32 ModuleID; 01918 01919 if (pEntry->pOpDesc != NULL) 01920 { 01921 BubbleID = pEntry->pOpDesc->GetBubbleId(); 01922 ModuleID = Tool::GetModuleID(pEntry->pOpDesc->GetToolID()); 01923 } 01924 else 01925 { 01926 BubbleID = pEntry->BubbleID; 01927 ModuleID = pEntry->ModuleID; 01928 } 01929 01930 // Load the bubble help text. 01931 // Ugly hack, but who cares? 01932 String_256 strCaption; 01933 GetWindowText(Window, strCaption, 255); 01934 if (strCaption == String_256("Download")) 01935 { 01936 if (BubbleWnd->SetText("Download this resource")) 01937 // If the string loaded ok, put the window in the correct place and show it. 01938 BubbleWnd->Show(); 01939 } 01940 else 01941 { 01942 if (BubbleWnd->SetText(BubbleID, ModuleID)) 01943 // If the string loaded ok, put the window in the correct place and show it. 01944 BubbleWnd->Show(); 01945 } 01946 } 01947 01948 break; 01949 01950 default: 01951 ENSURE(FALSE, "Wrong state in bubble help"); 01952 break; 01953 } 01954 } 01955 01956 /******************************************************************************************** 01957 01958 > void ControlHelper::InitialPendingHandler() 01959 01960 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01961 Created: 30/06/94 01962 Purpose: Sets the state to STATE_INITIAL_PENDING, which means that the bubble help 01963 window is about to come up, when a timer has elapsed, providing the user 01964 doesn't move the cursor away or press a key etc. 01965 SeeAlso: ControlHelper::DeadHandler; ControlHelper::ActiveHandler; 01966 ControlHelper::InitialDisabledHandler; ControlHelper::DisabledHandler; 01967 ControlHelper::UpdatePendingHandler 01968 01969 ********************************************************************************************/ 01970 01971 void ControlHelper::InitialPendingHandler() 01972 { 01973 #if STATE_TRACE 01974 if (IsUserName("Tim")) 01975 TRACE( _T("STATE_INITIAL_PENDING\n")); 01976 #endif 01977 01978 switch (BubbleHelpState) 01979 { 01980 case STATE_ACTIVE: 01981 // Kill off bubble help (if it exists) and fall through 01982 BubbleHelpKill(); 01983 01984 case STATE_DEAD: 01985 case STATE_INITIAL_DISABLED: 01986 // Sample timer (i.e. reset delay) 01987 PendingTimer.Sample(); 01988 BubbleHelpState = STATE_INITIAL_PENDING; 01989 break; 01990 01991 default: 01992 ENSURE(FALSE, "Wrong state in bubble help"); 01993 break; 01994 } 01995 } 01996 01997 /******************************************************************************************** 01998 01999 > void ControlHelper::InitialDisabledHandler() 02000 02001 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02002 Created: 30/06/94 02003 Purpose: Sets the bubble help state to STATE_INITIAL_DISABLED, which means that the 02004 cursor is over a Camelot bar but not over a control, or that for some 02005 reason (key press, focus change etc) bubble help should not be displayed, 02006 even though the cursor is over a control that supports bubble help. 02007 SeeAlso: ControlHelper::DeadHandler; ControlHelper::ActiveHandler; 02008 ControlHelper::InitialPendingHandler; ControlHelper::DisabledHandler; 02009 ControlHelper::UpdatePendingHandler 02010 02011 ********************************************************************************************/ 02012 02013 void ControlHelper::InitialDisabledHandler() 02014 { 02015 #if STATE_TRACE 02016 if (IsUserName("Tim")) 02017 TRACE( _T("STATE_INITIAL_DISABLED\n")); 02018 #endif 02019 02020 // If a control has focus, then don't change state unless it's in order to die. 02021 if (ControlHasFocus) 02022 { 02023 if (BubbleHelpState != STATE_DEAD) 02024 return; 02025 } 02026 02027 switch (BubbleHelpState) 02028 { 02029 case STATE_DEAD: 02030 case STATE_INITIAL_PENDING: 02031 // Don't do anything. 02032 BubbleHelpState = STATE_INITIAL_DISABLED; 02033 break; 02034 02035 default: 02036 ENSURE(FALSE, "Wrong state in bubble help"); 02037 break; 02038 } 02039 } 02040 02041 /******************************************************************************************** 02042 02043 > void ControlHelper::UpdatePendingHandler() 02044 02045 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02046 Created: 30/06/94 02047 Purpose: Set the bubble help state to STATE_UPDATE_PENDING, which means that the 02048 bubble help will appear very quickly if moved over a control. This is used 02049 when the user moves from a control to another control, so it enables the 02050 user to move along the controls and browse the bubble text for them quite 02051 quickly. 02052 SeeAlso: ControlHelper::DeadHandler; ControlHelper::ActiveHandler; 02053 ControlHelper::InitialPendingHandler; ControlHelper::InitialDisabledHandler; 02054 ControlHelper::DisabledHandler 02055 02056 ********************************************************************************************/ 02057 02058 void ControlHelper::UpdatePendingHandler() 02059 { 02060 #if STATE_TRACE 02061 if (IsUserName("Tim")) 02062 TRACE( _T("STATE_UPDATE_PENDING\n")); 02063 #endif 02064 02065 switch (BubbleHelpState) 02066 { 02067 case STATE_ACTIVE: 02068 // Kill the bubble help window and fall through. 02069 // NB. There may not really be a bubble help window, as we may have come via a 02070 // brief 'dummy' ACTIVE state (i.e. ACTIVE refused to be the current state 02071 // because a mouse button was down or we don't have focus etc). 02072 BubbleHelpKill(); 02073 02074 case STATE_DISABLED: 02075 // Sample the pending timer 02076 PendingTimer.Sample(); 02077 BubbleHelpState = STATE_UPDATE_PENDING; 02078 break; 02079 02080 default: 02081 ENSURE(FALSE, "Wrong state in bubble help"); 02082 break; 02083 } 02084 } 02085 02086 /******************************************************************************************** 02087 02088 > void ControlHelper::DisabledHandler() 02089 02090 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02091 Created: 30/06/94 02092 Purpose: Set the bubble help state to STATE_DISABLED, which means that the 02093 bubble help will appear very quickly if moved over a control. This is used 02094 when the user moves from a control to a Camelot bar, so it enables the 02095 user to move between bars (or even controls which are separated on a bar) 02096 and browse the bubble text for them quite quickly. 02097 SeeAlso: ControlHelper::DeadHandler; ControlHelper::ActiveHandler; 02098 ControlHelper::InitialPendingHandler; ControlHelper::InitialDisabledHandler; 02099 ControlHelper::UpdatePendingHandler 02100 02101 ********************************************************************************************/ 02102 02103 void ControlHelper::DisabledHandler() 02104 { 02105 #if STATE_TRACE 02106 if (IsUserName("Tim")) 02107 TRACE( _T("STATE_DISABLED\n")); 02108 #endif 02109 02110 // If a control has focus, then don't change state unless it's in order to die. 02111 if (ControlHasFocus) 02112 { 02113 if (BubbleHelpState != STATE_DEAD) 02114 return; 02115 } 02116 02117 switch (BubbleHelpState) 02118 { 02119 case STATE_ACTIVE: 02120 // Kill the bubble help window and fall through. 02121 ENSURE(BubbleWnd != NULL, "No bubble help window!"); 02122 BubbleHelpKill(); 02123 02124 case STATE_UPDATE_PENDING: 02125 BubbleHelpState = STATE_DISABLED; 02126 break; 02127 02128 default: 02129 ENSURE(FALSE, "Wrong state in bubble help"); 02130 break; 02131 } 02132 } 02133 02134 /******************************************************************************************** 02135 02136 > void ControlHelper::BubbleHelpDisable() 02137 02138 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02139 Created: 30/06/94 02140 Purpose: Cause the bubble help to go into its 'disabled' state, so that even if it 02141 is over a control that supports bubble help, bubble help will not be 02142 displayed. If bubble help is currently displayed, it is removed. 02143 This function should be called on events that ought to kill off bubble 02144 help, e.g. key presses, focus switches etc. 02145 SeeAlso: ControlHelper::BubbleHelpKill 02146 02147 ********************************************************************************************/ 02148 02149 void ControlHelper::BubbleHelpDisable() 02150 { 02151 // If bubble help is around, disable it. 02152 switch (BubbleHelpState) 02153 { 02154 case STATE_ACTIVE: 02155 case STATE_UPDATE_PENDING: 02156 // Bubble help is on screen or will be RSN so slide into the disabled 02157 // state in order to get rid of/avoid it. 02158 SetState(STATE_DISABLED); 02159 break; 02160 02161 case STATE_INITIAL_PENDING: 02162 // Bubble help will be on screen RSN so slide into the initial disabled 02163 // state in order to get rid of/avoid it. 02164 SetState(STATE_INITIAL_DISABLED); 02165 break; 02166 } 02167 } 02168 02169 /******************************************************************************************** 02170 02171 > void ControlHelper::BubbleHelpKill() 02172 02173 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02174 Created: 30/06/94 02175 Purpose: Low level function to kill off the bubble help window and delete it, and 02176 set various variables for ad-hoc bubble help to sensible 'null' values. 02177 SeeAlso: ControlHelper::BubbleHelpDisable 02178 Scope: Private 02179 02180 ********************************************************************************************/ 02181 02182 void ControlHelper::BubbleHelpKill() 02183 { 02184 // Destroy the bubble help window. 02185 if (BubbleWnd != NULL) 02186 { 02187 BubbleWnd->Hide(); 02188 delete BubbleWnd; 02189 BubbleWnd = NULL; 02190 } 02191 02192 // Disable ad-hoc bubble help. 02193 // NB we don't change the AdHocControl, because then we know that we're over the same 02194 // control and should remain disabled (e.g. if user clicks on button and bubble help 02195 // goes away, it shouldn't come back until they move to another control). 02196 AdHocWindow = NULL; 02197 AdHocCallback = NULL; 02198 AdHocReference = NULL; 02199 } 02200 02201 /******************************************************************************************** 02202 02203 > void ControlHelper::DoBubbleHelpOn(wxWindow* Window, UINT32 NewControl, 02204 BubbleHelpCallback Callback, void *Reference) 02205 02206 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02207 Created: 30/06/94 02208 Inputs: Window - the window to provide bubble help on. 02209 NewControl - pseudo-ID of the imaginary control - this is so the bubble 02210 knows when a different control has been moved onto, and hence 02211 that it should update the bubble help window. 02212 Callback - the callback routine for ad-hoc bubble help - this is called to 02213 get the bubble help text when the bubble window needs to be shown. 02214 Reference - arbritrary data that the Callback may make use of to provide 02215 it with context information for the callback event. 02216 Purpose: Provide bubble-help on an ad-hoc basis, i.e. this allows bubble help to 02217 be provided for GUI elements which are not necessarily 'controls' as such 02218 on a Camelot bar. For example the colour bar uses this to pretend that 02219 each colour swatch is a control, and provides the bubble help to be 02220 shown on it. This function should be called on mouse move messages over 02221 such GUI elements. (It cannot be done automatically by the bubble help 02222 system because we do not subclass such elements - because they're not 02223 really individual windows!). 02224 02225 ********************************************************************************************/ 02226 02227 void ControlHelper::DoBubbleHelpOn(wxWindow* Window, UINT32 NewControl, 02228 BubbleHelpCallback Callback, void *Reference) 02229 { 02230 // Caller is telling us that they have detected a mouse move over one of their 02231 // controls - therefore take a record of their window handle, and fake an event 02232 // to the state machine. 02233 AdHocWindow = Window; 02234 AdHocCallback = Callback; 02235 AdHocReference = Reference; 02236 02237 // Work out if this is a different control we're being told about. 02238 AdHocControlIsDifferent = (AdHocControl != NewControl); 02239 02240 // Remember control ID for next time (we do this before calling BubbleHelpStateMachine() 02241 // because it uses AdHocControl to display the bubble help when it flips into the 02242 // Active state). 02243 AdHocControl = NewControl; 02244 02245 // We give our WndProc to the state machine so that it thinks that NewControl is one of 02246 // our 'proper' controls. 02247 POINT Pos; 02248 ::GetCursorPos(&Pos); 02249 BubbleHelpStateMachine(Pos, Window, ControlHelper::MyWndProc); 02250 } 02251 02252 02253 /******************************************************************************************** 02254 02255 > void ControlHelper::InformModalDialogOpened() 02256 02257 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02258 Created: 30/09/94 02259 Purpose: Informs the ControlHelper class that a modal dialog which is NOT managed 02260 by the kernel Dialog Manager (i.e. NOT a DialogOp) has been opened. 02261 This allows us to disable bubble help whiole modal dialogs are open. 02262 Examples of the use of this are the error box, or use of the Windows 02263 Common Dialog functions. 02264 SeeAlso: ControlHelper::DecModalDialogCount 02265 02266 ********************************************************************************************/ 02267 02268 void ControlHelper::InformModalDialogOpened() 02269 { 02270 ModalDialogs++; 02271 // Record the currently active window 02272 DialogManager::RecordActiveDialogState(); 02273 // This is the ideal place to disable all modeless dialogs 02274 DialogManager::EnableAllDialogs(FALSE); 02275 } 02276 02277 02278 /******************************************************************************************** 02279 02280 > void ControlHelper::InformModalDialogClosed() 02281 02282 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02283 Created: 30/09/94 02284 Purpose: Informs the ControlHelper class that a modal dialog which is NOT managed 02285 by the kernel Dialog Manager (i.e. NOT a DialogOp) has been closed. 02286 This allows us to disable bubble help whiole modal dialogs are open. 02287 Examples of the use of this are the error box, or use of the Windows 02288 Common Dialog functions. 02289 SeeAlso: ControlHelper::IncModalDialogCount 02290 02291 ********************************************************************************************/ 02292 02293 void ControlHelper::InformModalDialogClosed() 02294 { 02295 ModalDialogs--; 02296 02297 // Restore the active window 02298 DialogManager::RestoreActiveDialogState(); 02299 02300 // Sanity check 02301 ENSURE(ModalDialogs >= 0, 02302 "Unbalanced call to ControlHelper::InformModalDialogClosed()!"); 02303 02304 } 02305 02306 02307 /******************************************************************************************** 02308 02309 > BOOL ControlHelper::IsUserInterfaceCaptured() 02310 02311 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02312 Created: 04/01/95 02313 Returns: TRUE => User interface is captured in some way (e.g. a menu is up) 02314 FALSE => User interface is not captured. 02315 Purpose: Determine if the user interface is 'captured' in any way, e.g. if a 02316 bar is being dragged or a menu is up, and so on. This is used to 02317 determine whether or not to do certain background/idle operations, e.g. 02318 background rendering and the like. This does NOT include drag operations 02319 such as any tool drags etc., as this would mean that the push tool would 02320 not work properly etc. 02321 02322 ********************************************************************************************/ 02323 02324 BOOL ControlHelper::IsUserInterfaceCaptured() 02325 { 02326 // Bodge for delta - don't ever disable background rendering. 02327 return FALSE; 02328 02329 if (Operation::GetCurrentDragOp() != NULL) 02330 // Camelot drag in progress - this does not count as capture. 02331 return FALSE; 02332 02333 // Find out the handle of our main window 02334 CWnd *pMainCWnd = AfxGetMainWnd(); 02335 02336 wxWindow* MainwxWindow* = NULL; 02337 02338 if (pMainCWnd != NULL) 02339 MainwxWindow* = pMainCWnd->GetSafewxWindow*(); 02340 02341 // Find out which window, if any, is captured. 02342 wxWindow* CapturedwxWindow* = ::GetCapture(); 02343 02344 // Return TRUE if mouse is captured, and it is not our window. 02345 return ((CapturedwxWindow* != NULL) && (CapturedwxWindow* != MainwxWindow*)); 02346 }