mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
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; git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@198 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -305,6 +305,38 @@ game:
|
||||
# Set info
|
||||
|
||||
# descriptions/help text
|
||||
#stylesheet:
|
||||
# magic-new:
|
||||
#
|
||||
stylesheet:
|
||||
magic-new:
|
||||
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mse version: 0.2.7
|
||||
mse version: 0.3.0
|
||||
# Symbol font in the 'popup' style, used for casting costs on modern cards
|
||||
|
||||
image font size: 135
|
||||
@@ -7,7 +7,15 @@ symbol:
|
||||
image: mana_circle.png
|
||||
symbol:
|
||||
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:
|
||||
code: W/U
|
||||
image: mana_wu.png
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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
|
||||
# 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:
|
||||
#
|
||||
#init script:
|
||||
# small_mana_t := "mana_t.png"
|
||||
# mana_t := {"new"}
|
||||
|
||||
image font size: 135
|
||||
horizontal space: 2
|
||||
@@ -14,7 +14,15 @@ symbol:
|
||||
image: mana_circle.png
|
||||
symbol:
|
||||
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:
|
||||
code: W/U
|
||||
image: mana_wu.png
|
||||
@@ -102,4 +110,50 @@ text font:
|
||||
text margin left: 3
|
||||
text margin right: 2
|
||||
text margin top: -1
|
||||
text margin bottom: -1
|
||||
text margin bottom: -1
|
||||
|
||||
##############################################################
|
||||
# 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:
|
||||
land_template := { "acard.jpg" }
|
||||
|
||||
# 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?
|
||||
white_font_colors := filter_rule(match:"^(hybrid )?black|^land")
|
||||
|
||||
@@ -26,9 +26,9 @@ init script:
|
||||
|
||||
# Use the normal tap symbol
|
||||
mana_t := {
|
||||
if styling.tap_symbol == "old" then "mana_t_old.png"
|
||||
else if styling.tap_symbol == "diagonal T" then "mana_t_older.png"
|
||||
else "mana_t.png"
|
||||
if styling.tap_symbol == "old" then "old"
|
||||
else if styling.tap_symbol == "diagonal T" then "older"
|
||||
else "new"
|
||||
}
|
||||
|
||||
# Does the card have a color that requires a white font for copyright/artist?
|
||||
|
||||
@@ -23,8 +23,8 @@ init script:
|
||||
# Horizontal 5 color blends are not supported
|
||||
card_hybrid_5b := card_hybrid_5
|
||||
|
||||
# Use the normal tap symbol
|
||||
mana_t := { "mana_t_old.png" }
|
||||
# Use the old tap symbol
|
||||
mana_t := { "old" }
|
||||
|
||||
# Does the card have a color that requires a black font for copyright/artist?
|
||||
black_font_colors := filter_rule(match:"^(hybrid 2 color)?white")
|
||||
|
||||
@@ -23,8 +23,8 @@ init script:
|
||||
# Horizontal 5 color blends are not supported
|
||||
card_hybrid_5b := card_hybrid_5
|
||||
|
||||
# Use the normal tap symbol
|
||||
mana_t := { "mana_t_old.png" }
|
||||
# Use the old tap symbol
|
||||
mana_t := { "old" }
|
||||
|
||||
# Does the card have a color that requires a black font for copyright/artist?
|
||||
black_font_colors := filter_rule(match:"^(hybrid 2 color)?white")
|
||||
|
||||
@@ -25,7 +25,7 @@ init script:
|
||||
pt_template := { input + "pt.jpg" }
|
||||
|
||||
# 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?
|
||||
white_font_colors := filter_rule(match:"^(hybrid 2 color)?black|^land")
|
||||
|
||||
@@ -9,8 +9,8 @@ icon: card-sample.png
|
||||
############################################################## Extra scripts
|
||||
|
||||
init script:
|
||||
# Use the normal tap symbol
|
||||
small_mana_t := "mana_t.png"
|
||||
# Use the old tap symbol
|
||||
mana_t := { "old" }
|
||||
|
||||
############################################################## Set info fields
|
||||
info style:
|
||||
|
||||
@@ -21,8 +21,7 @@ IMPLEMENT_REFLECTION(KeywordMode) {
|
||||
REFLECT(description);
|
||||
}
|
||||
IMPLEMENT_REFLECTION(KeywordExpansion) {
|
||||
REFLECT(before);
|
||||
REFLECT(after);
|
||||
REFLECT(match);
|
||||
REFLECT(reminder);
|
||||
}
|
||||
|
||||
@@ -36,15 +35,17 @@ void read_compat(Reader& tag, Keyword* k) {
|
||||
if (!separator.empty() || !parameter.empty() || !reminder.empty()) {
|
||||
// old style keyword declaration, no separate expansion
|
||||
KeywordExpansionP e(new KeywordExpansion);
|
||||
e->match = k->keyword;
|
||||
size_t start = separator.find_first_of('[');
|
||||
size_t end = separator.find_first_of(']');
|
||||
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()) {
|
||||
e->after += _("<param>") + parameter + _("</param>");
|
||||
e->match += _("<param>") + parameter + _("</param>");
|
||||
}
|
||||
e->reminder.set(reminder);
|
||||
k->expansions.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@ class KeywordMode {
|
||||
/// A way to use a keyword
|
||||
class KeywordExpansion {
|
||||
public:
|
||||
String before; ///< Components before the keyword: parameters and separators (tagged string)
|
||||
String after; ///< Components after the keyword: parameters and separators
|
||||
String match; ///< String to match, <param> tags are used for 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
|
||||
String mode; ///< Mode of use, can be used by scripts (only gives the name). Default is the mode of the Keyword.
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
+52
-4
@@ -7,6 +7,9 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <data/locale.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/symbol_font.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <script/to_value.hpp>
|
||||
|
||||
@@ -32,19 +35,64 @@ IMPLEMENT_REFLECTION(Locale) {
|
||||
REFLECT_N("error", translations[LOCALE_CAT_ERROR]);
|
||||
REFLECT_N("type", translations[LOCALE_CAT_TYPE]);
|
||||
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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
|
||||
String tr(LocaleCategory cat, const String& key) {
|
||||
if (!the_locale) return key; // no locale loaded (yet)
|
||||
map<String,String>::const_iterator it = the_locale->translations[cat].find(key);
|
||||
if (it == the_locale->translations[cat].end()) return _("missing:") + key;
|
||||
return it->second;
|
||||
return the_locale->translations[cat].tr(key);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+16
-6
@@ -15,14 +15,20 @@
|
||||
#include <util/io/package.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(Locale);
|
||||
DECLARE_POINTER_TYPE(GameLocale);
|
||||
DECLARE_POINTER_TYPE(SubLocale);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Locale class
|
||||
|
||||
/// Translations of the texts of a game
|
||||
class GameLocale {
|
||||
/// Translations of the texts of a game/stylesheet/symbolfont
|
||||
class SubLocale {
|
||||
public:
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -30,9 +36,13 @@ class GameLocale {
|
||||
class Locale : public Packaged {
|
||||
public:
|
||||
/// Translations of UI strings in each category
|
||||
map<String,String> translations[LOCALE_CAT_MAX];
|
||||
/// Translations of game specific texts, by game name
|
||||
map<String,GameLocaleP> game_translations;
|
||||
SubLocale translations[LOCALE_CAT_MAX];
|
||||
/// Translations of Game specific texts, by game name
|
||||
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
|
||||
static LocaleP byName(const String& name);
|
||||
|
||||
+172
-9
@@ -10,12 +10,14 @@
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <util/rotation.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <render/text/element.hpp> // fot CharInfo
|
||||
#include <script/image.hpp>
|
||||
#include <util/error.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolFont::DrawableSymbol);
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolInFontP);
|
||||
DECLARE_TYPEOF_COLLECTION(InsertSymbolMenuP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolFont
|
||||
|
||||
@@ -31,8 +33,13 @@ SymbolFont::SymbolFont()
|
||||
, text_margin_top(0), text_margin_bottom(0)
|
||||
, text_alignment(ALIGN_MIDDLE_CENTER)
|
||||
, merge_numbers(false)
|
||||
, processed_insert_symbol_menu(nullptr)
|
||||
{}
|
||||
|
||||
SymbolFont::~SymbolFont() {
|
||||
delete processed_insert_symbol_menu;
|
||||
}
|
||||
|
||||
String SymbolFont::typeNameStatic() { return _("symbol-font"); }
|
||||
String SymbolFont::typeName() const { return _("symbol-font"); }
|
||||
|
||||
@@ -57,6 +64,7 @@ IMPLEMENT_REFLECTION(SymbolFont) {
|
||||
REFLECT(text_margin_top);
|
||||
REFLECT(text_margin_bottom);
|
||||
REFLECT(text_alignment);
|
||||
REFLECT(insert_symbol_menu);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolInFont
|
||||
@@ -69,15 +77,21 @@ class SymbolInFont {
|
||||
/// Get a shrunk, zoomed bitmap
|
||||
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
|
||||
/** This is the size of the resulting image, it does NOT convert back to internal coordinates */
|
||||
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:
|
||||
ScriptableImage image; ///< The image for this symbol
|
||||
double img_size; ///< Font size used by the image
|
||||
wxSize actual_size; ///< Actual image size, only known after loading the image
|
||||
ScriptableImage image; ///< The image for this symbol
|
||||
double img_size; ///< Font size used by the image
|
||||
wxSize actual_size; ///< Actual image size, only known after loading the image
|
||||
/// Cached bitmaps for different sizes
|
||||
map<double, Bitmap> bitmaps;
|
||||
|
||||
@@ -86,6 +100,7 @@ class SymbolInFont {
|
||||
|
||||
SymbolInFont::SymbolInFont()
|
||||
: actual_size(0,0)
|
||||
, enabled(true)
|
||||
{
|
||||
assert(symbol_font_for_reading());
|
||||
img_size = symbol_font_for_reading()->img_size;
|
||||
@@ -112,6 +127,18 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) {
|
||||
}
|
||||
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) {
|
||||
if (actual_size.GetWidth() == 0) {
|
||||
@@ -121,9 +148,14 @@ RealSize SymbolInFont::size(Context& ctx, Package& pkg, double size) {
|
||||
return wxSize(actual_size * size / img_size);
|
||||
}
|
||||
|
||||
void SymbolInFont::update(Context& ctx) {
|
||||
enabled.update(ctx);
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION(SymbolInFont) {
|
||||
REFLECT(code);
|
||||
REFLECT(image);
|
||||
REFLECT(enabled);
|
||||
REFLECT_N("image font size", img_size);
|
||||
}
|
||||
|
||||
@@ -139,7 +171,11 @@ class SymbolFont::DrawableSymbol {
|
||||
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
|
||||
for (size_t pos = 0 ; pos < text.size() ; ) {
|
||||
// 1. check merged numbers
|
||||
@@ -154,7 +190,7 @@ void SymbolFont::split(const String& text, SplitSymbols& out) const {
|
||||
}
|
||||
// 2. check symbol list
|
||||
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()));
|
||||
pos += sym->code.size();
|
||||
goto next_symbol; // continue two levels
|
||||
@@ -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) {
|
||||
SplitSymbols symbols;
|
||||
split(text, symbols);
|
||||
split(text, ctx, symbols);
|
||||
draw(dc, ctx, rect, font_size, align, symbols);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
SplitSymbols symbols;
|
||||
split(text, symbols);
|
||||
split(text, ctx, symbols);
|
||||
getCharInfo(dc, ctx, font_size, symbols, out);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
DECLARE_POINTER_TYPE(Font);
|
||||
DECLARE_POINTER_TYPE(SymbolFont);
|
||||
DECLARE_POINTER_TYPE(SymbolInFont);
|
||||
DECLARE_POINTER_TYPE(InsertSymbolMenu);
|
||||
class RotatedDC;
|
||||
struct CharInfo;
|
||||
|
||||
@@ -26,6 +27,7 @@ struct CharInfo;
|
||||
class SymbolFont : public Packaged {
|
||||
public:
|
||||
SymbolFont();
|
||||
~SymbolFont();
|
||||
|
||||
/// Loads the symbol font with a given name, for example "magic-mana-large"
|
||||
static SymbolFontP byName(const String& name);
|
||||
@@ -33,7 +35,7 @@ class SymbolFont : public Packaged {
|
||||
class DrawableSymbol;
|
||||
typedef vector<DrawableSymbol> SplitSymbols;
|
||||
/// 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
|
||||
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 {
|
||||
static String typeNameStatic();
|
||||
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:
|
||||
UInt img_size; ///< Font size that the images use
|
||||
UInt min_size; ///< Minimum font size
|
||||
@@ -61,8 +73,11 @@ class SymbolFont : public Packaged {
|
||||
double text_margin_bottom;
|
||||
Alignment text_alignment;
|
||||
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 InsertSymbolMenu;
|
||||
vector<SymbolInFontP> symbols; ///< The individual symbols
|
||||
|
||||
/// Find the default symbol
|
||||
@@ -83,6 +98,35 @@ class SymbolFont : public Packaged {
|
||||
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
|
||||
|
||||
|
||||
@@ -143,6 +143,20 @@ void DataEditor::doCopy() { if (current_editor) current_ed
|
||||
void DataEditor::doPaste() { if (current_editor) current_editor->doPaste(); }
|
||||
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
|
||||
|
||||
void DataEditor::onLeftDown(wxMouseEvent& ev) {
|
||||
@@ -274,7 +288,9 @@ void DataEditor::onContextMenu(wxContextMenuEvent& ev) {
|
||||
}
|
||||
void DataEditor::onMenu(wxCommandEvent& ev) {
|
||||
if (current_editor) {
|
||||
current_editor->onMenu(ev);
|
||||
if (!current_editor->onCommand(ev.GetId())) {
|
||||
ev.Skip();
|
||||
}
|
||||
} else {
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@ class DataEditor : public CardViewer {
|
||||
bool canFormat(int type) const;
|
||||
bool hasFormat(int type) const;
|
||||
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
|
||||
|
||||
|
||||
@@ -282,7 +282,9 @@ void CardListBase::rebuild() {
|
||||
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 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);
|
||||
}
|
||||
// find field that determines color
|
||||
|
||||
@@ -75,7 +75,7 @@ void CardListColumnSelectDialog::initList() {
|
||||
// Init items
|
||||
Color window_color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
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
|
||||
int i = list->GetCount() - 1;
|
||||
list->Check(i, c.settings.visible);
|
||||
@@ -88,7 +88,7 @@ void CardListColumnSelectDialog::initList() {
|
||||
|
||||
void CardListColumnSelectDialog::refreshItem(int i) {
|
||||
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
|
||||
|
||||
@@ -38,7 +38,9 @@ void NativeLookEditor::drawViewer(RotatedDC& dc, ValueViewer& v) {
|
||||
dc.DrawRectangle(s.getRect().grow(1));
|
||||
// draw label
|
||||
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_control_border(this, dc.getDC(), RealRect(s.left - 1, s.top - 1, s.width + 2, s.height + 2));
|
||||
// draw viewer
|
||||
|
||||
@@ -77,6 +77,11 @@ void IconMenu::Append(int id, const String& text, const String& help, wxMenu* su
|
||||
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) {
|
||||
wxMenuItem* item = new wxMenuItem (this, id, text, help);
|
||||
item->SetBitmap(wxNullBitmap);
|
||||
|
||||
@@ -27,6 +27,8 @@ class IconMenu : public wxMenu {
|
||||
void Append(int id, const String& text, const String& help);
|
||||
/// Append a menu item, without an image
|
||||
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
|
||||
void Insert(size_t pos, int id, const String& text, const String& help);
|
||||
};
|
||||
|
||||
+57
-27
@@ -47,10 +47,49 @@ CardsPanel::CardsPanel(Window* parent, int id)
|
||||
s->Add(splitter, 1, wxEXPAND);
|
||||
s->SetSizeHints(this);
|
||||
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() {
|
||||
// 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() {
|
||||
@@ -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->Realize();
|
||||
// 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"));
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
@@ -120,8 +134,8 @@ void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
|
||||
tb->DeleteToolByPos(10); // delete separator
|
||||
tb->DeleteToolByPos(10); // delete separator
|
||||
// Menus
|
||||
delete mb->Remove(3);
|
||||
delete mb->Remove(2);
|
||||
mb->Remove(3);
|
||||
mb->Remove(2);
|
||||
}
|
||||
|
||||
void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
@@ -148,6 +162,16 @@ void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
class ImageCardList;
|
||||
class DataEditor;
|
||||
class TextCtrl;
|
||||
class IconMenu;
|
||||
|
||||
// ----------------------------------------------------------------------------- : CardsPanel
|
||||
|
||||
@@ -95,7 +96,8 @@ class CardsPanel : public SetWindowPanel {
|
||||
TextCtrl* notes;
|
||||
|
||||
// --------------------------------------------------- : Menus & tools
|
||||
wxMenu* cardMenu, formatMenu;
|
||||
IconMenu* menuCard, *menuFormat;
|
||||
wxMenuItem* insertSymbolMenu; // owned by menuFormat, but submenu owned by SymbolFont
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -53,8 +53,10 @@ class ValueEditor {
|
||||
/// a context menu is requested, add extra items to the menu m
|
||||
/** return false to suppress menu */
|
||||
virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent& ev) { return true; }
|
||||
/// A menu item was selected
|
||||
virtual void onMenu(wxCommandEvent& ev) { ev.Skip(); }
|
||||
/// Get a special menu, events will be sent to onMenu
|
||||
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
|
||||
|
||||
|
||||
+27
-1
@@ -192,7 +192,7 @@ void TextValueEditor::onChar(wxKeyEvent& ev) {
|
||||
// TODO: Find a more correct way to determine normal characters,
|
||||
// this might not work for internationalized input.
|
||||
// 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) {
|
||||
// always show the menu
|
||||
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) {
|
||||
if (ev.GetId() == ID_FORMAT_REMINDER) {
|
||||
// toggle reminder text
|
||||
@@ -235,6 +260,7 @@ void TextValueEditor::onMenu(wxCommandEvent& ev) {
|
||||
ev.Skip();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : Other overrides
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
|
||||
virtual void onMouseWheel(const RealPoint& pos, wxMouseEvent& ev);
|
||||
|
||||
virtual bool onContextMenu(wxMenu& m, wxContextMenuEvent&);
|
||||
virtual void onMenu(wxCommandEvent&);
|
||||
virtual wxMenu* getMenu(int type) const;
|
||||
virtual bool onCommand(int);
|
||||
|
||||
virtual void onChar(wxKeyEvent&);
|
||||
|
||||
@@ -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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Make sure the selection satisfies its constraints
|
||||
|
||||
+24
-6
@@ -24,7 +24,8 @@ String Error::what() const {
|
||||
|
||||
// Errors for which a message box was already shown
|
||||
vector<String> previous_errors;
|
||||
String pending_error;
|
||||
String pending_errors;
|
||||
String pending_warnings;
|
||||
DECLARE_TYPEOF_COLLECTION(String);
|
||||
|
||||
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
|
||||
if (!now || !wxThread::IsMain()) {
|
||||
if (!pending_error.empty()) pending_error += _("\n\n");
|
||||
pending_error += e;
|
||||
if (!pending_errors.empty()) pending_errors += _("\n\n");
|
||||
pending_errors += e;
|
||||
return;
|
||||
}
|
||||
// show message
|
||||
@@ -50,10 +51,27 @@ void handle_error(const Error& e, bool allow_duplicate, bool 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() {
|
||||
assert(wxThread::IsMain());
|
||||
if (!pending_error.empty()) {
|
||||
handle_error(pending_error);
|
||||
pending_error.clear();
|
||||
if (!pending_errors.empty()) {
|
||||
handle_error(pending_errors);
|
||||
pending_errors.clear();
|
||||
}
|
||||
if (!pending_warnings.empty()) {
|
||||
handle_warning(pending_warnings);
|
||||
pending_warnings.clear();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -96,7 +96,10 @@ class ScriptError : public Error {
|
||||
*/
|
||||
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) */
|
||||
void handle_pending_errors();
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class Package {
|
||||
bool needSaveAs() const;
|
||||
/// Determines the short name of this package: the filename without path or extension
|
||||
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;
|
||||
/// Return the absolute filename of this file
|
||||
const String& absoluteFilename() const;
|
||||
|
||||
@@ -41,7 +41,7 @@ void Reader::handleAppVersion() {
|
||||
if (enterBlock(_("mse_version"))) {
|
||||
handle(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();
|
||||
}
|
||||
@@ -53,7 +53,7 @@ void Reader::warning(const String& msg) {
|
||||
|
||||
void Reader::showWarnings() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <util/string.hpp>
|
||||
|
||||
class Game;
|
||||
class StyleSheet;
|
||||
class SymbolFont;
|
||||
|
||||
// ----------------------------------------------------------------------------- : Localisation macros
|
||||
|
||||
enum LocaleCategory
|
||||
@@ -37,6 +41,24 @@ enum LocaleCategory
|
||||
/// Translate 'key' in the category 'cat' using the current locale
|
||||
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
|
||||
#define _MENU_(s) tr(LOCALE_CAT_MENU, _(s))
|
||||
/// A localized string for help/statusbar text
|
||||
|
||||
+7
-3
@@ -141,13 +141,17 @@ String cannocial_name_form(const String& str) {
|
||||
ret.reserve(str.size());
|
||||
bool leading = true;
|
||||
FOR_EACH_CONST(c, str) {
|
||||
if ((c == _('_') || c == _(' ')) && !leading) {
|
||||
ret += _(' ');
|
||||
if ((c == _('_') || c == _(' '))) {
|
||||
if (!leading) ret += _(' ');
|
||||
} else {
|
||||
ret += c;
|
||||
leading = false;
|
||||
/*
|
||||
} else if (isAlnum(c) || c == _('-')) {
|
||||
ret += toLower(c);
|
||||
leading = false;
|
||||
} else {
|
||||
// ignore non alpha numeric
|
||||
// ignore non alpha numeric*/
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -331,7 +331,7 @@ String tagged_substr_replace(const String& input, size_t start, size_t end, cons
|
||||
return simplify_tagged(
|
||||
substr_replace(input, start, end,
|
||||
get_tags(input, start, end, true) + // close tags
|
||||
escape(replacement) +
|
||||
replacement +
|
||||
get_tags(input, start, end, false) // open tags
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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 means that when removing "<x>a</x>" nothing is left,
|
||||
* 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);
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ enum MenuID {
|
||||
enum ChildMenuID {
|
||||
|
||||
ID_CHILD_MIN = 1000
|
||||
, ID_CHILD_MAX = 2999
|
||||
, ID_CHILD_MAX = 3999
|
||||
|
||||
// Cards menu
|
||||
, ID_CARD_ADD = 1001
|
||||
@@ -106,6 +106,7 @@ enum ChildMenuID {
|
||||
, ID_FORMAT_ITALIC
|
||||
, ID_FORMAT_SYMBOL
|
||||
, ID_FORMAT_REMINDER
|
||||
, ID_INSERT_SYMBOL
|
||||
|
||||
// SymbolSelectEditor toolbar/menu
|
||||
, ID_PART = 2001
|
||||
@@ -146,6 +147,10 @@ enum ChildMenuID {
|
||||
|
||||
// Style
|
||||
, ID_STYLE_USE_FOR_ALL = 3201
|
||||
|
||||
// SymbolFont (Format menu)
|
||||
, ID_INSERT_SYMBOL_MENU_MIN = 3301
|
||||
, ID_INSERT_SYMBOL_MENU_MAX = 3999
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user