Files
wxWidgets/src/common/artprov.cpp
Stefan Brüns 128e3ff123 Make the wxART_* constants const wxStrings with static storage duration
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.
2020-08-06 12:31:37 +02:00

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