mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
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
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
+18
-13
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user