Create project

This commit is contained in:
Loic Guegan 2022-02-12 19:13:34 +01:00
commit a359219e33
24 changed files with 2152 additions and 0 deletions

View file

@ -0,0 +1,19 @@
#pragma once
#include "Types.hpp"
#include <vector>
namespace cgeditor {
class Component {
protected:
Status *status;
std::vector<Element> elements;
public:
Component(Status *s) : status(s){};
std::vector<Element> GetElements() { return (this->elements); }
virtual void Refresh() = 0;
};
} // namespace cgeditor

30
src/components/Margin.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "Margin.hpp"
namespace cgeditor {
Margin::Margin(Status *s) : Component(s) {}
void Margin::Refresh() {
elements.clear();
Element e;
e.x = 0;
e.y = 0;
e.height = status->CanvasHeight - status->ScrollbarWidth;
e.ShouldApplyScroll = true;
e.IgnoreScrollY = true;
DrawMargin(e);
}
void Margin::DrawMargin(Element e) {
e.prop=Property::Margin | Property::Rectangle;
e.width = status->MarginBarWidth;
elements.push_back(e);
}
void Margin::DrawMargin(std::vector<Element> elts) {
for(Element &e:elts){
DrawMargin(e);
}
}
} // namespace cgeditor

12
src/components/Margin.hpp Normal file
View file

@ -0,0 +1,12 @@
#include "Component.hpp"
namespace cgeditor {
class Margin : public Component {
public:
Margin(Status *s);
void Refresh();
void DrawMargin(Element e);
void DrawMargin(std::vector<Element> elts);
};
} // namespace cgeditor

64
src/components/Menu.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "Menu.hpp"
namespace cgeditor {
Menu::Menu(Status *s) : Component(s), WasOpen(false) {
entries.push_back("Delete from here");
entries.push_back("Promote");
entries.push_back("Set as main line");
}
void Menu::Refresh() {
if (WasOpen && (status->LeftClick || status->RightClick)) {
char i = 0;
for (Element &e : elements) {
if (e.IsOver(status->MouseX, status->MouseY)) {
if (i == 0) {
status->Events.push_back({Event::Type::Delete,status->SelectedMove});
} else if (i == 1) {
status->Events.push_back({Event::Type::Promote,status->SelectedMove});
} else if (i == 2) {
status->Events.push_back({Event::Type::SetAsMainline,status->SelectedMove});
}
}
i++;
}
status->IsMenuOpen = false;
WasOpen = false;
elements.clear();
return;
}
elements.clear();
// Draw menu backward to avoid getting out of the canvas
bool backwardY =
(status->MouseY + status->MenuItemHeight * entries.size()) >=
status->CanvasHeight;
bool backwardX =
(status->MouseX + status->MenuItemWidth) >= status->CanvasWidth;
if (status->IsMenuOpen) {
char i = 0;
for (std::string &en : entries) {
Element e;
e.prop=Property::Text|Property::Menuitem;
e.text = en;
if (backwardX) {
e.x = (status->MouseX - status->MenuItemWidth);
} else {
e.x = status->MouseX;
}
if (backwardY) {
e.y = (status->MouseY - status->MenuItemHeight) -
i * status->MenuItemHeight;
} else {
e.y = status->MouseY + i * status->MenuItemHeight;
}
e.width = status->MenuItemWidth;
e.height = status->MenuItemHeight;
elements.push_back(e);
i++;
}
WasOpen = true;
}
}
} // namespace cgeditor

12
src/components/Menu.hpp Normal file
View file

@ -0,0 +1,12 @@
#include "Component.hpp"
namespace cgeditor {
class Menu : public Component {
std::vector<std::string> entries;
/// @brief Set to true if the menu was open during the last editor draw
bool WasOpen;
public:
Menu(Status *s);
void Refresh();
};
} // namespace cgeditor

View file

