tahoma2d/toonz/sources/tnztools/edittoolgadgets.cpp

2984 lines
91 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "edittoolgadgets.h"
#include "tgl.h"
#include "toonz/tfxhandle.h"
#include "toonz/tobjecthandle.h"
#include "toonz/tframehandle.h"
#include "toonz/txsheethandle.h"
#include "toonz/stage.h"
#include "tools/tool.h"
#include "tfx.h"
#include "tparamcontainer.h"
#include "toonz/tcolumnfx.h"
#include "tdoubleparam.h"
#include "tparamset.h"
#include "tundo.h"
#include "tparamuiconcept.h"
#include "historytypes.h"
2022-02-28 11:18:09 +13:00
#include "toonzqt/gutil.h"
2016-03-19 06:57:51 +13:00
2022-02-28 20:51:59 +13:00
#include "toonz/tscenehandle.h"
#include "toonz/toonzscene.h"
#include "toonz/tcamera.h"
2017-05-18 22:45:18 +12:00
#include <QApplication>
#include <QDesktopWidget>
2022-02-16 17:49:00 +13:00
#include <QVector2D>
2017-05-18 22:45:18 +12:00
2016-03-19 06:57:51 +13:00
using namespace EditToolGadgets;
GLdouble FxGadget::m_selectedColor[3] = {0.2, 0.8, 0.1};
2017-05-18 22:45:18 +12:00
namespace {
TPointD hadamard(const TPointD &v1, const TPointD &v2) {
return TPointD(v1.x * v2.x, v1.y * v2.y);
2017-05-18 22:45:18 +12:00
}
2022-02-16 17:49:00 +13:00
#define SPIN_NUMVERTS 72
void drawSpinField(const TRectD geom, const TPointD center,
const double lineInterval, const double e_aspect_ratio,
const double e_angle) {
static GLdouble vertices[SPIN_NUMVERTS * 2];
static bool isInitialized = false;
if (!isInitialized) {
isInitialized = true;
for (int r = 0; r < SPIN_NUMVERTS; r++) {
double theta = 2.0 * M_PI * (double)r / (double)SPIN_NUMVERTS;
vertices[r * 2] = std::cos(theta);
vertices[r * 2 + 1] = std::sin(theta);
}
}
// obtain the nearest and the furthest pos inside the geom
TPointD nearestPos;
nearestPos.x = (center.x <= geom.x0) ? geom.x0
: (center.x >= geom.x1) ? geom.x1
: center.x;
nearestPos.y = (center.y <= geom.y0) ? geom.y0
: (center.y >= geom.y1) ? geom.y1
: center.y;
2022-02-16 17:49:00 +13:00
double minDist = norm(nearestPos - center);
TPointD farthestPos;
farthestPos.x = (center.x <= geom.x0) ? geom.x1
: (center.x >= geom.x1) ? geom.x0
: ((center.x - geom.x0) >= (geom.x1 - center.x)) ? geom.x0
: geom.x1;
farthestPos.y = (center.y <= geom.y0) ? geom.y1
: (center.y >= geom.y1) ? geom.y0
: ((center.y - geom.y0) >= (geom.y1 - center.y)) ? geom.y0
: geom.y1;
2022-02-16 17:49:00 +13:00
double maxDist = norm(farthestPos - center);
double scale[2] = {1.0, 1.0};
// adjust size for ellipse
if (e_aspect_ratio != 1.0) {
scale[0] = 2.0 * e_aspect_ratio / (e_aspect_ratio + 1);
scale[1] = scale[0] / e_aspect_ratio;
minDist *= std::min(scale[0], scale[1]);
maxDist *= std::max(scale[0], scale[1]);
}
// obtain id range
int minId = (int)std::ceil(minDist / lineInterval);
int maxId = (int)std::floor(maxDist / lineInterval);
glColor3dv(FxGadget::m_selectedColor);
2022-02-16 17:49:00 +13:00
glEnableClientState(GL_VERTEX_ARRAY);
glLineStipple(1, 0x00FF);
glEnable(GL_LINE_STIPPLE);
glVertexPointer(2, GL_DOUBLE, 0, vertices);
glPushMatrix();
glTranslated(center.x, center.y, 0.0);
glRotated(e_angle, 0., 0., 1.);
glScaled(scale[0] * lineInterval, scale[1] * lineInterval, 1.);
for (int id = minId; id <= maxId; id++) {
if (id == 0) continue;
if (id % 2 == 0)
glColor3dv(FxGadget::m_selectedColor);
else
glColor3d(0, 0, 1);
2022-02-16 17:49:00 +13:00
glPushMatrix();
glScaled((double)id, (double)id, 1.);
// draw using vertex array
glDrawArrays(GL_LINE_LOOP, 0, SPIN_NUMVERTS);
glPopMatrix();
}
glDisable(GL_LINE_STIPPLE);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
2022-02-28 20:51:59 +13:00
#define RADIAL_FIELD_NUMSEGMENTS 5
#define RADIAL_COMPASS_NUMSEGMENTS 20
void drawRadialField(const TRectD geom, const TPointD center,
const double lineInterval, const double e_aspect_ratio,
const double e_angle, const double twist,
const double pivot) {
// obtain the nearest and the furthest pos inside the geom
TPointD nearestPos;
nearestPos.x = (center.x <= geom.x0) ? geom.x0
: (center.x >= geom.x1) ? geom.x1
: center.x;
nearestPos.y = (center.y <= geom.y0) ? geom.y0
: (center.y >= geom.y1) ? geom.y1
: center.y;
2022-02-28 20:51:59 +13:00
double minDist = norm(nearestPos - center);
TPointD farthestPos;
farthestPos.x = (center.x <= geom.x0) ? geom.x1
: (center.x >= geom.x1) ? geom.x0
: ((center.x - geom.x0) >= (geom.x1 - center.x)) ? geom.x0
: geom.x1;
farthestPos.y = (center.y <= geom.y0) ? geom.y1
: (center.y >= geom.y1) ? geom.y0
: ((center.y - geom.y0) >= (geom.y1 - center.y)) ? geom.y0
: geom.y1;
2022-02-28 20:51:59 +13:00
double maxDist = norm(farthestPos - center);
double scale[2] = {1.0, 1.0};
// adjust size for ellipse
if (e_aspect_ratio != 1.0) {
scale[0] = 2.0 * e_aspect_ratio / (e_aspect_ratio + 1);
scale[1] = scale[0] / e_aspect_ratio;
minDist *= std::min(scale[0], scale[1]);
maxDist *= std::max(scale[0], scale[1]);
}
// obtain id range
int minId =
(minDist == 0.)
? 0
: (int)std::floor(std::log2(M_PI * minDist / lineInterval)) + 1;
int maxId = (int)std::ceil(std::log2(M_PI * maxDist / lineInterval)) + 1;
struct LineInfo {
double anglePos; // original direction of the line
int birthId; // generation where the line started to be drawn
};
// register lines information
QList<LineInfo> infoList;
// initial lines at minId
int initLineAmount = std::pow(2, minId);
for (int li = 0; li < initLineAmount; li++)
infoList.append({360.0 * (double)li / (double)initLineAmount, minId});
for (int id = minId + 1; id <= maxId; id++) {
// insert between the existing lines
QList<LineInfo>::iterator itr = infoList.end();
while (itr != infoList.begin()) {
double ap;
if (itr == infoList.end())
ap = (360.0 + (*(itr - 1)).anglePos) * 0.5;
else
ap = ((*itr).anglePos + (*(itr - 1)).anglePos) * 0.5;
itr = infoList.insert(itr, {ap, id});
itr--;
}
}
int unitDist =
std::pow(2, (maxId - 1)) - ((minId == 0) ? 0 : std::pow(2, (minId - 1)));
GLdouble *vertices =
new GLdouble[(unitDist * RADIAL_FIELD_NUMSEGMENTS + 1) * 2];
double radiStep = (lineInterval / M_PI) / (double)RADIAL_FIELD_NUMSEGMENTS;
double tmpRad =
(minId == 0) ? 0. : (std::pow(2, (minId - 1)) * lineInterval / M_PI);
for (int v = 0; v < unitDist * RADIAL_FIELD_NUMSEGMENTS + 1; v++) {
double tw = twist * tmpRad / pivot;
vertices[v * 2] = tmpRad * std::cos(tw);
vertices[v * 2 + 1] = tmpRad * std::sin(tw);
tmpRad += radiStep;
}
glColor3d(0, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
glLineStipple(1, 0x00FF);
glEnable(GL_LINE_STIPPLE);
glVertexPointer(2, GL_DOUBLE, 0, vertices);
glPushMatrix();
glTranslated(center.x, center.y, 0.0);
glRotated(e_angle, 0., 0., 1.);
glScaled(scale[0], scale[1], 1.);
int vertexIdOffset =
(minId == 0) ? 0 : std::pow(2, (minId - 1)) * RADIAL_FIELD_NUMSEGMENTS;
for (auto line : infoList) {
glPushMatrix();
glRotated(line.anglePos, 0., 0., 1.);
int startId = (line.birthId == 0) ? 0
: std::pow(2, (line.birthId - 1)) *
RADIAL_FIELD_NUMSEGMENTS -
vertexIdOffset;
// draw using vertex array
glDrawArrays(GL_LINE_STRIP, startId,
unitDist * RADIAL_FIELD_NUMSEGMENTS - startId);
glPopMatrix();
}
glDisable(GL_LINE_STIPPLE);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
delete[] vertices;
}
} // namespace
2016-03-19 06:57:51 +13:00
//*************************************************************************************
// FxGadgetUndo definition
//*************************************************************************************
class FxGadgetUndo final : public TUndo {
2016-06-15 18:43:10 +12:00
struct ParamData {
TDoubleParamP m_param;
double m_oldValue, m_newValue;
bool m_wasKeyframe;
};
2016-03-19 06:57:51 +13:00
private:
2016-06-15 18:43:10 +12:00
std::vector<ParamData> m_params;
int m_frame;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
FxGadgetUndo(const std::vector<TDoubleParamP> &params, int frame)
: m_frame(frame) {
m_params.resize(params.size());
for (int i = 0; i < (int)params.size(); i++) {
m_params[i].m_param = params[i];
m_params[i].m_oldValue = params[i]->getValue(frame);
m_params[i].m_newValue = m_params[i].m_oldValue;
m_params[i].m_wasKeyframe = m_params[i].m_param->isKeyframe(frame);
}
}
2016-06-19 20:06:29 +12:00
void onAdd() override {
2016-06-15 18:43:10 +12:00
for (int i = 0; i < (int)m_params.size(); i++) {
m_params[i].m_newValue = m_params[i].m_param->getValue(m_frame);
}
}
2016-06-19 20:06:29 +12:00
void undo() const override {
2016-06-15 18:43:10 +12:00
for (int i = 0; i < (int)m_params.size(); i++) {
if (!m_params[i].m_wasKeyframe)
m_params[i].m_param->deleteKeyframe(m_frame);
else
m_params[i].m_param->setValue(m_frame, m_params[i].m_oldValue);
}
}
2016-06-19 20:06:29 +12:00
void redo() const override {
2016-06-15 18:43:10 +12:00
for (int i = 0; i < (int)m_params.size(); i++) {
m_params[i].m_param->setValue(m_frame, m_params[i].m_newValue);
}
}
2016-06-19 20:06:29 +12:00
int getSize() const override {
2016-06-15 18:43:10 +12:00
return sizeof(*this) + m_params.size() * sizeof(ParamData);
}
2016-06-19 20:06:29 +12:00
QString getHistoryString() override {
2016-06-15 18:43:10 +12:00
QString str = QObject::tr("Modify Fx Gadget ");
for (int i = 0; i < (int)m_params.size(); i++) {
str += QString::fromStdString(m_params[i].m_param->getName());
if (i != (int)m_params.size() - 1) str += QString::fromStdString(", ");
}
str += QString(" Frame : %1").arg(QString::number(m_frame + 1));
return str;
}
2016-06-19 20:06:29 +12:00
int getHistoryType() override { return HistoryType::Fx; }
2016-03-19 06:57:51 +13:00
};
//*************************************************************************************
// GadgetDragTool definition
//*************************************************************************************
class GadgetDragTool final : public DragTool {
2016-06-15 18:43:10 +12:00
FxGadgetController *m_controller;
FxGadget *m_gadget;
TPointD m_firstPos;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
GadgetDragTool(FxGadgetController *controller, FxGadget *gadget)
: m_controller(controller), m_gadget(gadget) {}
TAffine getMatrix() const { return m_controller->getMatrix().inv(); }
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override {
2016-06-15 18:43:10 +12:00
m_gadget->createUndo();
m_gadget->leftButtonDown(getMatrix() * pos, e);
m_firstPos = pos;
2016-06-15 18:43:10 +12:00
}
2016-06-19 20:06:29 +12:00
void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override {
// precise control with pressing Alt key
if (e.isAltPressed()) {
TPointD precisePos = m_firstPos + (pos - m_firstPos) * 0.1;
m_gadget->leftButtonDrag(getMatrix() * precisePos, e);
} else
m_gadget->leftButtonDrag(getMatrix() * pos, e);
2016-06-15 18:43:10 +12:00
}
2016-06-19 20:06:29 +12:00
void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override {
2021-10-04 20:05:10 +13:00
leftButtonUp();
}
void leftButtonUp() override {
m_gadget->leftButtonUp();
2016-06-15 18:43:10 +12:00
m_gadget->commitUndo();
}
2016-03-19 06:57:51 +13:00
};
//*************************************************************************************
// FxGadget implementation
//*************************************************************************************
FxGadget::FxGadget(FxGadgetController *controller, int handleCount)
2016-06-15 18:43:10 +12:00
: m_id(-1)
, m_selected(-1)
2016-06-15 18:43:10 +12:00
, m_controller(controller)
, m_pixelSize(1)
, m_undo(0)
, m_scaleFactor(1)
, m_handleCount(handleCount) {
2016-06-15 18:43:10 +12:00
controller->assignId(this);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
FxGadget::~FxGadget() {
for (int i = 0; i < (int)m_params.size(); i++)
m_params[i]->removeObserver(this);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::addParam(const TDoubleParamP &param) {
m_params.push_back(param);
param->addObserver(this);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
double FxGadget::getValue(const TDoubleParamP &param) const {
return param->getValue(m_controller->getCurrentFrame());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::setValue(const TDoubleParamP &param, double value) {
param->setValue(m_controller->getCurrentFrame(), value);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TPointD FxGadget::getValue(const TPointParamP &param) const {
return param->getValue(m_controller->getCurrentFrame());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::setValue(const TPointParamP &param, const TPointD &pos) {
param->setValue(m_controller->getCurrentFrame(), pos);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2017-05-18 22:45:18 +12:00
void FxGadget::setPixelSize() {
2022-02-28 11:18:09 +13:00
setPixelSize(sqrt(tglGetPixelSize2()) * m_controller->getDevPixRatio());
2017-05-18 22:45:18 +12:00
}
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::drawTooltip(const TPointD &tooltipPos,
std::string tooltipPosText) {
2022-02-28 11:18:09 +13:00
double unit = sqrt(tglGetPixelSize2()) * m_controller->getDevPixRatio();
2016-06-15 18:43:10 +12:00
glPushMatrix();
glTranslated(tooltipPos.x, tooltipPos.y, 0.0);
double sc = unit * 1.6;
glScaled(sc, sc, 1);
tglDrawText(TPointD(8, -3), tooltipPosText);
glPopMatrix();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::drawDot(const TPointD &pos) {
double r = getPixelSize() * 3;
tglDrawRect(pos.x - r, pos.y - r, pos.x + r, pos.y + r);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::onChange(const TParamChange &) {
m_controller->invalidateViewer();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::createUndo() {
assert(m_undo == 0);
m_undo = new FxGadgetUndo(m_params, m_controller->getCurrentFrame());
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadget::commitUndo() {
assert(m_undo);
TUndoManager::manager()->add(m_undo);
m_undo = 0;
2016-03-19 06:57:51 +13:00
}
//*************************************************************************************
// Specific Gadget Concepts definition
//*************************************************************************************
class PointFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TPointD m_pos;
TDoubleParamP m_xParam, m_yParam;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
PointFxGadget(FxGadgetController *controller, const TPointParamP &param)
: FxGadget(controller), m_xParam(param->getX()), m_yParam(param->getY()) {
addParam(m_xParam);
addParam(m_yParam);
}
PointFxGadget(FxGadgetController *controller, const TDoubleParamP &xParam,
const TDoubleParamP &yParam)
: FxGadget(controller), m_xParam(xParam), m_yParam(yParam) {
addParam(m_xParam);
addParam(m_yParam);
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-06-15 18:43:10 +12:00
TPointD getPoint() const {
return TPointD(getValue(m_xParam), getValue(m_yParam));
}
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void PointFxGadget::draw(bool picking) {
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
TPointD pos(getPoint());
double unit = getPixelSize();
glPushMatrix();
glTranslated(pos.x, pos.y, 0);
double r = unit * 3;
double d = unit * 6;
glBegin(GL_LINES);
glVertex2d(-d, 0);
glVertex2d(-r, 0);
glVertex2d(d, 0);
glVertex2d(r, 0);
glVertex2d(0, -d);
glVertex2d(0, -r);
glVertex2d(0, d);
glVertex2d(0, r);
glEnd();
tglDrawRect(-r, -r, r, r);
glPopMatrix();
glPopName();
if (isSelected()) {
drawTooltip(pos + TPointD(7, 3) * unit, getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void PointFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {}
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void PointFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
if (m_xParam) setValue(m_xParam, pos.x);
if (m_yParam) setValue(m_yParam, pos.y);
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class RadiusFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_radius;
TPointParamP m_center;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
RadiusFxGadget(FxGadgetController *controller, const TDoubleParamP &radius,
const TPointParamP &center)
: FxGadget(controller), m_radius(radius), m_center(center) {
addParam(radius);
}
TPointD getCenter() const;
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TPointD RadiusFxGadget::getCenter() const {
return m_center ? getValue(m_center) : TPointD();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RadiusFxGadget::draw(bool picking) {
if (!m_radius) return;
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
double radius = getValue(m_radius);
TPointD center = getCenter();
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
tglDrawCircle(center, radius);
glDisable(GL_LINE_STIPPLE);
drawDot(center + TPointD(0.707, 0.707) * radius);
glPopName();
if (isSelected()) {
drawTooltip(center + TPointD(0.707, 0.707) * radius, getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RadiusFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {}
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RadiusFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
setValue(m_radius, norm(pos - getCenter()));
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class DistanceFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_distance, m_angle;
int m_grabPos;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
DistanceFxGadget(FxGadgetController *controller,
const TDoubleParamP &distance, const TDoubleParamP &angle)
: FxGadget(controller)
, m_distance(distance)
, m_angle(angle)
, m_grabPos(1) {
addParam(distance);
if (angle) addParam(angle);
}
TPointD getDirection() const {
if (!m_angle) return TPointD(1.0, 0.0);
double angle = getValue(m_angle);
return TPointD(cos(angle), sin(angle));
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DistanceFxGadget::draw(bool picking) {
if (!m_distance) return;
setPixelSize();
glColor3d(0, 0, 1);
double d = getValue(m_distance) * getScaleFactor();
TPointD dir(getDirection());
TPointD u = rotate90(dir) * (getPixelSize() * 10);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
tglDrawSegment(-u, u);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glPushName(getId());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TPointD b, c;
b = dir * (d * 0.5);
c = b - dir * d;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
tglDrawSegment(b - u, b + u);
tglDrawCircle(b, getPixelSize() * 5);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
tglDrawSegment(c - u, c + u);
tglDrawCircle(c, getPixelSize() * 5);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glPopName();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
tglDrawSegment(b, c);
glDisable(GL_LINE_STIPPLE);
if (isSelected()) {
drawTooltip(b + TPointD(5, 5) * getPixelSize(), getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DistanceFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
m_grabPos = (pos.x > 0.0) ? 1 : -1;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DistanceFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
double v = (pos * getDirection()) / getScaleFactor();
v = v * 2 * m_grabPos;
setValue(m_distance, v);
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class AngleFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_param;
TPointD m_pos;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
AngleFxGadget(FxGadgetController *controller, const TDoubleParamP &param,
const TPointD &pos);
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
AngleFxGadget::AngleFxGadget(FxGadgetController *controller,
const TDoubleParamP &param, const TPointD &pos)
: FxGadget(controller), m_param(param), m_pos(pos) {
addParam(param);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void AngleFxGadget::draw(bool picking) {
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
2022-02-28 11:18:09 +13:00
double pixelSize = sqrt(tglGetPixelSize2()) * m_controller->getDevPixRatio();
2016-06-15 18:43:10 +12:00
double r = pixelSize * 40;
double a = pixelSize * 10, b = pixelSize * 5;
tglDrawCircle(m_pos, r);
double phi = getValue(m_param);
glPushMatrix();
glTranslated(m_pos.x, m_pos.y, 0);
glRotated(phi, 0, 0, 1);
glBegin(GL_LINES);
glVertex2d(0, 0);
glVertex2d(r, 0);
glVertex2d(r, 0);
glVertex2d(r - a, b);
glVertex2d(r, 0);
glVertex2d(r - a, -b);
glEnd();
glPopMatrix();
glPopName();
if (isSelected()) {
drawTooltip(m_pos + TPointD(0.707, 0.707) * r, getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void AngleFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {}
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void AngleFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
TPointD d = pos - m_pos;
double phi = atan2(d.y, d.x);
setValue(m_param, phi * M_180_PI);
2016-03-19 06:57:51 +13:00
}
//=============================================================================
2019-11-11 23:35:16 +13:00
class AngleRangeFxGadget final : public FxGadget {
TDoubleParamP m_startAngle, m_endAngle;
TPointParamP m_center;
enum HANDLE { StartAngle = 0, EndAngle, None } m_handle = None;
double m_clickedAngle;
double m_targetAngle, m_anotherAngle;
public:
AngleRangeFxGadget(FxGadgetController *controller,
const TDoubleParamP &startAngle,
const TDoubleParamP &endAngle, const TPointParamP &center);
void draw(bool picking) override;
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2021-10-04 20:05:10 +13:00
void leftButtonUp() override;
2019-11-11 23:35:16 +13:00
};
//---------------------------------------------------------------------------
AngleRangeFxGadget::AngleRangeFxGadget(FxGadgetController *controller,
const TDoubleParamP &startAngle,
const TDoubleParamP &endAngle,
const TPointParamP &center)
: FxGadget(controller, 2)
, m_startAngle(startAngle)
, m_endAngle(endAngle)
, m_center(center) {
addParam(startAngle);
addParam(endAngle);
addParam(center->getX());
addParam(center->getY());
}
//---------------------------------------------------------------------------
void AngleRangeFxGadget::draw(bool picking) {
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
2022-02-28 11:18:09 +13:00
double pixelSize = sqrt(tglGetPixelSize2()) * m_controller->getDevPixRatio();
2019-11-11 23:35:16 +13:00
double r = pixelSize * 200;
double a = pixelSize * 30;
TPointD center = getValue(m_center);
double start = getValue(m_startAngle);
double end = getValue(m_endAngle);
glPushMatrix();
glTranslated(center.x, center.y, 0);
setColorById(StartAngle);
glPushMatrix();
glPushName(getId() + StartAngle);
glRotated(start, 0, 0, 1);
glBegin(GL_LINE_STRIP);
glVertex2d(0, 0);
glVertex2d(r, 0);
// expand handle while dragging
if (m_handle == StartAngle) glVertex2d(r * 5.0, 0);
glEnd();
glPopName();
glPushMatrix();
glTranslated(r * 1.05, 0, 0.0);
glScaled(pixelSize * 1.6, pixelSize * 1.6, 1);
glRotated(-start, 0, 0, 1);
tglDrawText(TPointD(0, 0), "Start Angle");
glPopMatrix();
glPopMatrix();
setColorById(EndAngle);
glPushMatrix();
glPushName(getId() + EndAngle);
glRotated(end, 0, 0, 1);
glBegin(GL_LINE_STRIP);
glVertex2d(0, 0);
glVertex2d(r, 0);
// expand handle while dragging
if (m_handle == EndAngle) glVertex2d(r * 5.0, 0);
glEnd();
glPopName();
glPushMatrix();
glTranslated(r * 1.05, 0, 0.0);
glScaled(pixelSize * 1.6, pixelSize * 1.6, 1);
glRotated(-end, 0, 0, 1);
tglDrawText(TPointD(0, 0), "End Angle");
glPopMatrix();
glPopMatrix();
// draw arc
while (end <= start) end += 360.0;
glColor3d(0, 0, 1);
glBegin(GL_LINE_STRIP);
double angle = start;
double dAngle = 5.0;
while (angle <= end) {
double rad = angle / M_180_PI;
glVertex2d(a * std::cos(rad), a * std::sin(rad));
angle += dAngle;
}
if (angle != end)
glVertex2d(a * std::cos(end / M_180_PI), a * std::sin(end / M_180_PI));
glEnd();
glPopMatrix();
}
//---------------------------------------------------------------------------
void AngleRangeFxGadget::leftButtonDown(const TPointD &pos,
const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
if (m_handle == None) return;
TPointD d = pos - getValue(m_center);
m_clickedAngle = atan2(d.y, d.x) * M_180_PI;
TDoubleParamP target = (m_handle == StartAngle) ? m_startAngle : m_endAngle;
TDoubleParamP another = (m_handle == StartAngle) ? m_endAngle : m_startAngle;
m_targetAngle = getValue(target);
m_anotherAngle = getValue(another);
}
//---------------------------------------------------------------------------
void AngleRangeFxGadget::leftButtonDrag(const TPointD &pos,
const TMouseEvent &e) {
if (m_handle == None) return;
TDoubleParamP target = (m_handle == StartAngle) ? m_startAngle : m_endAngle;
TPointD d = pos - getValue(m_center);
double angle = atan2(d.y, d.x) * M_180_PI;
double targetAngle = m_targetAngle + angle - m_clickedAngle;
// move every 10 degrees when pressing Shift key
if (e.isShiftPressed()) targetAngle = std::round(targetAngle / 10.0) * 10.0;
setValue(target, targetAngle);
// move both angles when pressing Ctrl key
if (e.isCtrlPressed()) {
TDoubleParamP another =
(m_handle == StartAngle) ? m_endAngle : m_startAngle;
double anotherAngle = m_anotherAngle + angle - m_clickedAngle;
if (e.isShiftPressed())
anotherAngle = std::round(anotherAngle / 10.0) * 10.0;
setValue(another, anotherAngle);
}
}
//---------------------------------------------------------------------------
2021-10-04 20:05:10 +13:00
void AngleRangeFxGadget::leftButtonUp() { m_handle = None; }
2019-11-11 23:35:16 +13:00
//=============================================================================
class DiamondFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_param;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
DiamondFxGadget(FxGadgetController *controller, const TDoubleParamP &param)
: FxGadget(controller), m_param(param) {
addParam(param);
}
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-03-19 06:57:51 +13:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {}
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DiamondFxGadget::draw(bool picking) {
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
double size = getValue(m_param);
double r = 3 * getPixelSize();
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex2d(-size + r, r);
glVertex2d(-r, size - r);
glVertex2d(r, size - r);
glVertex2d(size - r, r);
glVertex2d(size - r, -r);
glVertex2d(r, -size + r);
glVertex2d(-r, -size + r);
glVertex2d(-size + r, -r);
glEnd();
glDisable(GL_LINE_STIPPLE);
drawDot(-size, 0);
drawDot(size, 0);
drawDot(0, -size);
drawDot(0, size);
double d = getPixelSize() * 3;
glPopName();
if (isSelected()) {
drawTooltip(TPointD(d, size - d), getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void DiamondFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
double sz = fabs(pos.x) + fabs(pos.y);
2016-06-15 18:43:10 +12:00
if (sz < 0.1) sz = 0.1;
setValue(m_param, sz);
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class SizeFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_lx, m_ly;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
SizeFxGadget(FxGadgetController *controller, const TDoubleParamP &lx,
const TDoubleParamP &ly)
: FxGadget(controller), m_lx(lx), m_ly(ly) {
addParam(lx);
if (ly) addParam(ly);
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {}
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SizeFxGadget::draw(bool picking) {
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
double lx = getValue(m_lx), ly = m_ly ? getValue(m_ly) : lx;
double r = getPixelSize() * 3;
glLineStipple(1, 0xCCCC);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex2d(0, 0);
glVertex2d(lx, 0);
glVertex2d(0, 0);
glVertex2d(0, ly);
glVertex2d(lx, 0);
glVertex2d(lx, ly - r);
glVertex2d(0, ly);
glVertex2d(lx - r, ly);
glEnd();
glDisable(GL_LINE_STIPPLE);
drawDot(lx, ly);
double d = getPixelSize() * 3;
glPopName();
if (isSelected()) {
drawTooltip(TPointD(lx, ly), getLabel());
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void SizeFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
if (m_ly)
setValue(m_lx, std::max(pos.x, 0.1)), setValue(m_ly, std::max(pos.y, 0.1));
else
setValue(m_lx, std::max({pos.x, pos.y, 0.1}));
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class RectFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TDoubleParamP m_width, m_height;
TPointParamP m_center;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
int m_picked;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
enum { None, Corner, HorizontalSide, VerticalSide };
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
RectFxGadget(FxGadgetController *controller, const TDoubleParamP &width,
const TDoubleParamP &height, const TPointParamP &center)
: FxGadget(controller)
, m_width(width)
, m_height(height)
, m_center(center)
, m_picked(None) {
addParam(width);
addParam(height);
if (center) addParam(center->getX()), addParam(center->getY());
}
TPointD getCenter() const {
return m_center ? getValue(m_center) : TPointD();
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override;
2016-06-15 18:43:10 +12:00
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RectFxGadget::draw(bool picking) {
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
glPushMatrix();
TPointD center = getCenter();
glTranslated(center.x, center.y, 0);
double w_2 = 0.5 * getValue(m_width);
double h_2 = 0.5 * getValue(m_height);
double r = getPixelSize() * 3;
glLineStipple(1, 0xCCCC);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex2d(-w_2 + r, -h_2);
glVertex2d(w_2 - r, -h_2);
glVertex2d(-w_2 + r, h_2);
glVertex2d(w_2 - r, h_2);
glVertex2d(-w_2, -h_2 + r);
glVertex2d(-w_2, h_2 - r);
glVertex2d(w_2, -h_2 + r);
glVertex2d(w_2, h_2 - r);
glEnd();
glDisable(GL_LINE_STIPPLE);
drawDot(w_2, h_2);
drawDot(-w_2, h_2);
drawDot(w_2, -h_2);
drawDot(-w_2, -h_2);
glPopMatrix();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RectFxGadget::leftButtonDown(const TPointD &ppos, const TMouseEvent &) {
TPointD pos = ppos - getCenter();
m_picked = None;
double w_2 = 0.5 * getValue(m_width);
double h_2 = 0.5 * getValue(m_height);
double x = fabs(pos.x);
double y = fabs(pos.y);
double r = getPixelSize() * 15;
if (fabs(w_2 - x) < r && fabs(y - h_2) < r)
m_picked = Corner;
else if (fabs(w_2 - x) < r && y < h_2)
m_picked = VerticalSide;
else if (fabs(h_2 - y) < r && x < w_2)
m_picked = HorizontalSide;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void RectFxGadget::leftButtonDrag(const TPointD &ppos, const TMouseEvent &) {
TPointD pos = ppos - getCenter();
double w = fabs(pos.x), h = fabs(pos.y);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (m_picked == Corner || m_picked == VerticalSide)
setValue(m_width, 2.0 * w);
if (m_picked == Corner || m_picked == HorizontalSide)
setValue(m_height, 2.0 * h);
2016-03-19 06:57:51 +13:00
}
//=============================================================================
class PolarFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TPointD m_pos;
TDoubleParamP m_phiParam, m_lengthParam;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
PolarFxGadget(FxGadgetController *controller, const TPointD &pos,
const TDoubleParamP &phiParam, const TDoubleParamP &lengthParam)
: FxGadget(controller)
, m_pos(pos)
, m_phiParam(phiParam)
, m_lengthParam(lengthParam) {
addParam(phiParam);
addParam(lengthParam);
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override {
2016-06-15 18:43:10 +12:00
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
double pixelSize = getPixelSize();
double r = getValue(m_lengthParam);
double a = pixelSize * 10, b = pixelSize * 5, c = pixelSize * 4;
// tglDrawCircle(m_pos, r);
double phi = getValue(m_phiParam);
glPushMatrix();
glTranslated(m_pos.x, m_pos.y, 0);
glRotated(phi, 0, 0, 1);
double rr = r - c;
if (rr > 0) {
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINE_STRIP);
glVertex2d(0, 0);
glVertex2d(rr, 0);
glEnd();
glDisable(GL_LINE_STIPPLE);
}
glBegin(GL_LINES);
glVertex2d(rr, 0);
glVertex2d(rr - a, b);
glVertex2d(rr, 0);
glVertex2d(rr - a, -b);
glEnd();
glTranslated(r, 0, 0);
glRotated(-phi, 0, 0, 1);
drawDot(0, 0);
glPopMatrix();
glPopName();
if (isSelected()) {
double phiRad = phi * M_PI_180;
TPointD toolTipPos = m_pos + r * TPointD(cos(phiRad), sin(phiRad));
drawTooltip(toolTipPos, getLabel());
}
}
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {}
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override {
2016-06-15 18:43:10 +12:00
TPointD d = pos - m_pos;
double phi = atan2(d.y, d.x);
double length = norm(d);
setValue(m_phiParam, phi * M_180_PI);
setValue(m_lengthParam, length);
}
2016-03-19 06:57:51 +13:00
};
//=============================================================================
class VectorFxGadget final : public FxGadget {
2016-06-15 18:43:10 +12:00
TPointParamP m_pa, m_pb;
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
VectorFxGadget(FxGadgetController *controller, const TPointParamP &pa,
const TPointParamP &pb)
: FxGadget(controller), m_pa(pa), m_pb(pb) {
2016-06-15 18:43:10 +12:00
addParam(pa->getX());
addParam(pa->getY());
addParam(pb->getX());
addParam(pb->getY());
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override {
2016-06-15 18:43:10 +12:00
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
// glPushName(getId());
2016-06-15 18:43:10 +12:00
double pixelSize = getPixelSize();
TPointD pa = getValue(m_pa);
TPointD pb = getValue(m_pb);
TPointD dab = pb - pa;
double ab2 = norm2(dab);
if (ab2 > 0.0001) {
double ab = sqrt(ab2);
TPointD u = dab * (1.0 / ab);
TPointD v = rotate90(u);
double a = pixelSize * 10, b = pixelSize * 5;
double c = pixelSize * 4;
TPointD pbb = pb - u * c;
if (ab - c > 0) {
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
tglDrawSegment(pa, pbb);
glDisable(GL_LINE_STIPPLE);
}
tglDrawSegment(pbb, pbb - u * a + v * b);
tglDrawSegment(pbb, pbb - u * a - v * b);
// drawDot(pa);
// drawDot(pb);
} // else
// drawDot(pa);
// glPopName();
2016-06-15 18:43:10 +12:00
}
2016-06-19 20:06:29 +12:00
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {}
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override {}
2016-03-19 06:57:51 +13:00
};
//=============================================================================
class QuadFxGadget final : public FxGadget {
TPointParamP m_TL, m_TR, m_BR, m_BL;
enum HANDLE {
Body = 0,
TopLeft,
TopRight,
BottomRight,
BottomLeft,
TopEdge,
RightEdge,
BottomEdge,
LeftEdge,
None
} m_handle = None;
TPointD m_pivot;
TPointD m_dragStartPos;
TPointD m_startTL, m_startTR, m_startBR, m_startBL;
2016-03-19 06:57:51 +13:00
public:
QuadFxGadget(FxGadgetController *controller, const TPointParamP &topLeft,
const TPointParamP &topRight, const TPointParamP &bottomRight,
const TPointParamP &bottomLeft)
: FxGadget(controller, 9)
, m_TL(topLeft)
, m_TR(topRight)
, m_BR(bottomRight)
, m_BL(bottomLeft) {
addParam(topLeft->getX());
addParam(topLeft->getY());
addParam(topRight->getX());
addParam(topRight->getY());
addParam(bottomRight->getX());
addParam(bottomRight->getY());
addParam(bottomLeft->getX());
addParam(bottomLeft->getY());
2016-06-15 18:43:10 +12:00
}
2016-06-19 20:06:29 +12:00
void draw(bool picking) override {
int idBase = getId();
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
auto id2Str = [](const HANDLE handleId) -> std::string {
switch (handleId) {
case TopLeft:
return "Top Left";
case TopRight:
return "Top Right";
case BottomRight:
return "Bottom Right";
case BottomLeft:
return "Bottom Left";
default:
return "";
}
};
auto drawPoint = [&](const TPointD &pos, int id) {
setColorById(id);
glPushName(idBase + id);
double unit = getPixelSize();
glPushMatrix();
glTranslated(pos.x, pos.y, 0);
double r = unit * 3;
tglDrawRect(-r, -r, r, r);
glPopMatrix();
glPopName();
if (isSelected(id) && id >= TopLeft && id <= BottomLeft) {
drawTooltip(pos + TPointD(7, 3) * unit,
id2Str((HANDLE)id) + getLabel());
}
};
2016-06-15 18:43:10 +12:00
setPixelSize();
// lines for moving all vertices
glPushName(idBase + Body);
setColorById(Body);
double pixelSize = getPixelSize();
TPointD topLeft = getValue(m_TL);
TPointD topRight = getValue(m_TR);
TPointD bottomRight = getValue(m_BR);
TPointD bottomLeft = getValue(m_BL);
2016-06-15 18:43:10 +12:00
glLineStipple(1, 0xCCCC);
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINE_STRIP);
tglVertex(topLeft);
tglVertex(topRight);
tglVertex(bottomRight);
tglVertex(bottomLeft);
tglVertex(topLeft);
2016-06-15 18:43:10 +12:00
glEnd();
glDisable(GL_LINE_STIPPLE);
glPopName();
// corners
drawPoint(topLeft, TopLeft);
drawPoint(topRight, TopRight);
drawPoint(bottomRight, BottomRight);
drawPoint(bottomLeft, BottomLeft);
// center of the edges
drawPoint((topLeft + topRight) * 0.5, TopEdge);
drawPoint((topRight + bottomRight) * 0.5, RightEdge);
drawPoint((bottomRight + bottomLeft) * 0.5, BottomEdge);
drawPoint((bottomLeft + topLeft) * 0.5, LeftEdge);
2016-06-15 18:43:10 +12:00
}
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2021-10-04 20:05:10 +13:00
void leftButtonUp() override;
2016-03-19 06:57:51 +13:00
};
//---------------------------------------------------------------------------
void QuadFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
m_dragStartPos = pos;
m_startTL = getValue(m_TL);
m_startTR = getValue(m_TR);
m_startBR = getValue(m_BR);
m_startBL = getValue(m_BL);
m_pivot = (m_startTL + m_startTR + m_startBR + m_startBL) * 0.25;
}
//---------------------------------------------------------------------------
void QuadFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
TPointD offset = pos - m_dragStartPos;
auto scaleShape = [&](const TPointD &start, const TPointD &pivot) {
TPointD startVec = start - pivot;
TPointD endVec = start + offset - pivot;
TPointD scaleFac((startVec.x == 0.0) ? 1.0 : endVec.x / startVec.x,
(startVec.y == 0.0) ? 1.0 : endVec.y / startVec.y);
if (e.isShiftPressed()) {
if (std::abs(scaleFac.x) > std::abs(scaleFac.y))
scaleFac.y = scaleFac.x;
else
scaleFac.x = scaleFac.y;
}
if (m_startTL != pivot)
setValue(m_TL, pivot + hadamard((m_startTL - pivot), scaleFac));
if (m_startTR != pivot)
setValue(m_TR, pivot + hadamard((m_startTR - pivot), scaleFac));
if (m_startBR != pivot)
setValue(m_BR, pivot + hadamard((m_startBR - pivot), scaleFac));
if (m_startBL != pivot)
setValue(m_BL, pivot + hadamard((m_startBL - pivot), scaleFac));
};
auto doCorner = [&](const TPointParamP point, const TPointD &start,
const TPointD &opposite) {
if (e.isCtrlPressed())
setValue(point, start + offset);
else if (e.isAltPressed())
scaleShape(start, m_pivot);
else
scaleShape(start, opposite);
};
auto doEdge = [&](const TPointParamP p1, const TPointParamP p2) {
if (e.isShiftPressed()) {
if (std::abs(offset.x) > std::abs(offset.y))
offset.y = 0;
else
offset.x = 0;
}
if (m_TL == p1 || m_TL == p2)
setValue(m_TL, m_startTL + offset);
else if (e.isAltPressed())
setValue(m_TL, m_startTL - offset);
if (m_TR == p1 || m_TR == p2)
setValue(m_TR, m_startTR + offset);
else if (e.isAltPressed())
setValue(m_TR, m_startTR - offset);
if (m_BR == p1 || m_BR == p2)
setValue(m_BR, m_startBR + offset);
else if (e.isAltPressed())
setValue(m_BR, m_startBR - offset);
if (m_BL == p1 || m_BL == p2)
setValue(m_BL, m_startBL + offset);
else if (e.isAltPressed())
setValue(m_BL, m_startBL - offset);
};
auto pointRotate = [&](const TPointD pos, const double angle) {
TPointD p = pos - m_pivot;
return m_pivot + TPointD(p.x * std::cos(angle) - p.y * std::sin(angle),
p.x * std::sin(angle) + p.y * std::cos(angle));
};
switch (m_handle) {
case Body:
if (e.isCtrlPressed()) { // rotate
TPointD startVec = m_dragStartPos - m_pivot;
TPointD currentVec = pos - m_pivot;
if (currentVec == TPointD()) return;
double angle = std::atan2(currentVec.y, currentVec.x) -
std::atan2(startVec.y, startVec.x);
if (e.isShiftPressed()) {
angle = std::round(angle / (M_PI / 2.0)) * (M_PI / 2.0);
}
setValue(m_TL, pointRotate(m_startTL, angle));
setValue(m_TR, pointRotate(m_startTR, angle));
setValue(m_BR, pointRotate(m_startBR, angle));
setValue(m_BL, pointRotate(m_startBL, angle));
} else { // translate
// move all shapes
if (e.isShiftPressed()) {
if (std::abs(offset.x) > std::abs(offset.y))
offset.y = 0;
else
offset.x = 0;
}
setValue(m_TL, m_startTL + offset);
setValue(m_TR, m_startTR + offset);
setValue(m_BR, m_startBR + offset);
setValue(m_BL, m_startBL + offset);
}
break;
case TopLeft:
doCorner(m_TL, m_startTL, m_startBR);
break;
case TopRight:
doCorner(m_TR, m_startTR, m_startBL);
break;
case BottomRight:
doCorner(m_BR, m_startBR, m_startTL);
break;
case BottomLeft:
doCorner(m_BL, m_startBL, m_startTR);
break;
case TopEdge:
doEdge(m_TL, m_TR);
break;
case RightEdge:
doEdge(m_TR, m_BR);
break;
case BottomEdge:
doEdge(m_BR, m_BL);
break;
case LeftEdge:
doEdge(m_BL, m_TL);
break;
default:
break;
}
}
//---------------------------------------------------------------------------
2021-10-04 20:05:10 +13:00
void QuadFxGadget::leftButtonUp() { m_handle = None; }
2019-11-14 15:32:32 +13:00
//=============================================================================
class LinearRangeFxGadget final : public FxGadget {
TPointParamP m_start, m_end;
enum HANDLE { Body = 0, Start, End, None } m_handle = None;
TPointD m_clickedPos;
TPointD m_targetPos, m_anotherPos;
public:
LinearRangeFxGadget(FxGadgetController *controller,
const TPointParamP &startPoint,
const TPointParamP &endPoint);
void draw(bool picking) override;
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2021-10-04 20:05:10 +13:00
void leftButtonUp() override;
2019-11-14 15:32:32 +13:00
};
//---------------------------------------------------------------------------
LinearRangeFxGadget::LinearRangeFxGadget(FxGadgetController *controller,
const TPointParamP &startPoint,
const TPointParamP &endPoint)
: FxGadget(controller, 3), m_start(startPoint), m_end(endPoint) {
addParam(startPoint->getX());
addParam(startPoint->getY());
addParam(endPoint->getX());
addParam(endPoint->getY());
}
//---------------------------------------------------------------------------
void LinearRangeFxGadget::draw(bool picking) {
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
auto drawPoint = [&]() {
double r = getPixelSize() * 3;
double d = getPixelSize() * 6;
glBegin(GL_LINES);
glVertex2d(-d, 0);
glVertex2d(-r, 0);
glVertex2d(d, 0);
glVertex2d(r, 0);
glVertex2d(0, -d);
glVertex2d(0, -r);
glVertex2d(0, d);
glVertex2d(0, r);
glEnd();
tglDrawRect(-r, -r, r, r);
};
setPixelSize();
double r = getPixelSize() * 200;
double a = getPixelSize() * 5;
TPointD start = getValue(m_start);
TPointD end = getValue(m_end);
glPushMatrix();
if (start != end) {
// draw lines perpendicular to the line between ends
double angle = std::atan2(start.x - end.x, end.y - start.y) * M_180_PI;
// start
setColorById(Start);
glPushMatrix();
glTranslated(start.x, start.y, 0);
glRotated(angle, 0, 0, 1);
if (m_handle == Start) glScaled(5.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2d(-r, 0);
glVertex2d(r, 0);
glEnd();
glPopMatrix();
// end
setColorById(End);
glPushMatrix();
glTranslated(end.x, end.y, 0);
glRotated(angle, 0, 0, 1);
if (m_handle == End) glScaled(5.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
glVertex2d(-r, 0);
glVertex2d(r, 0);
glEnd();
glPopMatrix();
// line body
setColorById(Body);
glPushName(getId() + Body);
glBegin(GL_LINES);
glVertex2d(start.x, start.y);
glVertex2d(end.x, end.y);
glEnd();
// small dash at the center
glPushMatrix();
glTranslated((start.x + end.x) / 2.0, (start.y + end.y) / 2.0, 0);
glRotated(angle, 0, 0, 1);
glBegin(GL_LINES);
glVertex2d(-a, 0);
glVertex2d(a, 0);
glEnd();
glPopMatrix();
glPopName();
}
// start point
setColorById(Start);
glPushName(getId() + Start);
glPushMatrix();
glTranslated(start.x, start.y, 0);
drawPoint();
glPopMatrix();
glPopName();
drawTooltip(start + TPointD(7, 3) * getPixelSize(), "Start");
// end point
setColorById(End);
glPushName(getId() + End);
glPushMatrix();
glTranslated(end.x, end.y, 0);
drawPoint();
glPopMatrix();
glPopName();
drawTooltip(end + TPointD(7, 3) * getPixelSize(), "End");
glPopMatrix();
}
//---------------------------------------------------------------------------
void LinearRangeFxGadget::leftButtonDown(const TPointD &pos,
const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
if (m_handle == None) return;
m_clickedPos = pos;
m_targetPos = (m_handle == Start || m_handle == Body) ? getValue(m_start)
: getValue(m_end);
2019-11-14 15:32:32 +13:00
m_anotherPos = (m_handle == Start || m_handle == Body) ? getValue(m_end)
: getValue(m_start);
}
//---------------------------------------------------------------------------
void LinearRangeFxGadget::leftButtonDrag(const TPointD &pos,
const TMouseEvent &e) {
if (m_handle == None) return;
TPointD d = pos - m_clickedPos;
if (m_handle == Body) {
setValue(m_start, m_targetPos + d);
setValue(m_end, m_anotherPos + d);
return;
}
TPointParamP target = (m_handle == Start) ? m_start : m_end;
if (m_targetPos != m_anotherPos && e.isShiftPressed()) {
TPointD vecA = m_targetPos - m_anotherPos;
TPointD vecB = m_targetPos + d - m_anotherPos;
2019-11-22 04:15:47 +13:00
d = vecA * ((vecA.x * vecB.x + vecA.y * vecB.y) /
(vecA.x * vecA.x + vecA.y * vecA.y) -
1.0);
2019-11-14 15:32:32 +13:00
}
setValue(target, m_targetPos + d);
if (e.isCtrlPressed()) {
TPointParamP another = (m_handle == Start) ? m_end : m_start;
setValue(another, m_anotherPos - d);
}
}
//---------------------------------------------------------------------------
2021-10-04 20:05:10 +13:00
void LinearRangeFxGadget::leftButtonUp() { m_handle = None; }
//=============================================================================
class CompassFxGadget final : public FxGadget {
TPointParamP m_center;
2022-02-16 17:49:00 +13:00
TDoubleParamP m_ellipse_aspect_ratio;
TDoubleParamP m_ellipse_angle;
2022-02-28 20:51:59 +13:00
TDoubleParamP m_twist;
enum HANDLE { Body = 0, Near, Far, None } m_handle = None;
TPointD m_clickedPos, m_mousePos;
TPointD m_targetPos, m_anotherPos;
bool m_isSpin;
public:
CompassFxGadget(FxGadgetController *controller,
2022-02-16 17:49:00 +13:00
const TPointParamP &centerPoint, bool isSpin = false,
const TDoubleParamP &ellipse_aspect_ratio = TDoubleParamP(),
2022-02-28 20:51:59 +13:00
const TDoubleParamP &ellipse_angle = TDoubleParamP(),
const TDoubleParamP &twist = TDoubleParamP());
void draw(bool picking) override;
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
2021-10-04 20:05:10 +13:00
void leftButtonUp() override;
};
//---------------------------------------------------------------------------
CompassFxGadget::CompassFxGadget(FxGadgetController *controller,
2022-02-16 17:49:00 +13:00
const TPointParamP &centerPoint, bool isSpin,
const TDoubleParamP &ellipse_aspect_ratio,
2022-02-28 20:51:59 +13:00
const TDoubleParamP &ellipse_angle,
const TDoubleParamP &twist)
2022-02-16 17:49:00 +13:00
: FxGadget(controller, 3)
, m_center(centerPoint)
, m_isSpin(isSpin)
, m_ellipse_aspect_ratio(ellipse_aspect_ratio)
2022-02-28 20:51:59 +13:00
, m_ellipse_angle(ellipse_angle)
, m_twist(twist) {
addParam(centerPoint->getX());
addParam(centerPoint->getY());
2022-02-16 17:49:00 +13:00
if (ellipse_aspect_ratio) addParam(ellipse_aspect_ratio);
if (ellipse_angle) addParam(ellipse_angle);
}
//---------------------------------------------------------------------------
void CompassFxGadget::draw(bool picking) {
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
auto drawArrow = [&]() {
double arrowLength = getPixelSize() * 20;
double arrowTip = getPixelSize() * 5;
glBegin(GL_LINES);
glVertex2d(-arrowLength, 0.0);
glVertex2d(arrowLength, 0.0);
glVertex2d(-arrowLength + arrowTip, arrowTip);
glVertex2d(-arrowLength, 0.0);
glVertex2d(-arrowLength + arrowTip, -arrowTip);
glVertex2d(-arrowLength, 0.0);
glVertex2d(arrowLength - arrowTip, arrowTip);
glVertex2d(arrowLength, 0.0);
glVertex2d(arrowLength - arrowTip, -arrowTip);
glVertex2d(arrowLength, 0.0);
glEnd();
};
setPixelSize();
double lineHalf = getPixelSize() * 100;
double lineInterval = getPixelSize() * 50;
double r = getPixelSize() * 3;
glPushMatrix();
TPointD center = getValue(m_center);
double dCenter = norm(center);
2022-02-16 17:49:00 +13:00
double e_aspect_ratio =
(m_ellipse_aspect_ratio) ? getValue(m_ellipse_aspect_ratio) : 1.0;
2022-02-28 20:51:59 +13:00
double e_angle = (m_ellipse_angle) ? getValue(m_ellipse_angle) : 0.0;
TRectD cameraRect = m_controller->getCameraRect();
double pivot = getPixelSize() * cameraRect.getLy() / 2.0;
double twist = (m_twist) ? getValue(m_twist) * M_PI_180 : 0.0;
2022-02-16 17:49:00 +13:00
TPointD handleVec;
if (dCenter > lineHalf) {
handleVec = normalize(center) * lineHalf;
setColorById(Body);
glPushName(getId() + Body);
glBegin(GL_LINES);
glVertex2d(handleVec.x * 0.95, handleVec.y * 0.95);
glVertex2d(-handleVec.x * 0.95, -handleVec.y * 0.95);
glEnd();
glPopName();
double angle = std::atan2(-center.y, -center.x) * M_180_PI;
double theta = M_180_PI * lineInterval / dCenter;
2022-02-16 17:49:00 +13:00
// draw spin lines field
2022-02-28 20:51:59 +13:00
if (isSelected() && !isSelected(None) && m_ellipse_aspect_ratio &&
m_ellipse_angle) {
2022-02-16 17:49:00 +13:00
TRectD geom = m_controller->getGeometry();
2022-02-28 20:51:59 +13:00
if (m_isSpin)
drawSpinField(geom, center, lineInterval, e_aspect_ratio, e_angle);
else
drawRadialField(geom, center, lineInterval, e_aspect_ratio, e_angle,
twist, pivot);
2022-02-16 17:49:00 +13:00
} else {
// draw guides
glColor3d(0, 0, 1);
glLineStipple(1, 0x00FF);
glEnable(GL_LINE_STIPPLE);
glPushMatrix();
glTranslated(center.x, center.y, 0);
if (!m_isSpin) { // radial direction
2022-02-28 20:51:59 +13:00
if (areAlmostEqual(twist, 0.0)) {
for (int i = -3; i <= 3; i++) {
if (i == 0) continue;
glPushMatrix();
glRotated(theta * (double)i + angle, 0, 0, 1);
glBegin(GL_LINES);
glVertex2d(dCenter - lineHalf, 0.0);
glVertex2d(dCenter + lineHalf, 0.0);
glEnd();
glPopMatrix();
}
} else if (areAlmostEqual(e_aspect_ratio, 1.0)) { // twist case
for (int i = -3; i <= 3; i++) {
if (i == 0) continue;
glPushMatrix();
glRotated(theta * (double)i + angle, 0, 0, 1);
glBegin(GL_LINE_STRIP);
for (int j = 0; j <= RADIAL_COMPASS_NUMSEGMENTS; j++) {
double tmp_d = dCenter - lineHalf +
(double)j * 2.0 * lineHalf /
(double)RADIAL_COMPASS_NUMSEGMENTS;
double tmp_tw_radian = twist * (tmp_d - dCenter) / pivot;
glVertex2d(tmp_d * std::cos(tmp_tw_radian),
tmp_d * std::sin(tmp_tw_radian));
}
glEnd();
glPopMatrix();
}
} else { // elliptical + twist case
double scale[2];
scale[0] = 2.0 * e_aspect_ratio / (e_aspect_ratio + 1);
scale[1] = scale[0] / e_aspect_ratio;
2022-02-16 17:49:00 +13:00
glPushMatrix();
2022-02-28 20:51:59 +13:00
glRotated(e_angle, 0., 0., 1.);
glScaled(scale[0], scale[1], 1.);
QTransform tr =
QTransform().rotate(e_angle).scale(scale[0], scale[1]).inverted();
for (int i = -3; i <= 3; i++) {
if (i == 0) continue;
double tmp_angle_radian = (theta * (double)i + angle) * M_PI_180;
QPointF lineCenter(dCenter * std::cos(tmp_angle_radian),
dCenter * std::sin(tmp_angle_radian));
lineCenter = tr.map(lineCenter);
tmp_angle_radian = std::atan2(lineCenter.y(), lineCenter.x());
double dLineCenter = QVector2D(lineCenter).length();
double tmpLineHalf = lineHalf * dLineCenter / dCenter;
glBegin(GL_LINE_STRIP);
for (int j = 0; j <= RADIAL_COMPASS_NUMSEGMENTS; j++) {
double tmp_d = dLineCenter - tmpLineHalf +
(double)j * 2.0 * tmpLineHalf /
(double)RADIAL_COMPASS_NUMSEGMENTS;
double tmp_tw_radian = twist * (tmp_d - dLineCenter) / pivot;
QPointF p(tmp_d * std::cos(tmp_angle_radian + tmp_tw_radian),
tmp_d * std::sin(tmp_angle_radian + tmp_tw_radian));
glVertex2d(p.x(), p.y());
}
glEnd();
}
2022-02-16 17:49:00 +13:00
glPopMatrix();
}
} else { // rotational direction
2022-02-16 17:49:00 +13:00
if (areAlmostEqual(e_aspect_ratio, 1.0)) {
for (int i = -2; i <= 2; i++) {
double tmpRad = dCenter + (double)i * lineInterval;
double d_angle = (lineInterval / dCenter) * 6.0 / 10.0;
glBegin(GL_LINE_STRIP);
for (int r = -5; r <= 5; r++) {
double tmpAngle = (double)r * d_angle + angle * M_PI_180;
glVertex2d(tmpRad * std::cos(tmpAngle),
tmpRad * std::sin(tmpAngle));
}
glEnd();
}
2022-02-28 20:51:59 +13:00
} else { // elliptical case
2022-02-16 17:49:00 +13:00
double scale[2];
scale[0] = 2.0 * e_aspect_ratio / (e_aspect_ratio + 1);
scale[1] = scale[0] / e_aspect_ratio;
glRotated(e_angle, 0., 0., 1.);
glScaled(scale[0], scale[1], 1.);
QTransform tr = QTransform()
.translate(center.x, center.y)
.rotate(e_angle)
.scale(scale[0], scale[1])
.inverted();
QPointF begin = tr.map(QPointF(handleVec.x, handleVec.y));
QPointF end = tr.map(QPointF(-handleVec.x, -handleVec.y));
angle = std::atan2(begin.y(), begin.x());
double distBegin = QVector2D(begin).length();
double distEnd = QVector2D(end).length();
for (int i = 0; i <= 4; i++) {
double tmpRad = distBegin + (double)i * (distEnd - distBegin) / 4.;
double d_angle = (lineInterval / dCenter) * 6.0 / 10.0;
glBegin(GL_LINE_STRIP);
for (int r = -5; r <= 5; r++) {
double tmpAngle = (double)r * d_angle + angle;
glVertex2d(tmpRad * std::cos(tmpAngle),
tmpRad * std::sin(tmpAngle));
}
glEnd();
}
}
}
}
glPopMatrix();
glDisable(GL_LINE_STIPPLE);
for (int id = Near; id <= Far; id++) {
TPointD hPos = (id == Near) ? handleVec : -handleVec;
setColorById(id);
glPushName(getId() + id);
glPushMatrix();
glTranslated(hPos.x, hPos.y, 0);
tglDrawRect(-r, -r, r, r);
glPopMatrix();
glPopName();
}
}
if (m_handle == Body) {
glPushMatrix();
TPointD centerOffset = center - m_targetPos;
handleVec = normalize(m_targetPos) * lineHalf;
glTranslated(centerOffset.x, centerOffset.y, 0);
glBegin(GL_LINES);
glVertex2d(handleVec.x, handleVec.y);
glVertex2d(-handleVec.x, -handleVec.y);
glEnd();
glPopMatrix();
}
glPopMatrix();
}
//---------------------------------------------------------------------------
void CompassFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
if (m_handle == None) return;
m_clickedPos = pos;
m_targetPos = getValue(m_center);
}
//---------------------------------------------------------------------------
void CompassFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
if (m_handle == None) return;
TPointD d = pos - m_clickedPos;
if (m_handle == Body) {
setValue(m_center, m_targetPos + d);
return;
}
double angle =
std::atan2(pos.y, pos.x) - std::atan2(m_clickedPos.y, m_clickedPos.x);
double scale = norm(pos) / norm(m_clickedPos);
QTransform transform;
QPointF p = transform.rotateRadians(angle)
.scale(scale, scale)
.map(QPointF(m_targetPos.x, m_targetPos.y));
setValue(m_center, TPointD(p.x(), p.y()));
}
//---------------------------------------------------------------------------
2021-10-04 20:05:10 +13:00
void CompassFxGadget::leftButtonUp() { m_handle = None; }
2021-01-20 19:33:21 +13:00
//=============================================================================
class RainbowWidthFxGadget final : public FxGadget {
TDoubleParamP m_widthScale;
TDoubleParamP m_radius;
TPointParamP m_center;
enum HANDLE { Outside = 0, Inside, None } m_handle = None;
public:
RainbowWidthFxGadget(FxGadgetController *controller,
const TDoubleParamP &widthScale,
const TDoubleParamP &radius, const TPointParamP &center)
: FxGadget(controller, 2)
, m_widthScale(widthScale)
, m_radius(radius)
, m_center(center) {
addParam(widthScale);
}
void draw(bool picking) override;
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
};
//---------------------------------------------------------------------------
void RainbowWidthFxGadget::draw(bool picking) {
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
double radius = getValue(m_radius);
TPointD center = getValue(m_center);
double widthScale = getValue(m_widthScale);
double w = widthScale * radius / 41.3;
glPushName(getId() + Outside);
glLineStipple(1, 0x1C47);
glEnable(GL_LINE_STIPPLE);
tglDrawCircle(center, radius + w);
glDisable(GL_LINE_STIPPLE);
drawDot(center + TPointD(0.707, 0.707) * (radius + w));
glPopName();
if (isSelected(Outside)) {
drawTooltip(center + TPointD(0.707, 0.707) * (radius + w), getLabel());
}
glPushName(getId() + Inside);
glLineStipple(1, 0x1C47);
glEnable(GL_LINE_STIPPLE);
tglDrawCircle(center, radius - w);
glDisable(GL_LINE_STIPPLE);
drawDot(center + TPointD(0.707, 0.707) * (radius - w));
glPopName();
if (isSelected(Inside)) {
drawTooltip(center + TPointD(0.707, 0.707) * (radius - w), getLabel());
}
}
//---------------------------------------------------------------------------
void RainbowWidthFxGadget::leftButtonDown(const TPointD &pos,
const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
}
//---------------------------------------------------------------------------
void RainbowWidthFxGadget::leftButtonDrag(const TPointD &pos,
const TMouseEvent &) {
if (m_handle == None) return;
double radius = getValue(m_radius);
double wpos = norm(pos - getValue(m_center));
double width = (m_handle == Outside) ? wpos - radius : radius - wpos;
double scale = (width * 41.3) / (radius * 1.0);
double min, max, step;
m_widthScale->getValueRange(min, max, step);
setValue(m_widthScale, std::min(max, std::max(min, scale)));
}
2022-02-16 17:49:00 +13:00
//=============================================================================
class EllipseFxGadget final : public FxGadget {
TDoubleParamP m_radius;
TDoubleParamP m_xParam, m_yParam;
TDoubleParamP m_aspect_ratio;
TDoubleParamP m_angle;
2022-02-28 20:51:59 +13:00
TDoubleParamP m_twist;
2022-02-16 17:49:00 +13:00
TPointD m_pos;
2022-02-28 20:51:59 +13:00
bool m_isSpin;
enum HANDLE { Radius = 0, Center, AngleAndAR, Twist, None } m_handle = None;
2022-02-16 17:49:00 +13:00
public:
EllipseFxGadget(FxGadgetController *controller, const TDoubleParamP &radius,
const TPointParamP &center, const TDoubleParamP &aspect_ratio,
2022-02-28 20:51:59 +13:00
const TDoubleParamP &angle,
const TDoubleParamP &twist = TDoubleParamP())
2022-02-16 17:49:00 +13:00
: FxGadget(controller, 4)
, m_radius(radius)
, m_xParam(center->getX())
, m_yParam(center->getY())
, m_aspect_ratio(aspect_ratio)
2022-02-28 20:51:59 +13:00
, m_angle(angle)
, m_twist(twist) {
2022-02-16 17:49:00 +13:00
addParam(radius);
addParam(m_xParam);
addParam(m_yParam);
addParam(m_aspect_ratio);
addParam(m_angle);
2022-02-28 20:51:59 +13:00
m_isSpin = !m_twist;
2022-02-16 17:49:00 +13:00
}
TPointD getCenter() const;
void draw(bool picking) override;
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
void leftButtonUp() override;
};
//---------------------------------------------------------------------------
TPointD EllipseFxGadget::getCenter() const {
return TPointD(getValue(m_xParam), getValue(m_yParam));
}
//---------------------------------------------------------------------------
void EllipseFxGadget::draw(bool picking) {
int idBase = getId();
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
setPixelSize();
glPushMatrix();
TPointD center = getCenter();
double aspect_ratio = getValue(m_aspect_ratio);
double angle = getValue(m_angle);
2022-02-28 20:51:59 +13:00
TRectD cameraRect = m_controller->getCameraRect();
double pivot = getPixelSize() * cameraRect.getLy() / 2.0;
2022-02-16 17:49:00 +13:00
// draw spin lines field
if (isSelected() && !isSelected(None)) {
double lineInterval = getPixelSize() * 50;
TRectD geom = m_controller->getGeometry();
2022-02-28 20:51:59 +13:00
if (m_isSpin)
drawSpinField(geom, center, lineInterval, aspect_ratio, angle);
else { // radial case
double twist = getValue(m_twist) * M_PI_180;
drawRadialField(geom, center, lineInterval, aspect_ratio, angle, twist,
pivot);
}
2022-02-16 17:49:00 +13:00
}
double unit = getPixelSize();
glTranslated(center.x, center.y, 0);
//--- radius ---
setColorById(Radius);
glPushName(idBase + Radius);
double radius = getValue(m_radius);
double scale[2] = {1.0, 1.0};
if (!areAlmostEqual(aspect_ratio, 1.0)) {
scale[0] = 2.0 * aspect_ratio / (aspect_ratio + 1.0);
scale[1] = scale[0] / aspect_ratio;
}
glPushMatrix();
glRotated(angle, 0., 0., 1.);
glScaled(scale[0], scale[1], 1.0);
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
tglDrawCircle(TPointD(), radius);
glDisable(GL_LINE_STIPPLE);
glPopMatrix();
QTransform transform = QTransform().rotate(angle).scale(scale[0], scale[1]);
QPointF radiusHandlePos = transform.map(QPointF(0.0, radius));
drawDot(TPointD(radiusHandlePos.x(), radiusHandlePos.y()));
glPopName();
if (isSelected(Radius)) {
QPointF namePos = transform.map(QPointF(0.707, 0.707) * radius);
drawTooltip(TPointD(namePos.x(), namePos.y()), getLabel());
}
2022-02-28 20:51:59 +13:00
//--- twist ---
if (m_twist) {
setColorById(Twist);
glPushName(idBase + Twist);
glPushMatrix();
glRotated(angle, 0., 0., 1.);
glScaled(scale[0], scale[1], 1.0);
glLineStipple(1, 0x0F0F);
glEnable(GL_LINE_STIPPLE);
tglDrawCircle(TPointD(), pivot);
glDisable(GL_LINE_STIPPLE);
glPopMatrix();
glPopName();
if (isSelected(Twist)) {
QPointF namePos = transform.map(QPointF(0.707, 0.707) * pivot);
drawTooltip(TPointD(namePos.x(), namePos.y()), "Twist");
}
}
2022-02-16 17:49:00 +13:00
//--- center ---
setColorById(Center);
glPushName(idBase + Center);
double d = unit * 8;
tglDrawCircle(TPointD(), d);
if (radius > d) {
glBegin(GL_LINES);
glVertex2d(-d, 0);
glVertex2d(d, 0);
glVertex2d(0, -d);
glVertex2d(0, d);
glEnd();
}
glPopName();
if (isSelected(Center)) {
2022-02-28 20:51:59 +13:00
drawTooltip(TPointD(7, 3) * unit, "Center");
2022-02-16 17:49:00 +13:00
}
//---- AR and rotate
double handleLength = unit * 100;
radius = std::max(radius, unit * 10);
setColorById(AngleAndAR);
QPointF qHandleRoot = transform.map(QPointF(radius, 0.0));
glPushMatrix();
glPushName(idBase + AngleAndAR);
glTranslated(qHandleRoot.x(), qHandleRoot.y(), 0.);
glRotated(angle, 0., 0., 1.);
glBegin(GL_LINES);
glVertex2d(0., 0.);
glVertex2d(handleLength, 0.);
glEnd();
drawDot(TPointD(handleLength, 0.));
glPopMatrix();
glPopName();
if (isSelected(AngleAndAR)) {
double angle_radian = angle * M_PI_180;
TPointD namePos(qHandleRoot.x() + std::cos(angle_radian) * handleLength,
qHandleRoot.y() + std::sin(angle_radian) * handleLength);
drawTooltip(namePos, "Angle and Aspect");
}
glPopMatrix(); // cancel translation to center
}
//---------------------------------------------------------------------------
void EllipseFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
m_handle = (HANDLE)m_selected;
m_pos = pos;
}
//---------------------------------------------------------------------------
void EllipseFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
if (m_handle == None) return;
if (m_handle == Radius) {
double aspect_ratio = getValue(m_aspect_ratio);
double angle = getValue(m_angle);
double scale[2] = {1.0, 1.0};
if (!areAlmostEqual(aspect_ratio, 1.0)) {
scale[0] = 2.0 * aspect_ratio / (aspect_ratio + 1.0);
scale[1] = scale[0] / aspect_ratio;
}
TPointD center = getCenter();
QTransform transform = QTransform()
.translate(center.x, center.y)
.rotate(angle)
.scale(scale[0], scale[1])
.inverted();
QPointF transformedP = transform.map(QPointF(pos.x, pos.y));
setValue(m_radius, QVector2D(transformedP).length());
} else if (m_handle == Center) {
setValue(m_xParam, pos.x);
setValue(m_yParam, pos.y);
} else if (m_handle == AngleAndAR) {
// <20><><EFBFBD>]<5D>ƐL<C690>k<EFBFBD>ɕ<EFBFBD><C995><EFBFBD><EFBFBD><EFBFBD>
TPointD center = getCenter();
TPointD old_v = m_pos - center;
TPointD new_v = pos - center;
if (old_v == TPointD() || new_v == TPointD()) return;
2022-02-16 17:49:00 +13:00
// AR
if (!e.isShiftPressed()) { // lock AR when shift is pressed
double aspect_ratio = getValue(m_aspect_ratio);
double pre_axisLength = 2.0 * aspect_ratio / (aspect_ratio + 1.0);
double ratio = norm(new_v) / norm(old_v);
if (ratio == 0.) return;
double new_axisLength = pre_axisLength * ratio;
double new_ar = new_axisLength / (2.0 - new_axisLength);
if (new_ar < 0.1)
new_ar = 0.1;
else if (new_ar > 10.0)
new_ar = 10.0;
setValue(m_aspect_ratio, new_ar);
}
2022-02-16 17:49:00 +13:00
// angle
if (!e.isCtrlPressed()) { // lock angle when ctrl is pressed
double angle = getValue(m_angle);
double d_angle =
std::atan2(new_v.y, new_v.x) - std::atan2(old_v.y, old_v.x);
double new_angle = angle + d_angle * M_180_PI;
if (new_angle < -180.0)
new_angle += 360.0;
else if (new_angle > 180.0)
new_angle -= 360.0;
setValue(m_angle, new_angle);
}
2022-02-16 17:49:00 +13:00
2022-02-28 20:51:59 +13:00
m_pos = pos;
} else if (m_handle == Twist) {
TPointD center = getCenter();
TPointD old_v = m_pos - center;
TPointD new_v = pos - center;
if (old_v == TPointD() || new_v == TPointD()) return;
// angle
double twist = getValue(m_twist);
double d_twist =
std::atan2(new_v.y, new_v.x) - std::atan2(old_v.y, old_v.x);
double new_twist = twist + d_twist * M_180_PI;
if (new_twist < -180.0)
new_twist = -180.0;
else if (new_twist > 180.0)
new_twist = 180.0;
setValue(m_twist, new_twist);
2022-02-16 17:49:00 +13:00
m_pos = pos;
}
}
//---------------------------------------------------------------------------
void EllipseFxGadget::leftButtonUp() { m_handle = None; }
2019-11-27 19:57:55 +13:00
//=============================================================================
class VerticalPosFxGadget final : public FxGadget {
TPointD m_pos;
TDoubleParamP m_yParam;
TIntEnumParamP m_mode;
public:
VerticalPosFxGadget(FxGadgetController *controller,
const TDoubleParamP &param, const TIntEnumParamP &mode)
: FxGadget(controller), m_yParam(param), m_mode(mode) {
addParam(m_yParam);
}
void draw(bool picking) override;
bool isVisible();
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override;
};
//---------------------------------------------------------------------------
// Dirty resolution to hide gadget when selecting unrelated modes
bool VerticalPosFxGadget::isVisible() {
if (!m_mode) return true;
// condition for Distance Level parameter of Iwa_FloorBumpFx
if (m_yParam->getName() == "distanceLevel" && m_mode->getValue() != 5)
return false;
return true;
}
//---------------------------------------------------------------------------
void VerticalPosFxGadget::draw(bool picking) {
if (!isVisible()) return;
setPixelSize();
if (isSelected())
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
glPushName(getId());
double vPos = getValue(m_yParam);
double unit = getPixelSize();
glPushMatrix();
glTranslated(0, vPos, 0);
double r = unit * 3;
double d = unit * 300;
glBegin(GL_LINES);
glVertex2d(0, r);
glVertex2d(0, -r);
glVertex2d(-d, 0);
glVertex2d(d, 0);
glEnd();
drawTooltip(TPointD(7, 7) * unit, getLabel());
glPopMatrix();
glPopName();
}
//---------------------------------------------------------------------------
void VerticalPosFxGadget::leftButtonDown(const TPointD &pos,
const TMouseEvent &) {}
//---------------------------------------------------------------------------
void VerticalPosFxGadget::leftButtonDrag(const TPointD &pos,
const TMouseEvent &) {
if (m_yParam) setValue(m_yParam, pos.y);
}
//=============================================================================
class ParallelogramFxGadget final : public FxGadget {
TPointParamP m_pcenter, m_phoriz, m_pvert;
VectorFxGadget *m_hVecGadget, *m_vVecGadget;
TPointD m_clickedPos;
TPointParamP m_pcurve;
enum HANDLE { Body = 0, CurveAnchor, Rotation, None } m_handle = None;
public:
ParallelogramFxGadget(FxGadgetController *controller, const TPointParamP &pc,
const TPointParamP &ph, const TPointParamP &pv)
: FxGadget(controller)
, m_pcenter(pc)
, m_phoriz(ph)
, m_pvert(pv)
, m_hVecGadget(new VectorFxGadget(controller, pc, ph))
, m_vVecGadget(new VectorFxGadget(controller, pc, pv)) {
addParam(pc->getX());
addParam(pc->getY());
addParam(ph->getX());
addParam(ph->getY());
addParam(pv->getX());
addParam(pv->getY());
}
ParallelogramFxGadget(FxGadgetController *controller, const TPointParamP &pc,
const TPointParamP &ph, const TPointParamP &pv,
const TPointParamP &pcurve)
: FxGadget(controller, 3)
, m_pcenter(pc)
, m_phoriz(ph)
, m_pvert(pv)
, m_pcurve(pcurve)
, m_hVecGadget(new VectorFxGadget(controller, pc, ph))
, m_vVecGadget(new VectorFxGadget(controller, pc, pv)) {
addParam(pc->getX());
addParam(pc->getY());
addParam(ph->getX());
addParam(ph->getY());
addParam(pv->getX());
addParam(pv->getY());
}
~ParallelogramFxGadget() {
delete m_hVecGadget;
delete m_vVecGadget;
}
void draw(bool picking) override {
auto setColorById = [&](int id) {
if (isSelected(id))
glColor3dv(m_selectedColor);
else
glColor3d(0, 0, 1);
};
setPixelSize();
setColorById(Body);
glPushName(getId() + Body);
double pixelSize = getPixelSize();
double c = pixelSize * 4;
TPointD pc = getValue(m_pcenter);
TPointD ph = getValue(m_phoriz);
TPointD pv = getValue(m_pvert);
TPointD vec_h = ph - pc;
TPointD vec_v = pv - pc;
TPointD po = ph + vec_v;
TPointD unit_h = vec_h * (1.0 / sqrt(norm2(vec_h)));
TPointD unit_v = vec_v * (1.0 / sqrt(norm2(vec_v)));
glLineStipple(1, 0xAAAA);
glEnable(GL_LINE_STIPPLE);
tglDrawSegment(ph + unit_v * c, po);
tglDrawSegment(pv + unit_h * c, po);
glDisable(GL_LINE_STIPPLE);
glPopName();
if (m_pcurve.getPointer()) {
TPointD pcurve = getValue(m_pcurve);
TPointD ppivot = pc + (pcurve.x + 0.5) * vec_h + (pcurve.y + 0.5) * vec_v;
setColorById(Body);
glPushName(getId() + Body);
glEnable(GL_LINE_STIPPLE);
if (pcurve == TPointD()) {
tglDrawSegment((pc + ph) * 0.5, vec_v + (pc + ph) * 0.5);
tglDrawSegment((pc + pv) * 0.5, vec_h + (pc + pv) * 0.5);
} else {
TPointD p[2][2] = {{pc + vec_h * 0.5, pc + vec_h * 0.5 + vec_v},
{pc + vec_v * 0.5, pc + vec_v * 0.5 + vec_h}};
for (int k = 0; k < 2; k++) { //
glBegin(GL_LINE_STRIP);
for (int i = 0; i <= 10; i++) { //
double t = (double)i * 0.1;
tglVertex((1.0 - t) * (1.0 - t) * p[k][0] +
2.0 * (1.0 - t) * t * ppivot + t * t * p[k][1]);
}
glEnd();
}
}
glDisable(GL_LINE_STIPPLE);
glPopName();
setColorById(CurveAnchor);
glPushName(getId() + CurveAnchor);
glPushMatrix();
glTranslated(ppivot.x, ppivot.y, 0);
double r = pixelSize * 3;
tglDrawRect(-r, -r, r, r);
glPopMatrix();
glPopName();
}
setColorById(Rotation);
glPushName(getId() + Rotation);
double a = pixelSize * 10, b = pixelSize * 3;
TPointD diagonal = normalize(po - pc);
TPointD v = rotate90(diagonal);
tglDrawSegment(po + v * a, po - v * a);
tglDrawSegment(po + diagonal * b + v * a, po + diagonal * b - v * a);
glPopName();
m_hVecGadget->draw(picking);
m_vVecGadget->draw(picking);
}
void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {
m_handle = (HANDLE)m_selected;
if (m_handle == None) return;
m_clickedPos = pos;
}
void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override {
if (m_handle == None) return;
if (m_handle == Body) {
TPointD d = pos - m_clickedPos;
setValue(m_pcenter, getValue(m_pcenter) + d);
setValue(m_phoriz, getValue(m_phoriz) + d);
setValue(m_pvert, getValue(m_pvert) + d);
} else if (m_handle == CurveAnchor && m_pcurve.getPointer()) {
TPointD pc = getValue(m_pcenter);
TPointD ph = getValue(m_phoriz);
TPointD pv = getValue(m_pvert);
TPointD vec_h = ph - pc;
TPointD vec_v = pv - pc;
TAffine aff(vec_h.x, vec_v.x, pc.x, vec_h.y, vec_v.y, pc.y);
TPointD p_conv = aff.inv() * pos;
if (p_conv.x < 0.0)
p_conv.x = 0.0;
else if (p_conv.x > 1.0)
p_conv.x = 1.0;
if (p_conv.y < 0.0)
p_conv.y = 0.0;
else if (p_conv.y > 1.0)
p_conv.y = 1.0;
setValue(m_pcurve, p_conv - TPointD(0.5, 0.5));
} else if (m_handle == Rotation) {
TPointD ph = getValue(m_phoriz);
TPointD pv = getValue(m_pvert);
TPointD pivot = (ph + pv) * 0.5;
TPointD before = m_clickedPos - pivot;
TPointD after = pos - pivot;
double angle =
std::atan2(after.y, after.x) - std::atan2(before.y, before.x);
TAffine aff = TTranslation(pivot) * TRotation(angle * M_180_PI) *
TTranslation(-pivot);
setValue(m_pcenter, aff * getValue(m_pcenter));
setValue(m_phoriz, aff * getValue(m_phoriz));
setValue(m_pvert, aff * getValue(m_pvert));
}
m_clickedPos = pos;
}
void leftButtonUp() override { m_handle = None; }
};
2016-03-19 06:57:51 +13:00
//*************************************************************************************
// FxGadgetController implementation
//*************************************************************************************
FxGadgetController::FxGadgetController(TTool *tool)
2016-06-15 18:43:10 +12:00
: m_tool(tool)
, m_fxHandle(tool->getApplication()->getCurrentFx())
, m_idBase(0)
, m_nextId(0)
, m_selectedGadget(0)
, m_editingNonZeraryFx(false) {
m_idBase = m_nextId = 5000;
connect(m_fxHandle, SIGNAL(fxSwitched()), this, SLOT(onFxSwitched()));
connect(tool->getApplication()->getCurrentXsheet(), SIGNAL(xsheetChanged()),
this, SLOT(onFxSwitched()));
onFxSwitched();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
FxGadgetController::~FxGadgetController() { clearGadgets(); }
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::clearGadgets() {
std::vector<FxGadget *>::iterator it;
for (it = m_gadgets.begin(); it != m_gadgets.end(); ++it) delete (*it);
m_gadgets.clear();
m_idTable.clear();
m_selectedGadget = 0;
m_nextId = m_idBase;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::assignId(FxGadget *gadget) {
gadget->setId(m_nextId);
for (int g = 0; g < gadget->getHandleCount(); g++) {
m_idTable[m_nextId] = gadget;
++m_nextId;
}
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::addGadget(FxGadget *gadget) {
m_gadgets.push_back(gadget);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::draw(bool picking) {
glPushMatrix();
tglMultMatrix(getMatrix());
std::vector<FxGadget *>::iterator it;
for (it = m_gadgets.begin(); it != m_gadgets.end(); ++it)
(*it)->draw(picking);
glPopMatrix();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::selectById(unsigned int id) {
2022-02-21 22:21:22 +13:00
std::map<GLuint, FxGadget *>::iterator it = m_idTable.find(id);
FxGadget *selectedGadget = it != m_idTable.end() ? it->second : nullptr;
2016-06-15 18:43:10 +12:00
if (selectedGadget != m_selectedGadget) {
if (m_selectedGadget) m_selectedGadget->select(-1);
2016-06-15 18:43:10 +12:00
m_selectedGadget = selectedGadget;
}
2022-02-21 22:21:22 +13:00
if (!m_selectedGadget) return;
int handleId = id - m_selectedGadget->getId();
if (!m_selectedGadget->isSelected(handleId))
m_selectedGadget->select(handleId);
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
FxGadget *FxGadgetController::allocateGadget(const TParamUIConcept &uiConcept) {
FxGadget *gadget = 0;
switch (uiConcept.m_type) {
case TParamUIConcept::RADIUS: {
assert(uiConcept.m_params.size() >= 1 && uiConcept.m_params.size() <= 2);
TPointParamP center((uiConcept.m_params.size() >= 2)
? (TPointParamP)uiConcept.m_params[1]
: TPointParamP());
gadget = new RadiusFxGadget(this, uiConcept.m_params[0], center);
break;
}
case TParamUIConcept::WIDTH: {
assert(uiConcept.m_params.size() >= 1 && uiConcept.m_params.size() <= 2);
TDoubleParamP angle((uiConcept.m_params.size() >= 2)
? (TDoubleParamP)uiConcept.m_params[1]
: TDoubleParamP());
gadget = new DistanceFxGadget(this, uiConcept.m_params[0], angle);
break;
}
case TParamUIConcept::ANGLE: {
assert(uiConcept.m_params.size() == 1);
gadget = new AngleFxGadget(this, uiConcept.m_params[0], TPointD());
break;
}
2019-11-11 23:35:16 +13:00
case TParamUIConcept::ANGLE_2: {
assert(uiConcept.m_params.size() == 3);
gadget =
new AngleRangeFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1], uiConcept.m_params[2]);
break;
}
2016-06-15 18:43:10 +12:00
case TParamUIConcept::POINT: {
assert(uiConcept.m_params.size() == 1);
gadget = new PointFxGadget(this, uiConcept.m_params[0]);
break;
}
case TParamUIConcept::POINT_2: {
assert(uiConcept.m_params.size() == 2);
gadget =
new PointFxGadget(this, uiConcept.m_params[0], uiConcept.m_params[1]);
break;
}
case TParamUIConcept::VECTOR: {
assert(uiConcept.m_params.size() == 2);
gadget =
new VectorFxGadget(this, uiConcept.m_params[0], uiConcept.m_params[1]);
break;
}
case TParamUIConcept::POLAR: {
assert(uiConcept.m_params.size() == 2);
gadget = new PolarFxGadget(this, TPointD(), uiConcept.m_params[0],
uiConcept.m_params[1]);
break;
}
case TParamUIConcept::SIZE: {
assert(uiConcept.m_params.size() >= 1 && uiConcept.m_params.size() <= 2);
TDoubleParamP y((uiConcept.m_params.size() >= 2)
? (TDoubleParamP)uiConcept.m_params[1]
: TDoubleParamP());
gadget = new SizeFxGadget(this, uiConcept.m_params[0], y);
break;
}
case TParamUIConcept::QUAD: {
assert(uiConcept.m_params.size() == 4);
gadget =
new QuadFxGadget(this, uiConcept.m_params[0], uiConcept.m_params[1],
uiConcept.m_params[2], uiConcept.m_params[3]);
break;
}
case TParamUIConcept::RECT: {
assert(uiConcept.m_params.size() >= 2 && uiConcept.m_params.size() <= 3);
TPointParamP center((uiConcept.m_params.size() >= 3)
? (TPointParamP)uiConcept.m_params[2]
: TPointParamP());
gadget = new RectFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1], center);
break;
}
case TParamUIConcept::DIAMOND: {
assert(uiConcept.m_params.size() == 1);
gadget = new DiamondFxGadget(this, uiConcept.m_params[0]);
break;
}
2019-11-14 15:32:32 +13:00
case TParamUIConcept::LINEAR_RANGE: {
assert(uiConcept.m_params.size() == 2);
gadget = new LinearRangeFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1]);
break;
}
case TParamUIConcept::COMPASS: {
2022-02-28 20:51:59 +13:00
assert(uiConcept.m_params.size() == 1 || uiConcept.m_params.size() == 4);
if (uiConcept.m_params.size() == 1)
gadget = new CompassFxGadget(this, uiConcept.m_params[0]);
else
gadget = new CompassFxGadget(this, uiConcept.m_params[0], false,
uiConcept.m_params[1], uiConcept.m_params[2],
uiConcept.m_params[3]);
break;
}
case TParamUIConcept::COMPASS_SPIN: {
2022-02-16 17:49:00 +13:00
assert(uiConcept.m_params.size() == 1 || uiConcept.m_params.size() == 3);
if (uiConcept.m_params.size() == 3)
gadget =
new CompassFxGadget(this, uiConcept.m_params[0], true,
uiConcept.m_params[1], uiConcept.m_params[2]);
else
gadget = new CompassFxGadget(this, uiConcept.m_params[0], true);
break;
}
2021-01-20 19:33:21 +13:00
case TParamUIConcept::RAINBOW_WIDTH: {
assert(uiConcept.m_params.size() == 3);
gadget =
new RainbowWidthFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1], uiConcept.m_params[2]);
break;
}
2022-02-16 17:49:00 +13:00
case TParamUIConcept::ELLIPSE: {
2022-02-28 20:51:59 +13:00
assert(uiConcept.m_params.size() == 4 || uiConcept.m_params.size() == 5);
// radial blur has one more parameter (twist).
if (uiConcept.m_params.size() == 5)
gadget = new EllipseFxGadget(
this, uiConcept.m_params[0], uiConcept.m_params[1],
uiConcept.m_params[2], uiConcept.m_params[3], uiConcept.m_params[4]);
// spin blur case
else
gadget = new EllipseFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1], uiConcept.m_params[2],
uiConcept.m_params[3]);
2022-02-16 17:49:00 +13:00
break;
}
2019-11-27 19:57:55 +13:00
case TParamUIConcept::VERTICAL_POS: {
assert(uiConcept.m_params.size() >= 1 && uiConcept.m_params.size() <= 2);
TIntEnumParamP mode((uiConcept.m_params.size() >= 2)
? (TIntEnumParamP)uiConcept.m_params[1]
: TIntEnumParamP());
gadget = new VerticalPosFxGadget(this, uiConcept.m_params[0], mode);
break;
}
case TParamUIConcept::PARALLELOGRAM: {
assert(uiConcept.m_params.size() == 3 || uiConcept.m_params.size() == 4);
if (uiConcept.m_params.size() == 3) {
gadget = new ParallelogramFxGadget(this, uiConcept.m_params[0],
uiConcept.m_params[1],
uiConcept.m_params[2]);
} else
gadget = new ParallelogramFxGadget(
this, uiConcept.m_params[0], uiConcept.m_params[1],
uiConcept.m_params[2], uiConcept.m_params[3]);
break;
}
2020-04-12 17:19:20 +12:00
default:
break;
2016-06-15 18:43:10 +12:00
}
if (gadget) gadget->setLabel(uiConcept.m_label);
return gadget;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::onFxSwitched() {
clearGadgets();
bool enabled = false;
TFx *fx = m_fxHandle ? m_fxHandle->getFx() : 0;
if (fx) {
int referenceColumnIndex = fx->getReferenceColumnIndex();
if (referenceColumnIndex == -1) {
TObjectHandle *oh = m_tool->getApplication()->getCurrentObject();
if (!oh->getObjectId().isCamera()) {
TXsheet *xsh = m_tool->getXsheet();
oh->setObjectId(TStageObjectId::CameraId(xsh->getCameraColumnIndex()));
2016-06-15 18:43:10 +12:00
}
enabled = true;
} else if (referenceColumnIndex == m_tool->getColumnIndex())
enabled = true;
}
if (fx && enabled) {
m_editingNonZeraryFx = true;
TZeraryColumnFx *zfx = 0;
if ((zfx = dynamic_cast<TZeraryColumnFx *>(fx)) ||
dynamic_cast<TLevelColumnFx *>(fx))
// WARNING! quick patch for huge bug: I added the || with TLevelColumnFx;
// before, the levels were considered as nonZeraryFx and the edit tool
// gadget was not displayed! Vinz
{
if (zfx) fx = zfx->getZeraryFx();
2016-06-15 18:43:10 +12:00
m_editingNonZeraryFx = false;
}
// Parse the UI Concepts returned by the fx
TParamUIConcept *uiConcepts = 0;
int i, count;
fx->getParamUIs(uiConcepts, count);
for (i = 0; i < count; ++i) {
FxGadget *gadget = allocateGadget(uiConcepts[i]);
if (gadget) addGadget(gadget);
}
delete[] uiConcepts;
} else
m_editingNonZeraryFx = false;
m_tool->invalidate();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
EditToolGadgets::DragTool *FxGadgetController::createDragTool(int gadgetId) {
selectById(gadgetId);
if (m_selectedGadget)
return new GadgetDragTool(this, m_selectedGadget);
else
return 0;
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TAffine FxGadgetController::getMatrix() {
2021-09-09 13:01:54 +12:00
TFx *fx = m_fxHandle ? m_fxHandle->getFx() : 0;
if (fx) {
int referenceColumnIndex = fx->getReferenceColumnIndex();
if (referenceColumnIndex == -1)
return m_tool->getMatrix().inv();
else if (referenceColumnIndex != m_tool->getColumnIndex())
return m_tool->getMatrix().inv() *
m_tool->getColumnMatrix(referenceColumnIndex, -1);
}
2016-06-15 18:43:10 +12:00
return m_tool->getMatrix().inv() * m_tool->getCurrentColumnMatrix();
2016-03-19 06:57:51 +13:00
}
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
int FxGadgetController::getCurrentFrame() const { return m_tool->getFrame(); }
2016-03-19 06:57:51 +13:00
//---------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void FxGadgetController::invalidateViewer() { m_tool->invalidate(); }
2022-02-28 11:18:09 +13:00
2022-02-16 17:49:00 +13:00
//---------------------------------------------------------------------------
2022-02-28 11:18:09 +13:00
int FxGadgetController::getDevPixRatio() {
return getDevicePixelRatio(m_tool->getViewer()->viewerWidget());
}
2022-02-16 17:49:00 +13:00
//---------------------------------------------------------------------------
TRectD FxGadgetController::getGeometry() {
return (m_tool->getViewer()) ? m_tool->getViewer()->getGeometry() : TRectD();
}
2022-02-28 20:51:59 +13:00
//---------------------------------------------------------------------------
TRectD FxGadgetController::getCameraRect() {
return (m_tool->getViewer()) ? m_tool->getViewer()->getCameraRect()
: TRectD();
}