diff --git a/TODO.md b/TODO.md index 4496664..bb40991 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ ## Before releasing v0.1.0 - [ ] Implement pawn promotions in BoardCanvas - - [ ] Debug animations (have a more reliable approach (can segfault when clicking on variations in the editor)) + - [x] Debug animations (have a more reliable approach (can segfault when clicking on variations in the editor)) - [x] In BoardCanvas search for a workaround of the dynamic allocation of adata.buffer (on canvas resize) - [x] Bind the chess game editor settings to EditorPrefs.hpp - [x] Ask before closing MainWindow/Tabs if anything is not saved diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 6202889..7a8c27f 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -59,8 +59,8 @@ MainWindow::MainWindow() // Temporary TO REMOVE JUST FOR TESTS: - /*BaseTab *bt = new BaseTab((wxFrame *)notebook, "/home/loic/pgn/wijk_2003_annotated.pgn"); - this->AddPage(bt,bt);*/ + //BaseTab *bt = new BaseTab((wxFrame *)notebook, "/home/loic/pgn/wijk_2003_annotated.pgn"); + //this->AddPage(bt,bt); } void MainWindow::OnAuiNotebookPageCheck(wxAuiNotebookEvent& event){ diff --git a/src/game_tab/left_panel/GameTabLeftPanel.cpp b/src/game_tab/left_panel/GameTabLeftPanel.cpp index 5a7877d..d034115 100644 --- a/src/game_tab/left_panel/GameTabLeftPanel.cpp +++ b/src/game_tab/left_panel/GameTabLeftPanel.cpp @@ -72,14 +72,15 @@ void GameTabLeftPanel::OnPlay(wxCommandEvent &event) { } void GameTabLeftPanel::SetEngineArrows(std::vector arrows){ - engine_arrows=arrows; - int min_size=5, max_size=80; - int steps=(max_size-min_size)/arrows.size(); - int current_size=max_size; - for(std::string &arrow:engine_arrows){ - wxLogDebug("%s",arrow); - arrow+="#000000%"+std::to_string(current_size); - current_size-=steps; + engine_arrows.clear(); + float scale=1; + unsigned char color=0; + for(auto const &arrow:arrows){ + 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); } Notify(true); } @@ -94,16 +95,14 @@ void GameTabLeftPanel::Notify(bool skip_animation) { // Update capture and check if we should to animations during moves change: if (m){ captures = m->GetLineCaptures(); - if(!m->IsVariation()){ // Animations can lead to segfault when clicking on CGEditor move - if(m->HasParent(last_move)){ - m->GetAbsoluteMove(src,dst); - animate=true; - }else if(m->HasChild(last_move)){ - // 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; - } + 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(); @@ -128,8 +127,8 @@ void GameTabLeftPanel::Notify(bool skip_animation) { 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+"d"); - gs.squares_hl.push_back(dst_hl+"a"); + 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){ diff --git a/src/game_tab/left_panel/GameTabLeftPanel.hpp b/src/game_tab/left_panel/GameTabLeftPanel.hpp index 2dec70d..6bd6b38 100644 --- a/src/game_tab/left_panel/GameTabLeftPanel.hpp +++ b/src/game_tab/left_panel/GameTabLeftPanel.hpp @@ -13,7 +13,7 @@ class GameTabLeftPanel : public TabGameLeftPanel { BoardCanvas *board_canvas; bool repeat; HalfMove *last_move; - std::vector engine_arrows; + std::vector engine_arrows; public: GameTabLeftPanel(wxFrame *parent, std::shared_ptr game); diff --git a/src/game_tab/left_panel/board/BoardCanvas.cpp b/src/game_tab/left_panel/board/BoardCanvas.cpp index 9c80196..9294006 100644 --- a/src/game_tab/left_panel/board/BoardCanvas.cpp +++ b/src/game_tab/left_panel/board/BoardCanvas.cpp @@ -18,9 +18,10 @@ BoardCanvas::BoardCanvas(wxFrame *parent) valid_drag = false; arrow_drag = false; arrows_offset = t->GetSquaresSizes()/2.5; + arrow_thickness = t->GetSquaresSizes()/1.8; // Init animation data adata.duration=100; - adata.duration_fast=100; + adata.duration_fast=50; adata.fps=60; adata.buffer=new wxBitmap(500,500,32); adata.animate=false; @@ -230,30 +231,19 @@ void BoardCanvas::DrawBoard(wxDC &dc) { // Draw highlighted squares for(int i=0;i<(gs.squares_hl.size()+squares_hl.size());i++){ - const std::string &s=i2) - type=s[2]; - // Default highlight (type='a' or something else not supported) dc.SetPen(wxNullPen); - dc.SetBrush(wxColour(255, 102, 122)); - if(type=='b') - dc.SetBrush(wxColour(120, 255, 102)); - else if(type=='c') - dc.SetBrush(wxColour(102, 196, 255)); - else if(type=='d') - dc.SetBrush(wxColour(255, 204, 213)); - else if(type=='e') - dc.SetBrush(wxColour(220, 255, 204)); - else if(type=='f') - dc.SetBrush(wxColour(204, 231, 255)); + if(s.color!=wxNullColour) + dc.SetBrush(s.color); + else + dc.SetBrush(wxColour(255, 102, 122)); dc.DrawRectangle(wxRect(x,y,square_width,square_width)); } } @@ -396,12 +386,12 @@ void BoardCanvas::DrawBoard(wxDC &dc) { boardY + square_width * 8 + numbers_size.y*2)); } // Draw arrows - for(int i=0;i<(gs.arrows.size()+arrows.size());i++){ - const std::string &arrow= i4){ - std::string color="#"; - std::string new_thickness=""; - char key='?'; - for(const char &c:arrow){ - if(c=='#'||c=='%'){ - key=c; - continue; - }else if(key=='#'){ - color+=c; - } else if(key=='%'){ - new_thickness+=c; - } - } - if(color.size()>1) - dc.SetBrush(wxColour(color)); - if(new_thickness.size()>0) - thickness=(std::uint8_t)std::stoi(new_thickness); - } else + if(arrow.color!=wxNullColour) + dc.SetBrush(arrow.color); + else dc.SetBrush(color_arrows); if(((abs(drank-srank) == 2) && (abs(dfile-sfile) == 1))|| ((abs(drank-srank) == 1) && (abs(dfile-sfile) == 2))){ if(abs(drank-srank) == 1){ - DrawLArrow(dc,sx,sy,dx,dy,false,thickness); + DrawLArrow(dc,sx,sy,dx,dy,false,arrow_thickness*arrow.scale); } else { - DrawLArrow(dc,sx,sy,dx,dy,true,thickness); + DrawLArrow(dc,sx,sy,dx,dy,true,arrow_thickness*arrow.scale); } } else { - DrawArrow(dc,sx,sy,dx,dy,thickness); + DrawArrow(dc,sx,sy,dx,dy,arrow_thickness*arrow.scale); } } } @@ -519,14 +492,22 @@ void BoardCanvas::MouseEvent(wxMouseEvent &event) { std::to_string(+active_square.y + 1); std::string dst=((char)('a' + file)) + std::to_string(rank + 1); if(src!=dst){ - arrows.push_back(src+dst); + arrows.push_back(DEFAULT_ARROW(src,dst)); wxLogDebug("Draw arrow %s",src+dst); } else { - if(std::count(squares_hl.begin(), squares_hl.end(), src)){ - squares_hl.erase(std::remove(squares_hl.begin(), squares_hl.end(), src), squares_hl.end()); - }else{ - squares_hl.push_back(src+"f"); + int id=0; + bool removed=false; + for(GameState::Square &s:squares_hl){ + if(s.square==src){ + squares_hl.erase(squares_hl.begin()+id); + removed=true; + break; + } + id++; + } + if(!removed){ + squares_hl.push_back(DEFAULT_SQUARE(src)); wxLogDebug("Highlight square %s",src); } } @@ -548,6 +529,7 @@ void BoardCanvas::Zoom(std::int32_t zoom) { if(!t->Zoom(zoom)) return; t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + arrow_thickness = t->GetSquaresSizes()/1.8; Refresh(); } diff --git a/src/game_tab/left_panel/board/BoardCanvas.hpp b/src/game_tab/left_panel/board/BoardCanvas.hpp index 553994c..bc850b7 100644 --- a/src/game_tab/left_panel/board/BoardCanvas.hpp +++ b/src/game_tab/left_panel/board/BoardCanvas.hpp @@ -35,6 +35,8 @@ wxDECLARE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); #define CAPTURE_FACTOR 0.35 #define SQUARE_NUM_PADDING 5 +#define DEFAULT_ARROW(SRC,DST) {(SRC),(DST),wxNullColour,1} +#define DEFAULT_SQUARE(SQUARE) {(SQUARE),wxNullColour} typedef std::tuple ClockTime; @@ -61,11 +63,20 @@ typedef struct AnimState { } AnimState; typedef struct GameState { + typedef struct Arrow { + std::string src,dst; + wxColour color=wxNullColour; + float scale=1; + } Arrow; + typedef struct Square { + std::string square; + wxColour color=wxNullColour; + } Square; std::string white, black; std::string board; std::map captures; - std::vector squares_hl; - std::vector arrows; + std::vector squares_hl; + std::vector arrows; bool is_black_turn; bool mat_black; bool mat_white; @@ -78,10 +89,11 @@ class BoardCanvas : public wxPanel { Theme *t, *t_captures; wxColour color_arrows; int arrows_offset; + std::uint8_t arrow_thickness; std::string white_player,black_player; // Current highlighted squares and arrows: - std::vector squares_hl; - std::vector arrows; + std::vector squares_hl; + std::vector arrows; // Various canvas state variables bool black_side, is_dragging, valid_drag, arrow_drag, is_black_turn; diff --git a/src/game_tab/right_panel/LiveEngineDialog.cpp b/src/game_tab/right_panel/LiveEngineDialog.cpp index 0c2ecfc..2413d0b 100644 --- a/src/game_tab/right_panel/LiveEngineDialog.cpp +++ b/src/game_tab/right_panel/LiveEngineDialog.cpp @@ -101,23 +101,31 @@ void LiveEngineDialog::StartEngine() { } void LiveEngineDialog::OnTimerTick(wxTimerEvent &event) { - wxLogDebug("Tick!"); - lines_list->DeleteAllItems(); + lines_list->DeleteAllItems(); // Clear lines_list engine->SyncAfter(0); EngineEvaluation *eval=new EngineEvaluation(); - auto const &lines=engine->GetLines(); - eval->best_lines.resize(lines.size()); - for (auto const &line : lines) { - long index = lines_list->InsertItem(0, std::to_string(line.first)); + auto lines=engine->GetLines(); // First best lines + + // First retrieve lines ids from unordered map lines + std::vector ids; + for(auto const &line : lines){ + ids.push_back(line.first); + } + std::sort(ids.begin(),ids.end()); + + // Now fill eval and lines_list + for (int &id:ids) { + auto const &line=lines[id]; + long index = lines_list->InsertItem(id, std::to_string(id)); + // Update eval that will be deplayed on the board + if(line.pv.size()>0) + eval->best_lines.push_back(line.pv[0]); + // Refresh lines_list std::string line_moves; - for (std::string move : line.second.pv) { + for (std::string move : line.pv) line_moves += move + " "; - } - if(line.second.pv.size()>0){ - eval->best_lines.insert(eval->best_lines.begin()+line.first,line.second.pv[0]); - } - std::string cp_str = std::to_string(line.second.score_cp); - if (line.second.score_cp > 0) { + std::string cp_str = std::to_string(line.score_cp); + if (line.score_cp > 0) { cp_str = "+" + cp_str; } lines_list->SetItem(index, 1, cp_str);