From 322e8715fc8cc09149752bb3f7c5407cccac5b55 Mon Sep 17 00:00:00 2001 From: twanvl Date: Wed, 29 Aug 2007 22:52:56 +0000 Subject: [PATCH] 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. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@650 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/field.hpp | 2 +- src/data/field/choice.cpp | 12 +++-------- src/data/field/choice.hpp | 8 +++---- src/gfx/generated_image.cpp | 9 +++++++- src/gfx/generated_image.hpp | 19 +++++++++++++++-- src/gui/control/card_editor.cpp | 3 ++- src/gui/set/cards_panel.cpp | 1 + src/gui/set/window.cpp | 2 ++ src/gui/value/choice.cpp | 31 ++++++++++++++++------------ src/render/text/element.cpp | 10 ++++----- src/render/value/multiple_choice.cpp | 11 ++++++---- src/script/image.hpp | 5 ++++- src/script/script_manager.cpp | 2 +- src/util/rotation.hpp | 2 ++ 14 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/data/field.hpp b/src/data/field.hpp index 9242e28b..01e815db 100644 --- a/src/data/field.hpp +++ b/src/data/field.hpp @@ -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*); diff --git a/src/data/field/choice.cpp b/src/data/field/choice.cpp index a36cd354..a2f9051c 100644 --- a/src/data/field/choice.cpp +++ b/src/data/field/choice.cpp @@ -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) { diff --git a/src/data/field/choice.hpp b/src/data/field/choice.hpp index 763b858e..bc33e8a6 100644 --- a/src/data/field/choice.hpp +++ b/src/data/field/choice.hpp @@ -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(); diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index 0010a879..b1923c40 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -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; diff --git a/src/gfx/generated_image.hpp b/src/gfx/generated_image.hpp index b8e9d8ad..38435d41 100644 --- a/src/gfx/generated_image.hpp +++ b/src/gfx/generated_image.hpp @@ -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; diff --git a/src/gui/control/card_editor.cpp b/src/gui/control/card_editor.cpp index e0d83595..8fca0501 100644 --- a/src/gui/control/card_editor.cpp +++ b/src/gui/control/card_editor.cpp @@ -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) { diff --git a/src/gui/set/cards_panel.cpp b/src/gui/set/cards_panel.cpp index 03ca4420..6de4cd5e 100644 --- a/src/gui/set/cards_panel.cpp +++ b/src/gui/set/cards_panel.cpp @@ -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) { diff --git a/src/gui/set/window.cpp b/src/gui/set/window.cpp index f22463a7..919827db 100644 --- a/src/gui/set/window.cpp +++ b/src/gui/set/window.cpp @@ -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 diff --git a/src/gui/value/choice.cpp b/src/gui/value/choice.cpp index fa57afec..d67925a5 100644 --- a/src/gui/value/choice.cpp +++ b/src/gui/value/choice.cpp @@ -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(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(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(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(&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( + &cve, i, status == THUMB_NOT_MADE && !img.local(), img.threadSafe() + )); + } } } } diff --git a/src/render/text/element.cpp b/src/render/text/element.cpp index 5a6ff19f..131b22b0 100644 --- a/src/render/text/element.cpp +++ b/src/render/text/element.cpp @@ -98,9 +98,13 @@ struct TextElementsFromString { else if (is_substr(text, tag_start, _("::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) { diff --git a/src/script/image.hpp b/src/script/image.hpp index 92ecb6ba..ee587c23 100644 --- a/src/script/image.hpp +++ b/src/script/image.hpp @@ -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 diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index dd81fcc4..0e2d498a 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -357,7 +357,7 @@ void SetScriptManager::alsoUpdate(deque& to_update, const vector(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); diff --git a/src/util/rotation.hpp b/src/util/rotation.hpp index 149dd811..cbbbb4e9 100644 --- a/src/util/rotation.hpp +++ b/src/util/rotation.hpp @@ -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