mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-13 05:57:00 -04:00
Conversion to new ScriptableImage complete, this affected quite a bit, including the evil thumbnail thread;
Added StyleListener, so style changes are only propagated to interested viewers. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@329 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -17,6 +17,8 @@
|
|||||||
#include <data/field/information.hpp>
|
#include <data/field/information.hpp>
|
||||||
#include <util/error.hpp>
|
#include <util/error.hpp>
|
||||||
|
|
||||||
|
DECLARE_TYPEOF_COLLECTION(StyleListener*);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Field
|
// ----------------------------------------------------------------------------- : Field
|
||||||
|
|
||||||
Field::Field()
|
Field::Field()
|
||||||
@@ -120,6 +122,35 @@ void Style::initDependencies(Context& ctx, const Dependency& dep) const {
|
|||||||
// visible.initDependencies(ctx,dep);
|
// visible.initDependencies(ctx,dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : StyleListener
|
||||||
|
|
||||||
|
void Style::addListener(StyleListener* listener) {
|
||||||
|
listeners.push_back(listener);
|
||||||
|
}
|
||||||
|
void Style::removeListener(StyleListener* listener) {
|
||||||
|
listeners.erase(
|
||||||
|
std::remove(
|
||||||
|
listeners.begin(),
|
||||||
|
listeners.end(),
|
||||||
|
listener
|
||||||
|
),
|
||||||
|
listeners.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void Style::tellListeners() {
|
||||||
|
FOR_EACH(l, listeners) l->onStyleChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
StyleListener::StyleListener(const StyleP& style)
|
||||||
|
: styleP(style)
|
||||||
|
{
|
||||||
|
style->addListener(this);
|
||||||
|
}
|
||||||
|
StyleListener::~StyleListener() {
|
||||||
|
styleP->removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Value
|
// ----------------------------------------------------------------------------- : Value
|
||||||
|
|
||||||
Value::~Value() {}
|
Value::~Value() {}
|
||||||
|
|||||||
+27
-2
@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(Value);
|
|||||||
class Context;
|
class Context;
|
||||||
class Dependency;
|
class Dependency;
|
||||||
class Action;
|
class Action;
|
||||||
|
class StyleListener;
|
||||||
|
|
||||||
// for DataViewer/editor
|
// for DataViewer/editor
|
||||||
class DataViewer; class DataEditor;
|
class DataViewer; class DataEditor;
|
||||||
@@ -103,16 +104,26 @@ class Style {
|
|||||||
/** thisP is a smart pointer to this */
|
/** thisP is a smart pointer to this */
|
||||||
virtual ValueViewerP makeEditor(DataEditor& parent, const StyleP& thisP) = 0;
|
virtual ValueViewerP makeEditor(DataEditor& parent, const StyleP& thisP) = 0;
|
||||||
|
|
||||||
/// Update scripted values of this style, return true if anything has changed
|
/// Update scripted values of this style, return true if anything has changed.
|
||||||
|
/** The caller should tellListeners() */
|
||||||
virtual bool update(Context&);
|
virtual bool update(Context&);
|
||||||
/// Add the given dependency to the dependent_scripts list for the variables this style depends on
|
/// Add the given dependency to the dependent_scripts list for the variables this style depends on
|
||||||
/** Only use for things that need invalidate() */
|
/** Only use for things that need invalidate() */
|
||||||
virtual void initDependencies(Context&, const Dependency&) const;
|
virtual void initDependencies(Context&, const Dependency&) const;
|
||||||
/// Invalidate scripted images for this style
|
/// Invalidate scripted images for this style
|
||||||
virtual void invalidate() {}
|
virtual void invalidate(Context&) {}
|
||||||
|
|
||||||
|
/// Add a StyleListener
|
||||||
|
void addListener(StyleListener*);
|
||||||
|
/// Remove a StyleListener
|
||||||
|
void removeListener(StyleListener*);
|
||||||
|
/// Tell the StyleListeners that this style has changed
|
||||||
|
void tellListeners();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_REFLECTION_VIRTUAL();
|
DECLARE_REFLECTION_VIRTUAL();
|
||||||
|
/// Things that are listening to changes in this style
|
||||||
|
vector<StyleListener*> listeners;
|
||||||
};
|
};
|
||||||
|
|
||||||
void init_object(const FieldP&, StyleP&);
|
void init_object(const FieldP&, StyleP&);
|
||||||
@@ -120,6 +131,20 @@ inline const FieldP& get_key (const StyleP& s) { return s->fieldP; }
|
|||||||
inline const String& get_key_name(const StyleP& s) { return s->fieldP->name; }
|
inline const String& get_key_name(const StyleP& s) { return s->fieldP->name; }
|
||||||
template <> StyleP read_new<Style>(Reader&);
|
template <> StyleP read_new<Style>(Reader&);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : StyleListener
|
||||||
|
|
||||||
|
/// An object that can respond when a style changes;
|
||||||
|
class StyleListener {
|
||||||
|
public:
|
||||||
|
StyleListener(const StyleP& style);
|
||||||
|
virtual ~StyleListener();
|
||||||
|
|
||||||
|
/// Called when a (scripted) property of the viewed style has changed
|
||||||
|
virtual void onStyleChange() {}
|
||||||
|
protected:
|
||||||
|
const StyleP styleP; ///< The style we are listening to
|
||||||
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Value
|
// ----------------------------------------------------------------------------- : Value
|
||||||
|
|
||||||
/// A specific value 'in' a Field.
|
/// A specific value 'in' a Field.
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ BooleanStyle::BooleanStyle(const ChoiceFieldP& field)
|
|||||||
: ChoiceStyle(field)
|
: ChoiceStyle(field)
|
||||||
{
|
{
|
||||||
render_style = RENDER_BOTH;
|
render_style = RENDER_BOTH;
|
||||||
choice_images[_("yes")] = ScriptableImage(_("buildin_image(\"bool_yes\")"));
|
//%%choice_images[_("yes")] = ScriptableImage(_("buildin_image(\"bool_yes\")"));
|
||||||
choice_images[_("no")] = ScriptableImage(_("buildin_image(\"bool_no\")"));
|
//%%choice_images[_("no")] = ScriptableImage(_("buildin_image(\"bool_no\")"));
|
||||||
|
choice_images[_("yes")] = ScriptableImage(new_intrusive1<BuiltInImage>(_("bool_yes")));
|
||||||
|
choice_images[_("no")] = ScriptableImage(new_intrusive1<BuiltInImage>(_("bool_no")));
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION(BooleanStyle) {
|
IMPLEMENT_REFLECTION(BooleanStyle) {
|
||||||
|
|||||||
+23
-14
@@ -167,8 +167,6 @@ ChoiceStyle::ChoiceStyle(const ChoiceFieldP& field)
|
|||||||
, alignment(ALIGN_STRETCH)
|
, alignment(ALIGN_STRETCH)
|
||||||
, angle(0)
|
, angle(0)
|
||||||
, thumbnails(nullptr)
|
, thumbnails(nullptr)
|
||||||
, thumbnail_age(1) // thumbnails were made before the beginning of time
|
|
||||||
, invalidated_images(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ChoiceStyle::~ChoiceStyle() {
|
ChoiceStyle::~ChoiceStyle() {
|
||||||
@@ -178,8 +176,15 @@ ChoiceStyle::~ChoiceStyle() {
|
|||||||
|
|
||||||
bool ChoiceStyle::update(Context& ctx) {
|
bool ChoiceStyle::update(Context& ctx) {
|
||||||
// Don't update the choice images, leave that to invalidate()
|
// Don't update the choice images, leave that to invalidate()
|
||||||
return Style ::update(ctx)
|
bool change = Style ::update(ctx)
|
||||||
| mask_filename.update(ctx);
|
| mask_filename.update(ctx);
|
||||||
|
FOR_EACH(ci, choice_images) {
|
||||||
|
if (ci.second.update(ctx)) {
|
||||||
|
change = true;
|
||||||
|
// TODO : remove this thumbnail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return change;
|
||||||
}
|
}
|
||||||
void ChoiceStyle::initDependencies(Context& ctx, const Dependency& dep) const {
|
void ChoiceStyle::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||||
Style::initDependencies(ctx, dep);
|
Style::initDependencies(ctx, dep);
|
||||||
@@ -187,17 +192,21 @@ void ChoiceStyle::initDependencies(Context& ctx, const Dependency& dep) const {
|
|||||||
ci.second.initDependencies(ctx, dep);
|
ci.second.initDependencies(ctx, dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ChoiceStyle::invalidate() {
|
void ChoiceStyle::invalidate(Context& ctx) {
|
||||||
// rebuild choice images
|
// TODO : this is also done in update(), once should be enough
|
||||||
// TODO: Don't use this; rely on upToDate() instead
|
// Update choice images and thumbnails
|
||||||
FOR_EACH(ci, choice_images) {
|
bool change = false;
|
||||||
// TODO : only invalidate images that actually have dependencies
|
int end = field().choices->lastId();
|
||||||
ci.second.invalidate();
|
thumbnails_status.resize(end, THUMB_NOT_MADE);
|
||||||
|
for (int i = 0 ; i < end ; ++i) {
|
||||||
|
String name = cannocial_name_form(field().choices->choiceName(i));
|
||||||
|
ScriptableImage& img = choice_images[name];
|
||||||
|
if (img.update(ctx)) {
|
||||||
|
change = true;
|
||||||
|
thumbnails_status[i] = THUMB_CHANGED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (thumbnails) {
|
if (change) tellListeners();
|
||||||
thumbnails->RemoveAll();
|
|
||||||
}
|
|
||||||
invalidated_images = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChoiceStyle::loadMask(Package& pkg) {
|
void ChoiceStyle::loadMask(Package& pkg) {
|
||||||
|
|||||||
@@ -114,6 +114,12 @@ enum ChoiceRenderStyle
|
|||||||
, RENDER_BOTH_CHECKLIST = RENDER_CHECKLIST | RENDER_BOTH
|
, RENDER_BOTH_CHECKLIST = RENDER_CHECKLIST | RENDER_BOTH
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ThumbnailStatus
|
||||||
|
{ THUMB_NOT_MADE
|
||||||
|
, THUMB_OK
|
||||||
|
, THUMB_CHANGED
|
||||||
|
};
|
||||||
|
|
||||||
/// The Style for a ChoiceField
|
/// The Style for a ChoiceField
|
||||||
class ChoiceStyle : public Style {
|
class ChoiceStyle : public Style {
|
||||||
public:
|
public:
|
||||||
@@ -133,15 +139,14 @@ class ChoiceStyle : public Style {
|
|||||||
Image mask; ///< The actual mask image
|
Image mask; ///< The actual mask image
|
||||||
int angle; ///< Angle by which the images are rotated
|
int angle; ///< Angle by which the images are rotated
|
||||||
wxImageList* thumbnails; ///< Thumbnails for the choices
|
wxImageList* thumbnails; ///< Thumbnails for the choices
|
||||||
Age thumbnail_age; ///< Age the thumbnails were generated
|
vector<ThumbnailStatus> thumbnails_status; ///< Which thumbnails are up to date?
|
||||||
bool invalidated_images; ///< Have the images been invalidated?
|
|
||||||
|
|
||||||
/// Load the mask image, if it's not already done
|
/// Load the mask image, if it's not already done
|
||||||
void loadMask(Package& pkg);
|
void loadMask(Package& pkg);
|
||||||
|
|
||||||
virtual bool update(Context&);
|
virtual bool update(Context&);
|
||||||
virtual void initDependencies(Context&, const Dependency&) const;
|
virtual void initDependencies(Context&, const Dependency&) const;
|
||||||
virtual void invalidate();
|
virtual void invalidate(Context&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ImageStyle : public Style {
|
|||||||
DECLARE_STYLE_TYPE(Image);
|
DECLARE_STYLE_TYPE(Image);
|
||||||
|
|
||||||
Scriptable<String> mask_filename; ///< Filename for a mask image
|
Scriptable<String> mask_filename; ///< Filename for a mask image
|
||||||
ScriptableImage2 default_image; ///< Placeholder
|
ScriptableImage default_image; ///< Placeholder
|
||||||
|
|
||||||
virtual bool update(Context&);
|
virtual bool update(Context&);
|
||||||
|
|
||||||
|
|||||||
+40
-43
@@ -75,14 +75,14 @@ class SymbolInFont {
|
|||||||
SymbolInFont();
|
SymbolInFont();
|
||||||
|
|
||||||
/// Get a shrunk, zoomed bitmap
|
/// Get a shrunk, zoomed bitmap
|
||||||
Bitmap getBitmap(Context& ctx, Package& pkg, double size);
|
Bitmap getBitmap(Package& pkg, double size);
|
||||||
|
|
||||||
/// Get a bitmap with the given size
|
/// Get a bitmap with the given size
|
||||||
Bitmap getBitmap(Context& ctx, Package& pkg, wxSize size);
|
Bitmap getBitmap(Package& pkg, wxSize size);
|
||||||
|
|
||||||
/// Size of a (zoomed) bitmap
|
/// Size of a (zoomed) bitmap
|
||||||
/** This is the size of the resulting image, it does NOT convert back to internal coordinates */
|
/** This is the size of the resulting image, it does NOT convert back to internal coordinates */
|
||||||
RealSize size(Context& ctx, Package& pkg, double size);
|
RealSize size(Package& pkg, double size);
|
||||||
|
|
||||||
void update(Context& ctx);
|
void update(Context& ctx);
|
||||||
|
|
||||||
@@ -107,15 +107,15 @@ SymbolInFont::SymbolInFont()
|
|||||||
if (img_size <= 0) img_size = 1;
|
if (img_size <= 0) img_size = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) {
|
Bitmap SymbolInFont::getBitmap(Package& pkg, double size) {
|
||||||
// is this bitmap already loaded/generated?
|
// is this bitmap already loaded/generated?
|
||||||
Bitmap& bmp = bitmaps[size];
|
Bitmap& bmp = bitmaps[size];
|
||||||
if (!bmp.Ok()) {
|
if (!bmp.Ok()) {
|
||||||
// generate new bitmap
|
// generate new bitmap
|
||||||
if (!image) {
|
if (!image.isReady()) {
|
||||||
throw Error(_("No image specified for symbol with code '") + code + _("' in symbol font."));
|
throw Error(_("No image specified for symbol with code '") + code + _("' in symbol font."));
|
||||||
}
|
}
|
||||||
Image img = image.generate(ctx, pkg)->image;
|
Image img = image.generate(GeneratedImage::Options(0, 0, &pkg));
|
||||||
actual_size = wxSize(img.GetWidth(), img.GetHeight());
|
actual_size = wxSize(img.GetWidth(), img.GetHeight());
|
||||||
// scale to match expected size
|
// scale to match expected size
|
||||||
Image resampled_image((int) (actual_size.GetWidth() * size / img_size),
|
Image resampled_image((int) (actual_size.GetWidth() * size / img_size),
|
||||||
@@ -127,28 +127,24 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) {
|
|||||||
}
|
}
|
||||||
return bmp;
|
return bmp;
|
||||||
}
|
}
|
||||||
Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, wxSize size) {
|
Bitmap SymbolInFont::getBitmap(Package& pkg, wxSize size) {
|
||||||
// generate new bitmap
|
// generate new bitmap
|
||||||
if (!image) {
|
if (!image.isReady()) {
|
||||||
throw Error(_("No image specified for symbol with code '") + code + _("' in symbol font."));
|
throw Error(_("No image specified for symbol with code '") + code + _("' in symbol font."));
|
||||||
}
|
}
|
||||||
Image img = image.generate(ctx, pkg)->image;
|
return Bitmap( image.generate(GeneratedImage::Options(size.x, size.y, &pkg, nullptr, ASPECT_BORDER)) );
|
||||||
actual_size = wxSize(img.GetWidth(), img.GetHeight());
|
|
||||||
// scale to match expected size
|
|
||||||
Image resampled_image(size.GetWidth(), size.GetHeight(), false);
|
|
||||||
resample_preserve_aspect(img, resampled_image);
|
|
||||||
return Bitmap(resampled_image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) {
|
RealSize SymbolInFont::size(Package& pkg, double size) {
|
||||||
if (actual_size.GetWidth() == 0) {
|
if (actual_size.GetWidth() == 0) {
|
||||||
// we don't know what size the image will be
|
// we don't know what size the image will be
|
||||||
getBitmap(ctx, pkg, size);
|
getBitmap(pkg, size);
|
||||||
}
|
}
|
||||||
return wxSize(actual_size * (int) (size) / (int) (img_size));
|
return wxSize(actual_size * (int) (size) / (int) (img_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolInFont::update(Context& ctx) {
|
void SymbolInFont::update(Context& ctx) {
|
||||||
|
image.update(ctx);
|
||||||
enabled.update(ctx);
|
enabled.update(ctx);
|
||||||
}
|
}
|
||||||
void SymbolFont::update(Context& ctx) const {
|
void SymbolFont::update(Context& ctx) const {
|
||||||
@@ -180,8 +176,7 @@ class SymbolFont::DrawableSymbol {
|
|||||||
SymbolInFont* symbol; ///< Symbol to draw, if nullptr, use the default symbol and draw the text
|
SymbolInFont* symbol; ///< Symbol to draw, if nullptr, use the default symbol and draw the text
|
||||||
};
|
};
|
||||||
|
|
||||||
void SymbolFont::split(const String& text, Context& ctx, SplitSymbols& out) const {
|
void SymbolFont::split(const String& text, SplitSymbols& out) const {
|
||||||
update(ctx);
|
|
||||||
// read a single symbol until we are done with the text
|
// read a single symbol until we are done with the text
|
||||||
for (size_t pos = 0 ; pos < text.size() ; ) {
|
for (size_t pos = 0 ; pos < text.size() ; ) {
|
||||||
// 1. check merged numbers
|
// 1. check merged numbers
|
||||||
@@ -220,37 +215,38 @@ SymbolInFont* SymbolFont::defaultSymbol() const {
|
|||||||
|
|
||||||
void SymbolFont::draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text) {
|
void SymbolFont::draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text) {
|
||||||
SplitSymbols symbols;
|
SplitSymbols symbols;
|
||||||
split(text, ctx, symbols);
|
update(ctx);
|
||||||
draw(dc, ctx, rect, font_size, align, symbols);
|
split(text, symbols);
|
||||||
|
draw(dc, rect, font_size, align, symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolFont::draw(RotatedDC& dc, Context& ctx, RealRect rect, double font_size, const Alignment& align, const SplitSymbols& text) {
|
void SymbolFont::draw(RotatedDC& dc, RealRect rect, double font_size, const Alignment& align, const SplitSymbols& text) {
|
||||||
FOR_EACH_CONST(sym, text) {
|
FOR_EACH_CONST(sym, text) {
|
||||||
RealSize size = dc.trInvS(symbolSize(ctx, dc.trS(font_size), sym));
|
RealSize size = dc.trInvS(symbolSize(dc.trS(font_size), sym));
|
||||||
RealRect sym_rect = split_left(rect, size);
|
RealRect sym_rect = split_left(rect, size);
|
||||||
if (sym.symbol) {
|
if (sym.symbol) {
|
||||||
drawSymbol( dc, ctx, sym_rect, font_size, align, *sym.symbol);
|
drawSymbol( dc, sym_rect, font_size, align, *sym.symbol);
|
||||||
} else {
|
} else {
|
||||||
drawWithText(dc, ctx, sym_rect, font_size, align, sym.text);
|
drawWithText(dc, sym_rect, font_size, align, sym.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolFont::drawSymbol (RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, SymbolInFont& sym) {
|
void SymbolFont::drawSymbol (RotatedDC& dc, const RealRect& rect, double font_size, const Alignment& align, SymbolInFont& sym) {
|
||||||
// find bitmap
|
// find bitmap
|
||||||
Bitmap bmp = sym.getBitmap(ctx, *this, dc.trS(font_size));
|
Bitmap bmp = sym.getBitmap(*this, dc.trS(font_size));
|
||||||
// draw aligned in the rectangle
|
// draw aligned in the rectangle
|
||||||
dc.DrawBitmap(bmp, align_in_rect(align, dc.trInvS(RealSize(bmp.GetWidth(), bmp.GetHeight())), rect));
|
dc.DrawBitmap(bmp, align_in_rect(align, dc.trInvS(RealSize(bmp.GetWidth(), bmp.GetHeight())), rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolFont::drawWithText(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text) {
|
void SymbolFont::drawWithText(RotatedDC& dc, const RealRect& rect, double font_size, const Alignment& align, const String& text) {
|
||||||
// 1. draw background bitmap
|
// 1. draw background bitmap
|
||||||
// Size and position of symbol
|
// Size and position of symbol
|
||||||
RealRect sym_rect = rect;
|
RealRect sym_rect = rect;
|
||||||
// find and draw background bitmap
|
// find and draw background bitmap
|
||||||
SymbolInFont* def = defaultSymbol();
|
SymbolInFont* def = defaultSymbol();
|
||||||
if (def) {
|
if (def) {
|
||||||
Bitmap bmp = def->getBitmap(ctx, *this, dc.trS(font_size));
|
Bitmap bmp = def->getBitmap(*this, dc.trS(font_size));
|
||||||
// align symbol
|
// align symbol
|
||||||
sym_rect.size() = dc.trInvS(RealSize(bmp.GetWidth(), bmp.GetHeight()));
|
sym_rect.size() = dc.trInvS(RealSize(bmp.GetWidth(), bmp.GetHeight()));
|
||||||
sym_rect.position() = align_in_rect(align, sym_rect.size(), rect);
|
sym_rect.position() = align_in_rect(align, sym_rect.size(), rect);
|
||||||
@@ -295,14 +291,15 @@ void SymbolFont::drawWithText(RotatedDC& dc, Context& ctx, const RealRect& rect,
|
|||||||
|
|
||||||
void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out) {
|
void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out) {
|
||||||
SplitSymbols symbols;
|
SplitSymbols symbols;
|
||||||
split(text, ctx, symbols);
|
update(ctx);
|
||||||
getCharInfo(dc, ctx, font_size, symbols, out);
|
split(text, symbols);
|
||||||
|
getCharInfo(dc, font_size, symbols, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const SplitSymbols& text, vector<CharInfo>& out) {
|
void SymbolFont::getCharInfo(RotatedDC& dc, double font_size, const SplitSymbols& text, vector<CharInfo>& out) {
|
||||||
FOR_EACH_CONST(sym, text) {
|
FOR_EACH_CONST(sym, text) {
|
||||||
size_t count = sym.text.size();
|
size_t count = sym.text.size();
|
||||||
RealSize size = dc.trInvS(symbolSize(ctx, dc.trS(font_size), sym));
|
RealSize size = dc.trInvS(symbolSize(dc.trS(font_size), sym));
|
||||||
size.width /= count; // divide into count parts
|
size.width /= count; // divide into count parts
|
||||||
for (size_t i = 0 ; i < count ; ++i) {
|
for (size_t i = 0 ; i < count ; ++i) {
|
||||||
out.push_back(CharInfo(size, i == count - 1 ? BREAK_MAYBE : BREAK_NO));
|
out.push_back(CharInfo(size, i == count - 1 ? BREAK_MAYBE : BREAK_NO));
|
||||||
@@ -310,18 +307,18 @@ void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RealSize SymbolFont::symbolSize(Context& ctx, double font_size, const DrawableSymbol& sym) {
|
RealSize SymbolFont::symbolSize(double font_size, const DrawableSymbol& sym) {
|
||||||
if (sym.symbol) {
|
if (sym.symbol) {
|
||||||
return add_diagonal(sym.symbol->size(ctx, *this, font_size), spacing);
|
return add_diagonal(sym.symbol->size(*this, font_size), spacing);
|
||||||
} else {
|
} else {
|
||||||
return defaultSymbolSize(ctx, font_size);
|
return defaultSymbolSize(font_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RealSize SymbolFont::defaultSymbolSize(Context& ctx, double font_size) {
|
RealSize SymbolFont::defaultSymbolSize(double font_size) {
|
||||||
SymbolInFont* def = defaultSymbol();
|
SymbolInFont* def = defaultSymbol();
|
||||||
if (def) {
|
if (def) {
|
||||||
return add_diagonal(def->size(ctx, *this, font_size), spacing);
|
return add_diagonal(def->size(*this, font_size), spacing);
|
||||||
} else {
|
} else {
|
||||||
return add_diagonal(RealSize(1,1), spacing);
|
return add_diagonal(RealSize(1,1), spacing);
|
||||||
}
|
}
|
||||||
@@ -334,7 +331,7 @@ wxMenu* SymbolFont::insertSymbolMenu(Context& ctx) {
|
|||||||
if (!processed_insert_symbol_menu && insert_symbol_menu) {
|
if (!processed_insert_symbol_menu && insert_symbol_menu) {
|
||||||
update(ctx);
|
update(ctx);
|
||||||
// Make menu
|
// Make menu
|
||||||
processed_insert_symbol_menu = insert_symbol_menu->makeMenu(ID_INSERT_SYMBOL_MENU_MIN, ctx, *this);
|
processed_insert_symbol_menu = insert_symbol_menu->makeMenu(ID_INSERT_SYMBOL_MENU_MIN, *this);
|
||||||
}
|
}
|
||||||
return processed_insert_symbol_menu;
|
return processed_insert_symbol_menu;
|
||||||
}
|
}
|
||||||
@@ -384,22 +381,22 @@ String InsertSymbolMenu::getCode(int id, const SymbolFont& font) const {
|
|||||||
return wxEmptyString;
|
return wxEmptyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMenu* InsertSymbolMenu::makeMenu(int id, Context& ctx, SymbolFont& font) const {
|
wxMenu* InsertSymbolMenu::makeMenu(int id, SymbolFont& font) const {
|
||||||
if (type == ITEM_SUBMENU) {
|
if (type == ITEM_SUBMENU) {
|
||||||
wxMenu* menu = new wxMenu();
|
wxMenu* menu = new wxMenu();
|
||||||
FOR_EACH_CONST(i, items) {
|
FOR_EACH_CONST(i, items) {
|
||||||
menu->Append(i->makeMenuItem(menu, id, ctx, font));
|
menu->Append(i->makeMenuItem(menu, id, font));
|
||||||
id += i->size();
|
id += i->size();
|
||||||
}
|
}
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
wxMenuItem* InsertSymbolMenu::makeMenuItem(wxMenu* parent, int first_id, Context& ctx, SymbolFont& font) const {
|
wxMenuItem* InsertSymbolMenu::makeMenuItem(wxMenu* parent, int first_id, SymbolFont& font) const {
|
||||||
if (type == ITEM_SUBMENU) {
|
if (type == ITEM_SUBMENU) {
|
||||||
wxMenuItem* item = new wxMenuItem(parent, wxID_ANY, tr(font, _("menu item ") + name, name),
|
wxMenuItem* item = new wxMenuItem(parent, wxID_ANY, tr(font, _("menu item ") + name, name),
|
||||||
wxEmptyString, wxITEM_NORMAL,
|
wxEmptyString, wxITEM_NORMAL,
|
||||||
makeMenu(first_id, ctx, font));
|
makeMenu(first_id, font));
|
||||||
item->SetBitmap(wxNullBitmap);
|
item->SetBitmap(wxNullBitmap);
|
||||||
return item;
|
return item;
|
||||||
} else if (type == ITEM_LINE) {
|
} else if (type == ITEM_LINE) {
|
||||||
@@ -420,7 +417,7 @@ wxMenuItem* InsertSymbolMenu::makeMenuItem(wxMenu* parent, int first_id, Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (symbol) {
|
if (symbol) {
|
||||||
item->SetBitmap(symbol->getBitmap(ctx, font, wxSize(16,16)));
|
item->SetBitmap(symbol->getBitmap(font, wxSize(16,16)));
|
||||||
} else {
|
} else {
|
||||||
item->SetBitmap(wxNullBitmap);
|
item->SetBitmap(wxNullBitmap);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -32,10 +32,13 @@ class SymbolFont : public Packaged {
|
|||||||
/// Loads the symbol font with a given name, for example "magic-mana-large"
|
/// Loads the symbol font with a given name, for example "magic-mana-large"
|
||||||
static SymbolFontP byName(const String& name);
|
static SymbolFontP byName(const String& name);
|
||||||
|
|
||||||
|
// Script update
|
||||||
|
void update(Context& ctx) const;
|
||||||
|
|
||||||
class DrawableSymbol;
|
class DrawableSymbol;
|
||||||
typedef vector<DrawableSymbol> SplitSymbols;
|
typedef vector<DrawableSymbol> SplitSymbols;
|
||||||
/// Split a string into separate symbols for drawing and for determining their size
|
/// Split a string into separate symbols for drawing and for determining their size
|
||||||
void split(const String& text, Context& ctx, SplitSymbols& out) const;
|
void split(const String& text, SplitSymbols& out) const;
|
||||||
|
|
||||||
/// Draw a piece of text prepared using split
|
/// Draw a piece of text prepared using split
|
||||||
void draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text);
|
void draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text);
|
||||||
@@ -43,9 +46,9 @@ class SymbolFont : public Packaged {
|
|||||||
void getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out);
|
void getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out);
|
||||||
|
|
||||||
/// Draw a piece of text prepared using split
|
/// Draw a piece of text prepared using split
|
||||||
void draw(RotatedDC& dc, Context& ctx, RealRect rect, double font_size, const Alignment& align, const SplitSymbols& text);
|
void draw(RotatedDC& dc, RealRect rect, double font_size, const Alignment& align, const SplitSymbols& text);
|
||||||
/// Get information on characters in a string
|
/// Get information on characters in a string
|
||||||
void getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const SplitSymbols& text, vector<CharInfo>& out);
|
void getCharInfo(RotatedDC& dc, double font_size, const SplitSymbols& text, vector<CharInfo>& out);
|
||||||
|
|
||||||
static String typeNameStatic();
|
static String typeNameStatic();
|
||||||
virtual String typeName() const;
|
virtual String typeName() const;
|
||||||
@@ -79,24 +82,21 @@ class SymbolFont : public Packaged {
|
|||||||
friend class SymbolInFont;
|
friend class SymbolInFont;
|
||||||
friend class InsertSymbolMenu;
|
friend class InsertSymbolMenu;
|
||||||
vector<SymbolInFontP> symbols; ///< The individual symbols
|
vector<SymbolInFontP> symbols; ///< The individual symbols
|
||||||
|
|
||||||
// Script update
|
|
||||||
void update(Context& ctx) const;
|
|
||||||
|
|
||||||
/// Find the default symbol
|
/// Find the default symbol
|
||||||
/** may return nullptr */
|
/** may return nullptr */
|
||||||
SymbolInFont* defaultSymbol() const;
|
SymbolInFont* defaultSymbol() const;
|
||||||
|
|
||||||
/// Draws a single symbol inside the given rectangle
|
/// Draws a single symbol inside the given rectangle
|
||||||
void drawSymbol (RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, SymbolInFont& sym);
|
void drawSymbol (RotatedDC& dc, const RealRect& rect, double font_size, const Alignment& align, SymbolInFont& sym);
|
||||||
/// Draw the default bitmap to a dc and overlay a string of text
|
/// Draw the default bitmap to a dc and overlay a string of text
|
||||||
void drawWithText(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text);
|
void drawWithText(RotatedDC& dc, const RealRect& rect, double font_size, const Alignment& align, const String& text);
|
||||||
|
|
||||||
/// Size of a single symbol
|
/// Size of a single symbol
|
||||||
RealSize symbolSize (Context& ctx, double font_size, const DrawableSymbol& sym);
|
RealSize symbolSize (double font_size, const DrawableSymbol& sym);
|
||||||
public:
|
public:
|
||||||
/// Size of the default symbol
|
/// Size of the default symbol
|
||||||
RealSize defaultSymbolSize(Context& ctx, double font_size);
|
RealSize defaultSymbolSize(double font_size);
|
||||||
|
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
};
|
};
|
||||||
@@ -124,9 +124,9 @@ class InsertSymbolMenu {
|
|||||||
/// Get the code for an item, id relative to the start of this menu
|
/// Get the code for an item, id relative to the start of this menu
|
||||||
String getCode(int id, const SymbolFont& font) const;
|
String getCode(int id, const SymbolFont& font) const;
|
||||||
/// Make an actual menu
|
/// Make an actual menu
|
||||||
wxMenu* makeMenu(int first_id, Context& ctx, SymbolFont& font) const;
|
wxMenu* makeMenu(int first_id, SymbolFont& font) const;
|
||||||
/// Make an actual menu item
|
/// Make an actual menu item
|
||||||
wxMenuItem* makeMenuItem(wxMenu* parent, int first_id, Context& ctx, SymbolFont& font) const;
|
wxMenuItem* makeMenuItem(wxMenu* parent, int first_id, SymbolFont& font) const;
|
||||||
|
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,11 +32,13 @@ wxSize CardViewer::DoGetBestSize() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CardViewer::redraw(const ValueViewer& v) {
|
void CardViewer::redraw(const ValueViewer& v) {
|
||||||
|
if (drawing) return;
|
||||||
up_to_date = false;
|
up_to_date = false;
|
||||||
RefreshRect(getRotation().tr(v.boundingBox()), false);
|
RefreshRect(getRotation().tr(v.boundingBox()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardViewer::onChange() {
|
void CardViewer::onChange() {
|
||||||
|
if (drawing) return;
|
||||||
up_to_date = false;
|
up_to_date = false;
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class CardViewer : public wxControl, public DataViewer {
|
|||||||
shared_ptr<DC> overdrawDC();
|
shared_ptr<DC> overdrawDC();
|
||||||
|
|
||||||
/// Invalidate and redraw (the area of) a single value viewer
|
/// Invalidate and redraw (the area of) a single value viewer
|
||||||
void redraw(const ValueViewer&);
|
virtual void redraw(const ValueViewer&);
|
||||||
|
|
||||||
/// The rotation to use
|
/// The rotation to use
|
||||||
virtual Rotation getRotation() const;
|
virtual Rotation getRotation() const;
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) {
|
|||||||
if (request_names.find(request) != request_names.end()) {
|
if (request_names.find(request) != request_names.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
request_names.insert(request);
|
|
||||||
// Is the image in the cache?
|
// Is the image in the cache?
|
||||||
String filename = image_cache_dir() + safe_filename(request->cache_name) + _(".png");
|
String filename = image_cache_dir() + safe_filename(request->cache_name) + _(".png");
|
||||||
wxFileName fn(filename);
|
wxFileName fn(filename);
|
||||||
@@ -124,6 +123,7 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
request_names.insert(request);
|
||||||
// request generation
|
// request generation
|
||||||
{
|
{
|
||||||
wxMutexLocker lock(mutex);
|
wxMutexLocker lock(mutex);
|
||||||
|
|||||||
@@ -40,10 +40,9 @@ ChoiceThumbnailRequest::ChoiceThumbnailRequest(ValueViewer* cve, int id, bool fr
|
|||||||
|
|
||||||
Image ChoiceThumbnailRequest::generate() {
|
Image ChoiceThumbnailRequest::generate() {
|
||||||
ChoiceValueEditor& cve = *(ChoiceValueEditor*)owner;
|
ChoiceValueEditor& cve = *(ChoiceValueEditor*)owner;
|
||||||
Context& ctx = cve.getSet().getContextForThumbnails(stylesheet);
|
|
||||||
String name = cannocial_name_form(cve.field().choices->choiceName(id));
|
String name = cannocial_name_form(cve.field().choices->choiceName(id));
|
||||||
ScriptableImage& img = cve.style().choice_images[name];
|
ScriptableImage& img = cve.style().choice_images[name];
|
||||||
return img.generate(ctx, *stylesheet, 16, 16, ASPECT_BORDER, true)->image;
|
return img.generate(GeneratedImage::Options(16,16, stylesheet.get(), &cve.getSet(), ASPECT_BORDER, true), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChoiceThumbnailRequest::store(const Image& img) {
|
void ChoiceThumbnailRequest::store(const Image& img) {
|
||||||
@@ -79,6 +78,7 @@ void ChoiceThumbnailRequest::store(const Image& img) {
|
|||||||
} else {
|
} else {
|
||||||
il->Replace(id, img);
|
il->Replace(id, img);
|
||||||
}
|
}
|
||||||
|
cve.style().thumbnails_status[id] = THUMB_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,18 +157,15 @@ void DropDownChoiceListBase::generateThumbnailImages() {
|
|||||||
}
|
}
|
||||||
int image_count = style().thumbnails->GetImageCount();
|
int image_count = style().thumbnails->GetImageCount();
|
||||||
int end = group->lastId();
|
int end = group->lastId();
|
||||||
Context& ctx = cve.viewer.getContext();
|
style().thumbnails_status.resize(end, THUMB_NOT_MADE);
|
||||||
for (int i = 0 ; i < end ; ++i) {
|
for (int i = 0 ; i < end ; ++i) {
|
||||||
String name = cannocial_name_form(group->choiceName(i));
|
String name = cannocial_name_form(group->choiceName(i));
|
||||||
ScriptableImage& img = style().choice_images[name];
|
ThumbnailStatus status = style().thumbnails_status[i];
|
||||||
bool up_to_date = img.upToDate(ctx, style().thumbnail_age);
|
if (i >= image_count || status != THUMB_OK) {
|
||||||
if (i >= image_count || !up_to_date) {
|
|
||||||
// TODO : handle the case where image i was previously skipped
|
|
||||||
// request this thumbnail
|
// request this thumbnail
|
||||||
thumbnail_thread.request( new_shared3<ChoiceThumbnailRequest>(&cve, i, up_to_date && !style().invalidated_images) );
|
thumbnail_thread.request( new_shared3<ChoiceThumbnailRequest>(&cve, i, status == THUMB_NOT_MADE) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style().thumbnail_age.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DropDownChoiceListBase::onIdle(wxIdleEvent& ev) {
|
void DropDownChoiceListBase::onIdle(wxIdleEvent& ev) {
|
||||||
|
|||||||
@@ -441,7 +441,8 @@ void TextValueEditor::showCaret() {
|
|||||||
// it is not 0 for empty text, because TextRenderer handles that case
|
// it is not 0 for empty text, because TextRenderer handles that case
|
||||||
if (cursor.height == 0) {
|
if (cursor.height == 0) {
|
||||||
if (style().always_symbol && style().symbol_font.valid()) {
|
if (style().always_symbol && style().symbol_font.valid()) {
|
||||||
RealSize s = style().symbol_font.font->defaultSymbolSize(viewer.getContext(), rot.trS(style().symbol_font.size));
|
style().symbol_font.font->update(viewer.getContext());
|
||||||
|
RealSize s = style().symbol_font.font->defaultSymbolSize(rot.trS(style().symbol_font.size));
|
||||||
cursor.height = s.height;
|
cursor.height = s.height;
|
||||||
} else {
|
} else {
|
||||||
cursor.height = v.heightOfLastLine();
|
cursor.height = v.heightOfLastLine();
|
||||||
|
|||||||
@@ -34,15 +34,19 @@ void DataViewer::draw(DC& dc) {
|
|||||||
}
|
}
|
||||||
void DataViewer::draw(RotatedDC& dc, const Color& background) {
|
void DataViewer::draw(RotatedDC& dc, const Color& background) {
|
||||||
if (!set) return; // no set specified, don't draw anything
|
if (!set) return; // no set specified, don't draw anything
|
||||||
|
drawing = true;
|
||||||
// fill with background color
|
// fill with background color
|
||||||
clearDC(dc.getDC(), background);
|
clearDC(dc.getDC(), background);
|
||||||
// update style scripts
|
// update style scripts
|
||||||
//%% if (card) set->updateFor(card);
|
try {
|
||||||
Context& ctx = getContext();
|
Context& ctx = getContext();
|
||||||
FOR_EACH(v, viewers) {
|
FOR_EACH(v, viewers) {
|
||||||
if (v->getStyle()->update(ctx)) {
|
if (v->getStyle()->update(ctx)) {
|
||||||
v->onStyleChange();
|
v->getStyle()->tellListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (const Error& e) {
|
||||||
|
handle_error(e, false, false);
|
||||||
}
|
}
|
||||||
// draw values
|
// draw values
|
||||||
FOR_EACH(v, viewers) { // draw low z index fields first
|
FOR_EACH(v, viewers) { // draw low z index fields first
|
||||||
@@ -54,6 +58,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drawing = false;
|
||||||
}
|
}
|
||||||
void DataViewer::drawViewer(RotatedDC& dc, ValueViewer& v) {
|
void DataViewer::drawViewer(RotatedDC& dc, ValueViewer& v) {
|
||||||
v.draw(dc);
|
v.draw(dc);
|
||||||
@@ -159,16 +164,16 @@ void DataViewer::onAction(const Action& action, bool undone) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TYPE_CASE(action, ScriptStyleEvent) {
|
/*//% TYPE_CASE(action, ScriptStyleEvent) {
|
||||||
if (action.stylesheet == stylesheet.get()) {
|
if (action.stylesheet == stylesheet.get()) {
|
||||||
FOR_EACH(v, viewers) {
|
FOR_EACH(v, viewers) {
|
||||||
if (v->getStyle().get() == action.style) {
|
if (v->getStyle().get() == action.style) {
|
||||||
// refresh the viewer
|
// refresh the viewer
|
||||||
v->onStyleChange();
|
v->onStyleChange();
|
||||||
onChange();
|
if (!drawing) onChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class Context;
|
|||||||
/// A viewer can generate an image of some values, usually a card.
|
/// A viewer can generate an image of some values, usually a card.
|
||||||
class DataViewer : public SetView {
|
class DataViewer : public SetView {
|
||||||
public:
|
public:
|
||||||
|
DataViewer() : drawing(false) {}
|
||||||
|
|
||||||
// --------------------------------------------------- : Drawing
|
// --------------------------------------------------- : Drawing
|
||||||
|
|
||||||
/// Draw the current (card/data) to the given dc
|
/// Draw the current (card/data) to the given dc
|
||||||
@@ -56,6 +58,8 @@ class DataViewer : public SetView {
|
|||||||
virtual Rotation getRotation() const;
|
virtual Rotation getRotation() const;
|
||||||
/// The card we are viewing
|
/// The card we are viewing
|
||||||
inline CardP getCard() const { return card; }
|
inline CardP getCard() const { return card; }
|
||||||
|
/// Invalidate and redraw (the area of) a single value viewer
|
||||||
|
virtual void redraw(const ValueViewer&) {}
|
||||||
|
|
||||||
// --------------------------------------------------- : Setting data
|
// --------------------------------------------------- : Setting data
|
||||||
|
|
||||||
@@ -86,6 +90,7 @@ class DataViewer : public SetView {
|
|||||||
|
|
||||||
vector<ValueViewerP> viewers; ///< The viewers for the different values in the data
|
vector<ValueViewerP> viewers; ///< The viewers for the different values in the data
|
||||||
CardP card; ///< The card that is currently displayed, if any
|
CardP card; ///< The card that is currently displayed, if any
|
||||||
|
bool drawing; ///< Are we currently drawing?
|
||||||
public:
|
public:
|
||||||
mutable StyleSheetP stylesheet; ///< Stylesheet being used
|
mutable StyleSheetP stylesheet; ///< Stylesheet being used
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ void TextViewer::prepareLines(RotatedDC& dc, const String& text, const TextStyle
|
|||||||
// no text, find a dummy height for the single line we have
|
// no text, find a dummy height for the single line we have
|
||||||
if (lines.size() == 1 && lines[0].width() < 0.0001) {
|
if (lines.size() == 1 && lines[0].width() < 0.0001) {
|
||||||
if (style.always_symbol && style.symbol_font.valid()) {
|
if (style.always_symbol && style.symbol_font.valid()) {
|
||||||
lines[0].line_height = style.symbol_font.font->defaultSymbolSize(ctx, style.symbol_font.size).height;
|
lines[0].line_height = style.symbol_font.font->defaultSymbolSize(style.symbol_font.size).height;
|
||||||
} else {
|
} else {
|
||||||
dc.SetFont(style.font, scale);
|
dc.SetFont(style.font, scale);
|
||||||
lines[0].line_height = dc.GetCharHeight();
|
lines[0].line_height = dc.GetCharHeight();
|
||||||
|
|||||||
+25
-22
@@ -20,34 +20,33 @@ void ChoiceValueViewer::draw(RotatedDC& dc) {
|
|||||||
if (style().render_style & RENDER_IMAGE) {
|
if (style().render_style & RENDER_IMAGE) {
|
||||||
// draw image
|
// draw image
|
||||||
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(value().value()));
|
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(value().value()));
|
||||||
if (it != style().choice_images.end()) {
|
if (it != style().choice_images.end() && it->second.isReady()) {
|
||||||
ScriptableImage& img = it->second;
|
ScriptableImage& img = it->second;
|
||||||
ScriptImageP i;
|
GeneratedImage::Options img_options(0,0, viewer.stylesheet.get(), &getSet());
|
||||||
if (nativeLook()) {
|
if (nativeLook()) {
|
||||||
i = img.update(viewer.getContext(), *viewer.stylesheet, 16, 16, ASPECT_BORDER, false);
|
img_options.width = img_options.height = 16;
|
||||||
|
img_options.preserve_aspect = ASPECT_BORDER;
|
||||||
} else if(style().render_style & RENDER_TEXT) {
|
} else if(style().render_style & RENDER_TEXT) {
|
||||||
// also drawing text
|
// also drawing text, use original size
|
||||||
i = img.update(viewer.getContext(), *viewer.stylesheet, 0, 0);
|
|
||||||
} else {
|
} else {
|
||||||
i = img.update(viewer.getContext(), *viewer.stylesheet,
|
img_options.width = (int) dc.trS(style().width);
|
||||||
(int) dc.trS(style().width), (int) dc.trS(style().height),
|
img_options.height = (int) dc.trS(style().height);
|
||||||
style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT
|
img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (i) {
|
Image image = img.generate(img_options, true);
|
||||||
// apply mask?
|
ImageCombine combine = img.combine();
|
||||||
style().loadMask(*viewer.stylesheet);
|
// apply mask?
|
||||||
if (style().mask.Ok()) {
|
style().loadMask(*viewer.stylesheet);
|
||||||
set_alpha(i->image, style().mask);
|
if (style().mask.Ok()) {
|
||||||
}
|
set_alpha(image, style().mask);
|
||||||
// draw
|
|
||||||
dc.DrawImage(i->image,
|
|
||||||
align_in_rect(style().alignment, RealSize(i->image.GetWidth(), i->image.GetHeight()), style().getRect()),
|
|
||||||
i->combine == COMBINE_NORMAL ? style().combine : i->combine,
|
|
||||||
style().angle
|
|
||||||
);
|
|
||||||
margin = dc.trInvS(i->image.GetWidth()) + 1;
|
|
||||||
}
|
}
|
||||||
|
// draw
|
||||||
|
dc.DrawImage(image,
|
||||||
|
align_in_rect(style().alignment, RealSize(image.GetWidth(), image.GetHeight()), style().getRect()),
|
||||||
|
combine == COMBINE_NORMAL ? style().combine : combine,
|
||||||
|
style().angle
|
||||||
|
);
|
||||||
|
margin = dc.trInvS(image.GetWidth()) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (style().render_style & RENDER_TEXT) {
|
if (style().render_style & RENDER_TEXT) {
|
||||||
@@ -57,3 +56,7 @@ void ChoiceValueViewer::draw(RotatedDC& dc) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChoiceValueViewer::onStyleChange() {
|
||||||
|
viewer.redraw(*this);
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class ChoiceValueViewer : public ValueViewer {
|
|||||||
DECLARE_VALUE_VIEWER(Choice) : ValueViewer(parent,style) {}
|
DECLARE_VALUE_VIEWER(Choice) : ValueViewer(parent,style) {}
|
||||||
|
|
||||||
virtual void draw(RotatedDC& dc);
|
virtual void draw(RotatedDC& dc);
|
||||||
|
virtual void onStyleChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ bool ColorValueViewer::containsPoint(const RealPoint& p) const {
|
|||||||
|
|
||||||
void ColorValueViewer::onStyleChange() {
|
void ColorValueViewer::onStyleChange() {
|
||||||
alpha_mask = AlphaMaskP();
|
alpha_mask = AlphaMaskP();
|
||||||
|
viewer.redraw(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorValueViewer::loadMask(const Rotation& rot) const {
|
void ColorValueViewer::loadMask(const Rotation& rot) const {
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ void ImageValueViewer::onValueChange() {
|
|||||||
void ImageValueViewer::onStyleChange() {
|
void ImageValueViewer::onStyleChange() {
|
||||||
bitmap = Bitmap();
|
bitmap = Bitmap();
|
||||||
alpha_mask = AlphaMaskP(); // TODO: only reload whatever has changed
|
alpha_mask = AlphaMaskP(); // TODO: only reload whatever has changed
|
||||||
|
viewer.redraw(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageValueViewer::loadMask(const Rotation& rot) const {
|
void ImageValueViewer::loadMask(const Rotation& rot) const {
|
||||||
|
|||||||
@@ -49,13 +49,12 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const
|
|||||||
}
|
}
|
||||||
if (style().render_style & RENDER_IMAGE) {
|
if (style().render_style & RENDER_IMAGE) {
|
||||||
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(choice));
|
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(choice));
|
||||||
if (it != style().choice_images.end()) {
|
if (it != style().choice_images.end() && it->second.isReady()) {
|
||||||
ScriptImageP i = it->second.update(viewer.getContext(), *viewer.stylesheet, 0, 0);
|
Image image = it->second.generate(GeneratedImage::Options(0,0, viewer.stylesheet.get(),&getSet()), true);
|
||||||
if (i) {
|
ImageCombine combine = it->second.combine();
|
||||||
// TODO : alignment?
|
// TODO : alignment?
|
||||||
dc.DrawImage(i->image, pos + RealSize(size.width, 0), i->combine == COMBINE_NORMAL ? style().combine : i->combine);
|
dc.DrawImage(image, pos + RealSize(size.width, 0), combine == COMBINE_NORMAL ? style().combine : combine);
|
||||||
size = add_horizontal(size, dc.trInv(RealSize(i->image.GetWidth() + 1, i->image.GetHeight())));
|
size = add_horizontal(size, dc.trInv(RealSize(image.GetWidth() + 1, image.GetHeight())));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (style().render_style & RENDER_TEXT) {
|
if (style().render_style & RENDER_TEXT) {
|
||||||
|
|||||||
@@ -36,4 +36,5 @@ void TextValueViewer::onValueChange() {
|
|||||||
|
|
||||||
void TextValueViewer::onStyleChange() {
|
void TextValueViewer::onStyleChange() {
|
||||||
v.reset();
|
v.reset();
|
||||||
|
viewer.redraw(*this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// ----------------------------------------------------------------------------- : ValueViewer
|
// ----------------------------------------------------------------------------- : ValueViewer
|
||||||
|
|
||||||
ValueViewer::ValueViewer(DataViewer& parent, const StyleP& style)
|
ValueViewer::ValueViewer(DataViewer& parent, const StyleP& style)
|
||||||
: viewer(parent), styleP(style)
|
: StyleListener(style), viewer(parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Set& ValueViewer::getSet() const { return *viewer.getSet(); }
|
Set& ValueViewer::getSet() const { return *viewer.getSet(); }
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ DECLARE_POINTER_TYPE(Value);
|
|||||||
|
|
||||||
/// The virtual viewer control for a single field on a card (or in the set data)
|
/// The virtual viewer control for a single field on a card (or in the set data)
|
||||||
/** A viewer can only display a value, not edit it, ValueEditor is used for that */
|
/** A viewer can only display a value, not edit it, ValueEditor is used for that */
|
||||||
class ValueViewer {
|
class ValueViewer : public StyleListener{
|
||||||
public:
|
public:
|
||||||
/// Construct a ValueViewer, set the value at a later time
|
/// Construct a ValueViewer, set the value at a later time
|
||||||
ValueViewer(DataViewer& parent, const StyleP& style);
|
ValueViewer(DataViewer& parent, const StyleP& style);
|
||||||
@@ -62,7 +62,6 @@ class ValueViewer {
|
|||||||
|
|
||||||
DataViewer& viewer; ///< Our parent object
|
DataViewer& viewer; ///< Our parent object
|
||||||
protected:
|
protected:
|
||||||
StyleP styleP; ///< The style of this viewer
|
|
||||||
ValueP valueP; ///< The value we are currently viewing
|
ValueP valueP; ///< The value we are currently viewing
|
||||||
|
|
||||||
/// Should this viewer render using a platform native look?
|
/// Should this viewer render using a platform native look?
|
||||||
|
|||||||
@@ -14,39 +14,21 @@
|
|||||||
#include <data/stylesheet.hpp>
|
#include <data/stylesheet.hpp>
|
||||||
#include <data/symbol.hpp>
|
#include <data/symbol.hpp>
|
||||||
#include <data/field/symbol.hpp>
|
#include <data/field/symbol.hpp>
|
||||||
#include <render/symbol/filter.hpp>
|
|
||||||
#include <gui/util.hpp> // load_resource_image
|
|
||||||
|
|
||||||
#include <gfx/generated_image.hpp>
|
#include <gfx/generated_image.hpp>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(SymbolVariationP);
|
DECLARE_TYPEOF_COLLECTION(SymbolVariationP);
|
||||||
|
|
||||||
bool parse_enum(const String&, ImageCombine& out);
|
bool parse_enum(const String&, ImageCombine& out);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Macros
|
|
||||||
|
|
||||||
#define SCRIPT_IMAGE_FUNCTION(name) \
|
|
||||||
SCRIPT_FUNCTION(name) { \
|
|
||||||
if (last_update_age() == 0)
|
|
||||||
#define SCRIPT_IMAGE_FUNCTION_UP_TO_DATE }
|
|
||||||
|
|
||||||
template <> inline ScriptImageP from_script<ScriptImageP>(const ScriptValueP& value) {
|
|
||||||
return to_script_image(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SCRIPT_IMAGE_PARAM_UP_TO_DATE(name) script_image_up_to_date(ctx.getVariable(_(#name)))
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Utility
|
// ----------------------------------------------------------------------------- : Utility
|
||||||
|
|
||||||
// TODO : use this system
|
|
||||||
|
|
||||||
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
|
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
|
||||||
return image_from_script(value);
|
return image_from_script(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Image functions
|
// ----------------------------------------------------------------------------- : Image functions
|
||||||
|
|
||||||
SCRIPT_FUNCTION(linear_blend2) {
|
SCRIPT_FUNCTION(linear_blend) {
|
||||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||||
@@ -54,14 +36,14 @@ SCRIPT_FUNCTION(linear_blend2) {
|
|||||||
return new_intrusive6<LinearBlendImage>(image1, image2, x1,y1, x2,y2);
|
return new_intrusive6<LinearBlendImage>(image1, image2, x1,y1, x2,y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(masked_blend2) {
|
SCRIPT_FUNCTION(masked_blend) {
|
||||||
SCRIPT_PARAM(GeneratedImageP, light);
|
SCRIPT_PARAM(GeneratedImageP, light);
|
||||||
SCRIPT_PARAM(GeneratedImageP, dark);
|
SCRIPT_PARAM(GeneratedImageP, dark);
|
||||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||||
return new_intrusive3<MaskedBlendImage>(light, dark, mask);
|
return new_intrusive3<MaskedBlendImage>(light, dark, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(combine_blend2) {
|
SCRIPT_FUNCTION(combine_blend) {
|
||||||
SCRIPT_PARAM(String, combine);
|
SCRIPT_PARAM(String, combine);
|
||||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||||
@@ -72,13 +54,13 @@ SCRIPT_FUNCTION(combine_blend2) {
|
|||||||
return new_intrusive3<CombineBlendImage>(image1, image2, image_combine);
|
return new_intrusive3<CombineBlendImage>(image1, image2, image_combine);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(set_mask2) {
|
SCRIPT_FUNCTION(set_mask) {
|
||||||
SCRIPT_PARAM(GeneratedImageP, image);
|
SCRIPT_PARAM(GeneratedImageP, image);
|
||||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||||
return new_intrusive2<SetMaskImage>(image, mask);
|
return new_intrusive2<SetMaskImage>(image, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(set_combine2) {
|
SCRIPT_FUNCTION(set_combine) {
|
||||||
SCRIPT_PARAM(String, combine);
|
SCRIPT_PARAM(String, combine);
|
||||||
SCRIPT_PARAM(GeneratedImageP, input);
|
SCRIPT_PARAM(GeneratedImageP, input);
|
||||||
ImageCombine image_combine;
|
ImageCombine image_combine;
|
||||||
@@ -88,7 +70,7 @@ SCRIPT_FUNCTION(set_combine2) {
|
|||||||
return new_intrusive2<SetCombineImage>(input, image_combine);
|
return new_intrusive2<SetCombineImage>(input, image_combine);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(symbol_variation2) {
|
SCRIPT_FUNCTION(symbol_variation) {
|
||||||
// find symbol
|
// find symbol
|
||||||
SCRIPT_PARAM(ValueP, symbol);
|
SCRIPT_PARAM(ValueP, symbol);
|
||||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
||||||
@@ -108,125 +90,11 @@ SCRIPT_FUNCTION(symbol_variation2) {
|
|||||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(built_in_image2) {
|
SCRIPT_FUNCTION(built_in_image) {
|
||||||
SCRIPT_PARAM(String, input);
|
SCRIPT_PARAM(String, input);
|
||||||
return new_intrusive1<BuiltInImage>(input);
|
return new_intrusive1<BuiltInImage>(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Image functions
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(linear_blend) {
|
|
||||||
SCRIPT_PARAM(ScriptImageP, image1);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, image2);
|
|
||||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
|
||||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
|
||||||
linear_blend(image1->image, image2->image, x1, y1, x2, y2);
|
|
||||||
return image1;
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(masked_blend) {
|
|
||||||
SCRIPT_PARAM(ScriptImageP, light);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, dark);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, mask);
|
|
||||||
mask_blend(light->image, dark->image, mask->image);
|
|
||||||
return light;
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(light) &&
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(dark) &&
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(combine_blend) {
|
|
||||||
SCRIPT_PARAM(String, combine);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, image1);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, image2);
|
|
||||||
if (!parse_enum(combine, image1->combine)) {
|
|
||||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
|
||||||
}
|
|
||||||
combine_image(image1->image, image2->image, image1->combine);
|
|
||||||
return image1;
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image1) &&
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(set_mask) {
|
|
||||||
SCRIPT_PARAM(ScriptImageP, image);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, mask);
|
|
||||||
set_alpha(image->image, mask->image);
|
|
||||||
return image;
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(image) &&
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(mask)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(set_combine) {
|
|
||||||
SCRIPT_PARAM(String, combine);
|
|
||||||
SCRIPT_PARAM(ScriptImageP, input);
|
|
||||||
// parse and set combine
|
|
||||||
if (!parse_enum(combine, input->combine)) {
|
|
||||||
throw ScriptError(_("Not a valid combine mode: '") + combine + _("'"));
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(
|
|
||||||
SCRIPT_IMAGE_PARAM_UP_TO_DATE(input)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(symbol_variation) {
|
|
||||||
SCRIPT_PARAM(ValueP, symbol);
|
|
||||||
SymbolValueP value = dynamic_pointer_cast<SymbolValue>(symbol);
|
|
||||||
SCRIPT_PARAM(String, variation);
|
|
||||||
// find set & style
|
|
||||||
SCRIPT_PARAM(Set*, set);
|
|
||||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
|
||||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetFor(card)->styleFor(value->fieldP));
|
|
||||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
|
||||||
// load symbol
|
|
||||||
SymbolP the_symbol;
|
|
||||||
if (value->filename.empty()) {
|
|
||||||
the_symbol = default_symbol();
|
|
||||||
} else {
|
|
||||||
the_symbol = set->readFile<SymbolP>(value->filename);
|
|
||||||
}
|
|
||||||
// determine filter & render
|
|
||||||
FOR_EACH(v, style->variations) {
|
|
||||||
if (v->name == variation) {
|
|
||||||
// render & filter
|
|
||||||
return new_intrusive1<ScriptImage>(render_symbol(the_symbol, *v->filter, v->border_radius));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
// SCRIPT_RETURN(last_update_age() >= value->filename.last_update_age);
|
|
||||||
SCRIPT_RETURN(last_update_age() > 1); // the symbol was created/loaded after program start,
|
|
||||||
// don't use cached images
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRIPT_IMAGE_FUNCTION(buildin_image) {
|
|
||||||
SCRIPT_PARAM(String, input);
|
|
||||||
Image img = load_resource_image(input);
|
|
||||||
if (!img.Ok()) {
|
|
||||||
throw ScriptError(_("There is no build in image '") + input + _("'"));
|
|
||||||
}
|
|
||||||
return new_intrusive1<ScriptImage>(img);
|
|
||||||
SCRIPT_IMAGE_FUNCTION_UP_TO_DATE
|
|
||||||
SCRIPT_RETURN(true); // always up to date
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Init
|
// ----------------------------------------------------------------------------- : Init
|
||||||
|
|
||||||
void init_script_image_functions(Context& ctx) {
|
void init_script_image_functions(Context& ctx) {
|
||||||
@@ -236,5 +104,5 @@ void init_script_image_functions(Context& ctx) {
|
|||||||
ctx.setVariable(_("set mask"), script_set_mask);
|
ctx.setVariable(_("set mask"), script_set_mask);
|
||||||
ctx.setVariable(_("set combine"), script_set_combine);
|
ctx.setVariable(_("set combine"), script_set_combine);
|
||||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||||
ctx.setVariable(_("buildin image"), script_buildin_image);
|
ctx.setVariable(_("built in image"), script_built_in_image);
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-172
@@ -11,8 +11,7 @@
|
|||||||
#include <script/to_value.hpp>
|
#include <script/to_value.hpp>
|
||||||
#include <util/dynamic_arg.hpp>
|
#include <util/dynamic_arg.hpp>
|
||||||
#include <util/io/package.hpp>
|
#include <util/io/package.hpp>
|
||||||
|
#include <gfx/generated_image.hpp>
|
||||||
IMPLEMENT_DYNAMIC_ARG(Package*, load_images_from, nullptr);
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Utility
|
// ----------------------------------------------------------------------------- : Utility
|
||||||
|
|
||||||
@@ -27,167 +26,76 @@ GeneratedImageP image_from_script(const ScriptValueP& value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptableImage2
|
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||||
|
|
||||||
Image ScriptableImage2::generate(const GeneratedImage::Options& options, bool cache) const {
|
Image ScriptableImage::generate(const GeneratedImage::Options& options, bool cache) const {
|
||||||
if (!isReady()) {
|
if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) {
|
||||||
|
// cached, so we are done
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
// generate
|
||||||
|
Image image;
|
||||||
|
if (isReady()) {
|
||||||
|
image = value->generate(options);
|
||||||
|
} else {
|
||||||
// error, return blank image
|
// error, return blank image
|
||||||
Image i(1,1);
|
Image i(1,1);
|
||||||
i.InitAlpha();
|
i.InitAlpha();
|
||||||
i.SetAlpha(0,0,0);
|
i.SetAlpha(0,0,0);
|
||||||
return i;
|
image = i;
|
||||||
}
|
}
|
||||||
if (cached.Ok() && cached.GetWidth() == options.width && cached.GetHeight() == options.height) {
|
// resize?
|
||||||
return cached;
|
int iw = image.GetWidth(), ih = image.GetHeight();
|
||||||
|
if ((iw == options.width && ih == options.height) || options.width == 0 || options.height == 0) {
|
||||||
|
// already the right size
|
||||||
|
} else if (options.preserve_aspect == ASPECT_FIT) {
|
||||||
|
// determine actual size of resulting image
|
||||||
|
int w, h;
|
||||||
|
if (iw * options.height > ih * options.width) { // too much height requested
|
||||||
|
w = options.width;
|
||||||
|
h = options.width * ih / iw;
|
||||||
|
} else {
|
||||||
|
w = options.height * iw / ih;
|
||||||
|
h = options.height;
|
||||||
|
}
|
||||||
|
Image resampled_image(w, h, false);
|
||||||
|
resample(image, resampled_image);
|
||||||
|
image = resampled_image;
|
||||||
|
} else {
|
||||||
|
Image resampled_image(options.width, options.height, false);
|
||||||
|
if (options.preserve_aspect == ASPECT_BORDER && (options.width < options.height * 3) && (options.height < options.width * 3)) {
|
||||||
|
// preserve the aspect ratio if there is not too much difference
|
||||||
|
resample_preserve_aspect(image, resampled_image);
|
||||||
|
} else {
|
||||||
|
resample(image, resampled_image);
|
||||||
|
}
|
||||||
|
image = resampled_image;
|
||||||
}
|
}
|
||||||
Image img = value->generate(options);
|
if (options.saturate) {
|
||||||
if (cache) cached = img;
|
saturate(image, 40);
|
||||||
return img;
|
}
|
||||||
|
// cache? and return
|
||||||
|
if (cache) cached = image;
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCombine ScriptableImage2::combine() const {
|
ImageCombine ScriptableImage::combine() const {
|
||||||
if (!isReady()) return COMBINE_NORMAL;
|
if (!isReady()) return COMBINE_NORMAL;
|
||||||
return value->combine();
|
return value->combine();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScriptableImage2::update(Context& ctx) {
|
bool ScriptableImage::update(Context& ctx) {
|
||||||
if (!isScripted()) return false;
|
if (!isScripted()) return false;
|
||||||
GeneratedImageP new_value = image_from_script(script.invoke(ctx));
|
GeneratedImageP new_value = image_from_script(script.invoke(ctx));
|
||||||
if (!new_value || !value || *new_value != *value) {
|
if (!new_value || !value || *new_value != *value) {
|
||||||
value = new_value;
|
value = new_value;
|
||||||
|
cached = Image();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptImage
|
|
||||||
|
|
||||||
ScriptType ScriptImage::type() const { return SCRIPT_IMAGE; }
|
|
||||||
String ScriptImage::typeName() const { return _("image"); }
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Utility
|
|
||||||
|
|
||||||
/// Convert a script value to an image
|
|
||||||
ScriptImageP to_script_image(const ScriptValueP& value) {
|
|
||||||
if (ScriptImageP img = dynamic_pointer_cast<ScriptImage>(value)) {
|
|
||||||
return img; // already an image
|
|
||||||
} else if (value->type() == SCRIPT_STRING) {
|
|
||||||
// open a file
|
|
||||||
String filename = *value;
|
|
||||||
Package* pkg = load_images_from();
|
|
||||||
if (!pkg) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
|
||||||
InputStreamP file = pkg->openIn(filename);
|
|
||||||
ScriptImageP img = new_intrusive<ScriptImage>();
|
|
||||||
if (img->image.LoadFile(*file)) {
|
|
||||||
if (img->image.HasMask()) img->image.InitAlpha(); // we can't handle masks
|
|
||||||
return img;
|
|
||||||
} else {
|
|
||||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '" + pkg->name() + _("'")));
|
|
||||||
}
|
|
||||||
} else if (value->type() == SCRIPT_NIL) {
|
|
||||||
// error, return blank image
|
|
||||||
Image i(1,1);
|
|
||||||
i.InitAlpha();
|
|
||||||
i.SetAlpha(0,0,0);
|
|
||||||
return new_intrusive1<ScriptImage>(i);
|
|
||||||
} else {
|
|
||||||
throw ScriptError(_("Can not convert from '") + value->typeName() + _("' to image"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the given image up to date?
|
|
||||||
bool script_image_up_to_date(const ScriptValueP& value) {
|
|
||||||
if (value->type() == SCRIPT_INT) {
|
|
||||||
return (bool)*value; // boolean up-to-dateness from parameter
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
|
||||||
|
|
||||||
ScriptableImage::ScriptableImage(const String& script_)
|
|
||||||
: script(script_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
ScriptImageP ScriptableImage::generate(Context& ctx, Package& pkg) const {
|
|
||||||
try {
|
|
||||||
WITH_DYNAMIC_ARG(load_images_from, &pkg);
|
|
||||||
ScriptImageP img = to_script_image(script.invoke(ctx));
|
|
||||||
return img;
|
|
||||||
} catch (Error e) {
|
|
||||||
// loading images can fail
|
|
||||||
// it is likely we are inside a paint function or outside the main thread, handle error later
|
|
||||||
handle_error(e, false, false);
|
|
||||||
return new_intrusive1<ScriptImage>(Image(1,1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptImageP ScriptableImage::generate(Context& ctx, Package& pkg, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) const {
|
|
||||||
ScriptImageP image = generate(ctx, pkg);
|
|
||||||
if (!image->image.Ok()) {
|
|
||||||
// return an image so we don't fail
|
|
||||||
image->image = Image(1,1);
|
|
||||||
}
|
|
||||||
UInt iw = image->image.GetWidth(), ih = image->image.GetHeight();
|
|
||||||
if ((iw == width && ih == height) || width == 0) {
|
|
||||||
// already the right size
|
|
||||||
} else if (preserve_aspect == ASPECT_FIT) {
|
|
||||||
// determine actual size of resulting image
|
|
||||||
UInt w, h;
|
|
||||||
if (iw * height > ih * width) { // too much height requested
|
|
||||||
w = width;
|
|
||||||
h = width * ih / iw;
|
|
||||||
} else {
|
|
||||||
w = height * iw / ih;
|
|
||||||
h = height;
|
|
||||||
}
|
|
||||||
Image resampled_image(w, h, false);
|
|
||||||
resample(image->image, resampled_image);
|
|
||||||
image->image = resampled_image;
|
|
||||||
} else {
|
|
||||||
Image resampled_image(width, height, false);
|
|
||||||
if (preserve_aspect == ASPECT_BORDER && (width < height * 3) && (height < width * 3)) {
|
|
||||||
// preserve the aspect ratio if there is not too much difference
|
|
||||||
resample_preserve_aspect(image->image, resampled_image);
|
|
||||||
} else {
|
|
||||||
resample(image->image, resampled_image);
|
|
||||||
}
|
|
||||||
image->image = resampled_image;
|
|
||||||
}
|
|
||||||
if (saturate) {
|
|
||||||
::saturate(image->image, 40);
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptImageP ScriptableImage::update(Context& ctx, Package& pkg, UInt width, UInt height, PreserveAspect preserve_aspect, bool saturate) {
|
|
||||||
// up to date?
|
|
||||||
if (!cache || (UInt)cache->image.GetWidth() != width || (UInt)cache->image.GetHeight() != height || !upToDate(ctx, last_update)) {
|
|
||||||
// cache must be updated
|
|
||||||
cache = generate(ctx, pkg, width, height, preserve_aspect, saturate);
|
|
||||||
last_update.update();
|
|
||||||
}
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScriptableImage::upToDate(Context& ctx, Age age) const {
|
|
||||||
if (!script) return true;
|
|
||||||
try {
|
|
||||||
WITH_DYNAMIC_ARG(last_update_age, age.get());
|
|
||||||
return script_image_up_to_date(script.invoke(ctx));
|
|
||||||
} catch (Error e) {
|
|
||||||
return true; // script gives errors, don't update
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reflection
|
// ----------------------------------------------------------------------------- : Reflection
|
||||||
|
|
||||||
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
||||||
@@ -200,10 +108,8 @@ template <> void Reader::handle(ScriptableImage& s) {
|
|||||||
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
||||||
s.script.parse(*this, true);
|
s.script.parse(*this, true);
|
||||||
} else {
|
} else {
|
||||||
// script is a constant function
|
// a filename
|
||||||
s.script.script = new_intrusive<Script>();
|
s.value = new_intrusive1<PackagedImage>(s.script.unparsed);
|
||||||
s.script.script->addInstruction(I_PUSH_CONST, s.script.unparsed);
|
|
||||||
s.script.script->addInstruction(I_RET);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <> void Writer::handle(const ScriptableImage& s) {
|
template <> void Writer::handle(const ScriptableImage& s) {
|
||||||
@@ -212,31 +118,3 @@ template <> void Writer::handle(const ScriptableImage& s) {
|
|||||||
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
|
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
|
||||||
handle(s.script.unparsed);
|
handle(s.script.unparsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Reflection
|
|
||||||
|
|
||||||
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
|
|
||||||
|
|
||||||
template <> void Reader::handle(ScriptableImage2& s) {
|
|
||||||
handle(s.script.unparsed);
|
|
||||||
if (starts_with(s.script.unparsed, _("script:"))) {
|
|
||||||
s.script.unparsed = s.script.unparsed.substr(7);
|
|
||||||
s.script.parse(*this);
|
|
||||||
} else if (s.script.unparsed.find_first_of('{') != String::npos) {
|
|
||||||
s.script.parse(*this, true);
|
|
||||||
} else {
|
|
||||||
// script is a constant function
|
|
||||||
s.script.script = new_intrusive<Script>();
|
|
||||||
s.script.script->addInstruction(I_PUSH_CONST, s.script.unparsed);
|
|
||||||
s.script.script->addInstruction(I_RET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <> void Writer::handle(const ScriptableImage2& s) {
|
|
||||||
handle(s.script.unparsed);
|
|
||||||
}
|
|
||||||
template <> void GetDefaultMember::handle(const ScriptableImage2& s) {
|
|
||||||
handle(s.script.unparsed);
|
|
||||||
}
|
|
||||||
|
|||||||
+5
-85
@@ -13,13 +13,8 @@
|
|||||||
#include <util/age.hpp>
|
#include <util/age.hpp>
|
||||||
#include <util/dynamic_arg.hpp>
|
#include <util/dynamic_arg.hpp>
|
||||||
#include <script/scriptable.hpp>
|
#include <script/scriptable.hpp>
|
||||||
//%%#include <gfx/gfx.hpp>
|
|
||||||
#include <gfx/generated_image.hpp>
|
#include <gfx/generated_image.hpp>
|
||||||
|
|
||||||
class Package;
|
|
||||||
DECLARE_INTRUSIVE_POINTER_TYPE(ScriptImage); //%% OLD
|
|
||||||
DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage); //%% OLD
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
// ----------------------------------------------------------------------------- : ScriptableImage
|
||||||
|
|
||||||
/// An image that can also be scripted
|
/// An image that can also be scripted
|
||||||
@@ -28,10 +23,11 @@ DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage); //%% OLD
|
|||||||
* - Age is checked, chached images are used if possible
|
* - Age is checked, chached images are used if possible
|
||||||
* - The image can be scaled
|
* - The image can be scaled
|
||||||
*/
|
*/
|
||||||
class ScriptableImage2 {
|
class ScriptableImage {
|
||||||
public:
|
public:
|
||||||
inline ScriptableImage2() {}
|
inline ScriptableImage() {}
|
||||||
inline ScriptableImage2(const String& script) : script(script) {}
|
inline ScriptableImage(const String& script) : script(script) {}
|
||||||
|
inline ScriptableImage(const GeneratedImageP& gen) : value(gen) {}
|
||||||
|
|
||||||
/// Is there an image set?
|
/// Is there an image set?
|
||||||
inline bool isScripted() const { return script; }
|
inline bool isScripted() const { return script; }
|
||||||
@@ -59,86 +55,10 @@ class ScriptableImage2 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Missing for now
|
/// Missing for now
|
||||||
inline ScriptValueP to_script(const ScriptableImage2&) { return script_nil; }
|
inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
|
||||||
|
|
||||||
/// Convert a script value to a GeneratedImageP
|
/// Convert a script value to a GeneratedImageP
|
||||||
GeneratedImageP image_from_script(const ScriptValueP& value);
|
GeneratedImageP image_from_script(const ScriptValueP& value);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ScriptableImage
|
|
||||||
//%% OLD
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_ARG(Package*, load_images_from);
|
|
||||||
|
|
||||||
/// An image, returned by a script function
|
|
||||||
class ScriptImage : public ScriptValue {
|
|
||||||
public:
|
|
||||||
inline ScriptImage() : combine(COMBINE_NORMAL) {}
|
|
||||||
inline ScriptImage(const Image& image, ImageCombine combine = COMBINE_NORMAL)
|
|
||||||
: image(image), combine(combine)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Image image; ///< The image
|
|
||||||
ImageCombine combine; ///< How to combine the image with the background
|
|
||||||
|
|
||||||
virtual ScriptType type() const;
|
|
||||||
virtual String typeName() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// An image that can also be scripted
|
|
||||||
/** Differs from Scriptable<Image> in that:
|
|
||||||
* - A script is always used
|
|
||||||
* - Age is checked, chached images are used if possible
|
|
||||||
* - The image can be scaled
|
|
||||||
*/
|
|
||||||
class ScriptableImage {
|
|
||||||
public:
|
|
||||||
inline ScriptableImage() {}
|
|
||||||
ScriptableImage(const String& script);
|
|
||||||
|
|
||||||
/// Is there an image set?
|
|
||||||
inline operator bool() const { return script; }
|
|
||||||
|
|
||||||
/// Generate an image, doesn't cache, and doesn't scale
|
|
||||||
/** Image files are loaded from the given package.
|
|
||||||
* The result is always valid. */
|
|
||||||
ScriptImageP generate(Context& ctx, Package&) const;
|
|
||||||
/// Generate an image, scaling it and optionally saturating it
|
|
||||||
ScriptImageP generate(Context& ctx, Package&, UInt width, UInt height, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false) const;
|
|
||||||
|
|
||||||
/// Update and return the cached image
|
|
||||||
/** Only recomputes the image if it is out of date, or the size doesn't match.
|
|
||||||
* If width==height==0 then doesn't resample.
|
|
||||||
*/
|
|
||||||
ScriptImageP update(Context& ctx, Package&, UInt width = 0, UInt height = 0, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false);
|
|
||||||
|
|
||||||
/// Is the cached image up to date?
|
|
||||||
bool upToDate(Context& ctx, Age age) const;
|
|
||||||
|
|
||||||
inline void initDependencies(Context& ctx, const Dependency& dep) const {
|
|
||||||
script.initDependencies(ctx, dep);
|
|
||||||
}
|
|
||||||
/// Invalidate the cached image
|
|
||||||
inline void invalidate() {
|
|
||||||
cache = ScriptImageP();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
OptionalScript script; ///< The script, not really optional
|
|
||||||
ScriptImageP cache; ///< The cached image
|
|
||||||
Age last_update; ///< Age of last image update of the cached image
|
|
||||||
|
|
||||||
DECLARE_REFLECTION();
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Missing for now
|
|
||||||
inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
|
|
||||||
|
|
||||||
/// Convert a script value to an image
|
|
||||||
ScriptImageP to_script_image(const ScriptValueP& value);
|
|
||||||
|
|
||||||
/// Is the given image up to date?
|
|
||||||
bool script_image_up_to_date(const ScriptValueP& value);
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Context& SetScriptContext::getContext(const CardP& card) {
|
|||||||
if (card) {
|
if (card) {
|
||||||
ctx.setVariable(_("card"), to_script(card));
|
ctx.setVariable(_("card"), to_script(card));
|
||||||
} else {
|
} else {
|
||||||
ctx.setVariable(_("card"), script_nil);
|
ctx.setVariable(_("card"), ScriptValueP());
|
||||||
}
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@@ -190,8 +190,9 @@ void SetScriptManager::updateStyles(const CardP& card) {
|
|||||||
// update all styles
|
// update all styles
|
||||||
FOR_EACH(s, stylesheet->card_style) {
|
FOR_EACH(s, stylesheet->card_style) {
|
||||||
if (s->update(ctx)) {
|
if (s->update(ctx)) {
|
||||||
|
s->tellListeners();
|
||||||
// style has changed, tell listeners
|
// style has changed, tell listeners
|
||||||
// ScriptStyleEvent change(s.get());
|
//%% ScriptStyleEvent change(stylesheet.get(), s.get());
|
||||||
// set->actions.tellListeners(change);
|
// set->actions.tellListeners(change);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,7 @@ void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Depen
|
|||||||
// because the index is not exact enough, it only gives the field
|
// because the index is not exact enough, it only gives the field
|
||||||
StyleSheet* stylesheet = reinterpret_cast<StyleSheet*>(d.data);
|
StyleSheet* stylesheet = reinterpret_cast<StyleSheet*>(d.data);
|
||||||
StyleP style = stylesheet->card_style.at(d.index);
|
StyleP style = stylesheet->card_style.at(d.index);
|
||||||
style->invalidate();
|
style->invalidate(getContext(card));
|
||||||
// something changed, send event
|
// something changed, send event
|
||||||
ScriptStyleEvent change(stylesheet, style.get());
|
ScriptStyleEvent change(stylesheet, style.get());
|
||||||
set.actions.tellListeners(change, false);
|
set.actions.tellListeners(change, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user