@ -0,0 +1,280 @@
#include "MoveTable.hpp"
namespace cgeditor {
MoveTable::MoveTable(Status *s) : Component(s) {
ImageWidth = status->MoveWidth * 0.25; // Image is 25% of the cell
}
void MoveTable::Refresh() {
status->MoveTableMaxX = 0;
status->MoveTableMaxY = 0;
elements.clear();
VariationMargins.clear();
CurrentMove = -1; // No current move by default
if (status->Moves != NULL) {
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) {
if (status->UseMoveImages) {
elements[CurrentMove].prop |= Property::Current;
elements[CurrentMove + 1].prop |= Property::Current;
} else {
elements[CurrentMove].prop |= Property::Current;
}
}
} else {
Element e;
e.prop = Property::Text;
e.text = "No move to show";
e.x = status->MarginBarWidth;
e.y = 0;
e.height = status->MoveHeight;
e.width = -1;
elements.push_back(e);
}
}
bool MoveTable::IsMouseOver(const Element &e) const {
// Check if we clicked on scroll bars
if (status->IsMenuOpen ||
status->MouseX >= (status->CanvasWidth - status->ScrollbarWidth) ||
status->MouseY >= (status->CanvasHeight - status->ScrollbarWidth)) {
return (false);
}
return (e.IsOver(status->MouseX - status->ScrollX,
status->MouseY - status->ScrollY));
}
std::uint32_t MoveTable::UpdateMoves(CGEHalfMove *m, std::uint32_t line,
std::uint32_t indent, bool only_black) {
//---------- Check black or white ----------
char indent_black = 0;
if (m->IsBlack) {
indent_black++;
}
//---------- Create temporary move surrounding area ----------
Element move_bound;
move_bound.prop = Property::Move;
if (m->IsBlack) {
move_bound.prop |= Property::Black;
}
move_bound.x = status->MarginBarWidth + status->MoveX +
status->MoveWidth * (indent + indent_black) +
((indent + 1) / 2 * status->MarginBarWidth);
move_bound.y = status->MoveHeight * line;
move_bound.width = status->MoveWidth;
move_bound.height = status->MoveHeight;
move_bound.text = m->move;
move_bound.ShouldApplyScroll = true;
bool isMouseOver = IsMouseOver(move_bound);
//---------- Update current focus move ----------
if (isMouseOver) {
if (status->LeftClick) {
if (!status->IsMenuOpen) {
status->Events.push_back({Event::Type::Goto, m});
status->CurrentMove = m;
}
} else if (status->RightClick) {
status->IsMenuOpen = true;
status->SelectedMove = m;
}
}
//---------- Check if current move is focused ----------
if (status->CurrentMove == m) {
CurrentMove = elements.size();
}
//---------- Draw move ----------
if (status->UseMoveImages) {
// Image
Element img;
img.prop = Property::Image | Property::Move;
img.x = move_bound.x;
img.y = status->MoveHeight * line;
img.width = ImageWidth;
img.height = status->MoveHeight;
img.ShouldApplyScroll = true;
elements.push_back(img);
// Move
Element e;
e.prop = move_bound.prop | Property::Text;
e.text = m->move;
e.x = ImageWidth + move_bound.x;
e.y = status->MoveHeight * line;
e.width = status->MoveWidth - ImageWidth;
e.height = status->MoveHeight;
e.ShouldApplyScroll = true;
elements.push_back(e);
} else {
move_bound.prop |= Property::Text;
elements.push_back(move_bound);
}
//---------- 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 (only_black) {
DRAW_NB_VAR((move_bound.x - status->MoveWidth) - status->MarginBarWidth,
status->MoveHeight * line, m->Number);
} else {
DRAW_NB_VAR(move_bound.x - ((indent + 1) / 2 * status->MarginBarWidth),
status->MoveHeight * line, m->Number);
}
}
//---------- Draw dots ----------
if (only_black) {
DRAW_DOTS(move_bound.x - status->MoveWidth, move_bound.y);
}
//---------- Scrolling infos ----------
if ((move_bound.x + move_bound.width) > status->MoveTableMaxX) {
status->MoveTableMaxX = move_bound.x + move_bound.width;
}
if ((move_bound.y + move_bound.height) > status->MoveTableMaxY) {
status->MoveTableMaxY = move_bound.y + move_bound.height;
}
//---------- Comments ----------
if (m->GetNbLineComment() > 0) {
line = DrawComment(m, line, indent, move_bound, indent_black);
}
//---------- Variations ----------
if (m->variations.size() > 0) {
line = DrawVariations(m, line, indent, move_bound, indent_black);
}
//---------- Mainline ----------
if (m->MainLine != NULL) {
only_black = (m->MainLine->IsBlack &&
(m->GetNbLineComment() > 0 || m->variations.size()));
if (m->IsBlack) {
line = UpdateMoves(m->MainLine, line + 1, indent, only_black);
} else {
line = UpdateMoves(m->MainLine, line, indent, only_black);
}
}
return (line);
}
std::uint32_t MoveTable::DrawComment(CGEHalfMove *m, std::uint32_t line,
std::uint32_t indent,
const Element &move_bound,
const char &indent_black) {
// Show three dots
if (!m->IsBlack) {
DRAW_DOTS(status->MarginBarWidth + status->MoveX +
status->MoveWidth * (indent + 1) +
((indent + 1) / 2 * status->MarginBarWidth),
status->MoveHeight * line);
}
// Print comment
line++;
// Computer number of rows for the comment
std::uint16_t CommentRows = m->GetNbLineComment() / status->CommentLinePerRow;
if (m->GetNbLineComment() % status->CommentLinePerRow > 0) {
CommentRows++;
}
// Draw comment
Element e;
e.prop = Property::Text | Property::Comment;
e.x = move_bound.x -
(indent_black *
status->MoveWidth); // status->MarginBarWidth + status->MoveX;
e.y = status->MoveHeight * line;
e.width = -1; // Negative width means expands to the edge of the canvas
e.height = CommentRows * status->MoveHeight;
e.text = m->GetComment();
e.ShouldApplyScroll = true;
elements.push_back(e);
// Do not forget to add marging before comment
if (indent > 0) {
e.x -= status->MarginBarWidth;
VariationMargins.push_back(e);
}
if (status->LeftClick && IsMouseOver(e)) {
status->Events.push_back({Event::Type::CommentSelected, m});
}
line += CommentRows; // Skip right amount of lines
// Since we already increment line for black later on:
if (m->IsBlack || m->variations.size() > 0) {
line--;
}
return (line);
}
std::uint32_t MoveTable::DrawVariations(CGEHalfMove *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) {
DRAW_DOTS(status->MarginBarWidth + status->MoveX +
status->MoveWidth * (indent + 1),
status->MoveHeight * line);
}
// Show button on the right side of the move
{
Element e;
e.prop = Property::Rectangle | Property::Button;
e.x = move_bound.x + status->MoveWidth;
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;
}
if (!m->Folded) {
e.prop |= Property::On;
}
elements.push_back(e);
}
if (!m->Folded) {
for (CGEHalfMove *v : m->variations) {
// For each variation show show/hide button
{
Element e;
e.prop = Property::Rectangle | Property::Button;
e.x = (status->MarginBarWidth + status->MoveX +
status->MoveWidth * indent) +
status->MoveWidth - std::ceil(status->MoveHeight / 2) -
std::ceil(status->MoveHeight / 4);
e.y = (status->MoveHeight * (line + 1)) +
std::ceil(status->MoveHeight / 4);
e.width = std::ceil(status->MoveHeight / 2);
e.height = e.width;
e.ShouldApplyScroll = true;
if (status->LeftClick && IsMouseOver(e)) {
v->Hide = !v->Hide;
}
if (!v->Hide) {
e.prop |= Property::On;
}
elements.push_back(e);
}
if (!v->Hide) {
line = UpdateMoves(v, line + 1, indent + 1, v->IsBlack);
} else {
line++;
}
}
}
// New line after variation
if (m->MainLine != NULL && m->MainLine->IsBlack) {
line++;
}
return (line);
}
} // namespace cgeditor

