Newer
Older
/*
* Copyright (c) 2015 Tricoire Sebastien 3dsman@free.fr
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
*/
#include "OE_interfaceDisplay.h"
#include "OE_utils.h"
#include "OE_controller.h"
#include <iostream>
#include <GL/gl.h>
#include <cstdlib>
#include <math.h>
#include <cstdio>
#include <cstring>
#include "actions/OE_actionsCurves.h"
#include "actions/OE_actionsStitchs.h"
#include "actions/OE_actionsLineStitchs.h"
#include "actions/OE_actionsBirailStitchs.h"
3dsman
committed
#include "actions/OE_actionsLinkStitchs.h"
#include "actions/OE_actionsSelection.h"
#include "actions/OE_actionsThreads.h"
static const GLuint TOOLSSELID = 0;
static const GLuint STITCHSSELID = 1;
static const GLuint CURVESSELID = 2;
static const GLuint ZEROID = 0;
static const GLuint TRANSTOOLID = 1;
static const GLuint MOVETOOLID = 0;
static const GLuint SCALETOOLID = 1;
OE_interfaceDisplay::OE_interfaceDisplay(QWidget *parent, Qt::WindowFlags f) : OE_display(parent, f)
{
editStyle = new OE_display::OE_displayStyle();
commandStyle = new OE_display::OE_displayStyle();
commandStyle->drawGrid = false;
commandStyle->drawCurves = false;
commandStyle->drawStitches = false;
commandStyle->drawCommands = true;
setDisplayStyle(editStyle);
modState = Qt::KeyboardModifier::NoModifier;
}
OE_interfaceDisplay::~OE_interfaceDisplay()
{
//delete curDisplay;
}
bool OE_interfaceDisplay::setDocument(OE_document* document)
{
this->document = document;
}
bool OE_interfaceDisplay::setController(OE_controller* controller)
{
this->controller = controller;
}
void OE_interfaceDisplay::showAll()
{
OE_display::showAll();
}
{
bool redraw = false;
redraw |= OE_display::mouse_Pos(x, y);
vector_2dt oldClosestPoint = editClosestPoint;
vector_2d absMove = vector_2d((mouse.x - clicOldMouse.x)*zoom*2, (mouse.y - clicOldMouse.y)*zoom*2);
if (editionState == MoveSelection) //if the move action is enabled
controller->editActionMoveSelection(vector_2d((mouse.x - clicOldMouse.x)*zoom*2,
(mouse.y - clicOldMouse.y)*zoom*2));
if (editionState == ScaleSelection) //if the scale action is enabled
{
vector_2d bbCenter = controller->getSelectionBoundingBox().getCenter();
float scale = (absMouse-bbCenter).len()/(screenToDocument(clicOldMouse)-bbCenter).len();
controller->editActionScaleSelection(vector_2d(scale,scale));
if (editionState == NewSubcurve) //if we must find the closest subcurve (get the closest point on it too)
{
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
redraw = true;
}
else if (editSubcurve) //if we are working on a defined subcurve get the closest point on it
{
editClosestPoint = controller->getClosestPoint(editSubcurve->getCurve(), absMouse);
if (editionState == MovePointcurve && selControlCurve && selControlType==0) //if we're moving a curve control point
controller->editActionMovePointCurve(vector_2d((mouse.x - clicOldMouse.x)*zoom*2,
(mouse.y - clicOldMouse.y)*zoom*2));
3dsman
committed
if (editionState == MovePointstitch) //if we're moving a linkstitch control point
{
controller->editActionMovePointLinkStitch(absMove);
controller->editActionMoveGridPointFillStitch(absMove);
3dsman
committed
}
//if we're editing the scaleWidth of a linestitch
if (editionState == OffsetWidthLinestitch)
controller->editActionSetLinestitchWidth((mouse.x - clicOldMouse.x)/100.0f, true);
//if we're define a new subcurve and the reference curve is already picked
if ((editionState == NewSubcurve)&&(selControlStitch))
{
editionState = TraceSubcurve;
if (oldClosestPoint.t>editClosestPoint.t) controller->editActionAddSubcurvePosSwitchDir();
}
if (editionState == TraceSubcurve)
{
controller->editActionAddSubcurvePosEnd(editClosestPoint.t);
}
else if (editionState == MoveSubcurve)
{
controller->editActionSetSubcurvePos(editClosestPoint.t);
}
{
bool redraw = false;
redraw |= OE_display::mouse_Button(event);
if (curScreen == edit && event->button() == Qt::LeftButton && event->type() == QEvent::MouseButtonPress)
if (editionState == NewSubcurve)
{
if (!closestCurve)
{
editionState = None;
}
controller->addAction(new OE_actionJoincurveAddSubCurve(document, curJoincurve, subcurve_id, closestCurve,
selControlStitch = controller->getStitch(-1);
selControlType = 0;
//editSubcurve = curJoincurve->getCurve(-1);
editSubcurve = curJoincurve->getCurve(subcurve_id);
editionState = Selection;
if (curScreen == edit && event->button() == Qt::LeftButton && event->type() == QEvent::MouseButtonRelease)
selControlCurve = nullptr;
selControlStitch = nullptr;
if (editionState == AddSubcurve)
{
//curJoincurve = controller->getLineStitch(-1)->getJoincurve();
//closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
editionState = NewSubcurve;
joincurve_id = 0;
{
if ((mouse-clicOldMouse).len()>5)
selectBox();
selectApply(selectedCurves, selectedStitches);
editionState = None;
}
if ((editionState == NewSubcurve)||(editionState == TraceSubcurve))
if (joincurve_id == 0)
{
editionState = None;
}
else
{
editionState = NewSubcurve;
curJoincurve = controller->getBirailStitch(-1)->getJoincurve2();
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
joincurve_id -= 1;
}
editionState = None;
}
}
void OE_interfaceDisplay::scroll(double xoffset, double yoffset)
{
OE_display::scroll(xoffset, yoffset);
}
void OE_interfaceDisplay::resize(int width, int height)
{
OE_display::resize(width, height);
}
{
static QString writeFilters = QString::fromStdString(OE_document::getWriteDialogFilters());
static QString readFilters = QString::fromStdString(OE_document::getReadDialogFilters());
if (event->type() == QEvent::KeyPress)
modState = event->modifiers();
else
modState = Qt::KeyboardModifier::NoModifier;
if (event->type() == QEvent::KeyPress && curScreen == edit)
if (event->key() == Qt::Key_R && event->modifiers() == Qt::NoModifier)
if (editionState == TraceSubcurve)
controller->editActionAddSubcurvePosSwitchDir();
update();
else if (editionState == MoveSubcurve)
controller->editActionSetSubcurvePosSwitchDir();
update();
if(editionState==None)
if (event->key() == Qt::Key_Z && event->modifiers() == Qt::ControlModifier)
controller->undoAction();
update();
else if (event->key() == Qt::Key_S && event->modifiers() == Qt::ControlModifier)
if (document)
QString fileName = QFileDialog::getSaveFileName(this, "Save design", "", writeFilters);
if (!fileName.isEmpty())
{
document->saveToFile(fileName.toStdString());
}
else if (event->key() == Qt::Key_O && event->modifiers() == Qt::ControlModifier)
QString fileName = QFileDialog::getOpenFileName(this, "Open design", "", readFilters, &type);
loadFile(fileName.toStdString());
update();
else if (event->key() == Qt::Key_Z && event->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier))
if (controller)
{
controller->redoAction();
update();
else if (event->modifiers() == Qt::NoModifier)
if (controller)
controller->toggleCloseSelectedCurve();
update();
{
//TODO create an action to delete all selected stitches
std::list<OE_stitchs*>::iterator it=selectedStitches.begin();
controller->addAction(new OE_actionDelStitch(document, *it));
update();
{
std::list<OE_stitchs*>::iterator it=selectedStitches.begin();
if (it != selectedStitches.end())
{
it = std::find (document->stitchs.begin(), document->stitchs.end(), *it);
it++;
if (it != document->stitchs.end())
{
selectedStitches.clear();
selectedStitches.push_back(*it);
controller->clearSelection();
controller->selectStitches(selectedStitches,true);
update();
}
}
}
std::list<OE_stitchs*>::iterator it=selectedStitches.begin();
if (it != selectedStitches.end())
it = std::find (document->stitchs.begin(), document->stitchs.end(), *it);
if (it != document->stitchs.begin())
{
it--;
selectedStitches.clear();
selectedStitches.push_back(*it);
controller->clearSelection();
controller->selectStitches(selectedStitches,true);
update();
}
}
}
{
if (editionState == TraceSubcurve)
{
controller->editActionAddSubcurvePosSwitchDir();
update();
}
else if (editionState == MoveSubcurve)
{
controller->editActionSetSubcurvePosSwitchDir();
update();
update();
if (curScreen == edit)
{
curScreen = command;
setDisplayStyle(commandStyle);
update();
}
else
{
curScreen = edit;
setDisplayStyle(editStyle);
update();
if (controller)
{
controller->newLineStitch(2.5, 2.5, controller->getPattern(0));
document->selectedStitchs.push_back(controller->getLineStitch(-1));
curJoincurve = controller->getLineStitch(-1)->getJoincurve();
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
editionState = NewSubcurve;
joincurve_id = 0;
subcurve_id = -1;
update();
controller->newBirailStitch(false, false, 0, 0, 0.7f);
document->selectedStitchs.push_back(controller->getBirailStitch(-1));
curJoincurve = controller->getBirailStitch(-1)->getJoincurve1();
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
editionState = NewSubcurve;
joincurve_id = 1;
subcurve_id = -1;
update();
controller->newFillStitch(1.5f, 0.3f, controller->getPattern(0));
document->selectedStitchs.push_back(controller->getFillStitch(-1));
curJoincurve = controller->getFillStitch(-1)->getJoincurve();
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
editionState = NewSubcurve;
joincurve_id = 0;
update();
{
if (editionState == NewSubcurve)
{
if (joincurve_id == 0)
{
editionState = None;
curJoincurve = 0;
}
else
{
curJoincurve = controller->getBirailStitch(-1)->getJoincurve2();
closestCurve = controller->getClosestCurve(absMouse, editClosestPoint);
joincurve_id -= 1;
}
}
}*/
else if (event->key() == Qt::Key_Plus && event->modifiers() & Qt::KeypadModifier)
if (event->modifiers() & Qt::ControlModifier)
controller->addAction(new OE_actionScaleSelectedStitchLen(document, 1.1f));
update();
controller->addAction(new OE_actionScaleSelectedStitchWidth(document, 1.1f));
update();
else if (event->key() == Qt::Key_Minus && event->modifiers() & Qt::KeypadModifier)
if (event->modifiers() & Qt::ControlModifier)
controller->addAction(new OE_actionScaleSelectedStitchLen(document, 1.f/1.1f));
update();
controller->addAction(new OE_actionScaleSelectedStitchWidth(document, 1.f/1.1f));
update();
else if (event->key() == Qt::Key_1 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(0)));
update();
else if (event->key() == Qt::Key_2 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(1)));
update();
else if (event->key() == Qt::Key_3 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(2)));
update();
else if (event->key() == Qt::Key_4 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(3)));
update();
else if (event->key() == Qt::Key_5 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(4)));
update();
else if (event->key() == Qt::Key_6 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(5)));
update();
else if (event->key() == Qt::Key_7 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(6)));
update();
else if (event->key() == Qt::Key_8 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(7)));
update();
else if (event->key() == Qt::Key_9 && event->modifiers() & Qt::KeypadModifier)
controller->addAction(new OE_actionSetSelectedStitchPattern(document, controller->getPattern(8)));
update();
3dsman
committed
update();
3dsman
committed
}
}
selectedCurves.clear();
selectedStitches.clear();
vector_2d clicAbsMouse = viewPos+(clicOldMouse-vector_2d(width,height)/2)*zoom*2;
std::list<OE_pointcurve*>::iterator curve = document->curves.begin();
while (curve != document->curves.end())
{
BoundingBox box = (*curve)->getBound();
if ((box.getMin().x > std::min(clicAbsMouse.x, absMouse.x))
&&(box.getMax().x < std::max(clicAbsMouse.x, absMouse.x))
&&(box.getMin().y > std::min(clicAbsMouse.y, absMouse.y))
&&(box.getMax().y < std::max(clicAbsMouse.y, absMouse.y)))
{
selectedCurves.push_back(*curve);
}
curve++;
}
std::list<OE_stitchs*>::iterator stitch = document->stitchs.begin();
while (stitch != document->stitchs.end())
{
if ((box.getMin().x > std::min(clicAbsMouse.x, absMouse.x))
&&(box.getMax().x < std::max(clicAbsMouse.x, absMouse.x))
&&(box.getMin().y > std::min(clicAbsMouse.y, absMouse.y))
&&(box.getMax().y < std::max(clicAbsMouse.y, absMouse.y)))
{
selectedStitches.push_back(*stitch);
}
stitch++;
}
bool OE_interfaceDisplay::checkJoinCurveControl(OE_joincurve* joinCurve, int &index)
{
if (selControlType == index)
{
// get the corresponding subcurve
editSubcurve = joinCurve->getCurve(selControlIndex/2);
if (editSubcurve)
{
editionState = MoveSubcurve;
// get the closest point t value
vector_2dt pos = editSubcurve->getCurve()->closestPoint(absMouse);
// and add an action to move the point
controller->addAction(new OE_actionSetSubcurvePos(document, editSubcurve, selControlIndex%2, pos.t));
return true;
}
return false;
}
index++;
if (selControlType == index)
{
editionState = AddSubcurve;
subcurve_id = selControlIndex;
curJoincurve = joinCurve;
return true;
}
index++;
return false;
}
bool OE_interfaceDisplay::checkPicking()
{
{
editionState = MoveSelection;
controller->addAction(new OE_actionMoveSelection(document, vector_2d(0,0)));
{
editionState = ScaleSelection;
controller->addAction(new OE_actionScaleSelection(document, vector_2d(1,1), controller->getSelectionBoundingBox().getCenter()));
// if we picked a stitch control
OE_linestitch* tmpLineStitch = dynamic_cast<OE_linestitch*>(selControlStitch);
if (tmpLineStitch)
{
// check generic joinCurve controls
if (checkJoinCurveControl(tmpLineStitch->getJoincurve(), ControlTypeIndex)) return true;
//check picking for linestitch width controller
if (selControlType == ControlTypeIndex && selControlIndex == 0)
editionState = OffsetWidthLinestitch;
controller->addAction(new OE_actionSetLineStitchWidth(document, tmpLineStitch, tmpLineStitch->getWidth()));
return true;
}
}
OE_birailstitch* tmpBirailStitch = dynamic_cast<OE_birailstitch*>(selControlStitch);
// check generic joinCurve controls for each birail's joincurve
if (checkJoinCurveControl(tmpBirailStitch->getJoincurve1(), ControlTypeIndex)) return true;
if (checkJoinCurveControl(tmpBirailStitch->getJoincurve2(), ControlTypeIndex)) return true;
3dsman
committed
OE_fillstitch* tmpFillStitch = dynamic_cast<OE_fillstitch*>(selControlStitch);
// check generic joinCurve controls
if (checkJoinCurveControl(tmpFillStitch->getJoincurve(), ControlTypeIndex)) return true;
// check picking for grid's controller points
else if (selControlType == ControlTypeIndex)
editionState = MovePointstitch;
//edit gridpoint
controller->addAction(new OE_actionMovePointFillStitch(document, tmpFillStitch, selControlIndex, vector_2d(0,0)));
return true;
}
return false;
}
3dsman
committed
OE_linkstitch* tmpLinkStitch = dynamic_cast<OE_linkstitch*>(selControlStitch);
3dsman
committed
{
//check picking of control point, add or delete
3dsman
committed
if (selControlType == 0)
{
editionState = MovePointstitch;
controller->addAction(new OE_actionMovePointLinkStitch(document, tmpLinkStitch, selControlIndex, vector_2d()));
3dsman
committed
{
editionState = MovePointstitch;
controller->addAction(new OE_actionAddPointLinkStitch(document, tmpLinkStitch, selControlIndex, absMouse));
{
editionState = DelPointstitch;
controller->addAction(new OE_actionDelPointLinkStitch(document, tmpLinkStitch, selControlIndex));
3dsman
committed
}
return false;
}
3dsman
committed
}
OE_pointcurve* tmpPointCurve = dynamic_cast<OE_pointcurve*>(selControlCurve);
editionState = MovePointcurve;
controller->addAction(new OE_actionMovePointCurve(document, tmpPointCurve,
selControlIndex+1,
vector_2d(0,0)));
return true;
/** \brief set selection
*
* \return true if all is ok
*
*/
bool OE_interfaceDisplay::drawPicking()
GLuint selectBuf[64];
glSelectBuffer(64, selectBuf);
OE_display::pick(document->selectedCurves, document->selectedStitchs);
//get the hits of the picking
//hits are represented by an array of GLuint*
// first value give us the number of items on the name stack at the time of the hit
// next 2 values are deep value of the picked object (we don't use it)
// then the items we need arrived
// we format it like that:
// - type of the picked object (tool, stitch or curve)
// - index of the picked object (list index for stitch or curve, index of the tool for the tools)
// - if we picked a sub element of a curve, stich or tool here come his type (handle, startpoint,...)
// - then his index
//
// so a hit can be defined by
// 2 values in case a curve of a stitch was picked directly
// 3 values in case of picking a transform tool like move
// or 4 values if we picked a sub element of a curve or stitch
selectedCurves.clear();
selectedStitches.clear();
toolAction = 0;
//std::cout<<"hits : "<<"\r\n";
ptr = static_cast<GLuint*>(selectBuf);
for (GLint i=0; i<hits; i++) // for each hit
{
GLuint names = *ptr;
ptr+=3; //skip nearZ and farZ info (we don't use it) and goto first index
if (*ptr == TOOLSSELID) //tools picking
{
ptr++;
{
}
if (*ptr == TRANSTOOLID) //one of the transform selection tools
ptr++;
{
toolAction = 1;
checkPicking();
return true;
}
{
toolAction = 2;
checkPicking();
return true;
}
return false;
//ptr++;
{
ptr++;
if (names==2) //if name count correspond to an object (we picked a stitch, not one of his sub element)
if (*ptr >= document->stitchs.size())
{
return false;
}
std::list<OE_stitchs*>::iterator it = document->stitchs.begin();
std::advance(it, *ptr);
selectedStitches.push_back(*it);
return true;
}
else if (names==4) //if name count correspond to a stitch sub element (like control point)
if (*ptr >= document->selectedStitchs.size())
{
return false;
}
std::list<OE_stitchs*>::iterator it = document->selectedStitchs.begin();
std::advance(it, *ptr++);
selControlStitch = *it;
selControlType = *ptr++;
selControlIndex = *ptr++;
checkPicking();
return true;
{
ptr++;
if (names==2) //if name count correspond to an object (we picked a curve, not one of his sub element)
{
if (*ptr >= document->curves.size())
{
return false;
}
std::list<OE_pointcurve*>::iterator it = document->curves.begin();
std::advance(it, *ptr);
selectedCurves.push_back(*it);
return true;
}
else if (names==4) //if name count correspond to a sub element of curve (like control point)
if (*ptr >= document->selectedCurves.size())
{
return false;
}
//in *ptr we got "curve id" then "control type" and at last "control id"
std::list<OE_pointcurve*>::iterator it = document->selectedCurves.begin();
std::advance(it, *ptr++);
selControlCurve = *it;
selControlType = *ptr++;
selControlIndex = *ptr++;
checkPicking();
return true;
}
3dsman
committed
bool OE_interfaceDisplay::selectApply(std::list<OE_pointcurve*> selectedCurves, std::list<OE_stitchs*> selectedStitches)
{
controller->unselectCurves(selectedCurves);
}
else
{
controller->selectCurves(selectedCurves, !modState.testFlag(Qt::ShiftModifier));
{
controller->unselectStitches(selectedStitches);
}
else
{
controller->selectStitches(selectedStitches, !modState.testFlag(Qt::ShiftModifier));
3dsman
committed
if (!selectedStitches.size() && !selectedCurves.size())
{
controller->clearSelection();
}
return true;
/** \brief draw the document on screen
*
* \return true if all is ok
*
*/
bool OE_interfaceDisplay::draw()
{
if (!document)
{
return false;
}
//TODO remove controller->sendInstPoint();
OE_display::draw();
//draw the closest point
if (editionState==NewSubcurve)
// Points
glPointSize(5.0f);
glBegin(GL_POINTS);
if (joincurve_id == 0)
glVertex2f(editClosestPoint.v.x,editClosestPoint.v.y);
glEnd();
// draw the cursor cross
glLineWidth(1.5);
glBegin(GL_LINES);
if (editionState)
glColor4f(0.8f, 0.0f, 0.0f, 0.5f);
glColor4f(0.0f, 0.8f, 0.0f, 0.5f);
glColor4fv(style->cursorColor.rgba);
}
glVertex2f(absMouse.x,-10000);
glVertex2f(absMouse.x,10000);
glVertex2f(-10000,absMouse.y);
glVertex2f(10000,absMouse.y);
glEnd();
// draw the cursor picking zone
glLineWidth(2);
glBegin(GL_LINE_LOOP);
glColor4fv(style->cursorColor.rgba);
glVertex2f(absMouse.x-5*zoom,absMouse.y+5*zoom);
glVertex2f(absMouse.x-5*zoom,absMouse.y-5*zoom);
glVertex2f(absMouse.x+5*zoom,absMouse.y-5*zoom);
glVertex2f(absMouse.x+5*zoom,absMouse.y+5*zoom);
glEnd();
if (editionState == Selection)
{
vector_2d clicAbsMouse = viewPos+(clicOldMouse-vector_2d(width,height)/2)*zoom*2;
glBegin(GL_LINE_STRIP);
glColor4fv(style->cursorColor.rgba);
glVertex2f(absMouse.x,clicAbsMouse.y);
glVertex2f(absMouse.x,absMouse.y);
glVertex2f(clicAbsMouse.x,absMouse.y);
glVertex2f(clicAbsMouse.x,clicAbsMouse.y);
glVertex2f(absMouse.x,clicAbsMouse.y);
return true;
}