Commit b99f6c32 authored by twanvl's avatar twanvl

Basic text rendering working;

Added Font (done) and SymbolFont (skeleton);
Added styling to set;
Added CountourMap;
Some script fixes
parent 843d312f
...@@ -93,7 +93,7 @@ IMPLEMENT_REFLECTION(Style) { ...@@ -93,7 +93,7 @@ IMPLEMENT_REFLECTION(Style) {
} }
void init_object(const FieldP& field, StyleP& style) { void init_object(const FieldP& field, StyleP& style) {
style = field->newStyle(field); if (!style) style = field->newStyle(field);
} }
template <> StyleP read_new<Style>(Reader&) { template <> StyleP read_new<Style>(Reader&) {
throw InternalError(_("IndexMap contains nullptr StyleP the application should have crashed already")); throw InternalError(_("IndexMap contains nullptr StyleP the application should have crashed already"));
...@@ -123,7 +123,7 @@ IMPLEMENT_REFLECTION_NAMELESS(Value) { ...@@ -123,7 +123,7 @@ IMPLEMENT_REFLECTION_NAMELESS(Value) {
} }
void init_object(const FieldP& field, ValueP& value) { void init_object(const FieldP& field, ValueP& value) {
value = field->newValue(field); if (!value) value = field->newValue(field);
} }
template <> ValueP read_new<Value>(Reader&) { template <> ValueP read_new<Value>(Reader&) {
throw InternalError(_("IndexMap contains nullptr ValueP the application should have crashed already")); throw InternalError(_("IndexMap contains nullptr ValueP the application should have crashed already"));
......
...@@ -99,7 +99,7 @@ class Style { ...@@ -99,7 +99,7 @@ class Style {
/// Update scripted values of this style, return true if anything has changed /// Update scripted values of this style, return true if anything has changed
virtual bool update(Context&); virtual bool update(Context&);
/// Add the given dependency to the dependet_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
virtual void initDependencies(Context&, const Dependency&) const; virtual void initDependencies(Context&, const Dependency&) const;
private: private:
......
...@@ -22,6 +22,12 @@ String TextField::typeName() const { ...@@ -22,6 +22,12 @@ String TextField::typeName() const {
return _("text"); return _("text");
} }
void TextField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep);
}
IMPLEMENT_REFLECTION(TextField) { IMPLEMENT_REFLECTION(TextField) {
REFLECT_BASE(Field); REFLECT_BASE(Field);
...@@ -48,10 +54,19 @@ TextStyle::TextStyle(const TextFieldP& field) ...@@ -48,10 +54,19 @@ TextStyle::TextStyle(const TextFieldP& field)
, line_height_line(1.0) , line_height_line(1.0)
{} {}
bool TextStyle::update(Context& ctx) {
return Style::update(ctx)
| font.update(ctx);
}
void TextStyle::initDependencies(Context& ctx, const Dependency& dep) const {
Style::initDependencies(ctx, dep);
font.initDependencies(ctx, dep);
}
IMPLEMENT_REFLECTION(TextStyle) { IMPLEMENT_REFLECTION(TextStyle) {
REFLECT_BASE(Style); REFLECT_BASE(Style);
// REFLECT(font); REFLECT(font);
// REFLECT(symbol_font); REFLECT(symbol_font);
REFLECT(always_symbol); REFLECT(always_symbol);
REFLECT(allow_formating); REFLECT(allow_formating);
REFLECT(alignment); REFLECT(alignment);
...@@ -75,6 +90,11 @@ IMPLEMENT_REFLECTION(TextStyle) { ...@@ -75,6 +90,11 @@ IMPLEMENT_REFLECTION(TextStyle) {
String TextValue::toString() const { String TextValue::toString() const {
return value(); return value();
} }
bool TextValue::update(Context& ctx) {
Value::update(ctx);
return field().default_script.invokeOnDefault(ctx, value)
| field(). script.invokeOn(ctx, value);
}
IMPLEMENT_REFLECTION_NAMELESS(TextValue) { IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
REFLECT_NAMELESS(value); REFLECT_NAMELESS(value);
......
...@@ -12,7 +12,10 @@ ...@@ -12,7 +12,10 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/defaultable.hpp> #include <util/defaultable.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/font.hpp>
#include <data/symbol_font.hpp>
#include <script/scriptable.hpp> #include <script/scriptable.hpp>
#include <gfx/gfx.hpp>
// ----------------------------------------------------------------------------- : TextField // ----------------------------------------------------------------------------- : TextField
...@@ -32,6 +35,8 @@ class TextField : public Field { ...@@ -32,6 +35,8 @@ class TextField : public Field {
bool move_cursor_with_sort; ///< When the text is reordered by a script should the cursor position be updated? bool move_cursor_with_sort; ///< When the text is reordered by a script should the cursor position be updated?
String default_name; ///< Name of "default" value String default_name; ///< Name of "default" value
virtual void initDependencies(Context&, const Dependency&) const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
...@@ -44,8 +49,8 @@ class TextStyle : public Style { ...@@ -44,8 +49,8 @@ class TextStyle : public Style {
TextStyle(const TextFieldP&); TextStyle(const TextFieldP&);
DECLARE_STYLE_TYPE(Text); DECLARE_STYLE_TYPE(Text);
// FontInfo font; ///< Font to use for the text Font font; ///< Font to use for the text
// SymbolFontInfo symbol_font; ///< Symbol font for symbols in the text SymbolFontRef symbol_font; ///< Symbol font for symbols in the text
bool always_symbol; ///< Should everything be drawn as symbols? bool always_symbol; ///< Should everything be drawn as symbols?
bool allow_formating; ///< Is formating (bold/italic/..) allowed? bool allow_formating; ///< Is formating (bold/italic/..) allowed?
Alignment alignment; ///< Alignment inside the box Alignment alignment; ///< Alignment inside the box
...@@ -58,7 +63,11 @@ class TextStyle : public Style { ...@@ -58,7 +63,11 @@ class TextStyle : public Style {
double line_height_hard; ///< Line height for hard linebreaks double line_height_hard; ///< Line height for hard linebreaks
double line_height_line; ///< Line height for <line> tags double line_height_line; ///< Line height for <line> tags
String mask_filename; ///< Filename of the mask String mask_filename; ///< Filename of the mask
// ContourMaskP mask; ///< Mask to fit the text to (may be null) ContourMask mask; ///< Mask to fit the text to (may be null)
virtual bool update(Context&);
virtual void initDependencies(Context&, const Dependency&) const;
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
...@@ -74,6 +83,8 @@ class TextValue : public Value { ...@@ -74,6 +83,8 @@ class TextValue : public Value {
Defaultable<String> value; ///< The text of this value Defaultable<String> value; ///< The text of this value
virtual String toString() const; virtual String toString() const;
virtual bool update(Context&);
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <data/font.hpp>
// ----------------------------------------------------------------------------- : Font
Font::Font()
: font(*wxNORMAL_FONT)
, size(font.GetPointSize())
, scale_down_to(100000)
, shadow_displacement(0,0)
, separator_color(128,128,128)
{}
bool Font::update(Context& ctx) {
return color .update(ctx)
| shadow_color.update(ctx);
}
void Font::initDependencies(Context& ctx, const Dependency& dep) const {
color .initDependencies(ctx, dep);
shadow_color.initDependencies(ctx, dep);
}
FontP Font::make(bool bold, bool italic) const {
FontP f(new Font(*this));
if (bold) f->font.SetWeight(wxBOLD);
if (italic) {
if (!italic_name.empty()) {
f->font.SetFaceName(italic_name);
} else {
f->font.SetWeight(wxBOLD);
}
}
return f;
}
void reflect_font(Reader& tag, Font& font) {
String name, weight, style;
double size = -1;
REFLECT(name);
REFLECT(size);
REFLECT(weight);
REFLECT(style);
if (!name.empty()) font.font.SetFaceName(name);
if (size > 0) font.font.SetPointSize(font.size = size);
if (!weight.empty()) font.font.SetWeight(weight == _("bold") ? wxBOLD : wxNORMAL);
if (!style.empty()) font.font.SetWeight(style == _("italic") ? wxITALIC : wxNORMAL);
}
template <typename Tag>
void reflect_font(Tag& tag, const Font& font) {
REFLECT_N("name", font.font.GetFaceName());
REFLECT_N("size", font.size);
REFLECT_N("weight", font.font.GetWeight() == wxBOLD ? _("bold") : _("normal"));
REFLECT_N("style", font.font.GetStyle() == wxITALIC ? _("italic") : _("normal"));
}
IMPLEMENT_REFLECTION(Font) {
reflect_font(tag, *this);
REFLECT(italic_name);
REFLECT(color);
REFLECT(scale_down_to);
REFLECT_N("shadow_displacement_x", shadow_displacement.width);
REFLECT_N("shadow_displacement_y", shadow_displacement.height);
REFLECT(shadow_color);
REFLECT(separator_color);
}
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_DATA_FONT
#define HEADER_DATA_FONT
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/real_point.hpp>
#include <script/scriptable.hpp>
DECLARE_POINTER_TYPE(Font);
// ----------------------------------------------------------------------------- : Font
/// A font for rendering text
/** Contains additional information about scaling, color and shadow */
class Font {
public:
wxFont font; ///< The actual wxFont to use
double size; ///< Size of the font
double scale_down_to; ///< Smallest size to scale down to
Scriptable<Color> color; ///< Color to use
Scriptable<Color> shadow_color; ///< Color for shadow
RealSize shadow_displacement; ///< Position of the shadow
String italic_name; ///< Font name for italic text (optional)
Color separator_color; ///< Color for <sep> text
Font();
/// Update the scritables, returns true if there is a change
bool update(Context& ctx);
/// Add the given dependency to the dependent_scripts list for the variables this font depends on
virtual void initDependencies(Context&, const Dependency&) const;
/// Does this font have a shadow?
inline bool hasShadow() { return shadow_displacement.width != 0 || shadow_displacement.height != 0; }
/// Make a bold/italic version of this font
FontP make(bool bold, bool italic) const;
private:
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : EOF
#endif
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <data/field/text.hpp> // for 0.2.7 fix #include <data/field/text.hpp> // for 0.2.7 fix
#include <script/value.hpp> #include <script/value.hpp>
#include <script/script_manager.hpp> #include <script/script_manager.hpp>
#include <wx/sstream.h>
DECLARE_TYPEOF_COLLECTION(CardP); DECLARE_TYPEOF_COLLECTION(CardP);
typedef IndexMap<FieldP,ValueP> IndexMap_FieldP_ValueP; typedef IndexMap<FieldP,ValueP> IndexMap_FieldP_ValueP;
...@@ -45,6 +46,9 @@ Context& Set::getContext() { ...@@ -45,6 +46,9 @@ Context& Set::getContext() {
Context& Set::getContext(const Card& card) { Context& Set::getContext(const Card& card) {
return script_manager->getContext(card.stylesheet ? card.stylesheet : stylesheet); return script_manager->getContext(card.stylesheet ? card.stylesheet : stylesheet);
} }
void Set::updateFor(const CardP& card) {
script_manager->updateStyles(card);
}
StyleSheetP Set::stylesheetFor(const CardP& card) { StyleSheetP Set::stylesheetFor(const CardP& card) {
if (card && card->stylesheet) return card->stylesheet; if (card && card->stylesheet) return card->stylesheet;
...@@ -90,8 +94,16 @@ void Set::validate(Version file_app_version) { ...@@ -90,8 +94,16 @@ void Set::validate(Version file_app_version) {
*/ } */ }
} }
// in scripts, set.something is read from the set_info
template <typename Tag>
void reflect_set_info_get_member(Tag& tag, const IndexMap<FieldP, ValueP>& data) {}
void reflect_set_info_get_member(GetMember& tag, const IndexMap<FieldP, ValueP>& data) {
REFLECT_NAMELESS(data);
}
IMPLEMENT_REFLECTION(Set) { IMPLEMENT_REFLECTION(Set) {
tag.addAlias(300, _("style"), _("stylesheet")); // < 0.3.0 used style instead of stylesheet tag.addAlias(300, _("style"), _("stylesheet")); // < 0.3.0 used style instead of stylesheet
tag.addAlias(300, _("extra set info"), _("styling"));
REFLECT(game); REFLECT(game);
if (game) { if (game) {
if (tag.reading()) { if (tag.reading()) {
...@@ -100,11 +112,54 @@ IMPLEMENT_REFLECTION(Set) { ...@@ -100,11 +112,54 @@ IMPLEMENT_REFLECTION(Set) {
WITH_DYNAMIC_ARG(game_for_reading, game.get()); WITH_DYNAMIC_ARG(game_for_reading, game.get());
REFLECT(stylesheet); REFLECT(stylesheet);
REFLECT_N("set_info", data); REFLECT_N("set_info", data);
if (stylesheet) {
REFLECT_N("styling", styling_data);
}
REFLECT(cards); REFLECT(cards);
} }
reflect_set_info_get_member(tag,data);
REFLECT(apprentice_code); REFLECT(apprentice_code);
} }
// ----------------------------------------------------------------------------- : Styling
// Extra set data, for a specific stylesheet
/* The data is not read immediatly, because we do not know the stylesheet */
class Set::Styling {
public:
IndexMap<FieldP, ValueP> data;
String unread_data;
DECLARE_REFLECTION();
};
IndexMap<FieldP, ValueP>& Set::stylingDataFor(const StyleSheet& stylesheet) {
StylingP& styling = styling_data[stylesheet.stylesheetName()];
if (!styling) {
styling = new_shared<Styling>();
styling->data.init(stylesheet.styling_fields);
} else if (!styling->unread_data.empty()) {
// we delayed the reading of the data, read it now
styling->data.init(stylesheet.styling_fields);
Reader reader(new_shared1<wxStringInputStream>(styling->unread_data), _("styling data of ") + stylesheet.stylesheetName());
reader.handle(styling->data);
styling->unread_data.clear();
}
return styling->data;
}
// custom reflection : read into unread_data
template <> void Reader::handle(Set::Styling& s) {
handle(s.unread_data);
}
template <> void Writer::handle(const Set::Styling& s) {
handle(s.data);
}
template <> void GetMember::handle(const Set::Styling& s) {
handle(s.data);
}
template <> void GetDefaultMember::handle(const Set::Styling& s) {
handle(s.data);
}
// ----------------------------------------------------------------------------- : SetView // ----------------------------------------------------------------------------- : SetView
......
...@@ -19,6 +19,7 @@ DECLARE_POINTER_TYPE(Card); ...@@ -19,6 +19,7 @@ DECLARE_POINTER_TYPE(Card);
DECLARE_POINTER_TYPE(Set); DECLARE_POINTER_TYPE(Set);
DECLARE_POINTER_TYPE(Game); DECLARE_POINTER_TYPE(Game);
DECLARE_POINTER_TYPE(StyleSheet); DECLARE_POINTER_TYPE(StyleSheet);
DECLARE_POINTER_TYPE(Styling);
DECLARE_POINTER_TYPE(Field); DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Value);
class ScriptManager; class ScriptManager;
...@@ -44,6 +45,9 @@ class Set : public Packaged { ...@@ -44,6 +45,9 @@ class Set : public Packaged {
/// The values on the fields of the set /// The values on the fields of the set
/** The indices should correspond to the set_fields in the Game */ /** The indices should correspond to the set_fields in the Game */
IndexMap<FieldP, ValueP> data; IndexMap<FieldP, ValueP> data;
/// Extra values for specitic stylesheets, indexed by stylesheet name
DECLARE_POINTER_TYPE(Styling);
map<String, StylingP> styling_data;
/// The cards in the set /// The cards in the set
vector<CardP> cards; vector<CardP> cards;
/// Code to use for apprentice (Magic only) /// Code to use for apprentice (Magic only)
...@@ -57,10 +61,15 @@ class Set : public Packaged { ...@@ -57,10 +61,15 @@ class Set : public Packaged {
/// A context for performing scripts on a particular card /// A context for performing scripts on a particular card
/** Should only be used from the main thread! */ /** Should only be used from the main thread! */
Context& getContext(const Card& card); Context& getContext(const Card& card);
/// Update styles for a card
void updateFor(const CardP& card);
/// Stylesheet to use for a particular card /// Stylesheet to use for a particular card
StyleSheetP stylesheetFor(const CardP& card); StyleSheetP stylesheetFor(const CardP& card);
/// Styling information for a particular stylesheet
IndexMap<FieldP, ValueP>& stylingDataFor(const StyleSheet&);
protected: protected:
virtual String typeName() const; virtual String typeName() const;
virtual void validate(Version); virtual void validate(Version);
...@@ -71,6 +80,9 @@ class Set : public Packaged { ...@@ -71,6 +80,9 @@ class Set : public Packaged {
scoped_ptr<ScriptManager> script_manager; scoped_ptr<ScriptManager> script_manager;
}; };
inline int item_count(const Set& set) {
return (int)set.cards.size();
}
// ----------------------------------------------------------------------------- : SetView // ----------------------------------------------------------------------------- : SetView
......
...@@ -24,6 +24,14 @@ StyleSheet::StyleSheet() ...@@ -24,6 +24,14 @@ StyleSheet::StyleSheet()
StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) { StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) {
return packages.open<StyleSheet>(game.name() + _("-") + name + _(".mse-style")); return packages.open<StyleSheet>(game.name() + _("-") + name + _(".mse-style"));
} }
String StyleSheet::stylesheetName() const {
String sn = name(), gn = game->name();
if (sn.size() + 1 > gn.size()) {
return sn.substr(gn.size() + 1); // remove "gamename-"
} else {
return sn;
}
}
String StyleSheet::typeNameStatic() { return _("style"); } String StyleSheet::typeNameStatic() { return _("style"); }
String StyleSheet::typeName() const { return _("style"); } String StyleSheet::typeName() const { return _("style"); }
...@@ -36,6 +44,7 @@ InputStreamP StyleSheet::openIconFile() { ...@@ -36,6 +44,7 @@ InputStreamP StyleSheet::openIconFile() {
return game->openIconFile(); // use game icon by default return game->openIconFile(); // use game icon by default
} }
} }
IMPLEMENT_REFLECTION(StyleSheet) { IMPLEMENT_REFLECTION(StyleSheet) {
// < 0.3.0 didn't use card_ prefix // < 0.3.0 didn't use card_ prefix
tag.addAlias(300, _("width"), _("card width")); tag.addAlias(300, _("width"), _("card width"));
...@@ -44,6 +53,8 @@ IMPLEMENT_REFLECTION(StyleSheet) { ...@@ -44,6 +53,8 @@ IMPLEMENT_REFLECTION(StyleSheet) {
tag.addAlias(300, _("background"), _("card background")); tag.addAlias(300, _("background"), _("card background"));
tag.addAlias(300, _("info style"), _("set info style")); tag.addAlias(300, _("info style"), _("set info style"));
tag.addAlias(300, _("align"), _("alignment")); tag.addAlias(300, _("align"), _("alignment"));
tag.addAlias(300, _("extra field"),_("styling field"));
tag.addAlias(300, _("extra style"),_("styling style"));
REFLECT(game); REFLECT(game);
REFLECT(full_name); REFLECT(full_name);
...@@ -61,9 +72,9 @@ IMPLEMENT_REFLECTION(StyleSheet) { ...@@ -61,9 +72,9 @@ IMPLEMENT_REFLECTION(StyleSheet) {
REFLECT(card_style); REFLECT(card_style);
REFLECT(set_info_style); REFLECT(set_info_style);
} }
// io(_("extra field"), extraSetFields); REFLECT(styling_fields);
// extraInfoStyle.init(extraSetFields); if (tag.reading()) styling_style.init(styling_fields);
// io(_("extra style"), extraInfoStyle); REFLECT(styling_style);
} }
void StyleSheet::validate(Version) { void StyleSheet::validate(Version) {
......
...@@ -34,18 +34,23 @@ class StyleSheet : public Packaged { ...@@ -34,18 +34,23 @@ class StyleSheet : public Packaged {
double card_dpi; ///< The resolution of a card in dots per inch double card_dpi; ///< The resolution of a card in dots per inch
Color card_background; ///< The background color of cards Color card_background; ///< The background color of cards
/// The styling for card fields /// The styling for card fields
/** The indices should correspond to the set_fields in the Game */ /** The indices should correspond to the card_fields in the Game */
IndexMap<FieldP, StyleP> card_style; IndexMap<FieldP, StyleP> card_style;
/// The styling for set info fields /// The styling for set info fields
/** The indices should correspond to the set_fields in the Game */ /** The indices should correspond to the set_fields in the Game */
IndexMap<FieldP, StyleP> set_info_style; IndexMap<FieldP, StyleP> set_info_style;
/// Extra fields for styling
vector<FieldP> styling_fields;
/// The styling for the extra set fields
/** The indices should correspond to the styling_fields */
IndexMap<FieldP, StyleP> styling_style;
bool dependencies_initialized; ///< are the script dependencies comming from this stylesheet all initialized? bool dependencies_initialized; ///< are the script dependencies comming from this stylesheet all initialized?
/// Load a StyleSheet, given a Game and the name of the StyleSheet /// Load a StyleSheet, given a Game and the name of the StyleSheet
static StyleSheetP byGameAndName(const Game& game, const String& name); static StyleSheetP byGameAndName(const Game& game, const String& name);
/// name of the package without the game name /// name of the package without the game name
String styleName(); String stylesheetName() const;
static String typeNameStatic(); static String typeNameStatic();
virtual String typeName() const; virtual String typeName() const;
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <data/symbol_font.hpp>
// ----------------------------------------------------------------------------- : SymbolFont
// ----------------------------------------------------------------------------- : SymbolFontRef
SymbolFontRef::SymbolFontRef()
: size(12)
, scale_down_to(1)
, alignment(ALIGN_MIDDLE_CENTER)
{}
IMPLEMENT_REFLECTION(SymbolFontRef) {
REFLECT(name);
REFLECT(size);
REFLECT(scale_down_to);
REFLECT(alignment);
}
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_DATA_SYMBOL_FONT
#define HEADER_DATA_SYMBOL_FONT
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/alignment.hpp>
#include <util/io/package.hpp>
#include <data/font.hpp>
DECLARE_POINTER_TYPE(Font);
DECLARE_POINTER_TYPE(SymbolFont);
DECLARE_POINTER_TYPE(SymbolInFont);
// ----------------------------------------------------------------------------- : SymbolFont
// A font that is drawn using images
class SymbolFont : Packaged {
public:
/// Loads the symbol font with a given name, for example "magic-mana-large"
static SymbolFontP byName(const String& name);
private:
UInt imgSize; ///< Font size that the images use
UInt minSize; ///< Minimum font size
RealSize spacing; ///< Spacing between sybmols (for the default font size)
// writing text
bool scale_text; ///< Should text be scaled down to fit in a symbol?
FontP text_font; ///< Font to use for missing symbols
double text_margin_left;
double text_margin_right;
double text_margin_rop;
double text_margin_bottom;
Alignment text_align;
bool merge_numbers; ///< Merge numbers? e.g. "11" is a single symbol ('1' must not exist as a symbol)
public:
class Symbol;
private:
vector<SymbolInFontP> symbols; ///< The individual symbols
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : SymbolFontRef
/// A reference to an actual symbol font
class SymbolFontRef {
public:
SymbolFontRef();
// Script update
bool update(Context& ctx);
void initDependencies(Context&, Dependency& dep);
/// Is a font loaded?
bool valid();
private:
Scriptable<String> name; ///< Font package name, can be changed with script
double size; ///< Size of the font
double scale_down_to; ///< Mimumum size of the font
Alignment alignment; ///< Alignment of symbols in a line of text
SymbolFontP font; ///< The font, if it is loaded
/// (re)load the symbol font based on name
void loadFont();
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : EOF
#endif
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include "../util/prec.hpp" #include <util/prec.hpp>
#include <util/real_point.hpp>
// ----------------------------------------------------------------------------- : Resampling // ----------------------------------------------------------------------------- : Resampling
...@@ -103,6 +104,46 @@ void combine_image(Image& a, const Image& b, ImageCombine combine); ...@@ -103,6 +104,46 @@ void combine_image(Image& a, const Image& b, ImageCombine combine);
/// Draw an image to a DC using a combining function /// Draw an image to a DC using a combining function
void draw_combine_image(DC& dc, UInt x, UInt y, const Image& img, ImageCombine combine); void draw_combine_image(DC& dc, UInt x, UInt y, const Image& img, ImageCombine combine);
// ----------------------------------------------------------------------------- : Masks
/// An alpha mask is an alpha channel that can be copied to another image
/** It is created by treating black in the source image as transparent and white (red) as opaque
*/
class AlphaMask {
public:
AlphaMask();
~AlphaMask();
// TODO
private:
Byte* alpha;
};
/// A contour mask stores the size and position of each line in the image
/** It is created by treating black in the source image as transparent and white (red) as opaque
* The left is the first non-transparent pixel, the right is the last non-transparent pixel
*/
class ContourMask {
public:
ContourMask();
~ContourMask();
/// Load a contour mask
void load(const String& filename);
/// Unload the mask
void unload();
/// Returns the start of a row, when the mask were stretched to size
double rowLeft (double y, RealSize size) const;
/// Returns the end of a row, when the mask were stretched to size
double rowRight(double y, RealSize size) const;
private:
UInt width, height;
UInt *lefts, *rights;
};
// ----------------------------------------------------------------------------- : Utility // ----------------------------------------------------------------------------- : Utility
inline int bot(int x) { return max(0, x); } ///< bottom range check for color values inline int bot(int x) { return max(0, x); } ///< bottom range check for color values
......
...@@ -210,5 +210,5 @@ CardP CardsPanel::selectedCard() const { ...@@ -210,5 +210,5 @@ CardP CardsPanel::selectedCard() const {
} }
void CardsPanel::selectCard(const CardP& card) { void CardsPanel::selectCard(const CardP& card) {
card_list->setCard(card); card_list->setCard(card);
editor->setCard(*card); editor->setCard(card);
} }
...@@ -632,13 +632,40 @@ ...@@ -632,13 +632,40 @@
RelativePath=".\data\card.hpp"> RelativePath=".\data\card.hpp">
</File> </File>
<File <File
RelativePath=".\data\game.cpp"> RelativePath=".\data\font.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Debug Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
</File> </File>
<File <File
RelativePath=".\data\game.hpp"> RelativePath=".\data\font.hpp">
</File> </File>
<File <File
RelativePath=".\data\locale.hpp"> RelativePath=".\data\game.cpp">
</File>
<File
RelativePath=".\data\game.hpp">
</File> </File>
<File <File
RelativePath=".\data\set.cpp"> RelativePath=".\data\set.cpp">
...@@ -676,6 +703,12 @@ ...@@ -676,6 +703,12 @@
<File <File
RelativePath=".\data\symbol.hpp"> RelativePath=".\data\symbol.hpp">
</File> </File>
<File
RelativePath=".\data\symbol_font.cpp">
</File>
<File
RelativePath=".\data\symbol_font.hpp">
</File>
<Filter <Filter
Name="action" Name="action"
Filter=""> Filter="">
...@@ -887,6 +920,12 @@ ...@@ -887,6 +920,12 @@
<File <File
RelativePath=".\util\string.hpp"> RelativePath=".\util\string.hpp">
</File> </File>
<File
RelativePath=".\util\tagged_string.cpp">
</File>
<File
RelativePath=".\util\tagged_string.hpp">
</File>
<File <File
RelativePath=".\util\window_id.hpp"> RelativePath=".\util\window_id.hpp">
</File> </File>
...@@ -1183,36 +1222,6 @@ ...@@ -1183,36 +1222,6 @@
<Filter <Filter
Name="value" Name="value"
Filter=""> Filter="">
<File
RelativePath=".\render\value\boolean.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Debug Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
</File>
<File
RelativePath=".\render\value\boolean.hpp">
</File>
<File <File
RelativePath=".\render\value\choice.cpp"> RelativePath=".\render\value\choice.cpp">
<FileConfiguration <FileConfiguration
...@@ -1486,6 +1495,67 @@ ...@@ -1486,6 +1495,67 @@
RelativePath=".\render\symbol\viewer.hpp"> RelativePath=".\render\symbol\viewer.hpp">
</File> </File>
</Filter> </Filter>
<Filter
Name="text"
Filter="">
<File
RelativePath=".\render\text\element.cpp">
</File>
<File
RelativePath=".\render\text\element.hpp">
</File>
<File
RelativePath=".\render\text\font.cpp">
</File>
<File
RelativePath=".\render\text\line.cpp">
</File>
<File
RelativePath=".\render\text\symbol.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Debug Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)3.obj"/>
</FileConfiguration>
</File>
<File
RelativePath=".\render\text\viewer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
<FileConfiguration
Name="Release Unicode|Win32">
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
</FileConfiguration>
</File>
<File
RelativePath=".\render\text\viewer.hpp">
</File>
</Filter>
</Filter> </Filter>
<File <File
RelativePath=".\code_template.cpp"> RelativePath=".\code_template.cpp">
......
...@@ -33,6 +33,8 @@ void DataViewer::draw(RotatedDC& dc) { ...@@ -33,6 +33,8 @@ void DataViewer::draw(RotatedDC& dc) {
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(set->stylesheet->card_background); dc.SetBrush(set->stylesheet->card_background);
dc.DrawRectangle(dc.getInternalRect()); dc.DrawRectangle(dc.getInternalRect());
// update style scripts
if (card) set->updateFor(card);
// draw values // draw values
FOR_EACH(v, viewers) { // draw low z index fields first FOR_EACH(v, viewers) { // draw low z index fields first
if (v->getStyle()->visible) {// visible if (v->getStyle()->visible) {// visible
...@@ -52,10 +54,11 @@ Context& DataViewer::getContext() const { return set->getContext(); } ...@@ -52,10 +54,11 @@ Context& DataViewer::getContext() const { return set->getContext(); }
// ----------------------------------------------------------------------------- : Setting data // ----------------------------------------------------------------------------- : Setting data
void DataViewer::setCard(Card& card) { void DataViewer::setCard(const CardP& card) {
assert(set); assert(set);
this->card = card;
setStyles(set->stylesheet->card_style); setStyles(set->stylesheet->card_style);
setData(card.data); setData(card->data);
} }
// ----------------------------------------------------------------------------- : Viewers // ----------------------------------------------------------------------------- : Viewers
......
...@@ -54,7 +54,7 @@ class DataViewer : public SetView { ...@@ -54,7 +54,7 @@ class DataViewer : public SetView {
// --------------------------------------------------- : Setting data // --------------------------------------------------- : Setting data
/// Display a card in this viewer /// Display a card in this viewer
void setCard(Card& card); void setCard(const CardP& card);
// --------------------------------------------------- : The viewers // --------------------------------------------------- : The viewers
protected: protected:
...@@ -75,6 +75,7 @@ class DataViewer : public SetView { ...@@ -75,6 +75,7 @@ class DataViewer : public SetView {
private: private:
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
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
#include <util/tagged_string.hpp>
#include <data/field/text.hpp>
DECLARE_TYPEOF_COLLECTION(TextElementP);
// ----------------------------------------------------------------------------- : TextElements
void TextElements::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
FOR_EACH_CONST(e, elements) {
size_t start_ = max(start, e->start);
size_t end_ = min(end, e->end);
if (start_ < end_) {
e->draw(dc, scale, rect, what, start_, end_);
}
if (end <= e->end) return; // nothing can be after this
}
}
void TextElements::getCharInfo(RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const {
FOR_EACH_CONST(e, elements) {
// characters before this element, after the previous
for (size_t i = start ; i < e->start ; ++i) {
out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
}
e->getCharInfo(dc, scale, out);
start = min(end, e->end);
}
for (size_t i = start ; i < end ; ++i) {
out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
}
}
/*//@@
RealSize TextElements::charSize(const Rotation& rot, double scale, size_t index) const {
vector<TextElementP>::const_iterator e = findByIndex(index);
if (e != elements.end()) {
return (*e)->charSize(rot, scale, index);
} else {
return RealSize(0,0);
}
}
bool ends_before_index(const TextElementP& e, size_t index) {
return index < e->end;
}
vector<TextElementP>::const_iterator TextElements::findByIndex(size_t index) const {
// Note: slightly abusing lower_bound, since typeof(index) != elements.element_type
vector<TextElementP>::const_iterator it = lower_bound(elements.begin(), elements.end(), index, ends_before_index);
if ((*it)->start <= index && (*it)->end > index) return it;
else return elements.end();
}*/
// Helper class for TextElements::fromString, to allow persistent formating state accross recusive calls
struct TextElementsFromString {
// What formatting is enabled?
int bold, italic, symbol;
int soft, kwpph;
TextElementsFromString()
: bold(0), italic(0), symbol(0), soft(0), kwpph(0) {}
// read TextElements from a string
void fromString(TextElements& te, const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
te.elements.clear();
// for each character...
for (size_t pos = start ; pos < end ; ) {
Char c = text.GetChar(pos);
if (c == _('<')) {
size_t tag_start = pos;
pos = skip_tag(text, tag_start);
if (is_substr(text, tag_start, _( "<b"))) bold += 1;
else if (is_substr(text, tag_start, _("</b"))) bold -= 1;
else if (is_substr(text, tag_start, _( "<i"))) italic += 1;
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, _( "<sep-soft"))) soft += 1;
else if (is_substr(text, tag_start, _("</sep-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;
else if (is_substr(text, tag_start, _("<line"))) {
// horizontal line
te.elements.push_back(new_shared3<HorizontalLineTextElement>(text, tag_start, pos));
/* } else if (is_substr(text, start, _("<error"))) {
// underline with wavy 'error' indicator
size_t end = match_close_tag(text, tag_start);
shared_ptr<ErrorTextElement> e(new ErrorTextElement(text, pos, end));
fromString(e->elements, text, pos, end, style, ctx);
pos = skip_tag(text, end);
} else if (is_substr(text, start, _("<atom"))) {
// 'atomic' indicator
size_t end = match_close_tag(text, tag_start);
shared_ptr<AtomTextElement> e(new AtomTextElement(text, pos, end));
fromString(e->elements, text, pos, end, style, ctx);
pos = skip_tag(text, end);
*/ } else {
// ignore other tags
}
} else {
// A character of normal text, add to the last text element (if possible)
SimpleTextElement* e = nullptr;
if (!te.elements.empty()) e = dynamic_cast<SimpleTextElement*>(te.elements.back().get());
if (e && e->end == pos) {
e->end = pos + 1; // just move the end, no need to make a new element
} else {
// add a new element for this text
if (symbol > 0) {
te.elements.push_back(new_shared3<SymbolTextElement>(text, pos, pos + 1));
} else {
te.elements.push_back(new_shared4<FontTextElement> (text, pos, pos + 1, style.font.make(bold > 0, italic > 0)));
}
}
pos += 1;
}
}
}
};
void TextElements::fromString(const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx) {
TextElementsFromString f;
f.fromString(*this, text, start, end, style, ctx);
}
/*
// ----------------------------------------------------------------------------- : CompoundTextElement
void CompoundTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
elements.draw(dc, scale, rect, what, start, end);
}
RealSize CompoundTextElement::charSize(RotatedDC& dc, double scale, size_t index) const {
return elements.charSize(rot, scale, index);
}
*/
\ No newline at end of file
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_RENDER_TEXT_ELEMENT
#define HEADER_RENDER_TEXT_ELEMENT
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/rotation.hpp>
#include <util/real_point.hpp>
DECLARE_POINTER_TYPE(TextElement);
DECLARE_POINTER_TYPE(Font);
class TextStyle;
class Context;
// ----------------------------------------------------------------------------- : TextElement
/// What should be drawn?
enum DrawWhat
{ DRAW_NOTHING = 0x00
, DRAW_NORMAL = 0x01 // draw normal things, like the text
, DRAW_EDITOR = 0x02 // draw editor stuff, such as borders/lines
, DRAW_ACTIVE = 0x04 // draw active editor stuff, such as hidden separators and atom highlights
};
/// Information on a linebreak
enum LineBreak
{ BREAK_NO // no line break
, BREAK_SOFT // optional line break (' ')
, BREAK_HARD // always a line break ('\n')
, BREAK_LINE // line break with a separator line (<line>)
};
/// Information on a character in a TextElement
struct CharInfo {
RealSize size;
LineBreak break_after;
inline CharInfo(RealSize size, LineBreak break_after = BREAK_NO) : size(size), break_after(break_after) {}
};
/// A section of text that can be rendered using a TextViewer
class TextElement {
public:
/// What section of the input string is this element?
size_t start, end;
/// The text of which a subsection is drawn
String text;
inline TextElement(const String& text, size_t start ,size_t end) : text(text), start(start), end(end) {}
virtual ~TextElement() {}
/// Draw a subsection section of the text in the given rectangle
/** this->start <= start < end <= this->end <= text.size() */
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const = 0;
// /// The size of a single character at position index
// /** index is in the range [start..end) */
// virtual RealSize charSize(const Rotation& rot, double scale, size_t index) const = 0;
/// Get information on all characters in the range [start...end) and store them in out
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const = 0;
/*
// draw the section <start...end)
// drawSeparators indicates what we should draw, separators or normal text
// h is the height of the current line
virtual void draw(RotatedDC& dc, UInt shrink, RealRect rect, size_t start, size_t end, DrawWhat draw) const = 0;
/// Returns the width and height of the character at charId
virtual RealSize charSize(RotatedDC& dc, double scale, size_t charId) const = 0;
/// May the text be broken after char_id?
virtual BreakAfter breakAfter(size_t char_id) const = 0;
// number of characters in this object
abstract size_t size() const;
// maximum shrink factor allowed
// shrink indicates by how much the thing to render should be shrunk, there is no indication
// what it means (probably pixels or points), but size(shrink = k+1) <= size(shrink = k)
abstract UInt maxShrink() const;
// Size of an entire section
RealSize sectionSize(RotatedDC& dc, double scale, size_t start, size_t end) const;
RealSize for::sectionSize(RotatedDC& dc, double scale, size_t start, size_t end) const {
RealSize size;
for(i = start ; i < end ; ++i) {
size = addHorizontal(size, charSize(dc, scale, i));
}
return size;
}*/
};
// ----------------------------------------------------------------------------- : TextElements
/// A list of text elements
class TextElements : public vector<TextElementP> {
public:
/// Draw all the elements (as need to show the range start..end)
void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
// RealSize charSize(const Rotation& rot, double scale, size_t index) const;
// Get information on all characters in the range [start...end) and store them in out
void getCharInfo(RotatedDC& dc, double scale, size_t start, size_t end, vector<CharInfo>& out) const;
/// The actual elements
/** They must be in order of positions and not overlap, i.e.
* i < j ==> elements[i].end <= elements[j].start
*/
vector<TextElementP> elements;
/// Find the element that contains the given index, if there is any
vector<TextElementP>::const_iterator findByIndex(size_t index) const;
/// Read the elements from a string
void fromString(const String& text, size_t start, size_t end, const TextStyle& style, Context& ctx);
};
// ----------------------------------------------------------------------------- : SimpleTextElement
/// A text element that just shows text
class SimpleTextElement : public TextElement {
public:
SimpleTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
};
/// A text element that uses a normal font
class FontTextElement : public SimpleTextElement {
public:
FontTextElement(const String& text, size_t start ,size_t end, const FontP& font)
: SimpleTextElement(text, start, end)
, font(font)
{}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
private:
FontP font;
DrawWhat draw_as;
};
/// A text element that uses a symbol font
class SymbolTextElement : public SimpleTextElement {
public:
SymbolTextElement(const String& text, size_t start ,size_t end) : SimpleTextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
};
// ----------------------------------------------------------------------------- : CompoundTextElement
/// A TextElement consisting of sub elements
class CompoundTextElement : public TextElement {
public:
CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
TextElements elements; ///< the elements
};
// ----------------------------------------------------------------------------- : Other text elements
/// A text element that displays a horizontal separator line
class HorizontalLineTextElement : public TextElement {
public:
HorizontalLineTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual void getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const;
};
/*
// ----------------------------------------------------------------------------- : CompoundTextElement
/// A TextElement consisting of sub elements
class CompoundTextElement : public TextElement {
public:
CompoundTextElement(const String& text, size_t start ,size_t end) : TextElement(text, start, end) {}
virtual void draw (RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const;
virtual RealSize charSize(RotatedDC& dc, double scale, size_t index) const;
private:
TextElements elements;
};
*/
// ----------------------------------------------------------------------------- : EOF
#endif
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
#include <data/font.hpp>
// ----------------------------------------------------------------------------- : FontTextElement
void FontTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
dc.SetFont(font->font, font->size * scale);
if (end != start && text.substr(end-1, 1) == _("\n")) end -= 1; // don't draw the newline character at the end
/* if ((draw & DRAW_NORMAL) != DRAW_NORMAL) {
// don't draw
if (what == DRAW_ACTIVE) {
// we are drawing a separator
dc.SetTextForeground(font->separator_color);
dc.DrawText(text.substr(start, end-start), rect.position);
}
} else {*/
// draw normally
// draw shadow
if (font->hasShadow()) {
dc.SetTextForeground(font->shadow_color);
dc.DrawText(text.substr(start, end - start), rect.position + font->shadow_displacement);
}
// draw
dc.SetTextForeground(font->color);
dc.DrawText(text.substr(start, end - start), rect.position);
// }
}
void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// font
dc.SetFont(font->font, font->size * scale);
// find sizes & breaks
double prev_width = 0;
for (size_t i = start ; i < end ; ++i) {
Char c = text.GetChar(i);
RealSize s = dc.GetTextExtent(text.substr(start, i - start));
out.push_back(CharInfo(RealSize(s.width - prev_width, s.height),
c == _('\n') ? BREAK_HARD :
c == _(' ') ? BREAK_SOFT : BREAK_NO
));
prev_width = s.width;
}
}
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : HorizontalLineTextElement
void HorizontalLineTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
// TODO
}
void HorizontalLineTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// TODO
}
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : SymbolTextElement
void SymbolTextElement::draw(RotatedDC& dc, double scale, const RealRect& rect, DrawWhat what, size_t start, size_t end) const {
// TODO
}
void SymbolTextElement::getCharInfo(RotatedDC& dc, double scale, vector<CharInfo>& out) const {
// TODO
}
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <render/text/viewer.hpp>
#include <algorithm>
DECLARE_TYPEOF_COLLECTION(TextViewer::Line);
DECLARE_TYPEOF_COLLECTION(double);
// ----------------------------------------------------------------------------- : Line
struct TextViewer::Line {
size_t start; ///< Index of the first character in this line
vector<double> positions; ///< x position of each character in this line, gives the number of characters + 1, never empty
double top; ///< y position of (the top of) this line
double line_height; ///< The height of this line in pixels
bool separator_after; ///< Is there a saparator after this line?
Line()
: start(0), top(0), line_height(0), separator_after(false)
{}
/// The position (just beyond) the bottom of this line
double bottom() const { return top + line_height; }
/// The width of this line
double width() const { return positions.back() - positions.front(); }
/// Index just beyond the last character on this line
size_t end() const { return start + positions.size() - 1; }
/// Find the index of the character at the given position on this line
/** Always returns a value in the range [start..end()) */
size_t posToIndex(double x) const;
/// Is this line visible using the given rectangle?
bool visible(const Rotation& rot) const {
return top + line_height > 0 && top < rot.getInternalSize().height;
}
/// Draws a selection indicator on this line from start to end
/** start and end need not be in this line */
void drawSelection(RotatedDC& dc, size_t start, size_t end);
};
size_t TextViewer::Line::posToIndex(double x) const {
// largest index with pos <= x
vector<double>::const_iterator it1 = lower_bound(positions.begin(), positions.end(), x);
if (it1 == positions.end()) return end();
// first index with pos > x
vector<double>::const_iterator it2 = it1 + 1;
if (it2 == positions.end()) return it1 - positions.begin();
if (x - *it1 <= *it2 - x) return it1 - positions.begin(); // it1 is closer
else return it2 - positions.begin(); // it2 is closer
}
// ----------------------------------------------------------------------------- : TextViewer
// can't be declared in header because we need to know sizeof(Line)
TextViewer:: TextViewer() {}
TextViewer::~TextViewer() {}
// ----------------------------------------------------------------------------- : Drawing
void TextViewer::draw(RotatedDC& dc, const String& text, const TextStyle& style, Context& ctx, DrawWhat what) {
Rotater r(dc, Rotation(style.angle, style.getRect()));
if (lines.empty()) {
// not prepared yet
prepareElements(text, style, ctx);
prepareLines(dc, text, style);
}
// Draw the text line by line
FOR_EACH(l, lines) {
if (l.visible(dc)) {
RealRect rect(l.positions.front(), l.top, l.width(), l.line_height);
elements.draw(dc, scale, rect, what, l.start, l.end());
}
}
}
void TextViewer::drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end) {
Rotater r(dc, Rotation(style.angle, style.getRect()));
if (sel_start == sel_end) return;
if (sel_end < sel_start) swap(sel_start, sel_end);
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetLogicalFunction(wxINVERT);
FOR_EACH(l, lines) {
l.drawSelection(dc, sel_start, sel_end);
}
dc.SetLogicalFunction(wxCOPY);
}
void TextViewer::Line::drawSelection(RotatedDC& dc, size_t sel_start, size_t sel_end) {
if (!visible(dc)) return;
if (sel_start < end() && sel_end > start) {
double x1 = positions[sel_start];
double x2 = positions[max(end(), sel_end)];
dc.DrawRectangle(RealRect(x1, top, x2 - x1, line_height));
}
}
void TextViewer::reset() {
elements.clear();
lines.clear();
}
// ----------------------------------------------------------------------------- : Positions
size_t TextViewer::lineStart(size_t index) const {
if (lines.empty()) return 0;
return findLine(index).start;
}
size_t TextViewer::lineEnd(size_t index) const {
if (lines.empty()) return 0;
return findLine(index).end();
}
const TextViewer::Line& TextViewer::findLine(size_t index) const {
FOR_EACH_CONST(l, lines) {
if (l.end() > index) return l;
}
return lines.front();
}
// ----------------------------------------------------------------------------- : Elements
void TextViewer::prepareElements(const String& text, const TextStyle& style, Context& ctx) {
elements.fromString(text, 0, text.size(), style, ctx);
}
// ----------------------------------------------------------------------------- : Layout
void TextViewer::prepareLines(RotatedDC& dc, const String& text, const TextStyle& style) {
scale = 1;
prepareLinesScale(dc, text, style, false);
}
bool TextViewer::prepareLinesScale(RotatedDC& dc, const String& text, const TextStyle& style, bool stop_if_too_long) {
// Try to layout the text at the current scale
// find character sizes
vector<CharInfo> chars;
elements.getCharInfo(dc, scale, 0, text.size(), chars);
// first line
lines.clear();
Line line;
// size of the line so far
RealSize line_size(lineLeft(dc, style, 0), 0);
line.positions.push_back(line_size.width);
// The word we are currently reading
RealSize word_size;
vector<double> positions_word; // positios for this word
size_t word_start = 0;
// For each character ...
for(size_t i = 0 ; i < chars.size() ; ++i) {
CharInfo& c = chars[i];
// Should we break?
bool break_now = false;
bool accept_word = false; // the current word should be added to the line
bool hide_breaker = true; // hide the \n or _(' ') that caused a line break
double line_height_multiplier = 1; // multiplier for line height for next line top
if (c.break_after == BREAK_HARD) {
break_now = true;
accept_word = true;
line_height_multiplier = style.line_height_hard;
} else if (c.break_after == BREAK_LINE) {
line.separator_after = true;
break_now = true;
accept_word = true;
line_height_multiplier = style.line_height_line;
} else if (c.break_after == BREAK_SOFT && style.field().multi_line) {
// Soft break == end of word
accept_word = true;
}
// Add size of the character
word_size = addHorizontal(word_size, c.size);
positions_word.push_back(word_size.width);
// Did the word become too long?
if (style.field().multi_line && !break_now) {
double max_width = lineRight(dc, style, line.top);
if (word_start == line.start && word_size.width > max_width) {
// single word on this line; the word is too long
if (stop_if_too_long) {
return false; // just give up
} else {
// force a word break
break_now = true;
accept_word = true;
hide_breaker = false;
line_height_multiplier = style.line_height_soft;
}
} else if (line_size.width + word_size.width > max_width) {
// line would become too long, break before the current word
break_now = true;
line_height_multiplier = style.line_height_soft;
}
}
// Ending the current word
if (accept_word) {
// move word pos to line
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
// add size; next word
line_size = addHorizontal(line_size, word_size);
word_size = RealSize(0, 0);
word_start = i + 1;
positions_word.clear();
}
// Breaking (ending the current line)
if (break_now) {
// remove the _('\n') or _(' ') that caused the break
if (hide_breaker && line.positions.size() > 1) {
line.positions.pop_back();
}
// height of the line
if (line_size.height < 0.01 && !lines.empty()) {
// if a line has 0 height, use the height of the line above it, but at most once
} else {
line.line_height = line_size.height;
}
// push
lines.push_back(line);
// reset line object for next line
line.top += line.line_height * line_height_multiplier;
line.start = word_start;
line.positions.clear();
if (line.separator_after) line.line_height = 0;
line.separator_after = false;
// reset line_size
line_size = RealSize(lineLeft(dc, style, line.top), 0);
line.positions.push_back(line_size.width); // start position
}
}
// the last word
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
line_size = addHorizontal(line_size, word_size);
// the last line
if (line_size.height < 0.01 && !lines.empty()) {
// if a line has 0 height, use the height of the line above it, but at most once
} else {
line.line_height = line_size.height;
}
lines.push_back(line);
return true;
}
double TextViewer::lineLeft(RotatedDC& dc, const TextStyle& style, double y) {
return 0;
// return style.mask.rowLeft(y, dc.getInternalSize()) + style.padding_left;
}
double TextViewer::lineRight(RotatedDC& dc, const TextStyle& style, double y) {
return style.width;
// return style.mask.rowRight(y, dc.getInternalSize()) - style.padding_right;
}
ContourMask::ContourMask() {} // MOVEME //@@
ContourMask::~ContourMask() {}
\ No newline at end of file
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_RENDER_TEXT_VIEWER
#define HEADER_RENDER_TEXT_VIEWER
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/rotation.hpp>
#include <data/field/text.hpp>
#include <render/text/element.hpp>
// ----------------------------------------------------------------------------- : TextViewer
/// Class for viewing and determining positions in formated text
/** It can:
* - Draw text to a DC
* - Draw selection to a DC
* - Convert between screen coordinates and cursor position
*
* To refer to positions in the text this class uses several concepts:
* - index An index in the input string.
* For cursor positions char_id = 0 means the cursor is BEFORE character 0
* - pos The position of a character in real world x,y coordinates (in pixels)
* The position is the top-left of the character.
* A char_pos is often only the x coordinate.
* A line_pos is often only the y coordinate.
* - Line A line on the screen, this does not neccessarly correspond to explicit linebreaks,
* since textwrapping also leads to a new line.
* - line_id The index of a line, 0 is the first line.
*/
class TextViewer {
public:
/// Information on a line in the textbox
struct Line;
TextViewer();
~TextViewer();
// --------------------------------------------------- : Drawing
/// Draw the given text with the given text style
/** The drawing information is cached,
* before calling draw again with different text/style reset() should be called
*/
void draw(RotatedDC& dc, const String& text, const TextStyle& style, Context&, DrawWhat);
/// Draw an indicator for selected text
void drawSelection(RotatedDC& dc, const TextStyle& style, size_t sel_start, size_t sel_end);
/// Reset the cached data, at a new call to draw it will be recalculated
void reset();
// --------------------------------------------------- : Positions
/// Find the character index that is before the given index, and which has a nonzero width
size_t moveLeft(size_t index) const;
/// Find the character index that is on a line above/below index
/** If this would move outisde the text, returns the input index */
size_t moveLine(size_t index, int delta) const;
/// The character index of the start of the line that character #index is on
size_t lineStart(size_t index) const;
/// The character index past the end of the line that character #index is on
size_t lineEnd (size_t index) const;
private:
// --------------------------------------------------- : More drawing
double scale; /// < Scale when drawing
// --------------------------------------------------- : Elements
TextElements elements; ///< The elements of the prepared text
/// Find the elements in a string and add them to elements
void prepareElements(const String&, const TextStyle& style, Context& ctx);
// --------------------------------------------------- : Lines
vector<Line> lines; ///< The lines in the text box
/// Prepare the lines, layout the text
void prepareLines(RotatedDC& dc, const String& text, const TextStyle& style);
/// Prepare the lines, layout the text; at a specific scale
bool prepareLinesScale(RotatedDC& dc, const String& text, const TextStyle& style, bool stop_if_too_long);
/// Find the line the given index is on, returns the first line if the index is not found
const Line& findLine(size_t index) const;
// helper : get the start coordinate of a line, this is 0 unless there is a contour mask
double lineLeft (RotatedDC& dc, const TextStyle& style, double y);
// helper : get the end coordinate of a line, this is width unless there is a contour mask
double lineRight(RotatedDC& dc, const TextStyle& style, double y);
};
// ----------------------------------------------------------------------------- : EOF
#endif
...@@ -35,7 +35,7 @@ void ColorValueViewer::draw(RotatedDC& dc) { ...@@ -35,7 +35,7 @@ void ColorValueViewer::draw(RotatedDC& dc) {
dc.DrawRectangle(RealRect(style().left, style().top, 40, style().height)); dc.DrawRectangle(RealRect(style().left, style().top, 40, style().height));
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(style().getRect() + RealRect(40, 0, -40, 0)); dc.DrawRectangle(style().getRect().move(40, 0, -40, 0));
dc.DrawText(color_name, style().getPos() + RealSize(43, 3)); dc.DrawText(color_name, style().getPos() + RealSize(43, 3));
} else { } else {
// do we need clipping? // do we need clipping?
......
...@@ -7,5 +7,19 @@ ...@@ -7,5 +7,19 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <render/value/text.hpp> #include <render/value/text.hpp>
#include <render/card/viewer.hpp>
// ----------------------------------------------------------------------------- : // ----------------------------------------------------------------------------- : TextValueViewer
void TextValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
v.draw(dc, value().value(), style(), viewer.getContext(), DRAW_NORMAL);
}
void TextValueViewer::onValueChange() {
v.reset();
}
void TextValueViewer::onStyleChange() {
v.reset();
}
...@@ -10,8 +10,24 @@ ...@@ -10,8 +10,24 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <render/value/viewer.hpp>
#include <render/text/viewer.hpp>
#include <data/field/text.hpp>
// ----------------------------------------------------------------------------- : // ----------------------------------------------------------------------------- : TextValueViewer
/// Viewer that displays a text value
class TextValueViewer : public ValueViewer {
public:
DECLARE_VALUE_VIEWER(Text) : ValueViewer(parent,style) {}
virtual void draw(RotatedDC& dc);
virtual void onValueChange();
virtual void onStyleChange();
private:
TextViewer v;
};
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -78,11 +78,12 @@ ValueViewerP BooleanStyle ::makeViewer(DataViewer& parent, const StyleP& t ...@@ -78,11 +78,12 @@ ValueViewerP BooleanStyle ::makeViewer(DataViewer& parent, const StyleP& t
ValueViewerP MultipleChoiceStyle::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); } ValueViewerP MultipleChoiceStyle::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
//ValueViewerP ColorStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); } //ValueViewerP ColorStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
//ValueViewerP ImageStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); } //ValueViewerP ImageStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
IMPLEMENT_MAKE_VIEWER(Text);
IMPLEMENT_MAKE_VIEWER(Choice); IMPLEMENT_MAKE_VIEWER(Choice);
IMPLEMENT_MAKE_VIEWER(Color); IMPLEMENT_MAKE_VIEWER(Color);
IMPLEMENT_MAKE_VIEWER(Image); IMPLEMENT_MAKE_VIEWER(Image);
ValueViewerP SymbolStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); } ValueViewerP SymbolStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
ValueViewerP TextStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); } //ValueViewerP TextStyle ::makeViewer(DataViewer& parent, const StyleP& thisP) { return ValueViewerP(); }
ValueEditorP ChoiceStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); } ValueEditorP ChoiceStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); }
ValueEditorP BooleanStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); } ValueEditorP BooleanStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); }
......
...@@ -156,7 +156,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ...@@ -156,7 +156,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
} catch (...) { } catch (...) {
// cleanup after an exception // cleanup after an exception
if (scope) closeScope(scope); // restore scope if (useScope) closeScope(scope); // restore scope
stack.resize(stack_size); // restore stack stack.resize(stack_size); // restore stack
throw; // rethrow throw; // rethrow
} }
...@@ -307,4 +307,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& ...@@ -307,4 +307,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
// ----------------------------------------------------------------------------- : Simple instructions : ternary // ----------------------------------------------------------------------------- : Simple instructions : ternary
void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c) { void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP& b, const ScriptValueP& c) {
switch (i) {
case I_RGB:
a = toScript(Color((int)*a, (int)*b, (int)*c));
break;
}
} }
...@@ -135,9 +135,10 @@ void TokenIterator::readToken() { ...@@ -135,9 +135,10 @@ void TokenIterator::readToken() {
input = more.top().input; input = more.top().input;
pos = more.top().pos; pos = more.top().pos;
more.pop(); more.pop();
} } else {
// EOF // EOF
addToken(TOK_EOF, _("end of input")); addToken(TOK_EOF, _("end of input"));
}
return; return;
} }
// read a character from the input // read a character from the input
......
...@@ -15,11 +15,17 @@ ...@@ -15,11 +15,17 @@
typedef map<String, unsigned int> Variables; typedef map<String, unsigned int> Variables;
Variables variables; Variables variables;
DECLARE_TYPEOF(Variables); DECLARE_TYPEOF(Variables);
#ifdef _DEBUG
vector<String> variable_names;
#endif
/// Return a unique name for a variable to allow for faster loopups /// Return a unique name for a variable to allow for faster loopups
unsigned int string_to_variable(const String& s) { unsigned int string_to_variable(const String& s) {
map<String, unsigned int>::iterator it = variables.find(s); map<String, unsigned int>::iterator it = variables.find(s);
if (it == variables.end()) { if (it == variables.end()) {
#ifdef _DEBUG
variable_names.push_back(s);
#endif
unsigned int v = (unsigned int)variables.size(); unsigned int v = (unsigned int)variables.size();
variables.insert(make_pair(s,v)); variables.insert(make_pair(s,v));
return v; return v;
......
...@@ -61,7 +61,7 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) { ...@@ -61,7 +61,7 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) {
ctx->setVariable(_("game"), toScript(set.game)); ctx->setVariable(_("game"), toScript(set.game));
ctx->setVariable(_("stylesheet"), toScript(stylesheet)); ctx->setVariable(_("stylesheet"), toScript(stylesheet));
ctx->setVariable(_("card"), set.cards.empty() ? script_nil : toScript(set.cards.front())); // dummy value ctx->setVariable(_("card"), set.cards.empty() ? script_nil : toScript(set.cards.front())); // dummy value
//ctx->setVariable(_("styling"), toScript(set->extraStyleData(style))); ctx->setVariable(_("styling"), toScript(&set.stylingDataFor(*stylesheet)));
try { try {
// perform init scripts, don't use a scope, variables stay bound in the context // perform init scripts, don't use a scope, variables stay bound in the context
set.game ->init_script.invoke(*ctx, false); set.game ->init_script.invoke(*ctx, false);
......
...@@ -18,6 +18,7 @@ void store(const ScriptValueP& val, String& var) { var = static_cas ...@@ -18,6 +18,7 @@ void store(const ScriptValueP& val, String& var) { var = static_cas
void store(const ScriptValueP& val, int& var) { var = *val; } void store(const ScriptValueP& val, int& var) { var = *val; }
void store(const ScriptValueP& val, double& var) { var = *val; } void store(const ScriptValueP& val, double& var) { var = *val; }
void store(const ScriptValueP& val, bool& var) { var = static_cast<int>(*val); } void store(const ScriptValueP& val, bool& var) { var = static_cast<int>(*val); }
void store(const ScriptValueP& val, Color& var) { var = *val; }
void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); } void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); }
// ----------------------------------------------------------------------------- : OptionalScript // ----------------------------------------------------------------------------- : OptionalScript
......
...@@ -25,6 +25,7 @@ void store(const ScriptValueP& val, String& var); ...@@ -25,6 +25,7 @@ void store(const ScriptValueP& val, String& var);
void store(const ScriptValueP& val, int& var); void store(const ScriptValueP& val, int& var);
void store(const ScriptValueP& val, double& var); void store(const ScriptValueP& val, double& var);
void store(const ScriptValueP& val, bool& var); void store(const ScriptValueP& val, bool& var);
void store(const ScriptValueP& val, Color& var);
void store(const ScriptValueP& val, Defaultable<String>& var); void store(const ScriptValueP& val, Defaultable<String>& var);
// ----------------------------------------------------------------------------- : OptionalScript // ----------------------------------------------------------------------------- : OptionalScript
......
...@@ -162,6 +162,10 @@ class ScriptString : public ScriptValue { ...@@ -162,6 +162,10 @@ class ScriptString : public ScriptValue {
long l; long l;
if (value.ToLong(&l)) { if (value.ToLong(&l)) {
return l; return l;
} else if (value == _("yes") || value == _("true")) {
return true;
} else if (value == _("no") || value == _("false")) {
return false;
} else { } else {
throw ScriptError(_("Not a number: '") + value + _("'")); throw ScriptError(_("Not a number: '") + value + _("'"));
} }
...@@ -193,6 +197,7 @@ class ScriptColor : public ScriptValue { ...@@ -193,6 +197,7 @@ class ScriptColor : public ScriptValue {
ScriptColor(const Color& v) : value(v) {} ScriptColor(const Color& v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLOR; } virtual ScriptType type() const { return SCRIPT_COLOR; }
virtual String typeName() const { return _("color"); } virtual String typeName() const { return _("color"); }
virtual operator Color() const { return value; }
private: private:
Color value; Color value;
}; };
......
...@@ -214,6 +214,12 @@ class ScriptMap : public ScriptValue { ...@@ -214,6 +214,12 @@ class ScriptMap : public ScriptValue {
// ----------------------------------------------------------------------------- : Objects // ----------------------------------------------------------------------------- : Objects
/// Number of items in some collection like object, can be overloaded
template <typename T>
int item_count(const T& v) {
return -1;
}
/// Script value containing an object (pointer) /// Script value containing an object (pointer)
template <typename T> template <typename T>
class ScriptObject : public ScriptValue { class ScriptObject : public ScriptValue {
...@@ -239,6 +245,10 @@ class ScriptObject : public ScriptValue { ...@@ -239,6 +245,10 @@ class ScriptObject : public ScriptValue {
} }
} }
} }
virtual int itemCount() const {
int i = item_count(*value);
return i >= 0 ? i : ScriptValue::itemCount();
}
private: private:
T value; ///< The object T value; ///< The object
ScriptValueP getDefault() const { ScriptValueP getDefault() const {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
/** - K must have a unique member ->index of type UInt /** - K must have a unique member ->index of type UInt
* - There must exist a function void init_object(Key, Value&) * - There must exist a function void init_object(Key, Value&)
* that stores a new V object for a given key in the reference * that stores a new V object for a given key in the reference
* if the value is already set the function should do nothing
* - There must exist a function Key get_key(Value) * - There must exist a function Key get_key(Value)
* that returns a key for a given value * that returns a key for a given value
* - For reflection there must exist a function String get_key_name(Value) * - For reflection there must exist a function String get_key_name(Value)
...@@ -39,9 +40,10 @@ class IndexMap : private vector<Value> { ...@@ -39,9 +40,10 @@ class IndexMap : private vector<Value> {
using vector<Value>::begin; using vector<Value>::begin;
using vector<Value>::end; using vector<Value>::end;
/// Initialize this map with default values given a list of keys, has no effect if !empty() /// Initialize this map with default values given a list of keys
/** has no effect if already initialized with the given keys */
void init(const vector<Key>& keys) { void init(const vector<Key>& keys) {
if (!this->empty()) return; if (this->size() == keys.size()) return;
this->reserve(keys.size()); this->reserve(keys.size());
for(vector<Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it) { for(vector<Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it) {
const Key& key = *it; const Key& key = *it;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// ----------------------------------------------------------------------------- : GetDefaultMember // ----------------------------------------------------------------------------- : GetDefaultMember
template <> void GetDefaultMember::handle(const Char* const& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const String& v) { value = toScript(v); } template <> void GetDefaultMember::handle(const String& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const int& v) { value = toScript(v); } template <> void GetDefaultMember::handle(const int& v) { value = toScript(v); }
template <> void GetDefaultMember::handle(const unsigned int& v) { value = toScript((int)v); } template <> void GetDefaultMember::handle(const unsigned int& v) { value = toScript((int)v); }
......
...@@ -192,13 +192,13 @@ void Reader::handle(map<String, V>& m) { ...@@ -192,13 +192,13 @@ void Reader::handle(map<String, V>& m) {
template <typename K, typename V> template <typename K, typename V>
void Reader::handle(IndexMap<K,V>& m) { void Reader::handle(IndexMap<K,V>& m) {
do { //do {
UInt l = line_number; // UInt l = line_number;
for (typename IndexMap<K,V>::iterator it = m.begin() ; it != m.end() ; ++it) { for (typename IndexMap<K,V>::iterator it = m.begin() ; it != m.end() ; ++it) {
handle(get_key_name(*it).c_str(), *it); handle(get_key_name(*it).c_str(), *it);
} }
if (l == line_number) unknownKey(m); // if (l == line_number) unknownKey(m);
} while (indent >= expected_indent); //} while (indent >= expected_indent);
} }
// ----------------------------------------------------------------------------- : Reflection // ----------------------------------------------------------------------------- : Reflection
......
...@@ -41,7 +41,7 @@ class RealSize { ...@@ -41,7 +41,7 @@ class RealSize {
{} {}
/// Addition of two sizes /// Addition of two sizes
inline void operator += (const RealSize& s2) { /* inline void operator += (const RealSize& s2) {
width += s2.width; width += s2.width;
height += s2.height; height += s2.height;
} }
...@@ -62,7 +62,7 @@ class RealSize { ...@@ -62,7 +62,7 @@ class RealSize {
inline RealSize operator - () const { inline RealSize operator - () const {
return RealSize(-width, -height); return RealSize(-width, -height);
} }
*/
/// Multiplying a size by a scalar r, multiplies both components /// Multiplying a size by a scalar r, multiplies both components
inline void operator *= (double r) { inline void operator *= (double r) {
width *= r; width *= r;
...@@ -83,6 +83,26 @@ class RealSize { ...@@ -83,6 +83,26 @@ class RealSize {
} }
}; };
/// Add two sizes horizontally
/** #### $$$ ####$$$
* #### + $$$ = ####$$$
* #### ####...
*/
inline RealSize addHorizontal(const RealSize& a, const RealSize& b) {
return RealSize(a.width + b.width, max(a.height, b.height));
}
/// Add two sizes vertically
/** #### $$$ ####
* #### + $$$ = ####
* #### ####
* $$$.
* $$$.
*/
inline RealSize addVertical(const RealSize& a, const RealSize& b) {
return RealSize(max(a.width, b.width), a.height + b.height);
}
// ----------------------------------------------------------------------------- : Rectangle using doubles // ----------------------------------------------------------------------------- : Rectangle using doubles
/// A rectangle (postion and size) using real (double) coordinats /// A rectangle (postion and size) using real (double) coordinats
...@@ -110,9 +130,9 @@ class RealRect { ...@@ -110,9 +130,9 @@ class RealRect {
inline RealRect grow(double amount) { inline RealRect grow(double amount) {
return RealRect(position.x - amount, position.y - amount, size.width + 2 * amount, size.height + 2 * amount); return RealRect(position.x - amount, position.y - amount, size.width + 2 * amount, size.height + 2 * amount);
} }
/// Move the coordinates by some amount
inline RealRect operator + (const RealRect& r) const { inline RealRect move(double dx, double dy, double dw, double dh) {
return RealRect(position + r.position, size + r.size); return RealRect(position.x + dx, position.y + dy, size.width + dw, size.height + dh);
} }
}; };
......
...@@ -11,15 +11,25 @@ ...@@ -11,15 +11,25 @@
// ----------------------------------------------------------------------------- : Rotation // ----------------------------------------------------------------------------- : Rotation
// constrain an angle to {0,90,180,270}
int constrain_angle(int angle) {
int a = ((angle + 45) % 360 + 360) % 360; // [0..360)
return (a / 90) * 90; // multiple of 90
}
Rotation::Rotation(int angle, const RealRect& rect, double zoom) Rotation::Rotation(int angle, const RealRect& rect, double zoom)
: angle(angle) : angle(constrain_angle(angle))
, size(rect.size) , size(rect.size)
, origin(rect.position) , origin(rect.position)
, zoom(zoom) , zoom(zoom)
{ {
// set origin // set origin
if (revX()) origin.x += size.width; if (revX()) origin.x += size.width;
if (revY()) origin.x += size.height; if (revY()) origin.y += size.height;
}
RealRect Rotation::getExternalRect() const {
return RealRect(origin - RealSize(revX() ? size.width : 0, revY() ? size.height : 0), size);
} }
RealPoint Rotation::tr(const RealPoint& p) const { RealPoint Rotation::tr(const RealPoint& p) const {
...@@ -72,6 +82,21 @@ RealPoint Rotation::trInv(const RealPoint& p) const { ...@@ -72,6 +82,21 @@ RealPoint Rotation::trInv(const RealPoint& p) const {
// ----------------------------------------------------------------------------- : Rotater // ----------------------------------------------------------------------------- : Rotater
Rotater::Rotater(Rotation& rot, const Rotation& by)
: old(rot)
, rot(rot)
{
// apply rotation
RealRect new_ext = rot.trNoNeg(by.getExternalRect());
rot.angle = constrain_angle(rot.angle + by.angle);
rot.zoom *= by.zoom;
rot.size = new_ext.size;
rot.origin = new_ext.position + RealSize(rot.revX() ? rot.size.width : 0, rot.revY() ? rot.size.height : 0);
}
Rotater::~Rotater() {
rot = old; // restore
}
// ----------------------------------------------------------------------------- : RotatedDC // ----------------------------------------------------------------------------- : RotatedDC
......
...@@ -34,6 +34,8 @@ class Rotation { ...@@ -34,6 +34,8 @@ class Rotation {
inline RealSize getInternalSize() const { return trInv(size); } inline RealSize getInternalSize() const { return trInv(size); }
/// The intarnal rectangle (origin at (0,0)) /// The intarnal rectangle (origin at (0,0))
inline RealRect getInternalRect() const { return RealRect(RealPoint(0,0), getInternalSize()); } inline RealRect getInternalRect() const { return RealRect(RealPoint(0,0), getInternalSize()); }
/// The external rectangle (as passed to the constructor) == trNoNeg(getInternalRect())
RealRect getExternalRect() const;
/// Translate a size or length /// Translate a size or length
inline double trS(double s) const { return s * zoom; } inline double trS(double s) const { return s * zoom; }
...@@ -67,6 +69,8 @@ class Rotation { ...@@ -67,6 +69,8 @@ class Rotation {
RealPoint origin; ///< tr(0,0) RealPoint origin; ///< tr(0,0)
double zoom; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external double zoom; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external
friend class Rotater;
/// Is the rotation sideways (90 or 270 degrees)? /// Is the rotation sideways (90 or 270 degrees)?
// Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270) // Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270)
inline bool sideways() const { return (angle & 2) != 0; } inline bool sideways() const { return (angle & 2) != 0; }
...@@ -91,11 +95,15 @@ class Rotation { ...@@ -91,11 +95,15 @@ class Rotation {
* @endcode * @endcode
*/ */
class Rotater { class Rotater {
public:
/// Compose a rotation by onto the rotation rot /// Compose a rotation by onto the rotation rot
/** rot is restored when this object is destructed /** rot is restored when this object is destructed
*/ */
Rotater(Rotation& rot, const Rotation& by); Rotater(Rotation& rot, const Rotation& by);
~Rotater(); ~Rotater();
private:
Rotation old;
Rotation& rot;
}; };
// ----------------------------------------------------------------------------- : RotatedDC // ----------------------------------------------------------------------------- : RotatedDC
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/** @file util/string.hpp /** @file util/string.hpp
* *
* String and character utility functions and macros * @brief String and character utility functions and macros
*/ */
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/tagged_string.hpp>
// ----------------------------------------------------------------------------- : Conversion to/from normal string
String untag(const String& str) {
bool intag = false;
String ret; ret.reserve(str.size());
FOR_EACH_CONST(c, str) {
if (c==_('<')) intag = true;
if (!intag) ret += c==_('\1') ? _('<') : c;
if (c==_('>')) intag = false;
}
return ret;
}
String untag_no_escape(const String& str) {
bool intag = false;
String ret; ret.reserve(str.size());
FOR_EACH_CONST(c, str) {
if (c==_('<')) intag = true;
if (!intag) ret += c;
if (c==_('>')) intag = false;
}
return ret;
}
String escape(const String& str) {
String ret; ret.reserve(str.size());
FOR_EACH_CONST(c, str) {
if (c==_('<')) ret += _('\1');
else ret += c;
}
return ret;
}
// ----------------------------------------------------------------------------- : Finding tags
size_t skip_tag(const String& str, size_t start) {
if (start >= str.size()) return String::npos;
size_t end = str.find_first_of(_('>'), start);
return end == String::npos ? String::npos : end + 1;
}
// ----------------------------------------------------------------------------- : Global operations
// ----------------------------------------------------------------------------- : Simplification
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_TAGGED_STRING
#define HEADER_UTIL_TAGGED_STRING
/** @file util/tagged_string.hpp
*
* @brief Utility for working with strings with tags
*/
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
// ----------------------------------------------------------------------------- : Conversion to/from normal string
/// Remove all tags from a string and convert escaped '<' back to normal '<'
/** e.g. "<sym>R</> something <i>(note)</>"
* becomes "R something (note)"
*/
String untag(const String&);
/// Remove all tags from a string, but doesn't convert back escape codes
/** untag_no_escape(x) = escape(untag(x)) */
String untag_no_escape(const String&);
/// Remove all tags from a string
/** In addition to what untag() does this function also removes <sep-soft>...</sep-soft>
*/
String untag_hide_sep(const String&);
/// Escapes a String by converting '>' to '\1'
String escape(const String&);
/// Convert old style </> close tags to new style </tag> tags
/** This style was used until 0.2.6 */
String fix_old_tags(const String&);
// ----------------------------------------------------------------------------- : Finding tags
/// Returns the position just beyond the tag starting at start
size_t skip_tag(const String& str, size_t start);
/// Find the position of the closing tag matching the tag at start
/** If not found returns String::npos
*/
size_t match_close_tag(const String& str, size_t start);
/// Return the tag at the given position (without the <>)
String tag_at(const String& str, size_t pos);
/// Return the tag at the given position (without the <>)
/** stops at '-', so for "<kw-a>" returns "kw" */
String tag_type_at(const String& str, size_t pos);
/// Matching close tag for a tag
String close_tag(const String& tag);
/// The matching close tag for an open tag and vice versa
String anti_tag(const String& tag);
// ----------------------------------------------------------------------------- : Global operations
/// Remove all instances of a tag and its close tag, but keep the contents.
/** tag doesn't have to be a complete tag, for example remove_tag(str, "<kw-")
* removes all tags starting with "<kw-".
*/
String remove_tag(const String& str, const String& tag);
/// Remove all instances of tags starting with tag
String remove_tag_exact(const String& str, const String& tag);
/// Remove all instances of a tag (including contents) from a string
/** tag doesn't have to be a complete tag, for example remove_tag_contents(str, "<kw-")
* removes all tags starting with "<kw-".
*/
String remove_tag_contents(const String& str, const String& tag);
// ----------------------------------------------------------------------------- : Simplification
/// Verify that a string is correctly tagged, if it is not, change it so it is
/** Ensures that:
* - All tags end, i.e. for each '<' there is a matching '>'
* - There are no tags containing '<'
*/
String verify_tagged(const String& str);
/// Simplify a tagged string
/** - merges adjecent open/close tags: "<tag></tag>" --> ""
* - removes overlapping tags: "<i>a<i>b</i>c</i>" --> "<i>abc</i>"
*/
String simplify_tagged(const String& str);
/// Simplify a tagged string by merging adjecent open/close tags "<tag></tag>" --> ""
String simplify_tagged_merge(const String& str);
/// Simplify overlapping formatting tags
String simplify_tagged_overlap(const String& str);
// ----------------------------------------------------------------------------- : EOF
#endif
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