Commit b23c722e authored by twanvl's avatar twanvl

Fixed: choice images were generated with the wrong context from invalidate()

Choice thumbnails are now checked to not be 'local' before reading from cache, fixes issue with wrong rarity symbol in the drop down list;
Disabled unimplemented menu items;
Multiple choice items for RENDER_LIST are now zoomed, and positioning is on rotated cards is fixed.
parent 1975ba7a
......@@ -135,7 +135,7 @@ class Style : public IntrusivePtrVirtualBase {
/** In particular, if dep == DEP_DUMMY and name is a content property, set dep.index=true */
virtual void markDependencyMember(const String& name, const Dependency&) const;
/// Invalidate scripted images for this style
virtual void invalidate(Context&) {}
virtual void invalidate() {}
/// Add a StyleListener
void addListener(StyleListener*);
......
......@@ -239,21 +239,15 @@ void ChoiceStyle::initDependencies(Context& ctx, const Dependency& dep) const {
ci.second.initDependencies(ctx, dep);
}
}
void ChoiceStyle::invalidate(Context& ctx) {
void ChoiceStyle::invalidate() {
// TODO : this is also done in update(), once should be enough
// Update choice images and thumbnails
bool change = false;
int end = field().choices->lastId();
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_status[i] == THUMB_OK) thumbnails_status[i] = THUMB_CHANGED;
}
if (change) tellListeners(CHANGE_OTHER);
tellListeners(CHANGE_OTHER);
}
void ChoiceStyle::loadMask(Package& pkg) {
......
......@@ -130,9 +130,9 @@ enum ChoiceRenderStyle
};
enum ThumbnailStatus
{ THUMB_NOT_MADE
, THUMB_OK
, THUMB_CHANGED
{ THUMB_NOT_MADE // there is no image
, THUMB_OK // image is ok
, THUMB_CHANGED // there is an image, but it may need to be updated
};
/// The Style for a ChoiceField
......@@ -165,7 +165,7 @@ class ChoiceStyle : public Style {
virtual int update(Context&);
virtual void initDependencies(Context&, const Dependency&) const;
virtual void invalidate(Context&);
virtual void invalidate();
private:
DECLARE_REFLECTION();
......
......@@ -28,7 +28,14 @@ Image conform_image(const Image& img, const GeneratedImage::Options& options) {
// resize?
int iw = image.GetWidth(), ih = image.GetHeight();
if ((iw == options.width && ih == options.height) || (options.width == 0 && options.height == 0)) {
// already the right size
// zoom?
if (options.zoom != 1.0) {
Image resampled_image(iw * options.zoom, ih * options.zoom, false);
resample(image, resampled_image);
image = resampled_image;
} else {
// already the right size
}
} else if (options.height == 0) {
// width is given, determine height
int h = options.width * ih / iw;
......
......@@ -28,12 +28,13 @@ class GeneratedImage : public ScriptValue {
/// Options for generating the image
struct Options {
Options(int width = 0, int height = 0, Package* package = nullptr, Package* local_package = nullptr, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false)
: width(width), height(height), angle(0)
: width(width), height(height), zoom(1.0), angle(0)
, preserve_aspect(preserve_aspect), saturate(saturate)
, package(package), local_package(local_package)
{}
int width, height; ///< Width to force the image to, or 0 to keep the width of the input
double zoom; ///< Zoom factor to use, when witdth=height=0
int angle; ///< Angle to rotate image by afterwards
PreserveAspect preserve_aspect;
bool saturate;
......@@ -52,7 +53,10 @@ class GeneratedImage : public ScriptValue {
inline bool operator != (const GeneratedImage& that) const { return !(*this == that); }
/// Can this image be generated safely from another thread?
virtual bool threadSafe() const { return true; };
virtual bool threadSafe() const { return true; }
/// Is this image specific to the set (the local_package)?
virtual bool local() const { return false; }
virtual ScriptType type() const;
virtual String typeName() const;
......@@ -86,6 +90,7 @@ class LinearBlendImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image1->local() && image2->local(); }
private:
GeneratedImageP image1, image2;
double x1, y1, x2, y2;
......@@ -102,6 +107,7 @@ class MaskedBlendImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return light->local() && dark->local() && mask->local(); }
private:
GeneratedImageP light, dark, mask;
};
......@@ -117,6 +123,7 @@ class CombineBlendImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image1->local() && image2->local(); }
private:
GeneratedImageP image1, image2;
ImageCombine image_combine;
......@@ -133,6 +140,7 @@ class SetMaskImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local() && mask->local(); }
private:
GeneratedImageP image, mask;
};
......@@ -146,6 +154,7 @@ class SetAlphaImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
double alpha;
......@@ -162,6 +171,7 @@ class SetCombineImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
ImageCombine image_combine;
......@@ -178,6 +188,7 @@ class EnlargeImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
double border_size;
......@@ -194,6 +205,7 @@ class CropImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
double width, height;
......@@ -212,6 +224,7 @@ class DropShadowImage : public GeneratedImage {
virtual Image generate(const Options& opt) const;
virtual ImageCombine combine() const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return image->local(); }
private:
GeneratedImageP image;
double offset_x, offset_y;
......@@ -257,6 +270,7 @@ class SymbolToImage : public GeneratedImage {
~SymbolToImage();
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return true; }
#ifdef __WXGTK__
virtual bool threadSafe() const { return false; }
......@@ -277,6 +291,7 @@ class ImageValueToImage : public GeneratedImage {
~ImageValueToImage();
virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return true; }
private:
ImageValueToImage(const ImageValueToImage&); // copy ctor
String filename;
......
......@@ -206,7 +206,8 @@ void DataEditor::onRightDown(wxMouseEvent& ev) {
selectField(ev, &ValueEditor::onRightDown);
}
void DataEditor::onMouseWheel(wxMouseEvent& ev) {
if (current_editor) current_editor->onMouseWheel(mousePoint(ev), ev);
if (current_editor && current_editor->onMouseWheel(mousePoint(ev), ev));
else ev.Skip();
}
void DataEditor::onMotion(wxMouseEvent& ev) {
......
......@@ -160,6 +160,7 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
ev.Check(ss.card_angle() == a);
break;
}
case ID_CARD_ADD_MULT: ev.Enable(false); break; // not implemented
case ID_CARD_REMOVE: ev.Enable(set->cards.size() > 1); break;
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
if (focused_control(this) == ID_EDITOR) {
......
......@@ -397,6 +397,8 @@ void SetWindow::onUpdateUI(wxUpdateUIEvent& ev) {
case ID_EDIT_REPLACE : ev.Enable(current_panel->canReplace());break;
// windows
case ID_WINDOW_KEYWORDS: ev.Enable(set->game->has_keywords); break;
// help
case ID_HELP_INDEX : ev.Enable(false); break; // not implemented
// other
default:
// items created by the panel, and cut/copy/paste and find/replace
......
......@@ -20,7 +20,7 @@ DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
class ChoiceThumbnailRequest : public ThumbnailRequest {
public:
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk);
ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk, bool thread_safe);
virtual Image generate();
virtual void store(const Image&);
......@@ -34,22 +34,17 @@ class ChoiceThumbnailRequest : public ThumbnailRequest {
inline ValueViewer& viewer() { return *static_cast<ValueViewer*>(owner); }
};
ChoiceThumbnailRequest::ChoiceThumbnailRequest(ValueViewer* viewer, int id, bool from_disk)
ChoiceThumbnailRequest::ChoiceThumbnailRequest(ValueViewer* viewer, int id, bool from_disk, bool thread_safe)
: ThumbnailRequest(
static_cast<void*>(viewer),
viewer->viewer.stylesheet->name() + _("/") + viewer->getField()->name + _("/") << id,
from_disk ? viewer->viewer.stylesheet->lastModified()
: wxDateTime::Now()
)
, isThreadSafe(thread_safe)
, stylesheet(viewer->viewer.stylesheet)
, id(id)
{
assert(dynamic_pointer_cast<ChoiceStyle>(viewer->getStyle())); // only works on choice styles
ChoiceStyle& s = style();
String name = cannocial_name_form(s.field().choices->choiceName(id));
ScriptableImage img = s.choice_images[name];
isThreadSafe = img.threadSafe();
}
{}
Image ChoiceThumbnailRequest::generate() {
ChoiceStyle& s = style();
......@@ -184,8 +179,8 @@ void DropDownChoiceListBase::generateThumbnailImages() {
int image_count = style().thumbnails->GetImageCount();
int end = group->lastId();
// init choice images
Context& ctx = cve.viewer.getContext();
if (style().choice_images.empty() && style().image.isScripted()) {
Context& ctx = cve.viewer.getContext();
for (int i = 0 ; i < end ; ++i) {
try {
String name = cannocial_name_form(field().choices->choiceName(i));
......@@ -200,10 +195,20 @@ void DropDownChoiceListBase::generateThumbnailImages() {
// request thumbnails
style().thumbnails_status.resize(end, THUMB_NOT_MADE);
for (int i = 0 ; i < end ; ++i) {
ThumbnailStatus status = style().thumbnails_status[i];
ThumbnailStatus& status = style().thumbnails_status[i];
if (i >= image_count || status != THUMB_OK) {
// request this thumbnail
thumbnail_thread.request( new_intrusive3<ChoiceThumbnailRequest>(&cve, i, status == THUMB_NOT_MADE) );
// update image
ChoiceStyle& s = style();
String name = cannocial_name_form(s.field().choices->choiceName(i));
ScriptableImage& img = s.choice_images[name];
if (!img.update(ctx) && status == THUMB_CHANGED) {
status = THUMB_OK; // no need to rebuild
} else {
// request this thumbnail
thumbnail_thread.request( new_intrusive4<ChoiceThumbnailRequest>(
&cve, i, status == THUMB_NOT_MADE && !img.local(), img.threadSafe()
));
}
}
}
}
......
......@@ -98,9 +98,13 @@ struct TextElementsFromString {
else if (is_substr(text, tag_start, _("</i"))) italic -= 1;
else if (is_substr(text, tag_start, _( "<sym"))) symbol += 1;
else if (is_substr(text, tag_start, _("</sym"))) symbol -= 1;
else if (is_substr(text, tag_start, _( "<line"))) line += 1;
else if (is_substr(text, tag_start, _("</line"))) line -= 1;
else if (is_substr(text, tag_start, _( "<soft-line"))) soft_line += 1;
else if (is_substr(text, tag_start, _("</soft-line"))) soft_line -= 1;
else if (is_substr(text, tag_start, _( "<sep-soft"))) soft += 1;
else if (is_substr(text, tag_start, _("</sep-soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<soft"))) soft += 1;
else if (is_substr(text, tag_start, _( "<soft"))) soft += 1; // must be after <soft-line
else if (is_substr(text, tag_start, _("</soft"))) soft -= 1;
else if (is_substr(text, tag_start, _( "<atom-kwpph"))) kwpph += 1;
else if (is_substr(text, tag_start, _("</atom-kwpph"))) kwpph -= 1;
......@@ -125,10 +129,6 @@ struct TextElementsFromString {
else if (is_substr(text, tag_start, _("</ref-param"))) param_ref -= 1;
else if (is_substr(text, tag_start, _( "<atom-param"))) param += 1;
else if (is_substr(text, tag_start, _("</atom-param"))) param -= 1;
else if (is_substr(text, tag_start, _( "<line"))) line += 1;
else if (is_substr(text, tag_start, _("</line"))) line -= 1;
else if (is_substr(text, tag_start, _( "<soft-line"))) soft_line += 1;
else if (is_substr(text, tag_start, _("</soft-line"))) soft_line -= 1;
else if (is_substr(text, tag_start, _("<atom"))) {
// 'atomic' indicator
size_t end_tag = min(end, match_close_tag(text, tag_start));
......
......@@ -92,12 +92,15 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const
if (style().render_style & RENDER_IMAGE) {
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(choice));
if (it != style().choice_images.end() && it->second.isReady()) {
// TODO: scaling, caching
Image image = it->second.generate(GeneratedImage::Options(0,0, viewer.stylesheet.get(),&getSet()));
// TODO: caching
GeneratedImage::Options options(0,0, viewer.stylesheet.get(),&getSet());
options.zoom = dc.getZoom();
options.angle = dc.trAngle(style().angle);
Image image = it->second.generate(options);
ImageCombine combine = it->second.combine();
// TODO : alignment?
dc.DrawImage(image, pos + RealSize(size.width, 0), combine == COMBINE_DEFAULT ? style().combine : combine);
size = add_horizontal(size, dc.trInv(RealSize(image.GetWidth() + 1, image.GetHeight())));
dc.DrawPreRotatedImage(image, pos + RealSize(size.width, 0), combine == COMBINE_DEFAULT ? style().combine : combine);
size = add_horizontal(size, dc.trInvNoNeg(RealSize(image.GetWidth() + 1, image.GetHeight())));
}
}
if (style().render_style & RENDER_TEXT) {
......
......@@ -46,10 +46,13 @@ class ScriptableImage {
inline void initDependencies(Context& ctx, const Dependency& dep) const {
script.initDependencies(ctx, dep);
}
/// Can this be safely generated from another thread?
inline bool threadSafe() const { return !value || value->threadSafe(); }
/// Is this image specific to the set (the local_package)?
inline bool local() const { return value && value->local(); }
/// Get access to the script, be careful
inline Script& getScript() { return script.getScript(); }
/// Get access to the script, always returns a valid script
......
......@@ -357,7 +357,7 @@ void SetScriptManager::alsoUpdate(deque<ToUpdate>& to_update, const vector<Depen
// because the index is not exact enough, it only gives the field
StyleSheet* stylesheet = reinterpret_cast<StyleSheet*>(d.data);
StyleP style = stylesheet->card_style.at(d.index);
style->invalidate(getContext(card));
style->invalidate();
// something changed, send event
ScriptStyleEvent change(stylesheet, style.get());
set.actions.tellListeners(change, false);
......
......@@ -32,6 +32,8 @@ class Rotation {
/// Change the zoom factor
inline void setZoom(double z) { zoomX = zoomY = z; }
/// Retrieve the zoom factor
inline double getZoom() const { return zoomY; }
/// Change the angle
void setAngle(int a);
/// Change the origin
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment