aboutsummaryrefslogtreecommitdiff
path: root/src/game_tab/left_panel/GameTabLeftPanel.cpp
blob: 6a8deec87afc93f7c3a452e3fe7cdba2eec71b6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include "GameTabLeftPanel.hpp"
#include <wx/clipbrd.h>

GameTabLeftPanel::GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game)
    : TabGameLeftPanel(parent), game(game), repeat(false), is_engine_on(false) {

  // Configure toolbar (note that toolbar events are processed into the GameTab class)
  game_toolbar->AddTool(0, wxT("Save As"),
  wxArtProvider::GetBitmap(wxART_FILE_SAVE, wxART_TOOLBAR));
  game_toolbar->AddTool(1, wxT("Duplicate Game"),
  wxArtProvider::GetBitmap(wxART_COPY, wxART_TOOLBAR));

  // Add board
  board_canvas = new BoardCanvas((wxFrame *)this);
  main_sizer->Insert(1, board_canvas, 1, wxEXPAND);

  // Configure buttons
  swap_button->SetBitmapLabel(LoadPNG("swap"));
  zoomin_button->SetBitmapLabel(LoadPNG("zoomin"));
  zoomout_button->SetBitmapLabel(LoadPNG("zoomout"));

  // Configure FEN field
  fen_text_field->SetFont(wxFont(*wxNORMAL_FONT).Bold().Larger());
  last_move=game->GetCurrentMove();

  // Bind events:
  Bind(PLAY_MOVE_EVENT, &GameTabLeftPanel::OnPlay, this, wxID_ANY);
  Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Zoom(10);}, ZOOM_IN_BTN);
  Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Zoom(-10);}, ZOOM_OUT_BTN);
  Bind(wxEVT_BUTTON, [bc=board_canvas](wxCommandEvent &event){bc->Swap();}, SWAP_BTN);
  Bind(wxEVT_KEY_UP, [p=this](wxKeyEvent &e){p->repeat=false;});
  Bind(wxEVT_KEY_DOWN, [p=this](wxKeyEvent &e){
    if(e.GetKeyCode() == WXK_RIGHT){
      p->game->Next();
      p->Notify();
      p->repeat=true;
    } else if(e.GetKeyCode() == WXK_LEFT){
      p->game->Previous();
      p->Notify();
      p->repeat=true;
    }
    // Notify other classes
    wxCommandEvent event(GAME_CHANGE, p->GetId());
    event.SetEventObject(p);
    p->ProcessEvent(event);
  });
  Bind(wxEVT_MOUSEWHEEL, [p=this](wxMouseEvent& e){
    if(e.GetWheelRotation()<0){
      p->game->Next();
      p->Notify();
    }else {
      p->game->Previous();
      p->Notify();
    }
    // Notify other classes
    wxCommandEvent event(GAME_CHANGE, p->GetId());
    event.SetEventObject(p);
    p->ProcessEvent(event);
  });
}

void GameTabLeftPanel::OnPlay(wxCommandEvent &event) {
  engine_arrows.clear(); // Remove displayed engine arrows
  std::string move=event.GetString().ToStdString();
  int size=move.size();
  char promote=(char)event.GetInt();
  // First check if it is a promotion move (to prompt the user for a piece)
  if(size>0 && game->IsPromotionMove(move)){
    promote_on=move.substr(2,2); // Will trigger the piece prompt on next Notify()
    promotion_move=move; // Save the move that should be played for the promotion
  } else {
    if(size==0){ // It is a promotion move?
      move=promotion_move; // Play the save promotion move
      promote_on.clear(); // Clear user prompte (cf. Notify())
      promotion_move.clear();
    }
    if(game->Play(move,promote)){
      // Notify other classes
      wxCommandEvent event(GAME_CHANGE, GetId());
      event.SetEventObject(this);
      ProcessEvent(event);
    }
  }
  Notify(true); // Redraw event is move failed! Otherwise piece not resets to it initial position after dragging
}

void GameTabLeftPanel::SetEngineEvaluation(EngineEvaluation eval){
  if(is_engine_on){
    engine_arrows.clear();
    float scale=1;
    unsigned char alpha=190;
    for(auto const &arrow: eval.best_lines){
      std::string src=arrow.substr(0,2);
      std::string dst=arrow.substr(2,2);
      engine_arrows.push_back({src,dst,wxColour(6,57,112,alpha),scale});
      scale=std::max(0.1,scale-0.25);
      alpha=std::max(20,alpha-60);
    }
    eval_cp=eval.eval;
    Notify(true);
  }
}

void GameTabLeftPanel::SetLiveEngineState(bool isOn){
  is_engine_on=isOn;
  if(!is_engine_on){
    engine_arrows.clear();
    eval_cp=0;
    Notify(true);
  }
}


void GameTabLeftPanel::Notify(bool skip_animation) {
  // Update fen and captures
  std::string fen = game->GetFen();
  std::map<char, std::uint8_t> captures;
  bool animate=false;
  HalfMove *m = game->GetCurrentMove();
  std::string src,dst;
  // Update capture and check if we should to animations during moves change:
  if (m){
    captures = m->GetLineCaptures();
    if(m->HasParent(last_move) && !m->IsVariation()){
      m->GetAbsoluteMove(src,dst);
      animate=true;
    }else if(m->HasChild(last_move) && !last_move->IsVariation()){ // call to IsVariation is safe because of HasChild() before! cf below
      // Accessing last_move here is safe since it is still
      // in the tree of moves (since HasChild found it so not deleted)
      last_move->GetAbsoluteMove(dst,src);
      animate=true;
    }
  } else if(game->GetNextMove()){ // First move animation
    HalfMove *next=game->GetNextMove();
    if(next==last_move){
      game->GetNextMove()->GetAbsoluteMove(dst,src);
      animate=true;
    }
  }

  // Update board canvas:
  GameState gs;
  gs.board=chessarbiter::FENParser::Parse(fen).board;
  gs.is_black_turn=game->IsBlackToPlay();
  gs.captures=captures;
  gs.white=game->GetTag("White");
  gs.black=game->GetTag("Black");
  gs.mat_black=game->IsCheckmate(true);
  gs.mat_white=game->IsCheckmate(false);
  gs.arrows=engine_arrows;
  gs.promotion=promote_on;
  gs.show_evalbar=is_engine_on;
  gs.eval=eval_cp/100;
  if(m){
    // There should be a valid src_hl or dst_hl ortherwise it explode:
    std::string src_hl, dst_hl;
    m->GetAbsoluteMove(src_hl,dst_hl);
    if(src_hl.size()>0){ // Just in case
      gs.squares_hl.push_back({src_hl,wxColour(255,190,190)});
      gs.squares_hl.push_back({dst_hl,wxColour(255,100,100)});
    }
  }
  if(skip_animation || !animate){
    board_canvas->SetupBoard(gs);
  }
  else{
    board_canvas->Animate(gs, src,dst,repeat);
  }
  // Update last move
  last_move=m;
  // Update fen field:
  fen_text_field->SetValue(game->GetFen());
}

void GameTabLeftPanel::ApplyPreferences() { board_canvas->ApplyPreferences(); }