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