#include "ext/Selector.h"
#include "tgl.h"
//#include "drawutil.h"
#include "tmathutil.h"
using namespace ToonzExt;
//-----------------------------------------------------------------------------
namespace {
const GLfloat s_normalColor[] = {250.0 / 255.0, 127 / 255.0, 240 / 255.0};
const GLfloat s_highlightedColor[] = {150.0 / 255.0, 255.0 / 255.0,
140.0 / 255.0};
const double s_sqrt_2 = sqrt(2.0);
const double s_radius = 5.0;
const double s_over_size = 10;
const double s_length = 15;
const double s_square_size = 5;
const double s_arrow_ratio = 2.5;
void drawArrow(const TPointD &from, const TPointD &direction, double length,
const TPointD &arrowDirection = TPointD(0.0, -1.0),
double arrowLength = 0.0) {
if (length <= 0 || arrowLength < 0) return;
if (arrowLength == 0.0) arrowLength = 0.2 * length;
TPointD pnt(from), myDir = normalize(direction);
TPointD myArrowDirection(arrowDirection);
if (arrowDirection.y <= 0.0) myArrowDirection = normalize(TPointD(-0.5, 0.8));
if (direction * TPointD(1, 0) <= 0.0)
myArrowDirection.x = -myArrowDirection.x;
myDir = myDir * length;
myArrowDirection = myArrowDirection * arrowLength;
glBegin(GL_LINES);
tglVertex(pnt);
pnt += myDir;
tglVertex(pnt);
glEnd();
glBegin(GL_TRIANGLES);
TPointD up = myDir + myArrowDirection;
tglVertex(from + up);
// tglVertex(pnt);
tglVertex(pnt);
myArrowDirection.y = -myArrowDirection.y;
TPointD down = myDir + myArrowDirection;
tglVertex(from + down);
glEnd();
}
}
//-----------------------------------------------------------------------------
Selector::Selector(double stroke_length, double min_val, double max_val) {
original_stroke_length_ = stroke_length;
range_ = TPointD(min_val, max_val);
isVisible_ = false;
pixel_size_ = 1.0;
w_ = 0.5;
this->init();
}
//-----------------------------------------------------------------------------
void Selector::init() {
strokeRef_ = 0;
signum_ = 1.0;
isSelected_ = NONE;
}
//-----------------------------------------------------------------------------
Selector::~Selector() {}
//-----------------------------------------------------------------------------
TPointD Selector::getUp() const {
if (!strokeRef_) return TPointD();
TThickPoint pnt = strokeRef_->getPoint(w_);
TPointD p = convert(pnt), p1;
TPointD v0, v1, v = normalize(rotate90(strokeRef_->getSpeed(w_)));
const double delta = TConsts::epsilon;
if (w_ - delta >= 0.0)
v0 = rotate90(strokeRef_->getSpeed(w_ - delta));
else
v0 = rotate90(strokeRef_->getSpeed(0));
if (w_ + delta <= 1.0)
v1 = rotate90(strokeRef_->getSpeed(w_ + delta));
else
v1 = rotate90(strokeRef_->getSpeed(1.0));
if (!isAlmostZero(v * v0) || !isAlmostZero(v * v1)) v = normalize(v1 + v0);
return v;
}
//-----------------------------------------------------------------------------
void Selector::draw(Designer *designer) {
if (!strokeRef_ || !isVisible_) return;
pixel_size_ = designer ? sqrt(designer->getPixelSize2()) : 1.0;
TPointD v = this->getUp(), n = normalize(rotate90(v));
TThickPoint pnt = strokeRef_->getThickPoint(w_);
height_ = (pnt.thick + s_over_size) * pixel_size_;
TPointD p(pnt.x, pnt.y), up = p + v * height_, down = p - v * height_;
glColor3fv(s_normalColor);
glBegin(GL_LINES);
tglVertex(down);
tglVertex(up);
glEnd();
if (isSelected_ == POSITION)
glColor3fv(s_highlightedColor);
else
glColor3fv(s_normalColor);
double radius = s_radius * pixel_size_;
if (isSelected_ == POSITION) tglDrawDisk(up + v * radius, radius);
tglDrawCircle(up + v * radius, radius);
if (isSelected_ == LENGTH)
glColor3fv(s_highlightedColor);
else
glColor3fv(s_normalColor);
{
// the circle center is in
TPointD down = -this->getUp(), center = pnt + down * (height_);
const double length = s_square_size * 0.5 * pixel_size_;
TPointD
// offset(length, 0.0),
offset(length, length),
bottom_left = center - offset, top_rigth = center + offset;
TRectD rectangle(bottom_left, top_rigth);
if (isSelected_ == LENGTH) tglFillRect(rectangle);
tglDrawRect(rectangle);
}
/*
TPointD
arrowDirection(-0.5,0.8);
if( signum_ < 0.0 )
arrowDirection.x = -arrowDirection.x;
const double
length = s_length * pixel_size_,
arrow_length = length/s_arrow_ratio;
drawArrow(down,
TPointD(1,0),
length,
arrowDirection,
arrow_length);
drawArrow(down,
TPointD(-1,0),
length,
arrowDirection,
arrow_length);
*/
// draw stroke related information
if (designer && this->isSelected()) designer->draw(this);
#if 0 // def _DEBUG
{
TThickPoint
pnt = strokeRef_->getThickPoint(w_);
TPointD
up = this->getUp(),
down = -up;
double
radius = s_radius * pixel_size_;
// the circle center is in
TPointD
center = pnt + up * ( height_ + radius);
glColor3d(1.0,0.0,1.0);
tglDrawCircle(center,radius+pixel_size_);
// one pixel of tolerance
center = pnt + down * ( height_ );
const double
length = s_length * pixel_size_;
TPointD
offset(length, 0.0),
bottom_left = center - offset,
top_rigth = center + offset;
TRectD
rectangle(bottom_left,
top_rigth);
rectangle = rectangle.enlarge( 2.0* pixel_size_);
tglDrawRect(rectangle);
}
#endif
}
//-----------------------------------------------------------------------------
void Selector::mouseDown(const TPointD &pos) {
click_ = curr_ = pos;
if (!strokeRef_) return;
stroke_length_ = original_stroke_length_;
prev_ = curr_;
}
//-----------------------------------------------------------------------------
void Selector::mouseUp(const TPointD &pos) {
curr_ = pos;
if (!strokeRef_) return;
original_stroke_length_ = stroke_length_;
prev_ = curr_;
}
//-----------------------------------------------------------------------------
void Selector::mouseMove(const TPointD &pos) {
curr_ = pos;
if (!strokeRef_) return;
isSelected_ = this->getSelection(pos);
prev_ = curr_;
}
//-----------------------------------------------------------------------------
void Selector::mouseDrag(const TPointD &pos) {
curr_ = pos;
if (!strokeRef_) return;
double val = original_stroke_length_;
const double stroke_length = strokeRef_->getLength();
double max_val = std::min(stroke_length, range_.y);
TPointD v = curr_ - prev_;
signum_ = 1.0;
switch (isSelected_) {
case POSITION:
w_ = strokeRef_->getW(pos);
break;
case LENGTH:
signum_ = v * TPointD(1.0, 0.0) < 0.0 ? -1.0 : 1.0;
val = original_stroke_length_ + signum_ * pixel_size_ * norm(v);
stroke_length_ = std::max(std::min(max_val, val), range_.x);
break;
default:
assert(false);
}
prev_ = curr_;
}
//-----------------------------------------------------------------------------
void Selector::setStroke(const TStroke *ref) {
// if(strokeRef_ &&
// strokeRef_ != ref )
// w_=strokeRef_->getParameterAtLength( strokeRef_->getLength()*0.5);
// else
// w_=0.5;
this->init();
strokeRef_ = ref;
}
//-----------------------------------------------------------------------------
Selector::Selection Selector::getSelection(const TPointD &pos) {
if (!strokeRef_ || !isVisible_) return NONE;
TThickPoint pnt = strokeRef_->getThickPoint(w_);
TPointD up = this->getUp(), down = -up;
double radius = s_radius * pixel_size_;
// the circle center is in
TPointD center = pnt + up * (height_ + radius);
// one pixel of tolerance
if (tdistance2(center, pos) <= sq(radius + pixel_size_)) return POSITION;
center = pnt + down * (height_);
// const double length = s_length * pixel_size_;
const double length = s_square_size * 0.5 * pixel_size_;
TPointD
// offset(length, 0.0),
offset(length, length),
bottom_left = center - offset, top_rigth = center + offset;
TRectD rectangle(bottom_left, top_rigth);
rectangle = rectangle.enlarge(2.0 * pixel_size_);
if (rectangle.contains(pos)) return LENGTH;
return NONE;
}
//-----------------------------------------------------------------------------
double Selector::getLength() const { return stroke_length_; }
//-----------------------------------------------------------------------------
void Selector::setLength(double length) {
stroke_length_ = original_stroke_length_ = length;
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------