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

Start PGN Editor

parent 9f121fc8
Pipeline #217457234 passed with stage
in 7 minutes and 43 seconds
......@@ -39,8 +39,9 @@ file(GLOB_RECURSE CMD ${SRC}/command/*.cpp)
file(GLOB_RECURSE ENGINE ${SRC}/engine/*.cpp)
file(GLOB_RECURSE MODEL ${SRC}/model/*.cpp)
file(GLOB_RECURSE UTILS ${SRC}/utils/*.cpp)
file(GLOB_RECURSE PGNEDITOR ${SRC}/editor/*.cpp)
# Combine for reusability
add_library(libochess OBJECT ${CMD} ${CNF} ${ENGINE} ${MODEL} ${UTILS})
add_library(libochess OBJECT ${CMD} ${CNF} ${ENGINE} ${MODEL} ${UTILS} ${PGNEDITOR})
# GUI Module
file(GLOB_RECURSE GUI ${SRC}/gui/*.cpp)
# Generate Executable
......
/*
* Move.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include <vector>
#include <string>
namespace pgneditor {
class Move {
public:
std::string move;
Move* next;
std::vector<Move*> variations;
};
}
/*
* PGNEditor.cpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#include "PGNEditor.hpp"
#include <iostream>
namespace pgneditor {
void PGNEditor::Render(State *state){
this->state=state;
this->WhiteToPlay=state->WhiteToPlay;
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;
// Start Drawing
this->DrawHintBar();
this->DrawLine(state->moveline);
this->DrawScrollBars();
}
void PGNEditor::DrawHintBar(){
Shape hintBar(0,0,state->hintBarWidth,canvasH);
hintBar.target=Shape::HINTBAR;
DrawCall(hintBar);
}
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);
corner.target=Shape::SCROLLBAR_CORNER;
if(corner.x<=state->mouseX && corner.y <= state->mouseY &&
state->canvasW>= state->mouseX && state->canvasH >= state->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));
Shape HS(state->offsetX,canvasH,HSSize,state->scrollbarThickness);
HS.target=Shape::SCROLLBAR_H;
Shape VS(canvasW,state->offsetY,state->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)
HS.mouseHover=true;
if(VS.x<=state->mouseX && VS.y <= state->mouseY &&
(VS.x+state->scrollbarThickness)>= state->mouseX && (VS.y+VSSize) >= state->mouseY)
VS.mouseHover=true;
Draw(HS);
Draw(VS);
}
void PGNEditor::DrawLine(Move* line){
if(WhiteToPlay){
Shape bg(CurrentX,CurrentY,state->counterW,state->rowWidth);
bg.target=Shape::MOVE_COUNTER;
DrawCall(bg);
Shape count(std::to_string(MoveCount)+".",CurrentX,CurrentY);
count.target=Shape::MOVE_COUNTER;
DrawCall(count);
CurrentX+=state->counterW;
}
Shape bg(CurrentX,CurrentY,state->colWidth,state->rowWidth);
bg.target=Shape::MOVE;
DrawCall(bg);
Shape move(line->move,CurrentX,CurrentY);
move.target=Shape::MOVE;
DrawCall(move);
CurrentX+=state->colWidth;
if(!WhiteToPlay){
CurrentX-=(state->colWidth*2+state->counterW); // *2 Because we just increment it above
CurrentY+=state->rowWidth;
MoveCount++;
}
if(line->next!=nullptr){
WhiteToPlay=!WhiteToPlay;
DrawLine(line->next);
}
}
void PGNEditor::DrawCall(Shape shape){
shape.x+=state->offsetX;
shape.y+=state->offsetY;
int height=shape.GetHeight(state);
int width=shape.GetWidth(state);
int maxX=shape.x+width;
int maxY=shape.y+height;
if(maxX>MaxX)
MaxX=maxX;
if(maxY>MaxY)
MaxY=maxY;
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)
shape.mouseHover=true;
// Issue a draw only if necessary
if(shape.x<=canvasW && shape.y <= canvasH)
if(maxX >= 0 && maxY>=0)
Draw(shape);
}
}
/*
* PGNEditor.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include "Move.hpp"
#include "Shape.hpp"
#include "State.hpp"
#include <algorithm>
namespace pgneditor {
class PGNEditor {
private:
State *state;
int canvasW,canvasH;
bool WhiteToPlay;
int MoveCount;
int LineCount;
int CurrentX;
int CurrentY;
/// @brief Used by scrollbars
int MaxX,MinX;
int MaxY,MinY;
void DrawLine(Move* line);
void DrawScrollBars();
void DrawHintBar();
void DrawCall(Shape shape);
protected:
void Render(State *state);
virtual void Draw(Shape shape) = 0;
};
} /* namespace ochess */
/*
* Shape.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include <string>
#include "State.hpp"
namespace pgneditor {
class Shape {
public:
typedef enum TYPE{
RECTANGLE,
CIRCLE,
TEXT
} TYPE;
typedef enum TARGET{
NA,
MOVE,
MOVE_CURRENT,
MOVE_COUNTER,
LINE_INDEX,
SCROLLBAR_H,
SCROLLBAR_V,
SCROLLBAR_CORNER,
HINTBAR
} TARGET;
double x,y;
double w,h;
double radius;
std::string text;
TYPE type;
TARGET target;
bool mouseHover;
Shape(double x,double y,double w, double h):
x(x),y(y),w(w),h(h),radius(0),type(RECTANGLE),target(NA),mouseHover(false){
}
Shape(std::string text, double x,double y):
x(x),y(y),w(0),h(0),radius(0),text(text),type(TEXT),target(NA),mouseHover(false){
}
Shape(double x,double y, double radius):
x(x),y(y),w(0),h(0),radius(radius),type(CIRCLE),target(NA),mouseHover(false){
}
int GetWidth(State* state){
switch(type){
case RECTANGLE:
return(w);
case CIRCLE:
return(radius*2);
case TEXT:
return(text.size()*state->fontSize);
default:
return(0);
}
}
int GetHeight(State* state){
switch(type){
case RECTANGLE:
return(h);
case CIRCLE:
return(radius*2);
case TEXT:
return(state->fontSize);
default:
return(0);
}
}
};
}
/*
* State.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include "Move.hpp"
namespace pgneditor {
class State {
public:
Move *moveline;
bool WhiteToPlay;
int mouseX, mouseY;
int canvasW, canvasH;
/// @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;
int topMargin,leftMargin;
int hintBarWidth;
// @brief Size of the move counter column
int counterW;
State(){
moveline=nullptr;
mouseX=0;
mouseY=0;
canvasW=0;
canvasH=0;
variationOffset=20;
offsetX=0;
offsetY=0;
colWidth=50;
rowWidth=20;
scrollbarThickness=20;
fontSize=16;
WhiteToPlay=true;
topMargin=10;
leftMargin=10;
hintBarWidth=30;
counterW=20;
}
};
}
/*
* Editor.cpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#include "Editor.hpp"
namespace ochess {
namespace gui {
Editor::Editor(wxFrame *parent) :
wxPanel(parent), DC(nullptr) {
this->Bind(wxEVT_PAINT, &Editor::OnPaint, this);
this->SetBackgroundColour(*wxWHITE);
state = new State();
pgneditor::Move *w1 = new pgneditor::Move();
w1->move = "e5";
state->moveline = w1;
pgneditor::Move *b1 = new pgneditor::Move();
b1->move = "e6";
w1->next = b1;
pgneditor::Move *w2 = new pgneditor::Move();
w2->move = "d4";
b1->next = w2;
this->Bind(wxEVT_CHAR_HOOK, &Editor::OnKeyDown, this);
this->Bind(wxEVT_MOTION, &Editor::MouseMove, this);
}
void Editor::OnKeyDown(wxKeyEvent &event) {
Refresh();
}
void Editor::MouseMove(wxMouseEvent &event) {
Refresh();
}
void Editor::OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
DC = &dc;
DC->GetSize(&state->canvasW, &state->canvasH);
// Update mouse position
const wxPoint pt = wxGetMousePosition();
state->mouseX = pt.x - this->GetScreenPosition().x;
state->mouseY = pt.y - this->GetScreenPosition().y;
// Render editor
Render(state);
}
void Editor::Draw(Shape shape) {
DC->SetPen(wxNullPen);
DC->SetBrush(*wxBLACK);
if (shape.mouseHover)
DC->SetBrush(*wxRED);
switch (shape.type) {
case Shape::RECTANGLE:
if (shape.target != Shape::MOVE && shape.target != Shape::MOVE_COUNTER) {
if (shape.target == Shape::HINTBAR
|| shape.target == Shape::SCROLLBAR_CORNER)
DC->SetBrush(wxColour(184, 184, 184));
else if (shape.target == Shape::SCROLLBAR_H
|| shape.target == Shape::SCROLLBAR_V)
DC->SetBrush(wxColour(100, 100, 100));
DC->DrawRectangle(shape.x, shape.y, shape.w, shape.h);
} else {
if(shape.mouseHover){
DC->SetBrush(wxColour(184, 184, 184));
DC->DrawRectangle(shape.x, shape.y, shape.w, shape.h);
}
}
break;
case Shape::CIRCLE:
DC->DrawCircle(shape.x, shape.y, shape.radius);
break;
case Shape::TEXT:
//if (shape.mouseHover)
//DC->SetTextForeground(*wxRED);
DC->DrawText(shape.text, shape.x, shape.y);
DC->SetTextForeground(*wxBLACK);
break;
}
}
} /* namespace gui */
} /* namespace ochess */
/*
* Editor.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "editor/PGNEditor.hpp"
using namespace pgneditor;
namespace ochess {
namespace gui {
class Editor: public wxPanel, public PGNEditor {
wxDC *DC;
State *state;
public:
Editor(wxFrame *parent);
void OnPaint(wxPaintEvent& event);
void Draw(Shape shape) override;
void OnKeyDown(wxKeyEvent& event);
void MouseMove(wxMouseEvent& event);
};
} /* namespace gui */
} /* namespace ochess */
/*
* Editor.cpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#include "EditorView.hpp"
namespace ochess {
namespace gui {
EditorView::EditorView(wxFrame *parent):wxPanel(parent) {
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
Editor *E = new Editor((wxFrame*) this);
vbox->Add(E, 1, wxEXPAND);
this->SetSizer(vbox);
}
} /* namespace gui */
} /* namespace ochess */
/*
* Editor.hpp
*
* Created on: 17 nov. 2020
* Author: loic
*/
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "Editor.hpp"
namespace ochess {
namespace gui {
class EditorView: public wxPanel {
public:
EditorView(wxFrame *parent);
};
} /* namespace gui */
} /* namespace ochess */
......@@ -34,7 +34,8 @@ wxFrame(NULL, wxID_ANY, title, pos, size) {
SetMenuBar(menuBar);
// Create required windows
Create(WIN_SETTINGS);
//Create(WIN_SETTINGS);
Create(WIN_EDITOR);
//new EngineSelection(this);
// Setup status bar
......@@ -63,6 +64,11 @@ void MainFrame::Create(WIN name) {
Windows[name]=bs;
break;
}
case WIN_EDITOR: {
EditorView *e = new EditorView((wxFrame*) this);
Windows[name]=e;
break;
}
}
}
......
......@@ -13,6 +13,7 @@
#include "gui/board/BoardView.hpp"
#include "gui/engine/EngineView.hpp"
#include "settings/Settings.hpp"
#include "gui/editor/EditorView.hpp"
#define GET_VIEW(mainFrame, entry, viewType) ((viewType*)(*((MainFrame*)(mainFrame)))[(entry)])
......@@ -23,7 +24,7 @@ namespace gui {
* @brief Used to select a particular window
*/
typedef enum WIN {
WIN_BOARD,WIN_ENGINE,WIN_SETTINGS
WIN_BOARD,WIN_ENGINE,WIN_SETTINGS,WIN_EDITOR
} WIN;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment