Change tabs to two spaces.

This commit is contained in:
Lymia Aluysia
2017-01-18 08:43:21 -06:00
parent d7f5f0dc3b
commit d2c635f739
329 changed files with 41307 additions and 41496 deletions
+369 -369
View File
@@ -30,366 +30,366 @@
DECLARE_TYPEOF_COLLECTION(AddCardsScriptP);
#ifdef EVT_TOOL_DROPDOWN
// This is only available after patching wx or in version 2.10
// see http://trac.wxwidgets.org/ticket/8556
#define HAVE_TOOLBAR_DROPDOWN_MENU 1
// This is only available after patching wx or in version 2.10
// see http://trac.wxwidgets.org/ticket/8556
#define HAVE_TOOLBAR_DROPDOWN_MENU 1
#endif
// ----------------------------------------------------------------------------- : CardsPanel
CardsPanel::CardsPanel(Window* parent, int id)
: SetWindowPanel(parent, id)
: SetWindowPanel(parent, id)
{
// init controls
editor = new CardEditor(this, ID_EDITOR);
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
card_list = new FilteredImageCardList(splitter, ID_CARD_LIST);
nodes_panel = new Panel(splitter, wxID_ANY);
notes = new TextCtrl(nodes_panel, ID_NOTES, true);
collapse_notes = new HoverButton(nodes_panel, ID_COLLAPSE_NOTES, _("btn_collapse"), wxNullColour, false);
collapse_notes->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
filter = nullptr;
editor->next_in_tab_order = card_list;
// init sizer for notes panel
wxSizer* sn = new wxBoxSizer(wxVERTICAL);
wxSizer* sc = new wxBoxSizer(wxHORIZONTAL);
sc->Add(new wxStaticText(nodes_panel, wxID_ANY, _LABEL_("card notes")), 1, wxEXPAND | wxLEFT, 2);
sc->Add(collapse_notes, 0, wxALIGN_CENTER | wxRIGHT, 2);
sn->Add(sc, 0, wxEXPAND, 2);
sn->Add(notes, 1, wxEXPAND | wxTOP, 2);
nodes_panel->SetSizer(sn);
// init splitter
splitter->SetMinimumPaneSize(15);
splitter->SetSashGravity(1.0);
splitter->SplitHorizontally(card_list, nodes_panel, -40);
notes_below_editor = false;
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s_left = new wxBoxSizer(wxVERTICAL);
s_left->Add(editor);
s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
// init menus
menuCard = new IconMenu();
menuCard->Append(ID_CARD_PREV, _MENU_("previous card"), _HELP_("previous card"));
menuCard->Append(ID_CARD_NEXT, _MENU_("next card"), _HELP_("next card"));
menuCard->AppendSeparator();
menuCard->Append(ID_CARD_ADD, _("card_add"), _MENU_("add card"), _HELP_("add card"));
insertManyCardsMenu = new wxMenuItem(menuCard, ID_CARD_ADD_MULT, _MENU_("add cards"), _HELP_("add cards"));
set_menu_item_image(insertManyCardsMenu, _("card_add_multiple"));
((wxMenu*)menuCard)->Append(insertManyCardsMenu);
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
// Adding a space never hurts, please keep it just to be safe.
menuCard->Append(ID_CARD_REMOVE, _("card_del"), _MENU_("remove card")+_(" "),_HELP_("remove card"));
menuCard->AppendSeparator();
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _MENU_("rotate 0"), _HELP_("rotate 0"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _MENU_("rotate 270"), _HELP_("rotate 270"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _MENU_("rotate 90"), _HELP_("rotate 90"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _MENU_("rotate 180"), _HELP_("rotate 180"), wxITEM_CHECK);
menuCard->Append(wxID_ANY, _("card_rotate"), _MENU_("orientation"), _HELP_("orientation"), wxITEM_NORMAL, menuRotate);
menuCard->AppendSeparator();
// This probably belongs in the window menu, but there we can't remove the separator once it is added
menuCard->Append(ID_SELECT_COLUMNS, _MENU_("card list columns"),_HELP_("card list columns"));
menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _MENU_("bold"), _HELP_("bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _MENU_("italic"), _HELP_("italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _MENU_("symbols"), _HELP_("symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _MENU_("reminder text"), _HELP_("reminder text"), wxITEM_CHECK);
menuFormat->AppendSeparator();
insertSymbolMenu = new wxMenuItem(menuFormat, ID_INSERT_SYMBOL, _MENU_("insert symbol"));
menuFormat->Append(insertSymbolMenu);
toolAddCard = nullptr;
// init controls
editor = new CardEditor(this, ID_EDITOR);
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
card_list = new FilteredImageCardList(splitter, ID_CARD_LIST);
nodes_panel = new Panel(splitter, wxID_ANY);
notes = new TextCtrl(nodes_panel, ID_NOTES, true);
collapse_notes = new HoverButton(nodes_panel, ID_COLLAPSE_NOTES, _("btn_collapse"), wxNullColour, false);
collapse_notes->SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
filter = nullptr;
editor->next_in_tab_order = card_list;
// init sizer for notes panel
wxSizer* sn = new wxBoxSizer(wxVERTICAL);
wxSizer* sc = new wxBoxSizer(wxHORIZONTAL);
sc->Add(new wxStaticText(nodes_panel, wxID_ANY, _LABEL_("card notes")), 1, wxEXPAND | wxLEFT, 2);
sc->Add(collapse_notes, 0, wxALIGN_CENTER | wxRIGHT, 2);
sn->Add(sc, 0, wxEXPAND, 2);
sn->Add(notes, 1, wxEXPAND | wxTOP, 2);
nodes_panel->SetSizer(sn);
// init splitter
splitter->SetMinimumPaneSize(15);
splitter->SetSashGravity(1.0);
splitter->SplitHorizontally(card_list, nodes_panel, -40);
notes_below_editor = false;
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s_left = new wxBoxSizer(wxVERTICAL);
s_left->Add(editor);
s->Add(s_left, 0, wxEXPAND | wxRIGHT, 2);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
// init menus
menuCard = new IconMenu();
menuCard->Append(ID_CARD_PREV, _MENU_("previous card"), _HELP_("previous card"));
menuCard->Append(ID_CARD_NEXT, _MENU_("next card"), _HELP_("next card"));
menuCard->AppendSeparator();
menuCard->Append(ID_CARD_ADD, _("card_add"), _MENU_("add card"), _HELP_("add card"));
insertManyCardsMenu = new wxMenuItem(menuCard, ID_CARD_ADD_MULT, _MENU_("add cards"), _HELP_("add cards"));
set_menu_item_image(insertManyCardsMenu, _("card_add_multiple"));
((wxMenu*)menuCard)->Append(insertManyCardsMenu);
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
// Adding a space never hurts, please keep it just to be safe.
menuCard->Append(ID_CARD_REMOVE, _("card_del"), _MENU_("remove card")+_(" "),_HELP_("remove card"));
menuCard->AppendSeparator();
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _MENU_("rotate 0"), _HELP_("rotate 0"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _MENU_("rotate 270"), _HELP_("rotate 270"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _MENU_("rotate 90"), _HELP_("rotate 90"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _MENU_("rotate 180"), _HELP_("rotate 180"), wxITEM_CHECK);
menuCard->Append(wxID_ANY, _("card_rotate"), _MENU_("orientation"), _HELP_("orientation"), wxITEM_NORMAL, menuRotate);
menuCard->AppendSeparator();
// This probably belongs in the window menu, but there we can't remove the separator once it is added
menuCard->Append(ID_SELECT_COLUMNS, _MENU_("card list columns"),_HELP_("card list columns"));
menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _MENU_("bold"), _HELP_("bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _MENU_("italic"), _HELP_("italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _MENU_("symbols"), _HELP_("symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _MENU_("reminder text"), _HELP_("reminder text"), wxITEM_CHECK);
menuFormat->AppendSeparator();
insertSymbolMenu = new wxMenuItem(menuFormat, ID_INSERT_SYMBOL, _MENU_("insert symbol"));
menuFormat->Append(insertSymbolMenu);
toolAddCard = nullptr;
}
void CardsPanel::updateNotesPosition() {
wxSize editor_size = editor->GetBestSize();
int room_below_editor = GetSize().y - editor_size.y;
bool should_be_below = room_below_editor > 100;
// move?
if (should_be_below && !notes_below_editor) {
notes_below_editor = true;
// move the notes_panel to below the editor, it gets this as its parent
splitter->Unsplit(nodes_panel);
nodes_panel->Reparent(this);
s_left->Add(nodes_panel, 1, wxEXPAND | wxTOP, 2);
collapse_notes->Hide();
nodes_panel->Show();
} else if (!should_be_below && notes_below_editor) {
notes_below_editor = false;
// move the notes_panel back to below the card list
s_left->Detach(nodes_panel);
nodes_panel->Reparent(splitter);
collapse_notes->Show();
splitter->SplitHorizontally(card_list, nodes_panel, -80);
}
wxSize editor_size = editor->GetBestSize();
int room_below_editor = GetSize().y - editor_size.y;
bool should_be_below = room_below_editor > 100;
// move?
if (should_be_below && !notes_below_editor) {
notes_below_editor = true;
// move the notes_panel to below the editor, it gets this as its parent
splitter->Unsplit(nodes_panel);
nodes_panel->Reparent(this);
s_left->Add(nodes_panel, 1, wxEXPAND | wxTOP, 2);
collapse_notes->Hide();
nodes_panel->Show();
} else if (!should_be_below && notes_below_editor) {
notes_below_editor = false;
// move the notes_panel back to below the card list
s_left->Detach(nodes_panel);
nodes_panel->Reparent(splitter);
collapse_notes->Show();
splitter->SplitHorizontally(card_list, nodes_panel, -80);
}
}
bool CardsPanel::Layout() {
updateNotesPosition();
return SetWindowPanel::Layout();
updateNotesPosition();
return SetWindowPanel::Layout();
}
/*void removeInsertSymbolMenu() {
menuFormat->Append(ID_INSERT_SYMBOL, _(""), _MENU_("insert symbol"));
menuFormat->Append(ID_INSERT_SYMBOL, _(""), _MENU_("insert symbol"));
}*/// TODO
CardsPanel::~CardsPanel() {
// settings.card_notes_height = splitter->GetSashPosition();
// we don't own the submenu
wxMenu* menu = insertSymbolMenu->GetSubMenu();
if (menu && menu->GetParent() == menuFormat) {
menu->SetParent(nullptr);
}
insertSymbolMenu->SetSubMenu(nullptr);
// delete menus
delete menuCard;
delete menuFormat;
// settings.card_notes_height = splitter->GetSashPosition();
// we don't own the submenu
wxMenu* menu = insertSymbolMenu->GetSubMenu();
if (menu && menu->GetParent() == menuFormat) {
menu->SetParent(nullptr);
}
insertSymbolMenu->SetSubMenu(nullptr);
// delete menus
delete menuCard;
delete menuFormat;
}
void CardsPanel::onChangeSet() {
editor->setSet(set);
notes->setSet(set);
card_list->setSet(set);
// change insertManyCardsMenu
delete insertManyCardsMenu->GetSubMenu();
insertManyCardsMenu->SetSubMenu(makeAddCardsSubmenu(false));
// re-add the menu
menuCard->Remove(ID_CARD_ADD_MULT);
((wxMenu*)menuCard)->Insert(4,insertManyCardsMenu); // HACK: the position is hardcoded
// also for the toolbar dropdown menu
#if HAVE_TOOLBAR_DROPDOWN_MENU
if (toolAddCard) {
toolAddCard->SetDropdownMenu(makeAddCardsSubmenu(true));
}
#endif
editor->setSet(set);
notes->setSet(set);
card_list->setSet(set);
// change insertManyCardsMenu
delete insertManyCardsMenu->GetSubMenu();
insertManyCardsMenu->SetSubMenu(makeAddCardsSubmenu(false));
// re-add the menu
menuCard->Remove(ID_CARD_ADD_MULT);
((wxMenu*)menuCard)->Insert(4,insertManyCardsMenu); // HACK: the position is hardcoded
// also for the toolbar dropdown menu
#if HAVE_TOOLBAR_DROPDOWN_MENU
if (toolAddCard) {
toolAddCard->SetDropdownMenu(makeAddCardsSubmenu(true));
}
#endif
}
wxMenu* CardsPanel::makeAddCardsSubmenu(bool add_single_card_option) {
IconMenu* cards_scripts_menu = nullptr;
// default item?
if (add_single_card_option) {
cards_scripts_menu = new IconMenu;
cards_scripts_menu->Append(ID_CARD_ADD, _("card_add"), _MENU_("add card"), _HELP_("add card"));
cards_scripts_menu->AppendSeparator();
}
// create menu for add_cards_scripts
if (set && set->game && !set->game->add_cards_scripts.empty()) {
int id = ID_ADD_CARDS_MENU_MIN;
if (!cards_scripts_menu) cards_scripts_menu = new IconMenu;
FOR_EACH(cs, set->game->add_cards_scripts) {
cards_scripts_menu->Append(id++, cs->name, cs->description);
}
}
return cards_scripts_menu;
IconMenu* cards_scripts_menu = nullptr;
// default item?
if (add_single_card_option) {
cards_scripts_menu = new IconMenu;
cards_scripts_menu->Append(ID_CARD_ADD, _("card_add"), _MENU_("add card"), _HELP_("add card"));
cards_scripts_menu->AppendSeparator();
}
// create menu for add_cards_scripts
if (set && set->game && !set->game->add_cards_scripts.empty()) {
int id = ID_ADD_CARDS_MENU_MIN;
if (!cards_scripts_menu) cards_scripts_menu = new IconMenu;
FOR_EACH(cs, set->game->add_cards_scripts) {
cards_scripts_menu->Append(id++, cs->name, cs->description);
}
}
return cards_scripts_menu;
}
// ----------------------------------------------------------------------------- : UI
void CardsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
tb->AddTool(ID_FORMAT_BOLD, _(""), load_resource_tool_image(_("bold")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bold"), _HELP_("bold"));
tb->AddTool(ID_FORMAT_ITALIC, _(""), load_resource_tool_image(_("italic")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("italic"), _HELP_("italic"));
tb->AddTool(ID_FORMAT_SYMBOL, _(""), load_resource_tool_image(_("symbol")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symbols"), _HELP_("symbols"));
tb->AddTool(ID_FORMAT_REMINDER, _(""), load_resource_tool_image(_("reminder")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("reminder text"), _HELP_("reminder text"));
tb->AddSeparator();
#if HAVE_TOOLBAR_DROPDOWN_MENU
toolAddCard = tb->AddTool(ID_CARD_ADD, _(""), load_resource_tool_image(_("card_add")), wxNullBitmap, wxITEM_DROPDOWN,_TOOLTIP_("add card"), _HELP_("add card"));
toolAddCard->SetDropdownMenu(makeAddCardsSubmenu(true));
#else
tb->AddTool(ID_CARD_ADD, _(""), load_resource_tool_image(_("card_add")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("add card"), _HELP_("add card"));
#endif
tb->AddTool(ID_CARD_REMOVE, _(""), load_resource_tool_image(_("card_del")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("remove card"), _HELP_("remove card"));
tb->AddSeparator();
#if HAVE_TOOLBAR_DROPDOWN_MENU
wxToolBarToolBase* rot = tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap, wxITEM_DROPDOWN, _TOOLTIP_("rotate card"), _HELP_("rotate card"));
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _MENU_("rotate 0"), _HELP_("rotate 0"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _MENU_("rotate 270"), _HELP_("rotate 270"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _MENU_("rotate 90"), _HELP_("rotate 90"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _MENU_("rotate 180"), _HELP_("rotate 180"), wxITEM_CHECK);
rot->SetDropdownMenu(menuRotate);
#else
tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap,wxITEM_NORMAL, _TOOLTIP_("rotate card"), _HELP_("rotate card"));
#endif
// Filter/search textbox
tb->AddSeparator();
if (!filter) filter = new FilterCtrl(tb, ID_CARD_FILTER, _LABEL_("search cards"));
tb->AddControl(filter);
tb->Realize();
// Menus
mb->Insert(2, menuCard, _MENU_("cards"));
mb->Insert(3, menuFormat, _MENU_("format"));
// Toolbar
tb->AddTool(ID_FORMAT_BOLD, _(""), load_resource_tool_image(_("bold")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bold"), _HELP_("bold"));
tb->AddTool(ID_FORMAT_ITALIC, _(""), load_resource_tool_image(_("italic")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("italic"), _HELP_("italic"));
tb->AddTool(ID_FORMAT_SYMBOL, _(""), load_resource_tool_image(_("symbol")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symbols"), _HELP_("symbols"));
tb->AddTool(ID_FORMAT_REMINDER, _(""), load_resource_tool_image(_("reminder")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("reminder text"), _HELP_("reminder text"));
tb->AddSeparator();
#if HAVE_TOOLBAR_DROPDOWN_MENU
toolAddCard = tb->AddTool(ID_CARD_ADD, _(""), load_resource_tool_image(_("card_add")), wxNullBitmap, wxITEM_DROPDOWN,_TOOLTIP_("add card"), _HELP_("add card"));
toolAddCard->SetDropdownMenu(makeAddCardsSubmenu(true));
#else
tb->AddTool(ID_CARD_ADD, _(""), load_resource_tool_image(_("card_add")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("add card"), _HELP_("add card"));
#endif
tb->AddTool(ID_CARD_REMOVE, _(""), load_resource_tool_image(_("card_del")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("remove card"), _HELP_("remove card"));
tb->AddSeparator();
#if HAVE_TOOLBAR_DROPDOWN_MENU
wxToolBarToolBase* rot = tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap, wxITEM_DROPDOWN, _TOOLTIP_("rotate card"), _HELP_("rotate card"));
IconMenu* menuRotate = new IconMenu();
menuRotate->Append(ID_CARD_ROTATE_0, _("card_rotate_0"), _MENU_("rotate 0"), _HELP_("rotate 0"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_270, _("card_rotate_270"), _MENU_("rotate 270"), _HELP_("rotate 270"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_90, _("card_rotate_90"), _MENU_("rotate 90"), _HELP_("rotate 90"), wxITEM_CHECK);
menuRotate->Append(ID_CARD_ROTATE_180, _("card_rotate_180"), _MENU_("rotate 180"), _HELP_("rotate 180"), wxITEM_CHECK);
rot->SetDropdownMenu(menuRotate);
#else
tb->AddTool(ID_CARD_ROTATE, _(""), load_resource_tool_image(_("card_rotate")), wxNullBitmap,wxITEM_NORMAL, _TOOLTIP_("rotate card"), _HELP_("rotate card"));
#endif
// Filter/search textbox
tb->AddSeparator();
if (!filter) filter = new FilterCtrl(tb, ID_CARD_FILTER, _LABEL_("search cards"));
tb->AddControl(filter);
tb->Realize();
// Menus
mb->Insert(2, menuCard, _MENU_("cards"));
mb->Insert(3, menuFormat, _MENU_("format"));
}
void CardsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
tb->DeleteTool(ID_FORMAT_BOLD);
tb->DeleteTool(ID_FORMAT_ITALIC);
tb->DeleteTool(ID_FORMAT_SYMBOL);
tb->DeleteTool(ID_FORMAT_REMINDER);
tb->DeleteTool(ID_CARD_ADD);
tb->DeleteTool(ID_CARD_REMOVE);
tb->DeleteTool(ID_CARD_ROTATE);
tb->DeleteTool(filter->GetId()); filter = nullptr;
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(12); // delete separator
tb->DeleteToolByPos(12); // delete separator
tb->DeleteToolByPos(12); // delete separator
// Menus
mb->Remove(3);
mb->Remove(2);
toolAddCard = nullptr;
// Toolbar
tb->DeleteTool(ID_FORMAT_BOLD);
tb->DeleteTool(ID_FORMAT_ITALIC);
tb->DeleteTool(ID_FORMAT_SYMBOL);
tb->DeleteTool(ID_FORMAT_REMINDER);
tb->DeleteTool(ID_CARD_ADD);
tb->DeleteTool(ID_CARD_REMOVE);
tb->DeleteTool(ID_CARD_ROTATE);
tb->DeleteTool(filter->GetId()); filter = nullptr;
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(12); // delete separator
tb->DeleteToolByPos(12); // delete separator
tb->DeleteToolByPos(12); // delete separator
// Menus
mb->Remove(3);
mb->Remove(2);
toolAddCard = nullptr;
}
void CardsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
switch (ev.GetId()) {
case ID_CARD_PREV: ev.Enable(card_list->canSelectPrevious()); break;
case ID_CARD_NEXT: ev.Enable(card_list->canSelectNext()); break;
case ID_CARD_ROTATE_0: case ID_CARD_ROTATE_90: case ID_CARD_ROTATE_180: case ID_CARD_ROTATE_270: {
StyleSheetSettings& ss = settings.stylesheetSettingsFor(set->stylesheetFor(card_list->getCard()));
int a = ev.GetId() == ID_CARD_ROTATE_0 ? 0
: ev.GetId() == ID_CARD_ROTATE_90 ? 90
: ev.GetId() == ID_CARD_ROTATE_180 ? 180
: 270;
ev.Check(ss.card_angle() == a);
break;
}
case ID_CARD_ADD_MULT: {
ev.Enable(insertManyCardsMenu->GetSubMenu() != nullptr);
break;
}
case ID_CARD_REMOVE: ev.Enable(card_list->canDelete()); break;
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
if (focused_control(this) == ID_EDITOR) {
ev.Enable(editor->canFormat(ev.GetId()));
ev.Check (editor->hasFormat(ev.GetId()));
} else {
ev.Enable(false);
ev.Check(false);
}
break;
}
case ID_COLLAPSE_NOTES: {
bool collapse = notes->GetSize().y > 0;
collapse_notes->loadBitmaps(collapse ? _("btn_collapse") : _("btn_expand"));
collapse_notes->SetHelpText(collapse ? _HELP_("collapse notes") : _HELP_("expand notes"));
break;
}
switch (ev.GetId()) {
case ID_CARD_PREV: ev.Enable(card_list->canSelectPrevious()); break;
case ID_CARD_NEXT: ev.Enable(card_list->canSelectNext()); break;
case ID_CARD_ROTATE_0: case ID_CARD_ROTATE_90: case ID_CARD_ROTATE_180: case ID_CARD_ROTATE_270: {
StyleSheetSettings& ss = settings.stylesheetSettingsFor(set->stylesheetFor(card_list->getCard()));
int a = ev.GetId() == ID_CARD_ROTATE_0 ? 0
: ev.GetId() == ID_CARD_ROTATE_90 ? 90
: ev.GetId() == ID_CARD_ROTATE_180 ? 180
: 270;
ev.Check(ss.card_angle() == a);
break;
}
case ID_CARD_ADD_MULT: {
ev.Enable(insertManyCardsMenu->GetSubMenu() != nullptr);
break;
}
case ID_CARD_REMOVE: ev.Enable(card_list->canDelete()); break;
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
if (focused_control(this) == ID_EDITOR) {
ev.Enable(editor->canFormat(ev.GetId()));
ev.Check (editor->hasFormat(ev.GetId()));
} else {
ev.Enable(false);
ev.Check(false);
}
break;
}
case ID_COLLAPSE_NOTES: {
bool collapse = notes->GetSize().y > 0;
collapse_notes->loadBitmaps(collapse ? _("btn_collapse") : _("btn_expand"));
collapse_notes->SetHelpText(collapse ? _HELP_("collapse notes") : _HELP_("expand notes"));
break;
}
#if 0 //ifdef __WXGTK__ //crashes on GTK
case ID_INSERT_SYMBOL: ev.Enable(false); break;
case ID_INSERT_SYMBOL: ev.Enable(false); break;
#else
case ID_INSERT_SYMBOL: {
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
ev.Enable(menu);
break;
}
case ID_INSERT_SYMBOL: {
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
ev.Enable(menu);
break;
}
#endif
}
}
}
void CardsPanel::onMenuOpen(wxMenuEvent& ev) {
if (ev.GetMenu() != menuFormat) return;
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
if (insertSymbolMenu->GetSubMenu() != menu || (menu && menu->GetParent() != menuFormat)) {
// re-add the menu
fprintf(stderr,"insert1 %p %p\n", menuFormat,insertSymbolMenu);fflush(stderr);
menuFormat->Remove(ID_INSERT_SYMBOL);
fprintf(stderr,"insert2\n");fflush(stderr);
insertSymbolMenu->SetSubMenu(menu);
fprintf(stderr,"insert3\n");fflush(stderr);
menuFormat->Append(insertSymbolMenu);
fprintf(stderr,"insert4\n");fflush(stderr);
}
if (ev.GetMenu() != menuFormat) return;
wxMenu* menu = editor->getMenu(ID_INSERT_SYMBOL);
if (insertSymbolMenu->GetSubMenu() != menu || (menu && menu->GetParent() != menuFormat)) {
// re-add the menu
fprintf(stderr,"insert1 %p %p\n", menuFormat,insertSymbolMenu);fflush(stderr);
menuFormat->Remove(ID_INSERT_SYMBOL);
fprintf(stderr,"insert2\n");fflush(stderr);
insertSymbolMenu->SetSubMenu(menu);
fprintf(stderr,"insert3\n");fflush(stderr);
menuFormat->Append(insertSymbolMenu);
fprintf(stderr,"insert4\n");fflush(stderr);
}
}
void CardsPanel::onCommand(int id) {
switch (id) {
case ID_CARD_PREV:
// Note: Forwarded events may cause this to occur even at the top.
if (card_list->canSelectPrevious()) card_list->selectPrevious();
break;
case ID_CARD_NEXT:
// Note: Forwarded events may cause this to occur even at the bottom.
if (card_list->canSelectNext()) card_list->selectNext();
break;
case ID_CARD_ADD:
set->actions.addAction(new AddCardAction(*set));
break;
case ID_CARD_REMOVE:
card_list->doDelete();
break;
case ID_CARD_ROTATE:
case ID_CARD_ROTATE_0: case ID_CARD_ROTATE_90: case ID_CARD_ROTATE_180: case ID_CARD_ROTATE_270: {
StyleSheetSettings& ss = settings.stylesheetSettingsFor(set->stylesheetFor(card_list->getCard()));
ss.card_angle.assign(
id == ID_CARD_ROTATE ? sane_fmod(ss.card_angle() + 90, 360)
: id == ID_CARD_ROTATE_0 ? 0
: id == ID_CARD_ROTATE_90 ? 90
: id == ID_CARD_ROTATE_180 ? 180
: 270
);
set->actions.tellListeners(DisplayChangeAction(),true);
break;
}
case ID_SELECT_COLUMNS: {
card_list->selectColumns();
}
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
if (focused_control(this) == ID_EDITOR) {
editor->doFormat(id);
}
break;
}
case ID_COLLAPSE_NOTES: {
bool collapse = notes->GetSize().y > 0;
if (collapse) {
splitter->SetSashPosition(-1);
card_list->SetFocus();
} else {
splitter->SetSashPosition(-150);
notes->SetFocus();
}
break;
}
case ID_CARD_FILTER: {
// card filter has changed, update the card list
card_list->setFilter(filter->getFilter<Card>());
break;
}
default: {
if (id >= ID_INSERT_SYMBOL_MENU_MIN && id <= ID_INSERT_SYMBOL_MENU_MAX) {
// pass on to editor
editor->onCommand(id);
} else if (id >= ID_ADD_CARDS_MENU_MIN && id <= ID_ADD_CARDS_MENU_MAX) {
// add multiple cards
AddCardsScriptP script = set->game->add_cards_scripts.at(id - ID_ADD_CARDS_MENU_MIN);
script->perform(*set);
}
}
}
switch (id) {
case ID_CARD_PREV:
// Note: Forwarded events may cause this to occur even at the top.
if (card_list->canSelectPrevious()) card_list->selectPrevious();
break;
case ID_CARD_NEXT:
// Note: Forwarded events may cause this to occur even at the bottom.
if (card_list->canSelectNext()) card_list->selectNext();
break;
case ID_CARD_ADD:
set->actions.addAction(new AddCardAction(*set));
break;
case ID_CARD_REMOVE:
card_list->doDelete();
break;
case ID_CARD_ROTATE:
case ID_CARD_ROTATE_0: case ID_CARD_ROTATE_90: case ID_CARD_ROTATE_180: case ID_CARD_ROTATE_270: {
StyleSheetSettings& ss = settings.stylesheetSettingsFor(set->stylesheetFor(card_list->getCard()));
ss.card_angle.assign(
id == ID_CARD_ROTATE ? sane_fmod(ss.card_angle() + 90, 360)
: id == ID_CARD_ROTATE_0 ? 0
: id == ID_CARD_ROTATE_90 ? 90
: id == ID_CARD_ROTATE_180 ? 180
: 270
);
set->actions.tellListeners(DisplayChangeAction(),true);
break;
}
case ID_SELECT_COLUMNS: {
card_list->selectColumns();
}
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: case ID_FORMAT_REMINDER: {
if (focused_control(this) == ID_EDITOR) {
editor->doFormat(id);
}
break;
}
case ID_COLLAPSE_NOTES: {
bool collapse = notes->GetSize().y > 0;
if (collapse) {
splitter->SetSashPosition(-1);
card_list->SetFocus();
} else {
splitter->SetSashPosition(-150);
notes->SetFocus();
}
break;
}
case ID_CARD_FILTER: {
// card filter has changed, update the card list
card_list->setFilter(filter->getFilter<Card>());
break;
}
default: {
if (id >= ID_INSERT_SYMBOL_MENU_MIN && id <= ID_INSERT_SYMBOL_MENU_MAX) {
// pass on to editor
editor->onCommand(id);
} else if (id >= ID_ADD_CARDS_MENU_MIN && id <= ID_ADD_CARDS_MENU_MAX) {
// add multiple cards
AddCardsScriptP script = set->game->add_cards_scripts.at(id - ID_ADD_CARDS_MENU_MIN);
script->perform(*set);
}
}
}
}
// ----------------------------------------------------------------------------- : Actions
bool CardsPanel::wantsToHandle(const Action&, bool undone) const {
return false;
return false;
}
// ----------------------------------------------------------------------------- : Clipboard
// determine what control to use for clipboard actions
#define CUT_COPY_PASTE(op,return) \
int id = focused_control(this); \
if (id == ID_EDITOR) { return editor->op(); } \
else if (id == ID_CARD_LIST) { return card_list->op(); } \
else if (id == ID_NOTES) { return notes->op(); } \
else { return false; }
#define CUT_COPY_PASTE(op,return) \
int id = focused_control(this); \
if (id == ID_EDITOR) { return editor->op(); } \
else if (id == ID_CARD_LIST) { return card_list->op(); } \
else if (id == ID_NOTES) { return notes->op(); } \
else { return false; }
bool CardsPanel::canCut() const { CUT_COPY_PASTE(canCut, return) }
bool CardsPanel::canCopy() const { CUT_COPY_PASTE(canCopy, return) }
@@ -398,99 +398,99 @@ void CardsPanel::doCopy() { CUT_COPY_PASTE(doCopy, return (void)) }
// always alow pasting cards, even if something else is selected
bool CardsPanel::canPaste() const {
if (card_list->canPaste()) return true;
int id = focused_control(this);
if (id == ID_EDITOR) return editor->canPaste();
else if (id == ID_NOTES) return notes->canPaste();
else return false;
if (card_list->canPaste()) return true;
int id = focused_control(this);
if (id == ID_EDITOR) return editor->canPaste();
else if (id == ID_NOTES) return notes->canPaste();
else return false;
}
void CardsPanel::doPaste() {
if (card_list->canPaste()) {
card_list->doPaste();
} else {
int id = focused_control(this);
if (id == ID_EDITOR) editor->doPaste();
else if (id == ID_NOTES) notes->doPaste();
}
if (card_list->canPaste()) {
card_list->doPaste();
} else {
int id = focused_control(this);
if (id == ID_EDITOR) editor->doPaste();
else if (id == ID_NOTES) notes->doPaste();
}
}
// ----------------------------------------------------------------------------- : Searching
class CardsPanel::SearchFindInfo : public FindInfo {
public:
SearchFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) {
// Select the card
panel.card_list->setCard(card);
return true;
}
SearchFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) {
// Select the card
panel.card_list->setCard(card);
return true;
}
private:
CardsPanel& panel;
CardsPanel& panel;
};
class CardsPanel::ReplaceFindInfo : public FindInfo {
public:
ReplaceFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) {
// Select the card
panel.card_list->setCard(card);
// Replace
if (was_selection) {
panel.editor->insert(escape(what.GetReplaceString()), _("Replace"));
return false;
} else {
return true;
}
}
virtual bool searchSelection() const { return true; }
ReplaceFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos, bool was_selection) {
// Select the card
panel.card_list->setCard(card);
// Replace
if (was_selection) {
panel.editor->insert(escape(what.GetReplaceString()), _("Replace"));
return false;
} else {
return true;
}
}
virtual bool searchSelection() const { return true; }
private:
CardsPanel& panel;
CardsPanel& panel;
};
bool CardsPanel::doFind(wxFindReplaceData& what) {
SearchFindInfo find(*this, what);
return search(find, false);
SearchFindInfo find(*this, what);
return search(find, false);
}
bool CardsPanel::doReplace(wxFindReplaceData& what) {
ReplaceFindInfo find(*this, what);
return search(find, false);
ReplaceFindInfo find(*this, what);
return search(find, false);
}
bool CardsPanel::doReplaceAll(wxFindReplaceData& what) {
return false; // TODO
return false; // TODO
}
bool CardsPanel::search(FindInfo& find, bool from_start) {
bool include = from_start;
CardP current = card_list->getCard();
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
CardP card = card_list->getCard( (long) (find.forward() ? i : set->cards.size() - i - 1) );
if (card == current) include = true;
if (include) {
editor->setCard(card);
if (editor->search(find, from_start || card != current)) {
return true; // done
}
}
}
editor->setCard(current);
return false;
bool include = from_start;
CardP current = card_list->getCard();
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
CardP card = card_list->getCard( (long) (find.forward() ? i : set->cards.size() - i - 1) );
if (card == current) include = true;
if (include) {
editor->setCard(card);
if (editor->search(find, from_start || card != current)) {
return true; // done
}
}
}
editor->setCard(current);
return false;
}
// ----------------------------------------------------------------------------- : Selection
CardP CardsPanel::selectedCard() const {
return card_list->getCard();
return card_list->getCard();
}
void CardsPanel::selectCard(const CardP& card) {
if (!set) return; // we want onChangeSet first
card_list->setCard(card);
editor->setCard(card);
notes->setValue(card ? &card->notes : nullptr);
Layout();
updateNotesPosition();
if (!set) return; // we want onChangeSet first
card_list->setCard(card);
editor->setCard(card);
notes->setValue(card ? &card->notes : nullptr);
Layout();
updateNotesPosition();
}
void CardsPanel::selectFirstCard() {
if (!set) return; // we want onChangeSet first
card_list->selectFirst();
if (!set) return; // we want onChangeSet first
card_list->selectFirst();
}
+66 -66
View File
@@ -26,77 +26,77 @@ class FilterCtrl;
/// A card list and card editor panel
class CardsPanel : public SetWindowPanel {
public:
CardsPanel(Window* parent, int id);
~CardsPanel();
virtual void onChangeSet();
// --------------------------------------------------- : UI
virtual void initUI (wxToolBar* tb, wxMenuBar* mb);
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
virtual void onMenuOpen(wxMenuEvent&);
// --------------------------------------------------- : Actions
virtual bool wantsToHandle(const Action&, bool undone) const;
CardsPanel(Window* parent, int id);
~CardsPanel();
// --------------------------------------------------- : Clipboard
virtual bool canCut() const;
virtual bool canCopy() const;
virtual bool canPaste() const;
virtual void doCut();
virtual void doCopy();
virtual void doPaste();
// --------------------------------------------------- : Searching (find/replace)
virtual void onChangeSet();
// --------------------------------------------------- : UI
virtual void initUI (wxToolBar* tb, wxMenuBar* mb);
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
virtual void onMenuOpen(wxMenuEvent&);
// --------------------------------------------------- : Actions
virtual bool wantsToHandle(const Action&, bool undone) const;
// --------------------------------------------------- : Clipboard
virtual bool canCut() const;
virtual bool canCopy() const;
virtual bool canPaste() const;
virtual void doCut();
virtual void doCopy();
virtual void doPaste();
// --------------------------------------------------- : Searching (find/replace)
virtual bool canFind() const { return true; }
virtual bool canReplace() const { return true; }
virtual bool doFind (wxFindReplaceData&);
virtual bool doReplace (wxFindReplaceData&);
virtual bool doReplaceAll(wxFindReplaceData&);
virtual bool canFind() const { return true; }
virtual bool canReplace() const { return true; }
virtual bool doFind (wxFindReplaceData&);
virtual bool doReplace (wxFindReplaceData&);
virtual bool doReplaceAll(wxFindReplaceData&);
private:
/// Do a search or replace action for the given FindInfo in all cards
bool search(FindInfo& find, bool from_start);
class SearchFindInfo;
class ReplaceFindInfo;
friend class CardsPanel::SearchFindInfo;
friend class CardsPanel::ReplaceFindInfo;
/// Do a search or replace action for the given FindInfo in all cards
bool search(FindInfo& find, bool from_start);
class SearchFindInfo;
class ReplaceFindInfo;
friend class CardsPanel::SearchFindInfo;
friend class CardsPanel::ReplaceFindInfo;
public:
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
virtual void selectFirstCard();
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
virtual void selectFirstCard();
private:
// --------------------------------------------------- : Controls
wxSizer* s_left;
wxSplitterWindow* splitter;
DataEditor* editor;
FilteredImageCardList* card_list;
Panel* nodes_panel;
TextCtrl* notes;
HoverButton* collapse_notes;
FilterCtrl* filter;
bool notes_below_editor;
/// Move the notes panel below the editor or below the card list
void updateNotesPosition();
// before Layout, call updateNotesPosition.
// NOTE: docs say this function returns void, but the code says bool
virtual bool Layout();
// --------------------------------------------------- : Menus & tools
IconMenu* menuCard, *menuFormat;
wxToolBarToolBase* toolAddCard;
wxMenuItem* insertSymbolMenu; // owned by menuFormat, but submenu owned by SymbolFont
wxMenuItem* insertManyCardsMenu; // owned my menuCard, but submenu can be changed
wxMenu* makeAddCardsSubmenu(bool add_single_card_option);
// --------------------------------------------------- : Controls
wxSizer* s_left;
wxSplitterWindow* splitter;
DataEditor* editor;
FilteredImageCardList* card_list;
Panel* nodes_panel;
TextCtrl* notes;
HoverButton* collapse_notes;
FilterCtrl* filter;
bool notes_below_editor;
/// Move the notes panel below the editor or below the card list
void updateNotesPosition();
// before Layout, call updateNotesPosition.
// NOTE: docs say this function returns void, but the code says bool
virtual bool Layout();
// --------------------------------------------------- : Menus & tools
IconMenu* menuCard, *menuFormat;
wxToolBarToolBase* toolAddCard;
wxMenuItem* insertSymbolMenu; // owned by menuFormat, but submenu owned by SymbolFont
wxMenuItem* insertManyCardsMenu; // owned my menuCard, but submenu can be changed
wxMenu* makeAddCardsSubmenu(bool add_single_card_option);
};
// ----------------------------------------------------------------------------- : EOF
+390 -390
View File
@@ -25,420 +25,420 @@ DECLARE_TYPEOF_COLLECTION(ConsoleMessageP);
class ConsoleMessage : public IntrusivePtrBase<ConsoleMessage> {
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)
{}
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)));
}
bool have_selection() const {
return selection < messages.size();
}
bool canCopy() const {
return have_selection();
}
bool doCopy() {
if (selection >= messages.size()) return false;
ConsoleMessage const& msg = *messages[selection];
if (!wxTheClipboard->Open()) return false;
bool ok = false;
if (msg.bitmap.Ok()) {
ok = wxTheClipboard->SetData(new wxBitmapDataObject(msg.bitmap));
} else {
ok = wxTheClipboard->SetData(new wxTextDataObject(msg.text));
}
wxTheClipboard->Close();
return ok;
}
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)));
}
bool have_selection() const {
return selection < messages.size();
}
bool canCopy() const {
return have_selection();
}
bool doCopy() {
if (selection >= messages.size()) return false;
ConsoleMessage const& msg = *messages[selection];
if (!wxTheClipboard->Open()) return false;
bool ok = false;
if (msg.bitmap.Ok()) {
ok = wxTheClipboard->SetData(new wxBitmapDataObject(msg.bitmap));
} else {
ok = wxTheClipboard->SetData(new wxTextDataObject(msg.text));
}
wxTheClipboard->Close();
return ok;
}
private:
DECLARE_EVENT_TABLE();
// --------------------------------------------------- : Data
// the messages
vector<ConsoleMessageP> 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);
ev.Skip(); // for focus
}
size_t 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
const int LIST_SPACING = 1;
const int ICON_PADDING = 3;
const int TEXT_PADDING_LEFT = ICON_PADDING + 16 + 4;
const int TEXT_PADDING_RIGHT = 4;
const int TEXT_PADDING_TOP = 4;
const int TEXT_PADDING_BOTTOM = 2;
const int TEXT_LINE_SPACING = 1;
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
DECLARE_EVENT_TABLE();
// --------------------------------------------------- : Data
// the messages
vector<ConsoleMessageP> 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);
ev.Skip(); // for focus
}
size_t 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
const int LIST_SPACING = 1;
const int ICON_PADDING = 3;
const int TEXT_PADDING_LEFT = ICON_PADDING + 16 + 4;
const int TEXT_PADDING_RIGHT = 4;
const int TEXT_PADDING_TOP = 4;
const int TEXT_PADDING_BOTTOM = 2;
const int TEXT_LINE_SPACING = 1;
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)
EVT_PAINT(MessageCtrl::onPaint)
EVT_LEFT_DOWN(MessageCtrl::onLeftDown)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : ConsolePanel
ConsolePanel::ConsolePanel(Window* parent, int id)
: SetWindowPanel(parent, id)
, is_active_window(false)
, blinker_state(0)
, blinker_timer(this)
, messages(nullptr)
, entry(nullptr)
: SetWindowPanel(parent, id)
, is_active_window(false)
, blinker_state(0)
, blinker_timer(this)
, messages(nullptr)
, entry(nullptr)
{
// init controls
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
messages = new MessageCtrl(splitter, ID_MESSAGE_LIST);
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);
// init controls
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
messages = new MessageCtrl(splitter, ID_MESSAGE_LIST);
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
// TODO
}
// ----------------------------------------------------------------------------- : UI
void ConsolePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
// Menus
// focus on entry
entry->SetFocus();
// stop blinker
is_active_window = true;
stop_blinker();
// Menus
// focus on entry
entry->SetFocus();
// stop blinker
is_active_window = true;
stop_blinker();
}
void ConsolePanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
// Menus
// we are no longer active, allow blinker
is_active_window = false;
// Toolbar
// Menus
// we are no longer active, allow blinker
is_active_window = false;
}
void ConsolePanel::onUpdateUI(wxUpdateUIEvent& ev) {
if (ev.GetId() == ID_EVALUATE) {
ev.Enable(!entry->GetValue().empty());
}
if (ev.GetId() == ID_EVALUATE) {
ev.Enable(!entry->GetValue().empty());
}
}
void ConsolePanel::onEnter(wxCommandEvent& ev) {
onCommand(ID_EVALUATE);
onCommand(ID_EVALUATE);
}
void ConsolePanel::onCommand(int id) {
if (id == ID_EVALUATE) {
exec(entry->GetValue());
entry->SetValue(_(""));
}
if (id == ID_EVALUATE) {
exec(entry->GetValue());
entry->SetValue(_(""));
}
}
void ConsolePanel::onIdle(wxIdleEvent&) {
get_pending_errors();
get_pending_errors();
}
void ConsolePanel::get_pending_errors() {
// The panel might not be initialized yet, in particular, construction of controls might fail, which results in a popup dialog with an event loop
if (!messages) return;
// 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
if (!is_active_window) {
new_errors_since_last_view = max(new_errors_since_last_view,type);
start_blinker();
}
}
// The panel might not be initialized yet, in particular, construction of controls might fail, which results in a popup dialog with an event loop
if (!messages) return;
// 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
if (!is_active_window) {
new_errors_since_last_view = max(new_errors_since_last_view,type);
start_blinker();
}
}
}
void ConsolePanel::exec(String const& command) {
if (command.empty()) return;
// add input message
messages->add_message(MESSAGE_INPUT, command);
try {
// parse command
vector<ScriptParseError> 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 / 255.0);
message->bitmap = wxBitmap(image);
} else {
message->text = result->toCode();
}
messages->add_message(message);
} catch (ScriptError const& e) {
messages->add_message(MESSAGE_ERROR, e.what());
}
if (command.empty()) return;
// add input message
messages->add_message(MESSAGE_INPUT, command);
try {
// parse command
vector<ScriptParseError> 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 / 255.0);
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)
EVT_TIMER(wxID_ANY,ConsolePanel::onTimer)
EVT_TEXT_ENTER(wxID_ANY,ConsolePanel::onEnter)
EVT_IDLE(ConsolePanel::onIdle)
EVT_TIMER(wxID_ANY,ConsolePanel::onTimer)
END_EVENT_TABLE ()
// ----------------------------------------------------------------------------- : Clipboard
// determine what control to use for clipboard actions
#define CUT_COPY_PASTE(op,return) \
int id = focused_control(this); \
if (id == ID_MESSAGE_LIST) { return messages->op(); } \
else { return false; }
#define CUT_COPY_PASTE(op,return) \
int id = focused_control(this); \
if (id == ID_MESSAGE_LIST) { return messages->op(); } \
else { return false; }
bool ConsolePanel::canCut() const { return false; }
bool ConsolePanel::canCopy() const { CUT_COPY_PASTE(canCopy, return) }
@@ -448,36 +448,36 @@ void ConsolePanel::doCopy() { CUT_COPY_PASTE(doCopy, return (void)) }
// ----------------------------------------------------------------------------- : Annoying blinking icon thing
void ConsolePanel::start_blinker() {
if (new_errors_since_last_view) {
blinker_state = 0;
update_blinker();
if (blinker_state < MAX_BLINKS) {
blinker_timer.Start(BLINK_TIME);
}
}
if (new_errors_since_last_view) {
blinker_state = 0;
update_blinker();
if (blinker_state < MAX_BLINKS) {
blinker_timer.Start(BLINK_TIME);
}
}
}
void ConsolePanel::stop_blinker() {
blinker_state = 0;
new_errors_since_last_view = static_cast<MessageType>(0);
blinker_timer.Stop();
update_blinker();
blinker_state = 0;
new_errors_since_last_view = static_cast<MessageType>(0);
blinker_timer.Stop();
update_blinker();
}
void ConsolePanel::onTimer(wxTimerEvent&) {
blinker_state++;
if (blinker_state >= MAX_BLINKS) {
blinker_timer.Stop();
}
update_blinker();
blinker_state++;
if (blinker_state >= MAX_BLINKS) {
blinker_timer.Stop();
}
update_blinker();
}
void ConsolePanel::update_blinker() {
SetWindow* parent = static_cast<SetWindow*>(GetParent());
if (blinker_state % 2 == 1 || !new_errors_since_last_view) {
parent->setPanelIcon(this, load_resource_image(_("tool/window_console")));
} else if (new_errors_since_last_view == MESSAGE_INFO) {
parent->setPanelIcon(this, load_resource_image(_("message_information")));
} else if (new_errors_since_last_view == MESSAGE_WARNING) {
parent->setPanelIcon(this, load_resource_image(_("message_warning")));
} else {
parent->setPanelIcon(this, load_resource_image(_("message_error")));
}
SetWindow* parent = static_cast<SetWindow*>(GetParent());
if (blinker_state % 2 == 1 || !new_errors_since_last_view) {
parent->setPanelIcon(this, load_resource_image(_("tool/window_console")));
} else if (new_errors_since_last_view == MESSAGE_INFO) {
parent->setPanelIcon(this, load_resource_image(_("message_information")));
} else if (new_errors_since_last_view == MESSAGE_WARNING) {
parent->setPanelIcon(this, load_resource_image(_("message_warning")));
} else {
parent->setPanelIcon(this, load_resource_image(_("message_error")));
}
}
+41 -41
View File
@@ -20,49 +20,49 @@ class TextCtrl;
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 void doCopy();
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 void doCopy();
protected:
virtual void onChangeSet();
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);
// notification of new messages
bool is_active_window;
MessageType new_errors_since_last_view;
int blinker_state;
wxTimer blinker_timer;
static const int MAX_BLINKS = 6;
static const int BLINK_TIME = 1000;
void stop_blinker();
void start_blinker();
void update_blinker();
void onTimer(wxTimerEvent&);
DECLARE_EVENT_TABLE();
wxSplitterWindow* splitter;
MessageCtrl* messages;
wxPanel* entry_panel;
wxTextCtrl* entry;
void get_pending_errors();
void exec(String const& code);
// notification of new messages
bool is_active_window;
MessageType new_errors_since_last_view;
int blinker_state;
wxTimer blinker_timer;
static const int MAX_BLINKS = 6;
static const int BLINK_TIME = 1000;
void stop_blinker();
void start_blinker();
void update_blinker();
void onTimer(wxTimerEvent&);
};
// ----------------------------------------------------------------------------- : EOF
+289 -289
View File
@@ -30,241 +30,241 @@ DECLARE_TYPEOF_COLLECTION(KeywordModeP);
// ----------------------------------------------------------------------------- : KeywordsPanel
KeywordsPanel::KeywordsPanel(Window* parent, int id)
: SetWindowPanel(parent, id)
, menuKeyword(nullptr)
: SetWindowPanel(parent, id)
, menuKeyword(nullptr)
{
// delayed initialization by initControls()
// delayed initialization by initControls()
}
void KeywordsPanel::initControls() {
// init controls
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
list = new KeywordList(splitter, ID_KEYWORD_LIST);
panel = new Panel(splitter, wxID_ANY);
keyword = new TextCtrl(panel, ID_KEYWORD, false);
mode = new wxChoice(panel, ID_KEYWORD_MODE, wxDefaultPosition, wxDefaultSize, 0, nullptr);
match = new TextCtrl(panel, ID_MATCH, false);
add_param = new wxButton(panel, ID_KEYWORD_ADD_PARAM, _BUTTON_("insert parameter"));
reminder = new TextCtrl(panel, ID_REMINDER, true); // allow multiline for wordwrap
ref_param = new wxButton(panel, ID_KEYWORD_REF_PARAM, _BUTTON_("refer parameter"));
rules = new TextCtrl(panel, ID_RULES, true);
errors = new wxStaticText(panel, wxID_ANY, _(""));
filter = nullptr;
errors->SetForegroundColour(*wxRED);
// warning about fixed keywords
fixedL = new wxStaticText(panel, wxID_ANY, _(""));
wxStaticBitmap* fixedI = new wxStaticBitmap(panel, wxID_ANY, wxArtProvider::GetBitmap(wxART_WARNING));
fixed = new wxBoxSizer(wxVERTICAL);
wxSizer* s0 = new wxBoxSizer(wxHORIZONTAL);
s0->Add(fixedI, 0, wxALIGN_CENTER | wxRIGHT, 10);
s0->Add(fixedL, 0, wxALIGN_CENTER_VERTICAL);
fixed->Add(new wxStaticLine(panel), 0, wxEXPAND | wxBOTTOM, 8);
fixed->Add(s0, 0, (wxALL & ~wxTOP) | wxALIGN_CENTER, 8);
fixed->Add(new wxStaticLine(panel), 0, wxEXPAND | wxBOTTOM, 8);
// init sizer for panel
sp = new wxBoxSizer(wxVERTICAL);
sp->Add(fixed, 0, wxEXPAND); sp->Show(fixed,false);
wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0);
s1->Add(keyword, 0, wxEXPAND | wxTOP, 2);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP, 2);
s1->Add(mode, 0, wxEXPAND | wxTOP, 2);
sp->Add(s1, 0, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0);
s2->Add(match, 0, wxEXPAND | wxTOP, 2);
s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP, 2);
sp->Add(s2, 0, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s3 = new wxBoxSizer(wxVERTICAL);
s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0);
s3->Add(reminder, 1, wxEXPAND | wxTOP, 2);
s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP, 2);
s3->Add(errors, 0, wxEXPAND | wxTOP, 4);
//s3->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxTOP, 6);
sp->Add(s3, 1, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s4 = new wxBoxSizer(wxVERTICAL);
s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0);
s4->Add(rules, 1, wxEXPAND | wxTOP, 2);
sp->Add(s4, 1, wxEXPAND | wxLEFT, 2);
panel->SetSizer(sp);
// init splitter
splitter->SetMinimumPaneSize(100);
splitter->SetSashGravity(0.5);
splitter->SplitVertically(list, panel);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
//s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove
/* wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(list_active, 1, wxEXPAND);
s2->Add(list_inactive, 1, wxEXPAND);*/
// init menus
menuKeyword = new IconMenu();
menuKeyword->Append(ID_KEYWORD_PREV, _MENU_("previous keyword"), _HELP_("previous keyword"));
menuKeyword->Append(ID_KEYWORD_NEXT, _MENU_("next keyword"), _HELP_("next keyword"));
menuKeyword->AppendSeparator();
menuKeyword->Append(ID_KEYWORD_ADD, _("keyword_add"), _MENU_("add keyword"), _HELP_("add keyword"));
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
menuKeyword->Append(ID_KEYWORD_REMOVE, _("keyword_del"), _MENU_("remove keyword")+_(" "),_HELP_("remove keyword"));
// init controls
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
list = new KeywordList(splitter, ID_KEYWORD_LIST);
panel = new Panel(splitter, wxID_ANY);
keyword = new TextCtrl(panel, ID_KEYWORD, false);
mode = new wxChoice(panel, ID_KEYWORD_MODE, wxDefaultPosition, wxDefaultSize, 0, nullptr);
match = new TextCtrl(panel, ID_MATCH, false);
add_param = new wxButton(panel, ID_KEYWORD_ADD_PARAM, _BUTTON_("insert parameter"));
reminder = new TextCtrl(panel, ID_REMINDER, true); // allow multiline for wordwrap
ref_param = new wxButton(panel, ID_KEYWORD_REF_PARAM, _BUTTON_("refer parameter"));
rules = new TextCtrl(panel, ID_RULES, true);
errors = new wxStaticText(panel, wxID_ANY, _(""));
filter = nullptr;
errors->SetForegroundColour(*wxRED);
// warning about fixed keywords
fixedL = new wxStaticText(panel, wxID_ANY, _(""));
wxStaticBitmap* fixedI = new wxStaticBitmap(panel, wxID_ANY, wxArtProvider::GetBitmap(wxART_WARNING));
fixed = new wxBoxSizer(wxVERTICAL);
wxSizer* s0 = new wxBoxSizer(wxHORIZONTAL);
s0->Add(fixedI, 0, wxALIGN_CENTER | wxRIGHT, 10);
s0->Add(fixedL, 0, wxALIGN_CENTER_VERTICAL);
fixed->Add(new wxStaticLine(panel), 0, wxEXPAND | wxBOTTOM, 8);
fixed->Add(s0, 0, (wxALL & ~wxTOP) | wxALIGN_CENTER, 8);
fixed->Add(new wxStaticLine(panel), 0, wxEXPAND | wxBOTTOM, 8);
// init sizer for panel
sp = new wxBoxSizer(wxVERTICAL);
sp->Add(fixed, 0, wxEXPAND); sp->Show(fixed,false);
wxSizer* s1 = new wxBoxSizer(wxVERTICAL);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("keyword")+_(":")), 0);
s1->Add(keyword, 0, wxEXPAND | wxTOP, 2);
s1->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("mode")+_(":")), 0, wxTOP, 2);
s1->Add(mode, 0, wxEXPAND | wxTOP, 2);
sp->Add(s1, 0, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("match")+_(":")), 0);
s2->Add(match, 0, wxEXPAND | wxTOP, 2);
s2->Add(add_param, 0, wxALIGN_LEFT | wxTOP, 2);
sp->Add(s2, 0, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s3 = new wxBoxSizer(wxVERTICAL);
s3->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("reminder")+_(":")), 0);
s3->Add(reminder, 1, wxEXPAND | wxTOP, 2);
s3->Add(ref_param, 0, wxALIGN_LEFT | wxTOP, 2);
s3->Add(errors, 0, wxEXPAND | wxTOP, 4);
//s3->Add(new wxStaticText(panel, wxID_ANY, _("Example:")), 0, wxTOP, 6);
sp->Add(s3, 1, wxEXPAND | wxLEFT, 2);
sp->Add(new wxStaticLine(panel), 0, wxEXPAND | wxTOP | wxBOTTOM, 8);
wxSizer* s4 = new wxBoxSizer(wxVERTICAL);
s4->Add(new wxStaticText(panel, wxID_ANY, _LABEL_("rules")+_(":")), 0);
s4->Add(rules, 1, wxEXPAND | wxTOP, 2);
sp->Add(s4, 1, wxEXPAND | wxLEFT, 2);
panel->SetSizer(sp);
// init splitter
splitter->SetMinimumPaneSize(100);
splitter->SetSashGravity(0.5);
splitter->SplitVertically(list, panel);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
//s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove
/* wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(list_active, 1, wxEXPAND);
s2->Add(list_inactive, 1, wxEXPAND);*/
// init menus
menuKeyword = new IconMenu();
menuKeyword->Append(ID_KEYWORD_PREV, _MENU_("previous keyword"), _HELP_("previous keyword"));
menuKeyword->Append(ID_KEYWORD_NEXT, _MENU_("next keyword"), _HELP_("next keyword"));
menuKeyword->AppendSeparator();
menuKeyword->Append(ID_KEYWORD_ADD, _("keyword_add"), _MENU_("add keyword"), _HELP_("add keyword"));
// NOTE: space after "Del" prevents wx from making del an accellerator
// otherwise we delete a card when delete is pressed inside the editor
menuKeyword->Append(ID_KEYWORD_REMOVE, _("keyword_del"), _MENU_("remove keyword")+_(" "),_HELP_("remove keyword"));
}
KeywordsPanel::~KeywordsPanel() {
delete menuKeyword;
delete menuKeyword;
}
// ----------------------------------------------------------------------------- : UI
void KeywordsPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
// Controls
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
onChangeSet();
}
// Toolbar
tb->AddTool(ID_KEYWORD_ADD, _(""), load_resource_tool_image(_("keyword_add")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("add keyword"), _HELP_("add keyword"));
tb->AddTool(ID_KEYWORD_REMOVE, _(""), load_resource_tool_image(_("keyword_del")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("remove keyword"),_HELP_("remove keyword"));
// Filter/search textbox
tb->AddSeparator();
if (!filter) filter = new FilterCtrl(tb, ID_KEYWORD_FILTER, _LABEL_("search keywords"));
tb->AddControl(filter);
tb->Realize();
// Menus
mb->Insert(2, menuKeyword, _MENU_("keywords"));
// Controls
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
onChangeSet();
}
// Toolbar
tb->AddTool(ID_KEYWORD_ADD, _(""), load_resource_tool_image(_("keyword_add")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("add keyword"), _HELP_("add keyword"));
tb->AddTool(ID_KEYWORD_REMOVE, _(""), load_resource_tool_image(_("keyword_del")), wxNullBitmap, wxITEM_NORMAL,_TOOLTIP_("remove keyword"),_HELP_("remove keyword"));
// Filter/search textbox
tb->AddSeparator();
if (!filter) filter = new FilterCtrl(tb, ID_KEYWORD_FILTER, _LABEL_("search keywords"));
tb->AddControl(filter);
tb->Realize();
// Menus
mb->Insert(2, menuKeyword, _MENU_("keywords"));
}
void KeywordsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
tb->DeleteTool(ID_KEYWORD_ADD);
tb->DeleteTool(ID_KEYWORD_REMOVE);
tb->DeleteTool(filter->GetId()); filter = nullptr;
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(12); // delete separator
// Menus
mb->Remove(2);
// This is also a good moment to propagate changes
if (set) set->updateDelayed();
// Toolbar
tb->DeleteTool(ID_KEYWORD_ADD);
tb->DeleteTool(ID_KEYWORD_REMOVE);
tb->DeleteTool(filter->GetId()); filter = nullptr;
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(12); // delete separator
// Menus
mb->Remove(2);
// This is also a good moment to propagate changes
if (set) set->updateDelayed();
}
void KeywordsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
if (!isInitialized()) return;
switch (ev.GetId()) {
case ID_KEYWORD_PREV: ev.Enable(list->canSelectPrevious()); break;
case ID_KEYWORD_NEXT: ev.Enable(list->canSelectNext()); break;
case ID_KEYWORD_REMOVE: ev.Enable(list->getKeyword() && !list->getKeyword()->fixed); break;
}
if (!isInitialized()) return;
switch (ev.GetId()) {
case ID_KEYWORD_PREV: ev.Enable(list->canSelectPrevious()); break;
case ID_KEYWORD_NEXT: ev.Enable(list->canSelectNext()); break;
case ID_KEYWORD_REMOVE: ev.Enable(list->getKeyword() && !list->getKeyword()->fixed); break;
}
}
void KeywordsPanel::onCommand(int id) {
if (!isInitialized()) return;
switch (id) {
case ID_KEYWORD_PREV:
list->selectPrevious();
break;
case ID_KEYWORD_NEXT:
list->selectNext();
break;
case ID_KEYWORD_ADD:
set->actions.addAction(new AddKeywordAction(*set));
break;
case ID_KEYWORD_REMOVE:
if (list->canDelete()) {
// only remove set keywords
list->doDelete();
}
break;
case ID_KEYWORD_ADD_PARAM: {
wxMenu param_menu;
int id = ID_PARAM_TYPE_MIN;
FOR_EACH(p, set->game->keyword_parameter_types) {
param_menu.Append(id++, p->name, p->description);
}
add_param->PopupMenu(&param_menu, 0, add_param->GetSize().y);
break;
}
case ID_KEYWORD_REF_PARAM: {
wxMenu ref_menu;
int id = ID_PARAM_REF_MIN;
int param = 0;
FOR_EACH(p, list->getKeyword()->parameters) {
String item = String() << ++param << _(". ") << LEFT_ANGLE_BRACKET << p->name << RIGHT_ANGLE_BRACKET;
if (p->refer_scripts.empty()) {
ref_menu.Append(id++, item);
} else {
wxMenu* submenu = new wxMenu();
FOR_EACH(r, p->refer_scripts) {
submenu->Append(id++, r->name, r->description);
}
ref_menu.Append(wxID_ANY, item, submenu);
}
}
ref_param->PopupMenu(&ref_menu, 0, ref_param->GetSize().y);
break;
}
case ID_KEYWORD_FILTER: {
// keyword filter has changed, update the list
list->setFilter(filter->getFilter<Keyword>());
break;
}
default:
if (id >= ID_PARAM_TYPE_MIN && id < ID_PARAM_TYPE_MAX) {
// add parameter
KeywordParamP param = set->game->keyword_parameter_types.at(id - ID_PARAM_TYPE_MIN);
String to_insert = _("<atom-param>") + param->name + _("</atom-param>");
match->insert(to_insert, _("Insert parameter"));
} else if (id >= ID_PARAM_REF_MIN && id < ID_PARAM_REF_MAX) {
String to_insert = runRefScript(id - ID_PARAM_REF_MIN);
reminder->insert(to_insert, _("Use parameter"));
}
}
if (!isInitialized()) return;
switch (id) {
case ID_KEYWORD_PREV:
list->selectPrevious();
break;
case ID_KEYWORD_NEXT:
list->selectNext();
break;
case ID_KEYWORD_ADD:
set->actions.addAction(new AddKeywordAction(*set));
break;
case ID_KEYWORD_REMOVE:
if (list->canDelete()) {
// only remove set keywords
list->doDelete();
}
break;
case ID_KEYWORD_ADD_PARAM: {
wxMenu param_menu;
int id = ID_PARAM_TYPE_MIN;
FOR_EACH(p, set->game->keyword_parameter_types) {
param_menu.Append(id++, p->name, p->description);
}
add_param->PopupMenu(&param_menu, 0, add_param->GetSize().y);
break;
}
case ID_KEYWORD_REF_PARAM: {
wxMenu ref_menu;
int id = ID_PARAM_REF_MIN;
int param = 0;
FOR_EACH(p, list->getKeyword()->parameters) {
String item = String() << ++param << _(". ") << LEFT_ANGLE_BRACKET << p->name << RIGHT_ANGLE_BRACKET;
if (p->refer_scripts.empty()) {
ref_menu.Append(id++, item);
} else {
wxMenu* submenu = new wxMenu();
FOR_EACH(r, p->refer_scripts) {
submenu->Append(id++, r->name, r->description);
}
ref_menu.Append(wxID_ANY, item, submenu);
}
}
ref_param->PopupMenu(&ref_menu, 0, ref_param->GetSize().y);
break;
}
case ID_KEYWORD_FILTER: {
// keyword filter has changed, update the list
list->setFilter(filter->getFilter<Keyword>());
break;
}
default:
if (id >= ID_PARAM_TYPE_MIN && id < ID_PARAM_TYPE_MAX) {
// add parameter
KeywordParamP param = set->game->keyword_parameter_types.at(id - ID_PARAM_TYPE_MIN);
String to_insert = _("<atom-param>") + param->name + _("</atom-param>");
match->insert(to_insert, _("Insert parameter"));
} else if (id >= ID_PARAM_REF_MIN && id < ID_PARAM_REF_MAX) {
String to_insert = runRefScript(id - ID_PARAM_REF_MIN);
reminder->insert(to_insert, _("Use parameter"));
}
}
}
String KeywordsPanel::runRefScript(int find_i) {
int param = 0;
int i = 0;
FOR_EACH(p, list->getKeyword()->parameters) {
String param_s = String(_("param")) << ++param;
if (p->refer_scripts.empty()) {
if (i++ == find_i) {
// found it
return _("{") + param_s + _("}");
}
} else {
FOR_EACH(r, p->refer_scripts) {
if (i++ == find_i) {
Context& ctx = set->getContext();
ctx.setVariable(SCRIPT_VAR_input, to_script(param_s));
return r->script.invoke(ctx)->toString();
}
}
}
}
return wxEmptyString;
int param = 0;
int i = 0;
FOR_EACH(p, list->getKeyword()->parameters) {
String param_s = String(_("param")) << ++param;
if (p->refer_scripts.empty()) {
if (i++ == find_i) {
// found it
return _("{") + param_s + _("}");
}
} else {
FOR_EACH(r, p->refer_scripts) {
if (i++ == find_i) {
Context& ctx = set->getContext();
ctx.setVariable(SCRIPT_VAR_input, to_script(param_s));
return r->script.invoke(ctx)->toString();
}
}
}
}
return wxEmptyString;
}
// ----------------------------------------------------------------------------- : Clipboard
// determine what control to use for clipboard actions
#define CUT_COPY_PASTE(op,return,check) \
if (!isInitialized()) return false; \
int id = focused_control(this); \
if (id == ID_KEYWORD_LIST && keyword ->IsEnabled()) { return list ->op(); } \
else if (check) { return false; } \
else if (id == ID_KEYWORD && keyword ->IsEnabled()) { return keyword ->op(); } \
else if (id == ID_MATCH && match ->IsEnabled()) { return match ->op(); } \
else if (id == ID_REMINDER && reminder->IsEnabled()) { return reminder->op(); } \
else if (id == ID_RULES && rules ->IsEnabled()) { return rules ->op(); } \
else { return false; }
#define CUT_COPY_PASTE(op,return,check) \
if (!isInitialized()) return false; \
int id = focused_control(this); \
if (id == ID_KEYWORD_LIST && keyword ->IsEnabled()) { return list ->op(); } \
else if (check) { return false; } \
else if (id == ID_KEYWORD && keyword ->IsEnabled()) { return keyword ->op(); } \
else if (id == ID_MATCH && match ->IsEnabled()) { return match ->op(); } \
else if (id == ID_REMINDER && reminder->IsEnabled()) { return reminder->op(); } \
else if (id == ID_RULES && rules ->IsEnabled()) { return rules ->op(); } \
else { return false; }
bool KeywordsPanel::canCopy() const { CUT_COPY_PASTE(canCopy, return, false) }
bool KeywordsPanel::canCut() const { CUT_COPY_PASTE(canCut, return, !list->getKeyword() || list->getKeyword()->fixed) }
@@ -276,101 +276,101 @@ void KeywordsPanel::doPaste() { CUT_COPY_PASTE(doPaste, return (void), !
// ----------------------------------------------------------------------------- : Events
void KeywordsPanel::onChangeSet() {
if (!isInitialized()) return;
list->setSet(set);
// warning label (depends on game name)
fixedL->SetLabel(_LABEL_1_("standard keyword", set->game->short_name));
// init text controls
keyword ->setSet(set);
keyword ->getStyle().font.size = 16;
keyword ->getStyle().padding_bottom = 1;
keyword ->updateSize();
match ->setSet(set);
match ->getStyle().font.size = 12;
match ->getStyle().padding_bottom = 1;
match ->updateSize();
match ->getField().script = set->game->keyword_match_script;
reminder->setSet(set);
reminder->getStyle().padding_bottom = 2;
match ->getStyle().font.size = 10;
reminder->updateSize();
rules ->setSet(set);
// parameter & mode lists
add_param->Enable(false);
ref_param->Enable(false);
mode->Clear();
FOR_EACH(m, set->game->keyword_modes) {
mode->Append(m->name);
}
mode ->Enable(false);
// re-layout
panel->Layout();
if (!isInitialized()) return;
list->setSet(set);
// warning label (depends on game name)
fixedL->SetLabel(_LABEL_1_("standard keyword", set->game->short_name));
// init text controls
keyword ->setSet(set);
keyword ->getStyle().font.size = 16;
keyword ->getStyle().padding_bottom = 1;
keyword ->updateSize();
match ->setSet(set);
match ->getStyle().font.size = 12;
match ->getStyle().padding_bottom = 1;
match ->updateSize();
match ->getField().script = set->game->keyword_match_script;
reminder->setSet(set);
reminder->getStyle().padding_bottom = 2;
match ->getStyle().font.size = 10;
reminder->updateSize();
rules ->setSet(set);
// parameter & mode lists
add_param->Enable(false);
ref_param->Enable(false);
mode->Clear();
FOR_EACH(m, set->game->keyword_modes) {
mode->Append(m->name);
}
mode ->Enable(false);
// re-layout
panel->Layout();
}
void KeywordsPanel::onAction(const Action& action, bool undone) {
if (!isInitialized()) return;
TYPE_CASE(action, ValueAction) {
if (!action.card) {
{
KeywordReminderTextValue* value = dynamic_cast<KeywordReminderTextValue*>(action.valueP.get());
if (value && &value->keyword == list->getKeyword().get()) {
// the current keyword's reminder text changed
errors->SetLabel(value->errors);
}
}
{
KeywordTextValue* value = dynamic_cast<KeywordTextValue*>(action.valueP.get());
if (value && value->underlying == &list->getKeyword()->match) {
// match string changes, maybe there are parameters now
ref_param->Enable(!value->keyword.fixed && !value->keyword.parameters.empty());
}
}
}
}
TYPE_CASE(action, ChangeKeywordModeAction) {
if (&action.keyword == list->getKeyword().get()) {
// the current keyword's mode changed
mode->SetSelection((int)list->getKeyword()->findMode(set->game->keyword_modes));
}
}
if (!isInitialized()) return;
TYPE_CASE(action, ValueAction) {
if (!action.card) {
{
KeywordReminderTextValue* value = dynamic_cast<KeywordReminderTextValue*>(action.valueP.get());
if (value && &value->keyword == list->getKeyword().get()) {
// the current keyword's reminder text changed
errors->SetLabel(value->errors);
}
}
{
KeywordTextValue* value = dynamic_cast<KeywordTextValue*>(action.valueP.get());
if (value && value->underlying == &list->getKeyword()->match) {
// match string changes, maybe there are parameters now
ref_param->Enable(!value->keyword.fixed && !value->keyword.parameters.empty());
}
}
}
}
TYPE_CASE(action, ChangeKeywordModeAction) {
if (&action.keyword == list->getKeyword().get()) {
// the current keyword's mode changed
mode->SetSelection((int)list->getKeyword()->findMode(set->game->keyword_modes));
}
}
}
void KeywordsPanel::onKeywordSelect(KeywordSelectEvent& ev) {
if (ev.keyword) {
Keyword& kw = *ev.keyword;
sp->Show(fixed, kw.fixed);
keyword ->setValue(intrusive(new KeywordTextValue(keyword->getFieldP(), &kw, &kw.keyword, !kw.fixed, true)));
match ->setValue(intrusive(new KeywordTextValue(match->getFieldP(), &kw, &kw.match, !kw.fixed)));
rules ->setValue(intrusive(new KeywordTextValue(rules->getFieldP(), &kw, &kw.rules, !kw.fixed)));
intrusive_ptr<KeywordReminderTextValue> reminder_value(new KeywordReminderTextValue(*set, reminder->getFieldP(), &kw, !kw.fixed));
reminder->setValue(reminder_value);
errors->SetLabel(reminder_value->errors);
add_param->Enable(!kw.fixed && !set->game->keyword_parameter_types.empty());
ref_param->Enable(!kw.fixed && !kw.parameters.empty());
mode ->Enable(!kw.fixed && !set->game->keyword_modes.empty());
mode->SetSelection((int)kw.findMode(set->game->keyword_modes));
sp->Layout();
} else {
keyword ->setValue(nullptr);
match ->setValue(nullptr);
rules ->setValue(nullptr);
reminder->setValue(nullptr);
add_param->Enable(false);
ref_param->Enable(false);
mode ->Enable(false);
}
if (ev.keyword) {
Keyword& kw = *ev.keyword;
sp->Show(fixed, kw.fixed);
keyword ->setValue(intrusive(new KeywordTextValue(keyword->getFieldP(), &kw, &kw.keyword, !kw.fixed, true)));
match ->setValue(intrusive(new KeywordTextValue(match->getFieldP(), &kw, &kw.match, !kw.fixed)));
rules ->setValue(intrusive(new KeywordTextValue(rules->getFieldP(), &kw, &kw.rules, !kw.fixed)));
intrusive_ptr<KeywordReminderTextValue> reminder_value(new KeywordReminderTextValue(*set, reminder->getFieldP(), &kw, !kw.fixed));
reminder->setValue(reminder_value);
errors->SetLabel(reminder_value->errors);
add_param->Enable(!kw.fixed && !set->game->keyword_parameter_types.empty());
ref_param->Enable(!kw.fixed && !kw.parameters.empty());
mode ->Enable(!kw.fixed && !set->game->keyword_modes.empty());
mode->SetSelection((int)kw.findMode(set->game->keyword_modes));
sp->Layout();
} else {
keyword ->setValue(nullptr);
match ->setValue(nullptr);
rules ->setValue(nullptr);
reminder->setValue(nullptr);
add_param->Enable(false);
ref_param->Enable(false);
mode ->Enable(false);
}
}
void KeywordsPanel::onModeChange(wxCommandEvent& ev) {
if (!list->getKeyword()) return;
int sel = mode->GetSelection();
if (sel >= 0 && (size_t)sel < set->game->keyword_modes.size()) {
set->actions.addAction(new ChangeKeywordModeAction(*list->getKeyword(), set->game->keyword_modes[sel]->name));
}
if (!list->getKeyword()) return;
int sel = mode->GetSelection();
if (sel >= 0 && (size_t)sel < set->game->keyword_modes.size()) {
set->actions.addAction(new ChangeKeywordModeAction(*list->getKeyword(), set->game->keyword_modes[sel]->name));
}
}
BEGIN_EVENT_TABLE(KeywordsPanel, wxPanel)
EVT_KEYWORD_SELECT(wxID_ANY, KeywordsPanel::onKeywordSelect)
EVT_CHOICE (ID_KEYWORD_MODE, KeywordsPanel::onModeChange)
EVT_KEYWORD_SELECT(wxID_ANY, KeywordsPanel::onKeywordSelect)
EVT_CHOICE (ID_KEYWORD_MODE, KeywordsPanel::onModeChange)
END_EVENT_TABLE()
+50 -50
View File
@@ -25,57 +25,57 @@ class FilterCtrl;
/// A panel for listing and editing the keywords in a set
class KeywordsPanel : public SetWindowPanel {
public:
KeywordsPanel(Window* parent, int id);
~KeywordsPanel();
virtual void onChangeSet();
virtual void onAction(const Action&, bool);
// --------------------------------------------------- : UI
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();
KeywordsPanel(Window* parent, int id);
~KeywordsPanel();
virtual void onChangeSet();
virtual void onAction(const Action&, bool);
// --------------------------------------------------- : UI
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();
private:
DECLARE_EVENT_TABLE();
/// Find the code to insert based on the ref_scripts for the parameters of the current keyword
String runRefScript(int i);
/// Actual intialization of the controls
void initControls();
// --------------------------------------------------- : Controls
wxSplitterWindow* splitter;
wxPanel* panel;
wxSizer* sp;
KeywordList* list;
TextCtrl* keyword;
TextCtrl* match;
TextCtrl* reminder;
TextCtrl* rules;
IconMenu* menuKeyword;
wxStaticText* fixedL;
wxSizer* fixed;
wxStaticText* errors;
wxChoice* mode;
wxButton* add_param;
wxButton* ref_param;
FilterCtrl* filter;
// --------------------------------------------------- : Events
void onKeywordSelect(KeywordSelectEvent& ev);
void onModeChange(wxCommandEvent& ev);
DECLARE_EVENT_TABLE();
/// Find the code to insert based on the ref_scripts for the parameters of the current keyword
String runRefScript(int i);
/// Actual intialization of the controls
void initControls();
// --------------------------------------------------- : Controls
wxSplitterWindow* splitter;
wxPanel* panel;
wxSizer* sp;
KeywordList* list;
TextCtrl* keyword;
TextCtrl* match;
TextCtrl* reminder;
TextCtrl* rules;
IconMenu* menuKeyword;
wxStaticText* fixedL;
wxSizer* fixed;
wxStaticText* errors;
wxChoice* mode;
wxButton* add_param;
wxButton* ref_param;
FilterCtrl* filter;
// --------------------------------------------------- : Events
void onKeywordSelect(KeywordSelectEvent& ev);
void onModeChange(wxCommandEvent& ev);
};
// ----------------------------------------------------------------------------- : EOF
+3 -3
View File
@@ -13,13 +13,13 @@
// ----------------------------------------------------------------------------- : SetWindowPanel
SetWindowPanel::SetWindowPanel(Window* parent, int id, bool autoTabbing)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, autoTabbing ? wxTAB_TRAVERSAL : 0)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, autoTabbing ? wxTAB_TRAVERSAL : 0)
{}
CardP SetWindowPanel::selectedCard() const {
return CardP();
return CardP();
}
bool SetWindowPanel::isInitialized() const {
return !GetChildren().IsEmpty();
return !GetChildren().IsEmpty();
}
+55 -55
View File
@@ -22,62 +22,62 @@ class wxFindReplaceData;
*/
class SetWindowPanel : public wxPanel, public SetView {
public:
SetWindowPanel(Window* parent, int id, bool autoTabbing = true);
/// We will probably want to respond to set changes
virtual void onSetChange() {}
// // --------------------------------------------------- : Meta information
//
// virtual String helpFile() { return _(""); } ///< help file to use when this panel is active
// --------------------------------------------------- : UI
/// Init extra toolbar items and menus needed for this panel.
virtual void initUI (wxToolBar* tb, wxMenuBar* mb) {}
/// Destroy the extra items added by initUI.
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb) {}
/// Update the UI by enabling/disabling items.
/** Note: copy/paste and find/replace are not handled here.
*/
virtual void onUpdateUI(wxUpdateUIEvent&) {}
/// Respond to one of those extra menu/tool items
virtual void onCommand(int id) {}
/// Called before a menu is opened in the parent window
virtual void onMenuOpen(wxMenuEvent&) {}
// --------------------------------------------------- : Actions/Events
/// Should return true if this panel wants to get focus to show an action
virtual bool wantsToHandle(const Action&, bool undone) const { return false; }
/// Handle an action that changes the current set
virtual void onAction(const Action&, bool undone) {}
// --------------------------------------------------- : Clipboard
virtual bool canPaste() const { return false; } ///< Is pasting possible?
virtual bool canCopy() const { return false; } ///< Is copying possible?
virtual bool canCut() const { return canCopy(); } ///< Is cutting possible?
virtual void doPaste() {} ///< Paste the contents of the clipboard
virtual void doCopy() {} ///< Copy the selection to the clipboard
virtual void doCut() {} ///< Cut the selection to the clipboard
// --------------------------------------------------- : Searching (find/replace)
virtual bool canFind() const { return false; } ///< Is finding possible?
virtual bool canReplace() const { return false; } ///< Is replacing possible?
virtual bool doFind (wxFindReplaceData&) { return false; } ///< Find the next math
virtual bool doReplace (wxFindReplaceData&) { return false; } ///< Replace the next match
virtual bool doReplaceAll(wxFindReplaceData&) { return false; } ///< Replace all matches
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const; ///< Return the currently selected card, or CardP()
virtual void selectCard(const CardP& card) {} ///< Switch the view to another card, can be null
virtual void selectFirstCard() {} ///< Switch the view to the first card
virtual void selectionChoices(ExportCardSelectionChoices& out) {} ///< Card subsets that can be exported from this panel
SetWindowPanel(Window* parent, int id, bool autoTabbing = true);
/// We will probably want to respond to set changes
virtual void onSetChange() {}
// // --------------------------------------------------- : Meta information
//
// virtual String helpFile() { return _(""); } ///< help file to use when this panel is active
// --------------------------------------------------- : UI
/// Init extra toolbar items and menus needed for this panel.
virtual void initUI (wxToolBar* tb, wxMenuBar* mb) {}
/// Destroy the extra items added by initUI.
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb) {}
/// Update the UI by enabling/disabling items.
/** Note: copy/paste and find/replace are not handled here.
*/
virtual void onUpdateUI(wxUpdateUIEvent&) {}
/// Respond to one of those extra menu/tool items
virtual void onCommand(int id) {}
/// Called before a menu is opened in the parent window
virtual void onMenuOpen(wxMenuEvent&) {}
// --------------------------------------------------- : Actions/Events
/// Should return true if this panel wants to get focus to show an action
virtual bool wantsToHandle(const Action&, bool undone) const { return false; }
/// Handle an action that changes the current set
virtual void onAction(const Action&, bool undone) {}
// --------------------------------------------------- : Clipboard
virtual bool canPaste() const { return false; } ///< Is pasting possible?
virtual bool canCopy() const { return false; } ///< Is copying possible?
virtual bool canCut() const { return canCopy(); } ///< Is cutting possible?
virtual void doPaste() {} ///< Paste the contents of the clipboard
virtual void doCopy() {} ///< Copy the selection to the clipboard
virtual void doCut() {} ///< Cut the selection to the clipboard
// --------------------------------------------------- : Searching (find/replace)
virtual bool canFind() const { return false; } ///< Is finding possible?
virtual bool canReplace() const { return false; } ///< Is replacing possible?
virtual bool doFind (wxFindReplaceData&) { return false; } ///< Find the next math
virtual bool doReplace (wxFindReplaceData&) { return false; } ///< Replace the next match
virtual bool doReplaceAll(wxFindReplaceData&) { return false; } ///< Replace all matches
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const; ///< Return the currently selected card, or CardP()
virtual void selectCard(const CardP& card) {} ///< Switch the view to another card, can be null
virtual void selectFirstCard() {} ///< Switch the view to the first card
virtual void selectionChoices(ExportCardSelectionChoices& out) {} ///< Card subsets that can be exported from this panel
protected:
/// Have any controls been created?
bool isInitialized() const;
/// Have any controls been created?
bool isInitialized() const;
};
// ----------------------------------------------------------------------------- : EOF
File diff suppressed because it is too large Load Diff
+62 -62
View File
@@ -25,13 +25,13 @@ DECLARE_POINTER_TYPE(PackType);
// for lists of spin controls
struct PackAmountPicker {
PackTypeP pack;
SelectableLabel* label;
wxSpinCtrl* value;
PackAmountPicker() {}
PackAmountPicker(wxWindow* parent, wxFlexGridSizer* sizer, const PackTypeP& pack, bool interactive);
void destroy(wxFlexGridSizer* sizer);
PackTypeP pack;
SelectableLabel* label;
wxSpinCtrl* value;
PackAmountPicker() {}
PackAmountPicker(wxWindow* parent, wxFlexGridSizer* sizer, const PackTypeP& pack, bool interactive);
void destroy(wxFlexGridSizer* sizer);
};
// ----------------------------------------------------------------------------- : RandomPackPanel
@@ -39,63 +39,63 @@ struct PackAmountPicker {
/// A SetWindowPanel for creating random booster packs
class RandomPackPanel : public SetWindowPanel {
public:
RandomPackPanel(Window* parent, int id);
~RandomPackPanel();
// --------------------------------------------------- : UI
virtual void onBeforeChangeSet();
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
virtual void initUI (wxToolBar* tb, wxMenuBar* mb);
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
virtual void selectionChoices(ExportCardSelectionChoices& out);
// --------------------------------------------------- : Clipboard
virtual bool canCopy() const;
virtual void doCopy();
RandomPackPanel(Window* parent, int id);
~RandomPackPanel();
// --------------------------------------------------- : UI
virtual void onBeforeChangeSet();
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
virtual void initUI (wxToolBar* tb, wxMenuBar* mb);
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
virtual void selectionChoices(ExportCardSelectionChoices& out);
// --------------------------------------------------- : Clipboard
virtual bool canCopy() const;
virtual void doCopy();
private:
DECLARE_EVENT_TABLE();
CardViewer* preview; ///< Card preview
RandomCardList* card_list; ///< The list of cards
wxTextCtrl* seed; ///< Seed value
wxFlexGridSizer* packsSizer;
wxFlexGridSizer* totalsSizer;
wxButton* generate_button;
wxRadioButton* seed_random, *seed_fixed;
PackTotalsPanel* totals;
vector<PackAmountPicker> pickers;
PackGenerator generator;
int last_seed;
/// Actual intialization of the controls
void initControls();
/// Update the total count of each card type
void updateTotals();
/// Get a seed value
int getSeed();
void setSeed(int seed);
/// Generate the cards
void generate();
/// Store the settings
void storeSettings();
void onCardSelect(CardSelectEvent& ev);
void onPackTypeClick(wxCommandEvent& ev);
DECLARE_EVENT_TABLE();
CardViewer* preview; ///< Card preview
RandomCardList* card_list; ///< The list of cards
wxTextCtrl* seed; ///< Seed value
wxFlexGridSizer* packsSizer;
wxFlexGridSizer* totalsSizer;
wxButton* generate_button;
wxRadioButton* seed_random, *seed_fixed;
PackTotalsPanel* totals;
vector<PackAmountPicker> pickers;
PackGenerator generator;
int last_seed;
/// Actual intialization of the controls
void initControls();
/// Update the total count of each card type
void updateTotals();
/// Get a seed value
int getSeed();
void setSeed(int seed);
/// Generate the cards
void generate();
/// Store the settings
void storeSettings();
void onCardSelect(CardSelectEvent& ev);
void onPackTypeClick(wxCommandEvent& ev);
public:
typedef PackItem PackItem_for_typeof;
typedef PackItem PackItem_for_typeof;
};
// ----------------------------------------------------------------------------- : EOF
+42 -42
View File
@@ -16,66 +16,66 @@
// ----------------------------------------------------------------------------- : SetInfoPanel
SetInfoPanel::SetInfoPanel(Window* parent, int id)
: SetWindowPanel(parent, id)
: SetWindowPanel(parent, id)
{
// init controls
editor = new SetInfoEditor(this, wxID_ANY);
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(editor, 1, wxEXPAND, 2);
s->SetSizeHints(this);
SetSizer(s);
// init controls
editor = new SetInfoEditor(this, wxID_ANY);
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(editor, 1, wxEXPAND, 2);
s->SetSizeHints(this);
SetSizer(s);
}
void SetInfoPanel::onChangeSet() {
editor->setSet(set);
editor->setSet(set);
}
// ----------------------------------------------------------------------------- : UI
void SetInfoPanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
tb->AddTool(ID_FORMAT_BOLD, _(""), load_resource_tool_image(_("bold")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bold"), _HELP_("bold"));
tb->AddTool(ID_FORMAT_ITALIC, _(""), load_resource_tool_image(_("italic")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("italic"), _HELP_("italic"));
tb->AddTool(ID_FORMAT_SYMBOL, _(""), load_resource_tool_image(_("symbol")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symbols"), _HELP_("symbols"));
tb->Realize();
// Menus
IconMenu* menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _MENU_("bold"), _HELP_("bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _MENU_("italic"), _HELP_("italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _MENU_("symbols"), _HELP_("symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _MENU_("reminder text"), _HELP_("reminder text"), wxITEM_CHECK);
mb->Insert(2, menuFormat, _MENU_("format"));
// focus on editor
editor->SetFocus();
// Toolbar
tb->AddTool(ID_FORMAT_BOLD, _(""), load_resource_tool_image(_("bold")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bold"), _HELP_("bold"));
tb->AddTool(ID_FORMAT_ITALIC, _(""), load_resource_tool_image(_("italic")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("italic"), _HELP_("italic"));
tb->AddTool(ID_FORMAT_SYMBOL, _(""), load_resource_tool_image(_("symbol")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symbols"), _HELP_("symbols"));
tb->Realize();
// Menus
IconMenu* menuFormat = new IconMenu();
menuFormat->Append(ID_FORMAT_BOLD, _("bold"), _MENU_("bold"), _HELP_("bold"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_ITALIC, _("italic"), _MENU_("italic"), _HELP_("italic"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_SYMBOL, _("symbol"), _MENU_("symbols"), _HELP_("symbols"), wxITEM_CHECK);
menuFormat->Append(ID_FORMAT_REMINDER, _("reminder"), _MENU_("reminder text"), _HELP_("reminder text"), wxITEM_CHECK);
mb->Insert(2, menuFormat, _MENU_("format"));
// focus on editor
editor->SetFocus();
}
void SetInfoPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
tb->DeleteTool(ID_FORMAT_BOLD);
tb->DeleteTool(ID_FORMAT_ITALIC);
tb->DeleteTool(ID_FORMAT_SYMBOL);
// Menus
delete mb->Remove(2);
// Toolbar
tb->DeleteTool(ID_FORMAT_BOLD);
tb->DeleteTool(ID_FORMAT_ITALIC);
tb->DeleteTool(ID_FORMAT_SYMBOL);
// Menus
delete mb->Remove(2);
}
void SetInfoPanel::onUpdateUI(wxUpdateUIEvent& ev) {
switch (ev.GetId()) {
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: {
ev.Enable(editor->canFormat(ev.GetId()));
ev.Check (editor->hasFormat(ev.GetId()));
break;
}
}
switch (ev.GetId()) {
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: {
ev.Enable(editor->canFormat(ev.GetId()));
ev.Check (editor->hasFormat(ev.GetId()));
break;
}
}
}
void SetInfoPanel::onCommand(int id) {
switch (id) {
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: {
editor->doFormat(id);
break;
}
}
switch (id) {
case ID_FORMAT_BOLD: case ID_FORMAT_ITALIC: case ID_FORMAT_SYMBOL: {
editor->doFormat(id);
break;
}
}
}
// ----------------------------------------------------------------------------- : Clipboard
+21 -21
View File
@@ -18,29 +18,29 @@ class SetInfoEditor;
class SetInfoPanel : public SetWindowPanel {
public:
SetInfoPanel(Window* parent, int id);
// --------------------------------------------------- : UI
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();
SetInfoPanel(Window* parent, int id);
// --------------------------------------------------- : UI
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();
virtual void onChangeSet();
private:
SetInfoEditor* editor;
SetInfoEditor* editor;
};
// ----------------------------------------------------------------------------- : EOF
+431 -431
View File
@@ -35,70 +35,70 @@ DECLARE_TYPEOF_COLLECTION(pair_StatsDimensionP_String);
/// A list of fields of which the statistics can be shown
class StatCategoryList : public GalleryList {
public:
StatCategoryList(Window* parent, int id)
: GalleryList(parent, id, wxVERTICAL)
{
item_size = subcolumns[0].size = wxSize(150, 23);
}
void show(const GameP&);
/// The selected category
inline StatsCategory& getSelection() {
return *categories.at(subcolumns[0].selection);
}
StatCategoryList(Window* parent, int id)
: GalleryList(parent, id, wxVERTICAL)
{
item_size = subcolumns[0].size = wxSize(150, 23);
}
void show(const GameP&);
/// The selected category
inline StatsCategory& getSelection() {
return *categories.at(subcolumns[0].selection);
}
protected:
virtual size_t itemCount() const;
virtual void drawItem(DC& dc, int x, int y, size_t item);
virtual size_t itemCount() const;
virtual void drawItem(DC& dc, int x, int y, size_t item);
private:
GameP game;
vector<StatsCategoryP> categories; ///< Categories, sorted by position_hint
GameP game;
vector<StatsCategoryP> categories; ///< Categories, sorted by position_hint
};
struct ComparePositionHint{
inline bool operator () (const StatsCategoryP& a, const StatsCategoryP& b) {
return a->position_hint < b->position_hint;
}
inline bool operator () (const StatsCategoryP& a, const StatsCategoryP& b) {
return a->position_hint < b->position_hint;
}
};
void StatCategoryList::show(const GameP& game) {
this->game = game;
categories = game->statistics_categories;
stable_sort(categories.begin(), categories.end(), ComparePositionHint());
update();
// select first item
subcolumns[0].selection = itemCount() > 0 ? 0 : NO_SELECTION;
this->game = game;
categories = game->statistics_categories;
stable_sort(categories.begin(), categories.end(), ComparePositionHint());
update();
// select first item
subcolumns[0].selection = itemCount() > 0 ? 0 : NO_SELECTION;
}
size_t StatCategoryList::itemCount() const {
return categories.size();
return categories.size();
}
void StatCategoryList::drawItem(DC& dc, int x, int y, size_t item) {
StatsCategory& cat = *categories.at(item);
// draw icon
if (!cat.icon_filename.empty() && !cat.icon.Ok()) {
InputStreamP file = game->openIn(cat.icon_filename);
Image img(*file);
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
if (img.Ok()) {
cat.icon = Bitmap(resample_preserve_aspect(img, 21, 21));
}
}
if (cat.icon.Ok()) {
dc.DrawBitmap(cat.icon, x+1, y+1);
}
// draw name
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = capitalize(cat.name);
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
StatsCategory& cat = *categories.at(item);
// draw icon
if (!cat.icon_filename.empty() && !cat.icon.Ok()) {
InputStreamP file = game->openIn(cat.icon_filename);
Image img(*file);
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
if (img.Ok()) {
cat.icon = Bitmap(resample_preserve_aspect(img, 21, 21));
}
}
if (cat.icon.Ok()) {
dc.DrawBitmap(cat.icon, x+1, y+1);
}
// draw name
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = capitalize(cat.name);
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
}
// ----------------------------------------------------------------------------- : StatDimensionList
@@ -107,463 +107,463 @@ void StatCategoryList::drawItem(DC& dc, int x, int y, size_t item) {
/// A list of fields of which the statistics can be shown
class StatDimensionList : public GalleryList {
public:
StatDimensionList(Window* parent, int id, bool show_empty, int dimension_count = 3)
: GalleryList(parent, id, wxVERTICAL, false)
, dimension_count(dimension_count)
, prefered_dimension_count(dimension_count)
, show_empty(show_empty)
{
//item_size = wxSize(150, 23);
subcolumns[0].size = wxSize(140,23);
if (dimension_count > 0) {
subcolumns[0].selection = NO_SELECTION;
subcolumns[0].can_select = false;
active_subcolumn = 1;
}
// additional columns
SubColumn col;
col.selection = show_empty ? NO_SELECTION : 0;
col.can_select = true;
col.offset.x = subcolumns[0].size.x + SPACING;
col.size = wxSize(18,23);
for (int i = 0 ; i < dimension_count ; ++i) {
subcolumns.push_back(col);
col.offset.x += col.size.x + SPACING;
}
// total
item_size = wxSize(col.offset.x - SPACING, 23);
}
void show(const GameP&);
/// The selected category
StatsDimensionP getSelection(size_t subcol=(size_t)-1) {
size_t sel = subcolumns[subcol+1].selection - show_empty;
if (sel >= itemCount()) return StatsDimensionP();
else return dimensions.at(sel);
}
/// The number of dimensions shown
const int dimension_count;
size_t prefered_dimension_count;
void restrictDimensions(size_t dims) {
prefered_dimension_count = dims;
active_subcolumn = min(active_subcolumn, dims);
RefreshSelection();
}
StatDimensionList(Window* parent, int id, bool show_empty, int dimension_count = 3)
: GalleryList(parent, id, wxVERTICAL, false)
, dimension_count(dimension_count)
, prefered_dimension_count(dimension_count)
, show_empty(show_empty)
{
//item_size = wxSize(150, 23);
subcolumns[0].size = wxSize(140,23);
if (dimension_count > 0) {
subcolumns[0].selection = NO_SELECTION;
subcolumns[0].can_select = false;
active_subcolumn = 1;
}
// additional columns
SubColumn col;
col.selection = show_empty ? NO_SELECTION : 0;
col.can_select = true;
col.offset.x = subcolumns[0].size.x + SPACING;
col.size = wxSize(18,23);
for (int i = 0 ; i < dimension_count ; ++i) {
subcolumns.push_back(col);
col.offset.x += col.size.x + SPACING;
}
// total
item_size = wxSize(col.offset.x - SPACING, 23);
}
void show(const GameP&);
/// The selected category
StatsDimensionP getSelection(size_t subcol=(size_t)-1) {
size_t sel = subcolumns[subcol+1].selection - show_empty;
if (sel >= itemCount()) return StatsDimensionP();
else return dimensions.at(sel);
}
/// The number of dimensions shown
const int dimension_count;
size_t prefered_dimension_count;
void restrictDimensions(size_t dims) {
prefered_dimension_count = dims;
active_subcolumn = min(active_subcolumn, dims);
RefreshSelection();
}
protected:
virtual size_t itemCount() const;
virtual void drawItem(DC& dc, int x, int y, size_t item);
virtual double subcolumnActivity(size_t col) const {
return col-1 >= prefered_dimension_count ? 0.2 : 0.7;
}
virtual void onSelect(size_t item, size_t old_col, bool& changes) {
// swap selection with another subcolumn?
for (size_t j = 1 ; j < subcolumns.size() ; ++j) {
if (j != active_subcolumn && subcolumns[j].selection == item &&
subcolumns[active_subcolumn].selection != item) {
subcolumns[j].selection = subcolumns[active_subcolumn].selection;
changes = true;
break;
}
}
// update prefered dimension count?
if (active_subcolumn > prefered_dimension_count) {
prefered_dimension_count = active_subcolumn;
changes = true;
RefreshSelection();
}
// decrease dimension count? (toggle last dimension)
if (!changes && old_col == active_subcolumn) {
if (active_subcolumn == prefered_dimension_count && prefered_dimension_count > 1) {
prefered_dimension_count -= 1;
selectSubColumn(prefered_dimension_count);
changes = true;
} else if (active_subcolumn != prefered_dimension_count) {
active_subcolumn = prefered_dimension_count = active_subcolumn;
RefreshSelection();
changes = true;
}
}
}
virtual size_t itemCount() const;
virtual void drawItem(DC& dc, int x, int y, size_t item);
virtual double subcolumnActivity(size_t col) const {
return col-1 >= prefered_dimension_count ? 0.2 : 0.7;
}
virtual void onSelect(size_t item, size_t old_col, bool& changes) {
// swap selection with another subcolumn?
for (size_t j = 1 ; j < subcolumns.size() ; ++j) {
if (j != active_subcolumn && subcolumns[j].selection == item &&
subcolumns[active_subcolumn].selection != item) {
subcolumns[j].selection = subcolumns[active_subcolumn].selection;
changes = true;
break;
}
}
// update prefered dimension count?
if (active_subcolumn > prefered_dimension_count) {
prefered_dimension_count = active_subcolumn;
changes = true;
RefreshSelection();
}
// decrease dimension count? (toggle last dimension)
if (!changes && old_col == active_subcolumn) {
if (active_subcolumn == prefered_dimension_count && prefered_dimension_count > 1) {
prefered_dimension_count -= 1;
selectSubColumn(prefered_dimension_count);
changes = true;
} else if (active_subcolumn != prefered_dimension_count) {
active_subcolumn = prefered_dimension_count = active_subcolumn;
RefreshSelection();
changes = true;
}
}
}
private:
GameP game;
bool show_empty;
vector<StatsDimensionP> dimensions; ///< Dimensions, sorted by position_hint
GameP game;
bool show_empty;
vector<StatsDimensionP> dimensions; ///< Dimensions, sorted by position_hint
};
struct ComparePositionHint2{
inline bool operator () (const StatsDimensionP& a, const StatsDimensionP& b) {
return a->position_hint < b->position_hint;
}
inline bool operator () (const StatsDimensionP& a, const StatsDimensionP& b) {
return a->position_hint < b->position_hint;
}
};
void StatDimensionList::show(const GameP& game) {
this->game = game;
dimensions = game->statistics_dimensions;
stable_sort(dimensions.begin(), dimensions.end(), ComparePositionHint2());
update();
// select first item
if (dimension_count > 0) {
for (int j = 0 ; j < dimension_count ; ++j) {
subcolumns[j+1].selection = itemCount() > 0 ? 0 : NO_SELECTION;
}
prefered_dimension_count = 1;
} else {
subcolumns[0].selection = itemCount() > 0 ? 0 : NO_SELECTION;
}
this->game = game;
dimensions = game->statistics_dimensions;
stable_sort(dimensions.begin(), dimensions.end(), ComparePositionHint2());
update();
// select first item
if (dimension_count > 0) {
for (int j = 0 ; j < dimension_count ; ++j) {
subcolumns[j+1].selection = itemCount() > 0 ? 0 : NO_SELECTION;
}
prefered_dimension_count = 1;
} else {
subcolumns[0].selection = itemCount() > 0 ? 0 : NO_SELECTION;
}
}
size_t StatDimensionList::itemCount() const {
return dimensions.size() + show_empty;
return dimensions.size() + show_empty;
}
void StatDimensionList::drawItem(DC& dc, int x, int y, size_t item) {
if (show_empty && item == 0) {
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = _("None");
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
return;
}
StatsDimension& dim = *dimensions.at(item - show_empty);
// draw icon
if (!dim.icon_filename.empty() && !dim.icon.Ok()) {
InputStreamP file = game->openIn(dim.icon_filename);
Image img(*file);
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
Image resampled(21, 21);
resample_preserve_aspect(img, resampled);
if (img.Ok()) dim.icon = Bitmap(resampled);
}
if (dim.icon.Ok()) {
dc.DrawBitmap(dim.icon, x+1, y+1);
}
// draw name
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = capitalize(dim.name);
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
// draw selection icon
for (size_t j = 1 ; j <= dimensions.size() ; ++j) {
bool prefered = j <= prefered_dimension_count;
if (isSelected(item,j)) {
// TODO: different icons for different dimensions
/*
*/
int cx = x + subcolumns[j].offset.x + subcolumns[j].size.x/2;
int cy = y + subcolumns[j].offset.y + subcolumns[j].size.y/2;
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(prefered ? wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)
: lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),0.5));
dc.DrawCircle(cx,cy,6);
}
}
if (show_empty && item == 0) {
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = _("None");
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
return;
}
StatsDimension& dim = *dimensions.at(item - show_empty);
// draw icon
if (!dim.icon_filename.empty() && !dim.icon.Ok()) {
InputStreamP file = game->openIn(dim.icon_filename);
Image img(*file);
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
Image resampled(21, 21);
resample_preserve_aspect(img, resampled);
if (img.Ok()) dim.icon = Bitmap(resampled);
}
if (dim.icon.Ok()) {
dc.DrawBitmap(dim.icon, x+1, y+1);
}
// draw name
RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y));
String str = capitalize(dim.name);
dc.SetFont(*wxNORMAL_FONT);
int w, h;
dc.GetTextExtent(str, &w, &h);
RealSize size = RealSize(w,h);
RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect);
dc.DrawText(str, (int)pos.x, (int)pos.y);
// draw selection icon
for (size_t j = 1 ; j <= dimensions.size() ; ++j) {
bool prefered = j <= prefered_dimension_count;
if (isSelected(item,j)) {
// TODO: different icons for different dimensions
/*
*/
int cx = x + subcolumns[j].offset.x + subcolumns[j].size.x/2;
int cy = y + subcolumns[j].offset.y + subcolumns[j].size.y/2;
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(prefered ? wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)
: lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),0.5));
dc.DrawCircle(cx,cy,6);
}
}
}
#endif
// ----------------------------------------------------------------------------- : StatsPanel
StatsPanel::StatsPanel(Window* parent, int id)
: SetWindowPanel(parent, id)
, menuGraph(nullptr)
, up_to_date(true), active(false)
: SetWindowPanel(parent, id)
, menuGraph(nullptr)
, up_to_date(true), active(false)
{
// delayed initialization by initControls()
// delayed initialization by initControls()
}
void StatsPanel::initControls() {
// init controls
wxSplitterWindow* splitter;
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) {
dimensions[i] = new StatDimensionList(this, ID_FIELD_LIST, i > 0);
}
#elif USE_DIMENSION_LISTS
dimensions = new StatDimensionList(this, ID_FIELD_LIST, false, 3);
#else
categories = new StatCategoryList(this, ID_FIELD_LIST);
#endif
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
graph = new GraphControl (splitter, wxID_ANY);
card_list = new FilteredCardList(splitter, wxID_ANY);
// init splitter
splitter->SetMinimumPaneSize(100);
splitter->SetSashGravity(0.6);
splitter->SplitHorizontally(graph, card_list, -170);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
#if USE_SEPARATE_DIMENSION_LISTS
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(dimensions[0], 1, wxBOTTOM, 2);
s2->Add(dimensions[1], 1, wxBOTTOM, 2);
s2->Add(dimensions[2], 1);
s->Add(s2, 0, wxEXPAND | wxRIGHT, 2);
#elif USE_DIMENSION_LISTS
s->Add(dimensions, 0, wxEXPAND | wxRIGHT, 2);
#else
s->Add(categories, 0, wxEXPAND | wxRIGHT, 2);
#endif
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
// init menu
menuGraph = new IconMenu();
menuGraph->Append(ID_GRAPH_PIE, _("graph_pie"), _MENU_("pie"), _HELP_("pie"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_BAR, _("graph_bar"), _MENU_("bar"), _HELP_("bar"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_STACK, _("graph_stack"), _MENU_("stack"), _HELP_("stack"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_SCATTER, _("graph_scatter"), _MENU_("scatter"), _HELP_("scatter"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_SCATTER_PIE, _("graph_scatter_pie"), _MENU_("scatter pie"), _HELP_("scatter pie"), wxITEM_CHECK);
// init controls
wxSplitterWindow* splitter;
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) {
dimensions[i] = new StatDimensionList(this, ID_FIELD_LIST, i > 0);
}
#elif USE_DIMENSION_LISTS
dimensions = new StatDimensionList(this, ID_FIELD_LIST, false, 3);
#else
categories = new StatCategoryList(this, ID_FIELD_LIST);
#endif
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
graph = new GraphControl (splitter, wxID_ANY);
card_list = new FilteredCardList(splitter, wxID_ANY);
// init splitter
splitter->SetMinimumPaneSize(100);
splitter->SetSashGravity(0.6);
splitter->SplitHorizontally(graph, card_list, -170);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
#if USE_SEPARATE_DIMENSION_LISTS
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(dimensions[0], 1, wxBOTTOM, 2);
s2->Add(dimensions[1], 1, wxBOTTOM, 2);
s2->Add(dimensions[2], 1);
s->Add(s2, 0, wxEXPAND | wxRIGHT, 2);
#elif USE_DIMENSION_LISTS
s->Add(dimensions, 0, wxEXPAND | wxRIGHT, 2);
#else
s->Add(categories, 0, wxEXPAND | wxRIGHT, 2);
#endif
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
// init menu
menuGraph = new IconMenu();
menuGraph->Append(ID_GRAPH_PIE, _("graph_pie"), _MENU_("pie"), _HELP_("pie"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_BAR, _("graph_bar"), _MENU_("bar"), _HELP_("bar"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_STACK, _("graph_stack"), _MENU_("stack"), _HELP_("stack"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_SCATTER, _("graph_scatter"), _MENU_("scatter"), _HELP_("scatter"), wxITEM_CHECK);
menuGraph->Append(ID_GRAPH_SCATTER_PIE, _("graph_scatter_pie"), _MENU_("scatter pie"), _HELP_("scatter pie"), wxITEM_CHECK);
}
StatsPanel::~StatsPanel() {
delete menuGraph;
delete menuGraph;
}
void StatsPanel::onChangeSet() {
if (!isInitialized()) return;
card_list->setSet(set);
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) dimensions[i]->show(set->game);
#elif USE_DIMENSION_LISTS
dimensions->show(set->game);
#else
categories->show(set->game);
#endif
card = CardP();
onChange();
if (!isInitialized()) return;
card_list->setSet(set);
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) dimensions[i]->show(set->game);
#elif USE_DIMENSION_LISTS
dimensions->show(set->game);
#else
categories->show(set->game);
#endif
card = CardP();
onChange();
}
void StatsPanel::onAction(const Action& action, bool undone) {
if (!isInitialized()) return;
TYPE_CASE_(action, ScriptValueEvent) {
// ignore style only stuff
} else {
onChange();
}
if (!isInitialized()) return;
TYPE_CASE_(action, ScriptValueEvent) {
// ignore style only stuff
} else {
onChange();
}
}
void StatsPanel::initUI (wxToolBar* tb, wxMenuBar* mb) {
// Controls
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
CardP cur_card = card;
onChangeSet();
selectCard(cur_card);
}
// we are active
active = true;
if (!up_to_date) showCategory();
// Toolbar
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
tb->AddTool(ID_GRAPH_PIE, _(""), load_resource_tool_image(_("graph_pie")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("pie"), _HELP_("pie"));
tb->AddTool(ID_GRAPH_BAR, _(""), load_resource_tool_image(_("graph_bar")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bar"), _HELP_("bar"));
tb->AddTool(ID_GRAPH_STACK, _(""), load_resource_tool_image(_("graph_stack")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("stack"), _HELP_("stack"));
tb->AddTool(ID_GRAPH_SCATTER, _(""), load_resource_tool_image(_("graph_scatter")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("scatter"), _HELP_("scatter"));
tb->AddTool(ID_GRAPH_SCATTER_PIE, _(""), load_resource_tool_image(_("graph_scatter_pie")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("scatter pie"), _HELP_("scatter pie"));
tb->Realize();
// Menu
mb->Insert(2, menuGraph, _MENU_("graph"));
#endif
// Controls
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
CardP cur_card = card;
onChangeSet();
selectCard(cur_card);
}
// we are active
active = true;
if (!up_to_date) showCategory();
// Toolbar
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
tb->AddTool(ID_GRAPH_PIE, _(""), load_resource_tool_image(_("graph_pie")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("pie"), _HELP_("pie"));
tb->AddTool(ID_GRAPH_BAR, _(""), load_resource_tool_image(_("graph_bar")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("bar"), _HELP_("bar"));
tb->AddTool(ID_GRAPH_STACK, _(""), load_resource_tool_image(_("graph_stack")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("stack"), _HELP_("stack"));
tb->AddTool(ID_GRAPH_SCATTER, _(""), load_resource_tool_image(_("graph_scatter")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("scatter"), _HELP_("scatter"));
tb->AddTool(ID_GRAPH_SCATTER_PIE, _(""), load_resource_tool_image(_("graph_scatter_pie")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("scatter pie"), _HELP_("scatter pie"));
tb->Realize();
// Menu
mb->Insert(2, menuGraph, _MENU_("graph"));
#endif
}
void StatsPanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
active = false;
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
// Toolbar
tb->DeleteTool(ID_GRAPH_PIE);
tb->DeleteTool(ID_GRAPH_BAR);
tb->DeleteTool(ID_GRAPH_STACK);
tb->DeleteTool(ID_GRAPH_SCATTER);
tb->DeleteTool(ID_GRAPH_SCATTER_PIE);
// Menus
mb->Remove(2);
#endif
active = false;
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
// Toolbar
tb->DeleteTool(ID_GRAPH_PIE);
tb->DeleteTool(ID_GRAPH_BAR);
tb->DeleteTool(ID_GRAPH_STACK);
tb->DeleteTool(ID_GRAPH_SCATTER);
tb->DeleteTool(ID_GRAPH_SCATTER_PIE);
// Menus
mb->Remove(2);
#endif
}
void StatsPanel::onUpdateUI(wxUpdateUIEvent& ev) {
if (!isInitialized()) return;
switch (ev.GetId()) {
case ID_GRAPH_PIE: case ID_GRAPH_BAR: case ID_GRAPH_STACK: case ID_GRAPH_SCATTER: case ID_GRAPH_SCATTER_PIE: {
GraphType type = (GraphType)(ev.GetId() - ID_GRAPH_PIE);
ev.Check(graph->getLayout() == type);
#if USE_SEPARATE_DIMENSION_LISTS
ev.Enable(graph->getDimensionality() == dimensionality(type));
#endif
break;
}
}
if (!isInitialized()) return;
switch (ev.GetId()) {
case ID_GRAPH_PIE: case ID_GRAPH_BAR: case ID_GRAPH_STACK: case ID_GRAPH_SCATTER: case ID_GRAPH_SCATTER_PIE: {
GraphType type = (GraphType)(ev.GetId() - ID_GRAPH_PIE);
ev.Check(graph->getLayout() == type);
#if USE_SEPARATE_DIMENSION_LISTS
ev.Enable(graph->getDimensionality() == dimensionality(type));
#endif
break;
}
}
}
void StatsPanel::onCommand(int id) {
if (!isInitialized()) return;
switch (id) {
case ID_FIELD_LIST: {
onChange();
break;
}
case ID_GRAPH_PIE: case ID_GRAPH_BAR: case ID_GRAPH_STACK: case ID_GRAPH_SCATTER: case ID_GRAPH_SCATTER_PIE: {
GraphType type = (GraphType)(id - ID_GRAPH_PIE);
showLayout(type);
break;
}
}
if (!isInitialized()) return;
switch (id) {
case ID_FIELD_LIST: {
onChange();
break;
}
case ID_GRAPH_PIE: case ID_GRAPH_BAR: case ID_GRAPH_STACK: case ID_GRAPH_SCATTER: case ID_GRAPH_SCATTER_PIE: {
GraphType type = (GraphType)(id - ID_GRAPH_PIE);
showLayout(type);
break;
}
}
}
// ----------------------------------------------------------------------------- : Updating graph
void StatsPanel::onChange() {
if (active) {
showCategory();
} else {
up_to_date = false; // update later
}
if (active) {
showCategory();
} else {
up_to_date = false; // update later
}
}
void StatsPanel::showCategory(const GraphType* prefer_layout) {
up_to_date = true;
// find dimensions and layout
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
// dimensions
vector<StatsDimensionP> dims;
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) {
StatsDimensionP dim = dimensions[i]->getSelection();
if (dim) dims.push_back(dim);
}
#else // USE_DIMENSION_LISTS
for (size_t i = 0 ; i < dimensions->prefered_dimension_count ; ++i) {
StatsDimensionP dim = dimensions->getSelection(i);
if (dim) dims.push_back(dim);
}
#endif
// layout
GraphType layout = prefer_layout ? *prefer_layout : graph->getLayout();
if (dimensionality(layout) != dims.size()) {
// we must switch to another layout
layout = dims.size() == 1 ? GRAPH_TYPE_BAR
: dims.size() == 2 ? (layout == GRAPH_TYPE_SCATTER_PIE || dims[1]->numeric
? GRAPH_TYPE_SCATTER : GRAPH_TYPE_STACK)
: GRAPH_TYPE_SCATTER_PIE;
}
#else
if (!categories->hasSelection()) return
StatsCategory& cat = categories->getSelection();
// dimensions
cat.find_dimensions(set->game->statistics_dimensions);
vector<StatsDimensionP>& dims = cat.dimensions;
// layout
GraphType layout = cat.type;
#endif
// create axes
GraphDataPre d;
FOR_EACH(dim, dims) {
d.axes.push_back(intrusive(new GraphAxis(
dim->name,
dim->colors.empty() ? AUTO_COLOR_EVEN : AUTO_COLOR_NO,
dim->numeric,
dim->bin_size,
&dim->colors,
dim->groups.empty() ? nullptr : &dim->groups
)
));
}
// find values for each card
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
Context& ctx = set->getContext(set->cards[i]);
GraphElementP e(new GraphElement(i));
bool show = true;
FOR_EACH(dim, dims) {
String value = untag(dim->script.invoke(ctx)->toString());
e->values.push_back(value);
if (value.empty() && !dim->show_empty) {
// don't show this element
show = false;
break;
}
}
if (show) {
d.elements.push_back(e);
}
}
// split lists
size_t dim_id = 0;
FOR_EACH(dim, dims) {
if (dim->split_list) d.splitList(dim_id);
++dim_id;
}
// update graph and card list
graph->setLayout(layout, true);
graph->setData(d);
filterCards();
up_to_date = true;
// find dimensions and layout
#if USE_DIMENSION_LISTS || USE_SEPARATE_DIMENSION_LISTS
// dimensions
vector<StatsDimensionP> dims;
#if USE_SEPARATE_DIMENSION_LISTS
for (int i = 0 ; i < 3 ; ++i) {
StatsDimensionP dim = dimensions[i]->getSelection();
if (dim) dims.push_back(dim);
}
#else // USE_DIMENSION_LISTS
for (size_t i = 0 ; i < dimensions->prefered_dimension_count ; ++i) {
StatsDimensionP dim = dimensions->getSelection(i);
if (dim) dims.push_back(dim);
}
#endif
// layout
GraphType layout = prefer_layout ? *prefer_layout : graph->getLayout();
if (dimensionality(layout) != dims.size()) {
// we must switch to another layout
layout = dims.size() == 1 ? GRAPH_TYPE_BAR
: dims.size() == 2 ? (layout == GRAPH_TYPE_SCATTER_PIE || dims[1]->numeric
? GRAPH_TYPE_SCATTER : GRAPH_TYPE_STACK)
: GRAPH_TYPE_SCATTER_PIE;
}
#else
if (!categories->hasSelection()) return
StatsCategory& cat = categories->getSelection();
// dimensions
cat.find_dimensions(set->game->statistics_dimensions);
vector<StatsDimensionP>& dims = cat.dimensions;
// layout
GraphType layout = cat.type;
#endif
// create axes
GraphDataPre d;
FOR_EACH(dim, dims) {
d.axes.push_back(intrusive(new GraphAxis(
dim->name,
dim->colors.empty() ? AUTO_COLOR_EVEN : AUTO_COLOR_NO,
dim->numeric,
dim->bin_size,
&dim->colors,
dim->groups.empty() ? nullptr : &dim->groups
)
));
}
// find values for each card
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
Context& ctx = set->getContext(set->cards[i]);
GraphElementP e(new GraphElement(i));
bool show = true;
FOR_EACH(dim, dims) {
String value = untag(dim->script.invoke(ctx)->toString());
e->values.push_back(value);
if (value.empty() && !dim->show_empty) {
// don't show this element
show = false;
break;
}
}
if (show) {
d.elements.push_back(e);
}
}
// split lists
size_t dim_id = 0;
FOR_EACH(dim, dims) {
if (dim->split_list) d.splitList(dim_id);
++dim_id;
}
// update graph and card list
graph->setLayout(layout, true);
graph->setData(d);
filterCards();
}
void StatsPanel::showLayout(GraphType layout) {
#if USE_DIMENSION_LISTS && !USE_SEPARATE_DIMENSION_LISTS
// make sure we have the right number of data dimensions
if (dimensions->prefered_dimension_count != dimensionality(layout)) {
dimensions->restrictDimensions(dimensionality(layout));
showCategory(&layout); // full update
return;
}
#endif
graph->setLayout(layout);
graph->Refresh(false);
#if USE_DIMENSION_LISTS && !USE_SEPARATE_DIMENSION_LISTS
// make sure we have the right number of data dimensions
if (dimensions->prefered_dimension_count != dimensionality(layout)) {
dimensions->restrictDimensions(dimensionality(layout));
showCategory(&layout); // full update
return;
}
#endif
graph->setLayout(layout);
graph->Refresh(false);
}
void StatsPanel::onGraphSelect(wxCommandEvent&) {
filterCards();
filterCards();
}
// ----------------------------------------------------------------------------- : Filtering card list
class StatsFilter : public Filter<Card> {
public:
StatsFilter(GraphData& data, const vector<int> match) {
data.indices(match, indices);
}
virtual void getItems(const vector<CardP>& cards, vector<VoidP>& out) const {
FOR_EACH_CONST(idx, indices) {
out.push_back(cards.at(idx));
}
}
vector<size_t> indices; ///< Indices of cards to select
StatsFilter(GraphData& data, const vector<int> match) {
data.indices(match, indices);
}
virtual void getItems(const vector<CardP>& cards, vector<VoidP>& out) const {
FOR_EACH_CONST(idx, indices) {
out.push_back(cards.at(idx));
}
}
vector<size_t> indices; ///< Indices of cards to select
};
void StatsPanel::filterCards() {
intrusive_ptr<StatsFilter> filter(new StatsFilter(*graph->getData(), graph->getSelectionIndices()));
card_list->setFilter(filter);
intrusive_ptr<StatsFilter> filter(new StatsFilter(*graph->getData(), graph->getSelectionIndices()));
card_list->setFilter(filter);
}
// ----------------------------------------------------------------------------- : Events
BEGIN_EVENT_TABLE(StatsPanel, wxPanel)
EVT_GRAPH_SELECT(wxID_ANY, StatsPanel::onGraphSelect)
EVT_GRAPH_SELECT(wxID_ANY, StatsPanel::onGraphSelect)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : Selection
CardP StatsPanel::selectedCard() const {
if (!isInitialized()) return CardP();
return card_list->getCard();
if (!isInitialized()) return CardP();
return card_list->getCard();
}
void StatsPanel::selectCard(const CardP& card) {
this->card = card;
if (!isInitialized()) return;
card_list->setCard(card);
this->card = card;
if (!isInitialized()) return;
card_list->setCard(card);
}
+42 -42
View File
@@ -28,49 +28,49 @@ class IconMenu;
/// A panel for showing statistics on cards
class StatsPanel : public SetWindowPanel {
public:
StatsPanel(Window* parent, int id);
~StatsPanel();
// --------------------------------------------------- : UI
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
virtual void initUI (wxToolBar*, wxMenuBar*);
virtual void destroyUI(wxToolBar*, wxMenuBar*);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
// --------------------------------------------------- : Data
StatsPanel(Window* parent, int id);
~StatsPanel();
// --------------------------------------------------- : UI
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
virtual void initUI (wxToolBar*, wxMenuBar*);
virtual void destroyUI(wxToolBar*, wxMenuBar*);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const;
virtual void selectCard(const CardP& card);
// --------------------------------------------------- : Data
private:
DECLARE_EVENT_TABLE();
#if USE_SEPARATE_DIMENSION_LISTS
StatDimensionList* dimensions[3];
#elif USE_DIMENSION_LISTS
StatDimensionList* dimensions;
#else
StatCategoryList* categories;
#endif
GraphControl* graph;
FilteredCardList* card_list;
IconMenu* menuGraph;
CardP card; ///< Selected card
bool up_to_date; ///< Are the graph and card list up to date?
bool active; ///< Is this panel selected?
void initControls();
void onChange();
void onGraphSelect(wxCommandEvent&);
void showCategory(const GraphType* prefer_layout = nullptr);
void showLayout(GraphType);
void filterCards();
DECLARE_EVENT_TABLE();
#if USE_SEPARATE_DIMENSION_LISTS
StatDimensionList* dimensions[3];
#elif USE_DIMENSION_LISTS
StatDimensionList* dimensions;
#else
StatCategoryList* categories;
#endif
GraphControl* graph;
FilteredCardList* card_list;
IconMenu* menuGraph;
CardP card; ///< Selected card
bool up_to_date; ///< Are the graph and card list up to date?
bool active; ///< Is this panel selected?
void initControls();
void onChange();
void onGraphSelect(wxCommandEvent&);
void showCategory(const GraphType* prefer_layout = nullptr);
void showLayout(GraphType);
void filterCards();
};
// ----------------------------------------------------------------------------- : EOF
+113 -113
View File
@@ -26,131 +26,131 @@ DECLARE_TYPEOF_COLLECTION(FieldP);
// ----------------------------------------------------------------------------- : StylePanel : initialization
StylePanel::StylePanel(Window* parent, int id)
: SetWindowPanel(parent, id)
: SetWindowPanel(parent, id)
{
// delayed initialization by initControls()
// delayed initialization by initControls()
}
void StylePanel::initControls() {
// init controls
preview = new CardViewer (this, wxID_ANY);
list = new PackageList (this, wxID_ANY);
use_for_all = new wxButton (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards"));
use_custom_options = new wxCheckBox(this, ID_STYLE_USE_CUSTOM, _BUTTON_("use custom styling options"));
editor = new StylingEditor(this, ID_EDITOR, wxNO_BORDER);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(preview, 0, wxRIGHT, 2);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(list, 0, wxEXPAND | wxBOTTOM, 4);
s2->Add(use_for_all, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 4);
wxSizer* s3 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("styling options"));
s3->Add(use_custom_options, 0, wxEXPAND | wxALL, 4);
s3->Add(editor, 2, wxEXPAND, 0);
s2->Add(s3, 1, wxEXPAND | wxALL, 2);
s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s);
// init controls
preview = new CardViewer (this, wxID_ANY);
list = new PackageList (this, wxID_ANY);
use_for_all = new wxButton (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards"));
use_custom_options = new wxCheckBox(this, ID_STYLE_USE_CUSTOM, _BUTTON_("use custom styling options"));
editor = new StylingEditor(this, ID_EDITOR, wxNO_BORDER);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(preview, 0, wxRIGHT, 2);
wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(list, 0, wxEXPAND | wxBOTTOM, 4);
s2->Add(use_for_all, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 4);
wxSizer* s3 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("styling options"));
s3->Add(use_custom_options, 0, wxEXPAND | wxALL, 4);
s3->Add(editor, 2, wxEXPAND, 0);
s2->Add(s3, 1, wxEXPAND | wxALL, 2);
s->Add(s2, 1, wxEXPAND, 8);
s->SetSizeHints(this);
SetSizer(s);
}
void StylePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
CardP cur_card = card;
onChangeSet();
selectCard(cur_card);
}
if (!isInitialized()) {
wxBusyCursor busy;
initControls();
CardP cur_card = card;
onChangeSet();
selectCard(cur_card);
}
}
void StylePanel::updateListSize() {
if (!isInitialized()) return;
// how many columns fit?
size_t fit_columns = (size_t)((GetSize().y - 400) / 152);
// we only need enough columns to show all items
int x_room = GetSize().x - editor->GetBestSize().x - 6;
size_t need_columns = (size_t)ceil(list->requiredWidth() / (double)x_room);
size_t column_count = max((size_t)1, min(fit_columns, need_columns));
// change count
if (column_count != list->column_count) {
list->column_count = column_count;
static_cast<SetWindow*>(GetParent())->fixMinWindowSize();
}
if (!isInitialized()) return;
// how many columns fit?
size_t fit_columns = (size_t)((GetSize().y - 400) / 152);
// we only need enough columns to show all items
int x_room = GetSize().x - editor->GetBestSize().x - 6;
size_t need_columns = (size_t)ceil(list->requiredWidth() / (double)x_room);
size_t column_count = max((size_t)1, min(fit_columns, need_columns));
// change count
if (column_count != list->column_count) {
list->column_count = column_count;
static_cast<SetWindow*>(GetParent())->fixMinWindowSize();
}
}
bool StylePanel::Layout() {
updateListSize();
return SetWindowPanel::Layout();
updateListSize();
return SetWindowPanel::Layout();
}
// ----------------------------------------------------------------------------- : StylePanel
void StylePanel::onChangeSet() {
if (!isInitialized()) return;
list->showData<StyleSheet>(set->game->name() + _("-*"));
list->select(set->stylesheet->name(), false);
editor->setSet(set);
preview->setSet(set);
card = CardP();
use_for_all->Enable(false);
if (!isInitialized()) return;
list->showData<StyleSheet>(set->game->name() + _("-*"));
list->select(set->stylesheet->name(), false);
editor->setSet(set);
preview->setSet(set);
card = CardP();
use_for_all->Enable(false);
}
void StylePanel::onAction(const Action& action, bool undone) {
if (!isInitialized()) return;
TYPE_CASE_(action, ChangeSetStyleAction) {
list->select(set->stylesheetFor(card).name(), false);
editor->showCard(card);
}
TYPE_CASE(action, ChangeCardStyleAction) {
if (action.card == card) {
list->select(set->stylesheetFor(card).name(), false);
editor->showCard(card);
}
}
TYPE_CASE(action, ChangeCardHasStylingAction) {
if (action.card == card) {
editor->showCard(card);
}
}
TYPE_CASE(action, ValueAction) {
// is it a styling action?
if (!action.card) {
const StyleSheet& s = set->stylesheetFor(card);
FOR_EACH_CONST(f, s.styling_fields) {
if (action.valueP->fieldP == f) {
// refresh the viewer
preview->redraw();
return;
}
}
}
}
use_for_all->Enable(card && card->stylesheet);
use_custom_options->Enable(card);
use_custom_options->SetValue(card ? card->has_styling : false);
if (!isInitialized()) return;
TYPE_CASE_(action, ChangeSetStyleAction) {
list->select(set->stylesheetFor(card).name(), false);
editor->showCard(card);
}
TYPE_CASE(action, ChangeCardStyleAction) {
if (action.card == card) {
list->select(set->stylesheetFor(card).name(), false);
editor->showCard(card);
}
}
TYPE_CASE(action, ChangeCardHasStylingAction) {
if (action.card == card) {
editor->showCard(card);
}
}
TYPE_CASE(action, ValueAction) {
// is it a styling action?
if (!action.card) {
const StyleSheet& s = set->stylesheetFor(card);
FOR_EACH_CONST(f, s.styling_fields) {
if (action.valueP->fieldP == f) {
// refresh the viewer
preview->redraw();
return;
}
}
}
}
use_for_all->Enable(card && card->stylesheet);
use_custom_options->Enable(card);
use_custom_options->SetValue(card ? card->has_styling : false);
}
// ----------------------------------------------------------------------------- : Selection
void StylePanel::selectCard(const CardP& card) {
this->card = card;
if (!isInitialized()) return;
preview->setCard(card);
editor->showStylesheet(set->stylesheetForP(card));
editor->showCard(card);
list->select(set->stylesheetFor(card).name(), false);
use_for_all->Enable(card && card->stylesheet);
use_custom_options->Enable(card);
use_custom_options->SetValue(card ? card->has_styling : false);
this->card = card;
if (!isInitialized()) return;
preview->setCard(card);
editor->showStylesheet(set->stylesheetForP(card));
editor->showCard(card);
list->select(set->stylesheetFor(card).name(), false);
use_for_all->Enable(card && card->stylesheet);
use_custom_options->Enable(card);
use_custom_options->SetValue(card ? card->has_styling : false);
}
// ----------------------------------------------------------------------------- : Clipboard
// determine what control to use for clipboard actions
#define CUT_COPY_PASTE(op,return) \
if (!isInitialized()) return false; \
int id = focused_control(this); \
if (id == ID_EDITOR) { return editor->op(); } \
else { return false; }
#define CUT_COPY_PASTE(op,return) \
if (!isInitialized()) return false; \
int id = focused_control(this); \
if (id == ID_EDITOR) { return editor->op(); } \
else { return false; }
bool StylePanel::canCopy() const { CUT_COPY_PASTE(canCopy, return) }
bool StylePanel::canCut() const { CUT_COPY_PASTE(canCut, return) }
@@ -162,31 +162,31 @@ void StylePanel::doPaste() { CUT_COPY_PASTE(doPaste, return (void)) }
// ----------------------------------------------------------------------------- : Events
void StylePanel::onStyleSelect(wxCommandEvent&) {
if (list->hasSelection() && card) {
StyleSheetP stylesheet = list->getSelection<StyleSheet>();
if (stylesheet->game != set->game) {
throw PackageError(_("Stylesheet made for the wrong game"));
}
if (stylesheet == set->stylesheet) {
// select no special style when selecting the same style as the set default
stylesheet = StyleSheetP();
}
set->actions.addAction(new ChangeCardStyleAction(card, stylesheet));
Layout();
}
if (list->hasSelection() && card) {
StyleSheetP stylesheet = list->getSelection<StyleSheet>();
if (stylesheet->game != set->game) {
throw PackageError(_("Stylesheet made for the wrong game"));
}
if (stylesheet == set->stylesheet) {
// select no special style when selecting the same style as the set default
stylesheet = StyleSheetP();
}
set->actions.addAction(new ChangeCardStyleAction(card, stylesheet));
Layout();
}
}
void StylePanel::onUseForAll(wxCommandEvent&) {
set->actions.addAction(new ChangeSetStyleAction(*set, card));
Layout();
set->actions.addAction(new ChangeSetStyleAction(*set, card));
Layout();
}
void StylePanel::onUseCustom(wxCommandEvent&) {
set->actions.addAction(new ChangeCardHasStylingAction(*set, card));
set->actions.addAction(new ChangeCardHasStylingAction(*set, card));
}
BEGIN_EVENT_TABLE(StylePanel, wxPanel)
EVT_GALLERY_SELECT(wxID_ANY, StylePanel::onStyleSelect)
EVT_BUTTON (ID_STYLE_USE_FOR_ALL, StylePanel::onUseForAll)
EVT_CHECKBOX (ID_STYLE_USE_CUSTOM, StylePanel::onUseCustom)
EVT_GALLERY_SELECT(wxID_ANY, StylePanel::onStyleSelect)
EVT_BUTTON (ID_STYLE_USE_FOR_ALL, StylePanel::onUseForAll)
EVT_CHECKBOX (ID_STYLE_USE_CUSTOM, StylePanel::onUseCustom)
END_EVENT_TABLE()
+39 -39
View File
@@ -21,46 +21,46 @@ class StylingEditor;
/// A panel showing a list of stylesheets, and an editor for styling
class StylePanel : public SetWindowPanel {
public:
StylePanel(Window* parent, int id);
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
// --------------------------------------------------- : UI
virtual void initUI(wxToolBar*, wxMenuBar*);
// --------------------------------------------------- : Clipboard
virtual bool canCut() const;
virtual bool canCopy() const;
virtual bool canPaste() const;
virtual void doCut();
virtual void doCopy();
virtual void doPaste();
// --------------------------------------------------- : Selection
virtual void selectCard(const CardP& card);
StylePanel(Window* parent, int id);
virtual void onChangeSet();
virtual void onAction(const Action&, bool undone);
// --------------------------------------------------- : UI
virtual void initUI(wxToolBar*, wxMenuBar*);
// --------------------------------------------------- : Clipboard
virtual bool canCut() const;
virtual bool canCopy() const;
virtual bool canPaste() const;
virtual void doCut();
virtual void doCopy();
virtual void doPaste();
// --------------------------------------------------- : Selection
virtual void selectCard(const CardP& card);
private:
DECLARE_EVENT_TABLE();
CardViewer* preview; ///< Card preview
PackageList* list; ///< List of stylesheets
StylingEditor* editor; ///< Editor for styling information
wxButton* use_for_all;
wxCheckBox* use_custom_options;
CardP card; ///< Card we are working on
void onStyleSelect(wxCommandEvent&);
void onUseForAll(wxCommandEvent&);
void onUseCustom(wxCommandEvent&);
/// Determine the best size for the list of stylesheets based on available space
void updateListSize();
virtual bool Layout();
/// Actual intialization of the controls
void initControls();
DECLARE_EVENT_TABLE();
CardViewer* preview; ///< Card preview
PackageList* list; ///< List of stylesheets
StylingEditor* editor; ///< Editor for styling information
wxButton* use_for_all;
wxCheckBox* use_custom_options;
CardP card; ///< Card we are working on
void onStyleSelect(wxCommandEvent&);
void onUseForAll(wxCommandEvent&);
void onUseCustom(wxCommandEvent&);
/// Determine the best size for the list of stylesheets based on available space
void updateListSize();
virtual bool Layout();
/// Actual intialization of the controls
void initControls();
};
// ----------------------------------------------------------------------------- : EOF
+613 -613
View File
File diff suppressed because it is too large Load Diff
+141 -141
View File
@@ -26,151 +26,151 @@ struct CardSelectEvent;
*/
class SetWindow : public wxFrame, public SetView {
public:
/// Construct a SetWindow
SetWindow(Window* parent, const SetP& set);
~SetWindow();
/// Set the icon of one of the panels
void setPanelIcon(SetWindowPanel* panel, wxBitmap const& icon);
// --------------------------------------------------- : Set actions
/// Construct a SetWindow
SetWindow(Window* parent, const SetP& set);
~SetWindow();
/// Set the icon of one of the panels
void setPanelIcon(SetWindowPanel* panel, wxBitmap const& icon);
// --------------------------------------------------- : Set actions
private:
DECLARE_EVENT_TABLE();
// --------------------------------------------------- : Data
// gui items
vector<SetWindowPanel*> panels; ///< All panels on this window
SetWindowPanel* current_panel;
IconMenu* menuExport;
/// Number of items in the recent sets list
size_t number_of_recentSets;
// data for find/replace
wxDialog* find_dialog;
wxFindReplaceData find_data;
// --------------------------------------------------- : Panel managment
/// Add a panel to the window, as well as to the menu and tab bar
/** The position only determines the order in which events will be send.
*/
void addPanel(IconMenu* windowMenu, wxToolBar* tabBar, SetWindowPanel* panel, UInt pos, const String& image_name, const String& name);
/// Select a panel, based on a tab id
void selectPanel(int id);
// --------------------------------------------------- : Managing multiple main windows
/// All opened set windows
static vector<SetWindow*> set_windows;
/// Is this the only window that has this set?
bool isOnlyWithSet();
/// Switch this window to the new set, or open another window for it (depending on the settings)
void switchSet(const SetP& new_set);
// --------------------------------------------------- : Action related
DECLARE_EVENT_TABLE();
// --------------------------------------------------- : Data
// gui items
vector<SetWindowPanel*> panels; ///< All panels on this window
SetWindowPanel* current_panel;
IconMenu* menuExport;
/// Number of items in the recent sets list
size_t number_of_recentSets;
// data for find/replace
wxDialog* find_dialog;
wxFindReplaceData find_data;
// --------------------------------------------------- : Panel managment
/// Add a panel to the window, as well as to the menu and tab bar
/** The position only determines the order in which events will be send.
*/
void addPanel(IconMenu* windowMenu, wxToolBar* tabBar, SetWindowPanel* panel, UInt pos, const String& image_name, const String& name);
/// Select a panel, based on a tab id
void selectPanel(int id);
// --------------------------------------------------- : Managing multiple main windows
/// All opened set windows
static vector<SetWindow*> set_windows;
/// Is this the only window that has this set?
bool isOnlyWithSet();
/// Switch this window to the new set, or open another window for it (depending on the settings)
void switchSet(const SetP& new_set);
// --------------------------------------------------- : Action related
protected:
/// We want to respond to set changes
virtual void onChangeSet();
/// Actions that change the set
virtual void onAction(const Action&, bool undone);
/// We want to respond to set changes
virtual void onChangeSet();
/// Actions that change the set
virtual void onAction(const Action&, bool undone);
public:
// minSize = mainSizer->getMinWindowSize(this)
// but wx made that private
void fixMinWindowSize();
// minSize = mainSizer->getMinWindowSize(this)
// but wx made that private
void fixMinWindowSize();
private:
/// Update the window title based on the set name
void updateTitle();
// --------------------------------------------------- : Cards
/// A different card has been selected
void onCardSelect(CardSelectEvent&);
void onCardActivate(CardSelectEvent&);
/// Card subsets that can be exported
void selectionChoices(ExportCardSelectionChoices& out);
// --------------------------------------------------- : Window events - close
/// Ask the user to save the set
void onClose(wxCloseEvent&);
/// Ask if the user wants to save the set
/** Returns true if the action can be continued (the set was saved, or need not be saved)
* Returns false if the action should be canceled (user pressed cancel, or save failed)
*/
bool askSaveAndContinue();
// --------------------------------------------------- : Window events - update UI
void onUpdateUI(wxUpdateUIEvent&);
/// The number of 'recent set' menu items shown
UInt number_of_recent_sets;
void updateRecentSets();
// --------------------------------------------------- : Window events - menu - file
void onFileNew (wxCommandEvent&);
void onFileOpen (wxCommandEvent&);
void onFileSave (wxCommandEvent&);
void onFileSaveAs (wxCommandEvent&);
// void onFileInspect (wxCommandEvent&);
void onFileExportMenu (wxCommandEvent&);
void onFileExportImage (wxCommandEvent&);
void onFileExportImages (wxCommandEvent&);
void onFileExportHTML (wxCommandEvent&);
void onFileExportApprentice(wxCommandEvent&);
void onFileExportMWS (wxCommandEvent&);
void onFileCheckUpdates (wxCommandEvent&);
void onFileProfiler (wxCommandEvent&);
void onFilePrint (wxCommandEvent&);
void onFilePrintPreview (wxCommandEvent&);
void onFileReload (wxCommandEvent&);
void onFileRecent (wxCommandEvent&);
void onFileExit (wxCommandEvent&);
// --------------------------------------------------- : Window events - menu - edit
void onEditUndo (wxCommandEvent&);
void onEditRedo (wxCommandEvent&);
void onEditCut (wxCommandEvent&);
void onEditCopy (wxCommandEvent&);
void onEditPaste (wxCommandEvent&);
void onEditFind (wxCommandEvent&);
void onEditFindNext (wxCommandEvent&);
void onEditReplace (wxCommandEvent&);
void onEditAutoReplace (wxCommandEvent&);
void onEditPreferences (wxCommandEvent&);
void onFind (wxFindDialogEvent&);
void onFindNext (wxFindDialogEvent&);
void onReplace (wxFindDialogEvent&);
void onReplaceAll (wxFindDialogEvent&);
// --------------------------------------------------- : Window events - menu - window
void onWindowNewWindow (wxCommandEvent&);
void onWindowSelect (wxCommandEvent&);
// --------------------------------------------------- : Window events - menu - help
void onHelpIndex (wxCommandEvent&);
void onHelpWebsite (wxCommandEvent&);
void onHelpAbout (wxCommandEvent&);
// --------------------------------------------------- : Window events - other
void onChildMenu (wxCommandEvent&);
void onMenuOpen (wxMenuEvent&);
void onIdle (wxIdleEvent&);
void onSizeChange (wxCommandEvent&);
void onEraseBackground (wxEraseEvent&) {} // reduce flicker
/// Update the window title based on the set name
void updateTitle();
// --------------------------------------------------- : Cards
/// A different card has been selected
void onCardSelect(CardSelectEvent&);
void onCardActivate(CardSelectEvent&);
/// Card subsets that can be exported
void selectionChoices(ExportCardSelectionChoices& out);
// --------------------------------------------------- : Window events - close
/// Ask the user to save the set
void onClose(wxCloseEvent&);
/// Ask if the user wants to save the set
/** Returns true if the action can be continued (the set was saved, or need not be saved)
* Returns false if the action should be canceled (user pressed cancel, or save failed)
*/
bool askSaveAndContinue();
// --------------------------------------------------- : Window events - update UI
void onUpdateUI(wxUpdateUIEvent&);
/// The number of 'recent set' menu items shown
UInt number_of_recent_sets;
void updateRecentSets();
// --------------------------------------------------- : Window events - menu - file
void onFileNew (wxCommandEvent&);
void onFileOpen (wxCommandEvent&);
void onFileSave (wxCommandEvent&);
void onFileSaveAs (wxCommandEvent&);
// void onFileInspect (wxCommandEvent&);
void onFileExportMenu (wxCommandEvent&);
void onFileExportImage (wxCommandEvent&);
void onFileExportImages (wxCommandEvent&);
void onFileExportHTML (wxCommandEvent&);
void onFileExportApprentice(wxCommandEvent&);
void onFileExportMWS (wxCommandEvent&);
void onFileCheckUpdates (wxCommandEvent&);
void onFileProfiler (wxCommandEvent&);
void onFilePrint (wxCommandEvent&);
void onFilePrintPreview (wxCommandEvent&);
void onFileReload (wxCommandEvent&);
void onFileRecent (wxCommandEvent&);
void onFileExit (wxCommandEvent&);
// --------------------------------------------------- : Window events - menu - edit
void onEditUndo (wxCommandEvent&);
void onEditRedo (wxCommandEvent&);
void onEditCut (wxCommandEvent&);
void onEditCopy (wxCommandEvent&);
void onEditPaste (wxCommandEvent&);
void onEditFind (wxCommandEvent&);
void onEditFindNext (wxCommandEvent&);
void onEditReplace (wxCommandEvent&);
void onEditAutoReplace (wxCommandEvent&);
void onEditPreferences (wxCommandEvent&);
void onFind (wxFindDialogEvent&);
void onFindNext (wxFindDialogEvent&);
void onReplace (wxFindDialogEvent&);
void onReplaceAll (wxFindDialogEvent&);
// --------------------------------------------------- : Window events - menu - window
void onWindowNewWindow (wxCommandEvent&);
void onWindowSelect (wxCommandEvent&);
// --------------------------------------------------- : Window events - menu - help
void onHelpIndex (wxCommandEvent&);
void onHelpWebsite (wxCommandEvent&);
void onHelpAbout (wxCommandEvent&);
// --------------------------------------------------- : Window events - other
void onChildMenu (wxCommandEvent&);
void onMenuOpen (wxMenuEvent&);
void onIdle (wxIdleEvent&);
void onSizeChange (wxCommandEvent&);
void onEraseBackground (wxEraseEvent&) {} // reduce flicker
};
// ----------------------------------------------------------------------------- : EOF