| #include "ext/Selector.h" |
| #include "tgl.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); |
| 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); |
| |
| { |
| |
| TPointD down = -this->getUp(), center = pnt + down * (height_); |
| const double length = s_square_size * 0.5 * pixel_size_; |
| |
| TPointD |
| |
| offset(length, length), |
| bottom_left = center - offset, top_rigth = center + offset; |
| |
| TRectD rectangle(bottom_left, top_rigth); |
| |
| if (isSelected_ == LENGTH) tglFillRect(rectangle); |
| |
| tglDrawRect(rectangle); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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_; |
| |
| |
| TPointD |
| center = pnt + up * ( height_ + radius); |
| |
| glColor3d(1.0,0.0,1.0); |
| tglDrawCircle(center,radius+pixel_size_); |
| |
| |
| 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) { |
| |
| |
| |
| |
| |
| 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_; |
| |
| |
| TPointD center = pnt + up * (height_ + radius); |
| |
| |
| if (tdistance2(center, pos) <= sq(radius + pixel_size_)) return POSITION; |
| |
| center = pnt + down * (height_); |
| |
| |
| const double length = s_square_size * 0.5 * pixel_size_; |
| |
| TPointD |
| |
| 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; |
| } |
| |
| |
| |
| |