View file

@ -0,0 +1,65 @@
#include "Component.hpp"
#include <cmath>
#define IS_VISIBLE(e) \
(((e.x + status->ScrollX) >= 0 && \
((e.x + status->ScrollX) <= status->CanvasWidth) && \
(e.y + status->ScrollY) >= 0 && \
((e.y + status->ScrollY) <= status->CanvasHeight)) || \
((e.x + e.width + status->ScrollX) >= 0 && \
((e.x + e.width + status->ScrollX) <= status->CanvasWidth) && \
(e.y + e.height + status->ScrollY) >= 0 && \
((e.y + e.height + status->ScrollY) <= status->CanvasHeight)))
#define DRAW_DOTS(XX, YY) \
{ \
Element e; \
e.prop = Property::Text | Property::Dots; \
e.x = (XX); \
e.y = (YY); \
e.width = status->MoveWidth; \
e.height = status->MoveHeight; \
e.text = "..."; \
e.ShouldApplyScroll = true; \
elements.push_back(e); \
}
#define DRAW_NB_(XX, YY, NB) \
Element ln; \
ln.prop = Property::Text | Property::Movenumber; \
ln.text = std::to_string(NB); \
ln.x = (XX); \
ln.y = (YY); \
ln.width = status->MarginBarWidth; \
ln.height = status->MoveHeight; \
ln.ShouldApplyScroll = true; \
elements.push_back(ln);
#define DRAW_NB(XX, YY, NB) \
{ DRAW_NB_(XX, YY, NB); }
#define DRAW_NB_VAR(XX, YY, NB) \
{ \
DRAW_NB_(XX, YY, NB); \
VariationMargins.push_back(ln); \
}
namespace cgeditor {
class MoveTable : public Component {
std::uint32_t UpdateMoves(CGEHalfMove *, std::uint32_t, std::uint32_t,bool only_black);
std::int32_t CurrentMove;
double ImageWidth;
std::vector<Element> VariationMargins;
bool IsMouseOver(const Element &e) const;
std::uint32_t DrawComment(CGEHalfMove *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,
const Element &move_bound,
const char &indent_black);
public:
MoveTable(Status *s);
void Refresh();
std::vector<Element> GetVariationsMarging() { return (VariationMargins); }
};
} // namespace cgeditor

