Integrate CMI

This commit is contained in:
Loic Guegan 2023-01-19 13:06:36 +01:00
parent 5e18d43a6b
commit a84b210ca3
15 changed files with 194 additions and 286 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "libs/chess-move-interface"]
path = libs/chess-move-interface
url = git@gitlab.com:manzerbredes/chess-move-interface.git

View file

@ -18,6 +18,10 @@ include_directories(src)
file(GLOB_RECURSE SRC_CPP_FILES src/*.cpp)
add_library(cgeditor SHARED ${SRC_CPP_FILES})
# ChessMoveInterface
add_subdirectory(libs/chess-move-interface)
include_directories(${CMI_INCLUDE_DIR})
# Examples
set(COMPILE_EXAMPLES FALSE CACHE BOOL "Compiling included examples")
if(COMPILE_EXAMPLES)

View file

@ -4,3 +4,5 @@ find_package(wxWidgets COMPONENTS core base REQUIRED)
include(${wxWidgets_USE_FILE})
add_executable(wxwidgets_example main.cpp MyHalfMove.cpp)
target_link_libraries(wxwidgets_example cgeditor ${wxWidgets_LIBRARIES})
target_link_libraries(wxwidgets_example ChessMoveInterface)

View file

@ -1,114 +1,6 @@
#include "MyHalfMove.hpp"
MyHalfMove::MyHalfMove(std::string move) { this->move = move; }
MyHalfMove::~MyHalfMove() {}
void MyHalfMove::AddVariation(MyHalfMove *m) {
m->IsBlack = this->IsBlack;
m->Number = this->Number;
MyHalfMove::variations.push_back(m);
cgeditor::CGEHalfMove::variations.push_back(m);
m->SetParent(this);
}
void MyHalfMove::SetMainline(MyHalfMove *m) {
if (!this->IsBlack) {
m->IsBlack = true;
m->Number = this->Number;
} else {
m->IsBlack = false;
m->Number = this->Number + 1;
}
MyHalfMove::mainline = m;
cgeditor::CGEHalfMove::MainLine = m;
if (m != NULL) {
m->SetParent(this);
}
}
void MyHalfMove::SetParent(MyHalfMove *m) {
MyHalfMove::parent = m;
CGEHalfMove::Parent = m;
}
void MyHalfMove::RemoveChild(MyHalfMove *m) {
std::uint32_t i = 0;
bool found = false;
for (i; i < MyHalfMove::variations.size(); i++) {
if (MyHalfMove::variations[i] == m) {
found = true;
break;
}
}
if (found) {
MyHalfMove::variations.erase(MyHalfMove::variations.begin() + i);
}
if (MyHalfMove::MainLine == m) {
MyHalfMove::MainLine = NULL;
}
cgeditor::CGEHalfMove::RemoveChild((CGEHalfMove *)m);
}
MyHalfMove *MyHalfMove::GetParent() { return (parent); }
MyHalfMove *MyHalfMove::GetRoot() {
MyHalfMove *m = this;
MyHalfMove *p = MyHalfMove::parent;
while (p != NULL) {
if (p->mainline != m) {
return (m);
}
m = p;
p = m->MyHalfMove::parent;
}
return (m);
}
void MyHalfMove::SetAsMainline() {
MyHalfMove *root = GetRoot();
MyHalfMove *lastRoot;
do {
lastRoot = root;
root->MyHalfMove::Promote();
root = GetRoot();
} while (root != lastRoot);
// std::cout << IsVariation() << std::endl << std::flush;
}
void MyHalfMove::Promote() {
if (MyHalfMove::parent != NULL) {
MyHalfMove *p = MyHalfMove::parent;
if (p->MyHalfMove::mainline != this) {
if (MyHalfMove::parent->MyHalfMove::parent != NULL) {
MyHalfMove *pp = MyHalfMove::parent->MyHalfMove::parent;
if (pp->MyHalfMove::mainline == p) {
pp->MyHalfMove::SetMainline(this);
} else {
pp->AddVariation(this);
pp->MyHalfMove::RemoveChild(p);
}
}
if (p->MyHalfMove::mainline == this) {
p->MyHalfMove::SetMainline(NULL);
} else {
p->MyHalfMove::RemoveChild(this);
}
this->AddVariation(p);
}
}
}
bool MyHalfMove::IsVariation() {
MyHalfMove *m = this;
MyHalfMove *p = MyHalfMove::parent;
while (p != NULL) {
if (p->mainline != m) {
return (true);
}
m = p;
p = m->MyHalfMove::parent;
}
return (false);
}
MyHalfMove::MyHalfMove(std::string move){SetSAN(move); }
MyHalfMove *BuildExampleGame() {
MyHalfMove *m = new MyHalfMove("e4");
@ -128,7 +20,7 @@ MyHalfMove *BuildExampleGame() {
m2 = new MyHalfMove("Bc4");
m->SetMainline(m2);
m->comment="Italian Opening";
m->SetComment("Italian Opening");
m = m2;
m2 = new MyHalfMove("Bc5");
@ -136,7 +28,7 @@ MyHalfMove *BuildExampleGame() {
m = m2;
m2 = new MyHalfMove("c3");
m2->comment="Giuoco Pianissimo";
m2->SetComment("Giuoco Pianissimo");
m->SetMainline(m2);
m = m2;
@ -158,7 +50,7 @@ MyHalfMove *BuildExampleGame() {
{
MyHalfMove *var = new MyHalfMove("Re1");
var->comment="Also possible";
var->SetComment("Also possible");
m->AddVariation(var);
MyHalfMove *var2 = new MyHalfMove("a6");
@ -185,8 +77,8 @@ MyHalfMove *BuildExampleGame() {
m2 = new MyHalfMove("a6");
m->SetMainline(m2);
m->comment="Test for a very long comment, to see how line breaks are handle by the framework.";
m->comment+="Test for a very long comment, to see how line breaks are handle by the framework.";
m->SetComment("Test for a very long comment, to see how line breaks are handle by the framework.");
m->SetComment(m->GetComment()+"Test for a very long comment, to see how line breaks are handle by the framework.");
m = m2;
m2 = new MyHalfMove("Bb3");
@ -198,7 +90,7 @@ MyHalfMove *BuildExampleGame() {
m = m2;
m2 = new MyHalfMove("Re1");
m2->nag="!!";
m2->SetNAG(3);
m->SetMainline(m2);
m = m2;

View file

@ -1,5 +1,6 @@
#pragma once
#include "CGEditor.hpp"
#include <vector>
/**
* @brief Create your custom half move class
@ -8,32 +9,10 @@
* an overview of how to keep your move sync with the one of CGEditor
*
*/
class MyHalfMove : public cgeditor::CGEHalfMove {
MyHalfMove *parent = NULL;
MyHalfMove *mainline = NULL;
std::vector<MyHalfMove *> variations;
class MyHalfMove : public CMI::HalfMove {
public:
MyHalfMove(std::string move);
~MyHalfMove();
/// @brief Add variation to current move
void AddVariation(MyHalfMove *m);
/// @brief Remove the specified child from mainline and/or variations
void RemoveChild(MyHalfMove *m);
/// @brief Set value of the mailine
void SetMainline(MyHalfMove *m);
/// @brief Set this move as mainline
void SetAsMainline();
/// @brief Promote the current move and submove
void Promote();
/// @brief Check if current half move is within a variation
bool IsVariation();
/// @brief Get the root of a variation
MyHalfMove* GetRoot();
/// @brief Get parent of the current move
MyHalfMove* GetParent();
/// @brief Set parent of the current move
void SetParent(MyHalfMove *m);
};
/// @brief Build the example game to use in the editor

View file

@ -38,7 +38,7 @@ private:
CGEditor::status.CanvasWidth = sz.GetWidth();
CGEditor::status.CanvasHeight = sz.GetHeight();
CGEditor::status.UseMoveIcons =
true; // Piece image should be drawn before the move ?
false; // Piece image should be drawn before the move ?
const wxPoint pt = wxGetMousePosition();
CGEditor::status.MouseX = pt.x - this->GetScreenPosition().x;
@ -90,7 +90,7 @@ private:
e.y + (e.height - sz.GetHeight()) / 2));
}
/**
/**
* @brief CGEditor is going to call this method with the elements to draw on
* the canvas
*
@ -161,22 +161,27 @@ private:
str = "Comment Selected";
else if (e.type == cgeditor::Event::Type::Promote) {
str = "Promote";
static_cast<MyHalfMove *>(e.move)->MyHalfMove::Promote();
e.move->Promote();
SyncCache();
} else if (e.type == cgeditor::Event::Type::Delete) {
str = "Delete";
if (e.move->Parent != NULL) {
static_cast<MyHalfMove *>(e.move)->GetParent()->MyHalfMove::RemoveChild(
(MyHalfMove *)e.move);
if (e.move->GetParent() != nullptr) {
static_cast<MyHalfMove *>((e.move)->GetParent())->RemoveChild(static_cast<MyHalfMove *>(e.move));
delete static_cast<MyHalfMove *>(e.move);
SyncCache(); // Do not forget to sync the cache
} else {
CGEditor::status.Moves = NULL;
CGEditor::status.Moves = nullptr;
}
} else if (e.type == cgeditor::Event::Type::SetAsMainline) {
str = "Set as main line";
static_cast<MyHalfMove *>(e.move)->MyHalfMove::SetAsMainline();
e.move->SetAsMainline();
SyncCache();
} else if (e.type == cgeditor::Event::Type::Goto) {
str = "Goto move";
}
std::cout << "Event received: " << str << std::endl << std::flush;
wxLogDebug("Event received: %s", str);
if(CGEditor::status.Moves != nullptr && !CGEditor::status.Moves->IsConsistent())
wxLogError("ERROR!! The tree of moves is not consistent anymore! Something wrong happends");
}
// wxWidgets specific

@ -0,0 +1 @@
Subproject commit 720c394c50e7cb79e6403c408b40dfe8d994230a

View file

@ -1,43 +0,0 @@
#include "CGEHalfMove.hpp"
namespace cgeditor {
CGEHalfMove::CGEHalfMove()
: MainLine(NULL), IsBlack(false), Number(1), Parent(NULL) {}
CGEHalfMove::CGEHalfMove(CGEHalfMove *parent) {
CGEHalfMove();
Parent = parent;
Parent->MainLine = this;
if (parent->IsBlack) {
Number = parent->Number + 1;
IsBlack = false;
} else {
Number = parent->Number;
IsBlack = true;
}
}
CGEHalfMove::CGEHalfMove(const std::string &move)
: MainLine(NULL), IsBlack(false), Number(0), Parent(NULL) {
this->move = move;
}
void CGEHalfMove::RemoveChild(CGEHalfMove *m) {
std::uint32_t i = 0;
bool found = false;
for (i; i < variations.size(); i++) {
if (variations[i] == m) {
found = true;
break;
}
}
if (found) {
variations.erase(variations.begin() + i);
}
if (MainLine == m) {
MainLine = NULL;
}
}
} // namespace cgeditor

View file

@ -1,41 +0,0 @@
#pragma once
#include <string>
#include <vector>
namespace cgeditor {
/**
* @brief Move (mainlines and variations) displayed in the editor
*
*/
class CGEHalfMove {
public:
CGEHalfMove();
CGEHalfMove(CGEHalfMove *parent);
CGEHalfMove(const std::string &move);
/// @brief CUrrent move number
std::uint16_t Number;
/// @brief Current move value
std::string move;
/// @brief Current NAG
std::string nag;
/// @brief Comment linked to the move
std::string comment;
CGEHalfMove *MainLine;
CGEHalfMove *Parent;
bool IsBlack;
/// @brief Says if variations of that move must be drawn
bool Folded = false;
/// @brief Says if this move must be drawn
bool Hide = false;
/// @brief Variations of the move
std::vector<CGEHalfMove *> variations;
/// @brief Remove a move from the MainLine and/or variations
void RemoveChild(CGEHalfMove *m);
};
} // namespace cgeditor

