Commit 4f492f06 authored by twanvl's avatar twanvl

Implemented auto replace, including GUI

parent 5257a369
...@@ -29,6 +29,7 @@ menu: ...@@ -29,6 +29,7 @@ menu:
find: &Find Ctrl+F find: &Find Ctrl+F
find next: Find &Next F3 find next: Find &Next F3
replace: R&eplace Ctrl+H replace: R&eplace Ctrl+H
auto replace: Auto Rep&lace...
preferences: &Preferences... preferences: &Preferences...
cards: &Cards cards: &Cards
...@@ -125,6 +126,10 @@ help: ...@@ -125,6 +126,10 @@ help:
paste: Inserts the text from the clipboard paste: Inserts the text from the clipboard
paste card: Inserts the card from the clipboard paste card: Inserts the card from the clipboard
paste keyword: Inserts the keyword from the clipboard paste keyword: Inserts the keyword from the clipboard
find: Search the card texts
find next: Find the next match
replace: Replace in the card texts
auto replace: What text should automatically be replaced?
preferences: Change the configuration of Magic Set Editor preferences: Change the configuration of Magic Set Editor
cards: cards:
...@@ -435,6 +440,10 @@ label: ...@@ -435,6 +440,10 @@ label:
zoom: Zoom zoom: Zoom
filter: Filter filter: Filter
# Auto replace
auto match: Match
auto replace: Replace
# Symbol editor # Symbol editor
sides: sides sides: sides
...@@ -484,6 +493,14 @@ button: ...@@ -484,6 +493,14 @@ button:
# Update checker # Update checker
close: &Close close: &Close
# Auto replace
use auto replace: Use auto replace
add item: &Add
remove item: &Remove
defaults: Reset to &Defaults
enabled: Enabled
whole word: Match whole word only
############################################################## Titles in the GUI ############################################################## Titles in the GUI
title: title:
...@@ -519,6 +536,8 @@ title: ...@@ -519,6 +536,8 @@ title:
export cancelled: Export Cancelled export cancelled: Export Cancelled
export html: Export to HTML export html: Export to HTML
save html: Export to HTML save html: Export to HTML
# auto replace
auto replaces: Auto Replace
# Package Update Window # Package Update Window
package list: Package Updates package list: Package Updates
...@@ -537,6 +556,7 @@ action: ...@@ -537,6 +556,7 @@ action:
delete: Delete delete: Delete
cut: Cut cut: Cut
paste: Paste paste: Paste
auto replace: Auto Replace
# Choice/color editors # Choice/color editors
change: Change %s change: Change %s
...@@ -623,6 +643,7 @@ error: ...@@ -623,6 +643,7 @@ error:
When you open it, some aspects of the file may be lost. When you open it, some aspects of the file may be lost.
It is recommended that you upgrade to the latest version. It is recommended that you upgrade to the latest version.
Visit http:://magicseteditor.sourceforge.net/ Visit http:://magicseteditor.sourceforge.net/
word list type not found: The word list type %s was not found (from a <word-list> tag)
# Update checking # Update checking
checking updates failed: Checking updates failed. checking updates failed: Checking updates failed.
......
...@@ -57,7 +57,8 @@ IMPLEMENT_REFLECTION(Game) { ...@@ -57,7 +57,8 @@ IMPLEMENT_REFLECTION(Game) {
REFLECT(keyword_modes); REFLECT(keyword_modes);
REFLECT(keyword_parameter_types); REFLECT(keyword_parameter_types);
REFLECT_NO_SCRIPT(keywords); REFLECT_NO_SCRIPT(keywords);
REFLECT(word_lists); REFLECT_NO_SCRIPT(word_lists);
REFLECT_NO_SCRIPT(auto_replaces);
} }
void Game::validate(Version v) { void Game::validate(Version v) {
......
...@@ -25,6 +25,7 @@ DECLARE_POINTER_TYPE(KeywordParam); ...@@ -25,6 +25,7 @@ DECLARE_POINTER_TYPE(KeywordParam);
DECLARE_POINTER_TYPE(KeywordMode); DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword); DECLARE_POINTER_TYPE(Keyword);
DECLARE_POINTER_TYPE(WordList); DECLARE_POINTER_TYPE(WordList);
DECLARE_POINTER_TYPE(AutoReplace);
// ----------------------------------------------------------------------------- : Game // ----------------------------------------------------------------------------- : Game
...@@ -45,13 +46,14 @@ class Game : public Packaged { ...@@ -45,13 +46,14 @@ class Game : public Packaged {
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
vector<PackTypeP> pack_types; ///< Types of random card packs to generate vector<PackTypeP> pack_types; ///< Types of random card packs to generate
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
bool has_keywords; ///< Does this game use keywords? bool has_keywords; ///< Does this game use keywords?
OptionalScript keyword_match_script; ///< For the keyword editor OptionalScript keyword_match_script; ///< For the keyword editor
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
vector<KeywordModeP> keyword_modes; ///< Modes of keywords vector<KeywordModeP> keyword_modes; ///< Modes of keywords
vector<KeywordP> keywords; ///< Keywords for use in text vector<KeywordP> keywords; ///< Keywords for use in text
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized? bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <data/stylesheet.hpp> #include <data/stylesheet.hpp>
#include <data/field.hpp> #include <data/field.hpp>
#include <data/export_template.hpp> #include <data/export_template.hpp>
#include <data/word_list.hpp>
#include <util/reflect.hpp> #include <util/reflect.hpp>
#include <util/platform.hpp> #include <util/platform.hpp>
#include <util/io/reader.hpp> #include <util/io/reader.hpp>
...@@ -19,6 +20,8 @@ ...@@ -19,6 +20,8 @@
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
DECLARE_TYPEOF_COLLECTION(AutoReplaceP);
// ----------------------------------------------------------------------------- : Extra types // ----------------------------------------------------------------------------- : Extra types
IMPLEMENT_REFLECTION_ENUM(CheckUpdates) { IMPLEMENT_REFLECTION_ENUM(CheckUpdates) {
...@@ -43,7 +46,7 @@ ColumnSettings::ColumnSettings() ...@@ -43,7 +46,7 @@ ColumnSettings::ColumnSettings()
// dummy for ColumnSettings reflection // dummy for ColumnSettings reflection
ScriptValueP to_script(const ColumnSettings&) { return script_nil; } ScriptValueP to_script(const ColumnSettings&) { return script_nil; }
IMPLEMENT_REFLECTION(ColumnSettings) { IMPLEMENT_REFLECTION_NO_SCRIPT(ColumnSettings) {
REFLECT(width); REFLECT(width);
REFLECT(position); REFLECT(position);
REFLECT(visible); REFLECT(visible);
...@@ -53,9 +56,33 @@ GameSettings::GameSettings() ...@@ -53,9 +56,33 @@ GameSettings::GameSettings()
: sort_cards_ascending(true) : sort_cards_ascending(true)
, images_export_filename(_("{card.name}.jpg")) , images_export_filename(_("{card.name}.jpg"))
, images_export_conflicts(CONFLICT_NUMBER_OVERWRITE) , images_export_conflicts(CONFLICT_NUMBER_OVERWRITE)
, use_auto_replace(true)
, initialized(false)
{} {}
IMPLEMENT_REFLECTION(GameSettings) { void GameSettings::initDefaults(const Game& game) {
if (initialized) return;
initialized = true;
// init auto_replaces, copy from game file
FOR_EACH_CONST(ar, game.auto_replaces) {
// do we have this one?
bool already_have = false;
FOR_EACH(ar2, auto_replaces) {
if (ar->match == ar2->match) {
ar2->custom = false;
already_have = true;
break;
}
}
if (!already_have) {
// TODO: when we start saving games, clone here
ar->custom = false;
auto_replaces.push_back(ar);
}
}
}
IMPLEMENT_REFLECTION_NO_SCRIPT(GameSettings) {
REFLECT(default_stylesheet); REFLECT(default_stylesheet);
REFLECT(default_export); REFLECT(default_export);
REFLECT_N("cardlist columns", columns); REFLECT_N("cardlist columns", columns);
...@@ -63,6 +90,8 @@ IMPLEMENT_REFLECTION(GameSettings) { ...@@ -63,6 +90,8 @@ IMPLEMENT_REFLECTION(GameSettings) {
REFLECT(sort_cards_ascending); REFLECT(sort_cards_ascending);
REFLECT(images_export_filename); REFLECT(images_export_filename);
REFLECT(images_export_conflicts); REFLECT(images_export_conflicts);
REFLECT(use_auto_replace);
REFLECT(auto_replaces);
} }
...@@ -82,7 +111,7 @@ void StyleSheetSettings::useDefault(const StyleSheetSettings& ss) { ...@@ -82,7 +111,7 @@ void StyleSheetSettings::useDefault(const StyleSheetSettings& ss) {
if (card_normal_export.isDefault()) card_normal_export.assignDefault(ss.card_normal_export); if (card_normal_export.isDefault()) card_normal_export.assignDefault(ss.card_normal_export);
} }
IMPLEMENT_REFLECTION(StyleSheetSettings) { IMPLEMENT_REFLECTION_NO_SCRIPT(StyleSheetSettings) {
REFLECT(card_zoom); REFLECT(card_zoom);
REFLECT(card_angle); REFLECT(card_angle);
REFLECT(card_anti_alias); REFLECT(card_anti_alias);
...@@ -127,6 +156,7 @@ void Settings::addRecentFile(const String& filename) { ...@@ -127,6 +156,7 @@ void Settings::addRecentFile(const String& filename) {
GameSettings& Settings::gameSettingsFor(const Game& game) { GameSettings& Settings::gameSettingsFor(const Game& game) {
GameSettingsP& gs = game_settings[game.name()]; GameSettingsP& gs = game_settings[game.name()];
if (!gs) gs = new_intrusive<GameSettings>(); if (!gs) gs = new_intrusive<GameSettings>();
gs->initDefaults(game);
return *gs; return *gs;
} }
ColumnSettings& Settings::columnSettingsFor(const Game& game, const Field& field) { ColumnSettings& Settings::columnSettingsFor(const Game& game, const Field& field) {
...@@ -165,7 +195,7 @@ String Settings::settingsFile() { ...@@ -165,7 +195,7 @@ String Settings::settingsFile() {
return user_settings_dir() + _("mse8.config"); // use different file during development of C++ port return user_settings_dir() + _("mse8.config"); // use different file during development of C++ port
} }
IMPLEMENT_REFLECTION(Settings) { IMPLEMENT_REFLECTION_NO_SCRIPT(Settings) {
REFLECT_ALIAS(300, "style settings", "stylesheet settings"); REFLECT_ALIAS(300, "style settings", "stylesheet settings");
REFLECT_ALIAS(300, "default style settings", "default stylesheet settings"); REFLECT_ALIAS(300, "default style settings", "default stylesheet settings");
REFLECT(locale); REFLECT(locale);
......
...@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(GameSettings); ...@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(GameSettings);
DECLARE_POINTER_TYPE(StyleSheetSettings); DECLARE_POINTER_TYPE(StyleSheetSettings);
DECLARE_POINTER_TYPE(Field); DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(AutoReplace);
// ----------------------------------------------------------------------------- : Extra data structures // ----------------------------------------------------------------------------- : Extra data structures
...@@ -56,6 +57,9 @@ class GameSettings : public IntrusivePtrBase<GameSettings> { ...@@ -56,6 +57,9 @@ class GameSettings : public IntrusivePtrBase<GameSettings> {
public: public:
GameSettings(); GameSettings();
/// Where the settings have defaults, initialize with the values from the game
void initDefaults(const Game& g);
String default_stylesheet; String default_stylesheet;
String default_export; String default_export;
map<String, ColumnSettings> columns; map<String, ColumnSettings> columns;
...@@ -63,8 +67,12 @@ class GameSettings : public IntrusivePtrBase<GameSettings> { ...@@ -63,8 +67,12 @@ class GameSettings : public IntrusivePtrBase<GameSettings> {
bool sort_cards_ascending; bool sort_cards_ascending;
String images_export_filename; String images_export_filename;
FilenameConflicts images_export_conflicts; FilenameConflicts images_export_conflicts;
bool use_auto_replace;
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
DECLARE_REFLECTION(); DECLARE_REFLECTION();
private:
bool initialized;
}; };
/// Settings for a StyleSheet /// Settings for a StyleSheet
......
...@@ -281,9 +281,16 @@ IMPLEMENT_REFLECTION(Symbol) { ...@@ -281,9 +281,16 @@ IMPLEMENT_REFLECTION(Symbol) {
} }
double Symbol::aspectRatio() const { double Symbol::aspectRatio() const {
// Margin between the edges and the symbol.
// In each direction take the lowest one
// This is at most 0.5 (if the symbol is just a line in the middle)
// Multiply by 2 (below) to give something in the range [0...1] i.e. [touches the edge...only in the middle]
double margin_x = min(0.4999, max(0., min(min_pos.x, 1-max_pos.x))); double margin_x = min(0.4999, max(0., min(min_pos.x, 1-max_pos.x)));
double margin_y = min(0.4999, max(0., min(min_pos.y, 1-max_pos.y))); double margin_y = min(0.4999, max(0., min(min_pos.y, 1-max_pos.y)));
// The difference between these two,
// e.g. if the vertical margin is more then the horizontal one, the symbol is 'flat'
double delta = 2 * (margin_y - margin_x); double delta = 2 * (margin_y - margin_x);
// The aspect ratio, i.e. width/height
if (delta > 0) { if (delta > 0) {
return 1 / (1 - delta); return 1 / (1 - delta);
} else { } else {
......
...@@ -32,3 +32,18 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(WordList) { ...@@ -32,3 +32,18 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(WordList) {
REFLECT(words); REFLECT(words);
} }
// ----------------------------------------------------------------------------- : Auto replace words
AutoReplace::AutoReplace()
: enabled(true)
, whole_word(true)
, custom(true)
{}
IMPLEMENT_REFLECTION_NO_SCRIPT(AutoReplace) {
REFLECT(enabled);
REFLECT(whole_word);
REFLECT(match);
REFLECT(replace);
}
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
DECLARE_POINTER_TYPE(WordListWord); DECLARE_POINTER_TYPE(WordListWord);
DECLARE_POINTER_TYPE(WordList); DECLARE_POINTER_TYPE(WordList);
DECLARE_POINTER_TYPE(AutoReplace);
// ----------------------------------------------------------------------------- : WordList // ----------------------------------------------------------------------------- : WordList
...@@ -38,6 +39,23 @@ class WordList : public WordListWord { ...@@ -38,6 +39,23 @@ class WordList : public WordListWord {
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
// ----------------------------------------------------------------------------- : Auto replace words
/// Autoreplace specific shortcut words
class AutoReplace : public IntrusivePtrVirtualBase {
public:
AutoReplace();
bool enabled;
bool whole_word;
bool custom; ///< Is this a custom auto replace?
String match;
String replace;
inline AutoReplaceP clone() const { return new_intrusive1<AutoReplace>(*this); }
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <gui/print_window.hpp> #include <gui/print_window.hpp>
#include <gui/images_export_window.hpp> #include <gui/images_export_window.hpp>
#include <gui/html_export_window.hpp> #include <gui/html_export_window.hpp>
#include <gui/auto_replace_window.hpp>
#include <gui/icon_menu.hpp> #include <gui/icon_menu.hpp>
#include <gui/util.hpp> #include <gui/util.hpp>
#include <util/io/package_manager.hpp> #include <util/io/package_manager.hpp>
...@@ -86,9 +87,10 @@ SetWindow::SetWindow(Window* parent, const SetP& set) ...@@ -86,9 +87,10 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
menuEdit->Append(ID_EDIT_COPY, _("copy"), _MENU_("copy"), _HELP_("copy")); menuEdit->Append(ID_EDIT_COPY, _("copy"), _MENU_("copy"), _HELP_("copy"));
menuEdit->Append(ID_EDIT_PASTE, _("paste"), _MENU_("paste"), _HELP_("paste")); menuEdit->Append(ID_EDIT_PASTE, _("paste"), _MENU_("paste"), _HELP_("paste"));
menuEdit->AppendSeparator(); menuEdit->AppendSeparator();
menuEdit->Append(ID_EDIT_FIND, _("find"), _MENU_("find"), _("")); menuEdit->Append(ID_EDIT_FIND, _("find"), _MENU_("find"), _HELP_("find"));
menuEdit->Append(ID_EDIT_FIND_NEXT, _MENU_("find next"), _("")); menuEdit->Append(ID_EDIT_FIND_NEXT, _MENU_("find next"), _HELP_("find next"));
menuEdit->Append(ID_EDIT_REPLACE, _MENU_("replace"), _("")); menuEdit->Append(ID_EDIT_REPLACE, _MENU_("replace"), _HELP_("replace"));
menuEdit->Append(ID_EDIT_AUTO_REPLACE, _MENU_("auto replace"), _HELP_("auto replace"));
menuEdit->AppendSeparator(); menuEdit->AppendSeparator();
menuEdit->Append(ID_EDIT_PREFERENCES, _MENU_("preferences"), _HELP_("preferences")); menuEdit->Append(ID_EDIT_PREFERENCES, _MENU_("preferences"), _HELP_("preferences"));
menuBar->Append(menuEdit, _MENU_("edit")); menuBar->Append(menuEdit, _MENU_("edit"));
...@@ -619,6 +621,10 @@ void SetWindow::onReplaceAll(wxFindDialogEvent&) { ...@@ -619,6 +621,10 @@ void SetWindow::onReplaceAll(wxFindDialogEvent&) {
current_panel->doReplaceAll(find_data); current_panel->doReplaceAll(find_data);
} }
void SetWindow::onEditAutoReplace(wxCommandEvent&) {
(new AutoReplaceWindow(this, *set->game))->Show();
}
void SetWindow::onEditPreferences(wxCommandEvent&) { void SetWindow::onEditPreferences(wxCommandEvent&) {
PreferencesWindow wnd(this); PreferencesWindow wnd(this);
if (wnd.ShowModal() == wxID_OK) { if (wnd.ShowModal() == wxID_OK) {
...@@ -697,6 +703,7 @@ BEGIN_EVENT_TABLE(SetWindow, wxFrame) ...@@ -697,6 +703,7 @@ BEGIN_EVENT_TABLE(SetWindow, wxFrame)
EVT_MENU (ID_EDIT_FIND, SetWindow::onEditFind) EVT_MENU (ID_EDIT_FIND, SetWindow::onEditFind)
EVT_MENU (ID_EDIT_FIND_NEXT, SetWindow::onEditFindNext) EVT_MENU (ID_EDIT_FIND_NEXT, SetWindow::onEditFindNext)
EVT_MENU (ID_EDIT_REPLACE, SetWindow::onEditReplace) EVT_MENU (ID_EDIT_REPLACE, SetWindow::onEditReplace)
EVT_MENU (ID_EDIT_AUTO_REPLACE, SetWindow::onEditAutoReplace)
EVT_MENU (ID_EDIT_PREFERENCES, SetWindow::onEditPreferences) EVT_MENU (ID_EDIT_PREFERENCES, SetWindow::onEditPreferences)
EVT_MENU (ID_WINDOW_NEW, SetWindow::onWindowNewWindow) EVT_MENU (ID_WINDOW_NEW, SetWindow::onWindowNewWindow)
EVT_TOOL_RANGE (ID_WINDOW_MIN, ID_WINDOW_MAX, SetWindow::onWindowSelect) EVT_TOOL_RANGE (ID_WINDOW_MIN, ID_WINDOW_MAX, SetWindow::onWindowSelect)
......
...@@ -131,6 +131,7 @@ class SetWindow : public wxFrame, public SetView { ...@@ -131,6 +131,7 @@ class SetWindow : public wxFrame, public SetView {
void onEditFind (wxCommandEvent&); void onEditFind (wxCommandEvent&);
void onEditFindNext (wxCommandEvent&); void onEditFindNext (wxCommandEvent&);
void onEditReplace (wxCommandEvent&); void onEditReplace (wxCommandEvent&);
void onEditAutoReplace (wxCommandEvent&);
void onEditPreferences (wxCommandEvent&); void onEditPreferences (wxCommandEvent&);
void onFind (wxFindDialogEvent&); void onFind (wxFindDialogEvent&);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <gui/drop_down_list.hpp> #include <gui/drop_down_list.hpp>
#include <data/word_list.hpp> #include <data/word_list.hpp>
#include <data/game.hpp> #include <data/game.hpp>
#include <data/settings.hpp>
#include <data/action/value.hpp> #include <data/action/value.hpp>
#include <util/tagged_string.hpp> #include <util/tagged_string.hpp>
#include <util/find_replace.hpp> #include <util/find_replace.hpp>
...@@ -23,6 +24,7 @@ DECLARE_SHARED_POINTER_TYPE(DropDownList); ...@@ -23,6 +24,7 @@ DECLARE_SHARED_POINTER_TYPE(DropDownList);
DECLARE_TYPEOF_COLLECTION(WordListP); DECLARE_TYPEOF_COLLECTION(WordListP);
DECLARE_TYPEOF_COLLECTION(WordListWordP); DECLARE_TYPEOF_COLLECTION(WordListWordP);
DECLARE_TYPEOF_COLLECTION(WordListPosP); DECLARE_TYPEOF_COLLECTION(WordListPosP);
DECLARE_TYPEOF_COLLECTION(AutoReplaceP);
// ----------------------------------------------------------------------------- : TextValueEditorScrollBar // ----------------------------------------------------------------------------- : TextValueEditorScrollBar
...@@ -273,8 +275,8 @@ bool TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) { ...@@ -273,8 +275,8 @@ bool TextValueEditor::onMotion(const RealPoint& pos, wxMouseEvent& ev) {
if (select_words) { if (select_words) {
// on the left, swap start and end // on the left, swap start and end
bool left = selection_end_i < selection_start_i; bool left = selection_end_i < selection_start_i;
size_t next = nextWordBoundry(index); size_t next = nextWordBoundary(index);
size_t prev = prevWordBoundry(index); size_t prev = prevWordBoundary(index);
if (( left && next > max(selection_start_i, selection_end_i)) || if (( left && next > max(selection_start_i, selection_end_i)) ||
(!left && prev < min(selection_start_i, selection_end_i))) { (!left && prev < min(selection_start_i, selection_end_i))) {
left = !left; left = !left;
...@@ -294,8 +296,8 @@ bool TextValueEditor::onLeftDClick(const RealPoint& pos, wxMouseEvent& ev) { ...@@ -294,8 +296,8 @@ bool TextValueEditor::onLeftDClick(const RealPoint& pos, wxMouseEvent& ev) {
select_words = true; select_words = true;
selecting = true; selecting = true;
size_t index = v.indexAt(style().getRotation().trInv(pos)); size_t index = v.indexAt(style().getRotation().trInv(pos));
moveSelection(TYPE_INDEX, prevWordBoundry(index), true, MOVE_MID); moveSelection(TYPE_INDEX, prevWordBoundary(index), true, MOVE_MID);
moveSelection(TYPE_INDEX, nextWordBoundry(index), false, MOVE_MID); moveSelection(TYPE_INDEX, nextWordBoundary(index), false, MOVE_MID);
return true; return true;
} }
...@@ -323,17 +325,17 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -323,17 +325,17 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
case WXK_LEFT: case WXK_LEFT:
// move left (selection?) // move left (selection?)
if (ev.ControlDown()) { if (ev.ControlDown()) {
moveSelection(TYPE_INDEX, prevWordBoundry(selection_end_i),!ev.ShiftDown(), MOVE_LEFT); moveSelection(TYPE_INDEX, prevWordBoundary(selection_end_i),!ev.ShiftDown(), MOVE_LEFT);
} else { } else {
moveSelection(TYPE_CURSOR, prevCharBoundry(selection_end), !ev.ShiftDown(), MOVE_LEFT); moveSelection(TYPE_CURSOR, prevCharBoundary(selection_end), !ev.ShiftDown(), MOVE_LEFT);
} }
break; break;
case WXK_RIGHT: case WXK_RIGHT:
// move left (selection?) // move left (selection?)
if (ev.ControlDown()) { if (ev.ControlDown()) {
moveSelection(TYPE_INDEX, nextWordBoundry(selection_end_i),!ev.ShiftDown(), MOVE_RIGHT); moveSelection(TYPE_INDEX, nextWordBoundary(selection_end_i),!ev.ShiftDown(), MOVE_RIGHT);
} else { } else {
moveSelection(TYPE_CURSOR, nextCharBoundry(selection_end), !ev.ShiftDown(), MOVE_RIGHT); moveSelection(TYPE_CURSOR, nextCharBoundary(selection_end), !ev.ShiftDown(), MOVE_RIGHT);
} }
break; break;
case WXK_UP: case WXK_UP:
...@@ -369,10 +371,10 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -369,10 +371,10 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
case WXK_BACK: case WXK_BACK:
if (selection_start == selection_end) { if (selection_start == selection_end) {
// if no selection, select previous character // if no selection, select previous character
moveSelectionNoRedraw(TYPE_CURSOR, prevCharBoundry(selection_end), false); moveSelectionNoRedraw(TYPE_CURSOR, prevCharBoundary(selection_end), false);
if (selection_start == selection_end) { if (selection_start == selection_end) {
// Walk over a <sep> as if we are the LEFT key // Walk over a <sep> as if we are the LEFT key
moveSelection(TYPE_CURSOR, prevCharBoundry(selection_end), true, MOVE_LEFT); moveSelection(TYPE_CURSOR, prevCharBoundary(selection_end), true, MOVE_LEFT);
return true; return true;
} }
} }
...@@ -381,10 +383,10 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -381,10 +383,10 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
case WXK_DELETE: case WXK_DELETE:
if (selection_start == selection_end) { if (selection_start == selection_end) {
// if no selection select next // if no selection select next
moveSelectionNoRedraw(TYPE_CURSOR, nextCharBoundry(selection_end), false); moveSelectionNoRedraw(TYPE_CURSOR, nextCharBoundary(selection_end), false);
if (selection_start == selection_end) { if (selection_start == selection_end) {
// Walk over a <sep> as if we are the RIGHT key // Walk over a <sep> as if we are the RIGHT key
moveSelection(TYPE_CURSOR, nextCharBoundry(selection_end), true, MOVE_RIGHT); moveSelection(TYPE_CURSOR, nextCharBoundary(selection_end), true, MOVE_RIGHT);
} }
} }
replaceSelection(wxEmptyString, _ACTION_("delete")); replaceSelection(wxEmptyString, _ACTION_("delete"));
...@@ -411,9 +413,9 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) { ...@@ -411,9 +413,9 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
// 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!
#ifdef UNICODE #ifdef UNICODE
replaceSelection(escape(String(ev.GetUnicodeKey(), 1)), _ACTION_("typing")); replaceSelection(escape(String(ev.GetUnicodeKey(), 1)), _ACTION_("typing"), true);
#else #else
replaceSelection(escape(String((Char)ev.GetKeyCode(), 1)), _ACTION_("typing")); replaceSelection(escape(String((Char)ev.GetKeyCode(), 1)), _ACTION_("typing"), true);
#endif #endif
} else { } else {
return false; return false;
...@@ -775,7 +777,7 @@ size_t match_cursor_position(size_t pos1, const String& text1, size_t pos2, cons ...@@ -775,7 +777,7 @@ size_t match_cursor_position(size_t pos1, const String& text1, size_t pos2, cons
return 1000 * before + 2 * after - penalty; // matching 'before' is more important return 1000 * before + 2 * after - penalty; // matching 'before' is more important
} }
void TextValueEditor::replaceSelection(const String& replacement, const String& name) { void TextValueEditor::replaceSelection(const String& replacement, const String& name, bool allow_auto_replace, bool select_on_undo) {
if (replacement.empty() && selection_start == selection_end) { if (replacement.empty() && selection_start == selection_end) {
// no text selected, nothing to delete // no text selected, nothing to delete
return; return;
...@@ -785,10 +787,10 @@ void TextValueEditor::replaceSelection(const String& replacement, const String& ...@@ -785,10 +787,10 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
fixSelection(); fixSelection();
// execute the action before adding it to the stack, // execute the action before adding it to the stack,
// because we want to run scripts before action listeners see the action // because we want to run scripts before action listeners see the action
TextValueAction* action = typing_action(valueP(), selection_start_i, selection_end_i, selection_start, selection_end, replacement, name); TextValueAction* action = typing_action(valueP(), selection_start_i, selection_end_i, select_on_undo ? selection_start : selection_end, selection_end, replacement, name);
if (!action) { if (!action) {
// nothing changes, but move the selection anyway // nothing changes, but move the selection anyway
moveSelection(TYPE_CURSOR, selection_start); moveSelection(TYPE_CURSOR, selection_end);
return; return;
} }
// what we would expect if no scripts take place // what we would expect if no scripts take place
...@@ -832,10 +834,31 @@ void TextValueEditor::replaceSelection(const String& replacement, const String& ...@@ -832,10 +834,31 @@ void TextValueEditor::replaceSelection(const String& replacement, const String&
selection_end = selection_start = best_cursor; selection_end = selection_start = best_cursor;
fixSelection(TYPE_CURSOR, MOVE_RIGHT); fixSelection(TYPE_CURSOR, MOVE_RIGHT);
} }
// auto replace after typing?
if (allow_auto_replace) tryAutoReplace();
// scroll with next update // scroll with next update
scroll_with_cursor = true; scroll_with_cursor = true;
} }
void TextValueEditor::tryAutoReplace() {
size_t end = selection_start_i;
GameSettings& gs = settings.gameSettingsFor(*getSet().game);
FOR_EACH(ar, gs.auto_replaces) {
if (ar->enabled && ar->match.size() <= end) {
size_t start = end - ar->match.size();
if (is_substr(value().value(), start, ar->match) &&
(!ar->whole_word || (isWordBoundary(start) && isWordBoundary(end)))
) {
// replace
selection_start_i = start;
selection_end_i = end;
fixSelection(TYPE_INDEX);
replaceSelection(ar->replace, _ACTION_("auto replace"), false, false);
}
}
}
}
void TextValueEditor::moveSelection(IndexType t, size_t new_end, bool also_move_start, Movement dir) { void TextValueEditor::moveSelection(IndexType t, size_t new_end, bool also_move_start, Movement dir) {
size_t old_start = selection_start_i; size_t old_start = selection_start_i;
size_t old_end = selection_end_i; size_t old_end = selection_end_i;
...@@ -891,28 +914,64 @@ void TextValueEditor::fixSelection(IndexType t, Movement dir) { ...@@ -891,28 +914,64 @@ void TextValueEditor::fixSelection(IndexType t, Movement dir) {
} }
size_t TextValueEditor::prevCharBoundry(size_t pos) const { size_t TextValueEditor::prevCharBoundary(size_t pos) const {
return max(0, (int)pos - 1); return max(0, (int)pos - 1);
} }
size_t TextValueEditor::nextCharBoundry(size_t pos) const { size_t TextValueEditor::nextCharBoundary(size_t pos) const {
return min(index_to_cursor(value().value(), String::npos), pos + 1); return min(index_to_cursor(value().value(), String::npos), pos + 1);
} }
size_t TextValueEditor::prevWordBoundry(size_t pos_i) const {
static const Char word_bound_chars[] = _(" ,.:;()\n");
bool isWordBoundaryChar(Char c) {
return c == _(' ') || c == _(',') || c == _('.') || c == _(':') || c == _(';') ||
c == _('(') || c == _(')') || c == _('\n') || isPunct(c);
}
size_t TextValueEditor::prevWordBoundary(size_t pos_i) const {
const String& val = value().value(); const String& val = value().value();
size_t p = val.find_last_not_of(_(" ,.:;()\n"), max(0, (int)pos_i - 1)); size_t p = val.find_last_not_of(word_bound_chars, max(0, (int)pos_i - 1));
if (p == String::npos) return 0; if (p == String::npos) return 0;
p = val.find_last_of(_(" ,.:;()\n"), p); p = val.find_last_of(word_bound_chars, p);
if (p == String::npos) return 0; if (p == String::npos) return 0;
return p + 1; return p + 1;
} }
size_t TextValueEditor::nextWordBoundry(size_t pos_i) const { size_t TextValueEditor::nextWordBoundary(size_t pos_i) const {
const String& val = value().value(); const String& val = value().value();
size_t p = val.find_first_of(_(" ,.:;()\n"), pos_i); size_t p = val.find_first_of(word_bound_chars, pos_i);
if (p == String::npos) return val.size(); if (p == String::npos) return val.size();
p = val.find_first_not_of(_(" ,.:;()\n"), p); p = val.find_first_not_of(word_bound_chars, p);
if (p == String::npos) return val.size(); if (p == String::npos) return val.size();
return p; return p;
} }
bool TextValueEditor::isWordBoundary(size_t pos_i) const {
const String& val = value().value();
// boundary after?
size_t pos = pos_i;
while (true) {
if (pos >= val.size()) return true;
Char c = val.GetChar(pos);
if (c == _('<')) pos = skip_tag(val,pos); // skip tags
else if (isWordBoundaryChar(c)) return true;
else break;
}
// boundary before?
pos = pos_i;
while (true) {
if (pos == 0) return true;
Char c = val.GetChar(pos - 1);
if (c == _('>')) {
// (try to) skip tags in reverse
while (true) {
if (pos == 0) return false; // not a tag
--pos;
c = val.GetChar(pos - 1);
if (c == _('<')) { --pos; break; } // was a tag
else if (c == _('>')) return false; // was not a tag
}
}
else return isWordBoundaryChar(c);
}
}
void TextValueEditor::select(size_t start, size_t end) { void TextValueEditor::select(size_t start, size_t end) {
selection_start = start; selection_start = start;
...@@ -1129,7 +1188,7 @@ void TextValueEditor::drawWordListIndicators(RotatedDC& dc) { ...@@ -1129,7 +1188,7 @@ void TextValueEditor::drawWordListIndicators(RotatedDC& dc) {
if (current && wl->active) { if (current && wl->active) {
dc.SetPen (Color(0, 128,255)); dc.SetPen (Color(0, 128,255));
dc.SetBrush(Color(64, 160,255)); dc.SetBrush(Color(64, 160,255));
} else if (current && selection_end_i >= wl->start && selection_end_i <= wl->end) { } else if (current && selection_end_i >= wl->start && selection_end_i <= wl->end && !dropDownShown()) {
dc.SetPen (Color(64, 160,255)); dc.SetPen (Color(64, 160,255));
dc.SetBrush(Color(160,208,255)); dc.SetBrush(Color(160,208,255));
} else { } else {
......
...@@ -116,7 +116,9 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -116,7 +116,9 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
/// 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) */ /** 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, bool allow_auto_replace = false, bool select_on_undo = true);
/// Try to autoreplace at the position before the cursor
void tryAutoReplace();
/// Make sure the selection satisfies its constraints /// Make sure the selection satisfies its constraints
/** - selection_start and selection_end are inside the text /** - selection_start and selection_end are inside the text
...@@ -135,12 +137,13 @@ class TextValueEditor : public TextValueViewer, public ValueEditor { ...@@ -135,12 +137,13 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
/// Position of previous visible & selectable character /// Position of previous visible & selectable character
/** Uses cursor positions */ /** Uses cursor positions */
size_t prevCharBoundry(size_t pos) const; size_t prevCharBoundary(size_t pos) const;
size_t nextCharBoundry(size_t pos) const; size_t nextCharBoundary(size_t pos) const;
/// Front of previous word, used witch Ctrl+Left/right /// Front of previous word, used witch Ctrl+Left/right
/** Uses character indices */ /** Uses character indices */
size_t prevWordBoundry(size_t pos_i) const; size_t prevWordBoundary(size_t pos_i) const;
size_t nextWordBoundry(size_t pos_i) const; size_t nextWordBoundary(size_t pos_i) const;
bool isWordBoundary(size_t pos_i) const;
// --------------------------------------------------- : Scrolling // --------------------------------------------------- : Scrolling
......
...@@ -947,6 +947,12 @@ ...@@ -947,6 +947,12 @@
<File <File
RelativePath=".\gui\about_window.hpp"> RelativePath=".\gui\about_window.hpp">
</File> </File>
<File
RelativePath=".\gui\auto_replace_window.cpp">
</File>
<File
RelativePath=".\gui\auto_replace_window.hpp">
</File>
<File <File
RelativePath=".\gui\card_select_window.cpp"> RelativePath=".\gui\card_select_window.cpp">
</File> </File>
......
# This file contains the keys expected to be in MSE locales # This file contains the keys expected to be in MSE locales
# It was automatically generated by tools/locale/locale.pl # It was automatically generated by tools/locale/locale.pl
# Generated on Fri Aug 17 22:58:51 2007 # Generated on Sun Aug 26 21:17:38 2007
action: action:
add control point: 0 add control point: 0
add part: 1 add part: 1
add symmetry: 0 add symmetry: 0
backspace: 0 auto replace: 0
change: 1 backspace: 0
change combine mode: 0 change: 1
change shape name: 0 change combine mode: 0
change symmetry copies: 0 change shape name: 0
change symmetry type: 0 change symmetry copies: 0
convert to curve: 0 change symmetry type: 0
convert to line: 0 convert to curve: 0
cut: 0 convert to line: 0
delete: 0 cut: 0
delete point: 0 delete: 0
delete points: 0 delete point: 0
duplicate: 1 delete points: 0
enter: 0 duplicate: 1
group parts: 0 enter: 0
insert symbol: 0 group parts: 0
lock point: 0 insert symbol: 0
move: 1 lock point: 0
move curve: 0 move: 1
move handle: 0 move curve: 0
move symmetry center: 0 move handle: 0
move symmetry handle: 0 move symmetry center: 0
paste: 0 move symmetry handle: 0
remove parts: 1 paste: 0
reorder parts: 0 remove parts: 1
rotate: 1 reorder parts: 0
scale: 1 rotate: 1
shear: 1 scale: 1
soft line break: 0 shear: 1
typing: 0 soft line break: 0
ungroup parts: 0 typing: 0
button: ungroup parts: 0
always: 0 button:
browse: 0 add item: 0
check now: 0 always: 0
close: 0 browse: 0
edit symbol: 0 check now: 0
hide: 0 close: 0
high quality: 0 defaults: 0
if internet connection exists: 0 edit symbol: 0
insert parameter: 0 enabled: 0
keep old: 0 hide: 0
last opened set: 0 high quality: 0
move down: 0 if internet connection exists: 0
move up: 0 insert parameter: 0
never: 0 keep old: 0
new set: 0 last opened set: 0
number: 0 move down: 0
number overwrite: 0 move up: 0
open set: 0 never: 0
overwrite: 0 new set: 0
refer parameter: 0 number: 0
select: optional, 0 number overwrite: 0
select all: 0 open set: 0
select none: 0 overwrite: 0
show: 0 refer parameter: 0
show lines: 0 remove item: 0
symbol gallery: optional, 0 select: optional, 0
use custom styling options: 0 select all: 0
use for all cards: 0 select none: 0
zoom export: 0 show: 0
error: show lines: 0
aborting parsing: 0 symbol gallery: optional, 0
can't convert: 2 use auto replace: 0
can't convert value: 3 use custom styling options: 0
checking updates: 0 use for all cards: 0
checking updates failed: 0 whole word: 0
coordinates for blending overlap: 0 zoom export: 0
dimension not found: 1 error:
expected key: 1 aborting parsing: 0
file not found: 2 can't convert: 2
file parse error: 2 can't convert value: 3
has no member: 2 checking updates: 0
has no member value: 2 checking updates failed: 0
images used for blending must have the same size: 0 coordinates for blending overlap: 0
internal error: 1 dimension not found: 1
newer version: 2 expected key: 1
no game specified for the set: 0 file not found: 2
no packages: 0 file parse error: 2
no stylesheet specified for the set: 0 has no member: 2
no updates: 0 has no member value: 2
package not found: 1 images used for blending must have the same size: 0
package out of date: 3 internal error: 1
stylesheet and set refer to different game: 0 newer version: 2
unable to open output file: 0 no game specified for the set: 0
unable to store file: 0 no packages: 0
unrecognized value: 1 no stylesheet specified for the set: 0
unsupported field type: 1 no updates: 0
unsupported fill type: 1 package not found: 1
unsupported format: 1 package out of date: 3
help: stylesheet and set refer to different game: 0
about: 0 unable to open output file: 0
add card: 0 unable to store file: 0
add cards: 0 unrecognized value: 1
add keyword: 0 unsupported field type: 1
add symmetry: 0 unsupported fill type: 1
app language: 0 unsupported format: 1
basic shapes: 0 word list type not found: 1
bold: 0 help:
border: 0 about: 0
card list columns: 0 add card: 0
cards tab: 0 add cards: 0
check updates: 0 add keyword: 0
click to select shape: 0 add symmetry: 0
close symbol editor: 0 app language: 0
copies: 0 auto replace: 0
copy: 0 basic shapes: 0
copy card: 0 bold: 0
copy keyword: 0 border: 0
curve segment: 0 card list columns: 0
cut: 0 cards tab: 0
cut card: 0 check updates: 0
cut keyword: 0 click to select shape: 0
difference: 0 close symbol editor: 0
draft tab: optional, 0 copies: 0
drag to draw shape: 0 copy: 0
drag to move curve: 0 copy card: 0
drag to move line: 0 copy keyword: 0
drag to move point: 0 curve segment: 0
drag to resize: 1 cut: 0
drag to rotate: 1 cut card: 0
drag to shear: 1 cut keyword: 0
draw ellipse: 0 difference: 0
draw polygon: 0 draft tab: optional, 0
draw rectangle: 0 drag to draw shape: 0
draw star: 0 drag to move curve: 0
duplicate: 0 drag to move line: 0
ellipse: 0 drag to move point: 0
exit: 0 drag to resize: 1
export: 0 drag to rotate: 1
export apprentice: 0 drag to shear: 1
export html: 0 draw ellipse: 0
export image: 0 draw polygon: 0
export images: 0 draw rectangle: 0
export mws: 0 draw star: 0
filename format: 0 duplicate: 0
free point: 0 ellipse: 0
grid: 0 exit: 0
group: 0 export: 0
index: 0 export apprentice: 0
intersect: 0 export html: 0
italic: 0 export image: 0
keywords tab: 0 export images: 0
last opened set: 1 export mws: 0
line segment: 0 filename format: 0
merge: 0 find: 0
new set: 0 find next: 0
new symbol: 0 free point: 0
new window: 0 grid: 0
next card: 0 group: 0
next keyword: 0 index: 0
open set: 0 intersect: 0
open symbol: 0 italic: 0
orientation: 0 keywords tab: 0
overlap: 0 last opened set: 1
paint: 0 line segment: 0
paste: 0 merge: 0
paste card: 0 new set: 0
paste keyword: 0 new symbol: 0
points: 0 new window: 0
polygon: 0 next card: 0
preferences: 0 next keyword: 0
previous card: 0 open set: 0
previous keyword: 0 open symbol: 0
print: 0 orientation: 0
print preview: 0 overlap: 0
rectangle: 0 paint: 0
redo: 0 paste: 0
reflection: 0 paste card: 0
reload data: 0 paste keyword: 0
reminder text: 0 points: 0
remove card: 0 polygon: 0
remove keyword: 0 preferences: 0
remove symmetry: 0 previous card: 0
rotate: 0 previous keyword: 0
rotate 0: 0 print: 0
rotate 180: 0 print preview: 0
rotate 270: 0 rectangle: 0
rotate 90: 0 redo: 0
rotate card: 0 reflection: 0
rotation: 0 reload data: 0
save set: 0 reminder text: 0
save set as: 0 remove card: 0
save symbol: 0 remove keyword: 0
save symbol as: 0 remove symmetry: 0
select: 0 replace: 0
set code: 0 rotate: 0
set info tab: 0 rotate 0: 0
sides: 0 rotate 180: 0
smooth point: 0 rotate 270: 0
snap: 0 rotate 90: 0
star: 0 rotate card: 0
stats tab: 0 rotation: 0
store symbol: 0 save set: 0
style tab: 0 save set as: 0
subtract: 0 save symbol: 0
symbols: 0 save symbol as: 0
symmetric point: 0 select: 0
symmetry: 0 set code: 0
undo: 0 set info tab: 0
ungroup: 0 sides: 0
website: 0 smooth point: 0
welcome: 0 snap: 0
zoom export: 0 star: 0
label: stats tab: 0
app language: 0 store symbol: 0
apprentice: 0 style tab: 0
apprentice exe: 0 subtract: 0
apprentice export cancelled: 0 symbols: 0
card display: 0 symmetric point: 0
card notes: 0 symmetry: 0
cards to export: 0 undo: 0
check at startup: 0 ungroup: 0
checking requires internet: 0 website: 0
columns: 0 welcome: 0
export filenames: 0 zoom export: 0
external programs: 0 label:
filename conflicts: 0 app language: 0
filename format: 0 apprentice: 0
filename is ignored: 0 apprentice exe: 0
filter: 0 apprentice export cancelled: 0
game type: 0 auto match: 0
html export options: 0 auto replace: 0
html template: 0 card display: 0
keyword: 0 card notes: 0
language: 0 cards to export: 0
match: 0 check at startup: 0
mode: 0 checking requires internet: 0
original: 0 columns: 0
percent of normal: 0 export filenames: 0
reminder: 0 external programs: 0
result: 0 filename conflicts: 0
save changes: 1 filename format: 0
select cards print: 0 filename is ignored: 0
select columns: 0 filter: 0
selection: 0 game type: 0
set code: 0 html export options: 0
sides: optional, 0 html template: 0
size: 0 keyword: 0
standard keyword: 1 language: 0
style type: 0 match: 0
styling options: 0 mode: 0
uses: 0 original: 0
zoom: 0 percent of normal: 0
menu: reminder: 0
about: 0 result: 0
add card: 0 save changes: 1
add cards: 0 select cards print: 0
add keyword: 0 select columns: 0
basic shapes: 0 selection: 0
bold: 0 set code: 0
card list columns: 0 sides: optional, 0
cards: 0 size: 0
cards tab: 0 standard keyword: 1
check updates: 0 style type: 0
close symbol editor: 0 styling options: 0
copy: 0 uses: 0
cut: 0 zoom: 0
draft tab: optional, 0 menu:
duplicate: 0 about: 0
edit: 0 add card: 0
exit: 0 add cards: 0
export: 0 add keyword: 0
export apprentice: 0 auto replace: 0
export html: 0 basic shapes: 0
export image: 0 bold: 0
export images: 0 card list columns: 0
export mws: 0 cards: 0
file: 0 cards tab: 0
find: 0 check updates: 0
find next: 0 close symbol editor: 0
format: 0 copy: 0
group: 0 cut: 0
help: 0 draft tab: optional, 0
index: 0 duplicate: 0
insert symbol: 0 edit: 0
italic: 0 exit: 0
keywords: 0 export: 0
keywords tab: 0 export apprentice: 0
new set: 0 export html: 0
new symbol: 0 export image: 0
new window: 0 export images: 0
next card: 0 export mws: 0
next keyword: 0 file: 0
open set: 0 find: 0
open symbol: 0 find next: 0
orientation: 0 format: 0
paint: 0 group: 0
paste: 0 help: 0
points: 0 index: 0
preferences: 0 insert symbol: 0
previous card: 0 italic: 0
previous keyword: 0 keywords: 0
print: 0 keywords tab: 0
print preview: 0 new set: 0
redo: 1 new symbol: 0
reload data: 0 new window: 0
reminder text: 0 next card: 0
remove card: 0 next keyword: 0
remove keyword: 0 open set: 0
replace: 0 open symbol: 0
rotate: 0 orientation: 0
rotate 0: 0 paint: 0
rotate 180: 0 paste: 0
rotate 270: 0 points: 0
rotate 90: 0 preferences: 0
save set: 0 previous card: 0
save set as: 0 previous keyword: 0
save symbol: 0 print: 0
save symbol as: 0 print preview: 0
select: 0 redo: 1
set info tab: 0 reload data: 0
stats tab: 0 reminder text: 0
store symbol: 0 remove card: 0
style tab: 0 remove keyword: 0
symbols: 0 replace: 0
symmetry: 0 rotate: 0
tool: 0 rotate 0: 0
undo: 1 rotate 180: 0
ungroup: 0 rotate 270: 0
website: 0 rotate 90: 0
window: 0 save set: 0
title: save set as: 0
%s - magic set editor: 1 save symbol: 0
about: 0 save symbol as: 0
directories: 0 select: 0
display: 0 set info tab: 0
export cancelled: 0 stats tab: 0
export html: 0 store symbol: 0
export images: 0 style tab: 0
global: 0 symbols: 0
locate apprentice: 0 symmetry: 0
magic set editor: 0 tool: 0
new status: 0 undo: 1
open set: 0 ungroup: 0
package list: 0 website: 0
package name: 0 window: 0
package status: 0 title:
preferences: 0 %s - magic set editor: 1
print preview: 0 about: 0
save changes: 0 auto replaces: 0
save html: 0 directories: 0
save image: 0 display: 0
save set: 0 export cancelled: 0
select cards: 0 export html: 0
select cards export: 0 export images: 0
select columns: 0 global: 0
slice image: 0 locate apprentice: 0
symbol editor: 0 magic set editor: 0
untitled: 0 new status: 0
update check: 0 open set: 0
updates: 0 package list: 0
updates availible: 0 package name: 0
tool: package status: 0
add symmetry: 0 preferences: 0
basic shapes: 0 print preview: 0
border: 0 save changes: 0
cards tab: 0 save html: 0
curve segment: 0 save image: 0
difference: 0 save set: 0
draft tab: optional, 0 select cards: 0
ellipse: 0 select cards export: 0
free point: 0 select columns: 0
grid: 0 slice image: 0
intersect: 0 symbol editor: 0
keywords tab: 0 untitled: 0
line segment: 0 update check: 0
merge: 0 updates: 0
overlap: 0 updates availible: 0
paint: optional, 0 tool:
points: 0 add symmetry: 0
polygon: 0 basic shapes: 0
rectangle: 0 border: 0
redo: 0 cards tab: 0
reflection: 0 curve segment: 0
remove symmetry: 0 difference: 0
rotate: 0 draft tab: optional, 0
rotation: 0 ellipse: 0
select: 0 free point: 0
set info tab: 0 grid: 0
smooth point: 0 intersect: 0
snap: 0 keywords tab: 0
star: 0 line segment: 0
stats tab: 0 merge: 0
store symbol: 0 overlap: 0
style tab: 0 paint: optional, 0
subtract: 0 points: 0
symmetric point: 0 polygon: 0
symmetry: 0 rectangle: 0
undo: 0 redo: 0
tooltip: reflection: 0
add card: 0 remove symmetry: 0
add keyword: 0 rotate: 0
add symmetry: 0 rotation: 0
basic shapes: 0 select: 0
bold: 0 set info tab: 0
border: 0 smooth point: 0
cards tab: 0 snap: 0
copy: 0 star: 0
curve segment: 0 stats tab: 0
cut: 0 store symbol: 0
difference: 0 style tab: 0
draft tab: optional, 0 subtract: 0
ellipse: 0 symmetric point: 0
export: 0 symmetry: 0
free point: 0 undo: 0
grid: 0 tooltip:
intersect: 0 add card: 0
italic: 0 add keyword: 0
keywords tab: 0 add symmetry: 0
line segment: 0 basic shapes: 0
merge: 0 bold: 0
new set: 0 border: 0
open set: 0 cards tab: 0
overlap: 0 copy: 0
paint: optional, 0 curve segment: 0
paste: 0 cut: 0
points: 0 difference: 0
polygon: 0 draft tab: optional, 0
rectangle: 0 ellipse: 0
redo: 1 export: 0
reflection: 0 free point: 0
reminder text: 0 grid: 0
remove card: 0 intersect: 0
remove keyword: 0 italic: 0
remove symmetry: 0 keywords tab: 0
rotate: 0 line segment: 0
rotate card: 0 merge: 0
rotation: 0 new set: 0
save set: 0 open set: 0
select: 0 overlap: 0
set info tab: 0 paint: optional, 0
smooth point: 0 paste: 0
snap: 0 points: 0
star: 0 polygon: 0
stats tab: 0 rectangle: 0
store symbol: 0 redo: 1
style tab: 0 reflection: 0
subtract: 0 reminder text: 0
symbols: 0 remove card: 0
symmetric point: 0 remove keyword: 0
symmetry: 0 remove symmetry: 0
undo: 1 rotate: 0
type: rotate card: 0
boolean: 0 rotation: 0
card: 0 save set: 0
circle: 0 select: 0
collection: 0 set info tab: 0
collection of: 1 smooth point: 0
color: 0 snap: 0
do nothing: 0 star: 0
double: 0 stats tab: 0
ellipse: 0 store symbol: 0
field: 0 style tab: 0
function: 0 subtract: 0
game: 0 symbols: 0
group: 0 symmetric point: 0
hexagon: 0 symmetry: 0
image: 0 undo: 1
install: 0 type:
installed: 0 boolean: 0
integer: 0 card: 0
new mse: 0 circle: 0
nil: 0 collection: 0
object: 0 collection of: 1
pentagon: 0 color: 0
point: 0 do nothing: 0
points: 0 double: 0
polygon: 0 ellipse: 0
rectangle: 0 field: 0
reflection: 0 function: 0
rhombus: 0 game: 0
rotation: 0 group: 0
set: 0 hexagon: 0
shape: 0 image: 0
shapes: 0 install: 0
square: 0 installed: 0
star: 0 integer: 0
string: 0 new mse: 0
style: 0 nil: 0
stylesheet: 0 object: 0
triangle: 0 pentagon: 0
uninstall: 0 point: 0
uninstalled: 0 points: 0
upgrade: 0 polygon: 0
upgradeable: 0 rectangle: 0
value: 0 reflection: 0
rhombus: 0
rotation: 0
set: 0
shape: 0
shapes: 0
square: 0
star: 0
string: 0
style: 0
stylesheet: 0
triangle: 0
uninstall: 0
uninstalled: 0
upgrade: 0
upgradeable: 0
value: 0
...@@ -64,8 +64,8 @@ void Writer::handle(const String& value) { ...@@ -64,8 +64,8 @@ void Writer::handle(const String& value) {
// write indentation and key // write indentation and key
writeKey(); writeKey();
writeUTF8(stream, _(": ")); writeUTF8(stream, _(": "));
if (value.find_first_of(_('\n')) != String::npos) { if (value.find_first_of(_('\n')) != String::npos || (!value.empty() && isSpace(value.GetChar(0)))) {
// multiline string // multiline string, or contains leading whitespace
stream.PutChar(_('\n')); stream.PutChar(_('\n'));
indentation += 1; indentation += 1;
// split lines, and write each line // split lines, and write each line
......
...@@ -53,7 +53,8 @@ enum MenuID { ...@@ -53,7 +53,8 @@ enum MenuID {
, ID_EDIT_FIND = wxID_FIND , ID_EDIT_FIND = wxID_FIND
, ID_EDIT_FIND_NEXT = 103 , ID_EDIT_FIND_NEXT = 103
, ID_EDIT_REPLACE = wxID_REPLACE , ID_EDIT_REPLACE = wxID_REPLACE
, ID_EDIT_PREFERENCES = 104 , ID_EDIT_AUTO_REPLACE = 104
, ID_EDIT_PREFERENCES = 105
// Window menu (MainWindow) // Window menu (MainWindow)
, ID_WINDOW_NEW = 201 , ID_WINDOW_NEW = 201
...@@ -242,7 +243,13 @@ enum ControlID { ...@@ -242,7 +243,13 @@ enum ControlID {
, ID_INSTALL , ID_INSTALL
, ID_UPGRADE , ID_UPGRADE
, ID_REMOVE , ID_REMOVE
, ID_CANCEL , ID_CANCEL = wxID_CANCEL
// Auto replace window
, ID_USE_AUTO_REPLACE
, ID_ITEM_VALUE
, ID_ADD_ITEM
, ID_REMOVE_ITEM
, ID_DEFAULTS
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -16,7 +16,7 @@ close F; ...@@ -16,7 +16,7 @@ close F;
# insert stuff # insert stuff
$hpp =~ s/_\n/_$macro\n/g; $hpp =~ s/_\r?\n/_$macro\n/g;
$cpp =~ s@<util/prec.hpp>@<$file.hpp>@g; $cpp =~ s@<util/prec.hpp>@<$file.hpp>@g;
......
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