aboutsummaryrefslogtreecommitdiff
path: root/src/game_tab/right_panel
diff options
context:
space:
mode:
authorLoic Guegan <manzerbredes@mailbox.org>2022-02-28 13:44:27 +0100
committerLoic Guegan <manzerbredes@mailbox.org>2022-02-28 13:44:27 +0100
commitbf485fa577a76731f9eac97de3b0a647cd492e49 (patch)
tree731d9ec91070406124044e75b4b27949e5d230c0 /src/game_tab/right_panel
parent7178f18ab88bcc93bfbf2019adf53d2f60d8fa20 (diff)
Refactoring game tab
Diffstat (limited to 'src/game_tab/right_panel')
-rw-r--r--src/game_tab/right_panel/GameTabRightPanel.cpp193
-rw-r--r--src/game_tab/right_panel/GameTabRightPanel.hpp40
-rw-r--r--src/game_tab/right_panel/LiveEngineDialog.cpp111
-rw-r--r--src/game_tab/right_panel/LiveEngineDialog.hpp20
-rw-r--r--src/game_tab/right_panel/editor/EditorCanvas.cpp188
-rw-r--r--src/game_tab/right_panel/editor/EditorCanvas.hpp33
6 files changed, 585 insertions, 0 deletions
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 <wx/listctrl.h>
+#include <wx/notebook.h>
+
+// 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 <wx/timer.h>
+
+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 = &current_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()
+};