View file

@ -8,6 +8,58 @@ CGEditor::CGEditor() {
MT = new MoveTable(&status);
MA = new Margin(&status);
ME = new Menu(&status);
// Default Standard NagTable: https://en.wikipedia.org/wiki/Numeric_Annotation_Glyphs
status.NagTable[0]="";
status.NagTable[1]="!";
status.NagTable[2]="?";
status.NagTable[3]="!!";
status.NagTable[4]="??";
status.NagTable[5]="!?";
status.NagTable[6]="?!";
status.NagTable[7]="";
status.NagTable[10]="=";
status.NagTable[13]="";
status.NagTable[14]="";
status.NagTable[15]="";
status.NagTable[16]="±";
status.NagTable[17]="";
status.NagTable[18]="+-";
status.NagTable[19]="-+";
status.NagTable[22]="";
status.NagTable[23]="";
status.NagTable[26]="";
status.NagTable[27]="";
status.NagTable[32]="";
status.NagTable[33]="";
status.NagTable[36]="";
status.NagTable[37]="";
status.NagTable[40]="";
status.NagTable[41]="";
status.NagTable[44]="";
status.NagTable[45]="";
status.NagTable[132]="";
status.NagTable[133]="";
status.NagTable[138]="";
status.NagTable[139]="";
// Default Non-Standard NagTable: https://en.wikipedia.org/wiki/Numeric_Annotation_Glyphs
status.NagTable[140]="";
status.NagTable[141]="";
status.NagTable[142]="";
status.NagTable[143]="<=";
status.NagTable[144]="==";
status.NagTable[145]="RR";
status.NagTable[146]="N";
status.NagTable[220]="";
status.NagTable[221]="";
status.NagTable[238]="";
status.NagTable[239]="";
status.NagTable[240]="";
status.NagTable[241]="";
status.NagTable[242]="";
status.NagTable[243]="";
status.NagTable[244]="";
status.NagTable[245]="";
status.NagTable[254]="";
}
CGEditor::~CGEditor() {
@ -86,6 +138,15 @@ void CGEditor::CallDrawElement(Element e) {
DrawElement(e);
}
void CGEditor::SyncCache(){
MA->SyncCache();
MT->SyncCache();
MA->SyncCache();
SBV->SyncCache();
SBH->SyncCache();
ME->SyncCache();
}
void CGEditor::DrawComponent(Component *c) {
for (Element &e : c->GetElements()) {
CallDrawElement(e);
@ -103,4 +164,20 @@ bool CGEditor::ProcessEvents(){
return processed;
}
} // namespace cgeditor
std::string CGEditor::GetNAGSymbol(const std::uint8_t id) const{
for(auto const& pair: status.NagTable){
if(pair.first == id)
return pair.second;
}
return "";
}
std::uint8_t CGEditor::GetNAGId(const std::string& symbol) const{
for(auto const& pair: status.NagTable){
if(pair.second == symbol)
return pair.first;
}
return 0;
}
} // namespace cgeditor

View file

@ -27,11 +27,16 @@ protected:
void Draw();
/// @brief Process the events generated during the drawing
bool ProcessEvents();
/// @brief Synchronize the editor cache (must be called when game was modified from outside the editor)
void SyncCache();
/// @brief Draw an element on the canvas
virtual void DrawElement(const Element &) = 0;
/// @brief Handle event that occured during editor drawing
virtual void HandleEvent(const Event &) = 0;
/// @brief Convert NAG id to symbol using the NagTable
std::string GetNAGSymbol(const std::uint8_t) const;
/// @brief Convert NAG symbol to id using the NagTable
std::uint8_t GetNAGId(const std::string&) const;
public:
CGEditor();
~CGEditor();

View file

@ -1,7 +1,8 @@
#pragma once
#include "CGEHalfMove.hpp"
#include "CMI.hpp"
#include <string>
#include <unordered_map>
namespace cgeditor {
@ -54,7 +55,7 @@ typedef struct Event {
enum Type { CommentSelected, Promote, Delete, SetAsMainline, Goto, None };
Type type = None;
/// @brief Move related to the event
CGEHalfMove *move = NULL;
CMI::HalfMove *move = nullptr;
} Event;
/**
@ -92,10 +93,11 @@ typedef struct Status {
double MoveTableMaxX = 0, MoveTableMaxY = 0;
/// @brief User should set it to true when mouse is dragging
bool IsDrag = false;
CGEHalfMove *Moves = NULL;
CGEHalfMove *CurrentMove = NULL;
CGEHalfMove *SelectedMove = NULL;
CMI::HalfMove *Moves = nullptr;
CMI::HalfMove *CurrentMove = nullptr;
CMI::HalfMove *SelectedMove = nullptr;
std::vector<Event> Events;
std::unordered_map<std::uint8_t, std::string> NagTable;
} Status;
} // namespace cgeditor

View file

@ -14,6 +14,7 @@ public:
Component(Status *s) : status(s){};
std::vector<Element> GetElements() { return (this->elements); }
virtual void Refresh() = 0;
virtual void SyncCache() {};
};
} // namespace cgeditor

View file

@ -1,5 +1,4 @@
#include "MoveTable.hpp"
#include <iostream>
namespace cgeditor {
@ -11,8 +10,8 @@ void MoveTable::Refresh() {
elements.clear();
VariationMargins.clear();
CurrentMove = -1; // No current move by default
if (status->Moves != NULL) {
UpdateMoves(status->Moves, 0, 0, status->Moves->IsBlack);
if (status->Moves != nullptr) {
UpdateMoves(status->Moves, 0, 0, status->Moves->IsBlack());
// We only set the type after the call to UpdateMoves()
// This way only a single move will be the current move
if (CurrentMove >= 0) {
@ -46,19 +45,19 @@ bool MoveTable::IsMouseOver(const Element &e) const {
status->MouseY - status->ScrollY));
}
std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
std::uint32_t MoveTable::UpdateMoves(CMI::HalfMove *m, std::uint32_t line,
std::uint32_t indent, bool only_black) {
//---------- Check black or white ----------
char indent_black = 0;
if (m->IsBlack) {
if (m->IsBlack()) {
indent_black++;
}
//---------- Create temporary move surrounding area ----------
Element move_bound;
move_bound.prop = Property::Move;
if (m->IsBlack) {
if (m->IsBlack()) {
move_bound.prop |= Property::Black;
}
move_bound.x = status->MarginBarWidth +
@ -67,7 +66,7 @@ std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
move_bound.y = status->MoveHeight * line;
move_bound.width = status->MoveWidth;
move_bound.height = status->MoveHeight;
move_bound.text = m->move;
move_bound.text = m->GetSAN();
move_bound.ShouldApplyScroll = true;
bool isMouseOver = IsMouseOver(move_bound);
@ -102,12 +101,12 @@ std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
// Move
Element e;
e.prop = move_bound.prop | Property::Text;
e.text = m->move;
if (m->move.size() > 0) {
char c = m->move[0];
e.text = m->GetSAN();
if (m->GetSAN().size() > 0) {
char c = m->GetSAN()[0];
if (!(c == 'a' || c == 'b' || c == 'c' || c == 'd' || c == 'e' ||
c == 'f' || c == 'g' || c == 'h' || c == 'O' || c == '0')) {
e.text = m->move.substr(1, m->move.size());
e.text = m->GetSAN().substr(1, m->GetSAN().size());
if (c == 'N') {
img.prop |= Property::Knight;
} else if (c == 'B') {
@ -137,9 +136,9 @@ std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
}
//---------- NAG ----------
if(m->nag.size()>0){
if(m->GetNAG()>0){
Element nag;
nag.text = m->nag;
nag.text = status->NagTable[m->GetNAG()];
nag.x = move_bound.x + status->MoveWidth - status->NagWidth - status->NagRightMargin;
nag.y = status->MoveHeight * line;
nag.width = status->NagWidth;
@ -150,15 +149,15 @@ std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
}
//---------- Move number in marge or for variation ----------
if (indent == 0 && (!m->IsBlack || only_black)) {
DRAW_NB(0, status->MoveHeight * line, m->Number);
} else if (indent > 0 && (!m->IsBlack || only_black)) {
if (indent == 0 && (!m->IsBlack() || only_black)) {
DRAW_NB(0, status->MoveHeight * line, m->GetNumber());
} else if (indent > 0 && (!m->IsBlack() || only_black)) {
if (only_black) {
DRAW_NB_VAR((move_bound.x - status->MoveWidth) - status->MarginBarWidth,
status->MoveHeight * line, m->Number);
status->MoveHeight * line, m->GetNumber());
} else {
DRAW_NB_VAR(move_bound.x - ((indent + 1) / 2 * status->MarginBarWidth),
status->MoveHeight * line, m->Number);
status->MoveHeight * line, m->GetNumber());
}
}
@ -176,35 +175,50 @@ std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
}
//---------- Comments ----------
if (m->comment.size() > 0) {
if (m->GetComment().size() > 0) {
line = DrawComment(m, line, indent, move_bound, indent_black);
}
//---------- Variations ----------
if (m->variations.size() > 0) {
if (m->GetVariations().size() > 0) {
line = DrawVariations(m, line, indent, move_bound, indent_black);
}
//---------- Mainline ----------
if (m->MainLine != NULL) {
only_black = (m->MainLine->IsBlack &&
(m->comment.size() > 0 || m->variations.size()));
if (m->IsBlack) {
line = UpdateMoves(m->MainLine, line + 1, indent, only_black);
if (m->GetMainline() != nullptr) {
only_black = (m->GetMainline()->IsBlack() &&
(m->GetComment().size() > 0 || m->GetVariations().size()));
if (m->IsBlack()) {
line = UpdateMoves(m->GetMainline(), line + 1, indent, only_black);
} else {
line = UpdateMoves(m->MainLine, line, indent, only_black);
line = UpdateMoves(m->GetMainline(), line, indent, only_black);
}
}
return (line);
}
std::uint32_t MoveTable::DrawComment(CGEHalfMove *m, std::uint32_t line,
void MoveTable::SyncCache(){
if(status->Moves != nullptr){
std::vector<CMI::HalfMove*> toDelete;
for (auto const& entry : MovesStates){
if(!status->Moves->Contains(entry.first))
toDelete.push_back(entry.first);
}
for(auto key: toDelete){
MovesStates.erase(key);
}
}
else
MovesStates.clear();
}
std::uint32_t MoveTable::DrawComment(CMI::HalfMove *m, std::uint32_t line,
std::uint32_t indent,
const Element &move_bound,
const char &indent_black) {
// Show three dots
if (!m->IsBlack) {
if (!m->IsBlack()) {
DRAW_DOTS(status->MarginBarWidth + status->MoveWidth * (indent + 1) +
((indent + 1) / 2 * status->MarginBarWidth),
status->MoveHeight * line);
@ -212,7 +226,7 @@ std::uint32_t MoveTable::DrawComment(CGEHalfMove *m, std::uint32_t line,
line++; // Goto the right line
/// ----- Compute comment bounding box values:
int nchar=m->comment.size();
int nchar=m->GetComment().size();
int nline=ceil((double)nchar/(double)status->CommentCharPerLine);
std::uint16_t nrow=ceil(((nline*status->CommentCharHeight)+2*status->CommentPadding)/status->MoveHeight);
int width=status->CommentCharPerLine*status->CommentCharWidth+2*status->CommentPadding;
@ -249,7 +263,7 @@ std::uint32_t MoveTable::DrawComment(CGEHalfMove *m, std::uint32_t line,
l.height=status->CommentCharHeight;
l.ShouldApplyScroll = true;
for(int i=0;i<nline;i++){
l.text=m->comment.substr(i*status->CommentCharPerLine,status->CommentCharPerLine);
l.text=m->GetComment().substr(i*status->CommentCharPerLine,status->CommentCharPerLine);
// Remove leading space:
if(l.text.size()>2 && l.text[0]==' '){
l.text=l.text.substr(1,l.text.size());
@ -264,18 +278,18 @@ std::uint32_t MoveTable::DrawComment(CGEHalfMove *m, std::uint32_t line,
}
line += nrow; // Skip right amount of lines
// ----- Since we already increment line for black later on:
if (m->IsBlack || m->variations.size() > 0) {
if (m->IsBlack() || m->GetVariations().size() > 0) {
line--;
}
return (line);
}
std::uint32_t MoveTable::DrawVariations(CGEHalfMove *m, std::uint32_t line,
std::uint32_t MoveTable::DrawVariations(CMI::HalfMove *m, std::uint32_t line,
std::uint32_t indent,
const Element &move_bound,
const char &indent_black) {
// Show three dots next to move if white turn
if ((m->variations.size() == 0) && !m->IsBlack) {
if ((m->GetVariations().size() == 0) && !m->IsBlack()) {
DRAW_DOTS(status->MarginBarWidth + status->MoveWidth * (indent + 1),
status->MoveHeight * line);
}
@ -284,22 +298,22 @@ std::uint32_t MoveTable::DrawVariations(CGEHalfMove *m, std::uint32_t line,
Element e;
e.prop = Property::Rectangle | Property::Button;
e.x = move_bound.x + status->MoveWidth;
if (!m->IsBlack)
if (!m->IsBlack())
e.x += status->MoveWidth;
e.y = move_bound.y + std::ceil(status->MoveHeight / 4);
e.width = std::ceil(status->MoveHeight / 2);
e.height = e.width;
e.ShouldApplyScroll = true;
if (status->LeftClick && IsMouseOver(e)) {
m->Folded = !m->Folded;
MovesStates[m].IsFolded=!MovesStates[m].IsFolded;
}
if (!m->Folded) {
if (!MovesStates[m].IsFolded) {
e.prop |= Property::On;
}
elements.push_back(e);
}
if (!m->Folded) {
for (CGEHalfMove *v : m->variations) {
if (!MovesStates[m].IsFolded) {
for (CMI::HalfMove *v : m->GetVariations()) {
// For each variation show show/hide button
{
Element e;
@ -313,22 +327,22 @@ std::uint32_t MoveTable::DrawVariations(CGEHalfMove *m, std::uint32_t line,
e.height = e.width;
e.ShouldApplyScroll = true;
if (status->LeftClick && IsMouseOver(e)) {
v->Hide = !v->Hide;
MovesStates[v].IsHidden = !MovesStates[v].IsHidden;
}
if (!v->Hide) {
if (!MovesStates[v].IsHidden) {
e.prop |= Property::On;
}
elements.push_back(e);
}
if (!v->Hide) {
line = UpdateMoves(v, line + 1, indent + 1, v->IsBlack);
if (!MovesStates[v].IsHidden) {
line = UpdateMoves(v, line + 1, indent + 1, v->IsBlack());
} else {
line++;
}
}
}
// New line after variation
if (m->MainLine != NULL && m->MainLine->IsBlack) {
if (m->GetMainline() != nullptr && m->GetMainline()->IsBlack()) {
line++;
}
return (line);

View file

@ -1,5 +1,6 @@
#include "Component.hpp"
#include <cmath>
#include <unordered_map>
#define IS_VISIBLE(e) \
(((e.x + status->ScrollX) >= 0 && \
@ -46,19 +47,25 @@
namespace cgeditor {
class MoveTable : public Component {
std::uint32_t UpdateMoves(CGEHalfMove *, std::uint32_t, std::uint32_t,bool only_black);
typedef struct MoveState {
bool IsFolded=false;
bool IsHidden=false;
} MoveState;
std::uint32_t UpdateMoves(CMI::HalfMove *, std::uint32_t, std::uint32_t,bool only_black);
std::int32_t CurrentMove;
std::vector<Element> VariationMargins;
/// @brief Must be kept consistent:
std::unordered_map<CMI::HalfMove*,MoveState> MovesStates;
bool IsMouseOver(const Element &e) const;
std::uint32_t DrawComment(CGEHalfMove *m, std::uint32_t line, std::uint32_t indent,
std::uint32_t DrawComment(CMI::HalfMove *m, std::uint32_t line, std::uint32_t indent,
const Element &move_bound, const char &indent_black);
std::uint32_t DrawVariations(CGEHalfMove *m, std::uint32_t line, std::uint32_t indent,
std::uint32_t DrawVariations(CMI::HalfMove *m, std::uint32_t line, std::uint32_t indent,
const Element &move_bound,
const char &indent_black);
public:
MoveTable(Status *s);
void Refresh();
std::vector<Element> GetVariationsMarging() { return (VariationMargins); }
void SyncCache();
};
} // namespace cgeditor