00001 // $Id: cartprov.cpp 1013 2006-05-11 20:24:13Z 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 00100 #include "camtypes.h" 00101 00102 #include "cartprov.h" 00103 #include "camframe.h" 00104 #include "cartctl.h" 00105 00106 CamArtProvider * CamArtProvider::m_ArtProvider = NULL; 00107 00108 /***************************************************************************** 00109 00110 This file contains the class for CamArtProvider, derived from 00111 wxEvtHandler. This contains a mapping allowing dialogs of ANY class 00112 derived from wxDialog to call the relevant bits of DialogManager. 00113 00114 *****************************************************************************/ 00115 00116 IMPLEMENT_CLASS( CamArtProvider, wxEvtHandler ) 00117 BEGIN_EVENT_TABLE(CamArtProvider, wxEvtHandler) 00118 EVT_CAMARTPROVIDER_GETBITMAP (wxID_ANY, CamArtProvider::GetBitmapEvent) 00119 EVT_CAMARTPROVIDER_INVALIDATEART (wxID_ANY, CamArtProvider::InvalidateArtEvent) 00120 END_EVENT_TABLE(); 00121 00122 DEFINE_EVENT_TYPE(wxEVT_CAMARTPROVIDER_GETBITMAP) 00123 DEFINE_EVENT_TYPE(wxEVT_CAMARTPROVIDER_INVALIDATEART) 00124 IMPLEMENT_DYNAMIC_CLASS( wxCamArtProviderEvent, wxEvent ) 00125 00126 /******************************************************************************************** 00127 00128 > CamArtProvider::CamArtProvider() 00129 00130 00131 Author: Alex_Bligh <alex@alex.org.uk> 00132 Created: 30/12/2005 00133 Inputs: - 00134 Outputs: - 00135 Returns: - 00136 Purpose: Constructor 00137 Errors: - 00138 SeeAlso: - 00139 00140 ********************************************************************************************/ 00141 00142 CamArtProvider::CamArtProvider() 00143 { 00144 m_pHash = NULL; 00145 m_GetBitmapEventPending = FALSE; 00146 m_InvalidateArtEventPending = FALSE; 00147 m_pMissingImage = NULL; 00148 00149 m_pMissingImage = new wxImage; // if this returns NULL, all missing bitmaps will be blank. Oh well 00150 if (m_pMissingImage) CamResource::LoadwxImage(*m_pMissingImage, _T("missing.png") ); 00151 if (m_pMissingImage) m_pMissingBitmap=new wxBitmap(*m_pMissingImage, -1); 00152 00153 m_pHash = new ResIDWithFlagsToBitmapPtr; // if this returns NULL, Init will whinge, so don't check 00154 } 00155 00156 /******************************************************************************************** 00157 00158 > CamArtProvider::~CamArtProvider() 00159 00160 00161 Author: Alex_Bligh <alex@alex.org.uk> 00162 Created: 30/12/2005 00163 Inputs: - 00164 Outputs: - 00165 Returns: - 00166 Purpose: Destructor 00167 Errors: - 00168 SeeAlso: - 00169 00170 ********************************************************************************************/ 00171 00172 CamArtProvider::~CamArtProvider() 00173 { 00174 if (m_pHash) 00175 { 00176 DeleteHashContents(); 00177 if (m_pHash) delete m_pHash; 00178 m_pHash = NULL; 00179 } 00180 if (m_pMissingImage) 00181 { 00182 delete(m_pMissingImage); 00183 m_pMissingImage=NULL; 00184 } 00185 if (m_pMissingBitmap) 00186 { 00187 delete(m_pMissingBitmap); 00188 m_pMissingBitmap=NULL; 00189 } 00190 } 00191 00192 /******************************************************************************************** 00193 00194 > static wxColor CamArtProvider::DarkenColour(const wxColor& c, INT32 amount) 00195 00196 00197 Author: Alex_Bligh <alex@alex.org.uk> 00198 Created: 30/12/2005 00199 Inputs: c - a wxColour 00200 amount - amount to darken it by 00201 Outputs: a darkened colour 00202 Returns: - 00203 Purpose: Returns a darkened colour 00204 Errors: - 00205 SeeAlso: - 00206 00207 ********************************************************************************************/ 00208 00209 wxColor CamArtProvider::DarkenColour(const wxColor& c, INT32 amount) 00210 { 00211 INT32 r = c.Red(), g = c.Green(), b = c.Blue(); 00212 return wxColour((r*amount)/100, (g*amount)/100, (b*amount)/100); 00213 } 00214 00215 /******************************************************************************************** 00216 00217 > static wxColor CamArtProvider::LightenColour(const wxColor& c, INT32 amount) 00218 00219 00220 Author: Alex_Bligh <alex@alex.org.uk> 00221 Created: 30/12/2005 00222 Inputs: c - a wxColour 00223 amount - amount to lighten it by 00224 Outputs: a lightened colour 00225 Returns: - 00226 Purpose: Returns a lightened colour 00227 Errors: - 00228 SeeAlso: - 00229 00230 ********************************************************************************************/ 00231 00232 wxColor CamArtProvider::LightenColour(const wxColor& c, INT32 amount) 00233 { 00234 INT32 r = 255-c.Red(), g = 255-c.Green(), b = 255-c.Blue(); 00235 return wxColour(255-(r*amount)/100, 255-(g*amount)/100, 255-(b*amount)/100); 00236 } 00237 00238 /******************************************************************************************** 00239 00240 > static BOOL CamArtProvider::Init() 00241 00242 00243 Author: Alex_Bligh <alex@alex.org.uk> 00244 Created: 30/12/2005 00245 Inputs: None 00246 Outputs: None 00247 Returns: TRUE if succeeded, FALSE if fails 00248 Purpose: Initialize the class 00249 Errors: via wxMessageBox 00250 SeeAlso: - 00251 00252 ********************************************************************************************/ 00253 00254 BOOL CamArtProvider::Init() 00255 { 00256 ERROR3IF(m_ArtProvider, "Double Init of ArtProvider"); 00257 m_ArtProvider=new(CamArtProvider); 00258 ERROR2IF(!m_ArtProvider, FALSE, "Cannot get an ArtProvider"); 00259 00260 return TRUE; 00261 } 00262 00263 /******************************************************************************************** 00264 00265 > static void CamArtProvider::DeInit() 00266 00267 00268 Author: Alex_Bligh <alex@alex.org.uk> 00269 Created: 30/12/2005 00270 Inputs: None 00271 Outputs: None 00272 Returns: TRUE if succeeded, FALSE if fails 00273 Purpose: Initialize resources 00274 Errors: via wxMessageBox 00275 SeeAlso: - 00276 00277 ********************************************************************************************/ 00278 00279 void CamArtProvider::DeInit() 00280 { 00281 if (m_ArtProvider) 00282 { 00283 delete m_ArtProvider; 00284 m_ArtProvider = FALSE; 00285 } 00286 } 00287 00288 /******************************************************************************************** 00289 00290 > void CamArtProvider::DeleteHashContents() 00291 00292 00293 Author: Alex_Bligh <alex@alex.org.uk> 00294 Created: 30/12/2005 00295 Inputs: - 00296 Outputs: - 00297 Returns: - 00298 Purpose: Delete every hash table entry 00299 Errors: - 00300 SeeAlso: - 00301 00302 Note we don't need to delete the bitmaps themselves - CamResource:: does that. 00303 Thus right now this routine does nothing much with the hash contents. 00304 00305 ********************************************************************************************/ 00306 00307 void CamArtProvider::DeleteHashContents() 00308 { 00309 if (m_pHash) 00310 { 00311 ResIDWithFlagsToBitmapPtr::iterator current; 00312 00313 while (!m_pHash->empty()) 00314 { 00315 current = m_pHash->begin(); 00316 // wxImage * s=current->second.m_pImage; 00317 m_pHash->erase(current); 00318 // delete s; -- we don't need to do this, CamResource:: does this 00319 } 00320 // for good measure 00321 m_pHash->clear(); 00322 00323 delete (m_pHash); 00324 m_pHash = NULL; 00325 } 00326 } 00327 00328 /******************************************************************************************** 00329 00330 > void CamArtProvider::ArtLoad(BOOL newbitmaps = FALSE, BOOL defer = TRUE) 00331 00332 00333 Author: Alex_Bligh <alex@alex.org.uk> 00334 Created: 30/12/2005 00335 Inputs: newbitmaps - set TRUE if we should forget cache of all bitmaps that were 00336 missing last time. Also causes existing pending event flag 00337 to be ignored in case an event got lost (should never happen). 00338 defer - set TRUE if the art load is to be deferred 00339 Outputs: - 00340 Returns: - 00341 Purpose: Schedule a GetBitmap event, unless one is already scheduled 00342 Errors: - 00343 SeeAlso: - 00344 00345 ********************************************************************************************/ 00346 00347 void CamArtProvider::ArtLoad(BOOL newbitmaps, BOOL defer) 00348 { 00349 // If we already have an event pending, don't generate a new one 00350 if (m_GetBitmapEventPending && !newbitmaps) return; 00351 00352 if (newbitmaps && m_pMissingImage && m_pHash && !m_pHash->empty()) 00353 { 00354 ResIDWithFlagsToBitmapPtr::iterator current; 00355 00356 for( current = m_pHash->begin(); current != m_pHash->end(); ++current ) 00357 { 00358 // we don't need to worry about memory management as deleting the 00359 // bitmaps are CamResource::'s responsibility 00360 if (current->second.m_pImage == m_pMissingImage) 00361 m_pMissingImage = NULL; // mark as required to be loaded on the event 00362 } 00363 } 00364 00365 // Send ourselves a deferred event 00366 m_GetBitmapEventPending = TRUE; 00367 wxCamArtProviderEvent event (wxEVT_CAMARTPROVIDER_GETBITMAP, 0, defer); 00368 if (defer) 00369 AddPendingEvent(event); 00370 else 00371 ProcessEvent(event); 00372 } 00373 00374 00375 /******************************************************************************************** 00376 00377 > CamArtProvider::GetBitmapEvent(wxCamArtProviderEvent& event) 00378 00379 00380 Author: Alex_Bligh <alex@alex.org.uk> 00381 Created: 30/12/2005 00382 Inputs: event - the wxEvent 00383 Outputs: - 00384 Returns: - 00385 Purpose: Called when we need to load some art 00386 Errors: - 00387 SeeAlso: - 00388 00389 ********************************************************************************************/ 00390 00391 00392 void CamArtProvider::GetBitmapEvent(wxCamArtProviderEvent& event) 00393 { 00394 if (m_pHash && !m_pHash->empty()) 00395 { 00396 BOOL FoundBitmapToLoad = FALSE; 00397 ResIDWithFlagsToBitmapPtr::iterator current; 00398 for( current = m_pHash->begin(); current != m_pHash->end(); ++current ) 00399 { 00400 if (!current->second.m_pImage) // we have no blank bitmap 00401 { 00402 FoundBitmapToLoad = TRUE; 00403 00404 // ResourceID r = GetResourceID(current->first); 00405 // CamArtFlags f = GetFlags(current->first); 00406 // TRACE(_T("Hash for bitmap 0x%x:%d %s"),f,r,CamResource::GetObjectName(r)); 00407 00408 wxImage * pBitmap = MakeBitmap(current->first); 00409 current->second.m_pImage = pBitmap?pBitmap:m_pMissingImage; 00410 } 00411 } 00412 00413 if (FoundBitmapToLoad) 00414 { 00415 if (!m_InvalidateArtEventPending) 00416 { 00417 m_InvalidateArtEventPending = TRUE; 00418 BOOL defer=!event.m_deferred; //Defer the invalidate if this is immediate 00419 wxCamArtProviderEvent event (wxEVT_CAMARTPROVIDER_INVALIDATEART, 0, defer); 00420 if (defer) 00421 AddPendingEvent(event); 00422 else 00423 ProcessEvent(event); 00424 } 00425 } 00426 } 00427 m_GetBitmapEventPending=FALSE; 00428 } 00429 00430 /******************************************************************************************** 00431 00432 > CamArtProvider::GetBitmapEvent(wxCamArtProviderEvent& event) 00433 00434 00435 Author: Alex_Bligh <alex@alex.org.uk> 00436 Created: 30/12/2005 00437 Inputs: event - the wxEvent 00438 Outputs: - 00439 Returns: - 00440 Purpose: Called when we need to load some art 00441 Errors: - 00442 SeeAlso: - 00443 00444 ********************************************************************************************/ 00445 00446 00447 void CamArtProvider::InvalidateArtEvent(wxCamArtProviderEvent& event) 00448 { 00449 m_InvalidateArtEventPending = FALSE; 00450 InvalidateAllArt(); 00451 } 00452 00453 /******************************************************************************************** 00454 00455 > void CamArtProvider::InvalidateAllArt() 00456 00457 00458 Author: Alex_Bligh <alex@alex.org.uk> 00459 Created: 30/12/2005 00460 Inputs: - 00461 Outputs: - 00462 Returns: - 00463 Purpose: Invalidates every window which has art in it 00464 Errors: - 00465 SeeAlso: - 00466 00467 Note this function should do a broadcast to all, which will allow others to invalidate 00468 themselves. 00469 00470 ********************************************************************************************/ 00471 00472 00473 void CamArtProvider::InvalidateAllArt() 00474 { 00475 wxWindow * pWindow = CCamFrame::GetMainFrame(); 00476 if (pWindow) InvalidateAllArtInChildren(pWindow); 00477 00478 // Broadcast an art changing message here! 00479 00480 } 00481 00482 /******************************************************************************************** 00483 00484 > void CamArtProvider::InvalidateAllArtInChildren(wxWindow * pWindow) 00485 00486 00487 Author: Alex_Bligh <alex@alex.org.uk> 00488 Created: 30/12/2005 00489 Inputs: event - the wxEvent 00490 Outputs: - 00491 Returns: - 00492 Purpose: Invalidates every window which has art in it 00493 Errors: - 00494 SeeAlso: - 00495 00496 Note this function should do a broadcast to all, which will allow others to invalidate 00497 themselves. 00498 00499 ********************************************************************************************/ 00500 00501 00502 void CamArtProvider::InvalidateAllArtInChildren(wxWindow * pWindow) 00503 { 00504 // Process this one 00505 if (pWindow->IsKindOf(CLASSINFO(wxCamArtControl))) 00506 ((wxCamArtControl *)pWindow)->NewBitmap(); 00507 00508 // Now process children if any 00509 wxWindowList::Node * pNode = pWindow->GetChildren().GetFirst(); 00510 while (pNode) 00511 { 00512 InvalidateAllArtInChildren(pNode->GetData()); 00513 pNode = pNode->GetNext(); 00514 } 00515 return; 00516 } 00517 00518 /******************************************************************************************** 00519 00520 > void CamArtProvider::EnsureBitmapLoaded(ResourceID Resource, BOOL SkipArtLoad=FALSE) 00521 00522 00523 Author: Alex_Bligh <alex@alex.org.uk> 00524 Created: 30/12/2005 00525 Inputs: Resource - the ResourceID of the art to ensure is loaded 00526 Outputs: - 00527 Returns: - 00528 Purpose: Passes an event to DialogManager::Event 00529 Errors: - 00530 SeeAlso: - 00531 00532 ********************************************************************************************/ 00533 00534 00535 void CamArtProvider::EnsureBitmapLoaded(ResourceID Resource, BOOL SkipArtLoad) 00536 { 00537 UINT32 f; 00538 for (f = 0; f<CAF_CACHE_MAX; f++) 00539 { 00540 FindBitmap(Resource, (CamArtFlags)f, SkipArtLoad); // Find all the variants of the bitmap, thus ensuring a load 00541 } 00542 } 00543 00544 /******************************************************************************************** 00545 00546 > void CamArtProvider::EnsureChildBitmapsLoaded(wxWindow * pWindow = NULL, BOOL SkipArtLoad=FALSE) 00547 00548 00549 Author: Alex_Bligh <alex@alex.org.uk> 00550 Created: 30/12/2005 00551 Inputs: event - the wxEvent 00552 Outputs: - 00553 Returns: - 00554 Purpose: Invalidates every window which has art in it 00555 Errors: - 00556 SeeAlso: - 00557 00558 Note this function should do a broadcast to all, which will allow others to invalidate 00559 themselves. Note that we bunch up all the art loading until the end by ensuring that 00560 internally we call with SkipArtLoad set. 00561 00562 ********************************************************************************************/ 00563 00564 00565 void CamArtProvider::EnsureChildBitmapsLoaded(wxWindow * pWindow, BOOL SkipArtLoad) 00566 { 00567 if (!pWindow) 00568 pWindow = CCamFrame::GetMainFrame(); 00569 00570 if (!pWindow) return; 00571 00572 // Process this one 00573 if ( (pWindow->IsKindOf(CLASSINFO(wxCamArtControl))) && 00574 !(((wxCamArtControl*)pWindow)->GetStyle() & wxCACS_TEXT) ) // don't bother finding bitmaps for text ones, as there isn't one! 00575 EnsureBitmapLoaded((ResourceID)(pWindow->GetId()), TRUE); // always skip the art load 00576 00577 // Now process children if any 00578 wxWindowList::Node * pNode = pWindow->GetChildren().GetFirst(); 00579 while (pNode) 00580 { 00581 EnsureChildBitmapsLoaded(pNode->GetData(), TRUE); // Always skip the art load 00582 pNode = pNode->GetNext(); 00583 } 00584 00585 if (!SkipArtLoad) 00586 ArtLoad(FALSE, FALSE); 00587 00588 return; 00589 } 00590 00591 /******************************************************************************************** 00592 00593 > void CamArtProvider::ReloadAllArt() 00594 00595 00596 Author: Alex_Bligh <alex@alex.org.uk> 00597 Created: 30/12/2005 00598 Inputs: - 00599 Outputs: - 00600 Returns: - 00601 Purpose: Reloads all the art 00602 Errors: - 00603 SeeAlso: - 00604 00605 ********************************************************************************************/ 00606 00607 void CamArtProvider::ReloadAllArt() 00608 { 00609 m_GetBitmapEventPending=FALSE; // to be sure 00610 DeleteHashContents(); 00611 EnsureChildBitmapsLoaded(); 00612 } 00613 00614 /******************************************************************************************** 00615 00616 > ResIDWithFlagsToBitmapPtr::iterator CamArtProvider::Find(ResourceID Resource, CamArtFlags Flags = 0, BOOL SkipArtLoad=FALSE) 00617 00618 00619 Author: Alex_Bligh <alex@alex.org.uk> 00620 Created: 30/12/2005 00621 Inputs: Resource - the resource ID to find 00622 Flags - the flags to find 00623 Outputs: - 00624 Returns: a pointer to the bitmap that has been foudn 00625 Purpose: Finds the cached bitmap with the relevant resource ID & flags 00626 Errors: - 00627 SeeAlso: - 00628 00629 may return NULL if there is no default "missing bitmap" that could be loaded 00630 00631 ********************************************************************************************/ 00632 00633 00634 ResIDWithFlagsToBitmapPtr::iterator CamArtProvider::Find(ResourceID Resource, CamArtFlags Flags, BOOL SkipArtLoad) 00635 { 00636 ResourceIDWithFlags f = CombineFlags(Resource, (CamArtFlags)(Flags & (CAF_CACHE_MAX-1))); 00637 if (!m_pHash) return m_pHash->end(); 00638 00639 // get the bitmap from the hash 00640 ResIDWithFlagsToBitmapPtr::iterator i=m_pHash->find(f); 00641 if (i==m_pHash->end()) 00642 { 00643 // Oh dear, we haven't found an entry. We thus create one and schedule a load 00644 ImageAndBitmap IandB; 00645 (*m_pHash)[f]=IandB; 00646 if (!SkipArtLoad) 00647 ArtLoad(FALSE, FALSE); 00648 // See if it's appeared 00649 i=m_pHash->find(f); 00650 } 00651 00652 return i; 00653 } 00654 00655 /******************************************************************************************** 00656 00657 > wxImage * CamArtProvider::FindImage(ResourceID Resource, CamArtFlags Flags = 0, BOOL SkipArtLoad=FALSE) 00658 00659 00660 Author: Alex_Bligh <alex@alex.org.uk> 00661 Created: 30/12/2005 00662 Inputs: Resource - the resource ID to find 00663 Flags - the flags to find 00664 Outputs: - 00665 Returns: a pointer to the bitmap that has been foudn 00666 Purpose: Finds the cached bitmap with the relevant resource ID & flags 00667 Errors: - 00668 SeeAlso: - 00669 00670 may return NULL if there is no default "missing bitmap" that could be loaded 00671 00672 ********************************************************************************************/ 00673 00674 00675 wxImage * CamArtProvider::FindImage(ResourceID Resource, CamArtFlags Flags, BOOL SkipArtLoad) 00676 { 00677 ResIDWithFlagsToBitmapPtr::iterator i=Find(Resource, Flags, SkipArtLoad); 00678 if (i==m_pHash->end()) 00679 { 00680 return m_pMissingImage; 00681 } 00682 wxImage *pImage = i->second.m_pImage; 00683 00684 return pImage?pImage:m_pMissingImage; 00685 } 00686 00687 /******************************************************************************************** 00688 00689 > wxImage * CamArtProvider::FindBitmap(ResourceID Resource, CamArtFlags Flags = 0, BOOL SkipArtLoad=FALSE) 00690 00691 00692 Author: Alex_Bligh <alex@alex.org.uk> 00693 Created: 30/12/2005 00694 Inputs: Resource - the resource ID to find 00695 Flags - the flags to find 00696 Outputs: - 00697 Returns: a pointer to the bitmap that has been foudn 00698 Purpose: Finds the cached bitmap with the relevant resource ID & flags 00699 Errors: - 00700 SeeAlso: - 00701 00702 may return NULL if there is no default "missing bitmap" that could be loaded 00703 00704 We look for an image, and if there is an attached bitmap, use that, else make one 00705 00706 ********************************************************************************************/ 00707 00708 00709 wxBitmap * CamArtProvider::FindBitmap(ResourceID Resource, CamArtFlags Flags, BOOL SkipArtLoad) 00710 { 00711 ResIDWithFlagsToBitmapPtr::iterator i=Find(Resource, Flags, SkipArtLoad); 00712 if (i==m_pHash->end()) 00713 { 00714 return m_pMissingBitmap; 00715 } 00716 wxBitmap *pBitmap = i->second.m_pBitmap; 00717 if (pBitmap) return pBitmap; 00718 00719 // No bitmap. Do we have an image? 00720 wxImage *pImage = i->second.m_pImage; 00721 00722 if (!pImage || (pImage==m_pMissingImage)) 00723 return m_pMissingBitmap; 00724 00725 // OK make a bitmap 00726 pBitmap = new wxBitmap(*pImage, -1); // for now, always use screen depth, not least as GDK doesn't support anything except this & 1bpp 00727 if (!pBitmap) return m_pMissingBitmap; 00728 00729 i->second.m_pBitmap=pBitmap; 00730 return pBitmap; 00731 } 00732 00733 /******************************************************************************************** 00734 00735 > void CamArtProvider::Draw(wxDC& dc, const wxRect & rect, ResourceID Resource, CamArtFlags Flags = 0, const wxString &text = wxEmptyString) 00736 00737 00738 Author: Alex_Bligh <alex@alex.org.uk> 00739 Created: 30/12/2005 00740 Inputs: dc - the wxDC to draw into 00741 Resource - the ResourceID to load 00742 CamArtFlags - the flags to use for drawing 00743 InternalBorder - the internal border (in pixels) - see note 00744 Outputs: - 00745 Returns: pointer to a string containing the event number 00746 Purpose: Draws the art into the appropriate DC 00747 Errors: - 00748 SeeAlso: - 00749 00750 Note that the internal border is the TOTAL internal border (i.e. left plus right). Border 00751 pixels will be allocated preferentially on left and top, to right and bottom. Rect should 00752 already have been inflated (wxCamArtControl does this by increasing its client area). 00753 00754 ********************************************************************************************/ 00755 00756 void CamArtProvider::Draw(wxDC& dc, const wxRect & rect, ResourceID Resource, CamArtFlags Flags, const wxString &text) 00757 { 00758 dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); 00759 dc.SetPen(*wxTRANSPARENT_PEN); 00760 // dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); 00761 00762 // dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); 00763 dc.SetBrush(*wxTRANSPARENT_BRUSH); // Needed in case we need to paint 3D furniture, but not the button top (ALWAYS3D) 00764 00765 wxRect brect = rect; 00766 00767 UINT32 bitmapoffsetX=0; 00768 UINT32 bitmapoffsetY=0; 00769 00770 if ((Flags & CAF_PUSHBUTTON) && !rect.IsEmpty()) 00771 { 00772 // 3Dness 00773 brect.width-=1; 00774 brect.height-=1; 00775 00776 if (Flags & CAF_SELECTED) 00777 { 00778 // It's pushed in 00779 brect.x++; 00780 brect.y++; 00781 } 00782 00783 UINT32 InternalBorderX = (Flags & CAF_NOINTERNALBORDER)?0:2; 00784 UINT32 InternalBorderY = (Flags & CAF_NOINTERNALBORDER)?0:1; 00785 00786 bitmapoffsetX=1+((InternalBorderX+1)>>1); // this is a completely independent offset to the brect stuff, which gives the bitmap a border 00787 bitmapoffsetY=1+((InternalBorderY+1)>>1); // this is a completely independent offset to the brect stuff, which gives the bitmap a border 00788 00789 // BOOL FaceSelected = ( (Flags & CAF_SELECTED) || (Flags & CAF_BUTTONHOVER) ); 00790 // BOOL Border3D = ( (Flags & CAF_SELECTED) || (Flags & CAF_ALWAYS3D)); 00791 00792 BOOL FaceSelected = ( (Flags & CAF_SELECTED) || ((Flags & CAF_ALWAYS3D) && (Flags & CAF_BUTTONHOVER)) ); // highlight face on hover if always3D 00793 BOOL Border3D = ( (Flags & CAF_SELECTED) || (Flags & CAF_ALWAYS3D) || (Flags & CAF_BUTTONHOVER)); 00794 00795 // Change the brush if the face is selected 00796 if (FaceSelected) 00797 { 00798 if (Flags & CAF_TOOLBACKGROUND) 00799 dc.SetBrush(wxColour(255,255,192)); // A light yellow - we should load this from somewhere else 00800 else 00801 { 00802 if (Flags & CAF_BUTTONHOVER) 00803 dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT)); 00804 else 00805 dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); 00806 } 00807 } 00808 00809 if (Border3D) 00810 { 00811 // draw the light highlights 00812 dc.SetPen(wxSystemSettings::GetColour((Flags & CAF_SELECTED)?wxSYS_COLOUR_3DHIGHLIGHT:wxSYS_COLOUR_3DDKSHADOW)); 00813 // draw the background behind the button undisplaced 00814 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); 00815 // now draw the left & top bits 00816 dc.SetPen(wxSystemSettings::GetColour((Flags & CAF_SELECTED)?wxSYS_COLOUR_3DDKSHADOW:wxSYS_COLOUR_3DHIGHLIGHT)); 00817 dc.DrawLine(rect.x, rect.y, rect.x+rect.width-1, rect.y); 00818 dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height-1); 00819 } 00820 else if (FaceSelected) // if not FaceSelected, we've already drawn it 00821 { 00822 // draw the background behind the button displaced 00823 dc.DrawRectangle(brect.x, brect.y, brect.width, brect.height); 00824 } 00825 } 00826 00827 // Now apply justification to the object 00828 wxRect BestSize(GetSize(Resource, Flags, text)); 00829 if (BestSize.width != rect.width) 00830 { 00831 if (Flags & CAF_RIGHT) 00832 { 00833 bitmapoffsetX += (rect.width-BestSize.width); 00834 } 00835 else if (Flags & CAF_LEFT) 00836 { 00837 // do nothing 00838 } 00839 else 00840 { 00841 bitmapoffsetX += (rect.width-BestSize.width)/2; 00842 } 00843 } 00844 if (BestSize.height != rect.height) 00845 { 00846 if (Flags & CAF_BOTTOM) 00847 { 00848 bitmapoffsetY += (rect.height-BestSize.height); 00849 } 00850 else if (Flags & CAF_TOP) 00851 { 00852 // do nothing 00853 } 00854 else 00855 { 00856 bitmapoffsetY += (rect.height-BestSize.height)/2; 00857 } 00858 } 00859 00860 if (Flags & CAF_TEXT) 00861 { 00862 // The max width is the width of the entire control, less the internal border width 00863 wxCoord MaxWidth = rect.GetWidth() - GetBorderSize(Flags).GetWidth(); 00864 if (MaxWidth<0) 00865 MaxWidth=0; 00866 wxString ctext = GetTextInfoOrDraw(Resource, Flags, dc, TRUE, NULL, NULL, brect.x+bitmapoffsetX, brect.y+bitmapoffsetY, MaxWidth, text); 00867 } 00868 else 00869 { 00870 // Get the bitmap with the correct flags. We here pretend the button is selected if we are 00871 // hovering. We can't do this in the control (grrr...) because else by the time the flags get 00872 // here we cannot distinguish selection from hover, which means we slab wrongly 00873 wxBitmap *pBitmap = FindBitmap(Resource, (CamArtFlags)(Flags|((Flags & CAF_BUTTONHOVER)?CAF_SELECTED:0) )); 00874 00875 // plot the bitmap 00876 if (pBitmap) 00877 dc.DrawBitmap(*pBitmap, brect.x+bitmapoffsetX, brect.y+bitmapoffsetY, TRUE); 00878 } 00879 } 00880 00881 /******************************************************************************************** 00882 00883 > wxSize CamArtProvider::GetSize(ResourceID r, CamArtFlags Flags=CAF_DEFAULT, const wxString &text = wxEmptyString) 00884 00885 00886 Author: Alex_Bligh <alex@alex.org.uk> 00887 Created: 25/01/2005 00888 Inputs: r - the resource 00889 Flags - the flags 00890 Outputs: - 00891 Returns: The size of the control 00892 Purpose: - 00893 Errors: - 00894 SeeAlso: - 00895 00896 Note that the internal border is the TOTAL internal border (i.e. left plus right). Border 00897 pixels will be allocated preferentially on left and top, to right and bottom. Rect should 00898 already have been inflated (wxCamArtControl does this by increasing its client area). 00899 00900 ********************************************************************************************/ 00901 00902 wxSize CamArtProvider::GetSize(ResourceID r, CamArtFlags Flags, const wxString &text) 00903 { 00904 wxCoord w=24; 00905 wxCoord h=24; 00906 00907 if (Flags & CAF_TEXT) 00908 { 00909 wxScreenDC dc; 00910 wxString ctext = GetTextInfoOrDraw(r, Flags, dc, FALSE, &w, &h, 0, 0, -1, text); 00911 } 00912 else 00913 { 00914 wxBitmap * pBitmap=FindBitmap(r, Flags); 00915 if (pBitmap) 00916 { 00917 w=pBitmap->GetWidth(); 00918 h=pBitmap->GetHeight(); 00919 } 00920 } 00921 00922 wxSize Border=GetBorderSize(Flags); 00923 return wxSize(w+Border.GetWidth(), h+Border.GetHeight()); 00924 } 00925 00926 /******************************************************************************************** 00927 00928 > wxSize CamArtProvider::GetBorderSize(CamArtFlags Flags=CAF_DEFAULT) 00929 00930 00931 Author: Alex_Bligh <alex@alex.org.uk> 00932 Created: 25/01/2005 00933 Inputs: Flags - the flags 00934 Outputs: - 00935 Returns: The size of the border around the control 00936 Purpose: - 00937 Errors: - 00938 SeeAlso: - 00939 00940 Note that the internal border is the TOTAL internal border (i.e. left plus right). Border 00941 pixels will be allocated preferentially on left and top, to right and bottom. Rect should 00942 already have been inflated (wxCamArtControl does this by increasing its client area). 00943 00944 ********************************************************************************************/ 00945 00946 wxSize CamArtProvider::GetBorderSize(CamArtFlags Flags /*=CAF_DEFAULT*/) 00947 { 00948 UINT32 InternalBorderX = (Flags & CAF_NOINTERNALBORDER)?0:2; 00949 UINT32 InternalBorderY = (Flags & CAF_NOINTERNALBORDER)?0:1; 00950 // 3 extra pixels for push buttons, 2 border (one on each side) and one for push displacement 00951 UINT32 extraX=InternalBorderX+3*((Flags & CAF_ALWAYS3D) || (Flags & CAF_PUSHBUTTON)); // 3 or 0 00952 UINT32 extraY=InternalBorderY+3*((Flags & CAF_ALWAYS3D) || (Flags & CAF_PUSHBUTTON)); // 3 or 0 00953 return wxSize(extraX, extraY); 00954 } 00955 00956 /******************************************************************************************** 00957 00958 > wxString CamArtProvider::GetTextInfoOrDraw(ResourceID r, wxDC &dc, BOOL Draw=FALSE, wxCoord *w=NULL, wxCoord *h=NULL, 00959 wxCoord x=0, wxCoord y=0, wxCoord MaxWidth=-1, const wxString &text = wxEmptyString) 00960 00961 00962 Author: Alex_Bligh <alex@alex.org.uk> 00963 Created: 24/04/2006 00964 Inputs: r - the resource 00965 Flags - the flags 00966 Draw = TRUE to draw the text 00967 x, y - location to draw the text (if Draw is set) 00968 MaxWidth - the maximum width or the text (use -1 when calculating for no max width) 00969 Outputs: w, h, pointers to fill in (can be NULL) for the text extent. Either both or neither must be NULL 00970 Returns: The text 00971 Purpose: Sets up the DC and returns the text 00972 Errors: - 00973 SeeAlso: - 00974 00975 ********************************************************************************************/ 00976 00977 wxString CamArtProvider::GetTextInfoOrDraw(ResourceID r, CamArtFlags f, wxDC &dc, BOOL Draw/*=FALSE*/, wxCoord *w, wxCoord *h, wxCoord x, wxCoord y, 00978 wxCoord MaxWidth /*= -1*/, const wxString &text) 00979 { 00980 // find the name by looking up the ID as a string 00981 const TCHAR * tcname=text; 00982 00983 if (w) *w=0; 00984 if (h) *h=0; 00985 00986 if (text.IsEmpty()) 00987 { 00988 tcname = CamResource::GetTextFail(r); 00989 if (!tcname || ( (tcname[0]==_T('-')) && !tcname[1]) ) 00990 { 00991 // default to object name 00992 tcname = CamResource::GetObjectNameFail(r); 00993 } 00994 00995 if (!tcname) 00996 { 00997 // If this goes off, then somehow we've been passed a resource ID without a reverse 00998 // bitmap lookup. This can normally only happen if the resource ID is corrupted, or 00999 // the resources are corrupted 01000 ERROR3_PF(("Cannot get text for resource %d",r)); 01001 return wxEmptyString; 01002 } 01003 } 01004 01005 dc.SetTextForeground(wxSystemSettings::GetColour((f & CAF_GREYED)?wxSYS_COLOUR_GRAYTEXT:wxSYS_COLOUR_BTNTEXT)); 01006 wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); 01007 font.SetPointSize((f & CAF_HALFHEIGHT)?7:8); 01008 dc.SetFont(font); 01009 01010 wxString RenderText(tcname); 01011 01012 if (!(f & CAF_STATUSBARTEXT)) 01013 { 01014 if (h && w) 01015 dc.GetTextExtent(RenderText, w, h); 01016 01017 if (Draw) 01018 dc.DrawText(RenderText, x, y); 01019 } 01020 else 01021 { 01022 // It's status bar text. We have to go through the tokens individually 01023 01024 // First tokenize the string 01025 INT32 i=0; 01026 wxArrayString Tokens; 01027 wxArrayString Separators; 01028 wxString SubString=wxEmptyString; 01029 INT32 BoldBreak=-1; 01030 for (i=0; i<(INT32)(RenderText.Length()); i++) 01031 { 01032 wxChar c = RenderText[i]; 01033 if ( (c==_T(';')) || 01034 ((c==_T(':')) && (i<((INT32)RenderText.Length())-1) && (RenderText[i+1]==_T(':')) ) 01035 ) 01036 { 01037 // We found a separator 01038 Tokens.Add(SubString); 01039 Separators.Add(wxString(c)); 01040 01041 // Was it a colon separator? 01042 if (c==_T(':')) 01043 { 01044 // Remember it's now bold up to here 01045 BoldBreak=Tokens.GetCount(); 01046 // Skip over the second colon 01047 i++; 01048 } 01049 01050 SubString=wxEmptyString; 01051 } 01052 else 01053 SubString+=c; // It's not a separator, add it to the substring 01054 } 01055 01056 // add the final token 01057 if (!SubString.IsEmpty()) 01058 { 01059 Tokens.Add(SubString); 01060 Separators.Add(wxEmptyString); 01061 } 01062 01063 BOOL Stop = FALSE; 01064 wxCoord CumWidth = 0; // The cumulative width used so far 01065 wxCoord MaxHeight = 0; // The max height used so far 01066 wxFont BoldFont = font; 01067 BoldFont.SetWeight(wxFONTWEIGHT_BOLD); 01068 01069 for (i=0; i<(INT32)(Tokens.GetCount()) && !Stop; i++) 01070 { 01071 wxString TextBlob = Tokens[i] + Separators[i]; 01072 01073 // Set the font up 01074 if (i<BoldBreak) 01075 dc.SetFont(BoldFont); 01076 else 01077 dc.SetFont(font); 01078 01079 // Find out how large this blob is 01080 wxCoord ww=0; 01081 wxCoord hh=0; 01082 dc.GetTextExtent(TextBlob, &ww, &hh); 01083 01084 // Does it fit (or do we force it to fit because it is the first text) 01085 if ((MaxWidth<0) || (i==0) || (CumWidth+ww<=MaxWidth)) 01086 { 01087 // Draw it if necessary 01088 if (Draw) 01089 dc.DrawText(TextBlob, x+CumWidth, y); 01090 01091 // Account for its width 01092 CumWidth+=ww; 01093 if (hh>MaxHeight) 01094 MaxHeight=hh; 01095 } 01096 else 01097 Stop=TRUE; 01098 } 01099 if (h) 01100 *h = MaxHeight; 01101 if (w) 01102 *w = CumWidth; 01103 } 01104 01105 return RenderText; 01106 } 01107 01108 /******************************************************************************************** 01109 01110 > wxImage * CamArtProvider::MakeBitmap(ResourceIDWithFlags ResWithFlags, BOOL Grey=FALSE) 01111 01112 01113 Author: Alex_Bligh <alex@alex.org.uk> 01114 Created: 30/12/2005 01115 Inputs: ResWithFlags - the hash key to make a bitmap for (ResourceID combined with flags) 01116 Grey - true if we should grey (in software) the image we find. Don't set this 01117 when calling, set CAF_GREYED which will use a greyed preprepared version 01118 if available 01119 Outputs: - 01120 Returns: a pointer to the bitmap, or NULL if one could not be made 01121 Purpose: Makes a bitmap from the appropraite resource 01122 Errors: - 01123 SeeAlso: - 01124 01125 This routine is abstracted to allow an easy switch to vector art. Simlarly, it is only 01126 called from the main event loop, so we are safe to muck arround with the current document 01127 etc. so we can do a true render. 01128 01129 ********************************************************************************************/ 01130 01131 wxImage * CamArtProvider::MakeBitmap(ResourceIDWithFlags ResWithFlags) 01132 { 01133 ResourceID r = GetResourceID(ResWithFlags); 01134 CamArtFlags f = GetFlags(ResWithFlags); 01135 wxImage * pBitmap = NULL; 01136 01137 // find the name by looking up the ID as a string 01138 const TCHAR * tcname = NULL; /*CamResource::GetTextFail(r);*/ 01139 if (!tcname || ( (tcname[0]==_T('-')) && !tcname[1]) ) 01140 { 01141 // default to object name 01142 tcname = CamResource::GetObjectNameFail(r); 01143 } 01144 01145 if (!tcname) 01146 { 01147 // If this goes off, then somehow we've been passed a resource ID without a reverse 01148 // bitmap lookup. This can normally only happen if the resource ID is corrupted, or 01149 // the resources are corrupted 01150 ERROR3_PF(("Cannot get bitmap name for resource %d",r)); 01151 delete pBitmap; 01152 return FALSE; 01153 } 01154 01155 wxString basename(tcname); 01156 wxString resname; 01157 01158 // Iterate over all extensions 01159 INT32 ext; 01160 for (ext=0; ext<(INT32)(CamResource::BitmapExtensions.GetCount()); ext++) 01161 { 01162 resname=CamResource::MakeBitmapString(basename, MakeBitmapFlagString(f), CamResource::BitmapExtensions[ext]); 01163 01164 pBitmap=CamResource::GetCachedBitmap(resname.c_str()); 01165 if (pBitmap) return pBitmap; 01166 01167 // OK, it didn't work. Try deleting the flags in order and seeing whether 01168 // that works. Note each of these will itself try deleting flags. Thus recursively 01169 // we work our way down to the base bitmap. 01170 01171 #ifdef _DEBUG 01172 static INT32 recursion=0; 01173 recursion++; 01174 ERROR3IF(recursion>16,"Too much recursion in CamArtProvider::MakeBitmap"); 01175 #endif 01176 if (!pBitmap && (f & CAF_SELECTED)) pBitmap=MakeBitmap(CombineFlags(r, (CamArtFlags)(f & ~CAF_SELECTED))); 01177 if (!pBitmap && (f & CAF_FOCUS)) pBitmap=MakeBitmap(CombineFlags(r, (CamArtFlags)(f & ~CAF_FOCUS))); 01178 if (!pBitmap && (f & CAF_SMALL)) pBitmap=MakeBitmap(CombineFlags(r, (CamArtFlags)(f & ~CAF_SMALL))); 01179 if (!pBitmap && (f & CAF_GREYED)) pBitmap=MakeBitmap(CombineFlags(r, (CamArtFlags)(f & ~CAF_GREYED))); 01180 #if _DEBUG 01181 recursion--; 01182 #endif 01183 if (pBitmap) return pBitmap; 01184 } 01185 01186 return NULL; 01187 } 01188 01189 /******************************************************************************************** 01190 01191 > static CamArtFlags CamArtProvider::GetBitmapFlags(const wxString &str); 01192 01193 01194 Author: Alex_Bligh <alex@alex.org.uk> 01195 Created: 24/01/2005 01196 Inputs: str - sting to look at 01197 Outputs: None 01198 Returns: Flags associated with a bitmap string 01199 Purpose: 01200 Errors: - 01201 SeeAlso: - 01202 01203 ********************************************************************************************/ 01204 01205 CamArtFlags CamArtProvider::GetBitmapFlags(const wxString &str) 01206 { 01207 wxString ext=CamResource::GetBitmapFlagString(str); 01208 return (CamArtFlags)( 01209 ((ext.Find('s')>=0)?CAF_SMALL:0) | 01210 ((ext.Find('f')>=0)?CAF_FOCUS:0) | 01211 ((ext.Find('x')>=0)?CAF_SELECTED:0) | 01212 ((ext.Find('g')>=0)?CAF_GREYED:0) | 01213 0); 01214 } 01215 01216 /******************************************************************************************** 01217 01218 > static CamArtFlags CamArtProvider::MakeBitmapFlagString(const CamArtFlags flags) 01219 01220 01221 Author: Alex_Bligh <alex@alex.org.uk> 01222 Created: 24/01/2005 01223 Inputs: flags - the flags to look at 01224 Outputs: None 01225 Returns: Flags string associated with a bitmap 01226 Purpose: 01227 Errors: - 01228 SeeAlso: - 01229 01230 ********************************************************************************************/ 01231 01232 wxString CamArtProvider::MakeBitmapFlagString(const CamArtFlags flags) 01233 { 01234 wxString mod; 01235 01236 if (flags & CAF_SMALL) mod+=_T("s"); 01237 if (flags & CAF_FOCUS) mod+=_T("f"); 01238 if (flags & CAF_SELECTED) mod+=_T("x"); 01239 if (flags & CAF_GREYED) mod+=_T("g"); 01240 return mod; 01241 } 01242