#include "GameTabLeftPanel.hpp" #include GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, std::shared_ptr game) : TabGameLeftPanel(parent), game(game), repeat(false), is_engine_on(false) { // Configure toolbar (note that toolbar events are processed into the GameTab class) game_toolbar->AddTool(0, wxT("Save As"), wxArtProvider::GetBitmap(wxART_FILE_SAVE, wxART_TOOLBAR)); game_toolbar->AddTool(1, wxT("Duplicate Game"), wxArtProvider::GetBitmap(wxART_COPY, wxART_TOOLBAR)); // Add board board_canvas = new BoardCanvas((wxFrame *)this); main_sizer->Insert(1, board_canvas, 1, wxEXPAND); // Configure buttons swap_button->SetBitmapLabel(LoadPNG("swap")); zoomin_button->SetBitmapLabel(LoadPNG("zoomin")); zoomout_button->SetBitmapLabel(LoadPNG("zoomout")); // Configure FEN field fen_text_field->SetFont(wxFont(*wxNORMAL_FONT).Bold().Larger()); last_move=game->GetCurrentMove(); // Bind events: Bind(PLAY_MOVE_EVENT, &GameTabLeftPanel::OnPlay, this, wxID_ANY); Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Zoom(10);}, ZOOM_IN_BTN); Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Zoom(-10);}, ZOOM_OUT_BTN); Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Swap();}, SWAP_BTN); Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){p->repeat=false;}); Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){ if(e.GetKeyCode() == WXK_RIGHT){ p->game->Next(); p->Notify(); p->repeat=true; } else if(e.GetKeyCode() == WXK_LEFT){ p->game->Previous(); p->Notify(); p->repeat=true; } // Notify other classes wxCommandEvent event(GAME_CHANGE, p->GetId()); event.SetEventObject(p); p->ProcessEvent(event); }); Bind(wxEVT_MOUSEWHEEL, [p=this](wxMouseEvent& e){ if(e.GetWheelRotation()<0){ p->game->Next(); p->Notify(); }else { p->game->Previous(); p->Notify(); } // Notify other classes wxCommandEvent event(GAME_CHANGE, p->GetId()); event.SetEventObject(p); p->ProcessEvent(event); }); } void GameTabLeftPanel::OnPlay(wxCommandEvent &event) { engine_arrows.clear(); // Remove displayed engine arrows std::string move=event.GetString().ToStdString(); int size=move.size(); char promote=(char)event.GetInt(); // First check if it is a promotion move (to prompt the user for a piece) if(size>0 && game->IsPromotionMove(move)){ promote_on=move.substr(2,2); // Will trigger the piece prompt on next Notify() promotion_move=move; // Save the move that should be played for the promotion } else { if(size==0){ // It is a promotion move? move=promotion_move; // Play the save promotion move promote_on.clear(); // Clear user prompte (cf. Notify()) promotion_move.clear(); } if(game->Play(move,promote)){ // Notify other classes wxCommandEvent event(GAME_CHANGE, GetId()); event.SetEventObject(this); ProcessEvent(event); } } Notify(true); // Redraw event is move failed! Otherwise piece not resets to it initial position after dragging } void GameTabLeftPanel::SetEngineEvaluation(EngineEvaluation eval){ if(is_engine_on){ engine_arrows.clear(); float scale=1; unsigned char color=0; for(auto const &arrow: eval.best_lines){ std::string src=arrow.substr(0,2); std::string dst=arrow.substr(2,2); engine_arrows.push_back({src,dst,wxColour(color,color,color),scale}); scale=std::max(0.1,scale-0.25); color=std::min(255,color+70); } eval_cp=eval.eval; Notify(true); } } void GameTabLeftPanel::SetLiveEngineState(bool isOn){ is_engine_on=isOn; if(!is_engine_on){ engine_arrows.clear(); eval_cp=0; Notify(true); } } void GameTabLeftPanel::Notify(bool skip_animation) { // Update fen and captures std::string fen = game->GetFen(); std::map captures; bool animate=false; HalfMove *m = game->GetCurrentMove(); std::string src,dst; // Update capture and check if we should to animations during moves change: if (m){ captures = m->GetLineCaptures(); if(m->HasParent(last_move) && !m->IsVariation()){ m->GetAbsoluteMove(src,dst); animate=true; }else if(m->HasChild(last_move) && !last_move->IsVariation()){ // call to IsVariation is safe because of HasChild() before! cf below // Accessing last_move here is safe since it is still // in the tree of moves (since HasChild found it so not deleted) last_move->GetAbsoluteMove(dst,src); animate=true; } } else if(game->GetNextMove()){ // First move animation HalfMove *next=game->GetNextMove(); if(next==last_move){ game->GetNextMove()->GetAbsoluteMove(dst,src); animate=true; } } // Update board canvas: GameState gs; gs.board=chessarbiter::FENParser::Parse(fen).board; gs.is_black_turn=game->IsBlackToPlay(); gs.captures=captures; gs.white=game->GetTag("White"); gs.black=game->GetTag("Black"); gs.mat_black=game->IsCheckmate(true); gs.mat_white=game->IsCheckmate(false); gs.arrows=engine_arrows; gs.promotion=promote_on; gs.show_evalbar=is_engine_on; gs.eval=eval_cp/100; if(m){ // There should be a valid src_hl or dst_hl ortherwise it explode: std::string src_hl, dst_hl; m->GetAbsoluteMove(src_hl,dst_hl); if(src_hl.size()>0){ // Just in case gs.squares_hl.push_back({src_hl,wxColour(255,190,190)}); gs.squares_hl.push_back({dst_hl,wxColour(255,100,100)}); } } if(skip_animation || !animate){ board_canvas->SetupBoard(gs); } else{ board_canvas->Animate(gs, src,dst,repeat); } // Update last move last_move=m; // Update fen field: fen_text_field->SetValue(game->GetFen()); } void GameTabLeftPanel::ApplyPreferences() { board_canvas->ApplyPreferences(); }