mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Basic text rendering working;
Added Font (done) and SymbolFont (skeleton); Added styling to set; Added CountourMap; Some script fixes git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@73 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+2
-2
@@ -93,7 +93,7 @@ IMPLEMENT_REFLECTION(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&) {
|
||||
throw InternalError(_("IndexMap contains nullptr StyleP the application should have crashed already"));
|
||||
@@ -123,7 +123,7 @@ IMPLEMENT_REFLECTION_NAMELESS(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&) {
|
||||
throw InternalError(_("IndexMap contains nullptr ValueP the application should have crashed already"));
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ class Style {
|
||||
|
||||
/// Update scripted values of this style, return true if anything has changed
|
||||
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;
|
||||
|
||||
private:
|
||||
|
||||
+22
-2
@@ -22,6 +22,12 @@ String TextField::typeName() const {
|
||||
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) {
|
||||
REFLECT_BASE(Field);
|
||||
@@ -48,10 +54,19 @@ TextStyle::TextStyle(const TextFieldP& field)
|
||||
, 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) {
|
||||
REFLECT_BASE(Style);
|
||||
// REFLECT(font);
|
||||
// REFLECT(symbol_font);
|
||||
REFLECT(font);
|
||||
REFLECT(symbol_font);
|
||||
REFLECT(always_symbol);
|
||||
REFLECT(allow_formating);
|
||||
REFLECT(alignment);
|
||||
@@ -75,6 +90,11 @@ IMPLEMENT_REFLECTION(TextStyle) {
|
||||
String TextValue::toString() const {
|
||||
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) {
|
||||
REFLECT_NAMELESS(value);
|
||||
|
||||
+23
-12
@@ -12,7 +12,10 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <util/defaultable.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <data/font.hpp>
|
||||
#include <data/symbol_font.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : TextField
|
||||
|
||||
@@ -31,7 +34,9 @@ class TextField : public Field {
|
||||
bool multi_line; ///< Are newlines allowed in the text?
|
||||
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
|
||||
|
||||
|
||||
virtual void initDependencies(Context&, const Dependency&) const;
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
@@ -44,21 +49,25 @@ class TextStyle : public Style {
|
||||
TextStyle(const TextFieldP&);
|
||||
DECLARE_STYLE_TYPE(Text);
|
||||
|
||||
// FontInfo font; ///< Font to use for the text
|
||||
// SymbolFontInfo symbol_font; ///< Symbol font for symbols in the text
|
||||
bool always_symbol; ///< Should everything be drawn as symbols?
|
||||
bool allow_formating; ///< Is formating (bold/italic/..) allowed?
|
||||
Alignment alignment; ///< Alignment inside the box
|
||||
int angle; ///< Angle of the text inside the box
|
||||
Font font; ///< Font to use for the text
|
||||
SymbolFontRef symbol_font; ///< Symbol font for symbols in the text
|
||||
bool always_symbol; ///< Should everything be drawn as symbols?
|
||||
bool allow_formating; ///< Is formating (bold/italic/..) allowed?
|
||||
Alignment alignment; ///< Alignment inside the box
|
||||
int angle; ///< Angle of the text inside the box
|
||||
double padding_left, padding_left_min; ///< Padding
|
||||
double padding_right, padding_right_min; ///< Padding
|
||||
double padding_top, padding_top_min; ///< Padding
|
||||
double padding_bottom, padding_bottom_min; ///< Padding
|
||||
double line_height_soft; ///< Line height for soft linebreaks
|
||||
double line_height_hard; ///< Line height for hard linebreaks
|
||||
double line_height_line; ///< Line height for <line> tags
|
||||
String mask_filename; ///< Filename of the mask
|
||||
// ContourMaskP mask; ///< Mask to fit the text to (may be null)
|
||||
double line_height_soft; ///< Line height for soft linebreaks
|
||||
double line_height_hard; ///< Line height for hard linebreaks
|
||||
double line_height_line; ///< Line height for <line> tags
|
||||
String mask_filename; ///< Filename of the mask
|
||||
ContourMask mask; ///< Mask to fit the text to (may be null)
|
||||
|
||||
virtual bool update(Context&);
|
||||
virtual void initDependencies(Context&, const Dependency&) const;
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
@@ -74,6 +83,8 @@ class TextValue : public Value {
|
||||
Defaultable<String> value; ///< The text of this value
|
||||
|
||||
virtual String toString() const;
|
||||
virtual bool update(Context&);
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
+56
-1
@@ -14,6 +14,7 @@
|
||||
#include <data/field/text.hpp> // for 0.2.7 fix
|
||||
#include <script/value.hpp>
|
||||
#include <script/script_manager.hpp>
|
||||
#include <wx/sstream.h>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(CardP);
|
||||
typedef IndexMap<FieldP,ValueP> IndexMap_FieldP_ValueP;
|
||||
@@ -45,6 +46,9 @@ Context& Set::getContext() {
|
||||
Context& Set::getContext(const Card& card) {
|
||||
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) {
|
||||
if (card && card->stylesheet) return card->stylesheet;
|
||||
@@ -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) {
|
||||
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);
|
||||
if (game) {
|
||||
if (tag.reading()) {
|
||||
@@ -100,11 +112,54 @@ IMPLEMENT_REFLECTION(Set) {
|
||||
WITH_DYNAMIC_ARG(game_for_reading, game.get());
|
||||
REFLECT(stylesheet);
|
||||
REFLECT_N("set_info", data);
|
||||
if (stylesheet) {
|
||||
REFLECT_N("styling", styling_data);
|
||||
}
|
||||
REFLECT(cards);
|
||||
}
|
||||
reflect_set_info_get_member(tag,data);
|
||||
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
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ DECLARE_POINTER_TYPE(Card);
|
||||
DECLARE_POINTER_TYPE(Set);
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
DECLARE_POINTER_TYPE(Styling);
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Value);
|
||||
class ScriptManager;
|
||||
@@ -44,6 +45,9 @@ class Set : public Packaged {
|
||||
/// The values on the fields of the set
|
||||
/** The indices should correspond to the set_fields in the Game */
|
||||
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
|
||||
vector<CardP> cards;
|
||||
/// Code to use for apprentice (Magic only)
|
||||
@@ -57,10 +61,15 @@ class Set : public Packaged {
|
||||
/// A context for performing scripts on a particular card
|
||||
/** Should only be used from the main thread! */
|
||||
Context& getContext(const Card& card);
|
||||
/// Update styles for a card
|
||||
void updateFor(const CardP& card);
|
||||
|
||||
/// Stylesheet to use for a particular card
|
||||
StyleSheetP stylesheetFor(const CardP& card);
|
||||
|
||||
/// Styling information for a particular stylesheet
|
||||
IndexMap<FieldP, ValueP>& stylingDataFor(const StyleSheet&);
|
||||
|
||||
protected:
|
||||
virtual String typeName() const;
|
||||
virtual void validate(Version);
|
||||
@@ -71,6 +80,9 @@ class Set : public Packaged {
|
||||
scoped_ptr<ScriptManager> script_manager;
|
||||
};
|
||||
|
||||
inline int item_count(const Set& set) {
|
||||
return (int)set.cards.size();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetView
|
||||
|
||||
|
||||
+14
-3
@@ -24,6 +24,14 @@ StyleSheet::StyleSheet()
|
||||
StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) {
|
||||
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::typeName() const { return _("style"); }
|
||||
@@ -36,6 +44,7 @@ InputStreamP StyleSheet::openIconFile() {
|
||||
return game->openIconFile(); // use game icon by default
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
// < 0.3.0 didn't use card_ prefix
|
||||
tag.addAlias(300, _("width"), _("card width"));
|
||||
@@ -44,6 +53,8 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
tag.addAlias(300, _("background"), _("card background"));
|
||||
tag.addAlias(300, _("info style"), _("set info style"));
|
||||
tag.addAlias(300, _("align"), _("alignment"));
|
||||
tag.addAlias(300, _("extra field"),_("styling field"));
|
||||
tag.addAlias(300, _("extra style"),_("styling style"));
|
||||
|
||||
REFLECT(game);
|
||||
REFLECT(full_name);
|
||||
@@ -61,9 +72,9 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
REFLECT(card_style);
|
||||
REFLECT(set_info_style);
|
||||
}
|
||||
// io(_("extra field"), extraSetFields);
|
||||
// extraInfoStyle.init(extraSetFields);
|
||||
// io(_("extra style"), extraInfoStyle);
|
||||
REFLECT(styling_fields);
|
||||
if (tag.reading()) styling_style.init(styling_fields);
|
||||
REFLECT(styling_style);
|
||||
}
|
||||
|
||||
void StyleSheet::validate(Version) {
|
||||
|
||||
@@ -34,18 +34,23 @@ class StyleSheet : public Packaged {
|
||||
double card_dpi; ///< The resolution of a card in dots per inch
|
||||
Color card_background; ///< The background color of cards
|
||||
/// 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;
|
||||
/// The styling for set info fields
|
||||
/** The indices should correspond to the set_fields in the Game */
|
||||
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?
|
||||
|
||||
/// Load a StyleSheet, given a Game and the name of the StyleSheet
|
||||
static StyleSheetP byGameAndName(const Game& game, const String& name);
|
||||
/// name of the package without the game name
|
||||
String styleName();
|
||||
String stylesheetName() const;
|
||||
|
||||
static String typeNameStatic();
|
||||
virtual String typeName() const;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
+42
-1
@@ -14,7 +14,8 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include "../util/prec.hpp"
|
||||
#include <util/prec.hpp>
|
||||
#include <util/real_point.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Resampling
|
||||
|
||||
@@ -103,6 +104,46 @@ void combine_image(Image& a, const Image& b, ImageCombine combine);
|
||||
/// 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);
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
|
||||
inline int bot(int x) { return max(0, x); } ///< bottom range check for color values
|
||||
|
||||
@@ -210,5 +210,5 @@ CardP CardsPanel::selectedCard() const {
|
||||
}
|
||||
void CardsPanel::selectCard(const CardP& card) {
|
||||
card_list->setCard(card);
|
||||
editor->setCard(*card);
|
||||
editor->setCard(card);
|
||||
}
|
||||
|
||||
+103
-33
@@ -631,15 +631,42 @@
|
||||
<File
|
||||
RelativePath=".\data\card.hpp">
|
||||
</File>
|
||||
<File
|
||||
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
|
||||
RelativePath=".\data\font.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\game.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\game.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\locale.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\set.cpp">
|
||||
</File>
|
||||
@@ -676,6 +703,12 @@
|
||||
<File
|
||||
RelativePath=".\data\symbol.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\symbol_font.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\data\symbol_font.hpp">
|
||||
</File>
|
||||
<Filter
|
||||
Name="action"
|
||||
Filter="">
|
||||
@@ -887,6 +920,12 @@
|
||||
<File
|
||||
RelativePath=".\util\string.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\tagged_string.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\tagged_string.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\window_id.hpp">
|
||||
</File>
|
||||
@@ -1183,36 +1222,6 @@
|
||||
<Filter
|
||||
Name="value"
|
||||
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
|
||||
RelativePath=".\render\value\choice.cpp">
|
||||
<FileConfiguration
|
||||
@@ -1486,6 +1495,67 @@
|
||||
RelativePath=".\render\symbol\viewer.hpp">
|
||||
</File>
|
||||
</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>
|
||||
<File
|
||||
RelativePath=".\code_template.cpp">
|
||||
|
||||
@@ -33,6 +33,8 @@ void DataViewer::draw(RotatedDC& dc) {
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(set->stylesheet->card_background);
|
||||
dc.DrawRectangle(dc.getInternalRect());
|
||||
// update style scripts
|
||||
if (card) set->updateFor(card);
|
||||
// draw values
|
||||
FOR_EACH(v, viewers) { // draw low z index fields first
|
||||
if (v->getStyle()->visible) {// visible
|
||||
@@ -52,10 +54,11 @@ Context& DataViewer::getContext() const { return set->getContext(); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : Setting data
|
||||
|
||||
void DataViewer::setCard(Card& card) {
|
||||
void DataViewer::setCard(const CardP& card) {
|
||||
assert(set);
|
||||
this->card = card;
|
||||
setStyles(set->stylesheet->card_style);
|
||||
setData(card.data);
|
||||
setData(card->data);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Viewers
|
||||
|
||||
@@ -54,7 +54,7 @@ class DataViewer : public SetView {
|
||||
// --------------------------------------------------- : Setting data
|
||||
|
||||
/// Display a card in this viewer
|
||||
void setCard(Card& card);
|
||||
void setCard(const CardP& card);
|
||||
|
||||
// --------------------------------------------------- : The viewers
|
||||
protected:
|
||||
@@ -74,7 +74,8 @@ class DataViewer : public SetView {
|
||||
virtual void onChange() {}
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,186 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
@@ -0,0 +1,52 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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() {}
|
||||
@@ -0,0 +1,97 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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) {
|
||||
dc.DrawRectangle(RealRect(style().left, style().top, 40, style().height));
|
||||
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
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));
|
||||
} else {
|
||||
// do we need clipping?
|
||||
|
||||
@@ -7,5 +7,19 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#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 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#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
|
||||
|
||||
@@ -78,11 +78,12 @@ ValueViewerP BooleanStyle ::makeViewer(DataViewer& parent, const StyleP& t
|
||||
ValueViewerP MultipleChoiceStyle::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(); }
|
||||
IMPLEMENT_MAKE_VIEWER(Text);
|
||||
IMPLEMENT_MAKE_VIEWER(Choice);
|
||||
IMPLEMENT_MAKE_VIEWER(Color);
|
||||
IMPLEMENT_MAKE_VIEWER(Image);
|
||||
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 BooleanStyle ::makeEditor(DataEditor& parent, const StyleP& thisP) { return ValueEditorP(); }
|
||||
|
||||
@@ -156,7 +156,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
||||
|
||||
} catch (...) {
|
||||
// cleanup after an exception
|
||||
if (scope) closeScope(scope); // restore scope
|
||||
if (useScope) closeScope(scope); // restore scope
|
||||
stack.resize(stack_size); // restore stack
|
||||
throw; // rethrow
|
||||
}
|
||||
@@ -307,4 +307,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
|
||||
// ----------------------------------------------------------------------------- : Simple instructions : ternary
|
||||
|
||||
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() {
|
||||
input = more.top().input;
|
||||
pos = more.top().pos;
|
||||
more.pop();
|
||||
} else {
|
||||
// EOF
|
||||
addToken(TOK_EOF, _("end of input"));
|
||||
}
|
||||
// EOF
|
||||
addToken(TOK_EOF, _("end of input"));
|
||||
return;
|
||||
}
|
||||
// read a character from the input
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
typedef map<String, unsigned int> Variables;
|
||||
Variables variables;
|
||||
DECLARE_TYPEOF(Variables);
|
||||
#ifdef _DEBUG
|
||||
vector<String> variable_names;
|
||||
#endif
|
||||
|
||||
/// Return a unique name for a variable to allow for faster loopups
|
||||
unsigned int string_to_variable(const String& s) {
|
||||
map<String, unsigned int>::iterator it = variables.find(s);
|
||||
if (it == variables.end()) {
|
||||
#ifdef _DEBUG
|
||||
variable_names.push_back(s);
|
||||
#endif
|
||||
unsigned int v = (unsigned int)variables.size();
|
||||
variables.insert(make_pair(s,v));
|
||||
return v;
|
||||
|
||||
@@ -61,7 +61,7 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) {
|
||||
ctx->setVariable(_("game"), toScript(set.game));
|
||||
ctx->setVariable(_("stylesheet"), toScript(stylesheet));
|
||||
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 {
|
||||
// perform init scripts, don't use a scope, variables stay bound in the context
|
||||
set.game ->init_script.invoke(*ctx, false);
|
||||
|
||||
@@ -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, double& var) { var = *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); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : OptionalScript
|
||||
|
||||
@@ -25,6 +25,7 @@ void store(const ScriptValueP& val, String& var);
|
||||
void store(const ScriptValueP& val, int& var);
|
||||
void store(const ScriptValueP& val, double& var);
|
||||
void store(const ScriptValueP& val, bool& var);
|
||||
void store(const ScriptValueP& val, Color& var);
|
||||
void store(const ScriptValueP& val, Defaultable<String>& var);
|
||||
|
||||
// ----------------------------------------------------------------------------- : OptionalScript
|
||||
|
||||
@@ -162,6 +162,10 @@ class ScriptString : public ScriptValue {
|
||||
long l;
|
||||
if (value.ToLong(&l)) {
|
||||
return l;
|
||||
} else if (value == _("yes") || value == _("true")) {
|
||||
return true;
|
||||
} else if (value == _("no") || value == _("false")) {
|
||||
return false;
|
||||
} else {
|
||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
||||
}
|
||||
@@ -193,6 +197,7 @@ class ScriptColor : public ScriptValue {
|
||||
ScriptColor(const Color& v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
||||
virtual String typeName() const { return _("color"); }
|
||||
virtual operator Color() const { return value; }
|
||||
private:
|
||||
Color value;
|
||||
};
|
||||
|
||||
@@ -214,6 +214,12 @@ class ScriptMap : public ScriptValue {
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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)
|
||||
template <typename T>
|
||||
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:
|
||||
T value; ///< The object
|
||||
ScriptValueP getDefault() const {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
/** - K must have a unique member ->index of type UInt
|
||||
* - There must exist a function void init_object(Key, Value&)
|
||||
* 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)
|
||||
* that returns a key for a given value
|
||||
* - For reflection there must exist a function String get_key_name(Value)
|
||||
@@ -39,9 +40,10 @@ class IndexMap : private vector<Value> {
|
||||
using vector<Value>::begin;
|
||||
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) {
|
||||
if (!this->empty()) return;
|
||||
if (this->size() == keys.size()) return;
|
||||
this->reserve(keys.size());
|
||||
for(vector<Key>::const_iterator it = keys.begin() ; it != keys.end() ; ++it) {
|
||||
const Key& key = *it;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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 int& v) { value = toScript(v); }
|
||||
template <> void GetDefaultMember::handle(const unsigned int& v) { value = toScript((int)v); }
|
||||
|
||||
@@ -192,13 +192,13 @@ void Reader::handle(map<String, V>& m) {
|
||||
|
||||
template <typename K, typename V>
|
||||
void Reader::handle(IndexMap<K,V>& m) {
|
||||
do {
|
||||
UInt l = line_number;
|
||||
//do {
|
||||
// UInt l = line_number;
|
||||
for (typename IndexMap<K,V>::iterator it = m.begin() ; it != m.end() ; ++it) {
|
||||
handle(get_key_name(*it).c_str(), *it);
|
||||
}
|
||||
if (l == line_number) unknownKey(m);
|
||||
} while (indent >= expected_indent);
|
||||
// if (l == line_number) unknownKey(m);
|
||||
//} while (indent >= expected_indent);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reflection
|
||||
|
||||
+25
-5
@@ -41,7 +41,7 @@ class RealSize {
|
||||
{}
|
||||
|
||||
/// Addition of two sizes
|
||||
inline void operator += (const RealSize& s2) {
|
||||
/* inline void operator += (const RealSize& s2) {
|
||||
width += s2.width;
|
||||
height += s2.height;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class RealSize {
|
||||
inline RealSize operator - () const {
|
||||
return RealSize(-width, -height);
|
||||
}
|
||||
|
||||
*/
|
||||
/// Multiplying a size by a scalar r, multiplies both components
|
||||
inline void operator *= (double r) {
|
||||
width *= r;
|
||||
@@ -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
|
||||
|
||||
/// A rectangle (postion and size) using real (double) coordinats
|
||||
@@ -110,9 +130,9 @@ class RealRect {
|
||||
inline RealRect grow(double amount) {
|
||||
return RealRect(position.x - amount, position.y - amount, size.width + 2 * amount, size.height + 2 * amount);
|
||||
}
|
||||
|
||||
inline RealRect operator + (const RealRect& r) const {
|
||||
return RealRect(position + r.position, size + r.size);
|
||||
/// Move the coordinates by some amount
|
||||
inline RealRect move(double dx, double dy, double dw, double dh) {
|
||||
return RealRect(position.x + dx, position.y + dy, size.width + dw, size.height + dh);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+27
-2
@@ -11,15 +11,25 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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)
|
||||
: angle(angle)
|
||||
: angle(constrain_angle(angle))
|
||||
, size(rect.size)
|
||||
, origin(rect.position)
|
||||
, zoom(zoom)
|
||||
{
|
||||
// set origin
|
||||
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 {
|
||||
@@ -72,6 +82,21 @@ RealPoint Rotation::trInv(const RealPoint& p) const {
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ class Rotation {
|
||||
inline RealSize getInternalSize() const { return trInv(size); }
|
||||
/// The intarnal rectangle (origin at (0,0))
|
||||
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
|
||||
inline double trS(double s) const { return s * zoom; }
|
||||
@@ -67,6 +69,8 @@ class Rotation {
|
||||
RealPoint origin; ///< tr(0,0)
|
||||
double zoom; ///< Zoom factor, zoom = 2.0 means that 1 internal = 2 external
|
||||
|
||||
friend class Rotater;
|
||||
|
||||
/// Is the rotation sideways (90 or 270 degrees)?
|
||||
// Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270)
|
||||
inline bool sideways() const { return (angle & 2) != 0; }
|
||||
@@ -91,11 +95,15 @@ class Rotation {
|
||||
* @endcode
|
||||
*/
|
||||
class Rotater {
|
||||
public:
|
||||
/// Compose a rotation by onto the rotation rot
|
||||
/** rot is restored when this object is destructed
|
||||
*/
|
||||
Rotater(Rotation& rot, const Rotation& by);
|
||||
~Rotater();
|
||||
private:
|
||||
Rotation old;
|
||||
Rotation& rot;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : RotatedDC
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
/** @file util/string.hpp
|
||||
*
|
||||
* String and character utility functions and macros
|
||||
* @brief String and character utility functions and macros
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
@@ -0,0 +1,105 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| 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
|
||||
Reference in New Issue
Block a user