#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) { 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); 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){ // TODO: Ask the user before closing //event.Veto(); } void MainWindow::AddPage(wxWindow* window, TabInfos* infos){ window->SetClientData(infos); 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){ // Refresh tab that require knowledge on other tabs for(auto i: wxGetApp().ListTabInfos()){i->Refresh();} } void MainWindow::OnCloseTabEvent(wxCommandEvent &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 int 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) { std::uint32_t id = event.GetId(); if (id == wxID_EXIT) { Close(true); } else if (id >= 100) { // Engine from manage menu wxMenuItemList items = manageMenu->GetMenuItems(); for (wxMenuItem *item : items) { if (item->GetId() == id) { wxLogDebug("Selected %s", item->GetItemLabel()); EngineTab *bt = new EngineTab((wxWindow *)notebook, item->GetItemLabel().ToStdString()); notebook->AddPage(bt, bt->GetLabel()); notebook->SetSelection(notebook->GetPageIndex(bt)); } } } 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(); } } void MainWindow::OnRefreshEngineList(wxCommandEvent &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_name; long index; if (conf->GetFirstGroup(engine_name, index)) { std::uint32_t id = 0; do { manageMenu->Append(100 + id, engine_name, "Configure " + engine_name); id++; } while (conf->GetNextGroup(engine_name, index)); } CONFIG_CLOSE(conf); ApplyPreferences(); // Propagate motifications } 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 (int i = 0; i < notebook->GetPageCount(); i++) { TabInfos *infos = dynamic_cast(notebook->GetPage(i)); 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) { TabInfos *infos = dynamic_cast(notebook->GetCurrentPage()); 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) { GameTab *win = dynamic_cast(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); }