mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 21:47:00 -04:00
Change tabs to two spaces.
This commit is contained in:
+369
-369
@@ -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
@@ -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
@@ -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")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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(¶m_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(¶m_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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+457
-457
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+141
-141
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user