XRC: add GetBitmapBundle function
The function creates wxBitmapBundle from <bitmaps> xrc tag. Co-authored-by: VZ <vz-github@zeitlins.org>
This commit is contained in:
@@ -340,8 +340,9 @@ or translations are done.
|
||||
|
||||
@subsection overview_xrcformat_type_bitmap Bitmap
|
||||
|
||||
Bitmap properties contain specification of a single bitmap or icon. In the most
|
||||
basic form, their text value is simply a relative URL of the bitmap to use.
|
||||
Bitmap properties contain specification of a single bitmap, icon, a set of bitmaps
|
||||
or SVG file. In the most basic form, their text value is simply a relative URL of
|
||||
the bitmap to use.
|
||||
For example:
|
||||
@code
|
||||
<object class="tool" name="wxID_NEW">
|
||||
@@ -363,6 +364,31 @@ percent-encoded, e.g. here is the correct way to specify a bitmap with the path
|
||||
Bitmap file paths can include environment variables that are expanded if
|
||||
wxXRC_USE_ENVVARS was passed to the wxXmlResource constructor.
|
||||
|
||||
It is possible to specify the multi-resolution bitmap by a set of bitmaps or
|
||||
an SVG file, which are mutually exclusive. The set of bitmaps should contain
|
||||
one or more relative URLs of a bitmap, separated by @c ';'.
|
||||
For example, to specify two bitmaps, to be used in standard and 200% DPI
|
||||
scaling respectively, you could write:
|
||||
@code
|
||||
<bitmap>new.png;new_2x.png</bitmap>
|
||||
@endcode
|
||||
|
||||
Here the first bitmap is special, as its size determines the logical size of
|
||||
the bitmap. In other words, this bitmap is the one used when DPI scaling
|
||||
is not in effect. Any subsequent bitmaps can come in any order and will be used
|
||||
when the DPI scaling factor is equal, or at least close, to the ratio of their
|
||||
size to the size of the first bitmap. Using @c _2x naming convention here is common,
|
||||
but @e not required, the names of the bitmaps can be arbitrary, e.g.
|
||||
@code
|
||||
<bitmap>new_32x32.png;new_64x64.png</bitmap>
|
||||
@endcode
|
||||
would work just as well.
|
||||
When using SVG file you must also specify @c default_size attribute
|
||||
(even if the size is specified in SVG file, it may be different from the size needed here):
|
||||
@code
|
||||
<bitmap default_size="32,32">new.svg</bitmap>
|
||||
@endcode
|
||||
|
||||
Alternatively, it is possible to specify the bitmap using wxArtProvider IDs.
|
||||
In this case, the property element has no textual value (filename) and instead
|
||||
has the @c stock_id XML attribute that contains stock art ID as accepted by
|
||||
|
||||
@@ -583,6 +583,11 @@ public:
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize) wxOVERRIDE;
|
||||
|
||||
// Gets a bitmap bundle.
|
||||
wxBitmapBundle GetBitmapBundle(const wxString& param = wxT("bitmap"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize) wxOVERRIDE;
|
||||
|
||||
// Gets an icon.
|
||||
wxIcon GetIcon(const wxString& param = wxT("icon"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
|
||||
@@ -90,6 +90,9 @@ public:
|
||||
virtual wxBitmap GetBitmap(const wxXmlNode* node,
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize) = 0;
|
||||
virtual wxBitmapBundle GetBitmapBundle(const wxString& param = wxT("bitmap"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize) = 0;
|
||||
virtual wxIcon GetIcon(const wxString& param = wxT("icon"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize) = 0;
|
||||
@@ -332,6 +335,12 @@ protected:
|
||||
{
|
||||
return GetImpl()->GetBitmap(node, defaultArtClient, size);
|
||||
}
|
||||
wxBitmapBundle GetBitmapBundle(const wxString& param = wxT("bitmap"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize)
|
||||
{
|
||||
return GetImpl()->GetBitmapBundle(param, defaultArtClient, size);
|
||||
}
|
||||
wxIcon GetIcon(const wxString& param = wxT("icon"),
|
||||
const wxArtClient& defaultArtClient = wxASCII_STR(wxART_OTHER),
|
||||
wxSize size = wxDefaultSize)
|
||||
|
||||
@@ -467,7 +467,8 @@ t_bitmap = t_url?,
|
||||
(
|
||||
attribute stock_id { t_identifier},
|
||||
attribute stock_client { t_identifier}?
|
||||
)?
|
||||
)?,
|
||||
attribute default_size { t_size}?
|
||||
|
||||
t_font = (
|
||||
[xrc:p="o"] element size {_, t_float }* &
|
||||
|
||||
@@ -1852,6 +1852,52 @@ bool GetStockArtAttrs(const wxXmlNode *paramNode,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load a bitmap from a file system element.
|
||||
wxBitmap LoadBitmapFromFS(wxXmlResourceHandlerImpl* impl,
|
||||
const wxString& path,
|
||||
wxSize size,
|
||||
const wxString& nodeName)
|
||||
{
|
||||
if (path.empty()) return wxNullBitmap;
|
||||
#if wxUSE_FILESYSTEM
|
||||
wxFSFile *fsfile = impl->GetCurFileSystem().OpenFile(path, wxFS_READ | wxFS_SEEKABLE);
|
||||
if (fsfile == NULL)
|
||||
{
|
||||
impl->ReportParamError
|
||||
(
|
||||
nodeName,
|
||||
wxString::Format("cannot open bitmap resource \"%s\"", path)
|
||||
);
|
||||
return wxNullBitmap;
|
||||
}
|
||||
wxImage img(*(fsfile->GetStream()));
|
||||
delete fsfile;
|
||||
#else
|
||||
wxImage img(name);
|
||||
#endif
|
||||
|
||||
if (!img.IsOk())
|
||||
{
|
||||
impl->ReportParamError
|
||||
(
|
||||
nodeName,
|
||||
wxString::Format("cannot create bitmap from \"%s\"", path)
|
||||
);
|
||||
return wxNullBitmap;
|
||||
}
|
||||
if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
|
||||
return wxBitmap(img);
|
||||
}
|
||||
|
||||
// forward declaration
|
||||
template <typename T>
|
||||
T
|
||||
ParseStringInPixels(wxXmlResourceHandlerImpl* impl,
|
||||
const wxString& param,
|
||||
const wxString& str,
|
||||
const T& defaultValue,
|
||||
wxWindow *windowToUse = NULL);
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
wxBitmap wxXmlResourceHandlerImpl::GetBitmap(const wxString& param,
|
||||
@@ -1892,36 +1938,126 @@ wxBitmap wxXmlResourceHandlerImpl::GetBitmap(const wxXmlNode* node,
|
||||
}
|
||||
|
||||
/* ...or load the bitmap from file: */
|
||||
wxString name = GetFilePath(node);
|
||||
if (name.empty()) return wxNullBitmap;
|
||||
#if wxUSE_FILESYSTEM
|
||||
wxFSFile *fsfile = GetCurFileSystem().OpenFile(name, wxFS_READ | wxFS_SEEKABLE);
|
||||
if (fsfile == NULL)
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
node->GetName(),
|
||||
wxString::Format("cannot open bitmap resource \"%s\"", name)
|
||||
);
|
||||
return wxNullBitmap;
|
||||
}
|
||||
wxImage img(*(fsfile->GetStream()));
|
||||
delete fsfile;
|
||||
#else
|
||||
wxImage img(name);
|
||||
#endif
|
||||
return LoadBitmapFromFS(this, GetFilePath(node), size, node->GetName());
|
||||
}
|
||||
|
||||
if (!img.IsOk())
|
||||
|
||||
wxBitmapBundle wxXmlResourceHandlerImpl::GetBitmapBundle(const wxString& param,
|
||||
const wxArtClient& defaultArtClient,
|
||||
wxSize size)
|
||||
{
|
||||
wxASSERT_MSG( !param.empty(), "bitmap parameter name can't be empty" );
|
||||
|
||||
const wxXmlNode* const node = GetParamNode(param);
|
||||
|
||||
if ( !node )
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
node->GetName(),
|
||||
wxString::Format("cannot create bitmap from \"%s\"", name)
|
||||
);
|
||||
// this is not an error as bitmap parameter could be optional
|
||||
return wxNullBitmap;
|
||||
}
|
||||
if (!(size == wxDefaultSize)) img.Rescale(size.x, size.y);
|
||||
return wxBitmap(img);
|
||||
|
||||
/* If the bitmap is specified as stock item, query wxArtProvider for it: */
|
||||
wxString art_id, art_client;
|
||||
if ( GetStockArtAttrs(node, defaultArtClient,
|
||||
art_id, art_client) )
|
||||
{
|
||||
wxBitmapBundle stockArt(wxArtProvider::GetBitmapBundle(art_id, art_client, size));
|
||||
if ( stockArt.IsOk() )
|
||||
return stockArt;
|
||||
}
|
||||
|
||||
wxBitmapBundle bitmapBundle;
|
||||
wxString paramValue = GetParamValue(node);
|
||||
if ( paramValue.EndsWith(".svg") )
|
||||
{
|
||||
if ( paramValue.Contains(";") )
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
param,
|
||||
"may contain either one SVG file or a list of files separated by ';'"
|
||||
);
|
||||
return bitmapBundle;
|
||||
}
|
||||
|
||||
// it is a bundle from svg file
|
||||
wxString svgDefaultSizeAttr = node->GetAttribute("default_size", "");
|
||||
if ( svgDefaultSizeAttr.empty() )
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
param,
|
||||
"'default_size' attribute required with svg file"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef wxHAS_SVG
|
||||
wxSize svgDefaultSize = ParseStringInPixels(this, param, svgDefaultSizeAttr, wxDefaultSize);
|
||||
#if wxUSE_FILESYSTEM
|
||||
wxFSFile* fsfile = GetCurFileSystem().OpenFile(paramValue, wxFS_READ | wxFS_SEEKABLE);
|
||||
if (fsfile == NULL)
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
param,
|
||||
wxString::Format("cannot open SVG resource \"%s\"", paramValue)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxInputStream* s = fsfile->GetStream();
|
||||
const size_t len = static_cast<size_t>(s->GetLength());
|
||||
wxCharBuffer buf(len);
|
||||
char* const ptr = buf.data();
|
||||
|
||||
if (s->ReadAll(ptr, len))
|
||||
{
|
||||
bitmapBundle = wxBitmapBundle::FromSVG(ptr, svgDefaultSize);
|
||||
}
|
||||
delete fsfile;
|
||||
}
|
||||
#else
|
||||
bitmapBundle = wxBitmapBundle::FromSVGFile(paramValue, svgDefaultSize);
|
||||
#endif
|
||||
#else // !wxHAS_SVG
|
||||
ReportParamError
|
||||
(
|
||||
param,
|
||||
"SVG bitmaps are not supported in this build of the library"
|
||||
);
|
||||
#endif // wxHAS_SVG/!wxHAS_SVG
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( paramValue.Contains(".svg;") )
|
||||
{
|
||||
ReportParamError
|
||||
(
|
||||
param,
|
||||
"may contain either one SVG file or a list of files separated by ';'"
|
||||
);
|
||||
return bitmapBundle;
|
||||
}
|
||||
|
||||
// it is a bundle from bitmaps
|
||||
wxVector<wxBitmap> bitmaps;
|
||||
wxArrayString paths = wxSplit(paramValue, ';', '\0');
|
||||
for ( wxArrayString::const_iterator i = paths.begin(); i != paths.end(); ++i )
|
||||
{
|
||||
wxBitmap bmpNext = LoadBitmapFromFS(this, *i, size, param);
|
||||
if ( !bmpNext.IsOk() )
|
||||
{
|
||||
// error in loading wxBitmap, return invalid wxBitmapBundle
|
||||
return bitmapBundle;
|
||||
}
|
||||
bitmaps.push_back(bmpNext);
|
||||
}
|
||||
bitmapBundle = wxBitmapBundle::FromBitmaps(bitmaps);
|
||||
}
|
||||
|
||||
return bitmapBundle;
|
||||
}
|
||||
|
||||
|
||||
@@ -2182,17 +2318,17 @@ void XRCConvertFromDLU(wxWindow* w, T& value)
|
||||
value = w->ConvertDialogToPixels(value);
|
||||
}
|
||||
|
||||
// Helper for parsing values (of type T, for which XRCConvertFromAbsValue() and
|
||||
// XRCConvertFromDLU() functions must be defined) which can be expressed either
|
||||
// in pixels or dialog units.
|
||||
// Helper for parsing strings which contain values (of type T, for which
|
||||
// XRCConvertFromAbsValue() and XRCConvertFromDLU() functions must be defined)
|
||||
// which can be expressed either in pixels or dialog units.
|
||||
template <typename T>
|
||||
T
|
||||
ParseValueInPixels(wxXmlResourceHandlerImpl* impl,
|
||||
ParseStringInPixels(wxXmlResourceHandlerImpl* impl,
|
||||
const wxString& param,
|
||||
const wxString& s,
|
||||
const T& defaultValue,
|
||||
wxWindow *windowToUse = NULL)
|
||||
wxWindow *windowToUse)
|
||||
{
|
||||
const wxString s = impl->GetParamValue(param);
|
||||
if ( s.empty() )
|
||||
return defaultValue;
|
||||
|
||||
@@ -2235,6 +2371,17 @@ ParseValueInPixels(wxXmlResourceHandlerImpl* impl,
|
||||
return value;
|
||||
}
|
||||
|
||||
// Helper for parsing values which uses ParseStringInPixels() above.
|
||||
template <typename T>
|
||||
T
|
||||
ParseValueInPixels(wxXmlResourceHandlerImpl* impl,
|
||||
const wxString& param,
|
||||
const T& defaultValue,
|
||||
wxWindow *windowToUse = NULL)
|
||||
{
|
||||
return ParseStringInPixels(impl, param, impl->GetParamValue(param), defaultValue, windowToUse);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
wxSize wxXmlResourceHandlerImpl::GetSize(const wxString& param,
|
||||
|
||||
Reference in New Issue
Block a user