The pre-3.1.4 definitions of the constants were just string literals, while the type were wxString typedefs. To avoid implicit conversion these were converted to actual wxStrings. While the interface now matched the implementation, this has several drawbacks: - every use of the "constant" now is a string construction at runtime - the constant now is an rvalue, i.e. it is impossible to take its address. The latter breaks its use from wxPython. The IDs are moved to a separate file which can be included multiple times, once from the header to have the declarations in place, and once to instantiate the wxStrings. Using a common file avoids the declaration and definition going out of sync.
465 lines
13 KiB
C++
465 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/common/artprov.cpp
|
|
// Purpose: wxArtProvider class
|
|
// Author: Vaclav Slavik
|
|
// Modified by:
|
|
// Created: 18/03/2002
|
|
// Copyright: (c) Vaclav Slavik
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// headers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#if defined(__BORLANDC__)
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "wx/artprov.h"
|
|
|
|
#define wxART_MAKE_CLIENT_ID(id) \
|
|
extern WXDLLIMPEXP_DATA_CORE(const wxArtClient) id = wxASCII_STR(#id "_C");
|
|
#define wxART_MAKE_ART_ID(id) \
|
|
extern WXDLLIMPEXP_DATA_CORE(const wxArtID) id = wxASCII_STR(#id);
|
|
#include "wx/artids.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/list.h"
|
|
#include "wx/log.h"
|
|
#include "wx/hashmap.h"
|
|
#include "wx/image.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
// ===========================================================================
|
|
// implementation
|
|
// ===========================================================================
|
|
|
|
#include "wx/listimpl.cpp"
|
|
WX_DECLARE_LIST(wxArtProvider, wxArtProvidersList);
|
|
WX_DEFINE_LIST(wxArtProvidersList)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Cache class - stores already requested bitmaps
|
|
// ----------------------------------------------------------------------------
|
|
|
|
WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxBitmap, wxArtProviderBitmapsHash);
|
|
WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxIconBundle, wxArtProviderIconBundlesHash);
|
|
|
|
class WXDLLEXPORT wxArtProviderCache
|
|
{
|
|
public:
|
|
bool GetBitmap(const wxString& full_id, wxBitmap* bmp);
|
|
void PutBitmap(const wxString& full_id, const wxBitmap& bmp)
|
|
{ m_bitmapsHash[full_id] = bmp; }
|
|
|
|
bool GetIconBundle(const wxString& full_id, wxIconBundle* bmp);
|
|
void PutIconBundle(const wxString& full_id, const wxIconBundle& iconbundle)
|
|
{ m_iconBundlesHash[full_id] = iconbundle; }
|
|
|
|
void Clear();
|
|
|
|
static wxString ConstructHashID(const wxArtID& id,
|
|
const wxArtClient& client,
|
|
const wxSize& size);
|
|
|
|
static wxString ConstructHashID(const wxArtID& id,
|
|
const wxArtClient& client);
|
|
|
|
private:
|
|
wxArtProviderBitmapsHash m_bitmapsHash; // cache of wxBitmaps
|
|
wxArtProviderIconBundlesHash m_iconBundlesHash; // cache of wxIconBundles
|
|
};
|
|
|
|
bool wxArtProviderCache::GetBitmap(const wxString& full_id, wxBitmap* bmp)
|
|
{
|
|
wxArtProviderBitmapsHash::iterator entry = m_bitmapsHash.find(full_id);
|
|
if ( entry == m_bitmapsHash.end() )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
*bmp = entry->second;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool wxArtProviderCache::GetIconBundle(const wxString& full_id, wxIconBundle* bmp)
|
|
{
|
|
wxArtProviderIconBundlesHash::iterator entry = m_iconBundlesHash.find(full_id);
|
|
if ( entry == m_iconBundlesHash.end() )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
*bmp = entry->second;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void wxArtProviderCache::Clear()
|
|
{
|
|
m_bitmapsHash.clear();
|
|
m_iconBundlesHash.clear();
|
|
}
|
|
|
|
/* static */ wxString
|
|
wxArtProviderCache::ConstructHashID(const wxArtID& id,
|
|
const wxArtClient& client)
|
|
{
|
|
return id + wxT('-') + client;
|
|
}
|
|
|
|
|
|
/* static */ wxString
|
|
wxArtProviderCache::ConstructHashID(const wxArtID& id,
|
|
const wxArtClient& client,
|
|
const wxSize& size)
|
|
{
|
|
return ConstructHashID(id, client) + wxT('-') +
|
|
wxString::Format(wxT("%d-%d"), size.x, size.y);
|
|
}
|
|
|
|
// ============================================================================
|
|
// wxArtProvider class
|
|
// ============================================================================
|
|
|
|
wxIMPLEMENT_ABSTRACT_CLASS(wxArtProvider, wxObject);
|
|
|
|
wxArtProvidersList *wxArtProvider::sm_providers = NULL;
|
|
wxArtProviderCache *wxArtProvider::sm_cache = NULL;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxArtProvider ctors/dtor
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxArtProvider::~wxArtProvider()
|
|
{
|
|
Remove(this);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxArtProvider operations on provider stack
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*static*/ void wxArtProvider::CommonAddingProvider()
|
|
{
|
|
if ( !sm_providers )
|
|
{
|
|
sm_providers = new wxArtProvidersList;
|
|
sm_cache = new wxArtProviderCache;
|
|
}
|
|
|
|
sm_cache->Clear();
|
|
}
|
|
|
|
/*static*/ void wxArtProvider::Push(wxArtProvider *provider)
|
|
{
|
|
CommonAddingProvider();
|
|
sm_providers->Insert(provider);
|
|
}
|
|
|
|
/*static*/ void wxArtProvider::PushBack(wxArtProvider *provider)
|
|
{
|
|
CommonAddingProvider();
|
|
sm_providers->Append(provider);
|
|
}
|
|
|
|
/*static*/ bool wxArtProvider::Pop()
|
|
{
|
|
wxCHECK_MSG( sm_providers, false, wxT("no wxArtProvider exists") );
|
|
wxCHECK_MSG( !sm_providers->empty(), false, wxT("wxArtProviders stack is empty") );
|
|
|
|
delete sm_providers->GetFirst()->GetData();
|
|
sm_cache->Clear();
|
|
return true;
|
|
}
|
|
|
|
/*static*/ bool wxArtProvider::Remove(wxArtProvider *provider)
|
|
{
|
|
wxCHECK_MSG( sm_providers, false, wxT("no wxArtProvider exists") );
|
|
|
|
if ( sm_providers->DeleteObject(provider) )
|
|
{
|
|
sm_cache->Clear();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*static*/ bool wxArtProvider::Delete(wxArtProvider *provider)
|
|
{
|
|
// provider will remove itself from the stack in its dtor
|
|
delete provider;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*static*/ void wxArtProvider::CleanUpProviders()
|
|
{
|
|
if ( sm_providers )
|
|
{
|
|
while ( !sm_providers->empty() )
|
|
delete *sm_providers->begin();
|
|
|
|
wxDELETE(sm_providers);
|
|
wxDELETE(sm_cache);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxArtProvider: retrieving bitmaps/icons
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxArtProvider::RescaleBitmap(wxBitmap& bmp, const wxSize& sizeNeeded)
|
|
{
|
|
wxCHECK_RET( sizeNeeded.IsFullySpecified(), wxS("New size must be given") );
|
|
|
|
#if wxUSE_IMAGE
|
|
wxImage img = bmp.ConvertToImage();
|
|
img.Rescale(sizeNeeded.x, sizeNeeded.y);
|
|
bmp = wxBitmap(img);
|
|
#else // !wxUSE_IMAGE
|
|
// Fallback method of scaling the bitmap
|
|
wxBitmap newBmp(sizeNeeded, bmp.GetDepth());
|
|
#if defined(__WXMSW__) || defined(__WXOSX__)
|
|
// wxBitmap::UseAlpha() is used only on wxMSW and wxOSX.
|
|
newBmp.UseAlpha(bmp.HasAlpha());
|
|
#endif // __WXMSW__ || __WXOSX__
|
|
{
|
|
wxMemoryDC dc(newBmp);
|
|
double scX = (double)sizeNeeded.GetWidth() / bmp.GetWidth();
|
|
double scY = (double)sizeNeeded.GetHeight() / bmp.GetHeight();
|
|
dc.SetUserScale(scX, scY);
|
|
dc.DrawBitmap(bmp, 0, 0);
|
|
}
|
|
bmp = newBmp;
|
|
#endif // wxUSE_IMAGE/!wxUSE_IMAGE
|
|
}
|
|
|
|
/*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id,
|
|
const wxArtClient& client,
|
|
const wxSize& size)
|
|
{
|
|
// safety-check against writing client,id,size instead of id,client,size:
|
|
wxASSERT_MSG( client.Last() == wxT('C'), wxT("invalid 'client' parameter") );
|
|
|
|
wxCHECK_MSG( sm_providers, wxNullBitmap, wxT("no wxArtProvider exists") );
|
|
|
|
wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size);
|
|
|
|
wxBitmap bmp;
|
|
if ( !sm_cache->GetBitmap(hashId, &bmp) )
|
|
{
|
|
for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
|
|
node; node = node->GetNext())
|
|
{
|
|
bmp = node->GetData()->CreateBitmap(id, client, size);
|
|
if ( bmp.IsOk() )
|
|
break;
|
|
}
|
|
|
|
wxSize sizeNeeded = size;
|
|
if ( !bmp.IsOk() )
|
|
{
|
|
// no bitmap created -- as a fallback, try if we can find desired
|
|
// icon in a bundle
|
|
wxIconBundle iconBundle = DoGetIconBundle(id, client);
|
|
if ( iconBundle.IsOk() )
|
|
{
|
|
if ( sizeNeeded == wxDefaultSize )
|
|
sizeNeeded = GetNativeSizeHint(client);
|
|
|
|
wxIcon icon(iconBundle.GetIcon(sizeNeeded));
|
|
if ( icon.IsOk() )
|
|
{
|
|
// this icon may be not of the correct size, it will be
|
|
// rescaled below in such case
|
|
bmp.CopyFromIcon(icon);
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we didn't get the correct size, resize the bitmap
|
|
if ( bmp.IsOk() && sizeNeeded != wxDefaultSize )
|
|
{
|
|
if ( bmp.GetSize() != sizeNeeded )
|
|
{
|
|
RescaleBitmap(bmp, sizeNeeded);
|
|
}
|
|
}
|
|
|
|
sm_cache->PutBitmap(hashId, bmp);
|
|
}
|
|
|
|
return bmp;
|
|
}
|
|
|
|
/*static*/
|
|
wxIconBundle wxArtProvider::GetIconBundle(const wxArtID& id, const wxArtClient& client)
|
|
{
|
|
wxIconBundle iconbundle(DoGetIconBundle(id, client));
|
|
|
|
if ( iconbundle.IsOk() )
|
|
{
|
|
return iconbundle;
|
|
}
|
|
else
|
|
{
|
|
// fall back to single-icon bundle
|
|
return wxIconBundle(GetIcon(id, client));
|
|
}
|
|
}
|
|
|
|
/*static*/
|
|
wxIconBundle wxArtProvider::DoGetIconBundle(const wxArtID& id, const wxArtClient& client)
|
|
{
|
|
// safety-check against writing client,id,size instead of id,client,size:
|
|
wxASSERT_MSG( client.Last() == wxT('C'), wxT("invalid 'client' parameter") );
|
|
|
|
wxCHECK_MSG( sm_providers, wxNullIconBundle, wxT("no wxArtProvider exists") );
|
|
|
|
wxString hashId = wxArtProviderCache::ConstructHashID(id, client);
|
|
|
|
wxIconBundle iconbundle;
|
|
if ( !sm_cache->GetIconBundle(hashId, &iconbundle) )
|
|
{
|
|
for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
|
|
node; node = node->GetNext())
|
|
{
|
|
iconbundle = node->GetData()->CreateIconBundle(id, client);
|
|
if ( iconbundle.IsOk() )
|
|
break;
|
|
}
|
|
|
|
sm_cache->PutIconBundle(hashId, iconbundle);
|
|
}
|
|
|
|
return iconbundle;
|
|
}
|
|
|
|
/*static*/ wxIcon wxArtProvider::GetIcon(const wxArtID& id,
|
|
const wxArtClient& client,
|
|
const wxSize& size)
|
|
{
|
|
wxBitmap bmp = GetBitmap(id, client, size);
|
|
|
|
if ( !bmp.IsOk() )
|
|
return wxNullIcon;
|
|
|
|
wxIcon icon;
|
|
icon.CopyFromBitmap(bmp);
|
|
return icon;
|
|
}
|
|
|
|
/* static */
|
|
wxArtID wxArtProvider::GetMessageBoxIconId(int flags)
|
|
{
|
|
switch ( flags & wxICON_MASK )
|
|
{
|
|
default:
|
|
wxFAIL_MSG(wxT("incorrect message box icon flags"));
|
|
wxFALLTHROUGH;
|
|
|
|
case wxICON_ERROR:
|
|
return wxART_ERROR;
|
|
|
|
case wxICON_INFORMATION:
|
|
return wxART_INFORMATION;
|
|
|
|
case wxICON_WARNING:
|
|
return wxART_WARNING;
|
|
|
|
case wxICON_QUESTION:
|
|
return wxART_QUESTION;
|
|
}
|
|
}
|
|
|
|
/*static*/ wxSize wxArtProvider::GetSizeHint(const wxArtClient& client,
|
|
bool platform_dependent)
|
|
{
|
|
if (!platform_dependent)
|
|
{
|
|
wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst();
|
|
if (node)
|
|
return node->GetData()->DoGetSizeHint(client);
|
|
}
|
|
|
|
return GetNativeSizeHint(client);
|
|
}
|
|
|
|
#ifndef wxHAS_NATIVE_ART_PROVIDER_IMPL
|
|
/*static*/
|
|
wxSize wxArtProvider::GetNativeSizeHint(const wxArtClient& WXUNUSED(client))
|
|
{
|
|
// rather than returning some arbitrary value that doesn't make much
|
|
// sense (as 2.8 used to do), tell the caller that we don't have a clue:
|
|
return wxDefaultSize;
|
|
}
|
|
|
|
/*static*/
|
|
void wxArtProvider::InitNativeProvider()
|
|
{
|
|
}
|
|
#endif // !wxHAS_NATIVE_ART_PROVIDER_IMPL
|
|
|
|
|
|
/* static */
|
|
bool wxArtProvider::HasNativeProvider()
|
|
{
|
|
#ifdef __WXGTK20__
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// deprecated wxArtProvider methods
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if WXWIN_COMPATIBILITY_2_8
|
|
/* static */ void wxArtProvider::Insert(wxArtProvider *provider)
|
|
{
|
|
PushBack(provider);
|
|
}
|
|
#endif // WXWIN_COMPATIBILITY_2_8
|
|
|
|
// ============================================================================
|
|
// wxArtProviderModule
|
|
// ============================================================================
|
|
|
|
class wxArtProviderModule: public wxModule
|
|
{
|
|
public:
|
|
bool OnInit() wxOVERRIDE
|
|
{
|
|
// The order here is such that the native provider will be used first
|
|
// and the standard one last as all these default providers add
|
|
// themselves to the bottom of the stack.
|
|
wxArtProvider::InitNativeProvider();
|
|
#if wxUSE_ARTPROVIDER_TANGO
|
|
wxArtProvider::InitTangoProvider();
|
|
#endif // wxUSE_ARTPROVIDER_TANGO
|
|
#if wxUSE_ARTPROVIDER_STD
|
|
wxArtProvider::InitStdProvider();
|
|
#endif // wxUSE_ARTPROVIDER_STD
|
|
return true;
|
|
}
|
|
void OnExit() wxOVERRIDE
|
|
{
|
|
wxArtProvider::CleanUpProviders();
|
|
}
|
|
|
|
wxDECLARE_DYNAMIC_CLASS(wxArtProviderModule);
|
|
};
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(wxArtProviderModule, wxModule);
|