diff options
| author | Loic Guegan <manzerbredes@mailbox.org> | 2023-01-02 12:02:11 +0100 |
|---|---|---|
| committer | Loic Guegan <manzerbredes@mailbox.org> | 2023-01-02 12:02:11 +0100 |
| commit | e40f98ccda04da3bb9811b354b770fb8c6b563e5 (patch) | |
| tree | 3b0258e0cb3eca9f979d79d71da938fa7efb4bc8 /src/game_tab/left_panel | |
| parent | d05093513ec5124feed0dc6140789f48218b45c9 (diff) | |
| parent | 042f6ca17012414d13235d3e04ea9012ff49f79c (diff) | |
Improve game tab
Diffstat (limited to 'src/game_tab/left_panel')
| -rw-r--r-- | src/game_tab/left_panel/GameTabLeftPanel.cpp | 78 | ||||
| -rw-r--r-- | src/game_tab/left_panel/GameTabLeftPanel.hpp | 4 | ||||
| -rw-r--r-- | src/game_tab/left_panel/board/BoardCanvas.cpp | 112 | ||||
| -rw-r--r-- | src/game_tab/left_panel/board/BoardCanvas.hpp | 20 | ||||
| -rw-r--r-- | src/game_tab/left_panel/board/Theme.cpp | 17 | ||||
| -rw-r--r-- | src/game_tab/left_panel/board/Theme.hpp | 3 |
6 files changed, 140 insertions, 94 deletions
diff --git a/src/game_tab/left_panel/GameTabLeftPanel.cpp b/src/game_tab/left_panel/GameTabLeftPanel.cpp index 50919c0..25ded2c 100644 --- a/src/game_tab/left_panel/GameTabLeftPanel.cpp +++ b/src/game_tab/left_panel/GameTabLeftPanel.cpp @@ -21,6 +21,7 @@ GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game) // 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); @@ -31,11 +32,11 @@ GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game) Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){ if(e.GetKeyCode() == WXK_RIGHT){ p->game->Next(); - p->Notify(true,false); + p->Notify(); p->repeat=true; } else if(e.GetKeyCode() == WXK_LEFT){ p->game->Previous(); - p->Notify(true,true); + p->Notify(); p->repeat=true; } // Notify other classes @@ -46,10 +47,10 @@ GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game) Bind(wxEVT_MOUSEWHEEL, [p=this](wxMouseEvent& e){ if(e.GetWheelRotation()<0){ p->game->Next(); - p->Notify(true,false); + p->Notify(); }else { p->game->Previous(); - p->Notify(true,true); + p->Notify(); } // Notify other classes wxCommandEvent event(GAME_CHANGE, p->GetId()); @@ -67,54 +68,53 @@ void GameTabLeftPanel::OnPlay(wxCommandEvent &event) { event.SetEventObject(this); ProcessEvent(event); } - // Refresh board canvas: - Notify(); + Notify(true); // Redraw event is move failed! Otherwise piece not resets to it initial position after dragging } -void GameTabLeftPanel::Notify(bool animate, bool backward) { +void GameTabLeftPanel::Notify(bool skip_animation) { // Update fen and captures std::string fen = game->GetFen(); std::map<char, std::uint8_t> captures; + bool animate=false; HalfMove *m = game->GetCurrentMove(); - if (m != nullptr) { + 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->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; + } + } 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: - if(!animate){ - if(m){ - last_absolute_move=m->GetAbsoluteMove(); - } - board_canvas->SetupBoard(chessarbiter::FENParser::Parse(fen).board, - game->IsBlackToPlay(), captures, - game->GetTag("White"),game->GetTag("Black")); + 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); + if(skip_animation || !animate){ + board_canvas->SetupBoard(gs); } else{ - if(backward && last_absolute_move.size()>0){ - std::string dst=last_absolute_move.substr(0,2); - std::string src=last_absolute_move.substr(2,2); - board_canvas->Animate(chessarbiter::FENParser::Parse(fen).board, - game->IsBlackToPlay(), captures,src,dst,repeat); - if(m){ - last_absolute_move=m->GetAbsoluteMove(); - } - } - else if(!backward && m){ - std::string new_absolute_move=m->GetAbsoluteMove(); - if(last_absolute_move!=new_absolute_move){ - last_absolute_move=new_absolute_move; - std::string src=last_absolute_move.substr(0,2); - std::string dst=last_absolute_move.substr(2,2); - board_canvas->Animate(chessarbiter::FENParser::Parse(fen).board, - game->IsBlackToPlay(), captures,src,dst,repeat); - } - } - // If m undefined - if(!m){ - last_absolute_move=""; - } + board_canvas->Animate(gs, src,dst,repeat); } - + // Update last move + last_move=m; // Update fen field: fen_text_field->SetValue(game->GetFen()); } diff --git a/src/game_tab/left_panel/GameTabLeftPanel.hpp b/src/game_tab/left_panel/GameTabLeftPanel.hpp index b22d6fc..56297d8 100644 --- a/src/game_tab/left_panel/GameTabLeftPanel.hpp +++ b/src/game_tab/left_panel/GameTabLeftPanel.hpp @@ -11,12 +11,12 @@ wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); class GameTabLeftPanel : public TabGameLeftPanel { std::shared_ptr<Game> game; BoardCanvas *board_canvas; - std::string last_absolute_move; bool repeat; + HalfMove *last_move; public: GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game); - void Notify(bool animate=false,bool backward=false); + void Notify(bool skip_animation=false); void OnPlay(wxCommandEvent &event); void OnGotoMove(wxCommandEvent &event); void OnRefreshBoard(wxCommandEvent &event); diff --git a/src/game_tab/left_panel/board/BoardCanvas.cpp b/src/game_tab/left_panel/board/BoardCanvas.cpp index 1a85176..f6846f1 100644 --- a/src/game_tab/left_panel/board/BoardCanvas.cpp +++ b/src/game_tab/left_panel/board/BoardCanvas.cpp @@ -3,25 +3,50 @@ wxDEFINE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); BoardCanvas::BoardCanvas(wxFrame *parent) - : wxPanel(parent), black_side(false), is_black_turn(true), frozen(false), + : wxPanel(parent), black_side(false), frozen(false), lock_square_size(false), t(new Theme()), t_captures(new Theme()) { - board = "rnbqkbnrpppppppp PPPPPPPPRNBQKBNR"; is_dragging = false; valid_drag = false; + // Init animation data + adata.duration=200; + adata.duration_fast=80; + adata.fps=30; + adata.buffer=new wxBitmap(500,500,32); adata.reuseBuffer=false; adata.buffer=nullptr; - t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + // Init game state + gs.is_black_turn=false; + gs.board = "rnbqkbnrpppppppp PPPPPPPPRNBQKBNR"; + gs.mat_black=false; + gs.mat_white=false; + // Init clocks SetClockTime(-1, -1, -1, false); SetClockTime(-1, -1, -1, true); + // Init capture pieces + t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + // Load preferences ApplyPreferences(); // The following should be called when using an EVT_PAINT handler SetBackgroundStyle(wxBG_STYLE_PAINT); - adata.duration=200; - adata.duration_fast=80; - adata.fps=30; // Let GameTableLeftPanel process keyboard events: Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();}); Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){e.ResumePropagation(1);e.Skip();}); + Bind(wxEVT_PAINT, &BoardCanvas::OnPaint, this); + Bind(wxEVT_SIZE, &BoardCanvas::OnResize, this); + // Mouse events: + Bind(wxEVT_MOTION, &BoardCanvas::MouseEvent, this); + Bind(wxEVT_LEFT_DOWN, &BoardCanvas::MouseEvent, this); + Bind(wxEVT_LEFT_UP, &BoardCanvas::MouseEvent, this); +} + +void BoardCanvas::OnResize(wxSizeEvent &e){ + wxSize size=e.GetSize(); + if(size.x>100 && size.y>100){ + // Setup buffer (use for animations) + if(adata.buffer!=nullptr) + free(adata.buffer); + adata.buffer=new wxBitmap(size.x,size.y,32); + } } BoardCanvas::~BoardCanvas() { @@ -43,7 +68,6 @@ BoardCanvas::BoardCanvas(wxFrame *parent, std::uint32_t square_width, void BoardCanvas::OnPaint(wxPaintEvent &event) { wxBufferedPaintDC dc(this); dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); if(!adata.reuseBuffer){ // Setting up required attributes @@ -56,12 +80,8 @@ void BoardCanvas::OnPaint(wxPaintEvent &event) { boardX = 0; if (boardY > canvas_size.y) boardY = 0; - - // Setup buffer (later use for animations) - if(adata.buffer!=nullptr) - free(adata.buffer); - adata.buffer=new wxBitmap(canvas_size.x,canvas_size.y,32); wxMemoryDC memDC(*adata.buffer); + memDC.Clear(); DrawBoard(memDC); dc.Blit(0,0,canvas_size.x,canvas_size.y,(wxDC*)&memDC,0,0); } @@ -73,7 +93,7 @@ void BoardCanvas::OnPaint(wxPaintEvent &event) { dc.DrawBitmap(*t->Get(adata.piece_moved), adata.src.x + adata.frame*(adata.transVect.x/adata.frames), adata.src.y + adata.frame*(adata.transVect.y/adata.frames), false); - // end drawing + // End drawing adata.frame++; } } @@ -100,24 +120,26 @@ void BoardCanvas::ApplyPreferences() { Refresh(); } -void BoardCanvas::SetupBoard(std::string board, bool is_black_turn, - std::map<char, std::uint8_t> captures, - std::string white_player, std::string black_player) { - this->board = board; - this->is_black_turn = is_black_turn; - this->captures = captures; - this->white_player=white_player; - this->black_player=black_player; +void BoardCanvas::SetupBoard(const GameState &new_gs) { + gs.board = new_gs.board; + gs.is_black_turn = new_gs.is_black_turn; + gs.captures = new_gs.captures; + gs.white=new_gs.white; + gs.black=new_gs.black; + gs.mat_white=new_gs.mat_white; + gs.mat_black=new_gs.mat_black; + gs.black_time=new_gs.black_time; + gs.white_time=new_gs.white_time; Refresh(); } -void BoardCanvas::Animate(const std::string &board, bool is_black_turn, std::map<char, std::uint8_t> captures, std::string src, std::string dst,bool faster){ +void BoardCanvas::Animate(const GameState &new_gs, std::string src, std::string dst, bool faster){ std::uint8_t pfile = src[0]-'a'; std::uint8_t prank = src[1]-'1'; - adata.piece_moved = this->board[pfile + 8 * (7-prank)]; // Piece to move + adata.piece_moved = gs.board[pfile + 8 * (7-prank)]; // Piece to move // Now remove the piece that will be moved - this->board[pfile + 8 * (7-prank)]=' '; + gs.board[pfile + 8 * (7-prank)]=' '; wxMemoryDC memDC(*adata.buffer); DrawBoard(memDC); @@ -164,7 +186,7 @@ void BoardCanvas::Animate(const std::string &board, bool is_black_turn, std::map } adata.duration=faster ? duration_backup : duration_backup; adata.reuseBuffer=false; - SetupBoard(board, is_black_turn, captures,white_player,black_player); + SetupBoard(new_gs); } void BoardCanvas::DrawBoard(wxDC &dc) { @@ -217,7 +239,7 @@ void BoardCanvas::DrawBoard(wxDC &dc) { } std::uint32_t px = x + centrer_offset; std::uint32_t py = y + centrer_offset; - char piece = board[(7 - pfile) + 8 * prank]; + char piece = gs.board[(7 - pfile) + 8 * prank]; if (is_dragging && (7 - pfile) == active_square.x && (7 - prank) == active_square.y) { dp = piece; @@ -228,6 +250,8 @@ void BoardCanvas::DrawBoard(wxDC &dc) { } if (piece != ' ') { dc.DrawBitmap(*t->Get(piece), px, py, false); + if((piece == 'k' && gs.mat_black) || (piece == 'K' && gs.mat_white)) + dc.DrawBitmap(*t->Get('#'), x+square_width/2+centrer_offset, y+centrer_offset, false); } } } @@ -236,7 +260,7 @@ void BoardCanvas::DrawBoard(wxDC &dc) { dc.SetPen(wxPen(*wxBLACK, 3)); std::uint32_t badgeY = boardY; std::uint32_t badgeWidth = square_width / 2; - if (is_black_turn) { + if (gs.is_black_turn) { dc.SetBrush(*wxBLACK_BRUSH); if (black_side) { badgeY = boardY + (8 * square_width) - badgeWidth; @@ -265,15 +289,15 @@ void BoardCanvas::DrawBoard(wxDC &dc) { offsetYPlayerName = offsetY+captures_size; } for (char p : {'P', 'N', 'B', 'R', 'Q'}) { - if (captures.find(p) != captures.end()) { - for (std::uint8_t i = 0; i < captures[p]; i++) { + if (gs.captures.find(p) != gs.captures.end()) { + for (std::uint8_t i = 0; i < gs.captures[p]; i++) { dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); offsetX += captures_size / 2; } offsetX += captures_size / 2; } } - dc.DrawText(wxString(black_player),boardX,boardY + offsetYPlayerName); + dc.DrawText(wxString(gs.black),boardX,boardY + offsetYPlayerName); // Black (white's captures): offsetX = 0; if (black_side) { @@ -284,15 +308,15 @@ void BoardCanvas::DrawBoard(wxDC &dc) { offsetYPlayerName = offsetY+captures_size; } for (char p : {'p', 'n', 'b', 'r', 'q'}) { - if (captures.find(p) != captures.end()) { - for (std::uint8_t i = 0; i < captures[p]; i++) { + if (gs.captures.find(p) != gs.captures.end()) { + for (std::uint8_t i = 0; i < gs.captures[p]; i++) { dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); offsetX += captures_size / 2; } offsetX += captures_size / 2; } } - dc.DrawText(wxString(white_player),boardX,boardY + offsetYPlayerName); + dc.DrawText(wxString(gs.white),boardX,boardY + offsetYPlayerName); // Draw dragging piece if (DrawDraggingPiece) { @@ -306,9 +330,9 @@ void BoardCanvas::DrawBoard(wxDC &dc) { } // Draw Clocks - if (std::get<0>(black_time) >= 0) { + if (std::get<0>(gs.black_time) >= 0) { wxFont font = dc.GetFont(); - ClockTime clock = black_side ? white_time : black_time; + ClockTime clock = black_side ? gs.white_time : gs.black_time; wxString time = wxString::Format("%ds", std::get<1>(clock), std::get<2>(clock)); if (std::get<0>(clock) > 0) { @@ -321,7 +345,7 @@ void BoardCanvas::DrawBoard(wxDC &dc) { dc.GetTextExtent(time, &width, &height); dc.DrawText(time, wxPoint(boardX + square_width * 8 - width, boardY - height - numbers_size.y*2)); - clock = black_side ? black_time : white_time; + clock = black_side ? gs.black_time : gs.white_time; time = wxString::Format("%ds", std::get<1>(clock), std::get<2>(clock)); if (std::get<0>(clock) > 0) { time = wxString::Format("%d:%d", std::get<0>(clock), std::get<1>(clock)); @@ -359,6 +383,9 @@ void BoardCanvas::MouseEvent(wxMouseEvent &event) { ((char)('a' + file)) + std::to_string(rank + 1); event.SetString(move); ProcessEvent(event); + } else { + // If square not valid just redraw (place piece back to its square) + Refresh(); } } if (event.LeftDown()) { @@ -370,7 +397,7 @@ void BoardCanvas::MouseEvent(wxMouseEvent &event) { if (IsCurrentSquareValid) { active_square.x = file; active_square.y = rank; - if (board[(7 - rank) * 8 + file] != ' ') { + if (gs.board[(7 - rank) * 8 + file] != ' ') { wxLogDebug("Drag start on square (%d,%d)", file, rank); valid_drag = true; } @@ -385,7 +412,8 @@ void BoardCanvas::MouseEvent(wxMouseEvent &event) { } void BoardCanvas::Zoom(std::int32_t zoom) { - t->Zoom(zoom); + if(!t->Zoom(zoom)) + return; t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); Refresh(); } @@ -398,12 +426,8 @@ void BoardCanvas::Swap() { void BoardCanvas::SetClockTime(short hours, short min, short sec, bool IsBlack) { if (IsBlack) { - black_time = std::make_tuple(hours, min, sec); + gs.black_time = std::make_tuple(hours, min, sec); } else { - white_time = std::make_tuple(hours, min, sec); + gs.white_time = std::make_tuple(hours, min, sec); } } - -wxBEGIN_EVENT_TABLE(BoardCanvas, wxPanel) EVT_PAINT(BoardCanvas::OnPaint) - EVT_MOUSE_EVENTS(BoardCanvas::MouseEvent) - wxEND_EVENT_TABLE() diff --git a/src/game_tab/left_panel/board/BoardCanvas.hpp b/src/game_tab/left_panel/board/BoardCanvas.hpp index b26526f..7b6ccf7 100644 --- a/src/game_tab/left_panel/board/BoardCanvas.hpp +++ b/src/game_tab/left_panel/board/BoardCanvas.hpp @@ -58,6 +58,16 @@ typedef struct AnimState { wxPoint transVect; } AnimState; +typedef struct GameState { + std::string white, black; + std::string board; + std::map<char, std::uint8_t> captures; + bool is_black_turn; + bool mat_black; + bool mat_white; + ClockTime black_time, white_time; +} GameState; + class BoardCanvas : public wxPanel { // *t is theme for board+pieces and // *t_captures is theme for captured pieces (scale down version of t) @@ -73,11 +83,11 @@ class BoardCanvas : public wxPanel { wxSize canvas_size; wxPoint active_square; std::map<char, std::uint8_t> captures; - ClockTime black_time, white_time; bool frozen,lock_square_size; // Current animation state AnimState adata; + GameState gs; public: BoardCanvas(wxFrame *parent); @@ -89,10 +99,8 @@ public: void MouseEvent(wxMouseEvent &event); void Zoom(std::int32_t zoom); void Swap(); - void SetupBoard(std::string board, bool is_black_turn, - std::map<char, std::uint8_t> captures, - std::string white_player, std::string black_player); - void Animate(const std::string &board, bool is_black_turn, std::map<char, std::uint8_t> captures, std::string src, std::string dst,bool faster); + void OnResize(wxSizeEvent &e); + void SetupBoard(const GameState &new_gs); + void Animate(const GameState &new_gs, std::string src, std::string dst,bool faster); void SetClockTime(short hours, short min, short sec, bool IsBlack); - DECLARE_EVENT_TABLE() }; diff --git a/src/game_tab/left_panel/board/Theme.cpp b/src/game_tab/left_panel/board/Theme.cpp index 6ecbafc..f72dfab 100644 --- a/src/game_tab/left_panel/board/Theme.cpp +++ b/src/game_tab/left_panel/board/Theme.cpp @@ -11,6 +11,8 @@ Theme::Theme() : square_radius(10) { config->Read("board/theme/squares/path", "default").ToStdString(); wxFileName square_file(square); CONFIG_CLOSE(config); + // Mat + skin['#']=LoadPNG("mat").ConvertToImage(); // Piece if (piece == "default" || !piece_file.FileExists()) { wxLogDebug("Loading piece skin from binres"); @@ -95,12 +97,18 @@ wxBitmap *Theme::Get(char c) { return (skin_scaled[c]); } void Theme::ResizePieces(std::uint32_t width) { for (std::pair<char, wxImage> c : skin) { - if (c.first != 's' && c.first != 'S') { + if (c.first != 's' && c.first != 'S' && c.first != '#') { if (skin_scaled.count(c.first)) delete skin_scaled[c.first]; skin_scaled[c.first] = new wxBitmap(c.second.Scale(width, width, wxIMAGE_QUALITY_HIGH)); } + else if(c.first == '#'){ + if (skin_scaled.count(c.first)) + delete skin_scaled[c.first]; + skin_scaled[c.first] = + new wxBitmap(c.second.Scale(width*MAT_SIZE_FACTOR, width*MAT_SIZE_FACTOR, wxIMAGE_QUALITY_HIGH)); + } } } @@ -130,10 +138,15 @@ void Theme::ResizeSquares(std::uint32_t width) { skin_scaled['3']->SetMask(RoundedMask(width, 3)); } -void Theme::Zoom(int amount) { +bool Theme::Zoom(int amount) { double width = skin_scaled['s']->GetWidth() + amount; + if(width<=20) + return false; + if(width>=180) + return false; ResizeSquares(std::max(width, 1.0)); ResizePieces(std::max(width * PIECE_SIZE_FACTOR, 1.0)); + return true; } void Theme::SetSquareRadius(std::uint8_t radius) { diff --git a/src/game_tab/left_panel/board/Theme.hpp b/src/game_tab/left_panel/board/Theme.hpp index 88036d8..c3acf10 100644 --- a/src/game_tab/left_panel/board/Theme.hpp +++ b/src/game_tab/left_panel/board/Theme.hpp @@ -8,6 +8,7 @@ #define ELT_DIM 200 #define DEFAULT_SIZE 80 #define PIECE_SIZE_FACTOR 0.8 // Should be between 0 and 1 +#define MAT_SIZE_FACTOR 0.4 #define DEFAULT_PIECE_THEME "assets/pieces/cburnett.png" #define DEFAULT_SQUARE_THEME "assets/boards/chesscom_8bits.png" @@ -29,7 +30,7 @@ public: void ResizeSquaresAndPieces(std::uint32_t width); void SetSquareRadius(std::uint8_t radius); std::uint8_t GetSquareRadius(); - void Zoom(int amount); + bool Zoom(int amount); double GetPiecesSizes(); double GetSquaresSizes(); |
