aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoic Guegan <manzerbredes@mailbox.org>2023-01-10 11:14:25 +0100
committerLoic Guegan <manzerbredes@mailbox.org>2023-01-10 11:14:25 +0100
commite069a29f99dfb6e1139f47f3bb291902752d1283 (patch)
tree746ffcbfc5d17f076a34eed6a86fb086df979526
parent179a173b3b063a6e9e9807912919b77abbbe5115 (diff)
Debug animations, LiveEngine and improve arrow/squares highlights
-rw-r--r--TODO.md2
-rw-r--r--src/MainWindow.cpp4
-rw-r--r--src/game_tab/left_panel/GameTabLeftPanel.cpp39
-rw-r--r--src/game_tab/left_panel/GameTabLeftPanel.hpp2
-rw-r--r--src/game_tab/left_panel/board/BoardCanvas.cpp88
-rw-r--r--src/game_tab/left_panel/board/BoardCanvas.hpp20
-rw-r--r--src/game_tab/right_panel/LiveEngineDialog.cpp34
7 files changed, 95 insertions, 94 deletions
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<std::string> 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<std::string> engine_arrows;
+ std::vector<GameState::Arrow> engine_arrows;
public:
GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> 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=i<gs.squares_hl.size() ? gs.squares_hl[i] : squares_hl[i-gs.squares_hl.size()];
- std::uint8_t sfile = s[0]-'a';
- std::uint8_t srank = s[1]-'1';
+ const GameState::Square &s=i<gs.squares_hl.size() ? gs.squares_hl[i] : squares_hl[i-gs.squares_hl.size()];
+ std::uint8_t sfile = s.square[0]-'a';
+ std::uint8_t srank = s.square[1]-'1';
if (!black_side) {
srank = 7 - srank;
sfile = 7 - sfile;
}
if(srank == rank && sfile==file){
- char type='a';
- if(s.size()>2)
- 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= i<gs.arrows.size() ? gs.arrows[i] : arrows[i-gs.arrows.size()];
- std::uint8_t sfile = arrow[0]-'a';
- std::uint8_t srank = arrow[1]-'1';
- std::uint8_t dfile = arrow[2]-'a';
- std::uint8_t drank = arrow[3]-'1';
+ for(int i=0;i<(gs.arrows.size()+arrows.size());i++){
+ const GameState::Arrow &arrow= i<gs.arrows.size() ? gs.arrows[i] : arrows[i-gs.arrows.size()];
+ std::uint8_t sfile = arrow.src[0]-'a';
+ std::uint8_t srank = arrow.src[1]-'1';
+ std::uint8_t dfile = arrow.dst[0]-'a';
+ std::uint8_t drank = arrow.dst[1]-'1';
if (!black_side) {
srank = 7 - srank;
sfile = 7 - sfile;
@@ -414,37 +404,20 @@ void BoardCanvas::DrawBoard(wxDC &dc) {
std::uint32_t dy = boardY + drank * square_width + square_width/2;
// Parse arrow for metadata (maybe having a datatype is better)
- std::uint8_t thickness=50;
- if(arrow.size()>4){
- 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<short, short, short> 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<char, std::uint8_t> captures;
- std::vector<std::string> squares_hl;
- std::vector<std::string> arrows;
+ std::vector<Square> squares_hl;
+ std::vector<Arrow> 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<std::string> squares_hl;
- std::vector<std::string> arrows;
+ std::vector<GameState::Square> squares_hl;
+ std::vector<GameState::Arrow> 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<int> 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);