From bd55326c7dc75d24c542ca2d2d871e97e3de716e Mon Sep 17 00:00:00 2001 From: twanvl Date: Fri, 21 Jan 2011 13:26:03 +0000 Subject: [PATCH] * Added console panel for evaluating scripts and showing error messages. * Rewrite of error queue code: errors are now pulled, instead of being turned into messageboxes automatically. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1629 0fc631ac-6414-0410-93d0-97cfa31319b6 --- data/en.mse-locale/locale | 11 +- src/cli/cli_main.cpp | 25 +- src/cli/cli_main.hpp | 1 + src/cli/text_io_handler.cpp | 37 +- src/cli/text_io_handler.hpp | 6 +- src/data/font.cpp | 2 +- src/data/keyword.cpp | 4 +- src/data/locale.cpp | 4 +- src/data/statistics.cpp | 2 +- src/gui/html_export_window.cpp | 2 +- src/gui/new_window.cpp | 10 +- src/gui/set/console_panel.cpp | 401 ++++++ src/gui/set/console_panel.hpp | 61 + src/gui/set/window.cpp | 7 +- src/gui/thumbnail_thread.cpp | 4 +- src/gui/value/choice.cpp | 2 +- src/gui/welcome_window.cpp | 6 +- src/mse.vcproj | 8 + src/render/card/viewer.cpp | 6 +- src/render/value/image.cpp | 4 +- src/resource/common/expected_locale_keys | 1250 ++++++++++--------- src/resource/common/message_error.png | Bin 0 -> 701 bytes src/resource/common/message_information.png | Bin 0 -> 778 bytes src/resource/common/message_input.png | Bin 0 -> 410 bytes src/resource/common/message_warning.png | Bin 0 -> 666 bytes src/resource/msw/mse.rc | 6 + src/resource/msw/tool/window_console.png | Bin 0 -> 525 bytes src/script/functions/basic.cpp | 8 +- src/script/script_manager.cpp | 12 +- src/util/error.cpp | 108 +- src/util/error.hpp | 69 +- src/util/io/package.cpp | 6 +- src/util/io/package_manager.cpp | 8 +- src/util/io/reader.cpp | 4 +- src/util/tagged_string.cpp | 6 +- src/util/vcs/subversion.cpp | 2 +- src/util/window_id.hpp | 3 + 37 files changed, 1288 insertions(+), 797 deletions(-) create mode 100644 src/gui/set/console_panel.cpp create mode 100644 src/gui/set/console_panel.hpp create mode 100644 src/resource/common/message_error.png create mode 100644 src/resource/common/message_information.png create mode 100644 src/resource/common/message_input.png create mode 100644 src/resource/common/message_warning.png create mode 100644 src/resource/msw/tool/window_console.png diff --git a/data/en.mse-locale/locale b/data/en.mse-locale/locale index a4ade44a..08d89303 100644 --- a/data/en.mse-locale/locale +++ b/data/en.mse-locale/locale @@ -53,7 +53,7 @@ menu: previous keyword: Select &Previous Keyword PgUp next keyword: Select &Next Keyword PgDn add keyword: &Add Keyword Ctrl+Enter - remove keyword: &Remove Select Keyword Del + remove keyword: &Remove Select Keyword Del format: F&ormat bold: &Bold Ctrl+B @@ -79,6 +79,7 @@ menu: keywords tab: &Keywords F8 stats tab: S&tatistics F9 random pack tab: &Random Packs + console tab: &Console Ctrl+F9 help: &Help index: &Index... F1 @@ -190,6 +191,7 @@ help: keywords tab: Define extra keywords for this set stats tab: Show statistics about the cards in the set random pack tab: Try how the set works out in practice by generating random booster packs. + console tab: Shows error messages and allows executing script commands. help: index: @@ -205,6 +207,8 @@ help: seed: Seed number for the random generator. Using the same seed number gives the same 'random' packs. edit pack type: Double click to edit pack type number of packs: The number of %ss to generate + # Console panel + evaluate: Evaluate the entered script command # Preferences app language: @@ -292,6 +296,7 @@ tool: keywords tab: Keywords stats tab: Statistics random pack tab: Random + console tab: Console # symbol editor store symbol: Store @@ -337,6 +342,7 @@ tooltip: keywords tab: stats tab: random pack tab: Random packs + console tab: new set: New set open set: Open set @@ -562,6 +568,9 @@ button: fixed seed: &Fixed Seed add custom pack: Add &Custom Pack... + # Console panel + evaluate: &Evaluate + # Welcome new set: New set open set: Open set diff --git a/src/cli/cli_main.cpp b/src/cli/cli_main.cpp index b6e95bf5..978d10fe 100644 --- a/src/cli/cli_main.cpp +++ b/src/cli/cli_main.cpp @@ -75,7 +75,7 @@ void CLISetInterface::setExportInfoCwd() { void CLISetInterface::run() { // show welcome logo if (!quiet) showWelcome(); - handle_pending_errors(); + print_pending_errors(); // loop running = true; while (running) { @@ -88,6 +88,7 @@ void CLISetInterface::run() { String command = cli.getLine(); if (command.empty() && !cli.canGetLine()) break; handleCommand(command); + print_pending_errors(); cli.flush(); cli.flushRaw(); } @@ -134,7 +135,7 @@ void CLISetInterface::handleCommand(const String& command) { showUsage(); } else if (before == _(":l") || before == _(":load")) { if (arg.empty()) { - cli.showError(_("Give a filename to open.")); + cli.show_message(MESSAGE_ERROR,_("Give a filename to open.")); } else { setSet(import_set(arg)); } @@ -154,10 +155,10 @@ void CLISetInterface::handleCommand(const String& command) { } } else if (before == _(":c") || before == _(":cd")) { if (arg.empty()) { - cli.showError(_("Give a new working directory.")); + cli.show_message(MESSAGE_ERROR,_("Give a new working directory.")); } else { if (!wxSetWorkingDirectory(arg)) { - cli.showError(_("Can't change working directory to ")+arg); + cli.show_message(MESSAGE_ERROR,_("Can't change working directory to ")+arg); } else { setExportInfoCwd(); } @@ -166,7 +167,7 @@ void CLISetInterface::handleCommand(const String& command) { cli << ei.directory_absolute << ENDL; } else if (before == _(":!")) { if (arg.empty()) { - cli.showError(_("Give a shell command to execute.")); + cli.show_message(MESSAGE_ERROR,_("Give a shell command to execute.")); } else { #ifdef UNICODE #ifdef __WXMSW__ @@ -190,7 +191,7 @@ void CLISetInterface::handleCommand(const String& command) { } #endif } else { - cli.showError(_("Unknown command, type :help for help.")); + cli.show_message(MESSAGE_ERROR,_("Unknown command, type :help for help.")); } } else if (command == _("exit") || command == _("quit")) { cli << _("Use :quit to quit\n"); @@ -201,7 +202,7 @@ void CLISetInterface::handleCommand(const String& command) { vector errors; ScriptP script = parse(command,nullptr,false,errors); if (!errors.empty()) { - FOR_EACH(error,errors) cli.showError(error.what()); + FOR_EACH(error,errors) cli.show_message(MESSAGE_ERROR,error.what()); return; } // execute command @@ -212,7 +213,7 @@ void CLISetInterface::handleCommand(const String& command) { cli << result->toCode() << ENDL; } } catch (const Error& e) { - cli.showError(e.what()); + cli.show_message(MESSAGE_ERROR,e.what()); } } @@ -235,3 +236,11 @@ void CLISetInterface::handleCommand(const String& command) { } } #endif + +void CLISetInterface::print_pending_errors() { + MessageType type; + String msg; + while (get_queued_message(type,msg)) { + cli.show_message(type,msg); + } +} diff --git a/src/cli/cli_main.hpp b/src/cli/cli_main.hpp index 90ae9454..e461cfcd 100644 --- a/src/cli/cli_main.hpp +++ b/src/cli/cli_main.hpp @@ -36,6 +36,7 @@ class CLISetInterface : public SetView { #if USE_SCRIPT_PROFILING void showProfilingStats(const FunctionProfile& parent, int level = 0); #endif + void print_pending_errors(); /// our own context, when no set is loaded Context& getContext(); diff --git a/src/cli/text_io_handler.cpp b/src/cli/text_io_handler.cpp index d1327bb5..f86fc5e1 100644 --- a/src/cli/text_io_handler.cpp +++ b/src/cli/text_io_handler.cpp @@ -35,7 +35,7 @@ TextIOHandler cli; void TextIOHandler::init() { bool have_stderr; - #ifdef __WXMSW__ + #if defined(__WXMSW__) have_console = false; escapes = false; // Detect whether to use console output @@ -51,9 +51,20 @@ void TextIOHandler::init() { } } #else - // always use console on *nix (?) - have_console = true; - have_stderr = true; + // TODO: detect console on linux? + have_console = false; + have_stderr = false; + // Use console mode if one of the cli flags is passed + static const Char* redirect_flags[] = {_("-?"),_("--help"),_("-v"),_("--version"),_("--cli"),_("-c"),_("--export"),_("--create-installer")}; + for (int i = 1 ; i < wxTheApp->argc ; ++i) { + for (int j = 0 ; j < sizeof(redirect_flags)/sizeof(redirect_flags[0]) ; ++j) { + if (String(wxTheApp->argv[i]) == redirect_flags[j]) { + have_console = true; + have_stderr = true; + break; + } + } + } escapes = true; // TODO: detect output redirection #endif // write to standard output @@ -154,18 +165,14 @@ void TextIOHandler::flushRaw() { // ----------------------------------------------------------------------------- : Errors -void TextIOHandler::showError(const String& message) { +void TextIOHandler::show_message(MessageType type, String const& message) { stream = stdout; - *this << RED << _("ERROR: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL; + if (type == MESSAGE_WARNING) { + *this << YELLOW << _("WARNING: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL; + } else { + *this << RED << _("ERROR: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL; + } flush(); stream = stdout; - if (raw_mode) raw_mode_status = max(raw_mode_status, 2); -} - -void TextIOHandler::showWarning(const String& message) { - stream = stdout; - *this << YELLOW << _("WARNING: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL; - flush(); - stream = stdout; - if (raw_mode) raw_mode_status = max(raw_mode_status, 1); + if (raw_mode) raw_mode_status = max(raw_mode_status, type == MESSAGE_WARNING ? 1 : 2); } diff --git a/src/cli/text_io_handler.hpp b/src/cli/text_io_handler.hpp index 961542e7..57196204 100644 --- a/src/cli/text_io_handler.hpp +++ b/src/cli/text_io_handler.hpp @@ -36,10 +36,8 @@ class TextIOHandler { /// Flush output void flush(); - /// Show an error message - void showError(const String& message); - /// Show a warning message - void showWarning(const String& message); + /// Show an error or warning message + void show_message(MessageType type, String const& message); /// Enable raw mode void enableRaw(); diff --git a/src/data/font.cpp b/src/data/font.cpp index 61f00692..b7eae35f 100644 --- a/src/data/font.cpp +++ b/src/data/font.cpp @@ -60,7 +60,7 @@ FontP Font::make(int add_flags, AColor* other_color, double* other_size) const { f->color = Color(128,0,0); } if (add_flags & FONT_CODE_KW) { - f->color = Color(158,0,0); + f->color = Color(158,100,0); f->flags |= FONT_BOLD; } if (add_flags & FONT_SOFT) { diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index 01ba1b04..1539586c 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -215,7 +215,7 @@ void Keyword::prepare(const vector& param_types, bool force) { // throwing an error can mean a set will not be loaded! // instead, simply disable the keyword //throw InternalError(_("Unknown keyword parameter type: ") + type); - handle_error(_("Unknown keyword parameter type: ") + type, true, false); + handle_error(_("Unknown keyword parameter type: ") + type); valid = false; return; } @@ -700,7 +700,7 @@ bool KeywordDatabase::tryExpand(const Keyword& kw, try { reminder = kw.reminder.invoke(ctx)->toString(); } catch (const Error& e) { - handle_error(_ERROR_2_("in keyword reminder", e.what(), kw.keyword), true, false); + handle_error(_ERROR_2_("in keyword reminder", e.what(), kw.keyword)); } ctx.setVariable(_("keyword"), to_script(total)); ctx.setVariable(_("reminder"), to_script(reminder)); diff --git a/src/data/locale.cpp b/src/data/locale.cpp index 7a846fb1..75a02930 100644 --- a/src/data/locale.cpp +++ b/src/data/locale.cpp @@ -86,7 +86,7 @@ SubLocaleP find_wildcard_and_set(map& items, const String& na // ----------------------------------------------------------------------------- : Translation String warn_and_identity(const String& key) { - handle_warning(_("Missing key in locale: ") + key, false); + queue_message(MESSAGE_WARNING, _("Missing key in locale: ") + key); return key; } @@ -253,7 +253,7 @@ void Locale::validate(Version ver) { + _("\n found: ") + ver.toString(); } if (!errors.empty()) { - handle_warning(errors); + queue_message(MESSAGE_WARNING, errors); } } diff --git a/src/data/statistics.cpp b/src/data/statistics.cpp index 0b9d99d1..bda0b2bf 100644 --- a/src/data/statistics.cpp +++ b/src/data/statistics.cpp @@ -121,7 +121,7 @@ void StatsCategory::find_dimensions(const vector& available) { } } if (!dim) { - handle_error(_ERROR_1_("dimension not found",n),false); + handle_error(_ERROR_1_("dimension not found",n)); } else { dimensions.push_back(dim); } diff --git a/src/gui/html_export_window.cpp b/src/gui/html_export_window.cpp index 3b2eb870..99d40802 100644 --- a/src/gui/html_export_window.cpp +++ b/src/gui/html_export_window.cpp @@ -95,7 +95,7 @@ void HtmlExportWindow::onOk(wxCommandEvent&) { void HtmlExportWindow::onTemplateSelect(wxCommandEvent&) { wxBusyCursor wait; ExportTemplateP export_template = list->getSelection(); - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown options->showExport(export_template); settings.gameSettingsFor(*set->game).default_export = export_template->name(); UpdateWindowUI(wxUPDATE_UI_RECURSE); diff --git a/src/gui/new_window.cpp b/src/gui/new_window.cpp index 824d00a1..061c7c97 100644 --- a/src/gui/new_window.cpp +++ b/src/gui/new_window.cpp @@ -61,7 +61,7 @@ NewSetWindow::NewSetWindow(Window* parent) void NewSetWindow::onGameSelect(wxCommandEvent&) { wxBusyCursor wait; GameP game = game_list->getSelection(false); - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown settings.default_game = game->name(); stylesheet_list->showData(game->name() + _("-*")); stylesheet_list->select(settings.gameSettingsFor(*game).default_stylesheet); @@ -76,7 +76,7 @@ void NewSetWindow::onStyleSheetSelect(wxCommandEvent&) { // store this as default selection GameP game = game_list ->getSelection(false); StyleSheetP stylesheet = stylesheet_list->getSelection(false); - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown settings.gameSettingsFor(*game).default_stylesheet = stylesheet->name(); UpdateWindowUI(wxUPDATE_UI_RECURSE); } @@ -113,7 +113,7 @@ void NewSetWindow::onUpdateUI(wxUpdateUIEvent& ev) { void NewSetWindow::onIdle(wxIdleEvent& ev) { // Stuff that must be done in the main thread - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown } BEGIN_EVENT_TABLE(NewSetWindow, wxDialog) @@ -162,7 +162,7 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game, } void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) { - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown UpdateWindowUI(wxUPDATE_UI_RECURSE); } void SelectStyleSheetWindow::onStyleSheetActivate(wxCommandEvent&) { @@ -193,7 +193,7 @@ void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) { void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) { // Stuff that must be done in the main thread - handle_pending_errors(); + //handle_pending_errors(); // errors are ignored until set window is shown } BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog) diff --git a/src/gui/set/console_panel.cpp b/src/gui/set/console_panel.cpp new file mode 100644 index 00000000..9f088162 --- /dev/null +++ b/src/gui/set/console_panel.cpp @@ -0,0 +1,401 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2010 Twan van Laarhoven and Sean Hunt | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_POINTER_TYPE(ConsoleMessage); +DECLARE_TYPEOF_COLLECTION(ScriptParseError); +DECLARE_TYPEOF_COLLECTION(ConsoleMessageP); + +// ----------------------------------------------------------------------------- : MessageControl + +class ConsoleMessage : public IntrusivePtrBase { + public: + MessageType type; + String text; // string message + Bitmap bitmap; // image message instead of string + ScriptValueP value; // other valued message (images? cards?) + // location of error messages + String source_file; + int line_number; + // layout + bool joined_to_previous; + int top; + int height; + int bottom() const { return top+height; } + + ConsoleMessage(MessageType type, String const& text = _("")) + : type(type), text(text), line_number(-1), joined_to_previous(false), top(-1), height(-1) + {} +}; + +class MessageCtrl : public wxScrolledWindow { + public: + MessageCtrl(wxWindow* parent, int id) + : wxScrolledWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME) + { + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + SetScrollRate(0, 1); + EnableScrolling(false,true); + // icons + BOOST_STATIC_ASSERT(MESSAGE_TYPE_MAX == 6); + icons[MESSAGE_INPUT] = wxBitmap(load_resource_image(_("message_input"))); + icons[MESSAGE_OUTPUT] = wxBitmap(); + icons[MESSAGE_INFO] = wxBitmap(load_resource_image(_("message_information"))); + icons[MESSAGE_WARNING] = wxBitmap(load_resource_image(_("message_warning"))); + icons[MESSAGE_ERROR] = wxBitmap(load_resource_image(_("message_error"))); + icons[MESSAGE_FATAL_ERROR] = icons[MESSAGE_ERROR]; + // color + colors[MESSAGE_INPUT] = wxColour(0,80,0); + colors[MESSAGE_OUTPUT] = wxColour(255,255,255); + colors[MESSAGE_INFO] = wxColour(0,0,255); + colors[MESSAGE_WARNING] = wxColour(255,255,0); + colors[MESSAGE_ERROR] = colors[MESSAGE_FATAL_ERROR] = wxColour(255,0,0); + } + + void add_message(ConsoleMessageP const& msg) { + messages.push_back(msg); + layout_all(messages.size() - 1); + // refresh + ensure_visible(*messages.back()); + Refresh(false); + } + void add_message(MessageType type, String const& text) { + add_message(intrusive(new ConsoleMessage(type,text))); + } + + private: + DECLARE_EVENT_TABLE(); + + // --------------------------------------------------- : Data + + // the messages + vector messages; + size_t selection; + wxBitmap icons[MESSAGE_TYPE_MAX]; + wxColour colors[MESSAGE_TYPE_MAX]; + + // --------------------------------------------------- : Events + + void onLeftDown(wxMouseEvent& ev) { + int ystart; GetViewStart(nullptr,&ystart); + selection = find_point(ystart + ev.GetY()); + if (selection < messages.size()) { + ensure_visible(*messages[selection]); + } + Refresh(false); + } + + int find_point(int y) { + // TODO: could do a binary search here + for (size_t i = 0 ; i < messages.size() ; ++i) { + if (y >= messages[i]->top && y < messages[i]->bottom()) return i; + } + return (size_t)-1; + } + + void ensure_visible(ConsoleMessage const& msg) { + int ystart; GetViewStart(nullptr,&ystart); + int height = GetClientSize().y; + if (msg.top < ystart) { + Scroll(0, msg.top); + } else if (msg.bottom() > ystart + height) { + Scroll(0, msg.bottom() - height); + } + } + + // --------------------------------------------------- : Drawing + + void onPaint(wxPaintEvent& ev) { + wxAutoBufferedPaintDC dc(this); + PrepareDC(dc); + draw(dc); + } + void draw(wxDC& dc) const { + clearDC(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + dc.SetFont(*wxNORMAL_FONT); + FOR_EACH_CONST(msg, messages) { + draw(dc, *msg); + } + if (messages.empty()) { + // Say something about no messages? + } + } + + void draw(wxDC& dc, ConsoleMessage const& msg) const { + int left = 0; + int top = msg.top; + int width = GetClientSize().x; + wxColour color = colors[msg.type]; + wxColour bg, fg; + if (selection < messages.size() && messages[selection].get() == &msg) { + bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } else { + bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + } + + // draw background + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(lerp(bg,color, 0.05)); + dc.DrawRectangle(left,top,width,msg.height); + + // draw icon + if (icons[msg.type].Ok()) { + dc.DrawBitmap(icons[msg.type], left + ICON_PADDING,top + ICON_PADDING); + } + + // draw text + dc.SetTextForeground(fg); + int text_left = TEXT_PADDING_LEFT; + int text_top = top + TEXT_PADDING_TOP; + // find line breaks in the text + String::const_iterator begin = msg.text.begin(); + String::const_iterator it = begin; + while (it != msg.text.end()) { + if (*it == _('\n')) { + // break here + dc.DrawText(String(begin,it), text_left, text_top); + begin = it = it + 1; + text_top += dc.GetCharHeight() + TEXT_LINE_SPACING; + } else { + it++; + } + } + if (begin != msg.text.end()) { + dc.DrawText(String(begin,it), text_left, text_top); + text_top += dc.GetCharHeight() + TEXT_LINE_SPACING; + } + + // draw bitmap + if (msg.bitmap.Ok()) { + dc.DrawBitmap(msg.bitmap, text_left, text_top); + text_top += msg.bitmap.GetHeight(); + } + + // draw line below item + dc.SetPen(lerp(bg,fg, 0.3)); + dc.DrawLine(left, top+msg.height, left+width, top+msg.height); + } + + int item_height(wxDC& dc, ConsoleMessage const& msg) const { + // text height + int text_height = 0; + // find line breaks in the text + String::const_iterator begin = msg.text.begin(); + String::const_iterator it = begin; + while (it != msg.text.end()) { + if (*it == _('\n')) { + // break here + begin = it = it + 1; + text_height += dc.GetCharHeight() + TEXT_LINE_SPACING; + } else { + it++; + } + // TODO: break long lines + } + if (begin != msg.text.end()) { + text_height += dc.GetCharHeight() + TEXT_LINE_SPACING; + } + + // height of bitmap + int bitmap_height = msg.bitmap.Ok() ? msg.bitmap.GetHeight() : 0; + + return max(MIN_ITEM_HEIGHT, TEXT_PADDING_TOP + TEXT_PADDING_BOTTOM + text_height + bitmap_height) + LIST_SPACING; + } + + // --------------------------------------------------- : Layout + + static const int LIST_SPACING = 1; + static const int ICON_PADDING = 3; + static const int TEXT_PADDING_LEFT = ICON_PADDING + 16 + 4; + static const int TEXT_PADDING_RIGHT = 4; + static const int TEXT_PADDING_TOP = 4; + static const int TEXT_PADDING_BOTTOM = 2; + static const int TEXT_LINE_SPACING = 1; + static const int MIN_ITEM_HEIGHT = 16 + 2*ICON_PADDING; + + /// Layout all messages, starting from number start + /// layout = determine their height + void layout_all(size_t start = 0) { + // scratch dc, for finding text sizes + wxMemoryDC dc; + wxBitmap bmp(1,1); + dc.SelectObject(bmp); + dc.SetFont(*wxNORMAL_FONT); + + for (size_t i = start ; i < messages.size() ; ++i) { + // layout a single item + ConsoleMessage& msg = *messages[i]; + msg.top = start == 0 ? 0 : messages[i-1]->bottom() + LIST_SPACING; + if (i > 0 && msg.joined_to_previous) msg.top -= LIST_SPACING; + // text size + msg.height = item_height(dc, msg); + } + + // set size of the control + if (messages.empty()) { + SetVirtualSize(-1, 0); + } else { + int height = messages.back()->bottom(); + SetVirtualSize(-1, height); + } + } + + // --------------------------------------------------- : Layout + +}; + +BEGIN_EVENT_TABLE(MessageCtrl,wxScrolledWindow) + EVT_PAINT(MessageCtrl::onPaint) + EVT_LEFT_DOWN(MessageCtrl::onLeftDown) +END_EVENT_TABLE() + +// ----------------------------------------------------------------------------- : ConsolePanel + +ConsolePanel::ConsolePanel(Window* parent, int id) + : SetWindowPanel(parent, id) +{ + // init controls + splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + messages = new MessageCtrl(splitter, wxID_ANY); + entry_panel = new Panel(splitter, wxID_ANY); + entry = new wxTextCtrl(entry_panel, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + wxButton* evaluate = new wxButton(entry_panel, ID_EVALUATE, _BUTTON_("evaluate")); + // init sizer for entry_panel + wxSizer* se = new wxBoxSizer(wxHORIZONTAL); + se->Add(entry, 1, wxEXPAND, 2); + se->Add(evaluate, 0, wxEXPAND | wxLEFT, 2); + entry_panel->SetSizer(se); + // init splitter + splitter->SetMinimumPaneSize(40); + splitter->SetSashGravity(1.0); + splitter->SplitHorizontally(messages, entry_panel, -50); + // init sizer + wxSizer* s = new wxBoxSizer(wxVERTICAL); + s->Add(splitter, 1, wxEXPAND); + s->SetSizeHints(this); + SetSizer(s); +} + +void ConsolePanel::onChangeSet() { + // TODO +} + +// ----------------------------------------------------------------------------- : UI + +void ConsolePanel::initUI(wxToolBar* tb, wxMenuBar* mb) { + // Menus + // focus on entry + entry->SetFocus(); +} + +void ConsolePanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) { + // Toolbar + // Menus +} + +void ConsolePanel::onUpdateUI(wxUpdateUIEvent& ev) { + if (ev.GetId() == ID_EVALUATE) { + ev.Enable(!entry->GetValue().empty()); + } +} + +void ConsolePanel::onEnter(wxCommandEvent& ev) { + onCommand(ID_EVALUATE); +} +void ConsolePanel::onCommand(int id) { + if (id == ID_EVALUATE) { + exec(entry->GetValue()); + entry->SetValue(_("")); + } +} + +void ConsolePanel::onIdle(wxIdleEvent&) { + get_pending_errors(); +} + +void ConsolePanel::get_pending_errors() { + // add pending messages + MessageType type; + String msg; + while (get_queued_message(type,msg)) { + messages->add_message(type,msg); + } + // If this panel doesn't have the focus, then highlight it somehow + +} + +void ConsolePanel::exec(String const& command) { + if (command.empty()) return; + // add input message + messages->add_message(MESSAGE_INPUT, command); + try { + // parse command + vector errors; + ScriptP script = parse(command,nullptr,false,errors); + if (!errors.empty()) { + FOR_EACH(error,errors) { + // TODO: also squiglify the input? + messages->add_message(MESSAGE_ERROR,error.what()); + } + return; + } + // execute command + //WITH_DYNAMIC_ARG(export_info, &ei); // TODO: allow image export + Context& ctx = set->getContext(); + ScriptValueP result = ctx.eval(*script,false); + get_pending_errors(); + // show result + ConsoleMessageP message = intrusive(new ConsoleMessage(MESSAGE_OUTPUT)); + message->joined_to_previous = true; + message->value = result; + // type of result + ScriptType type = result->type(); + if (type == SCRIPT_IMAGE) { + GeneratedImage::Options options(0,0, set->stylesheet.get(), set.get()); + wxImage image = result->toImage(result)->generate(options); + message->bitmap = wxBitmap(image); + } else if (type == SCRIPT_COLOR) { + message->text = result->toCode(); + AColor color = (AColor)*result; + wxImage image(30,20); + fill_image(image,color); + set_alpha(image, color.alpha); + message->bitmap = wxBitmap(image); + } else { + message->text = result->toCode(); + } + messages->add_message(message); + } catch (ScriptError const& e) { + messages->add_message(MESSAGE_ERROR, e.what()); + } +} + +BEGIN_EVENT_TABLE(ConsolePanel, wxPanel) + EVT_TEXT_ENTER(wxID_ANY,ConsolePanel::onEnter) + EVT_IDLE(ConsolePanel::onIdle) +END_EVENT_TABLE () + +// ----------------------------------------------------------------------------- : Clipboard +/* +bool ConsolePanel::canCut() const { return entry->canCut(); } +bool ConsolePanel::canCopy() const { return entry->canCopy(); } +bool ConsolePanel::canPaste() const { return entry->canPaste(); } +void ConsolePanel::doCut() { entry->doCut(); } +void ConsolePanel::doCopy() { entry->doCopy(); } +void ConsolePanel::doPaste() { entry->doPaste(); } +*/ diff --git a/src/gui/set/console_panel.hpp b/src/gui/set/console_panel.hpp new file mode 100644 index 00000000..807186ea --- /dev/null +++ b/src/gui/set/console_panel.hpp @@ -0,0 +1,61 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2010 Twan van Laarhoven and Sean Hunt | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +#ifndef HEADER_GUI_SET_CONSOLE_PANEL +#define HEADER_GUI_SET_CONSOLE_PANEL + +// ----------------------------------------------------------------------------- : Includes + +#include +#include + +class wxSplitterWindow; +class MessageCtrl; +class TextCtrl; + +// ----------------------------------------------------------------------------- : ConsolePanel + +class ConsolePanel : public SetWindowPanel { + public: + ConsolePanel(Window* parent, int id); + + // --------------------------------------------------- : UI + + void onIdle(wxIdleEvent&); + void onEnter(wxCommandEvent&); + virtual void initUI (wxToolBar* tb, wxMenuBar* mb); + virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb); + virtual void onUpdateUI(wxUpdateUIEvent&); + virtual void onCommand(int id); + + // --------------------------------------------------- : Clipboard + + /* + virtual bool canCut() const; + virtual bool canCopy() const; + virtual bool canPaste() const; + virtual void doCut(); + virtual void doCopy(); + virtual void doPaste(); + */ + + protected: + virtual void onChangeSet(); + + private: + DECLARE_EVENT_TABLE(); + + wxSplitterWindow* splitter; + MessageCtrl* messages; + wxPanel* entry_panel; + wxTextCtrl* entry; + + void get_pending_errors(); + void exec(String const& code); +}; + +// ----------------------------------------------------------------------------- : EOF +#endif diff --git a/src/gui/set/window.cpp b/src/gui/set/window.cpp index 9a0761e4..1412294d 100644 --- a/src/gui/set/window.cpp +++ b/src/gui/set/window.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -145,11 +146,12 @@ SetWindow::SetWindow(Window* parent, const SetP& set) // panels addPanel(menuWindow, tabBar, new CardsPanel (this, wxID_ANY), 0, _("window_cards"), _("cards tab")); - addPanel(menuWindow, tabBar, new SetInfoPanel (this, wxID_ANY), 1, _("window_set_info"), _("set info tab")); - addPanel(menuWindow, tabBar, new StylePanel (this, wxID_ANY), 2, _("window_style"), _("style tab")); + addPanel(menuWindow, tabBar, new StylePanel (this, wxID_ANY), 1, _("window_style"), _("style tab")); + addPanel(menuWindow, tabBar, new SetInfoPanel (this, wxID_ANY), 2, _("window_set_info"), _("set info tab")); addPanel(menuWindow, tabBar, new KeywordsPanel (this, wxID_ANY), 3, _("window_keywords"), _("keywords tab")); addPanel(menuWindow, tabBar, new StatsPanel (this, wxID_ANY), 4, _("window_statistics"), _("stats tab")); addPanel(menuWindow, tabBar, new RandomPackPanel(this, wxID_ANY), 5, _("window_random_pack"),_("random pack tab")); + addPanel(menuWindow, tabBar, new ConsolePanel (this, wxID_ANY), 6, _("window_console"), _("console tab")); selectPanel(ID_WINDOW_CARDS); // select cards panel // loose ends @@ -778,7 +780,6 @@ void SetWindow::onChildMenu(wxCommandEvent& ev) { void SetWindow::onIdle(wxIdleEvent& ev) { // Stuff that must be done in the main thread - handle_pending_errors(); show_update_dialog(this); } diff --git a/src/gui/thumbnail_thread.cpp b/src/gui/thumbnail_thread.cpp index 06a26687..c93dca62 100644 --- a/src/gui/thumbnail_thread.cpp +++ b/src/gui/thumbnail_thread.cpp @@ -77,7 +77,7 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() { try { img = current->generate(); } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } catch (...) { } // store in cache @@ -150,7 +150,7 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) { try { img = request->generate(); } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } catch (...) { } // store in cache diff --git a/src/gui/value/choice.cpp b/src/gui/value/choice.cpp index 7c472be3..19974585 100644 --- a/src/gui/value/choice.cpp +++ b/src/gui/value/choice.cpp @@ -186,7 +186,7 @@ void DropDownChoiceListBase::generateThumbnailImages() { GeneratedImageP img = image_from_script(style().image.getValidScriptP()->eval(ctx)); style().choice_images.insert(make_pair(name, ScriptableImage(img))); } catch (const Error& e) { - handle_error(Error(e.what() + _("\n while generating choice images for drop down list")),true,false); + handle_error(Error(e.what() + _("\n while generating choice images for drop down list"))); } } } diff --git a/src/gui/welcome_window.cpp b/src/gui/welcome_window.cpp index 90f78088..bf31eb04 100644 --- a/src/gui/welcome_window.cpp +++ b/src/gui/welcome_window.cpp @@ -27,7 +27,9 @@ WelcomeWindow::WelcomeWindow() : Frame(nullptr, wxID_ANY, _TITLE_("magic set editor"), wxDefaultPosition, wxSize(520,380), wxDEFAULT_DIALOG_STYLE | wxTAB_TRAVERSAL | wxCLIP_CHILDREN ) , logo (load_resource_image(_("about"))) + #if USE_BETA_LOGO , logo2(load_resource_image(_("two_beta"))) + #endif { SetIcon(load_resource_icon(_("app"))); @@ -86,7 +88,9 @@ void WelcomeWindow::draw(DC& dc) { dc.DrawRectangle(0, 0, ws.GetWidth(), ws.GetHeight()); // draw logo dc.DrawBitmap(logo, (ws.GetWidth() - logo.GetWidth()) / 2, 5); - dc.DrawBitmap(logo2, ws.GetWidth() - logo2.GetWidth(), ws.GetHeight() - logo2.GetHeight()); + #if USE_BETA_LOGO + dc.DrawBitmap(logo2, ws.GetWidth() - logo2.GetWidth(), ws.GetHeight() - logo2.GetHeight()); + #endif // draw version number dc.SetFont(wxFont(8, wxSWISS, wxNORMAL, wxNORMAL, false, _("Arial"))); dc.SetTextForeground(Color(0,126,176)); diff --git a/src/mse.vcproj b/src/mse.vcproj index 4780ef91..ed2e259d 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -538,6 +538,14 @@ RelativePath=".\gui\set\cards_panel.hpp" > + + + + diff --git a/src/render/card/viewer.cpp b/src/render/card/viewer.cpp index f83db623..f8f85131 100644 --- a/src/render/card/viewer.cpp +++ b/src/render/card/viewer.cpp @@ -53,7 +53,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) { changed_content_properties = true; } } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } } } @@ -67,7 +67,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) { try { drawViewer(dc, *v); } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } } } @@ -91,7 +91,7 @@ void DataViewer::updateStyles(bool only_content_dependent) { } } } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } } diff --git a/src/render/value/image.cpp b/src/render/value/image.cpp index 75cb2427..b2752849 100644 --- a/src/render/value/image.cpp +++ b/src/render/value/image.cpp @@ -36,9 +36,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { if (image.LoadFile(*image_file)) { image.Rescale(w, h); } - } catch (Error e) { - handle_error(e, false, false); // don't handle now, we are in onPaint - } + } CATCH_ALL_ERRORS(false); } // nice placeholder if (!image.Ok() && style().default_image.isReady()) { diff --git a/src/resource/common/expected_locale_keys b/src/resource/common/expected_locale_keys index 9fe509b1..5bdc83d1 100644 --- a/src/resource/common/expected_locale_keys +++ b/src/resource/common/expected_locale_keys @@ -1,623 +1,627 @@ -# This file contains the keys expected to be in MSE locales -# It was automatically generated by tools/locale/locale.pl -# Generated on Sun Jan 16 14:30:12 2011 - -action: - add control point: 0 - add item: 1 - add symmetry: 0 - auto replace: 0 - backspace: 0 - change: 1 - change combine mode: 0 - change shape name: 0 - change symmetry copies: 0 - change symmetry type: 0 - convert to curve: 0 - convert to line: 0 - correct: 0 - cut: 0 - delete: 0 - delete point: 0 - delete points: 0 - duplicate: 1 - enter: 0 - group parts: 0 - insert symbol: 0 - lock point: 0 - move: 1 - move curve: 0 - move handle: 0 - move symmetry center: 0 - move symmetry handle: 0 - paste: 0 - remove item: 1 - reorder parts: 0 - rotate: 1 - scale: 1 - shear: 1 - soft line break: 0 - typing: 0 - ungroup parts: 0 -button: - add custom pack: 0 - add item: 0 - always: 0 - browse: 0 - check now: 0 - check updates: 0 - close: 0 - defaults: 0 - don't install package: 0 - edit symbol: 0 - enabled: 0 - export custom cards selection: 0 - export entire set: 0 - export generated packs: 0 - fixed seed: 0 - generate pack: 0 - hide: 0 - high quality: 0 - if internet connection exists: 0 - insert parameter: 0 - install group: optional, 0 - install package: 0 - keep old: 0 - keep package: 0 - last opened set: 0 - move down: 0 - move up: 0 - never: 0 - new set: 0 - number: 0 - number overwrite: 0 - open set: 0 - open sets in new window: 0 - overwrite: 0 - random seed: 0 - refer parameter: 0 - reinstall package: 0 - remove group: optional, 0 - remove item: 0 - remove package: 0 - select: optional, 0 - select all: 0 - select cards: 0 - select none: 0 - show: 0 - show editing hints: 0 - show lines: 0 - spellcheck enabled: 0 - symbol gallery: optional, 0 - upgrade group: optional, 0 - upgrade package: 0 - use auto replace: 0 - use custom styling options: 0 - use for all cards: 0 - whole word: 0 - zoom export: 0 -error: - aborting parsing: 0 - can't convert: 2 - can't convert value: 3 - can't download installer: 2 - cannot create file: 1 - change packages successful: 1 - checking updates failed: 0 - coordinates for blending overlap: 0 - dependency not given: 4 - dimension not found: 1 - downloading updates: 0 - expected key: 1 - file not found: 2 - file not found package like: 2 - file parse error: 2 - has no member: 2 - has no member value: 2 - images used for blending must have the same size: 0 - in function: 2 - in keyword reminder: 2 - in parameter: 2 - install packages successful: 1 - installing updates: 0 - newer version: 2 - no game specified: 1 - no stylesheet specified for the set: 0 - no updates: 0 - pack type duplicate name: 1 - pack type not found: 1 - package not found: 1 - package out of date: 3 - package too new: 4 - remove packages: 1 - remove packages modified: 2 - remove packages successful: 1 - stylesheet and set refer to different game: 0 - successful install: optional, 2 - unable to open output file: 0 - unable to store file: 0 - unrecognized value: 2 - unsupported field type: 1 - unsupported fill type: 1 - unsupported format: 1 - word list type not found: 1 -help: - about: 0 - add card: 0 - add cards: 0 - add keyword: 0 - add symmetry: 0 - add to dictionary: optional, 0 - app language: 0 - auto replace: 0 - bar: 0 - basic shapes: 0 - bold: 0 - border: 0 - card list columns: 0 - cards tab: 0 - check updates: 0 - click to select shape: 0 - close symbol editor: 0 - collapse notes: 0 - copies: 0 - copy: 0 - copy card: 0 - copy keyword: 0 - curve segment: 0 - cut: 0 - cut card: 0 - cut keyword: 0 - difference: 0 - drag to draw shape: 0 - drag to move curve: 0 - drag to move line: 0 - drag to move point: 0 - drag to resize: 1 - drag to rotate: 1 - drag to shear: 1 - draw ellipse: 0 - draw polygon: 0 - draw rectangle: 0 - draw star: 0 - duplicate: 0 - edit pack type: 0 - ellipse: 0 - exit: 0 - expand notes: 0 - export: 0 - export apprentice: 0 - export html: 0 - export image: 0 - export images: 0 - export mws: 0 - filename format: 0 - find: 0 - find next: 0 - fixed seed: 0 - free point: 0 - grid: 0 - group: 0 - index: 0 - intersect: 0 - italic: 0 - keywords tab: 0 - last opened set: 1 - line segment: 0 - merge: 0 - new set: 0 - new symbol: 0 - new window: 0 - next card: 0 - next keyword: 0 - no spelling suggestions: 0 - number of packs: 1 - open set: 0 - open symbol: 0 - orientation: 0 - overlap: 0 - paint: 0 - paste: 0 - paste card: 0 - paste keyword: 0 - pie: 0 - points: 0 - polygon: 0 - preferences: 0 - previous card: 0 - previous keyword: 0 - print: 0 - print preview: 0 - random pack tab: 0 - random seed: 0 - rectangle: 0 - redo: 0 - reflection: 0 - reload data: 0 - reminder text: 0 - remove card: 0 - remove keyword: 0 - remove symmetry: 0 - replace: 0 - rotate: 0 - rotate 0: 0 - rotate 180: 0 - rotate 270: 0 - rotate 90: 0 - rotate card: 0 - rotation: 0 - save set: 0 - save set as: 0 - save symbol: 0 - save symbol as: 0 - scatter: 0 - scatter pie: 0 - seed: 0 - select: 0 - set code: 0 - set info tab: 0 - show profiler: 0 - sides: 0 - smooth point: 0 - snap: 0 - stack: 0 - star: 0 - stats tab: 0 - store symbol: 0 - style tab: 0 - subtract: 0 - symbols: 0 - symmetric point: 0 - symmetry: 0 - undo: 0 - ungroup: 0 - website: 0 - welcome: 0 - zoom export: 0 -label: - app language: 0 - apprentice: 0 - apprentice exe: 0 - apprentice export cancelled: 0 - auto match: 0 - auto replace: 0 - card display: 0 - card notes: 0 - check at startup: 0 - checking requires internet: 0 - columns: 0 - custom size: 0 - export filenames: 0 - external programs: 0 - filename conflicts: 0 - filename format: 0 - filename is ignored: 0 - filter: 0 - fix aspect ratio: 0 - force to fit: 0 - game type: 0 - html export options: 0 - html template: 0 - install package: 0 - installable version: 0 - installed version: 0 - installer size: optional, 0 - installer status: optional, 0 - keyword: 0 - language: 0 - magic set editor package: optional, 0 - match: 0 - mode: 0 - no version: 0 - original: 0 - original size: 0 - pack name: 0 - pack selection: 0 - pack totals: 0 - package action: 0 - package conflicts: 0 - package installable: 0 - package installed: 0 - package modified: 0 - package name: 0 - package status: 0 - package updates: 0 - percent of normal: 0 - reinstall package: 0 - reminder: 0 - remove package: 0 - result: 0 - rules: 0 - save changes: 1 - search cards: 0 - search keywords: 0 - seed: 0 - select cards: 0 - select cards print: optional, 0 - select columns: 0 - selected card count: 1 - selection: 0 - selection height: 0 - selection left: 0 - selection top: 0 - selection width: 0 - set code: 0 - sharpen filter: 0 - sides: optional, 0 - size: 0 - size to fit: 0 - standard keyword: 1 - style type: 0 - stylesheet not found: 1 - styling options: 0 - total cards: 0 - upgrade package: 0 - uses: 0 - windows: 0 - zoom: 0 - zoom %: 0 - zoom amount: 0 - zoom amount x: 0 - zoom amount y: 0 -menu: - about: 0 - add card: 0 - add cards: 0 - add keyword: 0 - add to dictionary: optional, 0 - auto replace: 0 - bar: 0 - basic shapes: 0 - bold: 0 - card list columns: 0 - cards: 0 - cards tab: 0 - check updates: 0 - close symbol editor: 0 - copy: 0 - cut: 0 - duplicate: 0 - edit: 0 - exit: 0 - export: 0 - export apprentice: 0 - export html: 0 - export image: 0 - export images: 0 - export mws: 0 - file: 0 - find: 0 - find next: 0 - format: 0 - graph: 0 - group: 0 - help: 0 - index: 0 - insert symbol: 0 - italic: 0 - keywords: 0 - keywords tab: 0 - new set: 0 - new symbol: 0 - new window: 0 - next card: 0 - next keyword: 0 - no spelling suggestions: 0 - open set: 0 - open symbol: 0 - orientation: 0 - paint: 0 - paste: 0 - pie: 0 - points: 0 - preferences: 0 - previous card: 0 - previous keyword: 0 - print: 0 - print preview: 0 - random pack tab: 0 - redo: 1 - reload data: 0 - reminder text: 0 - remove card: 0 - remove keyword: 0 - replace: 0 - rotate: 0 - rotate 0: 0 - rotate 180: 0 - rotate 270: 0 - rotate 90: 0 - save set: 0 - save set as: 0 - save symbol: 0 - save symbol as: 0 - scatter: 0 - scatter pie: 0 - select: 0 - set info tab: 0 - show profiler: 0 - stack: 0 - stats tab: 0 - store symbol: 0 - style tab: 0 - symbols: 0 - symmetry: 0 - tool: 0 - undo: 1 - ungroup: 0 - website: 0 - window: 0 -title: - %s - magic set editor: 1 - about: 0 - auto replaces: 0 - cannot create file: 0 - custom pack: 0 - directories: 0 - display: 0 - export cancelled: 0 - export html: 0 - export images: 0 - global: 0 - installing updates: 0 - locate apprentice: 0 - magic set editor: 0 - new set: 0 - open set: 0 - packages window: 0 - preferences: 0 - print preview: 0 - save changes: 0 - save html: 0 - save image: 0 - save set: 0 - select cards: 0 - select cards export: 0 - select columns: 0 - select stylesheet: 0 - slice image: 0 - symbol editor: 0 - untitled: 0 - update check: 0 - updates: 0 - updates available: 0 -tool: - add symmetry: 0 - basic shapes: 0 - border: 0 - cards tab: 0 - curve segment: 0 - difference: 0 - ellipse: 0 - free point: 0 - grid: 0 - intersect: 0 - keywords tab: 0 - line segment: 0 - merge: 0 - overlap: 0 - paint: optional, 0 - points: 0 - polygon: 0 - random pack tab: 0 - rectangle: 0 - redo: 0 - reflection: 0 - remove symmetry: 0 - rotate: 0 - rotation: 0 - select: 0 - set info tab: 0 - smooth point: 0 - snap: 0 - star: 0 - stats tab: 0 - store symbol: 0 - style tab: 0 - subtract: 0 - symmetric point: 0 - symmetry: 0 - undo: 0 -tooltip: - add card: 0 - add keyword: 0 - add symmetry: 0 - bar: 0 - basic shapes: 0 - bold: 0 - border: 0 - cards tab: 0 - copy: 0 - curve segment: 0 - cut: 0 - difference: 0 - ellipse: 0 - export: 0 - free point: 0 - grid: 0 - intersect: 0 - italic: 0 - keywords tab: 0 - line segment: 0 - merge: 0 - new set: 0 - open set: 0 - overlap: 0 - paint: optional, 0 - paste: 0 - pie: 0 - points: 0 - polygon: 0 - random pack tab: 0 - rectangle: 0 - redo: 1 - reflection: 0 - reminder text: 0 - remove card: 0 - remove keyword: 0 - remove symmetry: 0 - rotate: 0 - rotate card: 0 - rotation: 0 - save set: 0 - scatter: 0 - scatter pie: 0 - select: 0 - set info tab: 0 - smooth point: 0 - snap: 0 - stack: 0 - star: 0 - stats tab: 0 - store symbol: 0 - style tab: 0 - subtract: 0 - symbols: 0 - symmetric point: 0 - symmetry: 0 - undo: 1 -type: - boolean: 0 - card: 0 - cards: 0 - circle: 0 - collection: 0 - collection of: 1 - color: 0 - date: 0 - double: 0 - ellipse: 0 - export template: 0 - field: 0 - function: 0 - game: 0 - group: 0 - hexagon: 0 - image: 0 - integer: 0 - keyword: 0 - keywords: 0 - locale: optional, 0 - nil: 0 - object: 0 - pack: 0 - package: optional, 0 - pentagon: 0 - point: 0 - points: 0 - polygon: 0 - rectangle: 0 - reflection: 0 - rhombus: 0 - rotation: 0 - set: 0 - shape: 0 - shapes: 0 - square: 0 - star: 0 - string: 0 - style: 0 - stylesheet: 0 - symbol: 0 - triangle: 0 - value: 0 +# This file contains the keys expected to be in MSE locales +# It was automatically generated by tools/locale/locale.pl +# Generated on Thu Jan 20 21:48:58 2011 + +action: + add control point: 0 + add item: 1 + add symmetry: 0 + auto replace: 0 + backspace: 0 + change: 1 + change combine mode: 0 + change shape name: 0 + change symmetry copies: 0 + change symmetry type: 0 + convert to curve: 0 + convert to line: 0 + correct: 0 + cut: 0 + delete: 0 + delete point: 0 + delete points: 0 + duplicate: 1 + enter: 0 + group parts: 0 + insert symbol: 0 + lock point: 0 + move: 1 + move curve: 0 + move handle: 0 + move symmetry center: 0 + move symmetry handle: 0 + paste: 0 + remove item: 1 + reorder parts: 0 + rotate: 1 + scale: 1 + shear: 1 + soft line break: 0 + typing: 0 + ungroup parts: 0 +button: + add custom pack: 0 + add item: 0 + always: 0 + browse: 0 + check now: 0 + check updates: 0 + close: 0 + defaults: 0 + don't install package: 0 + edit symbol: 0 + enabled: 0 + export custom cards selection: 0 + export entire set: 0 + export generated packs: 0 + fixed seed: 0 + generate pack: 0 + hide: 0 + high quality: 0 + if internet connection exists: 0 + insert parameter: 0 + install group: optional, 0 + install package: 0 + keep old: 0 + keep package: 0 + last opened set: 0 + move down: 0 + move up: 0 + never: 0 + new set: 0 + number: 0 + number overwrite: 0 + open set: 0 + open sets in new window: 0 + overwrite: 0 + random seed: 0 + refer parameter: 0 + reinstall package: 0 + remove group: optional, 0 + remove item: 0 + remove package: 0 + select: optional, 0 + select all: 0 + select cards: 0 + select none: 0 + show: 0 + show editing hints: 0 + show lines: 0 + spellcheck enabled: 0 + symbol gallery: optional, 0 + upgrade group: optional, 0 + upgrade package: 0 + use auto replace: 0 + use custom styling options: 0 + use for all cards: 0 + whole word: 0 + zoom export: 0 +error: + aborting parsing: 0 + can't convert: 2 + can't convert value: 3 + can't download installer: 2 + cannot create file: 1 + change packages successful: 1 + checking updates failed: 0 + coordinates for blending overlap: 0 + dependency not given: 4 + dimension not found: 1 + downloading updates: 0 + expected key: 1 + file not found: 2 + file not found package like: 2 + file parse error: 2 + has no member: 2 + has no member value: 2 + images used for blending must have the same size: 0 + in function: 2 + in keyword reminder: 2 + in parameter: 2 + install packages successful: 1 + installing updates: 0 + newer version: 2 + no game specified: 1 + no stylesheet specified for the set: 0 + no updates: 0 + pack type duplicate name: 1 + pack type not found: 1 + package not found: 1 + package out of date: 3 + package too new: 4 + remove packages: 1 + remove packages modified: 2 + remove packages successful: 1 + stylesheet and set refer to different game: 0 + successful install: optional, 2 + unable to open output file: 0 + unable to store file: 0 + unrecognized value: 2 + unsupported field type: 1 + unsupported fill type: 1 + unsupported format: 1 + word list type not found: 1 +help: + about: 0 + add card: 0 + add cards: 0 + add keyword: 0 + add symmetry: 0 + add to dictionary: optional, 0 + app language: 0 + auto replace: 0 + bar: 0 + basic shapes: 0 + bold: 0 + border: 0 + card list columns: 0 + cards tab: 0 + check updates: 0 + click to select shape: 0 + close symbol editor: 0 + collapse notes: 0 + console tab: 0 + copies: 0 + copy: 0 + copy card: 0 + copy keyword: 0 + curve segment: 0 + cut: 0 + cut card: 0 + cut keyword: 0 + difference: 0 + drag to draw shape: 0 + drag to move curve: 0 + drag to move line: 0 + drag to move point: 0 + drag to resize: 1 + drag to rotate: 1 + drag to shear: 1 + draw ellipse: 0 + draw polygon: 0 + draw rectangle: 0 + draw star: 0 + duplicate: 0 + edit pack type: 0 + ellipse: 0 + exit: 0 + expand notes: 0 + export: 0 + export apprentice: 0 + export html: 0 + export image: 0 + export images: 0 + export mws: 0 + filename format: 0 + find: 0 + find next: 0 + fixed seed: 0 + free point: 0 + grid: 0 + group: 0 + index: 0 + intersect: 0 + italic: 0 + keywords tab: 0 + last opened set: 1 + line segment: 0 + merge: 0 + new set: 0 + new symbol: 0 + new window: 0 + next card: 0 + next keyword: 0 + no spelling suggestions: 0 + number of packs: 1 + open set: 0 + open symbol: 0 + orientation: 0 + overlap: 0 + paint: 0 + paste: 0 + paste card: 0 + paste keyword: 0 + pie: 0 + points: 0 + polygon: 0 + preferences: 0 + previous card: 0 + previous keyword: 0 + print: 0 + print preview: 0 + random pack tab: 0 + random seed: 0 + rectangle: 0 + redo: 0 + reflection: 0 + reload data: 0 + reminder text: 0 + remove card: 0 + remove keyword: 0 + remove symmetry: 0 + replace: 0 + rotate: 0 + rotate 0: 0 + rotate 180: 0 + rotate 270: 0 + rotate 90: 0 + rotate card: 0 + rotation: 0 + save set: 0 + save set as: 0 + save symbol: 0 + save symbol as: 0 + scatter: 0 + scatter pie: 0 + seed: 0 + select: 0 + set code: 0 + set info tab: 0 + show profiler: 0 + sides: 0 + smooth point: 0 + snap: 0 + stack: 0 + star: 0 + stats tab: 0 + store symbol: 0 + style tab: 0 + subtract: 0 + symbols: 0 + symmetric point: 0 + symmetry: 0 + undo: 0 + ungroup: 0 + website: 0 + welcome: 0 + zoom export: 0 +label: + app language: 0 + apprentice: 0 + apprentice exe: 0 + apprentice export cancelled: 0 + auto match: 0 + auto replace: 0 + card display: 0 + card notes: 0 + check at startup: 0 + checking requires internet: 0 + columns: 0 + custom size: 0 + export filenames: 0 + external programs: 0 + filename conflicts: 0 + filename format: 0 + filename is ignored: 0 + filter: 0 + fix aspect ratio: 0 + force to fit: 0 + game type: 0 + html export options: 0 + html template: 0 + install package: 0 + installable version: 0 + installed version: 0 + installer size: optional, 0 + installer status: optional, 0 + keyword: 0 + language: 0 + magic set editor package: optional, 0 + match: 0 + mode: 0 + no version: 0 + original: 0 + original size: 0 + pack name: 0 + pack selection: 0 + pack totals: 0 + package action: 0 + package conflicts: 0 + package installable: 0 + package installed: 0 + package modified: 0 + package name: 0 + package status: 0 + package updates: 0 + percent of normal: 0 + reinstall package: 0 + reminder: 0 + remove package: 0 + result: 0 + rules: 0 + save changes: 1 + search cards: 0 + search keywords: 0 + seed: 0 + select cards: 0 + select cards print: optional, 0 + select columns: 0 + selected card count: 1 + selection: 0 + selection height: 0 + selection left: 0 + selection top: 0 + selection width: 0 + set code: 0 + sharpen filter: 0 + sides: optional, 0 + size: 0 + size to fit: 0 + standard keyword: 1 + style type: 0 + stylesheet not found: 1 + styling options: 0 + total cards: 0 + upgrade package: 0 + uses: 0 + windows: 0 + zoom: 0 + zoom %: 0 + zoom amount: 0 + zoom amount x: 0 + zoom amount y: 0 +menu: + about: 0 + add card: 0 + add cards: 0 + add keyword: 0 + add to dictionary: optional, 0 + auto replace: 0 + bar: 0 + basic shapes: 0 + bold: 0 + card list columns: 0 + cards: 0 + cards tab: 0 + check updates: 0 + close symbol editor: 0 + console tab: 0 + copy: 0 + cut: 0 + duplicate: 0 + edit: 0 + exit: 0 + export: 0 + export apprentice: 0 + export html: 0 + export image: 0 + export images: 0 + export mws: 0 + file: 0 + find: 0 + find next: 0 + format: 0 + graph: 0 + group: 0 + help: 0 + index: 0 + insert symbol: 0 + italic: 0 + keywords: 0 + keywords tab: 0 + new set: 0 + new symbol: 0 + new window: 0 + next card: 0 + next keyword: 0 + no spelling suggestions: 0 + open set: 0 + open symbol: 0 + orientation: 0 + paint: 0 + paste: 0 + pie: 0 + points: 0 + preferences: 0 + previous card: 0 + previous keyword: 0 + print: 0 + print preview: 0 + random pack tab: 0 + redo: 1 + reload data: 0 + reminder text: 0 + remove card: 0 + remove keyword: 0 + replace: 0 + rotate: 0 + rotate 0: 0 + rotate 180: 0 + rotate 270: 0 + rotate 90: 0 + save set: 0 + save set as: 0 + save symbol: 0 + save symbol as: 0 + scatter: 0 + scatter pie: 0 + select: 0 + set info tab: 0 + show profiler: 0 + stack: 0 + stats tab: 0 + store symbol: 0 + style tab: 0 + symbols: 0 + symmetry: 0 + tool: 0 + undo: 1 + ungroup: 0 + website: 0 + window: 0 +title: + %s - magic set editor: 1 + about: 0 + auto replaces: 0 + cannot create file: 0 + custom pack: 0 + directories: 0 + display: 0 + export cancelled: 0 + export html: 0 + export images: 0 + global: 0 + installing updates: 0 + locate apprentice: 0 + magic set editor: 0 + new set: 0 + open set: 0 + packages window: 0 + preferences: 0 + print preview: 0 + save changes: 0 + save html: 0 + save image: 0 + save set: 0 + select cards: 0 + select cards export: 0 + select columns: 0 + select stylesheet: 0 + slice image: 0 + symbol editor: 0 + untitled: 0 + update check: 0 + updates: 0 + updates available: 0 +tool: + add symmetry: 0 + basic shapes: 0 + border: 0 + cards tab: 0 + console tab: 0 + curve segment: 0 + difference: 0 + ellipse: 0 + free point: 0 + grid: 0 + intersect: 0 + keywords tab: 0 + line segment: 0 + merge: 0 + overlap: 0 + paint: optional, 0 + points: 0 + polygon: 0 + random pack tab: 0 + rectangle: 0 + redo: 0 + reflection: 0 + remove symmetry: 0 + rotate: 0 + rotation: 0 + select: 0 + set info tab: 0 + smooth point: 0 + snap: 0 + star: 0 + stats tab: 0 + store symbol: 0 + style tab: 0 + subtract: 0 + symmetric point: 0 + symmetry: 0 + undo: 0 +tooltip: + add card: 0 + add keyword: 0 + add symmetry: 0 + bar: 0 + basic shapes: 0 + bold: 0 + border: 0 + cards tab: 0 + console tab: 0 + copy: 0 + curve segment: 0 + cut: 0 + difference: 0 + ellipse: 0 + export: 0 + free point: 0 + grid: 0 + intersect: 0 + italic: 0 + keywords tab: 0 + line segment: 0 + merge: 0 + new set: 0 + open set: 0 + overlap: 0 + paint: optional, 0 + paste: 0 + pie: 0 + points: 0 + polygon: 0 + random pack tab: 0 + rectangle: 0 + redo: 1 + reflection: 0 + reminder text: 0 + remove card: 0 + remove keyword: 0 + remove symmetry: 0 + rotate: 0 + rotate card: 0 + rotation: 0 + save set: 0 + scatter: 0 + scatter pie: 0 + select: 0 + set info tab: 0 + smooth point: 0 + snap: 0 + stack: 0 + star: 0 + stats tab: 0 + store symbol: 0 + style tab: 0 + subtract: 0 + symbols: 0 + symmetric point: 0 + symmetry: 0 + undo: 1 +type: + boolean: 0 + card: 0 + cards: 0 + circle: 0 + collection: 0 + collection of: 1 + color: 0 + date: 0 + double: 0 + ellipse: 0 + export template: 0 + field: 0 + function: 0 + game: 0 + group: 0 + hexagon: 0 + image: 0 + integer: 0 + keyword: 0 + keywords: 0 + locale: optional, 0 + nil: 0 + object: 0 + pack: 0 + package: optional, 0 + pentagon: 0 + point: 0 + points: 0 + polygon: 0 + rectangle: 0 + reflection: 0 + rhombus: 0 + rotation: 0 + set: 0 + shape: 0 + shapes: 0 + square: 0 + star: 0 + string: 0 + style: 0 + stylesheet: 0 + symbol: 0 + triangle: 0 + value: 0 diff --git a/src/resource/common/message_error.png b/src/resource/common/message_error.png new file mode 100644 index 0000000000000000000000000000000000000000..c37bd062e60c3b38fc82e4d1f236a8ac2fae9d8c GIT binary patch literal 701 zcmV;u0z&N#0$9Ug7g~-`rQ^qx~m@y2OU8A z#zh~=7n#Z$Z*fx-GOtDf07cgx0suCz_W(2~Y(0tf@FX@P6EPuM_dgn$vj9LucO)%W zw%HgMW>=#oL>nZ>M&NEf08>)#)k<{$fCT_r>rPi=BV=hFh6WS^qqze>C6Ek}o{M5% za|@JGowu0t{&hgNzySHZxy@LTNh);YzZ2zSp_ zl$^T&Dnc|NLb&RD_!4>pt@VHdP)ZGER%5ZmWEe$lryR&y;2u^3cOkO4#6c%-(EY6a{600000NkvXXu0mjfxS2AI literal 0 HcmV?d00001 diff --git a/src/resource/common/message_information.png b/src/resource/common/message_information.png new file mode 100644 index 0000000000000000000000000000000000000000..12cd1aef900803abba99b26920337ec01ad5c267 GIT binary patch literal 778 zcmV+l1NHogP)BVme|mWaqy4$_pJm?y9KM{-*hp?1+Ey3e-CEDooTa!B;e(Q>TSF?bj>5At13y1p zriN3w3x~5SfZj{@J4M{kp{?=M_Lh2bV+5LH)Q)5W!-ePA$RgE1@5f1cyHki0Y}JyVEYZF(LD$xXlt$7A5CgE@ zpV-&l%vf;=5kZ2-2gi@Y6J&=cuwt>!vJ^#(&n|LcZyUzi6Duj$$hJ1s*HD-#;k-w@ zpdrwAuoDG_N2bvb07G$Zk*?Hc)JLtW4yqOnic_$zO7NZ#l>Fm){;fE?b$IbOaX2fe z0la4g0Dfw2xk7Wi7NapVD8YMPCZu?A1QCK*67dgsvRKBLFtrM>?$%&_lD1882mzdO zWPdw5KWw6IT`m1b_8=lS5jt8D3=RDa=&jWzR-)S@56WMslZ~mKu1)-wpXB>rNBQ>N zU#K`#1B&v|_AQK;7I~B}OdGiUT9LX>f0xm6<;LeP!=vFjPsUQF*wCJ*dO)4YBypgdiuF!=i@6Zyi7F|q#K zz?tlSZULa@t1D?$e;f@b36&N!V2mjOHw|*ZD2*!*kie8d0ob9Fh%G9Y=r;n&8^QUAkdX#Dq|D$hyKfc&Ml|8p0c z|4m?!%b@Oan%jHPb>P21W3>NYd-<1_&1WU%JGUHShzcVz!>-In&hVRPdDrmgA!XB=w& zAG5&bziK_hADjk6&({3E^3;U?OHcIvUwEwR|Gc9eKtr;M1&07*qoM6N<$ Ef*qF6bpQYW literal 0 HcmV?d00001 diff --git a/src/resource/common/message_warning.png b/src/resource/common/message_warning.png new file mode 100644 index 0000000000000000000000000000000000000000..628cf2dae3d419ae220c8928ac71393b480745a3 GIT binary patch literal 666 zcmV;L0%iS)P)eOSYYtbpBV}~vsBnU!_?2tr-P=|^T zED%wc9ezHgW@NMb!^uT_|SvCpFLJylbx zY%bpaTGI8IYXMN$9w<3j9VkA~NYOKEQXsj?6a9_hcwfU$acAhJhB)zb_w@MVUEy@S zX&I>K-R!bhu3?(6bHWIg$HEl7{9g>>&l_qdd+UYb(1~BCo9LptNq&8>!yoJ3Ui(i5 zRJ|XnYBklL!{@$-7=3mJ>P@1c=7Oc79e-V7yf+%lD2!I;Y&nXBZ>=B!5?CB>LvEx6 znI%n)qqi$#X#wKB(U7XP2P=+4{b@j#r%9-K(8UqtSDk>0UKzf*HM9yqMZ1D!$2MdZ zR=`U>0zhOH1XqN?nY@AQqB7)Fp4{v&dKXvb43hZKvnN8;Po;+jY*}~*Z|W9Q0W%{D z^T}Cc<|r(Su=1K=P5>Z4 zg`et&Va}tdzBS-G-ZcO)zCWpJvGQwrHZ`@wpM420ac@bI5~KkTFfGEM3sPWO8co4^fI6lPnA)Y{ef%@{+SnoUk0+dW+*{8WvF8}}l07*qoM6N<$g7cXs A&j0`b literal 0 HcmV?d00001 diff --git a/src/resource/msw/mse.rc b/src/resource/msw/mse.rc index 8c9aa548..ce83d1af 100644 --- a/src/resource/msw/mse.rc +++ b/src/resource/msw/mse.rc @@ -66,6 +66,7 @@ tool/window_style IMAGE "tool/window_style.png" tool/window_keywords IMAGE "tool/window_keywords.png" tool/window_statistics IMAGE "tool/window_statistics.png" tool/window_random_pack IMAGE "tool/window_random_pack.png" +tool/window_console IMAGE "tool/window_console.png" tool/help IMAGE "tool/help.png" @@ -186,6 +187,11 @@ installer_locales IMAGE "../common/installer_locales.png" installer_program IMAGE "../common/installer_program.png" //installer_font IMAGE "../common/installer_font.png" +message_input IMAGE "../common/message_input.png" +message_information IMAGE "../common/message_information.png" +message_warning IMAGE "../common/message_warning.png" +message_error IMAGE "../common/message_error.png" + // -------------------------------------------------------- : WX wxBITMAP_STD_COLOURS BITMAP "wx/msw/colours.bmp" diff --git a/src/resource/msw/tool/window_console.png b/src/resource/msw/tool/window_console.png new file mode 100644 index 0000000000000000000000000000000000000000..b3d8ce01e2e9c5a6ce83c3b6d7715cbb2b9d3fb0 GIT binary patch literal 525 zcmV+o0`mQdP)>Z+sNt2+U0SgfoD!Wm8sxbT>nyV*Byc6US+Mev^`pI%-cR#%pfrES|$2%tg@7${Im zLBJqCKm^~%kqyWahMtFC{m)BDn@^W+n<9Vs4o8^{xZi&Mv#JmPg~hDhyn9@iQaYl1 zb`JLD2V96U6l8WL=?n97fC_~~t>ED5npj0DEXy*Oju~q^dmy7QgiIy_{eJ&PQrd=O zTr3tLpD%!=R5+2n4HYIFZ-%8JGt|1(g~rh-D=YFj+Az zW(A5Kmc(%jan)&(SOLdLpDi*0KTl?3g3&8WuNWgH;XS@00@rm1q##!+l~R*`BVp_N zo+o>~-p$tT{t5Bs0?k82!-S(@;vSVo<7@Jfu3S^qP;(9ryrKIh{yWa!k>a)0QvY16 P00000NkvXXu0mjf=yc!b literal 0 HcmV?d00001 diff --git a/src/script/functions/basic.cpp b/src/script/functions/basic.cpp index 94867219..8ec90721 100644 --- a/src/script/functions/basic.cpp +++ b/src/script/functions/basic.cpp @@ -23,10 +23,10 @@ DECLARE_TYPEOF_COLLECTION(pair); SCRIPT_FUNCTION(trace) { SCRIPT_PARAM_C(String, input); - #ifdef _DEBUG + #if defined(_DEBUG) && 0 wxLogDebug(_("Trace:\t") + input); #else - handle_warning(_("Trace:\t") + input, false); + queue_message(MESSAGE_INFO, _("Trace: ") + input); #endif SCRIPT_RETURN(input); } @@ -35,7 +35,7 @@ SCRIPT_FUNCTION(warning) { SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_DEFAULT_C(bool, condition, true); if (condition) { - handle_warning(input, true); + queue_message(MESSAGE_WARNING, input); } return script_nil; } @@ -51,7 +51,7 @@ SCRIPT_FUNCTION(warning_if_neq) { try { s2 = v2->toCode(); } catch (...) {} - handle_warning(input + s1 + _(" != ") + s2, true); + queue_message(MESSAGE_WARNING, input + s1 + _(" != ") + s2); } return script_nil; } diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index 90a11288..8a683e28 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -67,7 +67,7 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) { set.game ->init_script.invoke(*ctx, false); stylesheet->init_script.invoke(*ctx, false); } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } onInit(stylesheet, ctx); return *ctx; @@ -108,7 +108,7 @@ void SetScriptManager::onInit(const StyleSheetP& stylesheet, Context* ctx) { initDependencies(*ctx, *set.game); initDependencies(*ctx, *stylesheet); } catch (const Error& e) { - handle_error(e, false, false); + handle_error(e); } } @@ -258,7 +258,7 @@ void SetScriptManager::updateStyles(Context& ctx, const IndexMap& } } catch (const ScriptError& e) { // NOTE: don't handle errors now, we are likely in an onPaint handler - handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'")), false, false); + handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'"))); } } } @@ -298,7 +298,7 @@ void SetScriptManager::updateAll() { PROFILER2( v->fieldP.get(), _("update set.") + v->fieldP->name ); v->update(ctx); } catch (const ScriptError& e) { - handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'")), false, true); + handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'"))); } } // update card data of all cards @@ -312,7 +312,7 @@ void SetScriptManager::updateAll() { #endif v->update(ctx); } catch (const ScriptError& e) { - handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'")), false, true); + handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'"))); } } } @@ -347,7 +347,7 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque& to_upd try { changes = u.value->update(ctx); } catch (const ScriptError& e) { - handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'")), false, true); + handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'"))); } if (changes) { // changed, send event diff --git a/src/util/error.cpp b/src/util/error.cpp index 74b740b3..80bd7016 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -13,6 +13,7 @@ #if wxUSE_STACKWALKER #include #endif +#include DECLARE_TYPEOF_COLLECTION(ScriptParseError); @@ -158,94 +159,45 @@ ScriptParseErrors::ScriptParseErrors(const vector& errors) // ----------------------------------------------------------------------------- : Error handling -// Errors for which a message box was already shown -vector previous_errors; -vector previous_warnings; -String pending_errors; -String pending_warnings; -DECLARE_TYPEOF_COLLECTION(String); +// messages can be posted from other threads, this mutex protects the message list wxMutex crit_error_handling; +typedef pair Message; +deque message_queue; +bool show_message_box_for_fatal_errors = true; bool write_errors_to_cli = false; -void show_pending_errors(); -void show_pending_warnings(); - -void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { - { - // Thread safety - wxMutexLocker lock(crit_error_handling); - // Check duplicates - if (!allow_duplicate) { - FOR_EACH(pe, previous_errors) { - if (e == pe) return; - } - previous_errors.push_back(e); - } - // Only show errors in the main thread - if (!pending_errors.empty()) pending_errors += _("\n\n"); - pending_errors += e; +void queue_message(MessageType type, String const& msg) { + if (write_errors_to_cli && wxThread::IsMain()) { + cli.show_message(type,msg); + return; // TODO: is this the right thing to do? } - // show messages - if ((write_errors_to_cli || now) && wxThread::IsMain()) { - show_pending_warnings(); // warnings are older, show them first - show_pending_errors(); + if (show_message_box_for_fatal_errors && type == MESSAGE_FATAL_ERROR && wxThread::IsMain()) { + // bring this to the user's attention right now! + wxMessageBox(msg, _("Error"), wxOK | wxICON_ERROR); } + // Thread safety + wxMutexLocker lock(crit_error_handling); + // Only show errors in the main thread + message_queue.push_back(make_pair(type,msg)); } -void handle_error(const Error& e, bool allow_duplicate, bool now) { - handle_error(e.what(), allow_duplicate, now); +void handle_error(const Error& e) { + queue_message(e.is_fatal() ? MESSAGE_FATAL_ERROR : MESSAGE_ERROR, e.what()); } -void handle_warning(const String& w, bool now) { - { - // Check duplicates - wxMutexLocker lock(crit_error_handling); - // Check duplicates - FOR_EACH(pw, previous_warnings) { - if (w == pw) return; - } - previous_warnings.push_back(w); - // Only show errors in the main thread - if (!pending_warnings.empty()) pending_warnings += _("\n\n"); - pending_warnings += w; - } - // show messages - if ((write_errors_to_cli || now) && wxThread::IsMain()) { - show_pending_errors(); - show_pending_warnings(); - } +bool have_queued_message() { + wxMutexLocker lock(crit_error_handling); + return !message_queue.empty(); } -void handle_pending_errors() { - show_pending_errors(); - show_pending_warnings(); -} - -void show_pending_errors() { - assert(wxThread::IsMain()); - if (crit_error_handling.TryLock() != wxMUTEX_NO_ERROR) - return; - if (!pending_errors.empty()) { - if (write_errors_to_cli) { - cli.showError(pending_errors); - } else { - wxMessageBox(pending_errors, _("Error"), wxOK | wxICON_ERROR); - } - pending_errors.clear(); +bool get_queued_message(MessageType& type, String& msg) { + wxMutexLocker lock(crit_error_handling); + if (message_queue.empty()) { + return false; + } else { + type = message_queue.back().first; + msg = message_queue.back().second; + message_queue.pop_back(); + return true; } - crit_error_handling.Unlock(); -} -void show_pending_warnings() { - assert(wxThread::IsMain()); - if (crit_error_handling.TryLock() != wxMUTEX_NO_ERROR) - return; - if (!pending_warnings.empty()) { - if (write_errors_to_cli) { - cli.showWarning(pending_warnings); - } else { - wxMessageBox(pending_warnings, _("Warning"), wxOK | wxICON_EXCLAMATION); - } - pending_warnings.clear(); - } - crit_error_handling.Unlock(); } diff --git a/src/util/error.hpp b/src/util/error.hpp index f3d32358..ebb1b601 100644 --- a/src/util/error.hpp +++ b/src/util/error.hpp @@ -26,6 +26,8 @@ class Error { /// Return the error message virtual String what() const; + /// Is the message (potentially) fatal? + virtual bool is_fatal() const { return false; } protected: String message; ///< The error message @@ -36,6 +38,8 @@ class Error { class InternalError : public Error { public: InternalError(const String& str); + // not all internal errors are fatal, but we had still better warn the user about them. + virtual bool is_fatal() const { return true; } }; // ----------------------------------------------------------------------------- : File errors @@ -128,37 +132,62 @@ class ScriptErrorNoMember : public ScriptError { : ScriptError(_ERROR_2_("has no member", type, member)) {} }; -// ----------------------------------------------------------------------------- : Error handling +// ----------------------------------------------------------------------------- : Bounds checking -/// Should errors be written to stdout? +template +T& at(vector& x, size_t pos) { + if (pos < x.size()) { + return x[pos]; + } else { + throw InternalError(_("vector index out of bounds: %d > %d, where T = ") + typeid(x).name()); + } +} + +// ----------------------------------------------------------------------------- : Error/message handling + +/// Should a popup be shown for internal errors? +extern bool show_message_box_for_fatal_errors; extern bool write_errors_to_cli; -/// Handle an error by showing a message box -/** If !allow_duplicate and the error is the same as the previous error, does nothing. - * If !now the error is handled by a later call to handle_pending_errors() +/// Types/levels of (error)messages +enum MessageType +{ MESSAGE_INPUT +, MESSAGE_OUTPUT +, MESSAGE_INFO +, MESSAGE_WARNING +, MESSAGE_ERROR +, MESSAGE_FATAL_ERROR + +, MESSAGE_TYPE_MAX +}; + +/// Queue an (error) message, it can later be retrieved with get_queued_message +/** If the message is a MESSAGE_FATAL_ERROR, and show_message_box_for_fatal_errors==true, then a popup is shown */ -void handle_error(const Error& e, bool allow_duplicate = true, bool now = true); +void queue_message(MessageType type, String const& msg); +/// Handle an error by queuing a message +void handle_error(const Error& e); -/// Handle a warning by showing a message box -void handle_warning(const String& w, bool now = true); +/// Are there any queued messages? +bool have_queued_message(); + +/// Get the first queued message, or return false +bool get_queued_message(MessageType& type, String& msg); -/// 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(); /// Make a stack trace for use in InternalErrors String get_stack_trace(); /// Catch all types of errors, and pass then to handle_error -#define CATCH_ALL_ERRORS(handle_now) \ - catch (const Error& e) { \ - handle_error(e, false, handle_now); \ - } catch (const std::exception& e) { \ - /* we don't throw std::exception ourselfs, so this is probably something serious */ \ - String message(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) ); \ - handle_error(InternalError(message), false, handle_now); \ - } catch (...) { \ - handle_error(InternalError(_("An unexpected exception occurred!")), false, handle_now); \ +#define CATCH_ALL_ERRORS(handle_now) \ + catch (const Error& e) { \ + handle_error(e); \ + } catch (const std::exception& e) { \ + /* we don't throw std::exception ourselfs, so this is probably something serious */ \ + String message(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) ); \ + handle_error(InternalError(message)); \ + } catch (...) { \ + handle_error(InternalError(_("An unexpected exception occurred!"))); \ } // ----------------------------------------------------------------------------- : EOF diff --git a/src/util/io/package.cpp b/src/util/io/package.cpp index ccbc39e6..2708e115 100644 --- a/src/util/io/package.cpp +++ b/src/util/io/package.cpp @@ -600,16 +600,16 @@ void Packaged::requireDependency(Packaged* package) { FOR_EACH(dep, dependencies) { if (dep->package == n) { if (package->version < dep->version) { - handle_warning(_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString()), false); + queue_message(MESSAGE_WARNING,_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString())); } else if (package->compatible_version > dep->version) { - handle_warning(_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename()), false); + queue_message(MESSAGE_WARNING,_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename())); } else { return; // ok } } } // dependency not found - handle_warning(_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()), false); + queue_message(MESSAGE_WARNING,_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString())); } // ----------------------------------------------------------------------------- : IncludePackage diff --git a/src/util/io/package_manager.cpp b/src/util/io/package_manager.cpp index 321d240c..b4e5b29e 100644 --- a/src/util/io/package_manager.cpp +++ b/src/util/io/package_manager.cpp @@ -153,20 +153,20 @@ bool PackageManager::checkDependency(const PackageDependency& dep, bool report_e // mse package? if (dep.package == mse_package) { if (app_version < dep.version) { - handle_warning(_ERROR_3_("package out of date", _("Magic Set Editor"), app_version.toString(), dep.version.toString()),false); + queue_message(MESSAGE_WARNING, _ERROR_3_("package out of date", _("Magic Set Editor"), app_version.toString(), dep.version.toString())); } return true; } // does the package exist? if (!local.exists(dep.package) && !global.exists(dep.package)) { if (report_errors) - handle_warning(_ERROR_1_("package not found", dep.package),false); + queue_message(MESSAGE_WARNING, _ERROR_1_("package not found", dep.package)); return false; } PackagedP package = openAny(dep.package, true); if (package->version < dep.version) { if (report_errors) - handle_warning(_ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString()),false); + queue_message(MESSAGE_WARNING, _ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString())); return false; } return true; @@ -378,7 +378,7 @@ bool PackageDirectory::install(const InstallablePackage& package) { bool PackageDirectory::actual_install(const InstallablePackage& package, const String& install_dir) { String name = package.description->name; if (!package.installer->installer) { - handle_warning(_("Installer not found for package: ") + name); + queue_message(MESSAGE_ERROR, _("Installer not found for package: ") + name); return false; } Installer& installer = *package.installer->installer; diff --git a/src/util/io/reader.cpp b/src/util/io/reader.cpp index 505459d4..76bfd997 100644 --- a/src/util/io/reader.cpp +++ b/src/util/io/reader.cpp @@ -61,7 +61,7 @@ void Reader::handleAppVersion() { if (enterBlock(_("mse_version"))) { handle(file_app_version); if (app_version < file_app_version) { - handle_warning(_ERROR_2_("newer version", filename, file_app_version.toString()), false); + queue_message(MESSAGE_WARNING, _ERROR_2_("newer version", filename, file_app_version.toString())); } exitBlock(); } @@ -75,7 +75,7 @@ void Reader::warning(const String& msg, int line_number_delta, bool warn_on_prev void Reader::showWarnings() { if (!warnings.empty()) { - handle_warning(_("Warnings while reading file:\n") + filename + _("\n") + warnings, false); + queue_message(MESSAGE_WARNING, _("Warnings while reading file:\n") + filename + _("\n") + warnings); warnings.clear(); } } diff --git a/src/util/tagged_string.cpp b/src/util/tagged_string.cpp index fb8fa4fb..ff6aadf1 100644 --- a/src/util/tagged_string.cpp +++ b/src/util/tagged_string.cpp @@ -598,12 +598,12 @@ void check_tagged(const String& str, bool check_balance) { if (str.GetChar(i) == _('<')) { size_t end = skip_tag(str,i); if (end == String::npos) { - handle_warning(_("Invalid tagged string: missing '>'"),false); + queue_message(MESSAGE_WARNING, _("Invalid tagged string: missing '>'")); } for (size_t j = i + 1 ; j + 1 < end ; ++j) { Char c = str.GetChar(j); if (c == _(' ') || c == _('<')) { - handle_warning(_("Invalid character in tag"),false); + queue_message(MESSAGE_WARNING, _("Invalid character in tag")); } } if (check_balance) { @@ -614,7 +614,7 @@ void check_tagged(const String& str, bool check_balance) { } else { size_t close = match_close_tag(str,i); if (close == String::npos) { - handle_warning(_("Invalid tagged string: missing close tag for <") + tag_at(str,i) + _(">"),false); + queue_message(MESSAGE_WARNING, _("Invalid tagged string: missing close tag for <") + tag_at(str,i) + _(">")); } } } diff --git a/src/util/vcs/subversion.cpp b/src/util/vcs/subversion.cpp index ec542783..a960a247 100644 --- a/src/util/vcs/subversion.cpp +++ b/src/util/vcs/subversion.cpp @@ -50,7 +50,7 @@ void SubversionVCS::removeFile(const wxFileName& filename) { String name = filename.GetFullPath(); const Char* name_c[] = {_("svn"), _("rm"), name.c_str(), nullptr}; - handle_warning(String(name_c[0]) + name_c[1] + name_c[2]); + queue_message(MESSAGE_WARNING, String(name_c[0]) + name_c[1] + name_c[2]); // TODO: do we really need to remove the file before calling "svn remove"? VCS::removeFile(filename); if (!run_svn(name_c)) { diff --git a/src/util/window_id.hpp b/src/util/window_id.hpp index 2654a2c5..c4130197 100644 --- a/src/util/window_id.hpp +++ b/src/util/window_id.hpp @@ -207,6 +207,9 @@ enum ChildMenuID { , ID_GENERATE_PACK , ID_CUSTOM_PACK + // Console panel +, ID_EVALUATE + // SymbolFont (Format menu) , ID_INSERT_SYMBOL_MENU_MIN = 9001 , ID_INSERT_SYMBOL_MENU_MAX = 10000