Commit c0d4b975 authored by twanvl's avatar twanvl

Added 'insert symbol' menu for SymbolFonts;

Added scriptable 'enabled' to symbols in symbol font, used instead of scripted filenames. This means changing the tap symbol style now works;
Added localisation for games, stylesheets and symbolfonts;
Warnings from Reader are now shown onIdle;
parent 5602cec0
...@@ -305,6 +305,38 @@ game: ...@@ -305,6 +305,38 @@ game:
# Set info # Set info
# descriptions/help text # descriptions/help text
#stylesheet: stylesheet:
# magic-new: magic-new:
#
\ No newline at end of file symbol font:
magic-mana-small:
menu item T: &Tap symbol T
menu item W: &White mana W
menu item U: Bl&ue mana U
menu item B: &Black mana B
menu item R: &Red mana R
menu item G: &Green mana G
menu item S: &Snow mana S
menu item X: Variable mana &X X
menu item Y: Variable mana &Y Y
menu item Z: Variable mana &Z Z
menu item colorless: &Colorless mana...
menu item half: &Half mana
menu item |W: &White |W
menu item |U: Bl&ue |U
menu item |B: &Black |B
menu item |R: &Red |R
menu item |G: &Green |G
menu item |S: &Snow |S
menu item 1/2: &Colorless 1/2
menu item hybrid: H&ybrid mana (two color)
menu item W/U: White/Blue mana W/U
menu item U/B: Blue/Black mana U/B
menu item B/R: Black/Ref mana B/R
menu item R/G: Red/Green mana R/G
menu item G/W: Green/White mana G/W
menu item W/B: White/Black mana W/B
menu item U/R: Blue/Red mana U/R
menu item B/G: Black/Green mana B/G
menu item R/W: Red/White mana R/W
menu item G/U: Green/blue mana G/U
mse version: 0.2.7 mse version: 0.3.0
# Symbol font in the 'popup' style, used for casting costs on modern cards # Symbol font in the 'popup' style, used for casting costs on modern cards
image font size: 135 image font size: 135
...@@ -7,7 +7,15 @@ symbol: ...@@ -7,7 +7,15 @@ symbol:
image: mana_circle.png image: mana_circle.png
symbol: symbol:
code: T code: T
image: script: mana_t() image: mana_t_older.png
enabled: { mana_t() == "older" }
symbol:
code: T
image: mana_t_old.png
enabled: { mana_t() == "old" }
symbol:
code: T
image: mana_t.png
symbol: symbol:
code: W/U code: W/U
image: mana_wu.png image: mana_wu.png
......
mse version: 0.2.7 mse version: 0.3.0
# Symbol font in the normal, flat, style, used for text boxes and on old style cards # Symbol font in the normal, flat, style, used for text boxes and on old style cards
# Note: # Note:
# Define small_mana_t:="mana_t(_old)?.png" in the init script of the style # Define mana_t := {"new|old|older"} in the init script of the style
# #
# So for example: # So for example:
# #
#init script: #init script:
# small_mana_t := "mana_t.png" # mana_t := {"new"}
image font size: 135 image font size: 135
horizontal space: 2 horizontal space: 2
...@@ -14,7 +14,15 @@ symbol: ...@@ -14,7 +14,15 @@ symbol:
image: mana_circle.png image: mana_circle.png
symbol: symbol:
code: T code: T
image: { mana_t() } image: mana_t_older.png
enabled: { mana_t() == "older" }
symbol:
code: T
image: mana_t_old.png
enabled: { mana_t() == "old" }
symbol:
code: T
image: mana_t.png
symbol: symbol:
code: W/U code: W/U
image: mana_wu.png image: mana_wu.png
...@@ -102,4 +110,50 @@ text font: ...@@ -102,4 +110,50 @@ text font:
text margin left: 3 text margin left: 3
text margin right: 2 text margin right: 2
text margin top: -1 text margin top: -1
text margin bottom: -1 text margin bottom: -1
\ No newline at end of file
##############################################################
# Insert-symbol menu
insert symbol menu:
item: T
item:
type: line
item: X
item: Y
item: Z
item:
type: custom
name: colorless
item:
type: line
item: W
item: U
item: B
item: R
item: G
item: S
item:
type: line
item:
name: half
item: 1/2
item: |W
item: |U
item: |B
item: |R
item: |G
item: |S
item:
name: hybrid
item: W/U
item: U/B
item: B/R
item: R/G
item: G/W
item:
type: line
item: W/B
item: U/R
item: B/G
item: R/W
item: G/U
...@@ -22,7 +22,7 @@ init script: ...@@ -22,7 +22,7 @@ init script:
land_template := { "acard.jpg" } land_template := { "acard.jpg" }
# Use the normal tap symbol # Use the normal tap symbol
mana_t := { "mana_t.png" } mana_t := { "new" }
# Does the card have a color that requires a white font for copyright/artist? # Does the card have a color that requires a white font for copyright/artist?
white_font_colors := filter_rule(match:"^(hybrid )?black|^land") white_font_colors := filter_rule(match:"^(hybrid )?black|^land")
......
...@@ -26,9 +26,9 @@ init script: ...@@ -26,9 +26,9 @@ init script:
# Use the normal tap symbol # Use the normal tap symbol
mana_t := { mana_t := {
if styling.tap_symbol == "old" then "mana_t_old.png" if styling.tap_symbol == "old" then "old"
else if styling.tap_symbol == "diagonal T" then "mana_t_older.png" else if styling.tap_symbol == "diagonal T" then "older"
else "mana_t.png" else "new"
} }
# Does the card have a color that requires a white font for copyright/artist? # Does the card have a color that requires a white font for copyright/artist?
......
...@@ -23,8 +23,8 @@ init script: ...@@ -23,8 +23,8 @@ init script:
# Horizontal 5 color blends are not supported # Horizontal 5 color blends are not supported
card_hybrid_5b := card_hybrid_5 card_hybrid_5b := card_hybrid_5
# Use the normal tap symbol # Use the old tap symbol
mana_t := { "mana_t_old.png" } mana_t := { "old" }
# Does the card have a color that requires a black font for copyright/artist? # Does the card have a color that requires a black font for copyright/artist?
black_font_colors := filter_rule(match:"^(hybrid 2 color)?white") black_font_colors := filter_rule(match:"^(hybrid 2 color)?white")
......
...@@ -23,8 +23,8 @@ init script: ...@@ -23,8 +23,8 @@ init script:
# Horizontal 5 color blends are not supported # Horizontal 5 color blends are not supported
card_hybrid_5b := card_hybrid_5 card_hybrid_5b := card_hybrid_5
# Use the normal tap symbol # Use the old tap symbol
mana_t := { "mana_t_old.png" } mana_t := { "old" }
# Does the card have a color that requires a black font for copyright/artist? # Does the card have a color that requires a black font for copyright/artist?
black_font_colors := filter_rule(match:"^(hybrid 2 color)?white") black_font_colors := filter_rule(match:"^(hybrid 2 color)?white")
......
...@@ -25,7 +25,7 @@ init script: ...@@ -25,7 +25,7 @@ init script:
pt_template := { input + "pt.jpg" } pt_template := { input + "pt.jpg" }
# Use the normal tap symbol # Use the normal tap symbol
small_mana_t := "mana_t.png" mana_t := { "new" }
# Does the card have a color that requires a white font for copyright/artist? # Does the card have a color that requires a white font for copyright/artist?
white_font_colors := filter_rule(match:"^(hybrid 2 color)?black|^land") white_font_colors := filter_rule(match:"^(hybrid 2 color)?black|^land")
......
...@@ -9,8 +9,8 @@ icon: card-sample.png ...@@ -9,8 +9,8 @@ icon: card-sample.png
############################################################## Extra scripts ############################################################## Extra scripts
init script: init script:
# Use the normal tap symbol # Use the old tap symbol
small_mana_t := "mana_t.png" mana_t := { "old" }
############################################################## Set info fields ############################################################## Set info fields
info style: info style:
......
...@@ -21,8 +21,7 @@ IMPLEMENT_REFLECTION(KeywordMode) { ...@@ -21,8 +21,7 @@ IMPLEMENT_REFLECTION(KeywordMode) {
REFLECT(description); REFLECT(description);
} }
IMPLEMENT_REFLECTION(KeywordExpansion) { IMPLEMENT_REFLECTION(KeywordExpansion) {
REFLECT(before); REFLECT(match);
REFLECT(after);
REFLECT(reminder); REFLECT(reminder);
} }
...@@ -36,15 +35,17 @@ void read_compat(Reader& tag, Keyword* k) { ...@@ -36,15 +35,17 @@ void read_compat(Reader& tag, Keyword* k) {
if (!separator.empty() || !parameter.empty() || !reminder.empty()) { if (!separator.empty() || !parameter.empty() || !reminder.empty()) {
// old style keyword declaration, no separate expansion // old style keyword declaration, no separate expansion
KeywordExpansionP e(new KeywordExpansion); KeywordExpansionP e(new KeywordExpansion);
e->match = k->keyword;
size_t start = separator.find_first_of('['); size_t start = separator.find_first_of('[');
size_t end = separator.find_first_of(']'); size_t end = separator.find_first_of(']');
if (start != String::npos && end != String::npos) { if (start != String::npos && end != String::npos) {
e->after += separator.substr(start + 1, end - start - 1); e->match += separator.substr(start + 1, end - start - 1);
} }
if (!parameter.empty()) { if (!parameter.empty()) {
e->after += _("<param>") + parameter + _("</param>"); e->match += _("<param>") + parameter + _("</param>");
} }
e->reminder.set(reminder); e->reminder.set(reminder);
k->expansions.push_back(e);
} }
} }
......
...@@ -46,11 +46,11 @@ class KeywordMode { ...@@ -46,11 +46,11 @@ class KeywordMode {
/// A way to use a keyword /// A way to use a keyword
class KeywordExpansion { class KeywordExpansion {
public: public:
String before; ///< Components before the keyword: parameters and separators (tagged string) String match; ///< String to match, <param> tags are used for parameters
String after; ///< Components after the keyword: parameters and separators
vector<KeywordParamP> parameters; ///< The types of parameters vector<KeywordParamP> parameters; ///< The types of parameters
wxRegEx splitter; ///< Regular expression to split/match the components, automatically generated // wxRegEx splitter; ///< Regular expression to split/match the components, automatically generated
StringScript reminder; ///< Reminder text of the keyword StringScript reminder; ///< Reminder text of the keyword
String mode; ///< Mode of use, can be used by scripts (only gives the name). Default is the mode of the Keyword.
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <data/locale.hpp> #include <data/locale.hpp>
#include <data/game.hpp>
#include <data/stylesheet.hpp>
#include <data/symbol_font.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <script/to_value.hpp> #include <script/to_value.hpp>
...@@ -32,19 +35,64 @@ IMPLEMENT_REFLECTION(Locale) { ...@@ -32,19 +35,64 @@ IMPLEMENT_REFLECTION(Locale) {
REFLECT_N("error", translations[LOCALE_CAT_ERROR]); REFLECT_N("error", translations[LOCALE_CAT_ERROR]);
REFLECT_N("type", translations[LOCALE_CAT_TYPE]); REFLECT_N("type", translations[LOCALE_CAT_TYPE]);
REFLECT_N("game", game_translations); REFLECT_N("game", game_translations);
REFLECT_N("stylesheet", stylesheet_translations);
REFLECT_N("symbol font", symbol_font_translations);
} }
IMPLEMENT_REFLECTION_NAMELESS(GameLocale) { IMPLEMENT_REFLECTION_NAMELESS(SubLocale) {
REFLECT_NAMELESS(translations); REFLECT_NAMELESS(translations);
} }
// ----------------------------------------------------------------------------- : Translation // ----------------------------------------------------------------------------- : Translation
String SubLocale::tr(const String& key) {
map<String,String>::const_iterator it = translations.find(key);
if (it == translations.end()) {
return _("missing:") + key;
} else {
return it->second;
}
}
String SubLocale::tr(const String& key, const String& def) {
map<String,String>::const_iterator it = translations.find(key);
if (it == translations.end()) {
return def;
} else {
return it->second;
}
}
// from util/locale.hpp // from util/locale.hpp
String tr(LocaleCategory cat, const String& key) { String tr(LocaleCategory cat, const String& key) {
if (!the_locale) return key; // no locale loaded (yet) if (!the_locale) return key; // no locale loaded (yet)
map<String,String>::const_iterator it = the_locale->translations[cat].find(key); return the_locale->translations[cat].tr(key);
if (it == the_locale->translations[cat].end()) return _("missing:") + key; }
return it->second;
String tr(const Game& g, const String& key) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->game_translations[g.name()]->tr(key);
}
String tr(const StyleSheet& s, const String& key) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->stylesheet_translations[s.name()]->tr(key);
}
String tr(const SymbolFont& f, const String& key) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->symbol_font_translations[f.name()]->tr(key);
}
String tr(const Game& g, const String& key, const String& def) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->game_translations[g.name()]->tr(key, def);
}
String tr(const StyleSheet& s, const String& key, const String& def) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->stylesheet_translations[s.name()]->tr(key, def);
}
String tr(const SymbolFont& f, const String& key, const String& def) {
if (!the_locale) return key; // no locale loaded (yet)
return the_locale->symbol_font_translations[f.name()]->tr(key, def);
} }
...@@ -15,14 +15,20 @@ ...@@ -15,14 +15,20 @@
#include <util/io/package.hpp> #include <util/io/package.hpp>
DECLARE_POINTER_TYPE(Locale); DECLARE_POINTER_TYPE(Locale);
DECLARE_POINTER_TYPE(GameLocale); DECLARE_POINTER_TYPE(SubLocale);
// ----------------------------------------------------------------------------- : Locale class // ----------------------------------------------------------------------------- : Locale class
/// Translations of the texts of a game /// Translations of the texts of a game/stylesheet/symbolfont
class GameLocale { class SubLocale {
public: public:
map<String,String> translations; map<String,String> translations;
/// Translate a key
String tr(const String& key);
/// Translate a key with a default value
String tr(const String& key, const String& def);
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
...@@ -30,9 +36,13 @@ class GameLocale { ...@@ -30,9 +36,13 @@ class GameLocale {
class Locale : public Packaged { class Locale : public Packaged {
public: public:
/// Translations of UI strings in each category /// Translations of UI strings in each category
map<String,String> translations[LOCALE_CAT_MAX]; SubLocale translations[LOCALE_CAT_MAX];
/// Translations of game specific texts, by game name /// Translations of Game specific texts, by game name
map<String,GameLocaleP> game_translations; map<String,SubLocaleP> game_translations;
/// Translations of StyleSheet specific texts, by stylesheet name
map<String,SubLocaleP> stylesheet_translations;
/// Translations of SymbolFont specific texts, by symbol font name
map<String,SubLocaleP> symbol_font_translations;
/// Open a locale with the given name /// Open a locale with the given name
static LocaleP byName(const String& name); static LocaleP byName(const String& name);
......
...@@ -10,12 +10,14 @@ ...@@ -10,12 +10,14 @@
#include <util/dynamic_arg.hpp> #include <util/dynamic_arg.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
#include <util/rotation.hpp> #include <util/rotation.hpp>
#include <util/error.hpp>
#include <util/window_id.hpp>
#include <render/text/element.hpp> // fot CharInfo #include <render/text/element.hpp> // fot CharInfo
#include <script/image.hpp> #include <script/image.hpp>
#include <util/error.hpp>
DECLARE_TYPEOF_COLLECTION(SymbolFont::DrawableSymbol); DECLARE_TYPEOF_COLLECTION(SymbolFont::DrawableSymbol);
DECLARE_TYPEOF_COLLECTION(SymbolInFontP); DECLARE_TYPEOF_COLLECTION(SymbolInFontP);
DECLARE_TYPEOF_COLLECTION(InsertSymbolMenuP);
// ----------------------------------------------------------------------------- : SymbolFont // ----------------------------------------------------------------------------- : SymbolFont
...@@ -31,8 +33,13 @@ SymbolFont::SymbolFont() ...@@ -31,8 +33,13 @@ SymbolFont::SymbolFont()
, text_margin_top(0), text_margin_bottom(0) , text_margin_top(0), text_margin_bottom(0)
, text_alignment(ALIGN_MIDDLE_CENTER) , text_alignment(ALIGN_MIDDLE_CENTER)
, merge_numbers(false) , merge_numbers(false)
, processed_insert_symbol_menu(nullptr)
{} {}
SymbolFont::~SymbolFont() {
delete processed_insert_symbol_menu;
}
String SymbolFont::typeNameStatic() { return _("symbol-font"); } String SymbolFont::typeNameStatic() { return _("symbol-font"); }
String SymbolFont::typeName() const { return _("symbol-font"); } String SymbolFont::typeName() const { return _("symbol-font"); }
...@@ -57,6 +64,7 @@ IMPLEMENT_REFLECTION(SymbolFont) { ...@@ -57,6 +64,7 @@ IMPLEMENT_REFLECTION(SymbolFont) {
REFLECT(text_margin_top); REFLECT(text_margin_top);
REFLECT(text_margin_bottom); REFLECT(text_margin_bottom);
REFLECT(text_alignment); REFLECT(text_alignment);
REFLECT(insert_symbol_menu);
} }
// ----------------------------------------------------------------------------- : SymbolInFont // ----------------------------------------------------------------------------- : SymbolInFont
...@@ -69,15 +77,21 @@ class SymbolInFont { ...@@ -69,15 +77,21 @@ class SymbolInFont {
/// Get a shrunk, zoomed bitmap /// Get a shrunk, zoomed bitmap
Bitmap getBitmap(Context& ctx, Package& pkg, double size); Bitmap getBitmap(Context& ctx, Package& pkg, double size);
/// Get a bitmap with the given size
Bitmap getBitmap(Context& ctx, Package& pkg, wxSize size);
/// Size of a (zoomed) bitmap /// Size of a (zoomed) bitmap
/** This is the size of the resulting image, it does NOT convert back to internal coordinates */ /** This is the size of the resulting image, it does NOT convert back to internal coordinates */
RealSize size(Context& ctx, Package& pkg, double size); RealSize size(Context& ctx, Package& pkg, double size);
String code; ///< Code for this symbol void update(Context& ctx);
String code; ///< Code for this symbol
Scriptable<bool> enabled; ///< Is this symbol enabled?
private: private:
ScriptableImage image; ///< The image for this symbol ScriptableImage image; ///< The image for this symbol
double img_size; ///< Font size used by the image double img_size; ///< Font size used by the image
wxSize actual_size; ///< Actual image size, only known after loading the image wxSize actual_size; ///< Actual image size, only known after loading the image
/// Cached bitmaps for different sizes /// Cached bitmaps for different sizes
map<double, Bitmap> bitmaps; map<double, Bitmap> bitmaps;
...@@ -86,6 +100,7 @@ class SymbolInFont { ...@@ -86,6 +100,7 @@ class SymbolInFont {
SymbolInFont::SymbolInFont() SymbolInFont::SymbolInFont()
: actual_size(0,0) : actual_size(0,0)
, enabled(true)
{ {
assert(symbol_font_for_reading()); assert(symbol_font_for_reading());
img_size = symbol_font_for_reading()->img_size; img_size = symbol_font_for_reading()->img_size;
...@@ -112,6 +127,18 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) { ...@@ -112,6 +127,18 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) {
} }
return bmp; return bmp;
} }
Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, wxSize size) {
// generate new bitmap
if (!image) {
throw Error(_("No image specified for symbol with code '") + code + _("' in symbol font."));
}
Image img = image.generate(ctx, pkg)->image;
actual_size = wxSize(img.GetWidth(), img.GetHeight());
// scale to match expected size
Image resampled_image(size.GetWidth(), size.GetHeight(), false);
resample_preserve_aspect(img, resampled_image);
return Bitmap(resampled_image);
}
RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) { RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) {
if (actual_size.GetWidth() == 0) { if (actual_size.GetWidth() == 0) {
...@@ -121,9 +148,14 @@ RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) { ...@@ -121,9 +148,14 @@ RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) {
return wxSize(actual_size * size / img_size); return wxSize(actual_size * size / img_size);
} }
void SymbolInFont::update(Context& ctx) {
enabled.update(ctx);
}
IMPLEMENT_REFLECTION(SymbolInFont) { IMPLEMENT_REFLECTION(SymbolInFont) {
REFLECT(code); REFLECT(code);
REFLECT(image); REFLECT(image);
REFLECT(enabled);
REFLECT_N("image font size", img_size); REFLECT_N("image font size", img_size);
} }
...@@ -139,7 +171,11 @@ class SymbolFont::DrawableSymbol { ...@@ -139,7 +171,11 @@ class SymbolFont::DrawableSymbol {
SymbolInFont* symbol; ///< Symbol to draw, if nullptr, use the default symbol and draw the text SymbolInFont* symbol; ///< Symbol to draw, if nullptr, use the default symbol and draw the text
}; };
void SymbolFont::split(const String& text, SplitSymbols& out) const { void SymbolFont::split(const String& text, Context& ctx, SplitSymbols& out) const {
// update all symbol-in-fonts
FOR_EACH_CONST(sym, symbols) {
sym->update(ctx);
}
// read a single symbol until we are done with the text // read a single symbol until we are done with the text
for (size_t pos = 0 ; pos < text.size() ; ) { for (size_t pos = 0 ; pos < text.size() ; ) {
// 1. check merged numbers // 1. check merged numbers
...@@ -154,7 +190,7 @@ void SymbolFont::split(const String& text, SplitSymbols& out) const { ...@@ -154,7 +190,7 @@ void SymbolFont::split(const String& text, SplitSymbols& out) const {
} }
// 2. check symbol list // 2. check symbol list
FOR_EACH_CONST(sym, symbols) { FOR_EACH_CONST(sym, symbols) {
if (!sym->code.empty() && is_substr(text, pos, sym->code)) { // symbol matches if (!sym->code.empty() && sym->enabled && is_substr(text, pos, sym->code)) { // symbol matches
out.push_back(DrawableSymbol(sym->code, sym.get())); out.push_back(DrawableSymbol(sym->code, sym.get()));
pos += sym->code.size(); pos += sym->code.size();
goto next_symbol; // continue two levels goto next_symbol; // continue two levels
...@@ -178,7 +214,7 @@ SymbolInFont* SymbolFont::defaultSymbol() const { ...@@ -178,7 +214,7 @@ SymbolInFont* SymbolFont::defaultSymbol() const {
void SymbolFont::draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text) { void SymbolFont::draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text) {
SplitSymbols symbols; SplitSymbols symbols;
split(text, symbols); split(text, ctx, symbols);
draw(dc, ctx, rect, font_size, align, symbols); draw(dc, ctx, rect, font_size, align, symbols);
} }
...@@ -253,7 +289,7 @@ void SymbolFont::drawWithText(RotatedDC& dc, Context& ctx, const RealRect& rect, ...@@ -253,7 +289,7 @@ void SymbolFont::drawWithText(RotatedDC& dc, Context& ctx, const RealRect& rect,
void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out) { void SymbolFont::getCharInfo(RotatedDC& dc, Context& ctx, double font_size, const String& text, vector<CharInfo>& out) {
SplitSymbols symbols; SplitSymbols symbols;
split(text, symbols); split(text, ctx, symbols);
getCharInfo(dc, ctx, font_size, symbols, out); getCharInfo(dc, ctx, font_size, symbols, out);
} }
...@@ -283,6 +319,133 @@ RealSize SymbolFont::defaultSymbolSize(Context& ctx, double font_size) { ...@@ -283,6 +319,133 @@ RealSize SymbolFont::defaultSymbolSize(Context& ctx, double font_size) {
} }
// ----------------------------------------------------------------------------- : InsertSymbolMenu
wxMenu* SymbolFont::insertSymbolMenu(Context& ctx) {
if (!processed_insert_symbol_menu && insert_symbol_menu) {
// Make menu
processed_insert_symbol_menu = insert_symbol_menu->makeMenu(ID_INSERT_SYMBOL_MENU_MIN, ctx, *this);
}
return processed_insert_symbol_menu;
}
String SymbolFont::insertSymbolCode(int menu_id) const {
// find item
if (insert_symbol_menu) {
return insert_symbol_menu->getCode(menu_id - ID_INSERT_SYMBOL_MENU_MIN, *this);
} else {
return wxEmptyString;
}
}
InsertSymbolMenu::InsertSymbolMenu()
: type(ITEM_CODE)
{}
int InsertSymbolMenu::size() const {
if (type == ITEM_CODE || type == ITEM_CUSTOM) {
return 1;
} else if (type == ITEM_SUBMENU) {
int count = 0;
FOR_EACH_CONST(i, items) {
count += i->size();
}
return count;
} else {
return 0;
}
}
String InsertSymbolMenu::getCode(int id, const SymbolFont& font) const {
if (type == ITEM_SUBMENU) {
FOR_EACH_CONST(i, items) {
int id2 = id - i->size();
if (id2 < 0) {
return i->getCode(id, font);
}
id = id2;
}
} else if (id == 0 && type == ITEM_CODE) {
return name;
} else if (id == 0 && type == ITEM_CUSTOM) {
String message = tr(font,name,name);
return wxGetTextFromUser(message, message);
}
return wxEmptyString;
}
wxMenu* InsertSymbolMenu::makeMenu(int id, Context& ctx, SymbolFont& font) const {
if (type == ITEM_SUBMENU) {
wxMenu* menu = new wxMenu();
FOR_EACH_CONST(i, items) {
menu->Append(i->makeMenuItem(menu, id, ctx, font));
id += i->size();
}
return menu;
}
return nullptr;
}
wxMenuItem* InsertSymbolMenu::makeMenuItem(wxMenu* parent, int first_id, Context& ctx, SymbolFont& font) const {
if (type == ITEM_SUBMENU) {
wxMenuItem* item = new wxMenuItem(parent, wxID_ANY, tr(font, _("menu item ") + name, name),
wxEmptyString, wxITEM_NORMAL,
makeMenu(first_id, ctx, font));
item->SetBitmap(wxNullBitmap);
return item;
} else if (type == ITEM_LINE) {
wxMenuItem* item = new wxMenuItem(parent, wxID_SEPARATOR);
return item;
} else {
wxMenuItem* item = new wxMenuItem(parent, first_id, tr(font, _("menu item ") + name, name));
// Generate bitmap for use on this item
SymbolInFont* symbol = nullptr;
if (type == ITEM_CUSTOM) {
symbol = font.defaultSymbol();
} else {
FOR_EACH(sym, font.symbols) {
if (!sym->code.empty() && sym->enabled && name == sym->code) {
symbol = sym.get();
break;
}
}
}
if (symbol) {
item->SetBitmap(symbol->getBitmap(ctx, font, wxSize(16,16)));
} else {
item->SetBitmap(wxNullBitmap);
}
return item;
}
}
IMPLEMENT_REFLECTION_ENUM(MenuItemType) {
VALUE_N("code", ITEM_CODE);
VALUE_N("custom", ITEM_CUSTOM);
VALUE_N("line", ITEM_LINE);
VALUE_N("submenu", ITEM_SUBMENU);
}
IMPLEMENT_REFLECTION_NO_GET_MEMBER(InsertSymbolMenu) {
if (!items.empty() || (tag.reading() && tag.isComplex())) {
// complex values are groups
REFLECT(type);
REFLECT(name);
REFLECT(items);
if (!items.empty()) type = ITEM_SUBMENU;
} else {
REFLECT_NAMELESS(name);
}
}
template <> void GetDefaultMember::handle(const InsertSymbolMenu& m) {
handle(m.name);
}
template <> void GetMember::handle(const InsertSymbolMenu& m) {
handle(_("type"), m.type);
handle(_("name"), m.name);
handle(_("items"), m.items);
}
// ----------------------------------------------------------------------------- : SymbolFontRef // ----------------------------------------------------------------------------- : SymbolFontRef
SymbolFontRef::SymbolFontRef() SymbolFontRef::SymbolFontRef()
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
DECLARE_POINTER_TYPE(Font); DECLARE_POINTER_TYPE(Font);
DECLARE_POINTER_TYPE(SymbolFont); DECLARE_POINTER_TYPE(SymbolFont);
DECLARE_POINTER_TYPE(SymbolInFont); DECLARE_POINTER_TYPE(SymbolInFont);
DECLARE_POINTER_TYPE(InsertSymbolMenu);
class RotatedDC; class RotatedDC;
struct CharInfo; struct CharInfo;
...@@ -26,6 +27,7 @@ struct CharInfo; ...@@ -26,6 +27,7 @@ struct CharInfo;
class SymbolFont : public Packaged { class SymbolFont : public Packaged {
public: public:
SymbolFont(); SymbolFont();
~SymbolFont();
/// Loads the symbol font with a given name, for example "magic-mana-large" /// Loads the symbol font with a given name, for example "magic-mana-large"
static SymbolFontP byName(const String& name); static SymbolFontP byName(const String& name);
...@@ -33,7 +35,7 @@ class SymbolFont : public Packaged { ...@@ -33,7 +35,7 @@ class SymbolFont : public Packaged {
class DrawableSymbol; class DrawableSymbol;
typedef vector<DrawableSymbol> SplitSymbols; typedef vector<DrawableSymbol> SplitSymbols;
/// Split a string into separate symbols for drawing and for determining their size /// Split a string into separate symbols for drawing and for determining their size
void split(const String& text, SplitSymbols& out) const; void split(const String& text, Context& ctx, SplitSymbols& out) const;
/// Draw a piece of text prepared using split /// Draw a piece of text prepared using split
void draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text); void draw(RotatedDC& dc, Context& ctx, const RealRect& rect, double font_size, const Alignment& align, const String& text);
...@@ -48,6 +50,16 @@ class SymbolFont : public Packaged { ...@@ -48,6 +50,16 @@ class SymbolFont : public Packaged {
static String typeNameStatic(); static String typeNameStatic();
virtual String typeName() const; virtual String typeName() const;
/// Generate a 'insert symbol' menu.
/** This class owns the menu!
* All ids used will be in the range ID_INSERT_SYMBOL_MENU_MIN...ID_INSERT_SYMBOL_MENU_MAX.
* If there is no insert symbol menu, returns nullptr.
*/
wxMenu* insertSymbolMenu(Context& ctx);
/// Process a choice from the insert symbol menu
/** Return the code representing the symbol */
String insertSymbolCode(int menu_id) const;
private: private:
UInt img_size; ///< Font size that the images use UInt img_size; ///< Font size that the images use
UInt min_size; ///< Minimum font size UInt min_size; ///< Minimum font size
...@@ -61,8 +73,11 @@ class SymbolFont : public Packaged { ...@@ -61,8 +73,11 @@ class SymbolFont : public Packaged {
double text_margin_bottom; double text_margin_bottom;
Alignment text_alignment; Alignment text_alignment;
bool merge_numbers; ///< Merge numbers? e.g. "11" is a single symbol ('1' must not exist as a symbol) bool merge_numbers; ///< Merge numbers? e.g. "11" is a single symbol ('1' must not exist as a symbol)
InsertSymbolMenuP insert_symbol_menu;
wxMenu* processed_insert_symbol_menu;
friend class SymbolInFont; friend class SymbolInFont;
friend class InsertSymbolMenu;
vector<SymbolInFontP> symbols; ///< The individual symbols vector<SymbolInFontP> symbols; ///< The individual symbols
/// Find the default symbol /// Find the default symbol
...@@ -83,6 +98,35 @@ class SymbolFont : public Packaged { ...@@ -83,6 +98,35 @@ class SymbolFont : public Packaged {
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
// ----------------------------------------------------------------------------- : InsertSymbolMenu
enum MenuItemType
{ ITEM_CODE ///< Name gives the code to insert
, ITEM_CUSTOM ///< Use a dialog box
, ITEM_LINE ///< A menu separator
, ITEM_SUBMENU ///< A submenu
};
/// Description of a menu to insert symbols from a symbol font into the text
class InsertSymbolMenu {
public:
InsertSymbolMenu();
MenuItemType type;
String name;
vector<InsertSymbolMenuP> items;
/// Number of ids used (recursive)
int size() const;
/// Get the code for an item, id relative to the start of this menu
String getCode(int id, const SymbolFont& font) const;
/// Make an actual menu
wxMenu* makeMenu(int first_id, Context& ctx, SymbolFont& font) const;
/// Make an actual menu item
wxMenuItem* makeMenuItem(wxMenu* parent, int first_id, Context& ctx, SymbolFont& font) const;
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : SymbolFontRef // ----------------------------------------------------------------------------- : SymbolFontRef
......
...@@ -143,6 +143,20 @@ void DataEditor::doCopy() { if (current_editor) current_ed ...@@ -143,6 +143,20 @@ void DataEditor::doCopy() { if (current_editor) current_ed
void DataEditor::doPaste() { if (current_editor) current_editor->doPaste(); } void DataEditor::doPaste() { if (current_editor) current_editor->doPaste(); }
void DataEditor::doFormat(int type) { if (current_editor) current_editor->doFormat(type); } void DataEditor::doFormat(int type) { if (current_editor) current_editor->doFormat(type); }
wxMenu* DataEditor::getMenu(int type) const {
if (current_editor) {
return current_editor->getMenu(type);
} else {
return nullptr;
}
}
void DataEditor::onCommand(int id) {
if (current_editor) {
current_editor->onCommand(id);
}
}
// ----------------------------------------------------------------------------- : Mouse events // ----------------------------------------------------------------------------- : Mouse events
void DataEditor::onLeftDown(wxMouseEvent& ev) { void DataEditor::onLeftDown(wxMouseEvent& ev) {
...@@ -274,7 +288,9 @@ void DataEditor::onContextMenu(wxContextMenuEvent& ev) { ...@@ -274,7 +288,9 @@ void DataEditor::onContextMenu(wxContextMenuEvent& ev) {
} }
void DataEditor::onMenu(wxCommandEvent& ev) { void DataEditor::onMenu(wxCommandEvent& ev) {
if (current_editor) { if (current_editor) {
current_editor->onMenu(ev); if (!current_editor->onCommand(ev.GetId())) {
ev.Skip();
}
} else { } else {
ev.Skip(); ev.Skip();
} }
......
...@@ -53,6 +53,10 @@ class DataEditor : public CardViewer { ...@@ -53,6 +53,10 @@ class DataEditor : public CardViewer {
bool canFormat(int type) const; bool canFormat(int type) const;
bool hasFormat(int type) const; bool hasFormat(int type) const;
void doFormat (int type); void doFormat (int type);
/// Get a special menu, events should be sent to onCommand
wxMenu* getMenu(int type) const;
/// A menu item from getMenu was selected
void onCommand(int id);
// --------------------------------------------------- : ValueViewers // --------------------------------------------------- : ValueViewers
......
...@@ -282,7 +282,9 @@ void CardListBase::rebuild() { ...@@ -282,7 +282,9 @@ void CardListBase::rebuild() {
if (f.second->card_list_align & ALIGN_RIGHT) align = wxLIST_FORMAT_RIGHT; if (f.second->card_list_align & ALIGN_RIGHT) align = wxLIST_FORMAT_RIGHT;
else if (f.second->card_list_align & ALIGN_CENTER) align = wxLIST_FORMAT_CENTRE; else if (f.second->card_list_align & ALIGN_CENTER) align = wxLIST_FORMAT_CENTRE;
else align = wxLIST_FORMAT_LEFT; else align = wxLIST_FORMAT_LEFT;
InsertColumn((long)column_fields.size(), capitalize(f.second->card_list_name), align, cs.width); InsertColumn((long)column_fields.size(),
tr(*set->game, f.second->card_list_name, capitalize(f.second->card_list_name)),
align, cs.width);
column_fields.push_back(f.second); column_fields.push_back(f.second);
} }
// find field that determines color // find field that determines color
......
...@@ -75,7 +75,7 @@ void CardListColumnSelectDialog::initList() { ...@@ -75,7 +75,7 @@ void CardListColumnSelectDialog::initList() {
// Init items // Init items
Color window_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); Color window_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
FOR_EACH(c, columns) { FOR_EACH(c, columns) {
list->Append(capitalize(c.field->card_list_name)); list->Append(tr(*game, c.field->card_list_name, capitalize(c.field->card_list_name)));
// check // check
int i = list->GetCount() - 1; int i = list->GetCount() - 1;
list->Check(i, c.settings.visible); list->Check(i, c.settings.visible);
...@@ -88,7 +88,7 @@ void CardListColumnSelectDialog::initList() { ...@@ -88,7 +88,7 @@ void CardListColumnSelectDialog::initList() {
void CardListColumnSelectDialog::refreshItem(int i) { void CardListColumnSelectDialog::refreshItem(int i) {
list->Check (i, columns[i].settings.visible); list->Check (i, columns[i].settings.visible);
list->SetString(i, capitalize(columns[i].field->card_list_name)); list->SetString(i, tr(*game, columns[i].field->card_list_name, capitalize(columns[i].field->card_list_name)) );
} }
// ----------------------------------------------------------------------------- : Events // ----------------------------------------------------------------------------- : Events
......
...@@ -38,7 +38,9 @@ void NativeLookEditor::drawViewer(RotatedDC& dc, ValueViewer& v) { ...@@ -38,7 +38,9 @@ void NativeLookEditor::drawViewer(RotatedDC& dc, ValueViewer& v) {
dc.DrawRectangle(s.getRect().grow(1)); dc.DrawRectangle(s.getRect().grow(1));
// draw label // draw label
dc.SetFont(*wxNORMAL_FONT); dc.SetFont(*wxNORMAL_FONT);
dc.DrawText(capitalize_sentence(s.fieldP->name), RealPoint(margin_left, s.top + 1)); // TODO : tr using stylesheet or using game?
dc.DrawText(tr(*set->game, s.fieldP->name, capitalize_sentence(s.fieldP->name)),
RealPoint(margin_left, s.top + 1));
// draw 3D border // draw 3D border
draw_control_border(this, dc.getDC(), RealRect(s.left - 1, s.top - 1, s.width + 2, s.height + 2)); draw_control_border(this, dc.getDC(), RealRect(s.left - 1, s.top - 1, s.width + 2, s.height + 2));
// draw viewer // draw viewer
......
...@@ -77,6 +77,11 @@ void IconMenu::Append(int id, const String& text, const String& help, wxMenu* su ...@@ -77,6 +77,11 @@ void IconMenu::Append(int id, const String& text, const String& help, wxMenu* su
wxMenu::Append(item); wxMenu::Append(item);
} }
void IconMenu::Append(wxMenuItem* item) {
item->SetBitmap(wxNullBitmap);
wxMenu::Append(item);
}
void IconMenu::Insert(size_t pos, int id, const String& text, const String& help) { void IconMenu::Insert(size_t pos, int id, const String& text, const String& help) {
wxMenuItem* item = new wxMenuItem (this, id, text, help); wxMenuItem* item = new wxMenuItem (this, id, text, help);
item->SetBitmap(wxNullBitmap); item->SetBitmap(wxNullBitmap);
......
...@@ -27,6 +27,8 @@ class IconMenu : public wxMenu { ...@@ -27,6 +27,8 @@ class IconMenu : public wxMenu {
void Append(int id, const String& text, const String& help); void Append(int id, const String& text, const String& help);
/// Append a menu item, without an image /// Append a menu item, without an image
void Append(int id, const String& text, const String& help, wxMenu* submenu); void Append(int id, const String& text, const String& help, wxMenu* submenu);
/// Append a menu item, without an image
void Append(wxMenuItem* item);
/// Insert a menu item, without an image /// Insert a menu item, without an image
void Insert(size_t pos, int id, const String& text, const String& help); void Insert(size_t pos, int id, const String& text, const String& help);
}; };
......
...@@ -47,10 +47,49 @@ CardsPanel::CardsPanel(Window* parent, int id) ...@@ -47,10 +47,49 @@ CardsPanel::CardsPanel(Window* parent, int id)
s->Add(splitter, 1, wxEXPAND); s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this); s->SetSizeHints(this);
SetSizer(s); SetSizer(s);
// init menus
menuCard = new IconMenu();
menuCard->Append(ID_CARD_PREV, _("Select &Previous Card\tPgUp"), _("Selects the previous card in the list"));
menuCard->Append(ID_CARD_NEXT, _("Select &Next Card\tPgDn"), _("Selects the next card in the list"));
menuCard->AppendSeparator();
menuCard->Append(ID_CARD_ADD, _("card_add"), _("&Add Card\tCtrl++"), _("Add a new, blank, card to this set"));
menuCard->Append(ID_CARD_ADD_MULT, _("card_add_multiple"), _("Add &Multiple Cards..."), _("Add multiple cards to the set"));
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
menuCard->Append(ID_CARD_REMOVE, _("card_del"), _("&Remove Select Card\tDel "), _("Delete the selected card from this set"));
menuCard->AppendSeparator();
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _("&Normal"), _("Display the card with the right side up"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _("Rotated 90 &Clockwise"), _("Display the card rotated clockwise"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _("Rotated 90 C&ounter Clockwise"), _("Display the card rotated counter-clockwise (anti-clockwise for the British)"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _("Rotated 180, &Up Side Down"), _("Display the card up side down"), wxITEM_CHECK);
menuCard->Append(wxID_ANY, _("card_rotate"), _("&Orientation"), _("Orientation of the card display"), wxITEM_NORMAL, menuRotate);
menuCard->AppendSeparator();
// This probably belongs in the window menu, but there we can't remove the separator once it is added
menuCard->Append(ID_SELECT_COLUMNS, _("C&ard List Columns..."), _("Select what columns should be shown and in what order."));
menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _("Bold\tCtrl+B"), _("Makes the selected text bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _("Italic\tCtrl+I"), _("Makes the selected text italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _("Symbols\tCtrl+M"), _("Draws the selected text with symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _("Reminder Text\tCtrl+R"), _("Show reminder text for the selected keyword"), wxITEM_CHECK);
menuFormat->AppendSeparator();
insertSymbolMenu = new wxMenuItem(menuFormat, ID_INSERT_SYMBOL, _("Insert Symbol"));
menuFormat->Append(insertSymbolMenu);
} }
CardsPanel::~CardsPanel() { CardsPanel::~CardsPanel() {
// settings.card_notes_height = splitter->GetSashPosition(); // settings.card_notes_height = splitter->GetSashPosition();
// we don't own the submenu
wxMenu* menu = insertSymbolMenu->GetSubMenu();
if (menu && menu->GetParent() == menuFormat) {
menu->SetParent(nullptr);
}
insertSymbolMenu->SetSubMenu(nullptr);
// delete menus
delete menuCard;
delete menuFormat;
} }
void CardsPanel::onChangeSet() { void CardsPanel::onChangeSet() {
...@@ -78,32 +117,7 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) { ...@@ -78,32 +117,7 @@ void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap,wxITEM_NORMAL,_TOOL_("rotate card")); tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap,wxITEM_NORMAL,_TOOL_("rotate card"));
tb->Realize(); tb->Realize();
// Menus // Menus
IconMenu* menuCard = new IconMenu();
menuCard->Append(ID_CARD_PREV, _("Select &Previous Card\tPgUp"), _("Selects the previous card in the list"));
menuCard->Append(ID_CARD_NEXT, _("Select &Next Card\tPgDn"), _("Selects the next card in the list"));
menuCard->AppendSeparator();
menuCard->Append(ID_CARD_ADD, _("card_add"), _("&Add Card\tCtrl++"), _("Add a new, blank, card to this set"));
menuCard->Append(ID_CARD_ADD_MULT, _("card_add_multiple"), _("Add &Multiple Cards..."), _("Add multiple cards to the set"));
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
menuCard->Append(ID_CARD_REMOVE, _("card_del"), _("&Remove Select Card\tDel "), _("Delete the selected card from this set"));
menuCard->AppendSeparator();
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _("&Normal"), _("Display the card with the right side up"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _("Rotated 90 &Clockwise"), _("Display the card rotated clockwise"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _("Rotated 90 C&ounter Clockwise"), _("Display the card rotated counter-clockwise (anti-clockwise for the British)"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _("Rotated 180, &Up Side Down"), _("Display the card up side down"), wxITEM_CHECK);
menuCard->Append(wxID_ANY, _("card_rotate"), _("&Orientation"), _("Orientation of the card display"), wxITEM_NORMAL, menuRotate);
menuCard->AppendSeparator();
// This probably belongs in the window menu, but there we can't remove the separator once it is added
menuCard->Append(ID_SELECT_COLUMNS, _("C&ard List Columns..."), _("Select what columns should be shown and in what order."));
mb->Insert(2, menuCard, _("&Cards")); mb->Insert(2, menuCard, _("&Cards"));
IconMenu* menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _("Bold\tCtrl+B"), _("Makes the selected text bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _("Italic\tCtrl+I"), _("Makes the selected text italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _("Symbols\tCtrl+M"), _("Draws the selected text with symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _("Reminder Text\tCtrl+R"), _("Show reminder text for the selected keyword"), wxITEM_CHECK);
mb->Insert(3, menuFormat, _("&Format")); mb->Insert(3, menuFormat, _("&Format"));
} }
...@@ -120,8 +134,8 @@ void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { ...@@ -120,8 +134,8 @@ void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
tb->DeleteToolByPos(10); // delete separator tb->DeleteToolByPos(10); // delete separator
tb->DeleteToolByPos(10); // delete separator tb->DeleteToolByPos(10); // delete separator
// Menus // Menus
delete mb->Remove(3); mb->Remove(3);
delete mb->Remove(2); mb->Remove(2);
} }
void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) { void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
...@@ -148,6 +162,16 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -148,6 +162,16 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
} }
break; break;
} }
case ID_INSERT_SYMBOL: {
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
ev.Enable(menu);
if (insertSymbolMenu->GetSubMenu() != menu || menu->GetParent() != menuFormat) {
// re-add the menu
menuFormat->Remove(insertSymbolMenu);
insertSymbolMenu->SetSubMenu(menu);
menuFormat->Append(insertSymbolMenu);
}
}
} }
} }
...@@ -187,6 +211,12 @@ void CardsPanel::onCommand(int id) { ...@@ -187,6 +211,12 @@ void CardsPanel::onCommand(int id) {
break; break;
} }
} }
default: {
if (id >= ID_INSERT_SYMBOL_MENU_MIN && id <= ID_INSERT_SYMBOL_MENU_MAX) {
// pass on to editor
editor->onCommand(id);
}
}
} }
} }
......
...@@ -16,6 +16,7 @@ class wxSplitterWindow; ...@@ -16,6 +16,7 @@ class wxSplitterWindow;
class ImageCardList; class ImageCardList;
class DataEditor; class DataEditor;
class TextCtrl; class TextCtrl;
class IconMenu;
// ----------------------------------------------------------------------------- : CardsPanel // ----------------------------------------------------------------------------- : CardsPanel
...@@ -95,7 +96,8 @@ class CardsPanel : public SetWindowPanel { ...@@ -95,7 +96,8 @@ class CardsPanel : public SetWindowPanel {
TextCtrl* notes; TextCtrl* notes;
// --------------------------------------------------- : Menus & tools // --------------------------------------------------- : Menus & tools
wxMenu* cardMenu, formatMenu; IconMenu* menuCard, *menuFormat;
wxMenuItem* insertSymbolMenu; // owned by menuFormat, but submenu owned by SymbolFont
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -53,8 +53,10 @@ class ValueEditor { ...@@ -53,8 +53,10 @@ class ValueEditor {
/// a context menu is requested, add extra items to the menu m /// a context menu is requested, add extra items to the menu m
/** return false to suppress menu */ /** return false to suppress menu */
virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent& ev) { return true; } virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent& ev) { return true; }
/// A menu item was selected /// Get a special menu, events will be sent to onMenu
virtual void onMenu(wxCommandEvent& ev) { ev.Skip(); } virtual wxMenu* getMenu(int type) const { return nullptr; }
/// A menu item was selected, return true if the command was processed
virtual bool onCommand(int id) { return false; }
// --------------------------------------------------- : Clipboard // --------------------------------------------------- : Clipboard
......
...@@ -192,7 +192,7 @@ void TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -192,7 +192,7 @@ void TextValueEditor::onChar(wxKeyEvent& ev) {
// TODO: Find a more correct way to determine normal characters, // TODO: Find a more correct way to determine normal characters,
// this might not work for internationalized input. // this might not work for internationalized input.
// It might also not be portable! // It might also not be portable!
replaceSelection(String(ev.GetUnicodeKey(), 1), _("Typing")); replaceSelection(escape(String(ev.GetUnicodeKey(), 1)), _("Typing"));
} }
} }
} }
...@@ -224,6 +224,31 @@ bool TextValueEditor::onContextMenu(wxMenu& m, wxContextMenuEvent& ev) { ...@@ -224,6 +224,31 @@ bool TextValueEditor::onContextMenu(wxMenu& m, wxContextMenuEvent& ev) {
// always show the menu // always show the menu
return true; return true;
} }
bool TextValueEditor::onCommand(int id) {
if (id >= ID_INSERT_SYMBOL_MENU_MIN && id <= ID_INSERT_SYMBOL_MENU_MAX) {
// Insert a symbol
if ((style().always_symbol || style().allow_formating) && style().symbol_font.valid()) {
String code = style().symbol_font.font->insertSymbolCode(id);
if (!style().always_symbol) {
code = _("<sym>") + code + _("</sym>");
}
replaceSelection(code, _("Insert Symbol"));
return true;
}
}
return false;
}
wxMenu* TextValueEditor::getMenu(int type) const {
if (type == ID_INSERT_SYMBOL && (style().always_symbol || style().allow_formating)
&& style().symbol_font.valid()) {
return style().symbol_font.font->insertSymbolMenu(viewer.getContext());
} else {
return nullptr;
}
}
/*
/// TODO : move to doFormat
void TextValueEditor::onMenu(wxCommandEvent& ev) { void TextValueEditor::onMenu(wxCommandEvent& ev) {
if (ev.GetId() == ID_FORMAT_REMINDER) { if (ev.GetId() == ID_FORMAT_REMINDER) {
// toggle reminder text // toggle reminder text
...@@ -235,6 +260,7 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) { ...@@ -235,6 +260,7 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) {
ev.Skip(); ev.Skip();
} }
} }
*/
// ----------------------------------------------------------------------------- : Other overrides // ----------------------------------------------------------------------------- : Other overrides
......
...@@ -44,7 +44,8 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -44,7 +44,8 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
virtual void onMouseWheel(const RealPoint& pos, wxMouseEvent& ev); virtual void onMouseWheel(const RealPoint& pos, wxMouseEvent& ev);
virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent&); virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent&);
virtual void onMenu(wxCommandEvent&); virtual wxMenu* getMenu(int type) const;
virtual bool onCommand(int);
virtual void onChar(wxKeyEvent&); virtual void onChar(wxKeyEvent&);
...@@ -98,6 +99,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -98,6 +99,7 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
void moveSelectionNoRedraw(IndexType t, size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID); void moveSelectionNoRedraw(IndexType t, size_t new_end, bool also_move_start=true, Movement dir = MOVE_MID);
/// Replace the current selection with 'replacement', name the action /// Replace the current selection with 'replacement', name the action
/** replacement should be a tagged string (i.e. already escaped) */
void replaceSelection(const String& replacement, const String& name); void replaceSelection(const String& replacement, const String& name);
/// Make sure the selection satisfies its constraints /// Make sure the selection satisfies its constraints
......
...@@ -24,7 +24,8 @@ String Error::what() const { ...@@ -24,7 +24,8 @@ String Error::what() const {
// Errors for which a message box was already shown // Errors for which a message box was already shown
vector<String> previous_errors; vector<String> previous_errors;
String pending_error; String pending_errors;
String pending_warnings;
DECLARE_TYPEOF_COLLECTION(String); DECLARE_TYPEOF_COLLECTION(String);
void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { void handle_error(const String& e, bool allow_duplicate = true, bool now = true) {
...@@ -38,8 +39,8 @@ void handle_error(const String& e, bool allow_duplicate = true, bool now = true) ...@@ -38,8 +39,8 @@ void handle_error(const String& e, bool allow_duplicate = true, bool now = true)
} }
// Only show errors in the main thread // Only show errors in the main thread
if (!now || !wxThread::IsMain()) { if (!now || !wxThread::IsMain()) {
if (!pending_error.empty()) pending_error += _("\n\n"); if (!pending_errors.empty()) pending_errors += _("\n\n");
pending_error += e; pending_errors += e;
return; return;
} }
// show message // show message
...@@ -50,10 +51,27 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) { ...@@ -50,10 +51,27 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) {
handle_error(e.what(), allow_duplicate, now); handle_error(e.what(), allow_duplicate, now);
} }
void handle_warning(const String& w, bool now) {
// Check duplicates
// TODO: thread safety
// Only show errors in the main thread
if (!now || !wxThread::IsMain()) {
if (!pending_warnings.empty()) pending_warnings += _("\n\n");
pending_warnings += w;
return;
}
// show message
wxMessageBox(w, _("Warning"), wxOK | wxICON_EXCLAMATION);
}
void handle_pending_errors() { void handle_pending_errors() {
assert(wxThread::IsMain()); assert(wxThread::IsMain());
if (!pending_error.empty()) { if (!pending_errors.empty()) {
handle_error(pending_error); handle_error(pending_errors);
pending_error.clear(); pending_errors.clear();
}
if (!pending_warnings.empty()) {
handle_warning(pending_warnings);
pending_warnings.clear();
} }
} }
...@@ -96,7 +96,10 @@ class ScriptError : public Error { ...@@ -96,7 +96,10 @@ class ScriptError : public Error {
*/ */
void handle_error(const Error& e, bool allow_duplicate = true, bool now = true); void handle_error(const Error& e, bool allow_duplicate = true, bool now = true);
/// Handle errors that were not handled immediatly in handleError /// Handle a warning by showing a message box
void handle_warning(const String& w, bool now = true);
/// Handle errors and warnings that were not handled immediatly in handleError
/** Should be called repeatedly (e.g. in an onIdle event handler) */ /** Should be called repeatedly (e.g. in an onIdle event handler) */
void handle_pending_errors(); void handle_pending_errors();
......
...@@ -59,7 +59,7 @@ class Package { ...@@ -59,7 +59,7 @@ class Package {
bool needSaveAs() const; bool needSaveAs() const;
/// Determines the short name of this package: the filename without path or extension /// Determines the short name of this package: the filename without path or extension
String name() const; String name() const;
/// Return the full name of this package, by default equal to name() /// Return the (user friendly) full name of this package, by default equal to name()
virtual String fullName() const; virtual String fullName() const;
/// Return the absolute filename of this file /// Return the absolute filename of this file
const String& absoluteFilename() const; const String& absoluteFilename() const;
......
...@@ -41,7 +41,7 @@ void Reader::handleAppVersion() { ...@@ -41,7 +41,7 @@ void Reader::handleAppVersion() {
if (enterBlock(_("mse_version"))) { if (enterBlock(_("mse_version"))) {
handle(file_app_version); handle(file_app_version);
if (app_version < file_app_version) { if (app_version < file_app_version) {
wxMessageBox(_ERROR_2_("newer version", filename, file_app_version.toString()), _("Warning"), wxOK | wxICON_EXCLAMATION); handle_warning(_ERROR_2_("newer version", filename, file_app_version.toString()), false);
} }
exitBlock(); exitBlock();
} }
...@@ -53,7 +53,7 @@ void Reader::warning(const String& msg) { ...@@ -53,7 +53,7 @@ void Reader::warning(const String& msg) {
void Reader::showWarnings() { void Reader::showWarnings() {
if (!warnings.empty()) { if (!warnings.empty()) {
wxMessageBox(_("Warnings while reading file:\n") + filename + _("\n") + warnings, _("Warning"), wxOK | wxICON_EXCLAMATION); handle_warning(_("Warnings while reading file:\n") + filename + _("\n") + warnings, false);
warnings.clear(); warnings.clear();
} }
} }
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/string.hpp> #include <util/string.hpp>
class Game;
class StyleSheet;
class SymbolFont;
// ----------------------------------------------------------------------------- : Localisation macros // ----------------------------------------------------------------------------- : Localisation macros
enum LocaleCategory enum LocaleCategory
...@@ -37,6 +41,24 @@ enum LocaleCategory ...@@ -37,6 +41,24 @@ enum LocaleCategory
/// Translate 'key' in the category 'cat' using the current locale /// Translate 'key' in the category 'cat' using the current locale
String tr(LocaleCategory cat, const String& key); String tr(LocaleCategory cat, const String& key);
/// Translate 'key' in the for a Game using the current locale
String tr(const Game&, const String& key);
/// Translate 'key' in the for a StyleSheet using the current locale
String tr(const StyleSheet&, const String& key);
/// Translate 'key' in the for a SymbolFont using the current locale
String tr(const SymbolFont&, const String& key);
/// Translate 'key' in the for a Game using the current locale
/** If the key is not found, use the default value */
String tr(const Game&, const String& key, const String& def);
/// Translate 'key' in the for a StyleSheet using the current locale
/** If the key is not found, use the default value */
String tr(const StyleSheet&, const String& key, const String& def);
/// Translate 'key' in the for a SymbolFont using the current locale
/** If the key is not found, use the default value */
String tr(const SymbolFont&, const String& key, const String& def);
/// A localized string for menus/toolbar buttons /// A localized string for menus/toolbar buttons
#define _MENU_(s) tr(LOCALE_CAT_MENU, _(s)) #define _MENU_(s) tr(LOCALE_CAT_MENU, _(s))
/// A localized string for help/statusbar text /// A localized string for help/statusbar text
......
...@@ -141,13 +141,17 @@ String cannocial_name_form(const String& str) { ...@@ -141,13 +141,17 @@ String cannocial_name_form(const String& str) {
ret.reserve(str.size()); ret.reserve(str.size());
bool leading = true; bool leading = true;
FOR_EACH_CONST(c, str) { FOR_EACH_CONST(c, str) {
if ((c == _('_') || c == _(' ')) && !leading) { if ((c == _('_') || c == _(' '))) {
ret += _(' '); if (!leading) ret += _(' ');
} else {
ret += c;
leading = false;
/*
} else if (isAlnum(c) || c == _('-')) { } else if (isAlnum(c) || c == _('-')) {
ret += toLower(c); ret += toLower(c);
leading = false; leading = false;
} else { } else {
// ignore non alpha numeric // ignore non alpha numeric*/
} }
} }
return ret; return ret;
......
...@@ -331,7 +331,7 @@ String tagged_substr_replace(const String& input, size_t start, size_t end, cons ...@@ -331,7 +331,7 @@ String tagged_substr_replace(const String& input, size_t start, size_t end, cons
return simplify_tagged( return simplify_tagged(
substr_replace(input, start, end, substr_replace(input, start, end,
get_tags(input, start, end, true) + // close tags get_tags(input, start, end, true) + // close tags
escape(replacement) + replacement +
get_tags(input, start, end, false) // open tags get_tags(input, start, end, false) // open tags
)); ));
} }
......
...@@ -127,7 +127,7 @@ String remove_tag_contents(const String& str, const String& tag); ...@@ -127,7 +127,7 @@ String remove_tag_contents(const String& str, const String& tag);
* This function makes sure tags still match. It also attempts to cancel out tags. * This function makes sure tags still match. It also attempts to cancel out tags.
* This means that when removing "<x>a</x>" nothing is left, * This means that when removing "<x>a</x>" nothing is left,
* but with input "<x>a" -> "<x>" and "</>a" -> "</>". * but with input "<x>a" -> "<x>" and "</>a" -> "</>".
* Escapes the replacement, i.e. all < in become \1. * Does not escape the replacement.
*/ */
String tagged_substr_replace(const String& input, size_t start, size_t end, const String& replacement); String tagged_substr_replace(const String& input, size_t start, size_t end, const String& replacement);
......
...@@ -81,7 +81,7 @@ enum MenuID { ...@@ -81,7 +81,7 @@ enum MenuID {
enum ChildMenuID { enum ChildMenuID {
ID_CHILD_MIN = 1000 ID_CHILD_MIN = 1000
, ID_CHILD_MAX = 2999 , ID_CHILD_MAX = 3999
// Cards menu // Cards menu
, ID_CARD_ADD = 1001 , ID_CARD_ADD = 1001
...@@ -106,6 +106,7 @@ enum ChildMenuID { ...@@ -106,6 +106,7 @@ enum ChildMenuID {
, ID_FORMAT_ITALIC , ID_FORMAT_ITALIC
, ID_FORMAT_SYMBOL , ID_FORMAT_SYMBOL
, ID_FORMAT_REMINDER , ID_FORMAT_REMINDER
, ID_INSERT_SYMBOL
// SymbolSelectEditor toolbar/menu // SymbolSelectEditor toolbar/menu
, ID_PART = 2001 , ID_PART = 2001
...@@ -146,6 +147,10 @@ enum ChildMenuID { ...@@ -146,6 +147,10 @@ enum ChildMenuID {
// Style // Style
, ID_STYLE_USE_FOR_ALL = 3201 , ID_STYLE_USE_FOR_ALL = 3201
// SymbolFont (Format menu)
, ID_INSERT_SYMBOL_MENU_MIN = 3301
, ID_INSERT_SYMBOL_MENU_MAX = 3999
}; };
......
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