View file

@ -0,0 +1,112 @@
#include "Scrollbar.hpp"
namespace cgeditor {
Scrollbar::Scrollbar(Status *s, bool IsHorizontal) : Component(s) {
this->IsHorizontal = IsHorizontal;
bg.prop = Property::Rectangle | Property::Scrollbarbg;
bar.prop = Property::Rectangle | Property::Scrollbar;
if (IsHorizontal) {
bg.prop |= Property::Horizontal;
bar.x = 0;
} else {
bar.y = 0;
}
DragX = 0;
DragY = 0;
Trigger = false;
}
void Scrollbar::Refresh() {
if (IsHorizontal) {
bg.y = status->CanvasHeight - status->ScrollbarWidth;
bg.width = status->CanvasWidth - status->ScrollbarWidth;
bg.height = status->ScrollbarWidth;
bar.y = bg.y;
} else {
bg.x = status->CanvasWidth - status->ScrollbarWidth;
bg.width = status->CanvasWidth;
bg.height = status->CanvasHeight - status->ScrollbarWidth;
bar.x = bg.x;
}
bar.width = bg.width;
bar.height = bg.height;
// Compute move table canvas
double MTCanvasHeight = status->CanvasHeight - status->ScrollbarWidth;
double MTCanvasWidth = status->CanvasWidth - status->ScrollbarWidth;
bool shouldScroll = false;
if (!IsHorizontal && status->MoveTableMaxY > MTCanvasHeight) {
bar.height =
std::ceil(bg.height * (MTCanvasHeight / status->MoveTableMaxY));
shouldScroll = true;
}
if (IsHorizontal && status->MoveTableMaxX > MTCanvasWidth) {
bar.width = std::ceil(bg.width * (MTCanvasWidth / status->MoveTableMaxX));
shouldScroll = true;
}
if (shouldScroll) {
if (IsHorizontal && status->EventHScroll != 0) {
double percent = status->EventHScroll / status->MoveTableMaxX;
double maxScroll = bg.width - bar.width;
bar.x += maxScroll * percent;
bar.x = std::max(bg.x, bar.x);
bar.x = std::min(bg.x + maxScroll, bar.x);
double curScroll = bar.x - bg.x;
double scrollPercent = curScroll / maxScroll;
status->ScrollX =
-(status->MoveTableMaxX - MTCanvasWidth) * scrollPercent;
status->EventHScroll = 0;
} else if (status->EventVScroll != 0) {
double percent = status->EventVScroll / status->MoveTableMaxY;
double maxScroll = bg.height - bar.height;
bar.y += maxScroll * percent;
bar.y = std::max(bg.y, bar.y);
bar.y = std::min(bg.y + maxScroll, bar.y);
double curScroll = bar.y - bg.y;
double scrollPercent = curScroll / maxScroll;
status->ScrollY =
-(status->MoveTableMaxY - MTCanvasHeight) * scrollPercent;
status->EventVScroll = 0;
} else if (status->LeftClick &&
bar.IsOver(status->MouseX, status->MouseY)) {
DragX = bar.x;
DragY = bar.y;
Trigger = true;
} else if (Trigger && status->IsDrag) {
if (IsHorizontal) {
bar.x = DragX + (status->MouseX - status->LastMouseClicX);
bar.x = std::max(bg.x, bar.x);
double maxScroll = bg.width - bar.width;
bar.x = std::min(bg.x + maxScroll, bar.x);
double curScroll = bar.x - bg.x;
double scrollPercent = curScroll / maxScroll;
status->ScrollX =
-(status->MoveTableMaxX - MTCanvasWidth) * scrollPercent;
} else {
bar.y = DragY + (status->MouseY - status->LastMouseClicY);
bar.y = std::max(bg.y, bar.y);
double maxScroll = bg.height - bar.height;
bar.y = std::min(bg.y + maxScroll, bar.y);
double curScroll = bar.y - bg.y;
double scrollPercent = curScroll / maxScroll;
status->ScrollY =
-(status->MoveTableMaxY - MTCanvasHeight) * scrollPercent;
}
} else {
Trigger = false;
}
}
elements.clear();
elements.push_back(bg);
elements.push_back(bar);
}
} // namespace cgeditor

View file

@ -0,0 +1,16 @@
#include "Component.hpp"
#include <algorithm> // std::max
#include <cmath>
namespace cgeditor {
class Scrollbar : public Component {
/// @brief Set to true if it is the horizontal scrollbar
bool IsHorizontal;
Element bg,bar;
double DragY,DragX;
bool Trigger;
public:
Scrollbar(Status* s,bool IsHorizontal);
void Refresh();
};
} // namespace cgeditor