#include "MainWindow.hpp" #include "ChessArbiter.hpp" #include "UCI.hpp" #include "engine_tab/EngineTab.hpp" #include "pgnp.hpp" #include "preferences/preferences.hpp" wxDEFINE_EVENT(REFRESH_TAB_TITLE, wxCommandEvent); wxDEFINE_EVENT(NEW_GAME_EVENT, wxCommandEvent); wxDEFINE_EVENT(CLOSE_TAB_EVENT, wxCommandEvent); wxDEFINE_EVENT(REFRESH_ENGINE_LIST, wxCommandEvent); wxDEFINE_EVENT(CLOSE_LINKED_TAB, wxCommandEvent); /// ---------- MainWindow ---------- MainWindow::MainWindow() : MainFrame(NULL, wxID_ANY, "OChess: The Open Chess software", wxDefaultPosition, wxSize(1500, 1000)), prefsEditor(nullptr), engine_count(0) { SetStatusText("OChess v"+std::string(OCHESS_VERSION)); /// File menu menu_file->Append(1, "Settings", "Configure OChess"); menu_file->AppendSeparator(); menu_file->Append(wxID_EXIT); // Game menu menu_game->Append(2, "New", "Create new game"); menu_game->Append(3, "New from position", "Create new game using FEN"); menu_game->Append(4, "Open", "Open first game of a file"); // Game base menu menu_db->Append(5, "New", "Create database"); menu_db->Append(6, "Open", "Open database"); // Engine menu menu_engine->Append(7, "New", "Create a new engine configuration"); menu_engine->AppendSeparator(); // Dynamically build manage submenu manageMenu = new wxMenu; menu_engine->AppendSubMenu(manageMenu, "Manage"); wxCommandEvent dummy(REFRESH_ENGINE_LIST, GetId()); OnRefreshEngineList(dummy); // Help menu menu_help->Append(wxID_ABOUT, "About", "OChess Informations"); Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, &MainWindow::OnPageChange, this, wxID_ANY); Bind(REFRESH_TAB_TITLE, &MainWindow::OnRefreshTabTitle, this, wxID_ANY); Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnClose, this); Bind(CLOSE_TAB_EVENT, &MainWindow::OnCloseTabEvent, this, wxID_ANY); Bind(wxEVT_MENU, &MainWindow::OnMenuItemClick, this, wxID_ANY); Bind(REFRESH_ENGINE_LIST, &MainWindow::OnRefreshEngineList, this, wxID_ANY); Bind(CLOSE_LINKED_TAB, &MainWindow::OnCloseTabLinkedTo, this, wxID_ANY); Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSED, &MainWindow::OnAuiNotebookPageClosed, this, wxID_ANY); Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSE, &MainWindow::OnAuiNotebookPageCheck, this, wxID_ANY); // Add new game tab by default NewGame(std::shared_ptr(new Game())); // Temporary TO REMOVE JUST FOR TESTS: //BaseTab *bt = new BaseTab((wxFrame *)notebook, "/home/loic/pgn/wijk_2003_annotated.pgn"); //this->AddPage(bt,bt); } void MainWindow::OnAuiNotebookPageCheck(wxAuiNotebookEvent& event){ int selection=event.GetSelection(); TabInfos *t=(TabInfos*)notebook->GetPage(selection)->GetClientData(); if(t->is_dirty){ wxMessageDialog *dial = new wxMessageDialog(NULL, wxT("This tab contains data that are not saved. Are you sure you want to close it?"), wxT("Information"), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); if(dial->ShowModal() == wxID_YES) event.Allow(); else event.Veto(); } } void MainWindow::AddPage(wxWindow* window, TabInfos* infos){ window->SetClientData(infos); // Allows to have safer cast in this class notebook->AddPage(window, window->GetLabel()); notebook->SetSelection(notebook->GetPageIndex(window)); // Refresh tab that require knowledge on other tabs for(auto i: wxGetApp().ListTabInfos()){i->Refresh();} } void MainWindow::OnAuiNotebookPageClosed(wxAuiNotebookEvent& event){ UNUSED(event); // Refresh tab that require knowledge on other tabs for(auto i: wxGetApp().ListTabInfos()){i->Refresh();} } void MainWindow::OnCloseTabEvent(wxCommandEvent &event) { UNUSED(event); notebook->DeletePage(notebook->GetSelection()); // Refresh tab that require knowledge on other tabs for(auto i: wxGetApp().ListTabInfos()){i->Refresh();} } void MainWindow::OnCloseTabLinkedTo(wxCommandEvent &event){ TabInfos *infosEvent=(TabInfos*)event.GetClientData(); // Now close all tabs in the notebook related to the one in the event std::size_t i=0; while(iGetPageCount()){ wxWindow *page=notebook->GetPage(i); TabInfos* infos=(TabInfos*)page->GetClientData(); if(infos->is_linked && infos->linked_id==infosEvent->id){ notebook->DeletePage(i); // Remove page i=0; // Restart to page 0 since notebook updated (we just remove one page) } else i++; } } void MainWindow::OnMenuItemClick(wxCommandEvent &event) { int id = event.GetId(); if (id == wxID_EXIT) { Close(true); } else if (id >= 100 && id <=(100+engine_count)) { // Engine from manage menu wxMenuItemList items = manageMenu->GetMenuItems(); for (wxMenuItem *item : items) { if (item->GetId() == id) { std::uint32_t engine_id=item->GetId()-100; // Check if not already opened for(auto i: wxGetApp().ListTabInfos()){ if(i->type==TabInfos::ENGINE && i->GetEngineId()==engine_id){ wxGetApp().FocusOnTab(i); return; } } // Open engine configuration tag: wxLogDebug("Selected %s", item->GetItemLabel()); EngineTab *et = new EngineTab((wxWindow *)notebook, engine_id); AddPage(et,et); } } } else if (id == 1) { // Settings OpenSettings(); } else if (id == 2) { // New game NewGame(false); } else if (id == 3) { // New game from FEN NewGame(true); } else if (id == 4) { // Open first game wxFileDialog openFileDialog(this, _("Open single game"), "", "", "PGN files (*.pgn)|*.pgn", wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (openFileDialog.ShowModal() != wxID_CANCEL) { std::string path = openFileDialog.GetPath().ToStdString(); NewGame(OpenGameX(path,0)); } } else if (id == 5) { // Create database wxFileDialog newFileDialog(this, _("Create database file"), "", "", "PGN files (*.pgn)|*.pgn", wxFD_SAVE|wxFD_OVERWRITE_PROMPT); if (newFileDialog.ShowModal() == wxID_CANCEL) return; // Create and open new db std::string path = newFileDialog.GetPath().ToStdString(); BaseTab *bt = new BaseTab((wxFrame *)notebook, path); AddPage(bt,bt); } else if (id == 6) { // Open Database wxFileDialog openFileDialog(this, _("Open database"), "", "", "PGN files (*.pgn)|*.pgn", wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (openFileDialog.ShowModal() != wxID_CANCEL) { std::string path = openFileDialog.GetPath().ToStdString(); // Test base tab BaseTab *bt = new BaseTab((wxFrame *)notebook, path); AddPage(bt,bt); } } else if (id == 7) { // Create new engine NewEngine(); } else if (id == wxID_ABOUT) { // Create new engine ShowAbout(); } } void MainWindow::OnRefreshEngineList(wxCommandEvent &event) { UNUSED(event); // Delete all items wxMenuItemList items = manageMenu->GetMenuItems(); for (wxMenuItem *item : items) { manageMenu->Delete(item->GetId()); } // Refresh items CONFIG_OPEN(conf); conf->SetPath("engines/"); wxString engine_id; long index; if (conf->GetFirstGroup(engine_id, index)) { std::uint32_t id = 0; do { wxString engine_name=conf->Read(engine_id+"/name"); manageMenu->Append(100 + id, engine_name, "Configure " + engine_name); id++; } while (conf->GetNextGroup(engine_id, index)); engine_count=id; } CONFIG_CLOSE(conf); ApplyPreferences(); // Propagate informations to the tabs that require it } void MainWindow::NewEngine() { wxFileDialog openFileDialog(this, _("Use engine"), "", "", "Executable|*", wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (openFileDialog.ShowModal() != wxID_CANCEL) { std::string path = openFileDialog.GetPath().ToStdString(); uciadapter::UCI *engine; try { engine = new uciadapter::UCI(path); EngineTab *bt = new EngineTab((wxWindow *)notebook, engine, path); AddPage(bt,bt); } catch (...) { SHOW_DIALOG_ERROR("Could not communicate with the engine"); } } } void MainWindow::OpenSettings() { if (prefsEditor != nullptr) { delete prefsEditor; } prefsEditor = new wxPreferencesEditor("Preferences"); prefsEditor->AddPage(new BoardPrefs()); prefsEditor->AddPage(new EditorPrefs()); prefsEditor->Show(this); } void MainWindow::ApplyPreferences() { for (std::size_t i = 0; i < notebook->GetPageCount(); i++) { TabInfos *infos = (TabInfos*)(notebook->GetPage(i))->GetClientData(); infos->ApplyPreferences(); } } void MainWindow::OnClose(wxCloseEvent &e) { if (prefsEditor != nullptr) { prefsEditor->Dismiss(); } e.Skip(); } void MainWindow::NewGame(bool useFen) { if (useFen) { wxTextEntryDialog *dial = new wxTextEntryDialog(NULL, wxT("Enter FEN:"), wxT("Error")); if (dial->ShowModal() == wxID_OK) { try { NewGame(new Game(dial->GetValue().ToStdString())); } catch (...) { SHOW_DIALOG_ERROR("Invalid FEN"); } } } else { NewGame(std::shared_ptr(new Game())); } } void MainWindow::OnPageChange(wxAuiNotebookEvent &event) { UNUSED(event); TabInfos *infos = (TabInfos*)(notebook->GetCurrentPage())->GetClientData(); if (infos->type != TabInfos::GAME) { for (short i = 10; i < 20; i++) { if (menu_game->FindChildItem(i) != NULL) { menu_game->Enable(i, false); } } } } void MainWindow::OnRefreshTabTitle(wxCommandEvent &event) { wxWindow *win = (wxWindow*)event.GetEventObject(); int page = notebook->GetPageIndex(win); if (page != wxNOT_FOUND) { notebook->SetPageText(page, win->GetLabel()); } } TabInfos* MainWindow::NewGame(std::shared_ptr game) { GameTab *gt = new GameTab((wxFrame *)notebook, game); this->AddPage(gt,gt); return(gt); } void MainWindow::ShowAbout(){ DialogAbout *dialog=new DialogAbout(this); wxFont font(wxFontInfo(12)); dialog->app_icon->SetBitmap(LoadPNG("ochess",wxSize(80,80))); dialog->appname_text->SetFont(wxFont(wxFontInfo(18).Bold())); dialog->appname_text->SetLabel(wxT("OChess v"+std::string(OCHESS_VERSION))); // Populate info: wxRichTextCtrl *t=dialog->info_richtext; t->SetFont(font); t->BeginAlignment(wxTEXT_ALIGNMENT_CENTRE); t->BeginBold(); t->BeginFontSize(20); t->WriteText(wxT("OChess")); t->EndFontSize(); t->Newline(); t->EndBold(); t->WriteText(wxT("An open source software for chess games analysis and games databases management.")); t->Newline(); t->Newline(); t->BeginFontSize(8); t->WriteText(wxT("OChess is delivered under GPLv3 license")); t->Newline(); t->WriteText(wxT("Built on "+std::string(BUILD_TIME))); t->EndFontSize(); t->Newline(); t->Newline(); t->WriteText("Repository:"); t->Newline(); t->BeginURL("https://gitlab.com/manzerbredes/ochess"); t->BeginUnderline(); t->WriteText(wxT("https://gitlab.com/manzerbredes/ochess")); t->EndUnderline(); t->EndURL(); t->Newline(); t->Newline(); t->BeginFontSize(10); t->WriteText("For any questions/discussion please join the IRC chat at "); t->BeginURL("irc://irc.libera.chat/ochess"); t->BeginUnderline(); t->WriteText(wxT("irc://irc.libera.chat/ochess")); t->EndUnderline(); t->EndURL(); t->EndFontSize(); t->Newline(); t->EndAlignment(); // Populate credits: wxRichTextCtrl *c=dialog->credits_richtext; c->SetFont(font); c->BeginBold(); c->WriteText("Developers:"); c->EndBold(); c->Newline(); c->WriteText(" - manzerbredes "); dialog->Show(); }