Commit b70571c1 authored by Loic Guegan's avatar Loic Guegan
Browse files

Improve editor

parent 533da878
Pipeline #219599183 passed with stage
in 10 minutes and 20 seconds
......@@ -11,22 +11,14 @@
namespace pgneditor {
class State {
class EditorConfig {
public:
Move *moveline;
bool WhiteToPlay;
int mouseX, mouseY;
int canvasW, canvasH;
/// @brief This value is automatically reset by the editor
bool MouseClick;
bool IsDragging;
/// @brief How much units variations should be shifted to the right
int variationOffset;
/// @brief Width of a column/row
int colWidth,rowWidth;
/// @brief Used by the scroll feature
int offsetX,offsetY;
int scrollbarThickness;
/// @brief Font size in px
int fontSize;
......@@ -37,15 +29,8 @@ public:
int varationSepW;
int extraCanvasMargin;
State(){
moveline=nullptr;
mouseX=0;
mouseY=0;
canvasW=0;
canvasH=0;
EditorConfig(){
variationOffset=20;
offsetX=0;
offsetY=0;
colWidth=50;
rowWidth=20;
scrollbarThickness=20;
......@@ -56,8 +41,6 @@ public:
hintBarWidth=30;
counterW=20;
varationSepW=5;
MouseClick=false;
IsDragging=false;
extraCanvasMargin=50;
}
......
......@@ -7,159 +7,159 @@
#include "PGNEditor.hpp"
#include <iostream>
#include <math.h>
#include <algorithm>
namespace pgneditor {
void PGNEditor::Render(State *state) {
this->state = state;
this->WhiteToPlay = state->WhiteToPlay;
float clamp(float d, float min, float max) {
const float t = d < min ? min : d;
return t > max ? max : t;
}
void PGNEditor::Render() {
this->MoveCount = 1;
this->LineCount = 1;
this->CurrentX = state->leftMargin + state->hintBarWidth;
this->CurrentY = state->topMargin;
this->canvasW = state->canvasW - state->scrollbarThickness;
this->canvasH = state->canvasH - state->scrollbarThickness;
this->MaxX = 1;
this->MaxY = 1;
this->MinX = 0;
this->MinY = 0;
if (state->MouseClick) {
this->LastMouseClickX = state->mouseX;
this->LastMouseClickY = state->mouseY;
this->CurrentX = Config.leftMargin + Config.hintBarWidth;
this->CurrentY = Config.topMargin;
InCanvasSize.w = CanvasW - Config.scrollbarThickness;
InCanvasSize.h = CanvasH - Config.scrollbarThickness;
this->MaxX = CurrentX;
this->MaxY = CurrentY;
this->MinX = CurrentX;
this->MinY = CurrentY;
if (IsMouseClicked) {
this->LastMouseClickX = MouseX;
this->LastMouseClickY = MouseY;
}
// Start Drawing
this->DrawHintBar();
if (state->moveline != nullptr)
this->DrawLine(state->moveline);
if (MoveLine != nullptr)
this->DrawLine(MoveLine);
this->DrawScrollBars();
state->MouseClick = false;
IsMouseClicked = false;
IsMouseDragging=false;
}
void PGNEditor::DrawHintBar() {
// Never issue a call to DrawCall here (otherwise MaxX and MaxY will be corrupted)
Shape hintBar(state->offsetX, 0, state->hintBarWidth, canvasH);
Shape hintBar(OffsetX, 0, Config.hintBarWidth, InCanvasSize.h);
hintBar.target = Shape::HINTBAR;
Draw(hintBar); // Do not issues a DrawCall here (MaxY will change);
}
void PGNEditor::ScrollV(int percent) {
double VSSize = (double) canvasH
* ((double) canvasH / std::max(canvasH, MaxY - MinY));
int maxScroll=(canvasH - VSSize);
float VSSize = (float) InCanvasSize.h
* ((float) InCanvasSize.h / std::max(InCanvasSize.h, MaxY - MinY));
int maxScroll=(InCanvasSize.h - VSSize);
int amount=maxScroll*percent/100;
CurrentVSY += amount;
if (CurrentVSY <= 0)
CurrentVSY = 0;
else if (CurrentVSY >= maxScroll)
CurrentVSY = maxScroll;
double percentPage = 0;
if ((canvasH - VSSize) > 0)
percentPage = CurrentVSY / (canvasH - VSSize);
int maxOffset = std::max((MaxY - MinY) - canvasH, 0);
state->offsetY = -(double) maxOffset * percentPage;
CurrentVSY=clamp(CurrentVSY,0,InCanvasSize.h - VSSize);
float percent2=CurrentVSY / (InCanvasSize.h - VSSize);
percent2=clamp(percent2,0.0,1.0);
int maxOffset = std::max((MaxY - MinY) - InCanvasSize.h, 0);
OffsetY = -(maxOffset * percent2);
OffsetY = clamp(OffsetY,-maxOffset,0);
}
void PGNEditor::ScrollH(int percent) {
double HSSize = (double) canvasW
* ((double) canvasW / std::max(canvasW, MaxX - MinX));
int maxScroll=(canvasW - HSSize);
float HSSize = (float) InCanvasSize.w
* ((float) InCanvasSize.w / std::max(InCanvasSize.w, MaxX - MinX));
int maxScroll=(InCanvasSize.w - HSSize);
int amount=maxScroll*percent/100;
CurrentHSX += amount;
if (CurrentHSX <= 0)
CurrentHSX = 0;
else if (CurrentHSX >= maxScroll)
CurrentHSX = maxScroll;
double percentPage = 0;
if ((canvasW - HSSize) > 0)
percentPage = CurrentHSX / (canvasW - HSSize);
int maxOffset = std::max((MaxX - MinX) - canvasW, 0);
state->offsetX = -(double) maxOffset * percentPage;
CurrentHSX=clamp(CurrentHSX,0,InCanvasSize.w - HSSize);
float percent2=CurrentHSX / (InCanvasSize.w - HSSize);
percent2=clamp(percent2,0.0,1.0);
int maxOffset = std::max((MaxX - MinX) - InCanvasSize.w, 0);
OffsetX = -(maxOffset * percent2);
OffsetX = clamp(OffsetX,-maxOffset,0);
}
bool PGNEditor::MouseHover(Shape shape){
return(shape.x <= state->mouseX && shape.y <= state->mouseY
&& (shape.x+shape.GetWidth(state)) >= state->mouseX && (shape.GetHeight(state)+shape.y) >= state->mouseY);
int x=shape.x+OffsetX;
int y=shape.y+OffsetY;
int maxX=x+shape.GetWidth(&Config);
int maxY=y+shape.GetHeight(&Config);
return((x <= MouseX) && (y <= MouseY) && (maxX >= MouseX) && (maxY >= MouseY));
}
void PGNEditor::SetConfiguration(EditorConfig config){
this->Config=config;
}
void PGNEditor::DrawScrollBars() {
// Never issue a call to DrawCall here (otherwise MaxX and MaxY will be corrupted)
// First draw scrolling corner on the bottom right side
Shape corner(canvasW, canvasH, state->scrollbarThickness,
state->scrollbarThickness);
Shape corner(InCanvasSize.w, InCanvasSize.h, Config.scrollbarThickness,
Config.scrollbarThickness);
corner.target = Shape::SCROLLBAR_CORNER;
if (corner.x <= state->mouseX && corner.y <= state->mouseY
&& state->canvasW >= state->mouseX
&& state->canvasH >= state->mouseY)
if (corner.x <= MouseX && corner.y <= MouseY
&& CanvasW >= MouseX
&& CanvasH >= MouseY)
corner.mouseHover = true;
Draw(corner);
// Compute scrollbal size
double HSSize = (double) canvasW
* ((double) canvasW / std::max(canvasW, MaxX - MinX));
double VSSize = (double) canvasH
* ((double) canvasH / std::max(canvasH, MaxY - MinY));
float HSSize = (float) InCanvasSize.w
* ((float) InCanvasSize.w / std::max(InCanvasSize.w, MaxX - MinX));
float VSSize = (float) InCanvasSize.h
* ((float) InCanvasSize.h / std::max(InCanvasSize.h, MaxY - MinY));
if (state->IsDragging) {
if (IsMouseDragging) {
if (LastMouseClickOnHS) {
CurrentHSX += (state->mouseX - LastMouseClickX);
LastMouseClickX = state->mouseX;
if (CurrentHSX <= 0)
CurrentHSX = 0;
else if (CurrentHSX >= (canvasW - HSSize))
CurrentHSX = (canvasW - HSSize);
double percent = 0;
if ((canvasW - HSSize) > 0)
percent = CurrentHSX / (canvasW - HSSize);
int maxOffset = (MaxX - MinX) - canvasW;
state->offsetX = -(double) maxOffset * percent;
CurrentHSX += (MouseX - LastMouseClickX);
LastMouseClickX = MouseX;
CurrentHSX=clamp(CurrentHSX,0,InCanvasSize.w - HSSize);
float percent=CurrentHSX / (InCanvasSize.w - HSSize);
percent=clamp(percent,0.0,1.0);
int maxOffset = std::max((MaxX - MinX) - InCanvasSize.w, 0);
OffsetX = -(maxOffset * percent);
OffsetX = clamp(OffsetX,-maxOffset,0);
}
if (LastMouseClickOnVS) {
CurrentVSY += (state->mouseY - LastMouseClickY);
LastMouseClickY = state->mouseY;
if (CurrentVSY <= 0)
CurrentVSY = 0;
else if (CurrentVSY >= (canvasH - VSSize))
CurrentVSY = (canvasH - VSSize);
double percent = 0;
if ((canvasH - VSSize) > 0)
percent = CurrentVSY / (canvasH - VSSize);
int maxOffset = std::max((MaxY - MinY) - canvasH, 0);
state->offsetY = -(double) maxOffset * percent;
else if (LastMouseClickOnVS) {
CurrentVSY += (MouseY - LastMouseClickY);
LastMouseClickY = MouseY;
CurrentVSY=clamp(CurrentVSY,0,InCanvasSize.h - VSSize);
float percent=CurrentVSY / (InCanvasSize.h - VSSize);
percent=clamp(percent,0.0,1.0);
int maxOffset = std::max((MaxY - MinY) - InCanvasSize.h, 0);
OffsetY = -(maxOffset * percent);
OffsetY = clamp(OffsetY,-maxOffset,0);
}
}
//std::cout << "MaxY:" << MaxY << " MinY " << MinY << " Diff:"<< MaxY-MinY << std::endl << std::flush;
//std::cout << "MaxX:" << MaxX << " MinX " << MinX << " Diff:"<< MaxX-MinX << " OffsetX " << OffsetX <<std::endl << std::flush;
Shape HS(CurrentHSX, canvasH, HSSize, state->scrollbarThickness);
CurrentHSX=clamp(CurrentHSX,0,InCanvasSize.w - HSSize);
CurrentVSY=clamp(CurrentVSY,0,InCanvasSize.h - VSSize);
Shape HS(CurrentHSX, InCanvasSize.h, HSSize, Config.scrollbarThickness);
HS.target = Shape::SCROLLBAR_H;
Shape VS(canvasW, CurrentVSY, state->scrollbarThickness, VSSize);
Shape VS(InCanvasSize.w, CurrentVSY, Config.scrollbarThickness, VSSize);
VS.target = Shape::SCROLLBAR_V;
// Check mouse over
if (HS.x <= state->mouseX && HS.y <= state->mouseY
&& (HS.x + HSSize) >= state->mouseX
&& (HS.y + state->scrollbarThickness) >= state->mouseY) {
if (HS.x <= MouseX && HS.y <= MouseY
&& (HS.x + HSSize) >= MouseX
&& (HS.y + Config.scrollbarThickness) >= MouseY) {
HS.mouseHover = true;
HS.mouseClick = state->MouseClick;
HS.mouseClick = IsMouseClicked;
}
if (VS.x <= state->mouseX && VS.y <= state->mouseY
&& (VS.x + state->scrollbarThickness) >= state->mouseX
&& (VS.y + VSSize) >= state->mouseY) {
if (VS.x <= MouseX && VS.y <= MouseY
&& (VS.x + Config.scrollbarThickness) >= MouseX
&& (VS.y + VSSize) >= MouseY) {
VS.mouseHover = true;
VS.mouseClick = state->MouseClick;
VS.mouseClick = IsMouseClicked;
}
if (state->MouseClick) {
LastMouseClickOnHS = (state->MouseClick && HS.mouseHover);
LastMouseClickOnVS = (state->MouseClick && VS.mouseHover);
if (IsMouseClicked) {
LastMouseClickOnHS = HS.mouseHover;
LastMouseClickOnVS = VS.mouseHover;
}
Draw(HS);
......@@ -169,16 +169,16 @@ void PGNEditor::DrawScrollBars() {
void PGNEditor::DrawLine(Move *line) {
DrawCount();
int CurrentXBack = CurrentX;
CurrentX += state->counterW;
CurrentX += Config.counterW;
if (WhiteToPlay) {
DrawMove(*line->move);
if (line->next != nullptr) {
CurrentX += state->colWidth;
CurrentX += Config.colWidth;
DrawMove(*line->next->move);
}
// Restore state
CurrentX = CurrentXBack;
CurrentY += state->rowWidth;
CurrentY += Config.rowWidth;
DrawVariations(line); // Draw White Variations
if (line->next != nullptr) {
WhiteToPlay = false;
......@@ -188,11 +188,11 @@ void PGNEditor::DrawLine(Move *line) {
}
} else {
CurrentX += state->colWidth;
CurrentX += Config.colWidth;
DrawMove(*line->move);
// Restore state
CurrentX = CurrentXBack;
CurrentY += state->rowWidth;
CurrentY += Config.rowWidth;
DrawVariations(line);
WhiteToPlay = true;
}
......@@ -209,19 +209,19 @@ void PGNEditor::DrawVariations(Move *line) {
bool WhiteToPlayBak = WhiteToPlay;
int CurrentXBack = CurrentX;
int MoveCountBak = MoveCount;
CurrentX += state->variationOffset;
CurrentX += Config.variationOffset;
// Draw separator
Shape sep(CurrentX, CurrentY, state->counterW + state->colWidth * 2,
state->varationSepW);
Shape sep(CurrentX, CurrentY, Config.counterW + Config.colWidth * 2,
Config.varationSepW);
if(line->fold)
sep.target=Shape::VAR_SEP_FOLD;
else
sep.target = Shape::VAR_SEP;
DrawCall(sep);
CurrentY += state->varationSepW;
CurrentY += Config.varationSepW;
if(state->MouseClick){
if(IsMouseClicked){
if(MouseHover(sep)){
line->fold=!line->fold;
}
......@@ -242,7 +242,7 @@ void PGNEditor::DrawVariations(Move *line) {
}
void PGNEditor::DrawMove(std::string move) {
Shape bg(CurrentX, CurrentY, state->colWidth, state->rowWidth);
Shape bg(CurrentX, CurrentY, Config.colWidth, Config.rowWidth);
bg.target = Shape::MOVE;
DrawCall(bg);
Shape moveS(move, CurrentX, CurrentY);
......@@ -250,7 +250,7 @@ void PGNEditor::DrawMove(std::string move) {
DrawCall(moveS);
}
void PGNEditor::DrawCount() {
Shape bg(CurrentX, CurrentY, state->counterW, state->rowWidth);
Shape bg(CurrentX, CurrentY, Config.counterW, Config.rowWidth);
bg.target = Shape::MOVE_COUNTER;
DrawCall(bg);
std::string dots = ".";
......@@ -262,34 +262,36 @@ void PGNEditor::DrawCount() {
}
void PGNEditor::DrawCall(Shape shape) {
shape.x += state->offsetX;
shape.y += state->offsetY;
shape.x += OffsetX;
shape.y += OffsetY;
int height = shape.GetHeight(state);
int width = shape.GetWidth(state);
int height = shape.GetHeight(&Config);
int width = shape.GetWidth(&Config);
int maxX = shape.x + width;
int maxY = shape.y + height;
if ((maxX + state->extraCanvasMargin) > MaxX)
MaxX = (maxX + state->extraCanvasMargin);
if ((maxY + state->extraCanvasMargin) > MaxY)
MaxY = (maxY + state->extraCanvasMargin);
if ((maxX + Config.extraCanvasMargin) > MaxX)
MaxX = (maxX + Config.extraCanvasMargin);
if ((maxY + Config.extraCanvasMargin) > MaxY)
MaxY = (maxY + Config.extraCanvasMargin);
if (shape.x < MinX)
MinX = shape.x;
if (shape.y < MinY)
MinY = shape.y;
if (shape.x <= state->mouseX && shape.y <= state->mouseY
&& maxX >= state->mouseX && maxY >= state->mouseY) {
if (shape.x <= MouseX && shape.y <= MouseY
&& maxX >= MouseX && maxY >= MouseY) {
shape.mouseHover = true;
shape.mouseClick = state->MouseClick;
shape.mouseClick = IsMouseClicked;
}
// Issue a draw only if necessary
if (shape.x <= canvasW && shape.y <= canvasH)
if (shape.x <= InCanvasSize.w && shape.y <= InCanvasSize.h){
if (maxX >= 0 && maxY >= 0)
Draw(shape);
}
}
}
......@@ -9,18 +9,20 @@
#include "Move.hpp"
#include "Shape.hpp"
#include "State.hpp"
#include <algorithm>
#include "EditorConfig.hpp"
#include "Types.hpp"
namespace pgneditor {
class PGNEditor {
private:
State *state;
int canvasW,canvasH;
bool WhiteToPlay;
EditorConfig Config;
Size InCanvasSize;
int MoveCount;
int LineCount;
int CurrentX;
......@@ -31,6 +33,7 @@ private:
bool LastMouseClickOnVS;
int CurrentVSY;
int CurrentHSX;
int OffsetY,OffsetX;
/// @brief Used by scrollbars
int MaxX,MinX;
......@@ -43,15 +46,32 @@ private:
void DrawCall(Shape shape);
void DrawCount();
void DrawMove(std::string move);
bool MouseHover(Shape shape);
protected:
void Render(State *state);
bool IsMouseClicked;
bool IsMouseDragging;
int CanvasW,CanvasH;
int MouseX,MouseY;
Move *MoveLine;
bool WhiteToPlay;
virtual void Draw(Shape shape) = 0;
void Render();
void ScrollV(int percent);
void ScrollH(int percent);
bool MouseHover(Shape shape);
public:
PGNEditor():LastMouseClickOnHS(false),LastMouseClickOnVS(false),CurrentVSY(0),CurrentHSX(0){
void SetConfiguration(EditorConfig config);
public:
PGNEditor():PGNEditor(EditorConfig()){}
PGNEditor(EditorConfig config):LastMouseClickOnHS(false),LastMouseClickOnVS(false),CurrentVSY(0),CurrentHSX(0){
this->Config=config;
OffsetY=0;
OffsetX=0;
CanvasW=0;
CanvasH=0;
MouseX=0;
MouseY=0;
WhiteToPlay=true;
}
};
......
......@@ -8,7 +8,8 @@
#pragma once
#include <string>
#include "State.hpp"
#include "EditorConfig.hpp"
namespace pgneditor {
......@@ -51,7 +52,7 @@ public:
x(x),y(y),w(0),h(0),radius(radius),type(CIRCLE),target(NA),mouseHover(false),mouseClick(false){
}
int GetWidth(State* state){
int GetWidth(EditorConfig* state){
switch(type){
case RECTANGLE:
return(w);
......@@ -64,7 +65,7 @@ public:
}
}
int GetHeight(State* state){
int GetHeight(EditorConfig* state){
switch(type){
case RECTANGLE:
return(h);
......
/*
* Types.hpp
*
* Created on: 21 nov. 2020
* Author: loic
*/
#pragma once
namespace pgneditor {
class Point {
public:
int x,y;
Point():x(0),y(0){
}
};
class Size {
public:
int w,h;
Size():w(0),h(0){
}
};
}
......@@ -20,29 +20,22 @@ Editor::Editor(wxFrame *parent) :
wxPanel(parent), DC(nullptr) {
//this->Bind(wxEVT_PAINT, &Editor::OnPaint, this);
this->SetBackgroundColour(*wxWHITE);
state = new State();
ochess::pgn::PGN pgn("/home/loic/test.pgn");
pgn.parseNextGame();
state->moveline = &(pgn.game->GetFirstMove()->editorMove);
MoveLine = &(pgn.game->GetFirstMove()->editorMove);
}
void Editor::OnKeyDown(wxKeyEvent &event) {
if(event.GetKeyCode()==WXK_NUMPAD0)
ScrollV(-10);
else
ScrollV(10);
Refresh();
}
void Editor::MouseEvent(wxMouseEvent &event) {
SetFocus();
if(event.LeftDown()){
state->MouseClick=true;
IsMouseClicked=true;
}