Barely function vector clip tool implemented

Originally committed to SVN as r1364.
This commit is contained in:
Rodrigo Braz Monteiro 2007-07-05 04:32:46 +00:00
parent 5e25ffe30b
commit 570321722b
16 changed files with 502 additions and 47 deletions

View File

@ -222,6 +222,7 @@ aegisub_SOURCES = \
visual_tool_rotatexy.cpp \
visual_tool_rotatez.cpp \
visual_tool_scale.cpp \
visual_tool_vector_clip.cpp \
MatroskaParser.c
noinst_HEADERS = \

View File

@ -101,6 +101,19 @@ void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) {
}
/////////////
// Draw line
void OpenGLWrapper::DrawDashedLine(float x1,float y1,float x2,float y2,float step) {
float dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
int steps = (dist-20)/step;
double stepx = double(x2-x1)/steps;
double stepy = double(y2-y1)/steps;
for (int i=0;i<steps;i++) {
if (i % 2 == 0) DrawLine(x1+int(i*stepx),y1+int(i*stepy),x1+int((i+1)*stepx),y1+int((i+1)*stepy));
}
}
///////////////
// Draw circle
void OpenGLWrapper::DrawEllipse(float x,float y,float radiusX,float radiusY) {

View File

@ -60,6 +60,7 @@ public:
void SetModeLine();
void SetModeFill();
void DrawLine(float x1,float y1,float x2,float y2);
void DrawDashedLine(float x1,float y1,float x2,float y2,float dashLen);
void DrawEllipse(float x,float y,float radiusX,float radiusY);
void DrawCircle(float x,float y,float radius) { DrawEllipse(x,y,radius,radius); }
void DrawRectangle(float x1,float y1,float x2,float y2);

View File

@ -36,6 +36,7 @@
///////////
// Headers
#include <wx/tokenzr.h>
#include "spline.h"
@ -63,10 +64,10 @@ wxString Spline::EncodeToASS() {
bool isFirst = true;
// Insert each element
for (std::list<SplineCurve>::iterator cur = curves.begin();cur!=curves.end();cur++) {
for (std::list<SplineCurve>::iterator cur=curves.begin();cur!=curves.end();cur++) {
// Start of spline
if (isFirst) {
result = wxString::Format(_T("m %i %i"),cur->x1,cur->y1);
result = wxString::Format(_T("m %i %i "),cur->x1,cur->y1);
lastCommand = 'm';
isFirst = false;
}
@ -78,14 +79,14 @@ wxString Spline::EncodeToASS() {
result += _T("l ");
lastCommand = 'l';
}
result += wxString::Format(_T("%i %i"),cur->x2,cur->y2);
result += wxString::Format(_T("%i %i "),cur->x2,cur->y2);
break;
case CURVE_BICUBIC:
if (lastCommand != 'b') {
result += _T("b ");
lastCommand = 'b';
}
result += wxString::Format(_T("%i %i %i %i"),cur->x2,cur->y2,cur->x3,cur->y3,cur->x4,cur->y4);
result += wxString::Format(_T("%i %i %i %i %i %i "),cur->x2,cur->y2,cur->x3,cur->y3,cur->x4,cur->y4);
break;
default: break;
}
@ -99,6 +100,79 @@ wxString Spline::EncodeToASS() {
void Spline::DecodeFromASS(wxString str) {
// Clear current
curves.clear();
std::vector<int> stack;
// Prepare
char lastCommand = 'm';
int x = 0;
int y = 0;
// Tokenize the string
wxStringTokenizer tkn(str,_T(" "));
while (tkn.HasMoreTokens()) {
wxString token = tkn.GetNextToken();
// Got a number
if (token.IsNumber()) {
long n;
token.ToLong(&n);
stack.push_back(n);
// Move
if (stack.size() == 2 && lastCommand == 'm') {
x = stack[0];
y = stack[1];
stack.clear();
}
// Line
if (stack.size() == 2 && lastCommand == 'l') {
SplineCurve curve;
curve.x1 = x;
curve.y1 = y;
curve.x2 = stack[0];
curve.y2 = stack[1];
curve.type = CURVE_LINE;
x = curve.x2;
y = curve.y2;
stack.clear();
AppendCurve(curve);
}
// Bicubic
else if (stack.size() == 6 && lastCommand == 'b') {
SplineCurve curve;
curve.x1 = x;
curve.y1 = y;
curve.x2 = stack[0];
curve.y2 = stack[1];
curve.x3 = stack[2];
curve.y3 = stack[3];
curve.x4 = stack[4];
curve.y4 = stack[5];
curve.type = CURVE_BICUBIC;
x = curve.x4;
y = curve.y4;
stack.clear();
AppendCurve(curve);
}
// Close
else if (lastCommand == 'c') {
stack.clear();
}
}
// Got something else
else {
if (token == _T("m")) lastCommand = 'm';
else if (token == _T("l")) lastCommand = 'l';
else if (token == _T("b")) lastCommand = 'b';
else if (token == _T("n")) lastCommand = 'n';
else if (token == _T("s")) lastCommand = 's';
else if (token == _T("c")) lastCommand = 'c';
}
}
}
@ -112,31 +186,63 @@ void Spline::AppendCurve(SplineCurve &curve) {
////////////////////////////////////////
// Moves a specific point in the spline
void Spline::MovePoint(int curveIndex,int point,wxPoint pos) {
// Curves
int i = 0;
SplineCurve *c0 = NULL;
SplineCurve *c1 = NULL;
SplineCurve *c2 = NULL;
// Indices
int size = curves.size();
int i0 = curveIndex-1;
int i1 = curveIndex;
int i2 = curveIndex+1;
//if (i0 < 0) i0 = size-1;
//if (i2 >= size) i2 = 0;
// Get the curves
for (std::list<SplineCurve>::iterator cur = curves.begin();cur!=curves.end();cur++) {
if (i == curveIndex) {
switch (point) {
case 0:
cur->x1 = pos.x;
cur->y1 = pos.y;
break;
case 1:
cur->x2 = pos.x;
cur->y2 = pos.y;
break;
case 2:
cur->x3 = pos.x;
cur->y3 = pos.y;
break;
case 3:
cur->x4 = pos.x;
cur->y4 = pos.y;
break;
}
return;
}
if (i == i0) c0 = &(*cur);
if (i == i1) c1 = &(*cur);
if (i == i2) c2 = &(*cur);
i++;
}
// Modify
if (point == 0) {
c1->x1 = pos.x;
c1->y1 = pos.y;
if (c0) {
if (c0->type == CURVE_BICUBIC) {
c0->x4 = pos.x;
c0->y4 = pos.y;
}
else {
c0->x2 = pos.x;
c0->y2 = pos.y;
}
}
}
else if (point == 1) {
c1->x2 = pos.x;
c1->y2 = pos.y;
if (c2 && c1->type != CURVE_BICUBIC) {
c2->x1 = pos.x;
c2->y1 = pos.y;
}
}
else if (point == 2) {
c1->x3 = pos.x;
c1->y3 = pos.y;
}
else if (point == 3) {
c1->x4 = pos.x;
c1->y4 = pos.y;
if (c2 && c1->type == CURVE_BICUBIC) {
c2->x1 = pos.x;
c2->y1 = pos.y;
}
}
}
@ -176,8 +282,8 @@ void Spline::GetPointList(std::vector<wxPoint> &points) {
int y3 = cur->y3;
int y4 = cur->y4;
// Hardcoded at 10 steps for now
int steps = 10;
// Hardcoded at 50 steps for now
int steps = 50;
for (int i=0;i<steps;i++) {
// Get t and t-1 (u)
float t = float(i)/float(steps);
@ -190,6 +296,11 @@ void Spline::GetPointList(std::vector<wxPoint> &points) {
}
}
}
// Insert a copy of the first point at the end
if (points.size()) {
points.push_back(points[0]);
}
}

View File

@ -71,10 +71,9 @@ public:
/////////////////////////
// Spline managing class
class Spline {
private:
public:
std::list<SplineCurve> curves;
public:
Spline();
wxString EncodeToASS();

View File

@ -118,6 +118,8 @@ VideoBox::VideoBox(wxWindow *parent)
scale->SetToolTip(_("Scale subtitles on X and Y axes."));
clip = new wxBitmapButton(videoPage,Video_Mode_Clip,wxBITMAP(visual_clip));
clip->SetToolTip(_("Clip subtitles to a rectangle."));
vectorClip = new wxBitmapButton(videoPage,Video_Mode_Vector_Clip,wxBITMAP(visual_clip));
vectorClip->SetToolTip(_("Clip subtitles to a vectorial area."));
realtime = new ToggleBitmap(videoPage,Video_Mode_Realtime,wxBITMAP(visual_realtime),wxSize(20,20));
realtime->SetToolTip(_("Toggle realtime display of changes."));
bool isRealtime = Options.AsBool(_T("Video Visual Realtime"));
@ -128,7 +130,8 @@ VideoBox::VideoBox(wxWindow *parent)
typeSizer->Add(rotatez,0,wxEXPAND,0);
typeSizer->Add(rotatexy,0,wxEXPAND,0);
typeSizer->Add(scale,0,wxEXPAND,0);
typeSizer->Add(clip,0,wxEXPAND | wxBOTTOM,5);
typeSizer->Add(clip,0,wxEXPAND,0);
typeSizer->Add(vectorClip,0,wxEXPAND | wxBOTTOM,5);
typeSizer->Add(realtime,0,wxEXPAND,0);
typeSizer->AddStretchSpacer(1);
@ -175,6 +178,7 @@ BEGIN_EVENT_TABLE(VideoBox, wxPanel)
EVT_BUTTON(Video_Mode_Rotate_XY, VideoBox::OnModeRotateXY)
EVT_BUTTON(Video_Mode_Scale, VideoBox::OnModeScale)
EVT_BUTTON(Video_Mode_Clip, VideoBox::OnModeClip)
EVT_BUTTON(Video_Mode_Vector_Clip, VideoBox::OnModeVectorClip)
EVT_TOGGLEBUTTON(Video_Mode_Realtime, VideoBox::OnToggleRealtime)
END_EVENT_TABLE()
@ -254,6 +258,13 @@ void VideoBox::OnModeClip(wxCommandEvent &event) {
}
////////////////////
// Vector clip mode
void VideoBox::OnModeVectorClip(wxCommandEvent &event) {
videoDisplay->SetVisualMode(6);
}
///////////////////
// Realtime toggle
void VideoBox::OnToggleRealtime(wxCommandEvent &event) {

View File

@ -62,6 +62,7 @@ private:
wxButton *rotatexy;
wxButton *scale;
wxButton *clip;
wxButton *vectorClip;
ToggleBitmap *realtime;
void OnVideoPlay(wxCommandEvent &event);
@ -79,6 +80,7 @@ private:
void OnModeRotateXY(wxCommandEvent &event);
void OnModeScale(wxCommandEvent &event);
void OnModeClip(wxCommandEvent &event);
void OnModeVectorClip(wxCommandEvent &event);
void OnToggleRealtime(wxCommandEvent &event);
public:
@ -113,6 +115,7 @@ enum {
Video_Mode_Rotate_XY,
Video_Mode_Scale,
Video_Mode_Clip,
Video_Mode_Vector_Clip,
Video_Mode_Realtime,
Video_Tracker_Menu,

View File

@ -73,6 +73,7 @@
#include "visual_tool_rotatexy.h"
#include "visual_tool_scale.h"
#include "visual_tool_clip.h"
#include "visual_tool_vector_clip.h"
#include "visual_tool_drag.h"
@ -106,7 +107,7 @@ END_EVENT_TABLE()
//////////////
// Parameters
int attribList[3] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, 0 };
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
///////////////
// Constructor
@ -185,18 +186,20 @@ void VideoDisplay::Render() {
wxASSERT(pw > 0);
wxASSERT(ph > 0);
// Clear frame buffer
glClearColor(0,0,0,0);
if (glGetError()) throw _T("Error setting glClearColor().");
glClearStencil(0);
if (glGetError()) throw _T("Error setting glClearStencil().");
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if (glGetError()) throw _T("Error calling glClear().");
// Freesized transform
dx1 = 0;
dy1 = 0;
dx2 = w;
dy2 = h;
if (freeSize) {
// Clear frame buffer
glClearColor(0,0,0,0);
if (glGetError()) throw _T("Error setting glClearColor().");
glClear(GL_COLOR_BUFFER_BIT);
if (glGetError()) throw _T("Error calling glClear().");
// Set aspect ratio
float thisAr = float(w)/float(h);
float vidAr;
@ -482,7 +485,8 @@ void VideoDisplay::OnKey(wxKeyEvent &event) {
if (event.GetKeyCode() == 'D') SetVisualMode(2);
if (event.GetKeyCode() == 'F') SetVisualMode(3);
if (event.GetKeyCode() == 'G') SetVisualMode(4);
if (event.GetKeyCode() == 'H') SetVisualMode(5);
if (event.GetKeyCode() == 'H') SetVisualMode(5);
if (event.GetKeyCode() == 'J') SetVisualMode(6);
}
@ -664,6 +668,7 @@ void VideoDisplay::SetVisualMode(int mode) {
case 3: visual = new VisualToolRotateXY(this); break;
case 4: visual = new VisualToolScale(this); break;
case 5: visual = new VisualToolClip(this); break;
case 6: visual = new VisualToolVectorClip(this); break;
default: visual = NULL;
}

View File

@ -46,7 +46,7 @@ VisualDraggableFeature::VisualDraggableFeature() {
type = DRAG_NONE;
x = -1;
y = -1;
value = 0;
value = value2 = 0;
layer = 0;
lineN = -1;
line = NULL;
@ -80,6 +80,12 @@ bool VisualDraggableFeature::IsMouseOver(int mx,int my) {
return (16*dx+9*dy < 0 && 16*dx-9*dy > 0);
}
// Small square
else if (type == DRAG_SMALL_SQUARE) {
if (mx < x-4 || mx > x+4 || my < y-4 || my > y+4) return false;
return true;
}
// Small circle
else if (type == DRAG_SMALL_CIRCLE) {
int dx = mx-x;
@ -120,6 +126,11 @@ void VisualDraggableFeature::Draw(OpenGLWrapper *gl) {
gl->DrawLine(x,y,x+14,y+8);
}
// Square
else if (type == DRAG_SMALL_SQUARE) {
gl->DrawRectangle(x-4,y-4,x+4,y+4);
}
// Small circle
else if (type == DRAG_SMALL_CIRCLE) {
gl->DrawCircle(x,y,4);

View File

@ -66,7 +66,7 @@ public:
DraggableFeatureType type;
int x,y;
int layer; // Higher = above
int value;
int value,value2;
AssDialogue *line;
int lineN;

View File

@ -581,6 +581,42 @@ void VisualTool::GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2)
}
//////////////////////////////////////
// Get line vector clip, if it exists
wxString VisualTool::GetLineVectorClip(AssDialogue *diag,int &scale) {
// Prepare overrides
wxString result;
scale = 1;
diag->ParseASSTags();
AssDialogueBlockOverride *override;
AssOverrideTag *tag;
size_t blockn = diag->Blocks.size();
if (blockn == 0) {
diag->ClearBlocks();
return result;
}
// Process override
override = AssDialogueBlock::GetAsOverride(diag->Blocks.at(0));
if (override) {
for (size_t j=0;j<override->Tags.size();j++) {
tag = override->Tags.at(j);
if (tag->Name == _T("\\clip")) {
if (tag->Params.size() == 1) {
result = tag->Params[0]->AsText();
}
if (tag->Params.size() == 2) {
scale = tag->Params[0]->AsInt();
result = tag->Params[1]->AsText();
}
}
}
}
diag->ClearBlocks();
return result;
}
////////////////
// Set override
void VisualTool::SetOverride(wxString tag,wxString value) {

View File

@ -101,6 +101,7 @@ protected:
void GetLineRotation(AssDialogue *diag,float &rx,float &ry,float &rz);
void GetLineScale(AssDialogue *diag,float &scalX,float &scalY);
void GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2);
wxString GetLineVectorClip(AssDialogue *diag,int &scale);
void FillPositionData();
void SetOverride(wxString tag,wxString value);

View File

@ -92,7 +92,7 @@ void VisualToolClip::Draw() {
// Draw outside area
SetLineColour(colour[3],0.0f);
SetFillColour(colour[3],0.3f);
SetFillColour(wxColour(0,0,0),0.5f);
DrawRectangle(0,0,sw,dy1);
DrawRectangle(0,dy2,sw,sh);
DrawRectangle(0,dy1,dx1,dy2);

View File

@ -185,12 +185,7 @@ void VisualToolDrag::Draw() {
// Draw dashed line
else {
SetLineColour(colour[3],0.5f,2);
int steps = (dist-20)/6;
double stepx = double(x2-x1)/steps;
double stepy = double(y2-y1)/steps;
for (int i=0;i<steps;i++) {
if (i % 2 == 0) DrawLine(x1+int(i*stepx),y1+int(i*stepy),x1+int((i+1)*stepx),y1+int((i+1)*stepy));
}
DrawDashedLine(x1,y1,x2,y2,6);
}
}
}

View File

@ -0,0 +1,204 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "visual_tool_vector_clip.h"
#include "ass_dialogue.h"
///////////////
// Constructor
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent)
: VisualTool(parent)
{
DoRefresh();
}
//////////
// Update
void VisualToolVectorClip::Update() {
GetParent()->Render();
}
////////
// Draw
void VisualToolVectorClip::Draw() {
// Get line
AssDialogue *line = GetActiveDialogueLine();
if (!line) return;
// Parse vector
std::vector<wxPoint> points;
spline.GetPointList(points);
// Draw lines
SetLineColour(colour[3]);
SetFillColour(colour[3],0.0f);
for (size_t i=0;i<points.size()-1;i++) {
DrawLine(points[i].x,points[i].y,points[i+1].x,points[i+1].y);
}
// Draw stencil mask
glEnable(GL_STENCIL_TEST);
glColorMask(0,0,0,0);
glStencilFunc(GL_NEVER,1,1);
glStencilOp(GL_INVERT,GL_INVERT,GL_INVERT);
for (size_t i=1;i<points.size()-1;i++) {
glBegin(GL_TRIANGLES);
glVertex2f(points[0].x,points[0].y);
glVertex2f(points[i].x,points[i].y);
glVertex2f(points[i+1].x,points[i+1].y);
glEnd();
}
// Draw "outside clip" mask
glColorMask(1,1,1,1);
glStencilFunc(GL_EQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
SetFillColour(wxColour(0,0,0),0.5f);
DrawRectangle(0,0,sw,sh);
glDisable(GL_STENCIL_TEST);
// Draw features
DrawAllFeatures();
// Draw lines connecting the bicubic features
SetLineColour(colour[3],0.9f,1);
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++) {
if (cur->type == CURVE_BICUBIC) {
DrawDashedLine(cur->x1,cur->y1,cur->x2,cur->y2,6);
DrawDashedLine(cur->x3,cur->y3,cur->x4,cur->y4,6);
}
}
}
/////////////////////////
// Populate feature list
void VisualToolVectorClip::PopulateFeatureList() {
// Clear
features.clear();
VisualDraggableFeature feat;
// Go through each curve
bool isFirst = true;
int i = 0;
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++,i++) {
// First point
if (isFirst) {
isFirst = false;
feat.x = cur->x1;
feat.y = cur->y1;
feat.type = DRAG_SMALL_CIRCLE;
feat.value = i;
feat.value2 = 0;
features.push_back(feat);
}
// Line
if (cur->type == CURVE_LINE) {
feat.x = cur->x2;
feat.y = cur->y2;
feat.type = DRAG_SMALL_CIRCLE;
feat.value = i;
feat.value2 = 1;
features.push_back(feat);
}
// Bicubic
if (cur->type == CURVE_BICUBIC) {
// Current size
int size = features.size();
// Control points
feat.x = cur->x2;
feat.y = cur->y2;
feat.value = i;
feat.value2 = 1;
feat.brother[0] = size-1;
feat.type = DRAG_SMALL_SQUARE;
features.push_back(feat);
feat.x = cur->x3;
feat.y = cur->y3;
feat.value2 = 2;
feat.brother[0] = size+2;
features.push_back(feat);
// End point
feat.x = cur->x4;
feat.y = cur->y4;
feat.type = DRAG_SMALL_CIRCLE;
feat.value2 = 3;
features.push_back(feat);
}
}
}
//////////
// Update
void VisualToolVectorClip::UpdateDrag(VisualDraggableFeature &feature) {
spline.MovePoint(feature.value,feature.value2,wxPoint(feature.x,feature.y));
}
//////////
// Commit
void VisualToolVectorClip::CommitDrag(VisualDraggableFeature &feature) {
SetOverride(_T("\\clip"),_T("(") + spline.EncodeToASS() + _T(")"));
}
///////////
// Refresh
void VisualToolVectorClip::DoRefresh() {
if (!dragging) {
// Get line
AssDialogue *line = GetActiveDialogueLine();
if (!line) return;
// Get clip vector
wxString vect;
int scale;
vect = GetLineVectorClip(line,scale);
if (vect.IsEmpty()) return;
spline.DecodeFromASS(vect);
PopulateFeatureList();
}
}

View File

@ -0,0 +1,64 @@
// Copyright (c) 2007, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
#pragma once
///////////
// Headers
#include "visual_tool.h"
#include "spline.h"
//////////////////////////
// Vector clip tool class
class VisualToolVectorClip : public VisualTool {
private:
Spline spline;
bool CanDrag() { return true; }
void PopulateFeatureList();
void UpdateDrag(VisualDraggableFeature &feature);
void CommitDrag(VisualDraggableFeature &feature);
void DoRefresh();
public:
VisualToolVectorClip(VideoDisplay *parent);
void Update();
void Draw();
};