From bf485fa577a76731f9eac97de3b0a647cd492e49 Mon Sep 17 00:00:00 2001 From: Loic Guegan Date: Mon, 28 Feb 2022 13:44:27 +0100 Subject: Refactoring game tab --- src/game_tab/GameTab.cpp | 4 +- src/game_tab/GameTab.hpp | 8 +- src/game_tab/board/BoardCanvas.cpp | 294 ----------------------- src/game_tab/board/BoardCanvas.hpp | 68 ------ src/game_tab/board/BoardPanel.cpp | 96 -------- src/game_tab/board/BoardPanel.hpp | 30 --- src/game_tab/board/Theme.cpp | 184 -------------- src/game_tab/board/Theme.hpp | 37 --- src/game_tab/editor/EditorCanvas.cpp | 188 --------------- src/game_tab/editor/EditorCanvas.hpp | 33 --- src/game_tab/editor/EditorPanel.cpp | 193 --------------- src/game_tab/editor/EditorPanel.hpp | 40 --- src/game_tab/editor/LiveEngineDialog.cpp | 111 --------- src/game_tab/editor/LiveEngineDialog.hpp | 20 -- src/game_tab/left_panel/GameTabLeftPanel.cpp | 96 ++++++++ src/game_tab/left_panel/GameTabLeftPanel.hpp | 30 +++ src/game_tab/left_panel/board/BoardCanvas.cpp | 294 +++++++++++++++++++++++ src/game_tab/left_panel/board/BoardCanvas.hpp | 68 ++++++ src/game_tab/left_panel/board/Theme.cpp | 184 ++++++++++++++ src/game_tab/left_panel/board/Theme.hpp | 37 +++ src/game_tab/right_panel/GameTabRightPanel.cpp | 193 +++++++++++++++ src/game_tab/right_panel/GameTabRightPanel.hpp | 40 +++ src/game_tab/right_panel/LiveEngineDialog.cpp | 111 +++++++++ src/game_tab/right_panel/LiveEngineDialog.hpp | 20 ++ src/game_tab/right_panel/editor/EditorCanvas.cpp | 188 +++++++++++++++ src/game_tab/right_panel/editor/EditorCanvas.hpp | 33 +++ src/preferences/BoardPrefs.hpp | 2 +- src/preferences/EditorPrefs.hpp | 1 - 28 files changed, 1301 insertions(+), 1302 deletions(-) delete mode 100644 src/game_tab/board/BoardCanvas.cpp delete mode 100644 src/game_tab/board/BoardCanvas.hpp delete mode 100644 src/game_tab/board/BoardPanel.cpp delete mode 100644 src/game_tab/board/BoardPanel.hpp delete mode 100644 src/game_tab/board/Theme.cpp delete mode 100644 src/game_tab/board/Theme.hpp delete mode 100644 src/game_tab/editor/EditorCanvas.cpp delete mode 100644 src/game_tab/editor/EditorCanvas.hpp delete mode 100644 src/game_tab/editor/EditorPanel.cpp delete mode 100644 src/game_tab/editor/EditorPanel.hpp delete mode 100644 src/game_tab/editor/LiveEngineDialog.cpp delete mode 100644 src/game_tab/editor/LiveEngineDialog.hpp create mode 100644 src/game_tab/left_panel/GameTabLeftPanel.cpp create mode 100644 src/game_tab/left_panel/GameTabLeftPanel.hpp create mode 100644 src/game_tab/left_panel/board/BoardCanvas.cpp create mode 100644 src/game_tab/left_panel/board/BoardCanvas.hpp create mode 100644 src/game_tab/left_panel/board/Theme.cpp create mode 100644 src/game_tab/left_panel/board/Theme.hpp create mode 100644 src/game_tab/right_panel/GameTabRightPanel.cpp create mode 100644 src/game_tab/right_panel/GameTabRightPanel.hpp create mode 100644 src/game_tab/right_panel/LiveEngineDialog.cpp create mode 100644 src/game_tab/right_panel/LiveEngineDialog.hpp create mode 100644 src/game_tab/right_panel/editor/EditorCanvas.cpp create mode 100644 src/game_tab/right_panel/editor/EditorCanvas.hpp (limited to 'src') diff --git a/src/game_tab/GameTab.cpp b/src/game_tab/GameTab.cpp index 48c69d7..cf49991 100644 --- a/src/game_tab/GameTab.cpp +++ b/src/game_tab/GameTab.cpp @@ -11,8 +11,8 @@ GameTab::GameTab(wxFrame *parent, Game *game) // Panels game->BuildAndVerify(); - board_panel = new BoardPanel((wxFrame *)splitter, game); - editor_panel = new EditorPanel((wxFrame *)splitter, game); + board_panel = new GameTabLeftPanel((wxFrame *)splitter, game); + editor_panel = new GameTabRightPanel((wxFrame *)splitter, game); splitter->SplitVertically(board_panel, editor_panel); // Setup splitter diff --git a/src/game_tab/GameTab.hpp b/src/game_tab/GameTab.hpp index d013266..c9dcd5a 100644 --- a/src/game_tab/GameTab.hpp +++ b/src/game_tab/GameTab.hpp @@ -2,8 +2,8 @@ #include "ChessArbiter.hpp" #include "Game.hpp" #include "HalfMove.hpp" -#include "board/BoardPanel.hpp" -#include "editor/EditorPanel.hpp" +#include "left_panel/GameTabLeftPanel.hpp" +#include "right_panel/GameTabRightPanel.hpp" #include "ochess.hpp" #include #include @@ -14,8 +14,8 @@ wxDECLARE_EVENT(REFRESH_TAB_TITLE, wxCommandEvent); wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); class GameTab : public wxPanel, public TabInfos { - EditorPanel *editor_panel; - BoardPanel *board_panel; + GameTabRightPanel *editor_panel; + GameTabLeftPanel *board_panel; Game *game; void RefreshLabel(); void OnRefreshTabTitle(wxCommandEvent &event); diff --git a/src/game_tab/board/BoardCanvas.cpp b/src/game_tab/board/BoardCanvas.cpp deleted file mode 100644 index 237a68a..0000000 --- a/src/game_tab/board/BoardCanvas.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include "BoardCanvas.hpp" - -wxDEFINE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); - -BoardCanvas::BoardCanvas(wxFrame *parent) - : wxPanel(parent), black_side(false), is_black_turn(true), frozen(false), - lock_square_size(false), t(new Theme()), t_captures(new Theme()) { - board = "rnbqkbnrpppppppp PPPPPPPPRNBQKBNR"; - is_dragging = false; - valid_drag = false; - t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); - SetClockTime(-1, -1, -1, false); - SetClockTime(-1, -1, -1, true); - ApplyPreferences(); -} - -BoardCanvas::BoardCanvas(wxFrame *parent, std::uint32_t square_width, - bool frozen) - : BoardCanvas(parent) { - t->ResizeSquaresAndPieces(square_width); - t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); - this->frozen = true; - lock_square_size = true; -} - -void BoardCanvas::OnPaint(wxPaintEvent &event) { - wxPaintDC dc(this); - REFRESH_MOUSE_LOCATION(); - square_width = t->GetSquaresSizes(); - canvas_size = dc.GetSize(); - boardX = (canvas_size.x - (8 * square_width)) / 2; - boardY = (canvas_size.y - (8 * square_width)) / 2; - if (boardX > canvas_size.x) - boardX = 0; - if (boardY > canvas_size.y) - boardY = 0; - DrawBoard(dc); -} - -void BoardCanvas::ApplyPreferences() { - if (t != NULL) - delete t; - if (t_captures != NULL) - delete t_captures; - t = new Theme(); - t_captures = new Theme(); - - CONFIG_OPEN(config); - black_side = config->Read("board/black_by_default", false); - if (lock_square_size) { - t->ResizeSquaresAndPieces(square_width); - } else { - t->ResizeSquaresAndPieces(config->Read("board/square_size", 80)); - } - t->SetSquareRadius(config->Read("board/corner_radius", 10)); - t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); - CONFIG_CLOSE(config); - - Refresh(); -} - -void BoardCanvas::SetupBoard(std::string board, bool is_black_turn, - std::map captures) { - this->board = board; - this->is_black_turn = is_black_turn; - this->captures = captures; - Refresh(); -} - -void BoardCanvas::DrawBoard(wxPaintDC &dc) { - std::uint32_t piece_width = t->GetPiecesSizes(); - std::uint32_t centrer_offset = (square_width - piece_width) / 2; - - bool DrawDraggingPiece = false; - char dp = 'p'; - std::uint32_t dpx = 0, dpy = 0; - for (std::int8_t file = 7; file >= 0; file--) { - for (std::uint8_t rank = 0; rank <= 7; rank++) { - std::uint32_t x = boardX + (7 - file) * square_width; - std::uint32_t y = boardY + rank * square_width; - if ((file + rank) % 2 == 0) { - if (file == 0 && rank == 0) { - dc.DrawBitmap(*t->Get('1'), x, y, true); - } else if (file == 7 && rank == 7) { - dc.DrawBitmap(*t->Get('2'), x, y, true); - } else { - dc.DrawBitmap(*t->Get('s'), x, y, true); - } - } else { - if (file == 7 && rank == 0) { - dc.DrawBitmap(*t->Get('0'), x, y, true); - } else if (file == 0 && rank == 7) { - dc.DrawBitmap(*t->Get('3'), x, y, true); - } else { - dc.DrawBitmap(*t->Get('S'), x, y, true); - } - } - - std::uint8_t prank = rank; - std::uint8_t pfile = file; - if (black_side) { - prank = 7 - rank; - pfile = 7 - file; - } - std::uint32_t px = x + centrer_offset; - std::uint32_t py = y + centrer_offset; - char piece = board[(7 - pfile) + 8 * prank]; - if (is_dragging && (7 - pfile) == active_square.x && - (7 - prank) == active_square.y) { - dp = piece; - dpx = px - (lastClickX - mouseX); - dpy = py - (lastClickY - mouseY); - DrawDraggingPiece = true; - continue; - } - if (piece != ' ') { - dc.DrawBitmap(*t->Get(piece), px, py, false); - } - } - } - - // Draw badge - dc.SetPen(wxPen(*wxBLACK, 3)); - std::uint32_t badgeY = boardY; - std::uint32_t badgeWidth = square_width / 2; - if (is_black_turn) { - dc.SetBrush(*wxBLACK_BRUSH); - if (black_side) { - badgeY = boardY + (8 * square_width) - badgeWidth; - } - } else { - dc.SetBrush(*wxWHITE_BRUSH); - if (!black_side) { - badgeY = boardY + (8 * square_width) - badgeWidth; - } - } - wxRect badge(boardX + (8 * square_width) + badgeWidth / 2, badgeY, badgeWidth, - badgeWidth); - dc.DrawRectangle(badge); - - // Draw captures first for white then for black - std::uint32_t captures_size = t_captures->GetPiecesSizes(); - std::uint8_t padding = 10; - std::uint32_t offsetX = 0; - std::uint32_t offsetY = -(captures_size + padding); - if (black_side) { - offsetY = 8 * square_width + padding; - } - for (char p : {'P', 'N', 'B', 'R', 'Q'}) { - if (captures.find(p) != captures.end()) { - for (std::uint8_t i = 0; i < captures[p]; i++) { - dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); - offsetX += captures_size / 2; - } - offsetX += captures_size / 2; - } - } - offsetX = 0; - if (black_side) { - offsetY = -(captures_size + padding); - } else { - offsetY = 8 * square_width + padding; - } - for (char p : {'p', 'n', 'b', 'r', 'q'}) { - if (captures.find(p) != captures.end()) { - for (std::uint8_t i = 0; i < captures[p]; i++) { - dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); - offsetX += captures_size / 2; - } - offsetX += captures_size / 2; - } - } - - // Draw dragging piece - if (DrawDraggingPiece) { - dc.DrawBitmap(*t->Get(dp), dpx, dpy, false); - } - - // Draw numbers - for (char l = 'a'; l < 'a' + 8; l++) { - dc.DrawText(wxString(l), wxPoint(boardX + l - 'a' * square_width, - boardY + 8 * square_width + 10)); - } - - // Draw Clocks - if (std::get<0>(black_time) >= 0) { - wxFont font = dc.GetFont(); - ClockTime clock = black_side ? white_time : black_time; - wxString 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)); - } else if (std::get<1>(clock) > 0) { - time = wxString::Format("%d:%ds", std::get<1>(clock), std::get<2>(clock)); - } - dc.SetFont(font.Scale(1.5).MakeBold()); - wxCoord width, height; - dc.GetTextExtent(time, &width, &height); - dc.DrawText(time, - wxPoint(boardX + square_width * 8 - width, boardY - height)); - clock = black_side ? black_time : 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)); - } else if (std::get<1>(clock) > 0) { - time = wxString::Format("%d:%ds", std::get<1>(clock), std::get<2>(clock)); - } - dc.GetTextExtent(time, &width, &height); - dc.DrawText(time, wxPoint(boardX + square_width * 8 - width, - boardY + square_width * 8)); - } -} - -void BoardCanvas::MouseEvent(wxMouseEvent &event) { - if (!frozen) { - if (event.Dragging()) { - if (valid_drag) { - is_dragging = true; - Refresh(); - } - } else { - if (is_dragging) { - is_dragging = false; - valid_drag = false; - // Handle drop - REFRESH_MOUSE_LOCATION(); - INIT_CURRENT_SQUARE(); - - if (IsCurrentSquareValid) { - wxLogDebug("Drag end on square (%d,%d)", file, rank); - /// Play the move - wxCommandEvent event(PLAY_MOVE_EVENT, GetId()); - event.SetEventObject(this); - std::string move = ((char)('a' + active_square.x)) + - std::to_string(+active_square.y + 1) + - ((char)('a' + file)) + std::to_string(rank + 1); - event.SetString(move); - ProcessEvent(event); - } - } - if (event.LeftDown()) { - SetFocus(); - REFRESH_MOUSE_LOCATION(); - lastClickX = mouseX; - lastClickY = mouseY; - INIT_CURRENT_SQUARE(); - if (IsCurrentSquareValid) { - active_square.x = file; - active_square.y = rank; - if (board[(7 - rank) * 8 + file] != ' ') { - wxLogDebug("Drag start on square (%d,%d)", file, rank); - valid_drag = true; - } - } - } - } - } -} - -void BoardCanvas::Zoom(std::int32_t zoom) { - t->Zoom(zoom); - t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); - Refresh(); -} - -void BoardCanvas::Swap() { - black_side = !black_side; - Refresh(); -} - -void BoardCanvas::OnKeyEvent(wxKeyEvent &event) { - if (event.GetKeyCode() == WXK_LEFT) { - wxCommandEvent previousEvent(PREVIOUS_MOVE_EVENT, GetId()); - previousEvent.SetEventObject(this); - ProcessEvent(previousEvent); - } else if (event.GetKeyCode() == WXK_RIGHT) { - wxCommandEvent nextEvent(NEXT_MOVE_EVENT, GetId()); - nextEvent.SetEventObject(this); - ProcessEvent(nextEvent); - } -} - -void BoardCanvas::SetClockTime(short hours, short min, short sec, - bool IsBlack) { - if (IsBlack) { - black_time = std::make_tuple(hours, min, sec); - } else { - white_time = std::make_tuple(hours, min, sec); - } -} - -wxBEGIN_EVENT_TABLE(BoardCanvas, wxPanel) EVT_PAINT(BoardCanvas::OnPaint) - EVT_MOUSE_EVENTS(BoardCanvas::MouseEvent) - EVT_CHAR_HOOK(BoardCanvas::OnKeyEvent) wxEND_EVENT_TABLE() diff --git a/src/game_tab/board/BoardCanvas.hpp b/src/game_tab/board/BoardCanvas.hpp deleted file mode 100644 index 34c4911..0000000 --- a/src/game_tab/board/BoardCanvas.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "Theme.hpp" -#include "ochess.hpp" -#include -#include -#include -#include -#include - -// Local events -wxDECLARE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); - -// Foreign events -wxDECLARE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); - -#define REFRESH_MOUSE_LOCATION() \ - { \ - const wxPoint pt = wxGetMousePosition(); \ - mouseX = pt.x - this->GetScreenPosition().x; \ - mouseY = pt.y - this->GetScreenPosition().y; \ - } - -#define INIT_CURRENT_SQUARE() \ - std::uint32_t file = 7 - (mouseX - boardX) / square_width; \ - std::uint32_t rank = (mouseY - boardY) / square_width; \ - if (!black_side) { \ - file = 7 - file; \ - rank = 7 - rank; \ - } \ - bool IsCurrentSquareValid = file >= 0 && file <= 7 && rank >= 0 && rank <= 7; - -#define MOUSE_ON(x, y, width, height) \ - (mouseX >= (x) && mouseX <= ((x) + (width)) && mouseY >= (y) && \ - mouseY <= ((y) + (height))) - -#define CAPTURE_FACTOR 0.5 - -typedef std::tuple ClockTime; - -class BoardCanvas : public wxPanel { - Theme *t, *t_captures; - std::string board; - bool black_side, is_dragging, valid_drag, is_black_turn; - std::uint32_t boardX, boardY, square_width, mouseX, mouseY, lastClickX, - lastClickY; - wxSize canvas_size; - wxPoint active_square; - std::map captures; - ClockTime black_time, white_time; - bool frozen,lock_square_size; - -public: - BoardCanvas(wxFrame *parent); - BoardCanvas(wxFrame *parent,std::uint32_t square_width, bool frozen); - void ApplyPreferences(); - void DrawBoard(wxPaintDC &dc); - void OnPaint(wxPaintEvent &event); - void OnKeyEvent(wxKeyEvent &event); - void MouseEvent(wxMouseEvent &event); - void Zoom(std::int32_t zoom); - void Swap(); - void SetupBoard(std::string board, bool is_black_turn, - std::map captures); - void SetClockTime(short hours, short min, short sec, bool IsBlack); - DECLARE_EVENT_TABLE() -}; diff --git a/src/game_tab/board/BoardPanel.cpp b/src/game_tab/board/BoardPanel.cpp deleted file mode 100644 index ff4fb62..0000000 --- a/src/game_tab/board/BoardPanel.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "BoardPanel.hpp" -#include - -BoardPanel::BoardPanel(wxFrame *parent, Game *game) - : wxPanel(parent), game(game) { - - wxBoxSizer *board_panel_sizer = new wxBoxSizer(wxVERTICAL); - board_canvas = new BoardCanvas((wxFrame *)this); - board_panel_sizer->Add(board_canvas, 1, wxEXPAND); - - // Left Panel buttons - wxBoxSizer *board_panel_button_sizer = new wxBoxSizer(wxHORIZONTAL); - board_panel_button_sizer->Add( - new wxBitmapButton(this, SWAP_BTN, LoadPNG("swap")), 0); - board_panel_button_sizer->Add( - new wxBitmapButton(this, ZOOM_IN_BTN, LoadPNG("zoomin")), 0); - board_panel_button_sizer->Add( - new wxBitmapButton(this, ZOOM_OUT_BTN, LoadPNG("zoomout")), 0); - board_panel_button_sizer->Add(new wxButton(this, COPY_FEN_BTN, L"Copy FEN"), - 0, wxEXPAND); - board_panel_sizer->Add(board_panel_button_sizer, 0); - this->SetSizer(board_panel_sizer); - - Bind(PLAY_MOVE_EVENT, &BoardPanel::OnPlay, this, wxID_ANY); - Bind(PREVIOUS_MOVE_EVENT, &BoardPanel::OnPreviousMove, this, wxID_ANY); - Bind(NEXT_MOVE_EVENT, &BoardPanel::OnNextMove, this, wxID_ANY); - Bind(wxEVT_BUTTON, &BoardPanel::OnSwap, this, SWAP_BTN); - Bind(wxEVT_BUTTON, &BoardPanel::OnZoomIn, this, ZOOM_IN_BTN); - Bind(wxEVT_BUTTON, &BoardPanel::OnZoomOut, this, ZOOM_OUT_BTN); - Bind(wxEVT_BUTTON, &BoardPanel::OnCopyFEN, this, COPY_FEN_BTN); -} - -void BoardPanel::OnPreviousMove(wxCommandEvent &event) { - game->Previous(); - Notify(); - NotifyEditor(); -} - -void BoardPanel::OnZoomIn(wxCommandEvent &event) { - wxLogDebug("Clicked on zoom in"); - board_canvas->Zoom(10); -} - -void BoardPanel::OnZoomOut(wxCommandEvent &event) { - wxLogDebug("Clicked on zoom out"); - board_canvas->Zoom(-10); -} - -void BoardPanel::OnSwap(wxCommandEvent &event) { - wxLogDebug("Clicked on swap"); - board_canvas->Swap(); -} - -void BoardPanel::OnNextMove(wxCommandEvent &event) { - wxLogDebug("Game tab received NEXT_MOVE_EVENT"); - game->Next(); - Notify(); - NotifyEditor(); -} - -void BoardPanel::OnPlay(wxCommandEvent &event) { - wxLogDebug("Game tab received PLAY_MOVE_EVENT"); - if (game->Play(event.GetString().ToStdString())) { - NotifyEditor(); - } - Notify(); -} - -void BoardPanel::OnCopyFEN(wxCommandEvent &event) { - wxLogDebug("Clicked on copy fen"); - if (wxTheClipboard->Open()) { - wxTheClipboard->SetData(new wxTextDataObject(game->GetFen())); - wxTheClipboard->Close(); - } -} - -void BoardPanel::Notify() { - std::string fen = game->GetFen(); - std::map captures; - HalfMove *m = game->GetCurrentMove(); - if (m != NULL) { - captures = m->GetLineCaptures(); - } - board_canvas->SetupBoard(chessarbiter::FENParser::Parse(fen).board, - game->IsBlackToPlay(), captures); -} - -void BoardPanel::NotifyEditor() { - wxCommandEvent previousEvent(GAME_CHANGE, GetId()); - previousEvent.SetEventObject(this); - ProcessEvent(previousEvent); -} - -void BoardPanel::ApplyPreferences() { - board_canvas->ApplyPreferences(); -} diff --git a/src/game_tab/board/BoardPanel.hpp b/src/game_tab/board/BoardPanel.hpp deleted file mode 100644 index 3c4bf77..0000000 --- a/src/game_tab/board/BoardPanel.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "../Game.hpp" -#include "BoardCanvas.hpp" -#include "ochess.hpp" - -// Foreign events -wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); - -enum { COPY_FEN_BTN = wxID_HIGHEST + 1, ZOOM_IN_BTN, ZOOM_OUT_BTN, SWAP_BTN }; - -class BoardPanel : public wxPanel { - Game *game; - BoardCanvas *board_canvas; - void NotifyEditor(); - -public: - BoardPanel(wxFrame *parent, Game *game); - void Notify(); - void OnPlay(wxCommandEvent &event); - void OnGotoMove(wxCommandEvent &event); - void OnPreviousMove(wxCommandEvent &event); - void OnNextMove(wxCommandEvent &event); - void OnCopyFEN(wxCommandEvent &event); - void OnZoomIn(wxCommandEvent &event); - void OnZoomOut(wxCommandEvent &event); - void OnSwap(wxCommandEvent &event); - void OnRefreshBoard(wxCommandEvent &event); - void ApplyPreferences(); -}; \ No newline at end of file diff --git a/src/game_tab/board/Theme.cpp b/src/game_tab/board/Theme.cpp deleted file mode 100644 index 6ecbafc..0000000 --- a/src/game_tab/board/Theme.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "Theme.hpp" -#include - -Theme::Theme() : square_radius(10) { - // Load config - CONFIG_OPEN(config); - std::string piece = - config->Read("board/theme/pieces/path", "default").ToStdString(); - wxFileName piece_file(piece); - std::string square = - config->Read("board/theme/squares/path", "default").ToStdString(); - wxFileName square_file(square); - CONFIG_CLOSE(config); - // Piece - if (piece == "default" || !piece_file.FileExists()) { - wxLogDebug("Loading piece skin from binres"); - LoadPiecesSkin(LoadPNG("cburnett").ConvertToImage()); - } else { - wxLogDebug("Loading piece skin: %s", piece); - LoadPiecesSkin(wxImage(piece, wxBITMAP_TYPE_PNG)); - } - // Square - if (square == "default" || !square_file.FileExists()) { - wxLogDebug("Loading square skin from binres"); - LoadSquaresSkin(LoadPNG("chesscom_8bits").ConvertToImage()); - } else { - wxLogDebug("Loading square skin: %s", square); - LoadSquaresSkin(wxImage(square, wxBITMAP_TYPE_PNG)); - } -} - -Theme::Theme(std::string piece, std::string square) : square_radius(10) { - wxLogDebug("Loading piece skin: %s", piece); - LoadPiecesSkin(wxImage(piece, wxBITMAP_TYPE_PNG)); - wxLogDebug("Loading square skin: %s", square); - LoadSquaresSkin(wxImage(square, wxBITMAP_TYPE_PNG)); -} - -Theme::~Theme() { - for (std::pair c : skin_scaled) { - delete c.second; - } -} - -std::uint8_t Theme::GetSquareRadius() { return (square_radius); } - -void Theme::LoadPiecesSkin(wxImage iskin) { - if (iskin.GetWidth() != 2 * ELT_DIM || iskin.GetHeight() != 6 * ELT_DIM) { - throw "Invalid piece theme"; - } - - int offset = 0; - // Kings - skin['k'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['K'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - // Queen - offset = ELT_DIM; - skin['q'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['Q'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - // Rook - offset = ELT_DIM * 2; - skin['r'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['R'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - // Bishop - offset = ELT_DIM * 3; - skin['b'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['B'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - // Knight - offset = ELT_DIM * 4; - skin['n'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['N'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - // Pawn - offset = ELT_DIM * 5; - skin['p'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); - skin['P'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); - - // Update scaled version - ResizePieces(DEFAULT_SIZE * PIECE_SIZE_FACTOR); -} - -void Theme::LoadSquaresSkin(wxImage iskin) { - if (iskin.GetWidth() != 2 * ELT_DIM || iskin.GetHeight() != ELT_DIM) { - throw "Invalid piece theme"; - } - - // Square - skin['s'] = iskin.GetSubImage(wxRect(0, 0, ELT_DIM, ELT_DIM)); - skin['S'] = iskin.GetSubImage(wxRect(ELT_DIM, 0, ELT_DIM, ELT_DIM)); - - // Update scaled version - ResizeSquares(DEFAULT_SIZE); -} - -wxBitmap *Theme::Get(char c) { return (skin_scaled[c]); } - -void Theme::ResizePieces(std::uint32_t width) { - for (std::pair c : skin) { - if (c.first != 's' && c.first != 'S') { - 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)); - } - } -} - -void Theme::ResizeSquaresAndPieces(std::uint32_t width) { - ResizeSquares(width); - ResizePieces(width * PIECE_SIZE_FACTOR); -} - -void Theme::ResizeSquares(std::uint32_t width) { - if (skin_scaled.count('s')) - delete skin_scaled['s']; - skin_scaled['s'] = - new wxBitmap(skin['s'].Scale(width, width, wxIMAGE_QUALITY_HIGH)); - if (skin_scaled.count('S')) - delete skin_scaled['S']; - skin_scaled['S'] = - new wxBitmap(skin['S'].Scale(width, width, wxIMAGE_QUALITY_HIGH)); - - skin_scaled['0'] = new wxBitmap(*skin_scaled['S']); - skin_scaled['1'] = new wxBitmap(*skin_scaled['s']); - skin_scaled['2'] = new wxBitmap(*skin_scaled['s']); - skin_scaled['3'] = new wxBitmap(*skin_scaled['S']); - - skin_scaled['0']->SetMask(RoundedMask(width, 0)); - skin_scaled['1']->SetMask(RoundedMask(width, 1)); - skin_scaled['2']->SetMask(RoundedMask(width, 2)); - skin_scaled['3']->SetMask(RoundedMask(width, 3)); -} - -void Theme::Zoom(int amount) { - double width = skin_scaled['s']->GetWidth() + amount; - ResizeSquares(std::max(width, 1.0)); - ResizePieces(std::max(width * PIECE_SIZE_FACTOR, 1.0)); -} - -void Theme::SetSquareRadius(std::uint8_t radius) { - square_radius = radius; - Zoom(0); // Refresh scale -} - -/** - * This will never fail since k entry always exists (cf constructor and - * ResizePieces) - */ -double Theme::GetPiecesSizes() { return (skin_scaled['k']->GetWidth()); } - -/** - * This will never fail since s entry always exists (cf constructor and - * ResizeSquares) - */ -double Theme::GetSquaresSizes() { return (skin_scaled['s']->GetWidth()); } - -wxMask *Theme::RoundedMask(std::uint32_t width, std::uint8_t corner) { - - wxBitmap b(width, width, 1); - wxMemoryDC dc; - dc.SelectObject(b); - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxBLACK_BRUSH); - dc.DrawRectangle(0, 0, width, width); - dc.SetBrush(*wxWHITE_BRUSH); - dc.SetPen(*wxWHITE_PEN); - dc.DrawRoundedRectangle(0, 0, width, width, square_radius); - - dc.SetBrush(*wxWHITE_BRUSH); - dc.SetPen(*wxWHITE_PEN); - if (corner == 0) { - dc.DrawRectangle(0, width / 2, width, width); - dc.DrawRectangle(width / 2, 0, width, width); - } else if (corner == 1) { - dc.DrawRectangle(0, 0, width / 2, width); - dc.DrawRectangle(0, width / 2, width, width); - } else if (corner == 2) { - dc.DrawRectangle(0, 0, width, width / 2); - dc.DrawRectangle(width / 2, 0, width, width); - } else if (corner == 3) { - dc.DrawRectangle(0, 0, width / 2, width); - dc.DrawRectangle(0, 0, width, width / 2); - } - return (new wxMask(b)); -} diff --git a/src/game_tab/board/Theme.hpp b/src/game_tab/board/Theme.hpp deleted file mode 100644 index 88036d8..0000000 --- a/src/game_tab/board/Theme.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "ochess.hpp" - -#include -#include - -#define ELT_DIM 200 -#define DEFAULT_SIZE 80 -#define PIECE_SIZE_FACTOR 0.8 // Should be between 0 and 1 -#define DEFAULT_PIECE_THEME "assets/pieces/cburnett.png" -#define DEFAULT_SQUARE_THEME "assets/boards/chesscom_8bits.png" - -class Theme { -private: - std::unordered_map skin; - std::unordered_map skin_scaled; - std::uint8_t square_radius; - wxMask *RoundedMask(std::uint32_t width, std::uint8_t corner); - -public: - Theme(); - Theme(std::string piece, std::string square); - ~Theme(); - void LoadPiecesSkin(wxImage skin); - void LoadSquaresSkin(wxImage iskin); - void ResizePieces(std::uint32_t width); - void ResizeSquares(std::uint32_t width); - void ResizeSquaresAndPieces(std::uint32_t width); - void SetSquareRadius(std::uint8_t radius); - std::uint8_t GetSquareRadius(); - void Zoom(int amount); - double GetPiecesSizes(); - double GetSquaresSizes(); - - wxBitmap *Get(char c); -}; diff --git a/src/game_tab/editor/EditorCanvas.cpp b/src/game_tab/editor/EditorCanvas.cpp deleted file mode 100644 index 0e2f77a..0000000 --- a/src/game_tab/editor/EditorCanvas.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include "EditorCanvas.hpp" - -EditorCanvas::EditorCanvas(wxFrame *parent) - : wxPanel(parent), NeedRedraw(false) { - hide_icon = LoadPNG("hide", wxSize(CGEditor::status.MoveIconWidth, - CGEditor::status.MoveIconWidth)); - t.ResizePieces(CGEditor::status.MoveIconWidth); -} - -void EditorCanvas::OnPaint(wxPaintEvent &event) { - wxPaintDC current_dc(this); - dc = ¤t_dc; - - // Refresh canvas size - wxSize sz = GetClientSize(); - CGEditor::status.CanvasWidth = sz.GetWidth(); - CGEditor::status.CanvasHeight = sz.GetHeight(); - CGEditor::status.UseMoveIcons = - true; // Piece image should be drawn before the move ? - - const wxPoint pt = wxGetMousePosition(); - CGEditor::status.MouseX = pt.x - this->GetScreenPosition().x; - CGEditor::status.MouseY = pt.y - this->GetScreenPosition().y; - CGEditor::Draw(); -} - -/** - * @brief Convenient fonction to center text - * - * @param e Element to center - * @return wxPoint The centered version of e according to wdWidget API - */ -wxPoint EditorCanvas::Middle(cgeditor::Element e) { - wxSize sz = dc->GetTextExtent(e.text); - return (wxPoint(e.x + (e.width - sz.GetWidth()) / 2, - e.y + (e.height - sz.GetHeight()) / 2)); -} - -void EditorCanvas::DrawElement(const cgeditor::Element &e) { - dc->SetPen(wxNullPen); - dc->SetBrush(*wxRED_BRUSH); - if (e.prop & cgeditor::Property::Rectangle) { - if (e.prop & cgeditor::Property::Scrollbarbg) { - dc->SetBrush(*wxCYAN_BRUSH); - } else if (e.prop & cgeditor::Property::Scrollbar) { - dc->SetBrush(*wxGREY_BRUSH); - } else if (e.prop & cgeditor::Property::Margin) { - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - } else if (e.prop & cgeditor::Property::Button) { - if (e.prop & cgeditor::Property::On) { - dc->DrawBitmap(hide_icon, e.x, e.y); - return; - } - dc->SetBrush(*wxBLACK_BRUSH); - } - wxRect recToDraw(e.x, e.y, e.width, e.height); - dc->DrawRectangle(recToDraw); - } else if (e.prop & cgeditor::Property::Text || - e.prop & cgeditor::Property::Image) { - if (e.prop & cgeditor::Property::Image) { - // Draw your pieces images instead - std::uint32_t y = Middle(e).y - CGEditor::status.MoveIconWidth / 2; - char p = 'P'; - if (e.prop & cgeditor::Property::Knight) { - p = 'N'; - } else if (e.prop & cgeditor::Property::Bishop) { - p = 'B'; - } else if (e.prop & cgeditor::Property::Queen) { - p = 'Q'; - } else if (e.prop & cgeditor::Property::King) { - p = 'K'; - } else if (e.prop & cgeditor::Property::Rook) { - p = 'R'; - } - if (e.prop & cgeditor::Property::Black) { - p = std::tolower(p); - } - if (e.prop & cgeditor::Property::Current) { - wxRect recToDraw(e.x, e.y, e.width, e.height); - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - dc->DrawRectangle(recToDraw); - } - dc->DrawBitmap(*t.Get(p), e.x, y); - } else if (e.prop & cgeditor::Property::Comment) { - wxRect recToDraw(e.x, e.y, e.width, e.height); - dc->SetBrush(*wxYELLOW_BRUSH); - dc->DrawRectangle(recToDraw); - dc->DrawText(wxString(e.text), wxPoint(e.x, e.y)); - } else if (e.prop & cgeditor::Property::Menuitem) { - wxRect recToDraw(e.x, e.y, e.width, e.height); - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - dc->DrawRectangle(recToDraw); - dc->DrawText(wxString(e.text), wxPoint(e.x, Middle(e).y)); - } else { - if (e.prop & cgeditor::Property::Move) { - if (e.prop & cgeditor::Property::Current) { - wxRect recToDraw(e.x, e.y, e.width, e.height); - dc->SetBrush(*wxLIGHT_GREY_BRUSH); - dc->DrawRectangle(recToDraw); - } - if (CGEditor::status.UseMoveIcons) { - dc->DrawText(wxString(e.text), wxPoint(e.x, Middle(e).y)); - } else { - dc->DrawText(wxString(e.text), Middle(e)); - } - } else { - dc->DrawText(wxString(e.text), Middle(e)); - } - } - } -} -void EditorCanvas::HandleEvent(const cgeditor::Event &e) { - wxLogDebug("Editor event!"); - if (e.type == cgeditor::Event::Goto) { - wxCommandEvent event(GOTO_MOVE_EVENT, GetId()); - event.SetEventObject(this); - event.SetClientData(e.move); - ProcessEvent(event); - } else if (e.type == cgeditor::Event::Delete) { - wxCommandEvent event(DELETE_MOVE_EVENT, GetId()); - event.SetEventObject(this); - event.SetClientData(e.move); - ProcessEvent(event); - } else if (e.type == cgeditor::Event::Promote) { - wxCommandEvent event(PROMOTE_MOVE_EVENT, GetId()); - event.SetEventObject(this); - event.SetClientData(e.move); - ProcessEvent(event); - } else if (e.type == cgeditor::Event::SetAsMainline) { - wxCommandEvent event(SET_AS_MAINLINE_EVENT, GetId()); - event.SetEventObject(this); - event.SetClientData(e.move); - ProcessEvent(event); - } -} - -void EditorCanvas::MouseEvent(wxMouseEvent &event) { - if (event.Dragging()) { - CGEditor::status.LeftClick = false; - CGEditor::status.IsDrag = true; - Refresh(); - } else if (event.LeftDown()) { - SetFocus(); - CGEditor::status.LeftClick = true; - Refresh(); - } else if (event.RightDown()) { - SetFocus(); - CGEditor::status.RightClick = true; - Refresh(); - } else if (event.GetWheelRotation() != 0) { - SetFocus(); - if (event.GetWheelRotation() < 0) { - CGEditor::status.EventVScroll = 50; - } else { - CGEditor::status.EventVScroll = -50; - } - Refresh(); - } - - // Should another draw of CGEditor be made? - if (NeedRedraw) { - Refresh(); - NeedRedraw = false; - } -} - -void EditorCanvas::SetMoves(HalfMove *moves, HalfMove *current) { - CGEditor::status.Moves = moves; - CGEditor::status.CurrentMove = current; - - Refresh(); -} - -void EditorCanvas::OnKeyEvent(wxKeyEvent &event) { - if (event.GetKeyCode() == WXK_LEFT) { - wxCommandEvent previousEvent(PREVIOUS_MOVE_EVENT, GetId()); - previousEvent.SetEventObject(this); - ProcessEvent(previousEvent); - } else if (event.GetKeyCode() == WXK_RIGHT) { - wxCommandEvent nextEvent(NEXT_MOVE_EVENT, GetId()); - nextEvent.SetEventObject(this); - ProcessEvent(nextEvent); - } -} - -wxBEGIN_EVENT_TABLE(EditorCanvas, wxPanel) EVT_PAINT(EditorCanvas::OnPaint) - EVT_MOUSE_EVENTS(EditorCanvas::MouseEvent) - EVT_CHAR_HOOK(EditorCanvas::OnKeyEvent) wxEND_EVENT_TABLE() diff --git a/src/game_tab/editor/EditorCanvas.hpp b/src/game_tab/editor/EditorCanvas.hpp deleted file mode 100644 index b3bb29f..0000000 --- a/src/game_tab/editor/EditorCanvas.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "../HalfMove.hpp" -#include "CGEditor.hpp" -#include "ochess.hpp" -#include "../board/Theme.hpp" - -// Foreign events -wxDECLARE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); - -class EditorCanvas : public wxPanel, public cgeditor::CGEditor { - wxPaintDC *dc; - bool NeedRedraw; - wxPoint Middle(cgeditor::Element e); - wxBitmap hide_icon; - Theme t; - -public: - EditorCanvas(wxFrame *parent); - void OnPaint(wxPaintEvent &event); - void MouseEvent(wxMouseEvent &event); - void DrawElement(const cgeditor::Element &e); - void HandleEvent(const cgeditor::Event &e); - void SetMoves(HalfMove *moves, HalfMove *current); - void OnKeyEvent(wxKeyEvent &event); - - DECLARE_EVENT_TABLE() -}; diff --git a/src/game_tab/editor/EditorPanel.cpp b/src/game_tab/editor/EditorPanel.cpp deleted file mode 100644 index 9f14f37..0000000 --- a/src/game_tab/editor/EditorPanel.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "EditorPanel.hpp" -#include "LiveEngineDialog.hpp" - -wxDEFINE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); -wxDEFINE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); -wxDEFINE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); -wxDEFINE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); -wxDEFINE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); -wxDEFINE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); - -EditorPanel::EditorPanel(wxFrame *parent, Game *game) - : TabGameRightPanel(parent), game(game), selected_item(-1) { - editor_canvas = new EditorCanvas((wxFrame *)editor_page); - editor_canvas_sizer->Add(editor_canvas, 1, wxEXPAND); - tags_list->InsertColumn(0, L"Name", wxLIST_FORMAT_LEFT, 200); - tags_list->InsertColumn(1, L"Value", wxLIST_FORMAT_LEFT, 500); - tagTextCtrl->SetHint("Tag"); - valueTextCtrl->SetHint("Value"); - - /*LiveEngineDialog *diag=new LiveEngineDialog(this, "Stockfish"); - diag->SetFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - - diag->Show();*/ - RefreshTagsList(); - - // Bind events - this->Bind(wxEVT_TEXT, &EditorPanel::OnCommentChange, this, - COMMENT_INPUT_BOX); - this->Bind(GOTO_MOVE_EVENT, &EditorPanel::OnGotoMove, this, wxID_ANY); - this->Bind(DELETE_MOVE_EVENT, &EditorPanel::OnMoveDelete, this, wxID_ANY); - this->Bind(PROMOTE_MOVE_EVENT, &EditorPanel::OnMovePromote, this, wxID_ANY); - this->Bind(SET_AS_MAINLINE_EVENT, &EditorPanel::OnMoveSetAsMainline, this, - wxID_ANY); - this->Bind(NEXT_MOVE_EVENT, &EditorPanel::OnNextMove, this, wxID_ANY); - this->Bind(PREVIOUS_MOVE_EVENT, &EditorPanel::OnPreviousMove, this, wxID_ANY); - this->Bind(wxEVT_LIST_ITEM_SELECTED, &EditorPanel::OnTagSelected, this, - wxID_ANY); - this->Bind(wxEVT_LIST_ITEM_DESELECTED, &EditorPanel::OnTagDeselected, this, - wxID_ANY); - this->Bind(wxEVT_BUTTON, &EditorPanel::OnApply, this, UPDATE_BTN); - this->Bind(wxEVT_BUTTON, &EditorPanel::OnDelete, this, DELETE_BTN); - this->Bind(wxEVT_BUTTON, &EditorPanel::OnLiveAnalysis, this, - LIVE_ANALYSIS_GAME_BUTTON); - - ApplyPreferences(); -} - -void EditorPanel::OnLiveAnalysis(wxCommandEvent &event) { - int selection = engine_list->GetSelection(); - if (selection != wxNOT_FOUND) { - LiveEngineDialog *diag = new LiveEngineDialog(this, engine_list->GetString(selection).ToStdString()); - diag->SetFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - diag->Show(); - } -} - -void EditorPanel::OnTagSelected(wxListEvent &event) { - wxListItem item = event.GetItem(); - std::string key = item.GetText().ToStdString(); - tagTextCtrl->ChangeValue(key); - item.SetColumn(1); - tags_list->GetItem(item); - valueTextCtrl->ChangeValue(item.GetText().ToStdString()); - selected_item = item.GetId(); - delete_button->Enable(true); -} - -void EditorPanel::OnTagDeselected(wxListEvent &event) { - selected_item = -1; - delete_button->Enable(false); -} - -void EditorPanel::NotifyBoard() { - wxCommandEvent previousEvent(GAME_CHANGE, GetId()); - previousEvent.SetEventObject(this); - ProcessEvent(previousEvent); -} - -void EditorPanel::OnCommentChange(wxCommandEvent &event) { - wxLogDebug("EditorPanel: comment input change"); - HalfMove *m = game->GetCurrentMove(); - if (m != NULL) { - m->SetComment(event.GetString().ToStdString()); - } - editor_canvas->Refresh(); -} - -void EditorPanel::OnApply(wxCommandEvent &event) { - std::string key = tagTextCtrl->GetValue().ToStdString(); - if (key == "FEN") { - SHOW_DIALOG_ERROR("Editing the FEN tag is forbidden"); - return; - } - if (key.size() > 0) { - std::string value = valueTextCtrl->GetValue().ToStdString(); - game->SetTag(key, value); - RefreshTagsList(); - wxCommandEvent event(REFRESH_TAB_TITLE, GetId()); - event.SetEventObject(this); - ProcessEvent(event); - } -} - -void EditorPanel::OnDelete(wxCommandEvent &event) { - if (selected_item >= 0) { - wxListItem item; - item.SetColumn(0); - item.SetId(selected_item); - tags_list->GetItem(item); - std::string key = item.GetText().ToStdString(); - if (key != "FEN") { - game->DeleteTag(key); - selected_item = -1; - RefreshTagsList(); - } else { - SHOW_DIALOG_ERROR("Deleting the FEN tag is forbidden."); - } - } -} - -void EditorPanel::OnGotoMove(wxCommandEvent &event) { - wxLogDebug("EditorPanel: received GOTO_MOVE_EVENT"); - game->SetCurrent((HalfMove *)event.GetClientData()); - NotifyBoard(); - editor_canvas->Refresh(); -} - -void EditorPanel::OnMoveDelete(wxCommandEvent &event) { - game->DeleteMove((HalfMove *)event.GetClientData()); - NotifyBoard(); - editor_canvas->Refresh(); -} - -void EditorPanel::OnMovePromote(wxCommandEvent &event) { - wxLogDebug("EditorPanel: promote move called"); - game->PromoteMove((HalfMove *)event.GetClientData()); - NotifyBoard(); - editor_canvas->Refresh(); -} - -void EditorPanel::OnMoveSetAsMainline(wxCommandEvent &event) { - wxLogDebug("EditorPanel: set move as mainline called"); - game->SetMoveAsMainline((HalfMove *)event.GetClientData()); - NotifyBoard(); - editor_canvas->Refresh(); -} - -void EditorPanel::Notify() { - HalfMove *m = game->GetCurrentMove(); - if (m != NULL) { - comment_input->ChangeValue( - m->GetComment()); // ChangeValue do not raise events - } - editor_canvas->SetMoves(game->GetMoves(), m); -} - -void EditorPanel::ApplyPreferences() { - engine_list->Clear(); - CONFIG_OPEN(conf); - conf->SetPath("engines/"); - wxString engine_name; - long index; - if (conf->GetFirstGroup(engine_name, index)) { - do { - engine_list->Append(engine_name); - } while (conf->GetNextGroup(engine_name, index)); - } - - CONFIG_CLOSE(conf); -} - -void EditorPanel::RefreshTagsList() { - tags_list->DeleteAllItems(); - for (std::string s : game->ListTags()) { - long index = tags_list->InsertItem(0, s); - tags_list->SetItem(index, 1, game->GetTag(s)); - if (s == "FEN") { - tags_list->SetItemBackgroundColour(index, wxColour(200, 200, 200)); - } - } -} - -void EditorPanel::OnPreviousMove(wxCommandEvent &event) { - game->Previous(); - Notify(); - NotifyBoard(); -} - -void EditorPanel::OnNextMove(wxCommandEvent &event) { - game->Next(); - Notify(); - NotifyBoard(); -} \ No newline at end of file diff --git a/src/game_tab/editor/EditorPanel.hpp b/src/game_tab/editor/EditorPanel.hpp deleted file mode 100644 index 3ab98a5..0000000 --- a/src/game_tab/editor/EditorPanel.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../Game.hpp" -#include "EditorCanvas.hpp" -#include "ochess.hpp" -#include -#include - -// Local events -wxDECLARE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); -wxDECLARE_EVENT(REFRESH_TAB_TITLE, wxCommandEvent); - -// Foreign events -wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); - -class EditorPanel : public TabGameRightPanel { - Game *game; - EditorCanvas *editor_canvas; - long selected_item; - -public: - EditorPanel(wxFrame *parent, Game *game); - void NotifyBoard(); - void Notify(); - void OnCommentChange(wxCommandEvent &event); - void OnGotoMove(wxCommandEvent &event); - void OnMoveDelete(wxCommandEvent &event); - void OnMovePromote(wxCommandEvent &event); - void OnMoveSetAsMainline(wxCommandEvent &event); - void RefreshTagsList(); - void OnTagSelected(wxListEvent &event); - void OnTagDeselected(wxListEvent &event); - void OnApply(wxCommandEvent &event); - void OnDelete(wxCommandEvent &event); - void OnPreviousMove(wxCommandEvent &event); - void OnNextMove(wxCommandEvent &event); - void OnLiveAnalysis(wxCommandEvent &event); - void ApplyPreferences(); -}; \ No newline at end of file diff --git a/src/game_tab/editor/LiveEngineDialog.cpp b/src/game_tab/editor/LiveEngineDialog.cpp deleted file mode 100644 index 1f509ae..0000000 --- a/src/game_tab/editor/LiveEngineDialog.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "LiveEngineDialog.hpp" - -LiveEngineDialog::LiveEngineDialog(wxWindow *parent, std::string engine_name) - : DialogLiveEngine(parent), engine_name(engine_name), interval(1000), - engine(NULL) { - lines_list->InsertColumn(0, "#", wxLIST_FORMAT_LEFT, 50); - lines_list->InsertColumn(1, "CP", wxLIST_FORMAT_LEFT, 70); - lines_list->InsertColumn(2, "Line", wxLIST_FORMAT_LEFT, 300); - current_engine->SetLabel(engine_name); - InitEngine(); - Bind(wxEVT_BUTTON, &LiveEngineDialog::TogglePauseEngine, this, - LIVE_ENGINE_PAUSE_BUTTON); - Bind(wxEVT_CLOSE_WINDOW, &LiveEngineDialog::OnClose, this); -} - -void LiveEngineDialog::InitEngine() { - if (engine == NULL) { - wxLogDebug("Start engine: %s", engine_name); - CONFIG_OPEN(conf); - engine = new uciadapter::UCI( - conf->Read("engines/" + engine_name + "/path").ToStdString()); - engine->ucinewgame(); - - long index; - std::string optsPath = "engines/" + engine_name + "/options"; - conf->SetPath(optsPath); - wxString opt_name; - if (conf->GetFirstGroup(opt_name, index)) { - do { - wxString optPath = opt_name + "/"; - wxString default_value_wxString = conf->Read(optPath + "value"); - std::string default_value = default_value_wxString.ToStdString(); - engine->setoption(opt_name.ToStdString(), default_value); - if (opt_name.Lower() == "multipv") { - multipv->SetLabel(default_value_wxString); - } else if (opt_name.Lower() == "threads") { - threads->SetLabel(default_value_wxString); - } - } while (conf->GetNextGroup(opt_name, index)); - } - - CONFIG_CLOSE(conf); - } - timer.Start(interval); - timer.Bind(wxEVT_TIMER, &LiveEngineDialog::OnTimerTick, this); -} - -void LiveEngineDialog::OnClose(wxCloseEvent &e) { - if (engine != NULL) { - wxLogDebug("Close live engine!!"); - timer.Stop(); - engine->stop(); - engine->quit(); - delete engine; - } - e.Skip(); -} - -void LiveEngineDialog::SetFEN(std::string fen) { - StopEngine(); - engine->position(fen); - StartEngine(); -} - -void LiveEngineDialog::TogglePauseEngine(wxCommandEvent &event) { - if (timer.IsRunning()) { - StopEngine(); - engine_stop_button->SetLabel("Restart"); - depth->Enable(true); - } else { - engine_stop_button->SetLabel("Stop"); - depth->Enable(false); - StartEngine(); - } -} - -void LiveEngineDialog::StopEngine() { - if (timer.IsRunning()) { - timer.Stop(); - } - engine->stop(); -}; - -void LiveEngineDialog::StartEngine() { - uciadapter::Go args; - args.depth = depth->GetValue(); - engine->go(args); - if (!timer.IsRunning()) { - timer.Start(interval); - } -} - -void LiveEngineDialog::OnTimerTick(wxTimerEvent &event) { - wxLogDebug("Tick!"); - lines_list->DeleteAllItems(); - engine->SyncAfter(0); - for (auto const &line : engine->GetLines()) { - long index = lines_list->InsertItem(0, std::to_string(line.first)); - std::string line_moves; - for (std::string move : line.second.pv) { - line_moves += move + " "; - } - std::string cp_str = std::to_string(line.second.score_cp); - if (line.second.score_cp > 0) { - cp_str = "+" + cp_str; - } - lines_list->SetItem(index, 1, cp_str); - lines_list->SetItem(index, 2, line_moves); - } - wxLogDebug("%s", engine->GetBuffer()); -} \ No newline at end of file diff --git a/src/game_tab/editor/LiveEngineDialog.hpp b/src/game_tab/editor/LiveEngineDialog.hpp deleted file mode 100644 index 999002f..0000000 --- a/src/game_tab/editor/LiveEngineDialog.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "UCI.hpp" -#include "ochess.hpp" -#include - -class LiveEngineDialog : public DialogLiveEngine { - uciadapter::UCI *engine; - std::string engine_name; - wxTimer timer; - std::uint32_t interval; - -public: - LiveEngineDialog(wxWindow *parent, std::string engine_name); - void InitEngine(); - void TogglePauseEngine(wxCommandEvent &event); - void OnTimerTick(wxTimerEvent &event); - void SetFEN(std::string fen); - void StopEngine(); - void StartEngine(); - void OnClose(wxCloseEvent &e); -}; \ No newline at end of file diff --git a/src/game_tab/left_panel/GameTabLeftPanel.cpp b/src/game_tab/left_panel/GameTabLeftPanel.cpp new file mode 100644 index 0000000..79894d0 --- /dev/null +++ b/src/game_tab/left_panel/GameTabLeftPanel.cpp @@ -0,0 +1,96 @@ +#include "GameTabLeftPanel.hpp" +#include + +GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, Game *game) + : wxPanel(parent), game(game) { + + wxBoxSizer *board_panel_sizer = new wxBoxSizer(wxVERTICAL); + board_canvas = new BoardCanvas((wxFrame *)this); + board_panel_sizer->Add(board_canvas, 1, wxEXPAND); + + // Left Panel buttons + wxBoxSizer *board_panel_button_sizer = new wxBoxSizer(wxHORIZONTAL); + board_panel_button_sizer->Add( + new wxBitmapButton(this, SWAP_BTN, LoadPNG("swap")), 0); + board_panel_button_sizer->Add( + new wxBitmapButton(this, ZOOM_IN_BTN, LoadPNG("zoomin")), 0); + board_panel_button_sizer->Add( + new wxBitmapButton(this, ZOOM_OUT_BTN, LoadPNG("zoomout")), 0); + board_panel_button_sizer->Add(new wxButton(this, COPY_FEN_BTN, L"Copy FEN"), + 0, wxEXPAND); + board_panel_sizer->Add(board_panel_button_sizer, 0); + this->SetSizer(board_panel_sizer); + + Bind(PLAY_MOVE_EVENT, &GameTabLeftPanel::OnPlay, this, wxID_ANY); + Bind(PREVIOUS_MOVE_EVENT, &GameTabLeftPanel::OnPreviousMove, this, wxID_ANY); + Bind(NEXT_MOVE_EVENT, &GameTabLeftPanel::OnNextMove, this, wxID_ANY); + Bind(wxEVT_BUTTON, &GameTabLeftPanel::OnSwap, this, SWAP_BTN); + Bind(wxEVT_BUTTON, &GameTabLeftPanel::OnZoomIn, this, ZOOM_IN_BTN); + Bind(wxEVT_BUTTON, &GameTabLeftPanel::OnZoomOut, this, ZOOM_OUT_BTN); + Bind(wxEVT_BUTTON, &GameTabLeftPanel::OnCopyFEN, this, COPY_FEN_BTN); +} + +void GameTabLeftPanel::OnPreviousMove(wxCommandEvent &event) { + game->Previous(); + Notify(); + NotifyEditor(); +} + +void GameTabLeftPanel::OnZoomIn(wxCommandEvent &event) { + wxLogDebug("Clicked on zoom in"); + board_canvas->Zoom(10); +} + +void GameTabLeftPanel::OnZoomOut(wxCommandEvent &event) { + wxLogDebug("Clicked on zoom out"); + board_canvas->Zoom(-10); +} + +void GameTabLeftPanel::OnSwap(wxCommandEvent &event) { + wxLogDebug("Clicked on swap"); + board_canvas->Swap(); +} + +void GameTabLeftPanel::OnNextMove(wxCommandEvent &event) { + wxLogDebug("Game tab received NEXT_MOVE_EVENT"); + game->Next(); + Notify(); + NotifyEditor(); +} + +void GameTabLeftPanel::OnPlay(wxCommandEvent &event) { + wxLogDebug("Game tab received PLAY_MOVE_EVENT"); + if (game->Play(event.GetString().ToStdString())) { + NotifyEditor(); + } + Notify(); +} + +void GameTabLeftPanel::OnCopyFEN(wxCommandEvent &event) { + wxLogDebug("Clicked on copy fen"); + if (wxTheClipboard->Open()) { + wxTheClipboard->SetData(new wxTextDataObject(game->GetFen())); + wxTheClipboard->Close(); + } +} + +void GameTabLeftPanel::Notify() { + std::string fen = game->GetFen(); + std::map captures; + HalfMove *m = game->GetCurrentMove(); + if (m != NULL) { + captures = m->GetLineCaptures(); + } + board_canvas->SetupBoard(chessarbiter::FENParser::Parse(fen).board, + game->IsBlackToPlay(), captures); +} + +void GameTabLeftPanel::NotifyEditor() { + wxCommandEvent previousEvent(GAME_CHANGE, GetId()); + previousEvent.SetEventObject(this); + ProcessEvent(previousEvent); +} + +void GameTabLeftPanel::ApplyPreferences() { + board_canvas->ApplyPreferences(); +} diff --git a/src/game_tab/left_panel/GameTabLeftPanel.hpp b/src/game_tab/left_panel/GameTabLeftPanel.hpp new file mode 100644 index 0000000..85b1e6e --- /dev/null +++ b/src/game_tab/left_panel/GameTabLeftPanel.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "../Game.hpp" +#include "board/BoardCanvas.hpp" +#include "ochess.hpp" + +// Foreign events +wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); + +enum { COPY_FEN_BTN = wxID_HIGHEST + 1, ZOOM_IN_BTN, ZOOM_OUT_BTN, SWAP_BTN }; + +class GameTabLeftPanel : public wxPanel { + Game *game; + BoardCanvas *board_canvas; + void NotifyEditor(); + +public: + GameTabLeftPanel(wxFrame *parent, Game *game); + void Notify(); + void OnPlay(wxCommandEvent &event); + void OnGotoMove(wxCommandEvent &event); + void OnPreviousMove(wxCommandEvent &event); + void OnNextMove(wxCommandEvent &event); + void OnCopyFEN(wxCommandEvent &event); + void OnZoomIn(wxCommandEvent &event); + void OnZoomOut(wxCommandEvent &event); + void OnSwap(wxCommandEvent &event); + void OnRefreshBoard(wxCommandEvent &event); + void ApplyPreferences(); +}; \ No newline at end of file diff --git a/src/game_tab/left_panel/board/BoardCanvas.cpp b/src/game_tab/left_panel/board/BoardCanvas.cpp new file mode 100644 index 0000000..237a68a --- /dev/null +++ b/src/game_tab/left_panel/board/BoardCanvas.cpp @@ -0,0 +1,294 @@ +#include "BoardCanvas.hpp" + +wxDEFINE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); + +BoardCanvas::BoardCanvas(wxFrame *parent) + : wxPanel(parent), black_side(false), is_black_turn(true), frozen(false), + lock_square_size(false), t(new Theme()), t_captures(new Theme()) { + board = "rnbqkbnrpppppppp PPPPPPPPRNBQKBNR"; + is_dragging = false; + valid_drag = false; + t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + SetClockTime(-1, -1, -1, false); + SetClockTime(-1, -1, -1, true); + ApplyPreferences(); +} + +BoardCanvas::BoardCanvas(wxFrame *parent, std::uint32_t square_width, + bool frozen) + : BoardCanvas(parent) { + t->ResizeSquaresAndPieces(square_width); + t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + this->frozen = true; + lock_square_size = true; +} + +void BoardCanvas::OnPaint(wxPaintEvent &event) { + wxPaintDC dc(this); + REFRESH_MOUSE_LOCATION(); + square_width = t->GetSquaresSizes(); + canvas_size = dc.GetSize(); + boardX = (canvas_size.x - (8 * square_width)) / 2; + boardY = (canvas_size.y - (8 * square_width)) / 2; + if (boardX > canvas_size.x) + boardX = 0; + if (boardY > canvas_size.y) + boardY = 0; + DrawBoard(dc); +} + +void BoardCanvas::ApplyPreferences() { + if (t != NULL) + delete t; + if (t_captures != NULL) + delete t_captures; + t = new Theme(); + t_captures = new Theme(); + + CONFIG_OPEN(config); + black_side = config->Read("board/black_by_default", false); + if (lock_square_size) { + t->ResizeSquaresAndPieces(square_width); + } else { + t->ResizeSquaresAndPieces(config->Read("board/square_size", 80)); + } + t->SetSquareRadius(config->Read("board/corner_radius", 10)); + t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + CONFIG_CLOSE(config); + + Refresh(); +} + +void BoardCanvas::SetupBoard(std::string board, bool is_black_turn, + std::map captures) { + this->board = board; + this->is_black_turn = is_black_turn; + this->captures = captures; + Refresh(); +} + +void BoardCanvas::DrawBoard(wxPaintDC &dc) { + std::uint32_t piece_width = t->GetPiecesSizes(); + std::uint32_t centrer_offset = (square_width - piece_width) / 2; + + bool DrawDraggingPiece = false; + char dp = 'p'; + std::uint32_t dpx = 0, dpy = 0; + for (std::int8_t file = 7; file >= 0; file--) { + for (std::uint8_t rank = 0; rank <= 7; rank++) { + std::uint32_t x = boardX + (7 - file) * square_width; + std::uint32_t y = boardY + rank * square_width; + if ((file + rank) % 2 == 0) { + if (file == 0 && rank == 0) { + dc.DrawBitmap(*t->Get('1'), x, y, true); + } else if (file == 7 && rank == 7) { + dc.DrawBitmap(*t->Get('2'), x, y, true); + } else { + dc.DrawBitmap(*t->Get('s'), x, y, true); + } + } else { + if (file == 7 && rank == 0) { + dc.DrawBitmap(*t->Get('0'), x, y, true); + } else if (file == 0 && rank == 7) { + dc.DrawBitmap(*t->Get('3'), x, y, true); + } else { + dc.DrawBitmap(*t->Get('S'), x, y, true); + } + } + + std::uint8_t prank = rank; + std::uint8_t pfile = file; + if (black_side) { + prank = 7 - rank; + pfile = 7 - file; + } + std::uint32_t px = x + centrer_offset; + std::uint32_t py = y + centrer_offset; + char piece = board[(7 - pfile) + 8 * prank]; + if (is_dragging && (7 - pfile) == active_square.x && + (7 - prank) == active_square.y) { + dp = piece; + dpx = px - (lastClickX - mouseX); + dpy = py - (lastClickY - mouseY); + DrawDraggingPiece = true; + continue; + } + if (piece != ' ') { + dc.DrawBitmap(*t->Get(piece), px, py, false); + } + } + } + + // Draw badge + dc.SetPen(wxPen(*wxBLACK, 3)); + std::uint32_t badgeY = boardY; + std::uint32_t badgeWidth = square_width / 2; + if (is_black_turn) { + dc.SetBrush(*wxBLACK_BRUSH); + if (black_side) { + badgeY = boardY + (8 * square_width) - badgeWidth; + } + } else { + dc.SetBrush(*wxWHITE_BRUSH); + if (!black_side) { + badgeY = boardY + (8 * square_width) - badgeWidth; + } + } + wxRect badge(boardX + (8 * square_width) + badgeWidth / 2, badgeY, badgeWidth, + badgeWidth); + dc.DrawRectangle(badge); + + // Draw captures first for white then for black + std::uint32_t captures_size = t_captures->GetPiecesSizes(); + std::uint8_t padding = 10; + std::uint32_t offsetX = 0; + std::uint32_t offsetY = -(captures_size + padding); + if (black_side) { + offsetY = 8 * square_width + padding; + } + for (char p : {'P', 'N', 'B', 'R', 'Q'}) { + if (captures.find(p) != captures.end()) { + for (std::uint8_t i = 0; i < captures[p]; i++) { + dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); + offsetX += captures_size / 2; + } + offsetX += captures_size / 2; + } + } + offsetX = 0; + if (black_side) { + offsetY = -(captures_size + padding); + } else { + offsetY = 8 * square_width + padding; + } + for (char p : {'p', 'n', 'b', 'r', 'q'}) { + if (captures.find(p) != captures.end()) { + for (std::uint8_t i = 0; i < captures[p]; i++) { + dc.DrawBitmap(*t_captures->Get(p), boardX + offsetX, boardY + offsetY); + offsetX += captures_size / 2; + } + offsetX += captures_size / 2; + } + } + + // Draw dragging piece + if (DrawDraggingPiece) { + dc.DrawBitmap(*t->Get(dp), dpx, dpy, false); + } + + // Draw numbers + for (char l = 'a'; l < 'a' + 8; l++) { + dc.DrawText(wxString(l), wxPoint(boardX + l - 'a' * square_width, + boardY + 8 * square_width + 10)); + } + + // Draw Clocks + if (std::get<0>(black_time) >= 0) { + wxFont font = dc.GetFont(); + ClockTime clock = black_side ? white_time : black_time; + wxString 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)); + } else if (std::get<1>(clock) > 0) { + time = wxString::Format("%d:%ds", std::get<1>(clock), std::get<2>(clock)); + } + dc.SetFont(font.Scale(1.5).MakeBold()); + wxCoord width, height; + dc.GetTextExtent(time, &width, &height); + dc.DrawText(time, + wxPoint(boardX + square_width * 8 - width, boardY - height)); + clock = black_side ? black_time : 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)); + } else if (std::get<1>(clock) > 0) { + time = wxString::Format("%d:%ds", std::get<1>(clock), std::get<2>(clock)); + } + dc.GetTextExtent(time, &width, &height); + dc.DrawText(time, wxPoint(boardX + square_width * 8 - width, + boardY + square_width * 8)); + } +} + +void BoardCanvas::MouseEvent(wxMouseEvent &event) { + if (!frozen) { + if (event.Dragging()) { + if (valid_drag) { + is_dragging = true; + Refresh(); + } + } else { + if (is_dragging) { + is_dragging = false; + valid_drag = false; + // Handle drop + REFRESH_MOUSE_LOCATION(); + INIT_CURRENT_SQUARE(); + + if (IsCurrentSquareValid) { + wxLogDebug("Drag end on square (%d,%d)", file, rank); + /// Play the move + wxCommandEvent event(PLAY_MOVE_EVENT, GetId()); + event.SetEventObject(this); + std::string move = ((char)('a' + active_square.x)) + + std::to_string(+active_square.y + 1) + + ((char)('a' + file)) + std::to_string(rank + 1); + event.SetString(move); + ProcessEvent(event); + } + } + if (event.LeftDown()) { + SetFocus(); + REFRESH_MOUSE_LOCATION(); + lastClickX = mouseX; + lastClickY = mouseY; + INIT_CURRENT_SQUARE(); + if (IsCurrentSquareValid) { + active_square.x = file; + active_square.y = rank; + if (board[(7 - rank) * 8 + file] != ' ') { + wxLogDebug("Drag start on square (%d,%d)", file, rank); + valid_drag = true; + } + } + } + } + } +} + +void BoardCanvas::Zoom(std::int32_t zoom) { + t->Zoom(zoom); + t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR); + Refresh(); +} + +void BoardCanvas::Swap() { + black_side = !black_side; + Refresh(); +} + +void BoardCanvas::OnKeyEvent(wxKeyEvent &event) { + if (event.GetKeyCode() == WXK_LEFT) { + wxCommandEvent previousEvent(PREVIOUS_MOVE_EVENT, GetId()); + previousEvent.SetEventObject(this); + ProcessEvent(previousEvent); + } else if (event.GetKeyCode() == WXK_RIGHT) { + wxCommandEvent nextEvent(NEXT_MOVE_EVENT, GetId()); + nextEvent.SetEventObject(this); + ProcessEvent(nextEvent); + } +} + +void BoardCanvas::SetClockTime(short hours, short min, short sec, + bool IsBlack) { + if (IsBlack) { + black_time = std::make_tuple(hours, min, sec); + } else { + white_time = std::make_tuple(hours, min, sec); + } +} + +wxBEGIN_EVENT_TABLE(BoardCanvas, wxPanel) EVT_PAINT(BoardCanvas::OnPaint) + EVT_MOUSE_EVENTS(BoardCanvas::MouseEvent) + EVT_CHAR_HOOK(BoardCanvas::OnKeyEvent) wxEND_EVENT_TABLE() diff --git a/src/game_tab/left_panel/board/BoardCanvas.hpp b/src/game_tab/left_panel/board/BoardCanvas.hpp new file mode 100644 index 0000000..34c4911 --- /dev/null +++ b/src/game_tab/left_panel/board/BoardCanvas.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "Theme.hpp" +#include "ochess.hpp" +#include +#include +#include +#include +#include + +// Local events +wxDECLARE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent); + +// Foreign events +wxDECLARE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); + +#define REFRESH_MOUSE_LOCATION() \ + { \ + const wxPoint pt = wxGetMousePosition(); \ + mouseX = pt.x - this->GetScreenPosition().x; \ + mouseY = pt.y - this->GetScreenPosition().y; \ + } + +#define INIT_CURRENT_SQUARE() \ + std::uint32_t file = 7 - (mouseX - boardX) / square_width; \ + std::uint32_t rank = (mouseY - boardY) / square_width; \ + if (!black_side) { \ + file = 7 - file; \ + rank = 7 - rank; \ + } \ + bool IsCurrentSquareValid = file >= 0 && file <= 7 && rank >= 0 && rank <= 7; + +#define MOUSE_ON(x, y, width, height) \ + (mouseX >= (x) && mouseX <= ((x) + (width)) && mouseY >= (y) && \ + mouseY <= ((y) + (height))) + +#define CAPTURE_FACTOR 0.5 + +typedef std::tuple ClockTime; + +class BoardCanvas : public wxPanel { + Theme *t, *t_captures; + std::string board; + bool black_side, is_dragging, valid_drag, is_black_turn; + std::uint32_t boardX, boardY, square_width, mouseX, mouseY, lastClickX, + lastClickY; + wxSize canvas_size; + wxPoint active_square; + std::map captures; + ClockTime black_time, white_time; + bool frozen,lock_square_size; + +public: + BoardCanvas(wxFrame *parent); + BoardCanvas(wxFrame *parent,std::uint32_t square_width, bool frozen); + void ApplyPreferences(); + void DrawBoard(wxPaintDC &dc); + void OnPaint(wxPaintEvent &event); + void OnKeyEvent(wxKeyEvent &event); + void MouseEvent(wxMouseEvent &event); + void Zoom(std::int32_t zoom); + void Swap(); + void SetupBoard(std::string board, bool is_black_turn, + std::map captures); + 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 new file mode 100644 index 0000000..6ecbafc --- /dev/null +++ b/src/game_tab/left_panel/board/Theme.cpp @@ -0,0 +1,184 @@ +#include "Theme.hpp" +#include + +Theme::Theme() : square_radius(10) { + // Load config + CONFIG_OPEN(config); + std::string piece = + config->Read("board/theme/pieces/path", "default").ToStdString(); + wxFileName piece_file(piece); + std::string square = + config->Read("board/theme/squares/path", "default").ToStdString(); + wxFileName square_file(square); + CONFIG_CLOSE(config); + // Piece + if (piece == "default" || !piece_file.FileExists()) { + wxLogDebug("Loading piece skin from binres"); + LoadPiecesSkin(LoadPNG("cburnett").ConvertToImage()); + } else { + wxLogDebug("Loading piece skin: %s", piece); + LoadPiecesSkin(wxImage(piece, wxBITMAP_TYPE_PNG)); + } + // Square + if (square == "default" || !square_file.FileExists()) { + wxLogDebug("Loading square skin from binres"); + LoadSquaresSkin(LoadPNG("chesscom_8bits").ConvertToImage()); + } else { + wxLogDebug("Loading square skin: %s", square); + LoadSquaresSkin(wxImage(square, wxBITMAP_TYPE_PNG)); + } +} + +Theme::Theme(std::string piece, std::string square) : square_radius(10) { + wxLogDebug("Loading piece skin: %s", piece); + LoadPiecesSkin(wxImage(piece, wxBITMAP_TYPE_PNG)); + wxLogDebug("Loading square skin: %s", square); + LoadSquaresSkin(wxImage(square, wxBITMAP_TYPE_PNG)); +} + +Theme::~Theme() { + for (std::pair c : skin_scaled) { + delete c.second; + } +} + +std::uint8_t Theme::GetSquareRadius() { return (square_radius); } + +void Theme::LoadPiecesSkin(wxImage iskin) { + if (iskin.GetWidth() != 2 * ELT_DIM || iskin.GetHeight() != 6 * ELT_DIM) { + throw "Invalid piece theme"; + } + + int offset = 0; + // Kings + skin['k'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['K'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + // Queen + offset = ELT_DIM; + skin['q'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['Q'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + // Rook + offset = ELT_DIM * 2; + skin['r'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['R'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + // Bishop + offset = ELT_DIM * 3; + skin['b'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['B'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + // Knight + offset = ELT_DIM * 4; + skin['n'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['N'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + // Pawn + offset = ELT_DIM * 5; + skin['p'] = iskin.GetSubImage(wxRect(0, offset, ELT_DIM, ELT_DIM)); + skin['P'] = iskin.GetSubImage(wxRect(ELT_DIM, offset, ELT_DIM, ELT_DIM)); + + // Update scaled version + ResizePieces(DEFAULT_SIZE * PIECE_SIZE_FACTOR); +} + +void Theme::LoadSquaresSkin(wxImage iskin) { + if (iskin.GetWidth() != 2 * ELT_DIM || iskin.GetHeight() != ELT_DIM) { + throw "Invalid piece theme"; + } + + // Square + skin['s'] = iskin.GetSubImage(wxRect(0, 0, ELT_DIM, ELT_DIM)); + skin['S'] = iskin.GetSubImage(wxRect(ELT_DIM, 0, ELT_DIM, ELT_DIM)); + + // Update scaled version + ResizeSquares(DEFAULT_SIZE); +} + +wxBitmap *Theme::Get(char c) { return (skin_scaled[c]); } + +void Theme::ResizePieces(std::uint32_t width) { + for (std::pair c : skin) { + if (c.first != 's' && c.first != 'S') { + 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)); + } + } +} + +void Theme::ResizeSquaresAndPieces(std::uint32_t width) { + ResizeSquares(width); + ResizePieces(width * PIECE_SIZE_FACTOR); +} + +void Theme::ResizeSquares(std::uint32_t width) { + if (skin_scaled.count('s')) + delete skin_scaled['s']; + skin_scaled['s'] = + new wxBitmap(skin['s'].Scale(width, width, wxIMAGE_QUALITY_HIGH)); + if (skin_scaled.count('S')) + delete skin_scaled['S']; + skin_scaled['S'] = + new wxBitmap(skin['S'].Scale(width, width, wxIMAGE_QUALITY_HIGH)); + + skin_scaled['0'] = new wxBitmap(*skin_scaled['S']); + skin_scaled['1'] = new wxBitmap(*skin_scaled['s']); + skin_scaled['2'] = new wxBitmap(*skin_scaled['s']); + skin_scaled['3'] = new wxBitmap(*skin_scaled['S']); + + skin_scaled['0']->SetMask(RoundedMask(width, 0)); + skin_scaled['1']->SetMask(RoundedMask(width, 1)); + skin_scaled['2']->SetMask(RoundedMask(width, 2)); + skin_scaled['3']->SetMask(RoundedMask(width, 3)); +} + +void Theme::Zoom(int amount) { + double width = skin_scaled['s']->GetWidth() + amount; + ResizeSquares(std::max(width, 1.0)); + ResizePieces(std::max(width * PIECE_SIZE_FACTOR, 1.0)); +} + +void Theme::SetSquareRadius(std::uint8_t radius) { + square_radius = radius; + Zoom(0); // Refresh scale +} + +/** + * This will never fail since k entry always exists (cf constructor and + * ResizePieces) + */ +double Theme::GetPiecesSizes() { return (skin_scaled['k']->GetWidth()); } + +/** + * This will never fail since s entry always exists (cf constructor and + * ResizeSquares) + */ +double Theme::GetSquaresSizes() { return (skin_scaled['s']->GetWidth()); } + +wxMask *Theme::RoundedMask(std::uint32_t width, std::uint8_t corner) { + + wxBitmap b(width, width, 1); + wxMemoryDC dc; + dc.SelectObject(b); + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxBLACK_BRUSH); + dc.DrawRectangle(0, 0, width, width); + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(*wxWHITE_PEN); + dc.DrawRoundedRectangle(0, 0, width, width, square_radius); + + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(*wxWHITE_PEN); + if (corner == 0) { + dc.DrawRectangle(0, width / 2, width, width); + dc.DrawRectangle(width / 2, 0, width, width); + } else if (corner == 1) { + dc.DrawRectangle(0, 0, width / 2, width); + dc.DrawRectangle(0, width / 2, width, width); + } else if (corner == 2) { + dc.DrawRectangle(0, 0, width, width / 2); + dc.DrawRectangle(width / 2, 0, width, width); + } else if (corner == 3) { + dc.DrawRectangle(0, 0, width / 2, width); + dc.DrawRectangle(0, 0, width, width / 2); + } + return (new wxMask(b)); +} diff --git a/src/game_tab/left_panel/board/Theme.hpp b/src/game_tab/left_panel/board/Theme.hpp new file mode 100644 index 0000000..88036d8 --- /dev/null +++ b/src/game_tab/left_panel/board/Theme.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "ochess.hpp" + +#include +#include + +#define ELT_DIM 200 +#define DEFAULT_SIZE 80 +#define PIECE_SIZE_FACTOR 0.8 // Should be between 0 and 1 +#define DEFAULT_PIECE_THEME "assets/pieces/cburnett.png" +#define DEFAULT_SQUARE_THEME "assets/boards/chesscom_8bits.png" + +class Theme { +private: + std::unordered_map skin; + std::unordered_map skin_scaled; + std::uint8_t square_radius; + wxMask *RoundedMask(std::uint32_t width, std::uint8_t corner); + +public: + Theme(); + Theme(std::string piece, std::string square); + ~Theme(); + void LoadPiecesSkin(wxImage skin); + void LoadSquaresSkin(wxImage iskin); + void ResizePieces(std::uint32_t width); + void ResizeSquares(std::uint32_t width); + void ResizeSquaresAndPieces(std::uint32_t width); + void SetSquareRadius(std::uint8_t radius); + std::uint8_t GetSquareRadius(); + void Zoom(int amount); + double GetPiecesSizes(); + double GetSquaresSizes(); + + wxBitmap *Get(char c); +}; diff --git a/src/game_tab/right_panel/GameTabRightPanel.cpp b/src/game_tab/right_panel/GameTabRightPanel.cpp new file mode 100644 index 0000000..f7c9b1b --- /dev/null +++ b/src/game_tab/right_panel/GameTabRightPanel.cpp @@ -0,0 +1,193 @@ +#include "GameTabRightPanel.hpp" +#include "LiveEngineDialog.hpp" + +wxDEFINE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); + +GameTabRightPanel::GameTabRightPanel(wxFrame *parent, Game *game) + : TabGameRightPanel(parent), game(game), selected_item(-1) { + editor_canvas = new EditorCanvas((wxFrame *)editor_page); + editor_canvas_sizer->Add(editor_canvas, 1, wxEXPAND); + tags_list->InsertColumn(0, L"Name", wxLIST_FORMAT_LEFT, 200); + tags_list->InsertColumn(1, L"Value", wxLIST_FORMAT_LEFT, 500); + tagTextCtrl->SetHint("Tag"); + valueTextCtrl->SetHint("Value"); + + /*LiveEngineDialog *diag=new LiveEngineDialog(this, "Stockfish"); + diag->SetFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + + diag->Show();*/ + RefreshTagsList(); + + // Bind events + this->Bind(wxEVT_TEXT, &GameTabRightPanel::OnCommentChange, this, + COMMENT_INPUT_BOX); + this->Bind(GOTO_MOVE_EVENT, &GameTabRightPanel::OnGotoMove, this, wxID_ANY); + this->Bind(DELETE_MOVE_EVENT, &GameTabRightPanel::OnMoveDelete, this, wxID_ANY); + this->Bind(PROMOTE_MOVE_EVENT, &GameTabRightPanel::OnMovePromote, this, wxID_ANY); + this->Bind(SET_AS_MAINLINE_EVENT, &GameTabRightPanel::OnMoveSetAsMainline, this, + wxID_ANY); + this->Bind(NEXT_MOVE_EVENT, &GameTabRightPanel::OnNextMove, this, wxID_ANY); + this->Bind(PREVIOUS_MOVE_EVENT, &GameTabRightPanel::OnPreviousMove, this, wxID_ANY); + this->Bind(wxEVT_LIST_ITEM_SELECTED, &GameTabRightPanel::OnTagSelected, this, + wxID_ANY); + this->Bind(wxEVT_LIST_ITEM_DESELECTED, &GameTabRightPanel::OnTagDeselected, this, + wxID_ANY); + this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnApply, this, UPDATE_BTN); + this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnDelete, this, DELETE_BTN); + this->Bind(wxEVT_BUTTON, &GameTabRightPanel::OnLiveAnalysis, this, + LIVE_ANALYSIS_GAME_BUTTON); + + ApplyPreferences(); +} + +void GameTabRightPanel::OnLiveAnalysis(wxCommandEvent &event) { + int selection = engine_list->GetSelection(); + if (selection != wxNOT_FOUND) { + LiveEngineDialog *diag = new LiveEngineDialog(this, engine_list->GetString(selection).ToStdString()); + diag->SetFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + diag->Show(); + } +} + +void GameTabRightPanel::OnTagSelected(wxListEvent &event) { + wxListItem item = event.GetItem(); + std::string key = item.GetText().ToStdString(); + tagTextCtrl->ChangeValue(key); + item.SetColumn(1); + tags_list->GetItem(item); + valueTextCtrl->ChangeValue(item.GetText().ToStdString()); + selected_item = item.GetId(); + delete_button->Enable(true); +} + +void GameTabRightPanel::OnTagDeselected(wxListEvent &event) { + selected_item = -1; + delete_button->Enable(false); +} + +void GameTabRightPanel::NotifyBoard() { + wxCommandEvent previousEvent(GAME_CHANGE, GetId()); + previousEvent.SetEventObject(this); + ProcessEvent(previousEvent); +} + +void GameTabRightPanel::OnCommentChange(wxCommandEvent &event) { + wxLogDebug("GameTabRightPanel: comment input change"); + HalfMove *m = game->GetCurrentMove(); + if (m != NULL) { + m->SetComment(event.GetString().ToStdString()); + } + editor_canvas->Refresh(); +} + +void GameTabRightPanel::OnApply(wxCommandEvent &event) { + std::string key = tagTextCtrl->GetValue().ToStdString(); + if (key == "FEN") { + SHOW_DIALOG_ERROR("Editing the FEN tag is forbidden"); + return; + } + if (key.size() > 0) { + std::string value = valueTextCtrl->GetValue().ToStdString(); + game->SetTag(key, value); + RefreshTagsList(); + wxCommandEvent event(REFRESH_TAB_TITLE, GetId()); + event.SetEventObject(this); + ProcessEvent(event); + } +} + +void GameTabRightPanel::OnDelete(wxCommandEvent &event) { + if (selected_item >= 0) { + wxListItem item; + item.SetColumn(0); + item.SetId(selected_item); + tags_list->GetItem(item); + std::string key = item.GetText().ToStdString(); + if (key != "FEN") { + game->DeleteTag(key); + selected_item = -1; + RefreshTagsList(); + } else { + SHOW_DIALOG_ERROR("Deleting the FEN tag is forbidden."); + } + } +} + +void GameTabRightPanel::OnGotoMove(wxCommandEvent &event) { + wxLogDebug("GameTabRightPanel: received GOTO_MOVE_EVENT"); + game->SetCurrent((HalfMove *)event.GetClientData()); + NotifyBoard(); + editor_canvas->Refresh(); +} + +void GameTabRightPanel::OnMoveDelete(wxCommandEvent &event) { + game->DeleteMove((HalfMove *)event.GetClientData()); + NotifyBoard(); + editor_canvas->Refresh(); +} + +void GameTabRightPanel::OnMovePromote(wxCommandEvent &event) { + wxLogDebug("GameTabRightPanel: promote move called"); + game->PromoteMove((HalfMove *)event.GetClientData()); + NotifyBoard(); + editor_canvas->Refresh(); +} + +void GameTabRightPanel::OnMoveSetAsMainline(wxCommandEvent &event) { + wxLogDebug("GameTabRightPanel: set move as mainline called"); + game->SetMoveAsMainline((HalfMove *)event.GetClientData()); + NotifyBoard(); + editor_canvas->Refresh(); +} + +void GameTabRightPanel::Notify() { + HalfMove *m = game->GetCurrentMove(); + if (m != NULL) { + comment_input->ChangeValue( + m->GetComment()); // ChangeValue do not raise events + } + editor_canvas->SetMoves(game->GetMoves(), m); +} + +void GameTabRightPanel::ApplyPreferences() { + engine_list->Clear(); + CONFIG_OPEN(conf); + conf->SetPath("engines/"); + wxString engine_name; + long index; + if (conf->GetFirstGroup(engine_name, index)) { + do { + engine_list->Append(engine_name); + } while (conf->GetNextGroup(engine_name, index)); + } + + CONFIG_CLOSE(conf); +} + +void GameTabRightPanel::RefreshTagsList() { + tags_list->DeleteAllItems(); + for (std::string s : game->ListTags()) { + long index = tags_list->InsertItem(0, s); + tags_list->SetItem(index, 1, game->GetTag(s)); + if (s == "FEN") { + tags_list->SetItemBackgroundColour(index, wxColour(200, 200, 200)); + } + } +} + +void GameTabRightPanel::OnPreviousMove(wxCommandEvent &event) { + game->Previous(); + Notify(); + NotifyBoard(); +} + +void GameTabRightPanel::OnNextMove(wxCommandEvent &event) { + game->Next(); + Notify(); + NotifyBoard(); +} \ No newline at end of file diff --git a/src/game_tab/right_panel/GameTabRightPanel.hpp b/src/game_tab/right_panel/GameTabRightPanel.hpp new file mode 100644 index 0000000..c5912dd --- /dev/null +++ b/src/game_tab/right_panel/GameTabRightPanel.hpp @@ -0,0 +1,40 @@ +#include "../Game.hpp" +#include "editor/EditorCanvas.hpp" +#include "ochess.hpp" +#include +#include + +// Local events +wxDECLARE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(REFRESH_TAB_TITLE, wxCommandEvent); + +// Foreign events +wxDECLARE_EVENT(GAME_CHANGE, wxCommandEvent); + +class GameTabRightPanel : public TabGameRightPanel { + Game *game; + EditorCanvas *editor_canvas; + long selected_item; + +public: + GameTabRightPanel(wxFrame *parent, Game *game); + void NotifyBoard(); + void Notify(); + void OnCommentChange(wxCommandEvent &event); + void OnGotoMove(wxCommandEvent &event); + void OnMoveDelete(wxCommandEvent &event); + void OnMovePromote(wxCommandEvent &event); + void OnMoveSetAsMainline(wxCommandEvent &event); + void RefreshTagsList(); + void OnTagSelected(wxListEvent &event); + void OnTagDeselected(wxListEvent &event); + void OnApply(wxCommandEvent &event); + void OnDelete(wxCommandEvent &event); + void OnPreviousMove(wxCommandEvent &event); + void OnNextMove(wxCommandEvent &event); + void OnLiveAnalysis(wxCommandEvent &event); + void ApplyPreferences(); +}; \ No newline at end of file diff --git a/src/game_tab/right_panel/LiveEngineDialog.cpp b/src/game_tab/right_panel/LiveEngineDialog.cpp new file mode 100644 index 0000000..1f509ae --- /dev/null +++ b/src/game_tab/right_panel/LiveEngineDialog.cpp @@ -0,0 +1,111 @@ +#include "LiveEngineDialog.hpp" + +LiveEngineDialog::LiveEngineDialog(wxWindow *parent, std::string engine_name) + : DialogLiveEngine(parent), engine_name(engine_name), interval(1000), + engine(NULL) { + lines_list->InsertColumn(0, "#", wxLIST_FORMAT_LEFT, 50); + lines_list->InsertColumn(1, "CP", wxLIST_FORMAT_LEFT, 70); + lines_list->InsertColumn(2, "Line", wxLIST_FORMAT_LEFT, 300); + current_engine->SetLabel(engine_name); + InitEngine(); + Bind(wxEVT_BUTTON, &LiveEngineDialog::TogglePauseEngine, this, + LIVE_ENGINE_PAUSE_BUTTON); + Bind(wxEVT_CLOSE_WINDOW, &LiveEngineDialog::OnClose, this); +} + +void LiveEngineDialog::InitEngine() { + if (engine == NULL) { + wxLogDebug("Start engine: %s", engine_name); + CONFIG_OPEN(conf); + engine = new uciadapter::UCI( + conf->Read("engines/" + engine_name + "/path").ToStdString()); + engine->ucinewgame(); + + long index; + std::string optsPath = "engines/" + engine_name + "/options"; + conf->SetPath(optsPath); + wxString opt_name; + if (conf->GetFirstGroup(opt_name, index)) { + do { + wxString optPath = opt_name + "/"; + wxString default_value_wxString = conf->Read(optPath + "value"); + std::string default_value = default_value_wxString.ToStdString(); + engine->setoption(opt_name.ToStdString(), default_value); + if (opt_name.Lower() == "multipv") { + multipv->SetLabel(default_value_wxString); + } else if (opt_name.Lower() == "threads") { + threads->SetLabel(default_value_wxString); + } + } while (conf->GetNextGroup(opt_name, index)); + } + + CONFIG_CLOSE(conf); + } + timer.Start(interval); + timer.Bind(wxEVT_TIMER, &LiveEngineDialog::OnTimerTick, this); +} + +void LiveEngineDialog::OnClose(wxCloseEvent &e) { + if (engine != NULL) { + wxLogDebug("Close live engine!!"); + timer.Stop(); + engine->stop(); + engine->quit(); + delete engine; + } + e.Skip(); +} + +void LiveEngineDialog::SetFEN(std::string fen) { + StopEngine(); + engine->position(fen); + StartEngine(); +} + +void LiveEngineDialog::TogglePauseEngine(wxCommandEvent &event) { + if (timer.IsRunning()) { + StopEngine(); + engine_stop_button->SetLabel("Restart"); + depth->Enable(true); + } else { + engine_stop_button->SetLabel("Stop"); + depth->Enable(false); + StartEngine(); + } +} + +void LiveEngineDialog::StopEngine() { + if (timer.IsRunning()) { + timer.Stop(); + } + engine->stop(); +}; + +void LiveEngineDialog::StartEngine() { + uciadapter::Go args; + args.depth = depth->GetValue(); + engine->go(args); + if (!timer.IsRunning()) { + timer.Start(interval); + } +} + +void LiveEngineDialog::OnTimerTick(wxTimerEvent &event) { + wxLogDebug("Tick!"); + lines_list->DeleteAllItems(); + engine->SyncAfter(0); + for (auto const &line : engine->GetLines()) { + long index = lines_list->InsertItem(0, std::to_string(line.first)); + std::string line_moves; + for (std::string move : line.second.pv) { + line_moves += move + " "; + } + std::string cp_str = std::to_string(line.second.score_cp); + if (line.second.score_cp > 0) { + cp_str = "+" + cp_str; + } + lines_list->SetItem(index, 1, cp_str); + lines_list->SetItem(index, 2, line_moves); + } + wxLogDebug("%s", engine->GetBuffer()); +} \ No newline at end of file diff --git a/src/game_tab/right_panel/LiveEngineDialog.hpp b/src/game_tab/right_panel/LiveEngineDialog.hpp new file mode 100644 index 0000000..999002f --- /dev/null +++ b/src/game_tab/right_panel/LiveEngineDialog.hpp @@ -0,0 +1,20 @@ +#include "UCI.hpp" +#include "ochess.hpp" +#include + +class LiveEngineDialog : public DialogLiveEngine { + uciadapter::UCI *engine; + std::string engine_name; + wxTimer timer; + std::uint32_t interval; + +public: + LiveEngineDialog(wxWindow *parent, std::string engine_name); + void InitEngine(); + void TogglePauseEngine(wxCommandEvent &event); + void OnTimerTick(wxTimerEvent &event); + void SetFEN(std::string fen); + void StopEngine(); + void StartEngine(); + void OnClose(wxCloseEvent &e); +}; \ No newline at end of file diff --git a/src/game_tab/right_panel/editor/EditorCanvas.cpp b/src/game_tab/right_panel/editor/EditorCanvas.cpp new file mode 100644 index 0000000..0e2f77a --- /dev/null +++ b/src/game_tab/right_panel/editor/EditorCanvas.cpp @@ -0,0 +1,188 @@ +#include "EditorCanvas.hpp" + +EditorCanvas::EditorCanvas(wxFrame *parent) + : wxPanel(parent), NeedRedraw(false) { + hide_icon = LoadPNG("hide", wxSize(CGEditor::status.MoveIconWidth, + CGEditor::status.MoveIconWidth)); + t.ResizePieces(CGEditor::status.MoveIconWidth); +} + +void EditorCanvas::OnPaint(wxPaintEvent &event) { + wxPaintDC current_dc(this); + dc = ¤t_dc; + + // Refresh canvas size + wxSize sz = GetClientSize(); + CGEditor::status.CanvasWidth = sz.GetWidth(); + CGEditor::status.CanvasHeight = sz.GetHeight(); + CGEditor::status.UseMoveIcons = + true; // Piece image should be drawn before the move ? + + const wxPoint pt = wxGetMousePosition(); + CGEditor::status.MouseX = pt.x - this->GetScreenPosition().x; + CGEditor::status.MouseY = pt.y - this->GetScreenPosition().y; + CGEditor::Draw(); +} + +/** + * @brief Convenient fonction to center text + * + * @param e Element to center + * @return wxPoint The centered version of e according to wdWidget API + */ +wxPoint EditorCanvas::Middle(cgeditor::Element e) { + wxSize sz = dc->GetTextExtent(e.text); + return (wxPoint(e.x + (e.width - sz.GetWidth()) / 2, + e.y + (e.height - sz.GetHeight()) / 2)); +} + +void EditorCanvas::DrawElement(const cgeditor::Element &e) { + dc->SetPen(wxNullPen); + dc->SetBrush(*wxRED_BRUSH); + if (e.prop & cgeditor::Property::Rectangle) { + if (e.prop & cgeditor::Property::Scrollbarbg) { + dc->SetBrush(*wxCYAN_BRUSH); + } else if (e.prop & cgeditor::Property::Scrollbar) { + dc->SetBrush(*wxGREY_BRUSH); + } else if (e.prop & cgeditor::Property::Margin) { + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + } else if (e.prop & cgeditor::Property::Button) { + if (e.prop & cgeditor::Property::On) { + dc->DrawBitmap(hide_icon, e.x, e.y); + return; + } + dc->SetBrush(*wxBLACK_BRUSH); + } + wxRect recToDraw(e.x, e.y, e.width, e.height); + dc->DrawRectangle(recToDraw); + } else if (e.prop & cgeditor::Property::Text || + e.prop & cgeditor::Property::Image) { + if (e.prop & cgeditor::Property::Image) { + // Draw your pieces images instead + std::uint32_t y = Middle(e).y - CGEditor::status.MoveIconWidth / 2; + char p = 'P'; + if (e.prop & cgeditor::Property::Knight) { + p = 'N'; + } else if (e.prop & cgeditor::Property::Bishop) { + p = 'B'; + } else if (e.prop & cgeditor::Property::Queen) { + p = 'Q'; + } else if (e.prop & cgeditor::Property::King) { + p = 'K'; + } else if (e.prop & cgeditor::Property::Rook) { + p = 'R'; + } + if (e.prop & cgeditor::Property::Black) { + p = std::tolower(p); + } + if (e.prop & cgeditor::Property::Current) { + wxRect recToDraw(e.x, e.y, e.width, e.height); + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->DrawRectangle(recToDraw); + } + dc->DrawBitmap(*t.Get(p), e.x, y); + } else if (e.prop & cgeditor::Property::Comment) { + wxRect recToDraw(e.x, e.y, e.width, e.height); + dc->SetBrush(*wxYELLOW_BRUSH); + dc->DrawRectangle(recToDraw); + dc->DrawText(wxString(e.text), wxPoint(e.x, e.y)); + } else if (e.prop & cgeditor::Property::Menuitem) { + wxRect recToDraw(e.x, e.y, e.width, e.height); + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->DrawRectangle(recToDraw); + dc->DrawText(wxString(e.text), wxPoint(e.x, Middle(e).y)); + } else { + if (e.prop & cgeditor::Property::Move) { + if (e.prop & cgeditor::Property::Current) { + wxRect recToDraw(e.x, e.y, e.width, e.height); + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->DrawRectangle(recToDraw); + } + if (CGEditor::status.UseMoveIcons) { + dc->DrawText(wxString(e.text), wxPoint(e.x, Middle(e).y)); + } else { + dc->DrawText(wxString(e.text), Middle(e)); + } + } else { + dc->DrawText(wxString(e.text), Middle(e)); + } + } + } +} +void EditorCanvas::HandleEvent(const cgeditor::Event &e) { + wxLogDebug("Editor event!"); + if (e.type == cgeditor::Event::Goto) { + wxCommandEvent event(GOTO_MOVE_EVENT, GetId()); + event.SetEventObject(this); + event.SetClientData(e.move); + ProcessEvent(event); + } else if (e.type == cgeditor::Event::Delete) { + wxCommandEvent event(DELETE_MOVE_EVENT, GetId()); + event.SetEventObject(this); + event.SetClientData(e.move); + ProcessEvent(event); + } else if (e.type == cgeditor::Event::Promote) { + wxCommandEvent event(PROMOTE_MOVE_EVENT, GetId()); + event.SetEventObject(this); + event.SetClientData(e.move); + ProcessEvent(event); + } else if (e.type == cgeditor::Event::SetAsMainline) { + wxCommandEvent event(SET_AS_MAINLINE_EVENT, GetId()); + event.SetEventObject(this); + event.SetClientData(e.move); + ProcessEvent(event); + } +} + +void EditorCanvas::MouseEvent(wxMouseEvent &event) { + if (event.Dragging()) { + CGEditor::status.LeftClick = false; + CGEditor::status.IsDrag = true; + Refresh(); + } else if (event.LeftDown()) { + SetFocus(); + CGEditor::status.LeftClick = true; + Refresh(); + } else if (event.RightDown()) { + SetFocus(); + CGEditor::status.RightClick = true; + Refresh(); + } else if (event.GetWheelRotation() != 0) { + SetFocus(); + if (event.GetWheelRotation() < 0) { + CGEditor::status.EventVScroll = 50; + } else { + CGEditor::status.EventVScroll = -50; + } + Refresh(); + } + + // Should another draw of CGEditor be made? + if (NeedRedraw) { + Refresh(); + NeedRedraw = false; + } +} + +void EditorCanvas::SetMoves(HalfMove *moves, HalfMove *current) { + CGEditor::status.Moves = moves; + CGEditor::status.CurrentMove = current; + + Refresh(); +} + +void EditorCanvas::OnKeyEvent(wxKeyEvent &event) { + if (event.GetKeyCode() == WXK_LEFT) { + wxCommandEvent previousEvent(PREVIOUS_MOVE_EVENT, GetId()); + previousEvent.SetEventObject(this); + ProcessEvent(previousEvent); + } else if (event.GetKeyCode() == WXK_RIGHT) { + wxCommandEvent nextEvent(NEXT_MOVE_EVENT, GetId()); + nextEvent.SetEventObject(this); + ProcessEvent(nextEvent); + } +} + +wxBEGIN_EVENT_TABLE(EditorCanvas, wxPanel) EVT_PAINT(EditorCanvas::OnPaint) + EVT_MOUSE_EVENTS(EditorCanvas::MouseEvent) + EVT_CHAR_HOOK(EditorCanvas::OnKeyEvent) wxEND_EVENT_TABLE() diff --git a/src/game_tab/right_panel/editor/EditorCanvas.hpp b/src/game_tab/right_panel/editor/EditorCanvas.hpp new file mode 100644 index 0000000..c2f35c8 --- /dev/null +++ b/src/game_tab/right_panel/editor/EditorCanvas.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "../../HalfMove.hpp" +#include "CGEditor.hpp" +#include "ochess.hpp" +#include "../../left_panel/board/Theme.hpp" + +// Foreign events +wxDECLARE_EVENT(GOTO_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(PREVIOUS_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(NEXT_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(DELETE_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(PROMOTE_MOVE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(SET_AS_MAINLINE_EVENT, wxCommandEvent); + +class EditorCanvas : public wxPanel, public cgeditor::CGEditor { + wxPaintDC *dc; + bool NeedRedraw; + wxPoint Middle(cgeditor::Element e); + wxBitmap hide_icon; + Theme t; + +public: + EditorCanvas(wxFrame *parent); + void OnPaint(wxPaintEvent &event); + void MouseEvent(wxMouseEvent &event); + void DrawElement(const cgeditor::Element &e); + void HandleEvent(const cgeditor::Event &e); + void SetMoves(HalfMove *moves, HalfMove *current); + void OnKeyEvent(wxKeyEvent &event); + + DECLARE_EVENT_TABLE() +}; diff --git a/src/preferences/BoardPrefs.hpp b/src/preferences/BoardPrefs.hpp index e0672b0..6169d22 100644 --- a/src/preferences/BoardPrefs.hpp +++ b/src/preferences/BoardPrefs.hpp @@ -1,4 +1,4 @@ -#include "game_tab/board/BoardCanvas.hpp" +#include "game_tab/left_panel/board/BoardCanvas.hpp" #include "ochess.hpp" #include #include diff --git a/src/preferences/EditorPrefs.hpp b/src/preferences/EditorPrefs.hpp index 8974bfe..9a8ca0d 100644 --- a/src/preferences/EditorPrefs.hpp +++ b/src/preferences/EditorPrefs.hpp @@ -1,4 +1,3 @@ -#include "game_tab/board/BoardCanvas.hpp" #include "ochess.hpp" #include #include -- cgit v1.2.3