diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
index 9bca1bb19..09215ad58 100644
--- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
+++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj
@@ -1919,6 +1919,10 @@
RelativePath="..\..\src\command\video.cpp"
>
+
+
+
diff --git a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters
index ed030b2c6..316a3b72c 100644
--- a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters
+++ b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters
@@ -1196,6 +1196,9 @@
Commands
+
+ Commands
+
Utilities\UI utilities
diff --git a/aegisub/src/agi_pre.h b/aegisub/src/agi_pre.h
index 8fd6a7f3d..b7c884ab2 100644
--- a/aegisub/src/agi_pre.h
+++ b/aegisub/src/agi_pre.h
@@ -160,6 +160,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -170,11 +171,11 @@
#include
#include
#include
-#include
#include
#include
#include
#include
+#include
#include
#include
#include
diff --git a/aegisub/src/base_grid.h b/aegisub/src/base_grid.h
index b90b85d82..58357f8df 100644
--- a/aegisub/src/base_grid.h
+++ b/aegisub/src/base_grid.h
@@ -121,6 +121,8 @@ protected:
void AdjustScrollbar();
void SetColumnWidths();
+ bool IsDisplayed(const AssDialogue *line) const;
+
// Re-implement functions from BaseSelectionController to add batching
void AnnounceActiveLineChanged(AssDialogue *new_line);
void AnnounceSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
@@ -139,7 +141,6 @@ public:
void EndBatch();
void SetByFrame(bool state);
- bool IsDisplayed(const AssDialogue *line) const;
void SelectRow(int row, bool addToSelected = false, bool select=true);
int GetFirstSelRow() const;
wxArrayInt GetSelection() const;
diff --git a/aegisub/src/command/Makefile b/aegisub/src/command/Makefile
index 6242e4d3c..89c362b1d 100644
--- a/aegisub/src/command/Makefile
+++ b/aegisub/src/command/Makefile
@@ -21,7 +21,8 @@ SRC = \
time.cpp \
timecode.cpp \
tool.cpp \
- video.cpp
+ video.cpp \
+ vis_tool.cpp
SRC += \
icon.cpp \
diff --git a/aegisub/src/command/command.cpp b/aegisub/src/command/command.cpp
index e40d719e4..17853fbec 100644
--- a/aegisub/src/command/command.cpp
+++ b/aegisub/src/command/command.cpp
@@ -88,6 +88,7 @@ namespace cmd {
void init_timecode();
void init_tool();
void init_video();
+ void init_visual_tools();
void init_builtin_commands() {
LOG_D("command/init") << "Populating command map";
@@ -104,6 +105,7 @@ namespace cmd {
init_timecode();
init_tool();
init_video();
+ init_visual_tools();
}
void clear() {
diff --git a/aegisub/src/command/icon.cpp b/aegisub/src/command/icon.cpp
index f6fb27f58..b1c5a907a 100644
--- a/aegisub/src/command/icon.cpp
+++ b/aegisub/src/command/icon.cpp
@@ -198,6 +198,13 @@ INSERT_ICON("video/opt/autoscroll", toggle_video_autoscroll)
INSERT_ICON("video/play", button_play)
INSERT_ICON("video/play/line", button_playline)
INSERT_ICON("video/stop", button_pause)
+INSERT_ICON("video/tool/clip", visual_clip)
+INSERT_ICON("video/tool/cross", visual_standard)
+INSERT_ICON("video/tool/drag", visual_move)
+INSERT_ICON("video/tool/rotate/xy", visual_rotatexy)
+INSERT_ICON("video/tool/rotate/z", visual_rotatez)
+INSERT_ICON("video/tool/scale", visual_scale)
+INSERT_ICON("video/tool/vector_clip", visual_vector_clip)
INSERT_ICON("video/zoom/in", zoom_in_button)
INSERT_ICON("video/zoom/out", zoom_out_button)
diff --git a/aegisub/src/command/video.cpp b/aegisub/src/command/video.cpp
index 2bd7ca4b7..f67a3c1ca 100644
--- a/aegisub/src/command/video.cpp
+++ b/aegisub/src/command/video.cpp
@@ -238,10 +238,7 @@ struct video_copy_coordinates : public validator_video_loaded {
void operator()(agi::Context *c) {
if (wxTheClipboard->Open()) {
- int x, y;
- c->videoBox->videoDisplay->GetMousePosition(&x, &y);
- c->videoBox->videoDisplay->ToScriptCoords(&x, &y);
- wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%d,%d", x, y)));
+ wxTheClipboard->SetData(new wxTextDataObject(c->videoBox->videoDisplay->GetMousePosition().Str()));
wxTheClipboard->Close();
}
}
diff --git a/aegisub/src/command/vis_tool.cpp b/aegisub/src/command/vis_tool.cpp
new file mode 100644
index 000000000..a6894895a
--- /dev/null
+++ b/aegisub/src/command/vis_tool.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2011, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Aegisub Project http://www.aegisub.org/
+//
+// $Id$
+
+/// @file vis_tool.cpp
+/// @brief Visual typesetting tools commands
+/// @ingroup command visual_ui
+///
+
+#include "../config.h"
+
+#include "command.h"
+
+#include "../include/aegisub/context.h"
+#include "../video_box.h"
+#include "../video_context.h"
+#include "../video_display.h"
+#include "../visual_tool_clip.h"
+#include "../visual_tool_cross.h"
+#include "../visual_tool_drag.h"
+#include "../visual_tool_rotatexy.h"
+#include "../visual_tool_rotatez.h"
+#include "../visual_tool_scale.h"
+#include "../visual_tool_vector_clip.h"
+
+namespace {
+ using cmd::Command;
+ /// @defgroup cmd-visual Visual typesetting tools commands
+ /// @{
+
+ struct validator_video_loaded : public Command {
+ CMD_TYPE(COMMAND_VALIDATE)
+ bool Validate(const agi::Context *c) {
+ return c->videoController->IsLoaded();
+ }
+ };
+
+ struct visual_mode_cross : public validator_video_loaded {
+ CMD_NAME("video/tool/cross")
+ STR_MENU("Standard")
+ STR_DISP("Standard")
+ STR_HELP("Standard mode, double click sets position.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolCross(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_drag : public validator_video_loaded {
+ CMD_NAME("video/tool/drag")
+ STR_MENU("Drag")
+ STR_DISP("Drag")
+ STR_HELP("Drag subtitles.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolDrag(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_rotate_z : public validator_video_loaded {
+ CMD_NAME("video/tool/rotate/z")
+ STR_MENU("Rotate Z")
+ STR_DISP("Rotate Z")
+ STR_HELP("Rotate subtitles on their Z axis.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolRotateZ(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_rotate_xy : public validator_video_loaded {
+ CMD_NAME("video/tool/rotate/xy")
+ STR_MENU("Rotate XY")
+ STR_DISP("Rotate XY")
+ STR_HELP("Rotate subtitles on their X and Y axes.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolRotateXY(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_scale : public validator_video_loaded {
+ CMD_NAME("video/tool/scale")
+ STR_MENU("Scale")
+ STR_DISP("Scale")
+ STR_HELP("Scale subtitles on X and Y axes.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolScale(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_clip : public validator_video_loaded {
+ CMD_NAME("video/tool/clip")
+ STR_MENU("Clip")
+ STR_DISP("Clip")
+ STR_HELP("Clip subtitles to a rectangle.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolClip(c->videoBox->videoDisplay, c));
+ }
+ };
+
+ struct visual_mode_vector_clip : public validator_video_loaded {
+ CMD_NAME("video/tool/vector_clip")
+ STR_MENU("Vector Clip")
+ STR_DISP("Vector Clip")
+ STR_HELP("Clip subtitles to a vectorial arean.")
+
+ void operator()(agi::Context *c) {
+ c->videoBox->videoDisplay->SetTool(new VisualToolVectorClip(c->videoBox->videoDisplay, c));
+ }
+ };
+}
+
+/// @}
+
+namespace cmd {
+ void init_visual_tools() {
+ reg(new visual_mode_cross);
+ reg(new visual_mode_drag);
+ reg(new visual_mode_rotate_z);
+ reg(new visual_mode_rotate_xy);
+ reg(new visual_mode_scale);
+ reg(new visual_mode_clip);
+ reg(new visual_mode_vector_clip);
+ }
+}
diff --git a/aegisub/src/dialog_properties.cpp b/aegisub/src/dialog_properties.cpp
index 819361a1e..775ae1b9c 100644
--- a/aegisub/src/dialog_properties.cpp
+++ b/aegisub/src/dialog_properties.cpp
@@ -52,7 +52,6 @@
#include "utils.h"
#include "validators.h"
#include "video_context.h"
-#include "video_display.h"
#include "video_provider_manager.h"
DialogProperties::DialogProperties(agi::Context *c)
diff --git a/aegisub/src/dialog_search_replace.cpp b/aegisub/src/dialog_search_replace.cpp
index 7e2fb63b9..95281e297 100644
--- a/aegisub/src/dialog_search_replace.cpp
+++ b/aegisub/src/dialog_search_replace.cpp
@@ -52,7 +52,6 @@
#include "selection_controller.h"
#include "subs_edit_ctrl.h"
#include "subs_grid.h"
-#include "video_display.h"
// IDs
enum {
diff --git a/aegisub/src/dialog_timing_processor.cpp b/aegisub/src/dialog_timing_processor.cpp
index dd3e4eb4e..a0b19fc06 100644
--- a/aegisub/src/dialog_timing_processor.cpp
+++ b/aegisub/src/dialog_timing_processor.cpp
@@ -55,7 +55,6 @@
#include "utils.h"
#include "validators.h"
#include "video_context.h"
-#include "video_display.h"
/// Window IDs
enum {
diff --git a/aegisub/src/gl_text.cpp b/aegisub/src/gl_text.cpp
index cdb27d6ae..447510089 100644
--- a/aegisub/src/gl_text.cpp
+++ b/aegisub/src/gl_text.cpp
@@ -342,20 +342,30 @@ void OpenGLTextTexture::Insert(OpenGLTextGlyph &glyph) {
/// Draw a glyph at (x,y)
void OpenGLTextGlyph::Draw(int x,int y) const {
- // Store matrix and translate
- glPushMatrix();
- glTranslatef((float)x,(float)y,0.0f);
-
glBindTexture(GL_TEXTURE_2D, tex);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glBegin(GL_QUADS);
- glTexCoord2f(x1,y1); glVertex2f(0,0); // Top-left
- glTexCoord2f(x1,y2); glVertex2f(0,h); // Bottom-left
- glTexCoord2f(x2,y2); glVertex2f(w,h); // Bottom-right
- glTexCoord2f(x2,y1); glVertex2f(w,0); // Top-right
- glEnd();
+ float tex_coords[] = {
+ x1, y1,
+ x1, y2,
+ x2, y2,
+ x2, y1
+ };
- glPopMatrix();
+ float vert_coords[] = {
+ x, y,
+ x, y + h,
+ x + w, y + h,
+ x + w, y
+ };
+
+ glVertexPointer(2, GL_FLOAT, 0, vert_coords);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex_coords);
+ glDrawArrays(GL_QUADS, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
/// @brief DOCME
diff --git a/aegisub/src/gl_wrap.cpp b/aegisub/src/gl_wrap.cpp
index 8772deea4..b1f93180b 100644
--- a/aegisub/src/gl_wrap.cpp
+++ b/aegisub/src/gl_wrap.cpp
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -42,303 +29,417 @@
#ifndef AGI_PRE
#include
-#ifdef __APPLE__
+#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
+#include
+#include
#include
#else
+#include
+#include
#include "gl/glext.h"
#endif
-
#endif
+static const float deg2rad = 3.1415926536f / 180.f;
+static const float rad2deg = 180.f / 3.1415926536f;
+static const float pi = 3.1415926535897932384626433832795f;
+
+#ifdef __WIN32__
+#define glGetProc(a) wglGetProcAddress(a)
+#elif !defined(__APPLE__)
+#include
+#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
+#endif
+
+#if defined(__APPLE__)
+// Not required on OS X.
+#define APIENTRY
+#define GL_EXT(type, name)
+#else
+#define GL_EXT(type, name) \
+ static type name = reinterpret_cast(glGetProc(#name)); \
+ if (!name) { \
+ name = reinterpret_cast(& name ## Fallback); \
+ }
+#endif
+
+class VertexArray {
+ std::vector data;
+ size_t dim;
+public:
+ VertexArray(size_t dims, size_t elems) {
+ SetSize(dims, elems);
+ }
+
+ void SetSize(size_t dims, size_t elems) {
+ dim = dims;
+ data.resize(elems * dim);
+ }
+
+ void Set(size_t i, float x, float y) {
+ data[i * dim] = x;
+ data[i * dim + 1] = y;
+ }
+
+ void Set(size_t i, float x, float y, float z) {
+ data[i * dim] = x;
+ data[i * dim + 1] = y;
+ data[i * dim + 2] = z;
+ }
+
+ void Set(size_t i, Vector2D p) {
+ data[i * dim] = p.X();
+ data[i * dim + 1] = p.Y();
+ }
+
+ void Draw(GLenum mode, bool clear = true) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(dim, GL_FLOAT, 0, &data[0]);
+ glDrawArrays(mode, 0, data.size() / dim);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ if (clear)
+ data.clear();
+ }
+};
-/// @brief Constructor
-///
OpenGLWrapper::OpenGLWrapper() {
- r1 = g1 = b1 = a1 = 1.0f;
- r2 = g2 = b2 = a2 = 1.0f;
- lw = 1;
+ line_r = line_g = line_b = line_a = 1.f;
+ fill_r = fill_g = fill_b = fill_a = 1.f;
+ line_width = 1;
+ transform_pushed = false;
+ smooth = true;
}
-
-
-/// @brief Draw line
-/// @param x1
-/// @param y1
-/// @param x2
-/// @param y2
-///
-void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) const {
+void OpenGLWrapper::DrawLine(Vector2D p1, Vector2D p2) const {
SetModeLine();
- glBegin(GL_LINES);
- glVertex2f(x1,y1);
- glVertex2f(x2,y2);
- glEnd();
+ VertexArray buf(2, 2);
+ buf.Set(0, p1);
+ buf.Set(1, p2);
+ buf.Draw(GL_LINES);
}
+static inline Vector2D interp(Vector2D p1, Vector2D p2, float t) {
+ return t * p1 + (1 - t) * p2;
+}
-
-/// @brief Draw line
-/// @param x1
-/// @param y1
-/// @param x2
-/// @param y2
-/// @param step
-///
-void OpenGLWrapper::DrawDashedLine(float x1,float y1,float x2,float y2,float step) const {
- float dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
- int steps = (int)((dist-20)/step);
- double stepx = double(x2-x1)/steps;
- double stepy = double(y2-y1)/steps;
- for (int i=0;i r1) {
- float temp = r1;
- r1 = r2;
- r2 = temp;
- }
+void OpenGLWrapper::DrawRing(Vector2D center, float r1, float r2, float ar, float arc_start, float arc_end) const {
+ if (r2 > r1)
+ std::swap(r1, r2);
// Arc range
- bool hasEnds = arcStart != arcEnd;
- float pi = 3.1415926535897932384626433832795f;
- arcEnd *= pi / 180.f;
- arcStart *= pi / 180.f;
- if (arcEnd <= arcStart) arcEnd += 2.0f*pi;
- float range = arcEnd - arcStart;
+ bool needs_end_caps = arc_start != arc_end;
+
+ arc_end *= deg2rad;
+ arc_start *= deg2rad;
+ if (arc_end <= arc_start)
+ arc_end += 2.f * pi;
+ float range = arc_end - arc_start;
// Math
- int steps = int((r1 + r1*ar) * range / (2.0f*pi))*4;
- if (steps < 12) steps = 12;
- //float end = arcEnd;
- float step = range/steps;
- float curAngle = arcStart;
+ int steps = std::max(((r1 + r1 * ar) * range / (2.f * pi)) * 4, 12);
+ float step = range / steps;
+ float cur_angle = arc_start;
- // Fill
- if (a2 != 0.0) {
+ VertexArray buf(2, steps);
+
+ Vector2D scale_inner = Vector2D(ar, 1) * r1;
+ Vector2D scale_outer = Vector2D(ar, 1) * r2;
+
+ if (fill_a != 0.0) {
SetModeFill();
// Annulus
if (r1 != r2) {
- glBegin(GL_QUADS);
- for (int i=0;i const& lines) {
+ DrawLines(dim, &lines[0], lines.size() / dim);
+}
-/// DOCME
-wxMutex OpenGLWrapper::glMutex;
+void OpenGLWrapper::DrawLines(size_t dim, std::vector const& lines, size_t c_dim, std::vector const& colors) {
+ glShadeModel(GL_SMOOTH);
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(c_dim, GL_FLOAT, 0, &colors[0]);
+ DrawLines(dim, &lines[0], lines.size() / dim);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glShadeModel(GL_FLAT);
+}
+void OpenGLWrapper::DrawLines(size_t dim, const float *lines, size_t n) {
+ SetModeLine();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(dim, GL_FLOAT, 0, lines);
+ glDrawArrays(GL_LINES, 0, n);
+ glDisableClientState(GL_VERTEX_ARRAY);
+}
+void OpenGLWrapper::DrawLineStrip(size_t dim, std::vector const& lines) {
+ SetModeLine();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(dim, GL_FLOAT, 0, &lines[0]);
+ glDrawArrays(GL_LINE_STRIP, 0, lines.size() / dim);
+ glDisableClientState(GL_VERTEX_ARRAY);
+}
+
+// Substitute for glMultiDrawArrays for sub-1.4 OpenGL
+// Not required on OS X.
+#ifndef __APPLE__
+static void APIENTRY glMultiDrawArraysFallback(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) {
+ for (int i = 0; i < primcount; ++i) {
+ glDrawArrays(mode, *first++, *count++);
+ }
+}
+#endif
+
+void OpenGLWrapper::DrawMultiPolygon(std::vector const& points, std::vector &start, std::vector &count, Vector2D video_size, bool invert) {
+ GL_EXT(PFNGLMULTIDRAWARRAYSPROC, glMultiDrawArrays);
+
+ // The following is nonzero winding-number PIP based on stencils
+
+ // Draw to stencil only
+ glEnable(GL_STENCIL_TEST);
+ glColorMask(0, 0, 0, 0);
+
+ // GL_INCR_WRAP was added in 1.4, so instead set the entire stencil to 128
+ // and wobble from there
+ glStencilFunc(GL_NEVER, 128, 0xFF);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ VertexArray buf(2, 4);
+ buf.Set(0, Vector2D());
+ buf.Set(1, Vector2D(video_size, 0));
+ buf.Set(2, video_size);
+ buf.Set(3, Vector2D(0, video_size));
+ glColor4f(0, 0, 0, 1);
+ glDisable(GL_BLEND);
+ buf.Draw(GL_QUADS, false);
+
+ // Increment the winding number for each forward facing triangle
+ glStencilOp(GL_INCR, GL_INCR, GL_INCR);
+ glEnable(GL_CULL_FACE);
+
+ glCullFace(GL_BACK);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, &points[0]);
+ glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
+
+ // Decrement the winding number for each backfacing triangle
+ glStencilOp(GL_DECR, GL_DECR, GL_DECR);
+ glCullFace(GL_FRONT);
+ glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
+ glDisable(GL_CULL_FACE);
+
+ // Draw the actual rectangle
+ glColorMask(1, 1, 1, 1);
+ float real_line_a = line_a;
+ line_a = 0;
+
+ // VSFilter draws when the winding number is nonzero, so we want to draw the
+ // mask when the winding number is zero (where 128 is zero due to the lack of
+ // wrapping combined with unsigned numbers)
+ glStencilFunc(invert ? GL_EQUAL : GL_NOTEQUAL, 128, 0xFF);
+ DrawRectangle(Vector2D(), video_size);
+ glDisable(GL_STENCIL_TEST);
+
+ // Draw lines
+ line_a = real_line_a;
+ SetModeLine();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_FLOAT, 0, &points[0]);
+ glMultiDrawArrays(GL_LINE_LOOP, &start[0], &count[0], start.size());
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+}
+
+void OpenGLWrapper::SetOrigin(Vector2D origin) {
+ PrepareTransform();
+ glTranslatef(origin.X(), origin.Y(), -1.f);
+}
+
+void OpenGLWrapper::SetScale(Vector2D scale) {
+ PrepareTransform();
+ glScalef(scale.X() / 100.f, scale.Y() / 100.f, 1.f);
+}
+
+void OpenGLWrapper::SetRotation(float x, float y, float z) {
+ PrepareTransform();
+ float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
+ glMultMatrixf(matrix);
+ glScalef(1.f, 1.f, 8.f);
+ glRotatef(y, 0.f, -1.f, 0.f);
+ glRotatef(x, -1.f, 0.f, 0.f);
+ glRotatef(z, 0.f, 0.f, -1.f);
+}
+
+void OpenGLWrapper::PrepareTransform() {
+ if (!transform_pushed) {
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ transform_pushed = true;
+ }
+}
+
+void OpenGLWrapper::ResetTransform() {
+ if (transform_pushed) {
+ glPopMatrix();
+ transform_pushed = false;
+ }
+}
diff --git a/aegisub/src/gl_wrap.h b/aegisub/src/gl_wrap.h
index ef82cc7ea..87470b52c 100644
--- a/aegisub/src/gl_wrap.h
+++ b/aegisub/src/gl_wrap.h
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -34,41 +21,13 @@
/// @ingroup video_output
///
-
-#ifdef __APPLE__
-#include
-#include
-#else
-#include
-#include
-
-/// DOCME
-typedef GLuint GLhandleARB;
-#endif
+#include "vector2d.h"
#ifndef AGI_PRE
-#include
-#include
-#endif
-
-#ifdef __WIN32__
-#define glGetProc(a) wglGetProcAddress(a)
-#else
-#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
-#endif
-
-#if defined(__APPLE__)
-// Not required on OS X.
-#define GL_EXT(type, name)
-#else
-
-#define GL_EXT(type, name) \
- static type name = reinterpret_cast(glGetProc(#name)); \
- if (!name) { \
- name = reinterpret_cast(& name ## Fallback); \
- }
+#include
#endif
+class wxColour;
/// DOCME
/// @class OpenGLWrapper
@@ -76,55 +35,51 @@ typedef GLuint GLhandleARB;
///
/// DOCME
class OpenGLWrapper {
-private:
+ float line_r, line_g, line_b, line_a;
+ float fill_r, fill_g, fill_b, fill_a;
- /// DOCME
+ int line_width;
+ bool smooth;
- /// DOCME
-
- /// DOCME
-
- /// DOCME
- float r1,g1,b1,a1;
-
- /// DOCME
-
- /// DOCME
-
- /// DOCME
-
- /// DOCME
- float r2,g2,b2,a2;
-
- /// DOCME
- int lw;
+ bool transform_pushed;
+ void PrepareTransform();
public:
OpenGLWrapper();
-
- /// DOCME
- static wxMutex glMutex;
-
- void SetLineColour(wxColour col,float alpha=1.0f,int width=1);
- void SetFillColour(wxColour col,float alpha=1.0f);
+ void SetLineColour(wxColour col, float alpha = 1.0f, int width = 1);
+ void SetFillColour(wxColour col, float alpha = 1.0f);
void SetModeLine() const;
void SetModeFill() const;
- void DrawLine(float x1,float y1,float x2,float y2) const;
- void DrawDashedLine(float x1,float y1,float x2,float y2,float dashLen) const;
- void DrawEllipse(float x,float y,float radiusX,float radiusY) const;
- /// @brief DOCME
- /// @param x
- /// @param y
- /// @param radius
- ///
- void DrawCircle(float x,float y,float radius) const { DrawEllipse(x,y,radius,radius); }
- void DrawRectangle(float x1,float y1,float x2,float y2) const;
- void DrawRing(float x,float y,float r1,float r2,float ar=1.0f,float arcStart=0.0f,float arcEnd=0.0f) const;
- void DrawTriangle(float x1,float y1,float x2,float y2,float x3,float y3) const;
+ void SetInvert();
+ void ClearInvert();
+
+ void SetScale(Vector2D scale);
+ void SetOrigin(Vector2D origin);
+ void SetRotation(float x, float y, float z);
+ void ResetTransform();
+
+ void DrawLine(Vector2D p1, Vector2D p2) const;
+ void DrawDashedLine(Vector2D p1, Vector2D p2, float dashLen) const;
+ void DrawEllipse(Vector2D center, Vector2D radius) const;
+ void DrawCircle(Vector2D center, float radius) const { DrawEllipse(center, Vector2D(radius, radius)); }
+ void DrawRectangle(Vector2D p1, Vector2D p2) const;
+ void DrawRing(Vector2D center, float r1, float r2, float ar = 1.0f, float arcStart = 0.0f, float arcEnd = 0.0f) const;
+ void DrawTriangle(Vector2D p1, Vector2D p2, Vector2D p3) const;
+
+ void DrawLines(size_t dim, std::vector const& lines);
+ void DrawLines(size_t dim, std::vector const& lines, size_t c_dim, std::vector const& colors);
+ void DrawLines(size_t dim, const float *lines, size_t n);
+ void DrawLineStrip(size_t dim, std::vector const& lines);
+
+ /// Draw a multipolygon serialized into a single array
+ /// @param points List of coordinates
+ /// @param start Indices in points which are the start of a new polygon
+ /// @param count Number of points in each polygon
+ /// @param video_size Bottom-right corner of the visible area
+ /// @param invert Draw the area outside the polygons instead
+ void DrawMultiPolygon(std::vector const& points, std::vector &start, std::vector &count, Vector2D video_size, bool invert);
static bool IsExtensionSupported(const char *ext);
};
-
-
diff --git a/aegisub/src/include/aegisub/toolbar.h b/aegisub/src/include/aegisub/toolbar.h
index 6c4d5d890..c1259b36f 100644
--- a/aegisub/src/include/aegisub/toolbar.h
+++ b/aegisub/src/include/aegisub/toolbar.h
@@ -34,5 +34,5 @@ namespace toolbar {
/// @param context Project context
/// @param hotkey Hotkey context for the tooltip
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *context, std::string const& hotkey);
- wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *context, std::string const& hotkey);
+ wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *context, std::string const& hotkey, bool vertical = false);
}
diff --git a/aegisub/src/libresrc/default_hotkey.json b/aegisub/src/libresrc/default_hotkey.json
index ae2373834..839eea4c0 100644
--- a/aegisub/src/libresrc/default_hotkey.json
+++ b/aegisub/src/libresrc/default_hotkey.json
@@ -474,43 +474,43 @@
"key" : "Left"
}
],
- "visual typesetting set tool crosshair" : [
+ "video/tool/cross" : [
{
"modifiers" : [],
"key" : "A"
}
],
- "visual typesetting set tool drag" : [
+ "video/tool/drag" : [
{
"modifiers" : [],
"key" : "S"
}
],
- "visual typesetting set tool rectangle clip" : [
+ "video/tool/clip" : [
{
"modifiers" : [],
"key" : "H"
}
],
- "visual typesetting set tool rotate xy" : [
+ "video/tool/rotate/xy" : [
{
"modifiers" : [],
"key" : "F"
}
],
- "visual typesetting set tool rotate z" : [
+ "video/tool/rotate/z" : [
{
"modifiers" : [],
"key" : "D"
}
],
- "visual typesetting set tool scale" : [
+ "video/tool/scale" : [
{
"modifiers" : [],
"key" : "G"
}
],
- "visual typesetting set tool vector clip" : [
+ "video/tool/vector_clip" : [
{
"modifiers" : [],
"key" : "J"
diff --git a/aegisub/src/libresrc/default_toolbar.json b/aegisub/src/libresrc/default_toolbar.json
index 0e85cf05b..fb67293ed 100644
--- a/aegisub/src/libresrc/default_toolbar.json
+++ b/aegisub/src/libresrc/default_toolbar.json
@@ -61,5 +61,16 @@
"",
"app/options",
"grid/tag/cycle_hiding"
+ ],
+ "visual_tools" : [
+ "video/tool/cross",
+ "video/tool/drag",
+ "video/tool/rotate/z",
+ "video/tool/rotate/xy",
+ "video/tool/scale",
+ "video/tool/clip",
+ "video/tool/vector_clip",
+ "",
+ "help/video"
]
}
diff --git a/aegisub/src/spline.cpp b/aegisub/src/spline.cpp
index f73156350..f4f9812d6 100644
--- a/aegisub/src/spline.cpp
+++ b/aegisub/src/spline.cpp
@@ -37,192 +37,164 @@
#include "config.h"
#ifndef AGI_PRE
+#include
+
#include
#endif
-#include
-
#include "spline.h"
-#include "utils.h"
-#include "video_display.h"
-/// @brief Spline constructor
-Spline::Spline(const VideoDisplay &scale) : scale(scale) {
+#include "utils.h"
+#include "visual_tool.h"
+
+Spline::Spline(const VisualToolBase &scale) : scale(scale) {
}
/// @brief Encode to ASS
wxString Spline::EncodeToASS() {
wxString result;
- char lastCommand = 0;
+ result.reserve(size() * 10);
+ char last = 0;
- // Insert each element
- for (iterator cur=begin();cur!=end();cur++) {
- // Each curve
+ for (iterator cur = begin(); cur != end(); ++cur) {
switch (cur->type) {
- case CURVE_POINT: {
- if (lastCommand != 'm') {
+ case SplineCurve::POINT:
+ if (last != 'm') {
result += "m ";
- lastCommand = 'm';
+ last = 'm';
}
- int x = cur->p1.x;
- int y = cur->p1.y;
- scale.ToScriptCoords(&x, &y);
- result += wxString::Format("%i %i ", x, y);
+ result += scale.ToScriptCoords(cur->p1).DStr(' ');
break;
- }
- case CURVE_LINE: {
- if (lastCommand != 'l') {
+
+ case SplineCurve::LINE:
+ if (last != 'l') {
result += "l ";
- lastCommand = 'l';
+ last = 'l';
}
- int x = cur->p2.x;
- int y = cur->p2.y;
- scale.ToScriptCoords(&x, &y);
- result += wxString::Format("%i %i ", x, y);
+ result += scale.ToScriptCoords(cur->p2).DStr(' ');
break;
- }
- case CURVE_BICUBIC: {
- if (lastCommand != 'b') {
+
+ case SplineCurve::BICUBIC:
+ if (last != 'b') {
result += "b ";
- lastCommand = 'b';
+ last = 'b';
}
- int x2 = cur->p2.x;
- int y2 = cur->p2.y;
- int x3 = cur->p3.x;
- int y3 = cur->p3.y;
- int x4 = cur->p4.x;
- int y4 = cur->p4.y;
- scale.ToScriptCoords(&x2, &y2);
- scale.ToScriptCoords(&x3, &y3);
- scale.ToScriptCoords(&x4, &y4);
- result += wxString::Format("%i %i %i %i %i %i ", x2, y2, x3, y3, x4, y4);
+ result += scale.ToScriptCoords(cur->p2).DStr(' ');
+ result += scale.ToScriptCoords(cur->p3).DStr(' ');
+ result += scale.ToScriptCoords(cur->p4).DStr(' ');
break;
- }
+
default: break;
}
+ result += " ";
}
return result;
}
-/// @brief Decode from ASS
-/// @param str
void Spline::DecodeFromASS(wxString str) {
// Clear current
clear();
- std::vector stack;
+ std::vector stack;
// Prepare
- char lastCommand = 'm';
- int x = 0;
- int y = 0;
+ char command = 'm';
+ Vector2D pt;
// Tokenize the string
- wxStringTokenizer tkn(str," ");
+ wxStringTokenizer tkn(str, " ");
while (tkn.HasMoreTokens()) {
wxString token = tkn.GetNextToken();
-
- // Got a number
- if (token.IsNumber()) {
- long n;
- token.ToLong(&n);
+ double n;
+ if (token.ToCDouble(&n)) {
stack.push_back(n);
// Move
- if (stack.size() == 2 && lastCommand == 'm') {
- scale.FromScriptCoords(&stack[0], &stack[1]);
- SplineCurve curve;
- x = curve.p1.x = stack[0];
- y = curve.p1.y = stack[1];
- curve.type = CURVE_POINT;
+ if (stack.size() == 2 && command == 'm') {
+ pt = scale.FromScriptCoords(Vector2D(stack[0], stack[1]));
stack.clear();
- push_back(curve);
+
+ push_back(pt);
}
// Line
- if (stack.size() == 2 && lastCommand == 'l') {
- scale.FromScriptCoords(&stack[0], &stack[1]);
- SplineCurve curve;
- curve.p1.x = x;
- curve.p1.y = y;
- x = curve.p2.x = stack[0];
- y = curve.p2.y = stack[1];
- curve.type = CURVE_LINE;
- stack.clear();
+ if (stack.size() == 2 && command == 'l') {
+ SplineCurve curve(pt, scale.FromScriptCoords(Vector2D(stack[0], stack[1])));
push_back(curve);
+
+ pt = curve.p2;
+ stack.clear();
}
// Bicubic
- else if (stack.size() == 6 && lastCommand == 'b') {
- scale.FromScriptCoords(&stack[0], &stack[1]);
- scale.FromScriptCoords(&stack[2], &stack[3]);
- scale.FromScriptCoords(&stack[4], &stack[5]);
- SplineCurve curve;
- curve.p1.x = x;
- curve.p1.y = y;
- curve.p2.x = stack[0];
- curve.p2.y = stack[1];
- curve.p3.x = stack[2];
- curve.p3.y = stack[3];
- curve.p4.x = stack[4];
- curve.p4.y = stack[5];
- curve.type = CURVE_BICUBIC;
- x = curve.p4.x;
- y = curve.p4.y;
- stack.clear();
+ else if (stack.size() == 6 && command == 'b') {
+ SplineCurve curve(pt,
+ scale.FromScriptCoords(Vector2D(stack[0], stack[1])),
+ scale.FromScriptCoords(Vector2D(stack[2], stack[3])),
+ scale.FromScriptCoords(Vector2D(stack[4], stack[5])));
push_back(curve);
- }
- // Close
- else if (lastCommand == 'c') {
+ pt = curve.p4;
stack.clear();
}
}
// Got something else
- else {
- if (token == "m") lastCommand = 'm';
- else if (token == "l") lastCommand = 'l';
- else if (token == "b") lastCommand = 'b';
- else if (token == "n") lastCommand = 'n';
- else if (token == "s") lastCommand = 's';
- else if (token == "c") lastCommand = 'c';
+ else if (token.size() == 1) {
+ command = token[0];
+ stack.clear();
}
}
}
-/// @brief Moves a specific point in the spline
-/// @param curveIndex
-/// @param point
-/// @param pos
-void Spline::MovePoint(iterator curve,int point,Vector2D const& pos) {
+void Spline::MovePoint(iterator curve,int point,Vector2D pos) {
iterator prev = curve;
if (curve != begin()) --prev;
iterator next = curve;
++next;
- if (next != end() && next->type == CURVE_POINT) next = end();
+ if (next != end() && next->type == SplineCurve::POINT)
+ next = end();
// Modify
if (point == 0) {
curve->p1 = pos;
- if (curve != begin() && curve->type != CURVE_POINT) prev->EndPoint() = pos;
- if (next != end() && curve->type == CURVE_POINT) next->p1 = pos;
+ if (curve != begin() && curve->type != SplineCurve::POINT)
+ prev->EndPoint() = pos;
+ if (next != end() && curve->type == SplineCurve::POINT)
+ next->p1 = pos;
}
else if (point == 1) {
curve->p2 = pos;
- if (next != end() && curve->type == CURVE_LINE) next->p1 = pos;
+ if (next != end() && curve->type == SplineCurve::LINE)
+ next->p1 = pos;
}
else if (point == 2) {
curve->p3 = pos;
}
else if (point == 3) {
curve->p4 = pos;
- if (next != end()) next->p1 = pos;
+ if (next != end())
+ next->p1 = pos;
}
}
-/// @brief Gets a list of points in the curve
-/// @param points
-/// @param pointCurve
+static int render_bicubic(Spline::iterator cur, std::vector &points) {
+ int len = int(
+ (cur->p2 - cur->p1).Len() +
+ (cur->p3 - cur->p2).Len() +
+ (cur->p4 - cur->p3).Len());
+ int steps = len/8;
+
+ for (int i = 0; i <= steps; ++i) {
+ // Get t and t-1 (u)
+ float t = i / float(steps);
+ Vector2D p = cur->GetPoint(t);
+ points.push_back(p.X());
+ points.push_back(p.Y());
+ }
+
+ return steps;
+}
+
void Spline::GetPointList(std::vector& points, std::vector& first, std::vector& count) {
points.clear();
first.clear();
@@ -232,106 +204,65 @@ void Spline::GetPointList(std::vector& points, std::vector& first, s
int curCount = 0;
// Generate points for each curve
- for (iterator cur = begin();cur!=end();cur++) {
+ for (iterator cur = begin(); cur != end(); ++cur) {
switch (cur->type) {
- case CURVE_POINT:
- if (curCount > 0) {
+ case SplineCurve::POINT:
+ if (curCount > 0)
count.push_back(curCount);
- }
// start new path
first.push_back(points.size() / 2);
- points.push_back(cur->p1.x);
- points.push_back(cur->p1.y);
+ points.push_back(cur->p1.X());
+ points.push_back(cur->p1.Y());
curCount = 1;
break;
- case CURVE_LINE:
- points.push_back(cur->p2.x);
- points.push_back(cur->p2.y);
- curCount++;
- break;
- case CURVE_BICUBIC: {
- // Get the control points
- Vector2D p1 = cur->p1;
- Vector2D p2 = cur->p2;
- Vector2D p3 = cur->p3;
- Vector2D p4 = cur->p4;
- // Find number of steps
- int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
- int steps = len/8;
-
- // Render curve
- for (int i=1;i<=steps;i++) {
- // Get t and t-1 (u)
- float t = float(i)/float(steps);
- Vector2D p = cur->GetPoint(t);
- points.push_back(p.x);
- points.push_back(p.y);
- }
- curCount += steps;
+ case SplineCurve::LINE:
+ points.push_back(cur->p2.X());
+ points.push_back(cur->p2.Y());
+ ++curCount;
break;
- }
+
+ case SplineCurve::BICUBIC:
+ curCount += render_bicubic(cur, points);
+ break;
+
default: break;
}
}
count.push_back(curCount);
}
+
void Spline::GetPointList(std::vector &points, iterator curve) {
points.clear();
if (curve == end()) return;
switch (curve->type) {
- case CURVE_LINE:
- points.push_back(curve->p1.x);
- points.push_back(curve->p1.y);
- points.push_back(curve->p2.x);
- points.push_back(curve->p2.y);
+ case SplineCurve::LINE:
+ points.push_back(curve->p1.X());
+ points.push_back(curve->p1.Y());
+ points.push_back(curve->p2.X());
+ points.push_back(curve->p2.Y());
break;
- case CURVE_BICUBIC: {
- // Get the control points
- Vector2D p1 = curve->p1;
- Vector2D p2 = curve->p2;
- Vector2D p3 = curve->p3;
- Vector2D p4 = curve->p4;
- // Find number of steps
- int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
- int steps = len/8;
-
- // Render curve
- for (int i=0;i<=steps;i++) {
- // Get t and t-1 (u)
- float t = float(i)/float(steps);
- Vector2D p = curve->GetPoint(t);
- points.push_back(p.x);
- points.push_back(p.y);
- }
+ case SplineCurve::BICUBIC:
+ render_bicubic(curve, points);
break;
- }
+
default: break;
}
}
-/// @brief t value and curve of the point closest to reference
-/// @param reference
-/// @param curve
-/// @param t
-/// @param pt
-void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve,float &t,Vector2D &pt) {
+void Spline::GetClosestParametricPoint(Vector2D reference,iterator &curve,float &t,Vector2D &pt) {
curve = end();
t = 0.f;
if (empty()) return;
// Close the shape
- SplineCurve pad;
- pad.p1 = back().EndPoint();
- pad.p2 = front().p1;
- pad.type = CURVE_LINE;
- push_back(pad);
+ push_back(SplineCurve(back().EndPoint(), front().p1));
float closest = std::numeric_limits::infinity();
- for (iterator cur = begin();cur!=end();cur++) {
+ for (iterator cur = begin(); cur != end(); ++cur) {
float param = cur->GetClosestParam(reference);
Vector2D p1 = cur->GetPoint(param);
float dist = (p1-reference).SquareLen();
@@ -351,19 +282,14 @@ void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve
pop_back();
}
-/// @brief Point closest to reference
-/// @param reference
-/// @return
-Vector2D Spline::GetClosestPoint(Vector2D const& reference) {
+Vector2D Spline::GetClosestPoint(Vector2D reference) {
iterator curve;
float t;
Vector2D point;
- GetClosestParametricPoint(reference,curve,t,point);
+ GetClosestParametricPoint(reference, curve, t, point);
return point;
}
-/// @brief Smoothes the spline
-/// @param smooth
void Spline::Smooth(float smooth) {
// See if there are enough curves
if (size() < 3) return;
@@ -371,13 +297,12 @@ void Spline::Smooth(float smooth) {
// Smooth curve
iterator curve1 = end();
--curve1;
- for (iterator cur = begin(); cur != end();) {
+ for (iterator cur = begin(); cur != end(); ) {
iterator curve0 = curve1;
curve1 = cur;
- cur++;
+ ++cur;
iterator curve2 = cur == end() ? begin() : cur;
- // Smooth curve
- curve1->Smooth(curve0->p1,curve2->p2,smooth);
+ curve1->Smooth(curve0->p1, curve2->p2, smooth);
}
}
diff --git a/aegisub/src/spline.h b/aegisub/src/spline.h
index 98e9f90c8..0eabd68f1 100644
--- a/aegisub/src/spline.h
+++ b/aegisub/src/spline.h
@@ -43,29 +43,41 @@
#include "spline_curve.h"
-class VideoDisplay;
+class VisualToolBase;
/// DOCME
/// @class Spline
/// @brief DOCME
class Spline : private std::list {
-private:
- const VideoDisplay &scale;
+ const VisualToolBase &scale;
public:
- Spline(const VideoDisplay &scale);
+ Spline(const VisualToolBase &scale);
+ /// Encode to an ASS vector drawing
wxString EncodeToASS();
+
+ /// Decode an ASS vector drawing
void DecodeFromASS(wxString str);
- void MovePoint(iterator curve,int point,Vector2D const& pos);
+ /// @brief Moves a specific point in the spline
+ /// @param curve Curve which the point is in
+ /// @param point Index in the curve
+ /// @param pos New position
+ void MovePoint(iterator curve, int point, Vector2D pos);
+
+ /// Smooth the spline
void Smooth(float smooth=1.0f);
+ /// Gets a list of points in the curve
void GetPointList(std::vector& points, std::vector& first, std::vector& count);
+ /// Gets a list of points in the curve
void GetPointList(std::vector &points, iterator curve);
- void GetClosestParametricPoint(Vector2D const& reference, iterator& curve, float &t, Vector2D &point);
- Vector2D GetClosestPoint(Vector2D const& reference);
- Vector2D GetClosestControlPoint(Vector2D const& reference);
+ /// Get t value and curve of the point closest to reference
+ void GetClosestParametricPoint(Vector2D reference, iterator& curve, float &t, Vector2D &point);
+ /// Get closest point on the curve to reference
+ Vector2D GetClosestPoint(Vector2D reference);
+ Vector2D GetClosestControlPoint(Vector2D reference);
// This list intentionally excludes things specific to std::list
using std::list::value_type;
diff --git a/aegisub/src/spline_curve.cpp b/aegisub/src/spline_curve.cpp
index 839e35d31..732ec1451 100644
--- a/aegisub/src/spline_curve.cpp
+++ b/aegisub/src/spline_curve.cpp
@@ -34,145 +34,103 @@
/// @ingroup visual_ts
///
-///////////
-// Headers
#include "config.h"
#include "spline_curve.h"
#include "utils.h"
-/// @brief Curve constructor
-///
-SplineCurve::SplineCurve() {
- type = CURVE_INVALID;
+#ifndef AGI_PRE
+#include
+#include
+#endif
+
+SplineCurve::SplineCurve(Vector2D p1) : p1(p1), type(POINT) { }
+SplineCurve::SplineCurve(Vector2D p1, Vector2D p2) : p1(p1), p2(p2), type(LINE) { }
+SplineCurve::SplineCurve(Vector2D p1, Vector2D p2, Vector2D p3, Vector2D p4)
+: p1(p1), p2(p2), p3(p3), p4(p4), type(BICUBIC)
+{
}
-/// @brief Split a curve in two using the de Casteljau algorithm
-/// @param c1
-/// @param c2
-/// @param t
-///
-void SplineCurve::Split(SplineCurve &c1,SplineCurve &c2,float t) {
- // Split a line
- if (type == CURVE_LINE) {
- c1.type = CURVE_LINE;
- c2.type = CURVE_LINE;
- c1.p1 = p1;
- c2.p2 = p2;
- c1.p2 = p1*(1-t)+p2*t;
- c2.p1 = c1.p2;
+void SplineCurve::Split(SplineCurve &c1, SplineCurve &c2, float t) {
+ if (type == LINE) {
+ c1 = SplineCurve(p1, p1 * (1 - t) + p2 * t);
+ c2 = SplineCurve(c1.p2, p2);
}
+ else if (type == BICUBIC) {
+ float u = 1 - t;
+ Vector2D p12 = p1 * u + p2 * t;
+ Vector2D p23 = p2 * u + p3 * t;
+ Vector2D p34 = p3 * u + p4 * t;
+ Vector2D p123 = p12 * u + p23 * t;
+ Vector2D p234 = p23 * u + p34 * t;
+ Vector2D p1234 = p123 * u + p234 * t;
- // Split a bicubic
- else if (type == CURVE_BICUBIC) {
- c1.type = CURVE_BICUBIC;
- c2.type = CURVE_BICUBIC;
-
- // Sub-divisions
- float u = 1-t;
- Vector2D p12 = p1*u+p2*t;
- Vector2D p23 = p2*u+p3*t;
- Vector2D p34 = p3*u+p4*t;
- Vector2D p123 = p12*u+p23*t;
- Vector2D p234 = p23*u+p34*t;
- Vector2D p1234 = p123*u+p234*t;
-
- // Set points
- c1.p1 = p1;
- c2.p4 = p4;
- c1.p2 = p12;
- c1.p3 = p123;
- c1.p4 = p1234;
- c2.p1 = p1234;
- c2.p2 = p234;
- c2.p3 = p34;
+ c1 = SplineCurve(p1, p12, p123, p1234);
+ c2 = SplineCurve(p1234, p234, p34, p4);
}
}
-/// @brief Based on http://antigrain.com/research/bezier_interpolation/index.html Smoothes the curve
-/// @param P0
-/// @param P3
-/// @param smooth
-/// @return
-///
-void SplineCurve::Smooth(Vector2D const& P0,Vector2D const& P3,float smooth) {
- // Validate
- if (type != CURVE_LINE) return;
- if (p1 == p2) return;
- smooth = mid(0.f,smooth,1.f);
-
- // Get points
- Vector2D P1 = p1;
- Vector2D P2 = p2;
+void SplineCurve::Smooth(Vector2D p0, Vector2D p3, float smooth) {
+ if (type != LINE || p1 == p2) return;
+ smooth = mid(0.f, smooth, 1.f);
// Calculate intermediate points
- Vector2D c1 = (P0+P1)/2.f;
- Vector2D c2 = (P1+P2)/2.f;
- Vector2D c3 = (P2+P3)/2.f;
- float len1 = (P1-P0).Len();
- float len2 = (P2-P1).Len();
- float len3 = (P3-P2).Len();
- float k1 = len1/(len1+len2);
- float k2 = len2/(len2+len3);
- Vector2D m1 = c1+(c2-c1)*k1;
- Vector2D m2 = c2+(c3-c2)*k2;
+ Vector2D c1 = (p0 + p1) / 2.f;
+ Vector2D c2 = (p1 + p2) / 2.f;
+ Vector2D c3 = (p2 + p3) / 2.f;
+
+ float len1 = (p1 - p0).Len();
+ float len2 = (p2 - p1).Len();
+ float len3 = (p3 - p2).Len();
+
+ float k1 = len1 / (len1 + len2);
+ float k2 = len2 / (len2 + len3);
+
+ Vector2D m1 = c1 + (c2 - c1) * k1;
+ Vector2D m2 = c2 + (c3 - c2) * k2;
// Set curve points
p4 = p2;
- p2 = m1+(c2-m1)*smooth + P1 - m1;
- p3 = m2+(c2-m2)*smooth + P2 - m2;
- type = CURVE_BICUBIC;
+ p3 = m2 + (c2 - m2) * smooth + p2 - m2;
+ p2 = m1 + (c2 - m1) * smooth + p1 - m1;
+ type = BICUBIC;
}
-/// @brief Get a point
-/// @param t
-/// @return
-///
Vector2D SplineCurve::GetPoint(float t) const {
- if (type == CURVE_POINT) return p1;
- if (type == CURVE_LINE) {
- return p1*(1.f-t) + p2*t;
- }
- if (type == CURVE_BICUBIC) {
- float u = 1.f-t;
- return p1*u*u*u + 3*p2*t*u*u + 3*p3*t*t*u + p4*t*t*t;
- }
+ float u = 1.f - t;
- return Vector2D(0,0);
+ if (type == POINT)
+ return p1;
+ if (type == LINE)
+ return p1 * u + p2 * t;
+
+ return p1*u*u*u + 3*p2*t*u*u + 3*p3*t*t*u + p4*t*t*t;
}
Vector2D& SplineCurve::EndPoint() {
switch (type) {
- case CURVE_POINT: return p1;
- case CURVE_LINE: return p2;
- case CURVE_BICUBIC: return p4;
- default: return p1;
+ case POINT: return p1;
+ case LINE: return p2;
+ case BICUBIC: return p4;
+ default: return p1;
}
}
-/// @brief Get point closest to reference
-/// @param ref
-/// @return
-///
-Vector2D SplineCurve::GetClosestPoint(Vector2D const& ref) const {
+Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const {
return GetPoint(GetClosestParam(ref));
}
-/// @brief Get value of parameter closest to point
-/// @param ref
-/// @return
-///
-float SplineCurve::GetClosestParam(Vector2D const& ref) const {
- if (type == CURVE_LINE) {
- return GetClosestSegmentPart(p1,p2,ref);
- }
- if (type == CURVE_BICUBIC) {
+float SplineCurve::GetClosestParam(Vector2D ref) const {
+ if (type == LINE)
+ return GetClosestSegmentPart(p1, p2, ref);
+
+ if (type == BICUBIC) {
int steps = 100;
- float bestDist = 80000000.f;
+ float bestDist = std::numeric_limits::max();
float bestT = 0.f;
- for (int i=0;i<=steps;i++) {
- float t = float(i)/float(steps);
- float dist = (GetPoint(t)-ref).Len();
+ for (int i = 0; i <= steps; ++i) {
+ float t = i / float(steps);
+ float dist = (GetPoint(t) - ref).SquareLen();
if (dist < bestDist) {
bestDist = dist;
bestT = t;
@@ -180,45 +138,30 @@ float SplineCurve::GetClosestParam(Vector2D const& ref) const {
}
return bestT;
}
+
return 0.f;
}
-/// @brief Quick distance
-/// @param ref
-/// @return
-///
-float SplineCurve::GetQuickDistance(Vector2D const& ref) const {
- using std::min;
- if (type == CURVE_BICUBIC) {
- float len1 = GetClosestSegmentDistance(p1,p2,ref);
- float len2 = GetClosestSegmentDistance(p2,p3,ref);
- float len3 = GetClosestSegmentDistance(p3,p4,ref);
- float len4 = GetClosestSegmentDistance(p4,p1,ref);
- float len5 = GetClosestSegmentDistance(p1,p3,ref);
- float len6 = GetClosestSegmentDistance(p2,p4,ref);
- return min(min(min(len1,len2),min(len3,len4)),min(len5,len6));
+float SplineCurve::GetQuickDistance(Vector2D ref) const {
+ if (type == BICUBIC) {
+ float lens[] = {
+ GetClosestSegmentDistance(p1, p2, ref),
+ GetClosestSegmentDistance(p2, p3, ref),
+ GetClosestSegmentDistance(p3, p4, ref),
+ GetClosestSegmentDistance(p4, p1, ref),
+ GetClosestSegmentDistance(p1, p3, ref),
+ GetClosestSegmentDistance(p2, p4, ref)
+ };
+ return *std::min_element(lens, lens + 6);
}
-
- // Something else
- else return (GetClosestPoint(ref)-ref).Len();
+ return (GetClosestPoint(ref) - ref).Len();
}
-/// @brief Closest t in segment p1-p2 to point p3
-/// @param pt1
-/// @param pt2
-/// @param pt3
-/// @return
-///
-float SplineCurve::GetClosestSegmentPart(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
- return mid(0.f,(pt3-pt1).Dot(pt2-pt1)/(pt2-pt1).SquareLen(),1.f);
+float SplineCurve::GetClosestSegmentPart(Vector2D pt1, Vector2D pt2, Vector2D pt3) const {
+ return mid(0.f, (pt3 - pt1).Dot(pt2 - pt1) / (pt2 - pt1).SquareLen(), 1.f);
}
-/// @brief Closest distance between p3 and segment p1-p2
-/// @param pt1
-/// @param pt2
-/// @param pt3
-///
-float SplineCurve::GetClosestSegmentDistance(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
- float t = GetClosestSegmentPart(pt1,pt2,pt3);
- return (pt1*(1.f-t)+pt2*t-pt3).Len();
+float SplineCurve::GetClosestSegmentDistance(Vector2D pt1, Vector2D pt2, Vector2D pt3) const {
+ float t = GetClosestSegmentPart(pt1, pt2, pt3);
+ return (pt1 * (1.f - t) + pt2 * t - pt3).Len();
}
diff --git a/aegisub/src/spline_curve.h b/aegisub/src/spline_curve.h
index 0da098ced..0bd38c435 100644
--- a/aegisub/src/spline_curve.h
+++ b/aegisub/src/spline_curve.h
@@ -34,57 +34,54 @@
/// @ingroup visual_ts
///
-///////////
-// Headers
#include "vector2d.h"
-/// DOCME
-enum CurveType {
-
- /// DOCME
- CURVE_INVALID,
-
- /// DOCME
- CURVE_POINT,
-
- /// DOCME
- CURVE_LINE,
-
- /// DOCME
- CURVE_BICUBIC
-};
-
/// DOCME
/// @class SplineCurve
/// @brief DOCME
///
/// DOCME
class SplineCurve {
-private:
- float GetClosestSegmentPart(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
- float GetClosestSegmentDistance(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
+ /// Closest t in segment p1-p2 to point p3
+ float GetClosestSegmentPart(Vector2D p1, Vector2D p2, Vector2D p3) const;
+ /// Closest distance between p3 and segment p1-p2
+ float GetClosestSegmentDistance(Vector2D p1, Vector2D p2, Vector2D p3) const;
public:
+ enum CurveType {
+ POINT,
+ LINE,
+ BICUBIC
+ };
- /// DOCME
-
- /// DOCME
-
- /// DOCME
-
- /// DOCME
- Vector2D p1,p2,p3,p4;
+ Vector2D p1;
+ Vector2D p2;
+ Vector2D p3;
+ Vector2D p4;
/// DOCME
CurveType type;
- SplineCurve();
- void Split(SplineCurve &c1,SplineCurve &c2,float t=0.5);
- void Smooth(Vector2D const& prev,Vector2D const& next,float smooth=1.0f);
+ SplineCurve(Vector2D p1 = Vector2D());
+ SplineCurve(Vector2D p1, Vector2D p2);
+ SplineCurve(Vector2D p1, Vector2D p2, Vector2D p3, Vector2D p4);
+
+ /// @brief Split a curve in two using the de Casteljau algorithm
+ /// @param[out] c1 Curve before split point
+ /// @param[out] c2 Curve after split point
+ /// @param t Split point
+ void Split(SplineCurve &c1, SplineCurve &c2, float t = 0.5f);
+
+ /// @brief Smooths the curve
+ /// @note Based on http://antigrain.com/research/bezier_interpolation/index.html
+ void Smooth(Vector2D prev, Vector2D next, float smooth = 1.0f);
Vector2D GetPoint(float t) const;
Vector2D& EndPoint();
- Vector2D GetClosestPoint(Vector2D const& ref) const;
- float GetClosestParam(Vector2D const& ref) const;
- float GetQuickDistance(Vector2D const& ref) const;
+ /// Get point on the curve closest to reference
+ Vector2D GetClosestPoint(Vector2D ref) const;
+ /// Get t value for the closest point to reference
+ float GetClosestParam(Vector2D ref) const;
+ /// Get distance from ref to the closest point on the curve
+ float GetQuickDistance(Vector2D ref) const;
};
diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp
index d5de9e976..63600a8a6 100644
--- a/aegisub/src/subs_edit_box.cpp
+++ b/aegisub/src/subs_edit_box.cpp
@@ -74,7 +74,6 @@
#include "utils.h"
#include "validators.h"
#include "video_context.h"
-#include "video_display.h"
enum {
BUTTON_BOLD = 1300,
diff --git a/aegisub/src/toolbar.cpp b/aegisub/src/toolbar.cpp
index 896d0362a..9f8846f6f 100644
--- a/aegisub/src/toolbar.cpp
+++ b/aegisub/src/toolbar.cpp
@@ -166,8 +166,8 @@ namespace {
}
public:
- Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context)
- : wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_HORIZONTAL)
+ Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context, bool vertical)
+ : wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | (vertical ? wxTB_VERTICAL : wxTB_HORIZONTAL))
, name(name)
, context(c)
, ht_context(ht_context)
@@ -182,10 +182,10 @@ namespace {
namespace toolbar {
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *c, std::string const& hotkey) {
- frame->SetToolBar(new Toolbar(frame, name, c, hotkey));
+ frame->SetToolBar(new Toolbar(frame, name, c, hotkey, false));
}
- wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& hotkey) {
- return new Toolbar(parent, name, c, hotkey);
+ wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& hotkey, bool vertical) {
+ return new Toolbar(parent, name, c, hotkey, vertical);
}
}
diff --git a/aegisub/src/vector2d.cpp b/aegisub/src/vector2d.cpp
index b83754c8e..66ff49c08 100644
--- a/aegisub/src/vector2d.cpp
+++ b/aegisub/src/vector2d.cpp
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -34,238 +21,77 @@
/// @ingroup utility visual_ts
///
-
-///////////
-// Headers
#include "config.h"
-#ifndef AGI_PRE
-#include
-#endif
-
#include "vector2d.h"
+#ifndef AGI_PRE
+#include
-/// @brief Null constructor
-///
-Vector2D::Vector2D () {
- x = y = 0;
+#include
+#endif
+
+Vector2D operator *(float f, Vector2D v) {
+ return Vector2D(v.X() * f, v.Y() * f);
}
-
-
-/// @brief Standard constructor
-/// @param _x
-/// @param _y
-///
-Vector2D::Vector2D (float _x,float _y) {
- x = _x;
- y = _y;
+Vector2D operator /(float f, Vector2D v) {
+ return Vector2D(f / v.X(), f / v.Y());
}
-
-
-/// @brief Construction from another vector
-/// @param vec
-///
-Vector2D::Vector2D (const Vector2D &vec) {
- x = vec.x;
- y = vec.y;
+Vector2D operator +(float f, Vector2D v) {
+ return Vector2D(v.X() + f, v.Y() + f);
}
-
-
-/// @brief Assignment
-/// @param param
-///
-void Vector2D::operator = (const Vector2D param) {
- x = param.x;
- y = param.y;
+Vector2D operator -(float f, Vector2D v) {
+ return Vector2D(f - v.X(), f - v.Y());
}
-
-
-/// @brief Comparison
-/// @param param
-/// @return
-///
-bool Vector2D::operator == (const Vector2D param) const {
- return ((x == param.x) && (y == param.y));
+Vector2D Vector2D::Unit() const {
+ float len = Len();
+ if (len == 0)
+ return Vector2D(0, 0);
+ return *this / len;
}
-
-/// @brief DOCME
-/// @param param
-/// @return
-///
-bool Vector2D::operator != (const Vector2D param) const {
- return ((x != param.x) || (y == param.y));
+Vector2D Vector2D::SingleAxis() const {
+ if (abs(x) < abs(y))
+ return Vector2D(0, y);
+ else
+ return Vector2D(x, 0);
}
-
-
-/// @brief Adition
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator + (const Vector2D param) const {
- return Vector2D(x + param.x,y + param.y);
+Vector2D Vector2D::Max(Vector2D param) const {
+ return Vector2D(std::max(x, param.x), std::max(y, param.y));
}
-
-/// @brief DOCME
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator += (const Vector2D param) {
- x += param.x;
- y += param.y;
- return *this;
+Vector2D Vector2D::Min(Vector2D param) const {
+ return Vector2D(std::min(x, param.x), std::min(y, param.y));
}
-
-
-/// @brief Subtraction
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator - (const Vector2D param) const {
- return Vector2D(x - param.x,y - param.y);
+Vector2D Vector2D::Round(float step) const {
+ return Vector2D(floorf(x / step + .5f) * step, floorf(y / step + .5f) * step);
}
-
-/// @brief DOCME
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator -= (const Vector2D param) {
- x -= param.x;
- y -= param.y;
- return *this;
+Vector2D::operator unspecified_bool_type() const {
+ return *this == Bad() ? 0 : &Vector2D::x;
}
-
-
-/// @brief Negate
-/// @return
-///
-Vector2D Vector2D::operator - () const {
- return Vector2D(-x,-y);
+Vector2D Vector2D::Bad() {
+ return Vector2D(std::numeric_limits::min(), std::numeric_limits::min());
}
-
-
-/// @brief Multiplication by scalar
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator * (float param) const {
- return Vector2D(x * param,y * param);
+wxString Vector2D::PStr(char sep) const {
+ return "(" + Str(sep) + ")";
}
-
-/// @brief DOCME
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator *= (float param) {
- x *= param;
- y *= param;
- return *this;
+wxString Vector2D::DStr(char sep) const {
+ return wxString::Format("%d%c%d", (int)x, sep, (int)y);
}
-
-/// @brief DOCME
-/// @param f
-/// @param v
-/// @return
-///
-Vector2D operator * (float f,const Vector2D &v) {
- return Vector2D(v.x * f,v.y * f);
+wxString Vector2D::Str(char sep) const {
+ return
+ wxNumberFormatter::ToString(x, 3, wxNumberFormatter::Style_NoTrailingZeroes) +
+ sep +
+ wxNumberFormatter::ToString(y, 3, wxNumberFormatter::Style_NoTrailingZeroes);
}
-
-
-
-/// @brief Division by scalar
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator / (float param) const {
- return Vector2D(x / param,y / param);
-}
-
-
-/// @brief DOCME
-/// @param param
-/// @return
-///
-Vector2D Vector2D::operator /= (float param) {
- x /= param;
- y /= param;
- return *this;
-}
-
-
-/// @brief DOCME
-/// @param f
-/// @param v
-/// @return
-///
-Vector2D operator / (float f,const Vector2D &v) {
- return Vector2D(v.x / f,v.y / f);
-}
-
-
-
-/// @brief Cross product
-/// @param param
-/// @return
-///
-float Vector2D::Cross (const Vector2D param) const {
- return x * param.y - y * param.x;
-}
-
-
-
-/// @brief Dot product
-/// @param param
-/// @return
-///
-float Vector2D::Dot (const Vector2D param) const {
- return (x * param.x) + (y * param.y);
-}
-
-
-
-/// @brief Length
-/// @return
-///
-float Vector2D::Len () const {
- return sqrt(x*x + y*y);
-}
-
-
-
-/// @brief Squared Length
-/// @return
-///
-float Vector2D::SquareLen () const {
- return x*x + y*y;
-}
-
-
-
-/// @brief Unitary
-///
-Vector2D Vector2D::Unit () const {
- float l = Len();
- if (l != 0) {
- Vector2D temp;
- temp.x = x;
- temp.y = y;
- return temp / l;
- }
- else return Vector2D(0,0);
-}
-
-
diff --git a/aegisub/src/vector2d.h b/aegisub/src/vector2d.h
index 147f5dd95..7301477e8 100644
--- a/aegisub/src/vector2d.h
+++ b/aegisub/src/vector2d.h
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -34,8 +21,13 @@
/// @ingroup utility visual_ts
///
+#pragma once
+#ifndef AGI_PRE
+#include
+#include
+#endif
/// DOCME
/// @class Vector2D
@@ -43,53 +35,62 @@
///
/// DOCME
class Vector2D {
+ float x, y;
+
+ typedef float Vector2D::*unspecified_bool_type;
public:
+ float X() const { return x; }
+ float Y() const { return y; }
- /// DOCME
+ Vector2D() : x(0), y(0) { }
+ Vector2D(float x, float y) : x(x), y(y) { }
+ Vector2D(wxPoint pt) : x(pt.x), y(pt.y) { }
+ Vector2D(Vector2D x, Vector2D y) : x(x.x), y(y.y) { }
+ Vector2D(float x, Vector2D y) : x(x), y(y.y) { }
+ Vector2D(Vector2D x, float y) : x(x.x), y(y) { }
- /// DOCME
- float x,y;
+ bool operator ==(const Vector2D r) const { return x == r.x && y == r.y; }
+ bool operator !=(const Vector2D r) const { return x != r.x || y != r.y; }
+ operator unspecified_bool_type() const;
- Vector2D ();
- Vector2D (float _x,float _y);
- Vector2D (const Vector2D &vec);
+ Vector2D operator -() const { return Vector2D(-x, -y); }
+ Vector2D operator +(const Vector2D r) const { return Vector2D(x + r.x, y + r.y); }
+ Vector2D operator -(const Vector2D r) const { return Vector2D(x - r.x, y - r.y); }
+ Vector2D operator *(const Vector2D r) const { return Vector2D(x * r.x, y * r.y); }
+ Vector2D operator /(const Vector2D r) const { return Vector2D(x / r.x, y / r.y); }
+ Vector2D operator +(float param) const { return Vector2D(x + param, y + param); }
+ Vector2D operator -(float param) const { return Vector2D(x - param, y - param); }
+ Vector2D operator *(float param) const { return Vector2D(x * param, y * param); }
+ Vector2D operator /(float param) const { return Vector2D(x / param, y / param); }
- void operator = (const Vector2D param);
- bool operator == (const Vector2D param) const;
- bool operator != (const Vector2D param) const;
+ Vector2D Unit() const;
+ Vector2D SingleAxis() const;
- Vector2D operator - () const;
- Vector2D operator + (const Vector2D param) const;
- Vector2D operator - (const Vector2D param) const;
- Vector2D operator * (float param) const;
- Vector2D operator / (float param) const;
+ Vector2D Perpendicular() const { return Vector2D(-y, x); }
- Vector2D operator += (const Vector2D param);
- Vector2D operator -= (const Vector2D param);
- Vector2D operator *= (float param);
- Vector2D operator /= (float param);
+ Vector2D Max(Vector2D param) const;
+ Vector2D Min(Vector2D param) const;
+ Vector2D Round(float step) const;
- Vector2D Unit () const;
- float Cross (const Vector2D param) const;
- float Dot (const Vector2D param) const;
+ float Cross(const Vector2D param) const { return x * param.y - y * param.x; }
+ float Dot(const Vector2D param) const { return x * param.x + y * param.y; }
- float Len () const;
+ float Len() const { return sqrt(x*x + y*y); }
+ float SquareLen() const { return x*x + y*y; }
+ float Angle() const { return atan2(y, x); }
- /// @brief DOCME
- /// @return
- ///
- float Length () const { return Len(); }
- float SquareLen () const;
+ /// Get as string with given separator
+ wxString Str(char sep = ',') const;
+ /// Get as string surrounded by parentheses with given separator
+ wxString PStr(char sep = ',') const;
+ /// Get as string with given separator with values rounded to ints
+ wxString DStr(char sep = ',') const;
- /// @brief DOCME
- ///
- float SquareLength () const { return SquareLen(); }
+ static Vector2D FromAngle(float angle) { return Vector2D(cos(-angle), sin(-angle)); }
+ static Vector2D Bad();
};
-
-////////////////////
-// Global operators
-Vector2D operator * (float f,const Vector2D &v);
-Vector2D operator / (float f,const Vector2D &v);
-
-
+Vector2D operator * (float f, Vector2D v);
+Vector2D operator / (float f, Vector2D v);
+Vector2D operator + (float f, Vector2D v);
+Vector2D operator - (float f, Vector2D v);
diff --git a/aegisub/src/video_box.cpp b/aegisub/src/video_box.cpp
index a5189178a..3bc133d83 100644
--- a/aegisub/src/video_box.cpp
+++ b/aegisub/src/video_box.cpp
@@ -44,6 +44,7 @@
#endif
#include "include/aegisub/context.h"
+#include "include/aegisub/toolbar.h"
#include "ass_dialogue.h"
#include "ass_file.h"
@@ -104,22 +105,11 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, agi::Context *context)
zoomBox = new wxComboBox(this, -1, "75%", wxDefaultPosition, wxDefaultSize, choices, wxCB_DROPDOWN);
// Typesetting buttons
- visualToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,wxTB_VERTICAL|wxTB_FLAT|wxTB_NODIVIDER);
- visualToolBar->AddTool(Video_Mode_Standard,_("Standard"),GETIMAGE(visual_standard_24),_("Standard mode, double click sets position."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Drag,_("Drag"),GETIMAGE(visual_move_24),_("Drag subtitles."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Rotate_Z,_("Rotate Z"),GETIMAGE(visual_rotatez_24),_("Rotate subtitles on their Z axis."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Rotate_XY,_("Rotate XY"),GETIMAGE(visual_rotatexy_24),_("Rotate subtitles on their X and Y axes."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Scale,_("Scale"),GETIMAGE(visual_scale_24),_("Scale subtitles on X and Y axes."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Clip,_("Clip"),GETIMAGE(visual_clip_24),_("Clip subtitles to a rectangle."),wxITEM_RADIO);
- visualToolBar->AddTool(Video_Mode_Vector_Clip,_("Vector Clip"),GETIMAGE(visual_vector_clip_24),_("Clip subtitles to a vectorial area."),wxITEM_RADIO);
- visualToolBar->AddSeparator();
- visualToolBar->AddTool(wxID_HELP,_("Help"),cmd::get("help/video")->Icon(24),_("Open the manual page for Visual Typesetting."));
- visualToolBar->Realize();
+ visualToolBar = toolbar::GetToolbar(this, "visual_tools", context, "Video", true);
// Avoid ugly themed background on Vista and possibly also Win7
visualToolBar->SetBackgroundStyle(wxBG_STYLE_COLOUR);
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
- // Display
videoDisplay = new VideoDisplay(this,isDetached,zoomBox,this,context);
// Top sizer
diff --git a/aegisub/src/video_box.h b/aegisub/src/video_box.h
index 1899ac80a..e3d0e8cc7 100644
--- a/aegisub/src/video_box.h
+++ b/aegisub/src/video_box.h
@@ -92,14 +92,3 @@ public:
VideoBox(wxWindow *parent, bool isDetached, agi::Context *context);
~VideoBox();
};
-
-// IDs
-enum {
- Video_Mode_Standard = 5000,
- Video_Mode_Drag,
- Video_Mode_Rotate_Z,
- Video_Mode_Rotate_XY,
- Video_Mode_Scale,
- Video_Mode_Clip,
- Video_Mode_Vector_Clip,
-};
diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp
index 79cb1c16e..61c0b8d00 100644
--- a/aegisub/src/video_context.cpp
+++ b/aegisub/src/video_context.cpp
@@ -266,7 +266,8 @@ void VideoContext::JumpToFrame(int n) {
frame_n = mid(0, n, GetLength() - 1);
- Seek(n);
+ GetFrameAsync(frame_n);
+ Seek(frame_n);
}
void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
@@ -274,11 +275,11 @@ void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
}
void VideoContext::GetFrameAsync(int n) {
- provider->RequestFrame(n,videoFPS.TimeAtFrame(n)/1000.0);
+ provider->RequestFrame(n, videoFPS.TimeAtFrame(n) / 1000.0);
}
std::tr1::shared_ptr VideoContext::GetFrame(int n, bool raw) {
- return provider->GetFrame(n, videoFPS.TimeAtFrame(n)/1000.0, raw);
+ return provider->GetFrame(n, videoFPS.TimeAtFrame(n) / 1000.0, raw);
}
int VideoContext::GetWidth() const {
@@ -326,10 +327,6 @@ void VideoContext::SaveSnapshot(bool raw) {
GetFrame(frame_n,raw)->GetImage().SaveFile(path,wxBITMAP_TYPE_PNG);
}
-void VideoContext::GetScriptSize(int &sw,int &sh) {
- context->ass->GetResolution(sw,sh);
-}
-
void VideoContext::NextFrame() {
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
return;
diff --git a/aegisub/src/video_context.h b/aegisub/src/video_context.h
index c65491de7..56f9165bd 100644
--- a/aegisub/src/video_context.h
+++ b/aegisub/src/video_context.h
@@ -232,13 +232,6 @@ public:
/// @param end Type of time
void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START);
- /// @brief Get the height and width of the current script
- /// @param[out] w Width
- /// @param[out] h Height
- ///
- /// This probably shouldn't be in VideoContext
- void GetScriptSize(int &w,int &h);
-
/// Starting playing the video
void Play();
/// Play the next frame then stop
diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp
index 3be8866b1..fe61828a9 100644
--- a/aegisub/src/video_display.cpp
+++ b/aegisub/src/video_display.cpp
@@ -56,13 +56,13 @@
#include
#endif
-#include "include/aegisub/context.h"
-#include "include/aegisub/hotkey.h"
-#include "include/aegisub/menu.h"
-
#include "video_display.h"
#include "ass_file.h"
+#include "command/command.h"
+#include "include/aegisub/context.h"
+#include "include/aegisub/hotkey.h"
+#include "include/aegisub/menu.h"
#include "main.h"
#include "threaded_frame_source.h"
#include "utils.h"
@@ -70,13 +70,6 @@
#include "video_box.h"
#include "video_context.h"
#include "visual_tool.h"
-#include "visual_tool_clip.h"
-#include "visual_tool_cross.h"
-#include "visual_tool_drag.h"
-#include "visual_tool_rotatexy.h"
-#include "visual_tool_rotatez.h"
-#include "visual_tool_scale.h"
-#include "visual_tool_vector_clip.h"
/// Attribute list for gl canvases; set the canvases to doublebuffered rgba with an 8 bit stencil buffer
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
@@ -104,14 +97,17 @@ VideoDisplay::VideoDisplay(
: wxGLCanvas (parent, -1, attribList, wxDefaultPosition, wxDefaultSize, 0, wxPanelNameStr)
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
, con(c)
-, currentFrame(-1)
-, w(8), h(8), viewport_x(0), viewport_width(0), viewport_bottom(0), viewport_top(0), viewport_height(0)
+, w(8)
+, h(8)
+, mouse_pos(Vector2D::Bad())
+, viewport_left(0)
+, viewport_width(0)
+, viewport_bottom(0)
+, viewport_top(0)
+, viewport_height(0)
, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125)
, videoOut(new VideoOutGL())
-, activeMode(Video_Mode_Standard)
, toolBar(box->visualSubToolBar)
-, scriptW(INT_MIN)
-, scriptH(INT_MIN)
, zoomBox(zoomBox)
, box(box)
, freeSize(freeSize)
@@ -120,34 +116,29 @@ VideoDisplay::VideoDisplay(
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
zoomBox->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &VideoDisplay::SetZoomFromBox, this);
- box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VideoDisplay::OnMode, this, Video_Mode_Standard, Video_Mode_Vector_Clip);
con->videoController->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
- slots.push_back(con->videoController->AddSeekListener(&VideoDisplay::SetFrame, this));
slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this));
slots.push_back(con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this));
- slots.push_back(con->ass->AddCommitListener(&VideoDisplay::OnCommit, this));
Bind(wxEVT_PAINT, std::tr1::bind(&VideoDisplay::Render, this));
if (freeSize) {
Bind(wxEVT_SIZE, &VideoDisplay::OnSizeEvent, this);
}
Bind(wxEVT_CONTEXT_MENU, &VideoDisplay::OnContextMenu, this);
+ Bind(wxEVT_ENTER_WINDOW, &VideoDisplay::OnMouseEvent, this);
Bind(wxEVT_KEY_DOWN, &VideoDisplay::OnKeyDown, this);
+ Bind(wxEVT_LEAVE_WINDOW, &VideoDisplay::OnMouseLeave, this);
Bind(wxEVT_LEFT_DCLICK, &VideoDisplay::OnMouseEvent, this);
Bind(wxEVT_LEFT_DOWN, &VideoDisplay::OnMouseEvent, this);
Bind(wxEVT_LEFT_UP, &VideoDisplay::OnMouseEvent, this);
Bind(wxEVT_MOTION, &VideoDisplay::OnMouseEvent, this);
- Bind(wxEVT_ENTER_WINDOW, &VideoDisplay::OnMouseEnter, this);
- Bind(wxEVT_LEAVE_WINDOW, &VideoDisplay::OnMouseLeave, this);
Bind(wxEVT_MOUSEWHEEL, &VideoDisplay::OnMouseWheel, this);
SetCursor(wxNullCursor);
- if (con->videoController->IsLoaded()) {
- con->videoController->GetScriptSize(scriptW, scriptH);
+ if (con->videoController->IsLoaded())
OnVideoOpen();
- }
}
VideoDisplay::~VideoDisplay () {
@@ -163,25 +154,6 @@ bool VideoDisplay::InitContext() {
return true;
}
-void VideoDisplay::ShowCursor(bool show) {
- if (show) {
- SetCursor(wxNullCursor);
- }
- else {
- SetCursor(wxCursor(wxCURSOR_BLANK));
- }
-}
-
-void VideoDisplay::SetFrame(int frameNumber) {
- currentFrame = frameNumber;
-
- // Render the new frame
- if (con->videoController->IsLoaded()) {
- tool->SetFrame(frameNumber);
- con->videoController->GetFrameAsync(currentFrame);
- }
-}
-
void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
if (!InitContext()) return;
@@ -207,16 +179,10 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
void VideoDisplay::OnVideoOpen() {
if (!con->videoController->IsLoaded()) return;
+ if (!tool.get())
+ cmd::call("video/tool/cross", con);
UpdateSize();
- if (!tool.get()) tool.reset(new VisualToolCross(this, con, video, toolBar));
- SetFrame(0);
- tool->Refresh();
-}
-
-void VideoDisplay::OnCommit(int type) {
- if (type == AssFile::COMMIT_NEW || type & AssFile::COMMIT_SCRIPTINFO)
- con->videoController->GetScriptSize(scriptW, scriptH);
- if (tool.get()) tool->Refresh();
+ con->videoController->JumpToFrame(0);
}
void VideoDisplay::Render() try {
@@ -225,7 +191,7 @@ void VideoDisplay::Render() try {
assert(wxIsMainThread());
if (!viewport_height || !viewport_width) UpdateSize();
- videoOut->Render(viewport_x, viewport_bottom, viewport_width, viewport_height);
+ videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height);
E(glViewport(0, std::min(viewport_bottom, 0), w, h));
E(glMatrixMode(GL_PROJECTION));
@@ -238,73 +204,55 @@ void VideoDisplay::Render() try {
// Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
// 16:9 or wider
if (ar > 1.75) {
- DrawOverscanMask(w * 0.1, h * 0.05, wxColor(30,70,200),0.5);
- DrawOverscanMask(w * 0.035, h * 0.035, wxColor(30,70,200),0.5);
+ DrawOverscanMask(.1f, .05f);
+ DrawOverscanMask(0.035f, 0.035f);
}
-
// Less wide than 16:9 (use 4:3 standard)
else {
- DrawOverscanMask(w * 0.067, h * 0.05, wxColor(30,70,200),0.5);
- DrawOverscanMask(w * 0.033, h * 0.035, wxColor(30,70,200),0.5);
+ DrawOverscanMask(.067f, .05f);
+ DrawOverscanMask(0.033f, 0.035f);
}
}
- if (video.x > INT_MIN || video.y > INT_MIN || alwaysShowTools->GetBool()) {
+ if (mouse_pos || alwaysShowTools->GetBool()) {
if (!con->videoController->IsPlaying())
tool->Draw();
}
SwapBuffers();
}
-catch (const VideoOutException &err) {
+catch (const agi::Exception &err) {
wxLogError(
"An error occurred trying to render the video frame on the screen.\n"
"Error message reported: %s",
- err.GetMessage());
- con->videoController->Reset();
-}
-catch (const OpenGlException &err) {
- wxLogError(
- "An error occurred trying to render visual overlays on the screen.\n"
- "Error message reported: %s",
- err.GetMessage());
- con->videoController->Reset();
-}
-catch (const char *err) {
- wxLogError(
- "An error occurred trying to render the video frame on the screen.\n"
- "Error message reported: %s",
- err);
- con->videoController->Reset();
-}
-catch (...) {
- wxLogError(
- "An error occurred trying to render the video frame to screen.\n"
- "No further error message given.");
+ err.GetChainedMessage());
con->videoController->Reset();
}
-void VideoDisplay::DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const {
+void VideoDisplay::DrawOverscanMask(float horizontal_percent, float vertical_percent) const {
+ Vector2D size(w * horizontal_percent / 2, h * vertical_percent / 2);
int rad1 = h * 0.05;
- int gapH = sizeH+rad1;
- int gapV = sizeV+rad1;
- int rad2 = sqrt(double(gapH*gapH + gapV*gapV)) + 1;
+ Vector2D gap = size + rad1;
+ int rad2 = gap.Len() + 1;
+ Vector2D v(w, h);
+ Vector2D igap = v - gap;
+ Vector2D isize = v - size;
OpenGLWrapper gl;
- E(gl.SetFillColour(color, alpha));
- gl.SetLineColour(wxColor(0, 0, 0), 0.0, 1);
+ gl.SetFillColour(wxColor(30, 70, 200), .5f);
+ gl.SetLineColour(*wxBLACK, 0, 1);
// Draw sides
- E(gl.DrawRectangle(gapH, 0, w-gapH, sizeV)); // Top
- E(gl.DrawRectangle(w-sizeH, gapV, w, h-gapV)); // Right
- E(gl.DrawRectangle(gapH, h-sizeV, w-gapH, h)); // Bottom
- E(gl.DrawRectangle(0, gapV, sizeH, h-gapV)); // Left
+ gl.DrawRectangle(Vector2D(gap, 0), Vector2D(igap, size)); // Top
+ gl.DrawRectangle(Vector2D(isize, gap), Vector2D(v, igap)); // Right
+ gl.DrawRectangle(Vector2D(gap, isize), Vector2D(igap, v)); // Bottom
+ gl.DrawRectangle(Vector2D(0, gap), Vector2D(size, igap)); // Left
// Draw rounded corners
- E(gl.DrawRing(gapH, gapV, rad1, rad2, 1.0, 180.0, 270.0)); // Top-left
- E(gl.DrawRing(w-gapH, gapV, rad1, rad2, 1.0, 90.0, 180.0)); // Top-right
- E(gl.DrawRing(w-gapH, h-gapV, rad1, rad2, 1.0, 0.0, 90.0)); // Bottom-right
- E(gl.DrawRing(gapH, h-gapV, rad1, rad2, 1.0,270.0,360.0)); // Bottom-left
+ gl.DrawRing(gap, rad1, rad2, 1.f, 90.f, 180.f); // Top-left
+ gl.DrawRing(Vector2D(igap, gap), rad1, rad2, 1.f, 0.f, 90.f); // Top-right
+ gl.DrawRing(v - gap, rad1, rad2, 1.f, 270.f, 360.f); // Bottom-right
+ gl.DrawRing(Vector2D(gap, igap), rad1, rad2, 1.f, 180.f, 270.f); // Bottom-left
E(glDisable(GL_BLEND));
}
@@ -323,7 +271,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
if (freeSize) {
GetClientSize(&w,&h);
- viewport_x = 0;
+ viewport_left = 0;
viewport_bottom = 0;
viewport_top = 0;
viewport_width = w;
@@ -336,7 +284,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
// Window is wider than video, blackbox left/right
if (displayAr - videoAr > 0.01f) {
int delta = w - videoAr * h;
- viewport_x = delta / 2;
+ viewport_left = delta / 2;
viewport_width = w - delta;
}
@@ -359,7 +307,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
// Cap the canvas size to the window size
int cw = std::min(w, maxW), ch = std::min(h, maxH);
- viewport_x = 0;
+ viewport_left = 0;
viewport_bottom = ch - h;
viewport_top = 0;
viewport_width = w;
@@ -380,11 +328,8 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
SetEvtHandlerEnabled(true);
}
- con->videoController->GetScriptSize(scriptW, scriptH);
- video.w = w;
- video.h = h;
-
- if (tool.get()) tool->Refresh();
+ if (tool.get())
+ tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
Refresh(false);
}
@@ -403,20 +348,13 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
if (event.ButtonDown())
SetFocus();
- video.x = event.GetX();
- video.y = event.GetY();
+ mouse_pos = event.GetPosition();
tool->OnMouseEvent(event);
}
-void VideoDisplay::OnMouseEnter(wxMouseEvent& event) {
- ShowCursor(activeMode != Video_Mode_Standard);
- tool->OnMouseEvent(event);
-}
-
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
- video.x = INT_MIN;
- video.y = INT_MIN;
+ mouse_pos = Vector2D::Bad();
tool->OnMouseEvent(event);
}
@@ -429,33 +367,22 @@ void VideoDisplay::OnMouseWheel(wxMouseEvent& event) {
void VideoDisplay::OnContextMenu(wxContextMenuEvent&) {
if (!context_menu.get()) context_menu.reset(menu::GetMenu("video_context", con));
- ShowCursor(true);
+ SetCursor(wxNullCursor);
menu::OpenPopupMenu(context_menu.get(), this);
}
void VideoDisplay::OnKeyDown(wxKeyEvent &event) {
- /// @todo
- int kc = event.GetKeyCode();
- if (kc == 'A') SetMode(Video_Mode_Standard);
- else if (kc == 'S') SetMode(Video_Mode_Drag);
- else if (kc == 'D') SetMode(Video_Mode_Rotate_Z);
- else if (kc == 'F') SetMode(Video_Mode_Rotate_XY);
- else if (kc == 'G') SetMode(Video_Mode_Scale);
- else if (kc == 'H') SetMode(Video_Mode_Clip);
- else if (kc == 'J') SetMode(Video_Mode_Vector_Clip);
- else {
- event.StopPropagation();
- if (hotkey::check("Video Display", con, event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
- return;
- }
+ event.StopPropagation();
+ if (hotkey::check("Video", con, event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
+ return;
}
-
void VideoDisplay::SetZoom(double value) {
zoomValue = std::max(value, .125);
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
UpdateSize();
}
+
void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
wxString strValue = zoomBox->GetValue();
strValue.EndsWith("%", &strValue);
@@ -466,57 +393,19 @@ void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
}
}
-template
-void VideoDisplay::SetTool() {
- tool.reset();
- tool.reset(new T(this, con, video, toolBar));
- box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &T::OnSubTool, static_cast(tool.get()), VISUAL_SUB_TOOL_START, VISUAL_SUB_TOOL_END);
-}
-void VideoDisplay::OnMode(const wxCommandEvent &event) {
- SetMode(event.GetId());
-}
-void VideoDisplay::SetMode(int mode) {
- if (activeMode == mode) return;
-
+void VideoDisplay::SetTool(VisualToolBase *new_tool) {
toolBar->ClearTools();
toolBar->Realize();
toolBar->Show(false);
- if (!box->visualToolBar->GetToolState(mode)) {
- box->visualToolBar->ToggleTool(mode, true);
- }
-
- activeMode = mode;
- switch (mode) {
- case Video_Mode_Standard: SetTool(); break;
- case Video_Mode_Drag: SetTool(); break;
- case Video_Mode_Rotate_Z: SetTool(); break;
- case Video_Mode_Rotate_XY: SetTool(); break;
- case Video_Mode_Scale: SetTool(); break;
- case Video_Mode_Clip: SetTool(); break;
- case Video_Mode_Vector_Clip: SetTool(); break;
- default: assert(false); break;
- }
+ tool.reset(new_tool);
+ tool->SetToolbar(toolBar);
+ tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
// Update size as the new typesetting tool may have changed the subtoolbar size
UpdateSize();
- ShowCursor(activeMode != Video_Mode_Standard);
}
-void VideoDisplay::ToScriptCoords(int *x, int *y) const {
- int sx = *x - viewport_x > 0 ? viewport_width : -viewport_width;
- int sy = *y - viewport_top > 0 ? viewport_height : -viewport_height;
- *x = ((*x - viewport_x) * scriptW + sx / 2) / viewport_width;
- *y = ((*y - viewport_top) * scriptH + sy / 2) / viewport_height;
-}
-void VideoDisplay::FromScriptCoords(int *x, int *y) const {
- int sx = *x > 0 ? scriptW : -scriptW;
- int sy = *y > 0 ? scriptH : -scriptH;
- *x = (*x * viewport_width + sx / 2) / scriptW + viewport_x;
- *y = (*y * viewport_height + sy / 2) / scriptH + viewport_top;
-}
-
-void VideoDisplay::GetMousePosition(int *x, int *y) const {
- *x = video.x;
- *y = video.y;
+Vector2D VideoDisplay::GetMousePosition() const {
+ return mouse_pos ? tool->ToScriptCoords(mouse_pos) : mouse_pos;
}
diff --git a/aegisub/src/video_display.h b/aegisub/src/video_display.h
index b39460e86..1942a796a 100644
--- a/aegisub/src/video_display.h
+++ b/aegisub/src/video_display.h
@@ -44,12 +44,14 @@
#include
#include
+#include "vector2d.h"
+
// Prototypes
class FrameReadyEvent;
class VideoBox;
class VideoContext;
class VideoOutGL;
-class IVisualTool;
+class VisualToolBase;
class wxComboBox;
class wxTextCtrl;
class wxToolBar;
@@ -59,14 +61,6 @@ namespace agi {
class OptionValue;
}
-struct VideoState {
- int x;
- int y;
- int w;
- int h;
- VideoState() : x(INT_MIN), y(INT_MIN), w(INT_MIN), h(INT_MIN) { }
-};
-
/// @class VideoDisplay
/// @brief DOCME
class VideoDisplay : public wxGLCanvas {
@@ -87,8 +81,10 @@ class VideoDisplay : public wxGLCanvas {
/// The height of the canvas in screen pixels
int h;
+ Vector2D mouse_pos;
+
/// Screen pixels between the left of the canvas and the left of the video
- int viewport_x;
+ int viewport_left;
/// The width of the video in screen pixels
int viewport_width;
/// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport
@@ -105,22 +101,13 @@ class VideoDisplay : public wxGLCanvas {
agi::scoped_ptr videoOut;
/// The active visual typesetting tool
- agi::scoped_ptr tool;
- /// The current tool's ID
- int activeMode;
+ agi::scoped_ptr tool;
/// The toolbar used by individual typesetting tools
wxToolBar* toolBar;
/// The OpenGL context for this display
agi::scoped_ptr glContext;
- /// The current script width
- int scriptW;
- /// The current script height
- int scriptH;
-
- VideoState video;
-
/// The dropdown box for selecting zoom levels
wxComboBox *zoomBox;
@@ -131,11 +118,9 @@ class VideoDisplay : public wxGLCanvas {
bool freeSize;
/// @brief Draw an overscan mask
- /// @param sizeH The amount of horizontal overscan on one side
- /// @param sizeV The amount of vertical overscan on one side
- /// @param colour The color of the mask
- /// @param alpha The alpha of the mask
- void DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const;
+ /// @param horizontal_percent The percent of the video reserved horizontally
+ /// @param vertical_percent The percent of the video reserved vertically
+ void DrawOverscanMask(float horizontal_percent, float vertical_percent) const;
/// Upload the image for the current frame to the video card
void UploadFrameData(FrameReadyEvent&);
@@ -144,21 +129,8 @@ class VideoDisplay : public wxGLCanvas {
/// @return Could the context be set?
bool InitContext();
- /// @brief Set this video display to the given frame
- /// @frameNumber The desired frame number
- void SetFrame(int frameNumber);
-
void OnVideoOpen();
- void OnCommit(int type);
- void SetMode(int mode);
- /// @brief Switch the active tool to a new object of the specified class
- /// @param T The class of the new visual typesetting tool
- template void SetTool();
-
- /// @brief Set the cursor to either default or blank
- /// @param show Whether or not the cursor should be visible
- void ShowCursor(bool show);
/// @brief Set the size of the display based on the current zoom and video resolution
void UpdateSize(int arType = -1, double arValue = -1.);
/// @brief Set the zoom level to that indicated by the dropdown
@@ -169,11 +141,9 @@ class VideoDisplay : public wxGLCanvas {
/// @brief Mouse event handler
void OnMouseEvent(wxMouseEvent& event);
void OnMouseWheel(wxMouseEvent& event);
- void OnMouseEnter(wxMouseEvent& event);
void OnMouseLeave(wxMouseEvent& event);
/// @brief Recalculate video positioning and scaling when the available area or zoom changes
void OnSizeEvent(wxSizeEvent &event);
- void OnMode(const wxCommandEvent &event);
void OnContextMenu(wxContextMenuEvent&);
public:
@@ -195,17 +165,8 @@ public:
/// @brief Get the current zoom level
double GetZoom() const { return zoomValue; }
- /// @brief Convert a point from screen to script coordinate frame
- /// @param x x coordinate; in/out
- /// @param y y coordinate; in/out
- void ToScriptCoords(int *x, int *y) const;
- /// @brief Convert a point from script to screen coordinate frame
- /// @param x x coordinate; in/out
- /// @param y y coordinate; in/out
- void FromScriptCoords(int *x, int *y) const;
+ /// Get the last seen position of the mouse in script coordinates
+ Vector2D GetMousePosition() const;
- /// Get the last seen position of the mouse in screen coordinates
- /// @param[out] x x coordinate
- /// @param[out] y y coordinate
- void GetMousePosition(int *x, int *y) const;
+ void SetTool(VisualToolBase *new_tool);
};
diff --git a/aegisub/src/visual_feature.cpp b/aegisub/src/visual_feature.cpp
index 68b61cfcc..4e5a7032d 100644
--- a/aegisub/src/visual_feature.cpp
+++ b/aegisub/src/visual_feature.cpp
@@ -40,69 +40,89 @@
#include "visual_feature.h"
VisualDraggableFeature::VisualDraggableFeature()
-: type(DRAG_NONE)
-, x(INT_MIN)
-, y(INT_MIN)
-, origX(INT_MIN)
-, origY(INT_MIN)
+: start(Vector2D::Bad())
+, type(DRAG_NONE)
+, pos(Vector2D::Bad())
, layer(0)
-, line(NULL)
+, line(0)
{
}
-bool VisualDraggableFeature::IsMouseOver(int mx,int my) const {
+bool VisualDraggableFeature::IsMouseOver(Vector2D mouse_pos) const {
+ if (!pos) return false;
+
+ Vector2D delta = mouse_pos - pos;
+
switch (type) {
case DRAG_BIG_SQUARE:
- return !(mx < x-8 || mx > x+8 || my < y-8 || my > y+8);
- case DRAG_BIG_CIRCLE: {
- int dx = mx-x;
- int dy = my-y;
- return dx*dx + dy*dy <= 64;
- }
+ return fabs(delta.X()) < 8 && fabs(delta.Y()) < 8;
+
+ case DRAG_BIG_CIRCLE:
+ return delta.SquareLen() < 64;
+
case DRAG_BIG_TRIANGLE: {
- int _my = my+2;
- if (_my < y-8 || _my > y+8) return false;
- int dx = mx-x;
- int dy = _my-y-8;
- return (16*dx+9*dy < 0 && 16*dx-9*dy > 0);
+ if (delta.Y() < -10 || delta.Y() > 6) return false;
+ float dy = delta.Y() - 6;
+ return 16 * delta.X() + 9 * dy < 0 && 16 * delta.X() - 9 * dy > 0;
}
+
case DRAG_SMALL_SQUARE:
- return !(mx < x-4 || mx > x+4 || my < y-4 || my > y+4);
- case DRAG_SMALL_CIRCLE: {
- int dx = mx-x;
- int dy = my-y;
- return dx*dx + dy*dy <= 16;
- }
+ return fabs(delta.X()) < 4 && fabs(delta.Y()) < 4;
+
+ case DRAG_SMALL_CIRCLE:
+ return delta.SquareLen() < 16;
+
default:
return false;
}
}
void VisualDraggableFeature::Draw(OpenGLWrapper const& gl) const {
+ if (!pos) return;
+
switch (type) {
case DRAG_BIG_SQUARE:
- gl.DrawRectangle(x-8,y-8,x+8,y+8);
- gl.DrawLine(x,y-16,x,y+16);
- gl.DrawLine(x-16,y,x+16,y);
+ gl.DrawRectangle(pos - 8, pos + 8);
+ gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
+ gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
break;
+
case DRAG_BIG_CIRCLE:
- gl.DrawCircle(x,y,8);
- gl.DrawLine(x,y-16,x,y+16);
- gl.DrawLine(x-16,y,x+16,y);
+ gl.DrawCircle(pos, 8);
+ gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
+ gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
break;
+
case DRAG_BIG_TRIANGLE:
- gl.DrawTriangle(x-9,y-6,x+9,y-6,x,y+10);
- gl.DrawLine(x,y,x,y-16);
- gl.DrawLine(x,y,x-14,y+8);
- gl.DrawLine(x,y,x+14,y+8);
+ gl.DrawTriangle(pos - Vector2D(9, 6), pos + Vector2D(9, -6), pos + Vector2D(0, 10));
+ gl.DrawLine(pos, pos + Vector2D(0, -16));
+ gl.DrawLine(pos, pos + Vector2D(-14, 8));
+ gl.DrawLine(pos, pos + Vector2D(14, 8));
break;
+
case DRAG_SMALL_SQUARE:
- gl.DrawRectangle(x-4,y-4,x+4,y+4);
+ gl.DrawRectangle(pos - 4, pos + 4);
break;
+
case DRAG_SMALL_CIRCLE:
- gl.DrawCircle(x,y,4);
+ gl.DrawCircle(pos, 4);
break;
default:
break;
}
}
+
+void VisualDraggableFeature::StartDrag() {
+ start = pos;
+}
+
+void VisualDraggableFeature::UpdateDrag(Vector2D d, bool single_axis) {
+ if (single_axis)
+ d = d.SingleAxis();
+
+ pos = start + d;
+}
+
+bool VisualDraggableFeature::HasMoved() const {
+ return pos != start;
+}
diff --git a/aegisub/src/visual_feature.h b/aegisub/src/visual_feature.h
index ca1a857b6..82c49a21d 100644
--- a/aegisub/src/visual_feature.h
+++ b/aegisub/src/visual_feature.h
@@ -36,6 +36,8 @@
#pragma once
+#include "vector2d.h"
+
class OpenGLWrapper;
class AssDialogue;
@@ -65,6 +67,8 @@ enum DraggableFeatureType {
/// @class VisualDraggableFeature
/// @brief Onscreen control used by many visual tools which doesn't do much
class VisualDraggableFeature {
+ Vector2D start; ///< position before the last operation began
+
public:
/// @brief Constructor
VisualDraggableFeature();
@@ -72,21 +76,23 @@ public:
/// Shape of feature
DraggableFeatureType type;
- int x; /// x coordinate
- int y; /// y coordinate
-
- int origX; /// x coordindate before the last operation began
- int origY; /// y coordindate before the last operation began
+ Vector2D pos;
int layer; /// Layer; Higher = above
AssDialogue* line; /// The dialogue line this feature is for
/// @brief Is the given point over this feature?
- /// @param mx x coordinate to test
- /// @param my y coordinate to test
- bool IsMouseOver(int x,int y) const;
+ /// @param mouse_pos Position of the mouse
+ bool IsMouseOver(Vector2D mouse_pos) const;
+
/// @brief Draw this feature
/// @param gl OpenGLWrapper to use
void Draw(OpenGLWrapper const& gl) const;
+
+ void StartDrag();
+
+ void UpdateDrag(Vector2D d, bool single_axis);
+
+ bool HasMoved() const;
};
diff --git a/aegisub/src/visual_tool.cpp b/aegisub/src/visual_tool.cpp
index d06666718..aa915f3bc 100644
--- a/aegisub/src/visual_tool.cpp
+++ b/aegisub/src/visual_tool.cpp
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -40,6 +27,8 @@
#include
#endif
+#include "visual_tool.h"
+
#include "ass_dialogue.h"
#include "ass_file.h"
#include "ass_override.h"
@@ -47,133 +36,219 @@
#include "ass_time.h"
#include "include/aegisub/context.h"
#include "main.h"
-#include "subs_grid.h"
#include "utils.h"
#include "video_context.h"
#include "video_display.h"
#include "video_provider_manager.h"
#include "visual_feature.h"
-#include "visual_tool.h"
#include "visual_tool_clip.h"
#include "visual_tool_drag.h"
#include "visual_tool_vector_clip.h"
-const wxColour IVisualTool::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
+template
+static void for_each(C &range, F func) {
+ std::for_each(range.begin(), range.end(), func);
+}
-template
-VisualTool::VisualTool(VideoDisplay *parent, agi::Context *context, VideoState const& video)
-: dragStartX(0)
-, dragStartY(0)
-, commitId(-1)
-, selChanged(false)
-, selectedFeatures(selFeatures)
-, c(context)
+using std::tr1::placeholders::_1;
+
+const wxColour VisualToolBase::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
+
+VisualToolBase::VisualToolBase(VideoDisplay *parent, agi::Context *context)
+: c(context)
, parent(parent)
, holding(false)
+, active_line(0)
, dragging(false)
-, externalChange(true)
-, video(video)
-, leftClick(false)
-, leftDClick(false)
-, shiftDown(false)
-, ctrlDown(false)
-, altDown(false)
+, frame_number(c->videoController->GetFrameN())
+, left_click(false)
+, left_double(false)
+, shift_down(false)
+, ctrl_down(false)
+, alt_down(false)
+, file_changed_connection(c->ass->AddCommitListener(&VisualToolBase::OnCommit, this))
+, commit_id(-1)
{
- frameNumber = c->videoController->GetFrameN();
- curDiag = GetActiveDialogueLine();
+ int script_w, script_h;
+ c->ass->GetResolution(script_w, script_h);
+ script_res = Vector2D(script_w, script_h);
+ active_line = GetActiveDialogueLine();
c->selectionController->AddSelectionListener(this);
- curFeature = features.begin();
+ connections.push_back(c->videoController->AddSeekListener(&VisualToolBase::OnSeek, this));
+ parent->Bind(wxEVT_MOUSE_CAPTURE_LOST, &VisualToolBase::OnMouseCaptureLost, this);
+}
+
+VisualToolBase::~VisualToolBase() {
+ c->selectionController->RemoveSelectionListener(this);
+}
+
+void VisualToolBase::OnCommit(int type) {
+ holding = false;
+ dragging = false;
+
+ if (type & AssFile::COMMIT_NEW || type & AssFile::COMMIT_SCRIPTINFO) {
+ int script_w, script_h;
+ c->ass->GetResolution(script_w, script_h);
+ script_res = Vector2D(script_w, script_h);
+ OnCoordinateSystemsChanged();
+ }
+
+ if (type & AssFile::COMMIT_DIAG_FULL || type & AssFile::COMMIT_DIAG_ADDREM) {
+ active_line = GetActiveDialogueLine();
+ OnFileChanged();
+ }
+}
+
+void VisualToolBase::OnSeek(int new_frame) {
+ if (frame_number == new_frame) return;
+
+ frame_number = new_frame;
+ dragging = false;
+ OnFrameChanged();
+
+ AssDialogue *new_line = GetActiveDialogueLine();
+ if (new_line != active_line) {
+ active_line = new_line;
+ OnLineChanged();
+ }
+}
+
+void VisualToolBase::OnMouseCaptureLost(wxMouseCaptureLostEvent &) {
+ holding = false;
+ dragging = false;
+ left_click = false;
+}
+
+void VisualToolBase::OnActiveLineChanged(AssDialogue *new_line) {
+ if (!IsDisplayed(new_line))
+ new_line = 0;
+
+ holding = false;
+ dragging = false;
+ if (new_line != active_line) {
+ active_line = new_line;
+ OnLineChanged();
+ }
+}
+
+bool VisualToolBase::IsDisplayed(AssDialogue *line) const {
+ int frame = c->videoController->GetFrameN();
+ return
+ line &&
+ c->videoController->FrameAtTime(line->Start.GetMS(), agi::vfr::START) <= frame &&
+ c->videoController->FrameAtTime(line->End.GetMS(), agi::vfr::END) >= frame;
+}
+
+void VisualToolBase::Commit(wxString message) {
+ file_changed_connection.Block();
+ if (message.empty())
+ message = _("visual typesetting");
+
+ commit_id = c->ass->Commit(message, AssFile::COMMIT_DIAG_TEXT, commit_id);
+ file_changed_connection.Unblock();
+}
+
+AssDialogue* VisualToolBase::GetActiveDialogueLine() {
+ AssDialogue *diag = c->selectionController->GetActiveLine();
+ if (IsDisplayed(diag))
+ return diag;
+ return 0;
+}
+
+void VisualToolBase::SetDisplayArea(int x, int y, int w, int h) {
+ video_pos = Vector2D(x, y);
+ video_res = Vector2D(w, h);
+
+ holding = false;
+ dragging = false;
+ OnCoordinateSystemsChanged();
+}
+
+Vector2D VisualToolBase::ToScriptCoords(Vector2D point) const {
+ return (point - video_pos) * script_res / video_res;
+}
+
+Vector2D VisualToolBase::FromScriptCoords(Vector2D point) const {
+ return (point * video_res / script_res) + video_pos;
}
template
-VisualTool::~VisualTool() {
- c->selectionController->RemoveSelectionListener(this);
+VisualTool::VisualTool(VideoDisplay *parent, agi::Context *context)
+: VisualToolBase(parent, context)
+, sel_changed(false)
+{
+ active_feature = features.begin();
}
template
void VisualTool::OnMouseEvent(wxMouseEvent &event) {
- bool needRender = false;
+ left_click = event.LeftDown();
+ left_double = event.LeftDClick();
+ shift_down = event.ShiftDown();
+ ctrl_down = event.CmdDown();
+ alt_down = event.AltDown();
+
+ mouse_pos = event.GetPosition();
+
+ bool need_render = false;
if (event.Leaving()) {
- Update();
+ mouse_pos = Vector2D::Bad();
parent->Render();
return;
}
- else if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool()) {
- needRender = true;
- }
- externalChange = false;
- leftClick = event.ButtonDown(wxMOUSE_BTN_LEFT);
- leftDClick = event.LeftDClick();
- shiftDown = event.m_shiftDown;
-#ifdef __APPLE__
- ctrlDown = event.m_metaDown; // Cmd key
-#else
- ctrlDown = event.m_controlDown;
-#endif
- altDown = event.m_altDown;
+ if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool())
+ need_render = true;
if (!dragging) {
- feature_iterator oldHigh = curFeature;
- GetHighlightedFeature();
- if (curFeature != oldHigh) needRender = true;
+ feature_iterator prev_feature = active_feature;
+
+ int max_layer = INT_MIN;
+ active_feature = features.end();
+ for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
+ if (cur->IsMouseOver(mouse_pos) && cur->layer >= max_layer) {
+ active_feature = cur;
+ max_layer = cur->layer;
+ }
+ }
+
+ need_render |= active_feature != prev_feature;
}
if (dragging) {
// continue drag
if (event.LeftIsDown()) {
- for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
- (*cur)->x = (video.x - dragStartX + (*cur)->origX);
- (*cur)->y = (video.y - dragStartY + (*cur)->origY);
- if (shiftDown) {
- if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) {
- (*cur)->y = (*cur)->origY;
- }
- else {
- (*cur)->x = (*cur)->origX;
- }
- }
- UpdateDrag(*cur);
- CommitDrag(*cur);
- }
+ for_each(sel_features, bind(&FeatureType::UpdateDrag, _1,
+ mouse_pos - drag_start, shift_down));
+ for_each(sel_features, bind(&VisualTool::UpdateDrag, this, _1));
Commit();
- needRender = true;
+ need_render = true;
}
// end drag
else {
dragging = false;
// mouse didn't move, fiddle with selection
- if (curFeature->x == curFeature->origX && curFeature->y == curFeature->origY) {
+ if (active_feature != features.end() && !active_feature->HasMoved()) {
// Don't deselect stuff that was selected in this click's mousedown event
- if (!selChanged) {
- if (ctrlDown) {
- // deselect this feature
- RemoveSelection(curFeature);
- }
- else {
- SetSelection(curFeature);
- }
+ if (!sel_changed) {
+ if (ctrl_down)
+ RemoveSelection(active_feature);
+ else
+ SetSelection(active_feature, true);
}
}
- else {
- for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
- CommitDrag(*cur);
- }
- Commit();
- }
- curFeature = features.end();
+ active_feature = features.end();
parent->ReleaseMouse();
parent->SetFocus();
}
}
else if (holding) {
- // continue hold
if (event.LeftIsDown()) {
UpdateHold();
- needRender = true;
+ need_render = true;
}
// end hold
else {
@@ -182,422 +257,318 @@ void VisualTool::OnMouseEvent(wxMouseEvent &event) {
parent->ReleaseMouse();
parent->SetFocus();
}
- CommitHold();
Commit();
}
- else if (leftClick) {
+ else if (left_click) {
+ drag_start = mouse_pos;
+
// start drag
- if (curFeature != features.end()) {
- if (selFeatures.find(curFeature) == selFeatures.end()) {
- selChanged = true;
- if (ctrlDown) {
- AddSelection(curFeature);
- }
- else {
- SetSelection(curFeature);
- }
+ if (active_feature != features.end()) {
+ if (!sel_features.count(active_feature)) {
+ sel_changed = true;
+ SetSelection(active_feature, !ctrl_down);
}
- else {
- selChanged = false;
- }
- if (curFeature->line) c->selectionController->SetActiveLine(curFeature->line);
+ else
+ sel_changed = false;
- if (InitializeDrag(curFeature)) {
- dragStartX = video.x;
- dragStartY = video.y;
- for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
- (*cur)->origX = (*cur)->x;
- (*cur)->origY = (*cur)->y;
- }
+ if (active_feature->line)
+ c->selectionController->SetActiveLine(active_feature->line);
+ if (InitializeDrag(active_feature)) {
+ for_each(sel_features, bind(&VisualDraggableFeature::StartDrag, _1));
dragging = true;
parent->CaptureMouse();
}
}
// start hold
else {
- if (!altDown) {
- ClearSelection();
+ if (!alt_down) {
+ sel_features.clear();
Selection sel;
sel.insert(c->selectionController->GetActiveLine());
c->selectionController->SetSelectedSet(sel);
- needRender = true;
+ need_render = true;
}
- if (curDiag && InitializeHold()) {
+ if (active_line && InitializeHold()) {
holding = true;
parent->CaptureMouse();
}
}
}
- if (Update() || needRender) parent->Render();
- externalChange = true;
+ if (active_line && left_double)
+ OnDoubleClick();
- if (!event.LeftIsDown()) {
- // Only coalesce the changes made in a single drag
- commitId = -1;
- }
-}
+ //if (need_render)
+ parent->Render();
-template
-void VisualTool::Commit(wxString message) {
- externalChange = false;
- if (message.empty()) {
- message = _("visual typesetting");
- }
- commitId = c->ass->Commit(message, AssFile::COMMIT_DIAG_TEXT, commitId);
- externalChange = true;
-}
-
-template
-AssDialogue* VisualTool::GetActiveDialogueLine() {
- AssDialogue *diag = c->selectionController->GetActiveLine();
- if (diag && c->subsGrid->IsDisplayed(diag))
- return diag;
- return NULL;
-}
-
-template
-void VisualTool::GetHighlightedFeature() {
- int highestLayerFound = INT_MIN;
- curFeature = features.end();
- for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
- if (cur->IsMouseOver(video.x, video.y) && cur->layer > highestLayerFound) {
- curFeature = cur;
- highestLayerFound = cur->layer;
- }
- }
+ // Only coalesce the changes made in a single drag
+ if (!event.LeftIsDown())
+ commit_id = -1;
}
template
void VisualTool::DrawAllFeatures() {
- SetLineColour(colour[0],1.0f,2);
+ gl.SetLineColour(colour[0], 1.0f, 2);
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
- int fill;
- if (cur == curFeature)
+ int fill = 1;
+ if (cur == active_feature)
fill = 2;
- else if (selFeatures.find(cur) != selFeatures.end())
+ else if (sel_features.count(cur))
fill = 3;
- else
- fill = 1;
- SetFillColour(colour[fill],0.6f);
- cur->Draw(*this);
+ gl.SetFillColour(colour[fill], 0.6f);
+ cur->Draw(gl);
}
}
template
-void VisualTool::Refresh() {
- if (externalChange) {
- curDiag = GetActiveDialogueLine();
- curFeature = features.end();
- OnFileChanged();
- }
-}
-
-template
-void VisualTool::SetFrame(int newFrameNumber) {
- if (frameNumber == newFrameNumber) return;
- frameNumber = newFrameNumber;
- curFeature = features.end();
- OnFrameChanged();
- AssDialogue *newCurDiag = GetActiveDialogueLine();
- if (newCurDiag != curDiag) {
- curDiag = newCurDiag;
- OnLineChanged();
- }
-}
-
-template
-void VisualTool::OnActiveLineChanged(AssDialogue *new_line) {
- if (new_line && !c->subsGrid->IsDisplayed(new_line)) {
- new_line = NULL;
- }
- if (new_line != curDiag) {
- curDiag = new_line;
- OnLineChanged();
- }
-}
-
-
-template
-void VisualTool::SetSelection(feature_iterator feat) {
- selFeatures.clear();
- lineSelCount.clear();
-
- selFeatures.insert(feat);
-
- AssDialogue *line = feat->line;
- if (line) {
- lineSelCount[line] = 1;
+void VisualTool::SetSelection(feature_iterator feat, bool clear) {
+ if (clear)
+ sel_features.clear();
+ if (sel_features.insert(feat).second && feat->line) {
Selection sel;
- sel.insert(line);
- c->selectionController->SetSelectedSet(sel);
- }
-}
-
-
-template
-void VisualTool::AddSelection(feature_iterator feat) {
- if (selFeatures.insert(feat).second && feat->line) {
- lineSelCount[feat->line] += 1;
- Selection sel = c->selectionController->GetSelectedSet();
- if (sel.insert(feat->line).second) {
+ if (!clear)
+ sel = c->selectionController->GetSelectedSet();
+ if (sel.insert(feat->line).second)
c->selectionController->SetSelectedSet(sel);
- }
}
}
template
void VisualTool::RemoveSelection(feature_iterator feat) {
- if (selFeatures.erase(feat) > 0 && feat->line) {
- // Deselect a line only if all features for that line have been
- // deselected
- AssDialogue* line = feat->line;
- lineSelCount[line] -= 1;
- assert(lineSelCount[line] >= 0);
- if (lineSelCount[line] <= 0) {
- Selection sel = c->selectionController->GetSelectedSet();
+ if (!sel_features.erase(feat) || !feat->line) return;
- // Don't deselect the only selected line
- if (sel.size() <= 1) return;
-
- sel.erase(line);
-
- // Set the active line to an arbitrary selected line if we just
- // deselected the active line
- if (line == c->selectionController->GetActiveLine()) {
- c->selectionController->SetActiveLine(*sel.begin());
- }
-
- c->selectionController->SetSelectedSet(sel);
- }
+ for (selection_iterator it = sel_features.begin(); it != sel_features.end(); ++it) {
+ if ((*it)->line == feat->line) return;
}
+
+ Selection sel = c->selectionController->GetSelectedSet();
+
+ // Don't deselect the only selected line
+ if (sel.size() <= 1) return;
+
+ sel.erase(feat->line);
+
+ // Set the active line to an arbitrary selected line if we just
+ // deselected the active line
+ if (feat->line == c->selectionController->GetActiveLine()) {
+ c->selectionController->SetActiveLine(*sel.begin());
+ }
+
+ c->selectionController->SetSelectedSet(sel);
}
-template
-void VisualTool::ClearSelection() {
- selFeatures.clear();
- lineSelCount.clear();
-}
+//////// PARSERS
-enum TagFoundType {
- TAG_NOT_FOUND = 0,
- PRIMARY_TAG_FOUND,
- ALT_TAG_FOUND
+typedef const std::vector * param_vec;
+
+// Parse line on creation and unparse at the end of scope
+struct scoped_tag_parse {
+ AssDialogue *diag;
+ scoped_tag_parse(AssDialogue *diag) : diag(diag) { diag->ParseASSTags(); }
+ ~scoped_tag_parse() { diag->ClearBlocks(); }
};
-/// @brief Get the first value set for a tag
-/// @param line Line to get the value from
-/// @param tag Tag to get the value of
-/// @param n Number of parameters passed
-/// @return Which tag (if any) was found
-template
-static TagFoundType get_value(const AssDialogue *line, wxString tag, size_t n, ...) {
- wxString alt;
- if (tag == "\\pos") alt = "\\move";
- else if (tag == "\\an") alt = "\\a";
- else if (tag == "\\clip") alt = "\\iclip";
-
- for (size_t i = 0; i < line->Blocks.size(); i++) {
+// Find a tag's parameters in a line or return NULL if it's not found
+static param_vec find_tag(const AssDialogue *line, wxString tag_name) {
+ for (size_t i = 0; i < line->Blocks.size(); ++i) {
const AssDialogueBlockOverride *ovr = dynamic_cast(line->Blocks[i]);
if (!ovr) continue;
- for (size_t j=0; j < ovr->Tags.size(); j++) {
- const AssOverrideTag *cur = ovr->Tags[j];
- if ((cur->Name == tag || cur->Name == alt) && cur->Params.size() >= n) {
- va_list argp;
- va_start(argp, n);
- for (size_t j = 0; j < n; j++) {
- T *val = va_arg(argp, T *);
- *val = cur->Params[j]->Get(*val);
- }
- va_end(argp);
- return cur->Name == alt ? ALT_TAG_FOUND : PRIMARY_TAG_FOUND;
- }
+ for (size_t j = 0; j < ovr->Tags.size(); ++j) {
+ if (ovr->Tags[j]->Name == tag_name)
+ return &ovr->Tags[j]->Params;
}
}
- return TAG_NOT_FOUND;
+
+ return 0;
}
-template
-void VisualTool::GetLinePosition(AssDialogue *diag,int &x, int &y) {
- int orgx,orgy;
- GetLinePosition(diag,x,y,orgx,orgy);
+// Get a Vector2D from the given tag parameters, or Vector2D::Bad() if they are not valid
+static Vector2D vec_or_bad(param_vec tag, size_t x_idx, size_t y_idx) {
+ if (!tag ||
+ tag->size() <= x_idx || tag->size() <= y_idx ||
+ (*tag)[x_idx]->omitted || (*tag)[y_idx]->omitted ||
+ (*tag)[x_idx]->GetType() == VARDATA_NONE || (*tag)[y_idx]->GetType() == VARDATA_NONE)
+ {
+ return Vector2D::Bad();
+ }
+ return Vector2D((*tag)[x_idx]->Get(), (*tag)[y_idx]->Get());
}
-template
-void VisualTool::GetLinePosition(AssDialogue *diag,int &x, int &y, int &orgx, int &orgy) {
+Vector2D VisualToolBase::GetLinePosition(AssDialogue *diag) {
+ scoped_tag_parse parse(diag);
+
+ if (Vector2D ret = vec_or_bad(find_tag(diag, "\\pos"), 0, 1)) return ret;
+ if (Vector2D ret = vec_or_bad(find_tag(diag, "\\move"), 0, 1)) return ret;
+
+ // Get default position
int margin[4];
- for (int i=0;i<4;i++) margin[i] = diag->Margin[i];
+ std::copy(diag->Margin, diag->Margin + 4, margin);
int align = 2;
- AssStyle *style = c->ass->GetStyle(diag->Style);
- if (style) {
+ if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
align = style->alignment;
- for (int i=0;i<4;i++) {
- if (margin[i] == 0) margin[i] = style->Margin[i];
+ for (int i = 0; i < 4; i++) {
+ if (margin[i] == 0)
+ margin[i] = style->Margin[i];
}
}
- int sw,sh;
- c->videoController->GetScriptSize(sw,sh);
+ param_vec align_tag;
+ if ((align_tag = find_tag(diag, "\\an")) && !(*align_tag)[0]->omitted)
+ align = (*align_tag)[0]->Get();
+ else if ((align_tag = find_tag(diag, "\\a"))) {
+ align = (*align_tag)[0]->Get(2);
- // Process margins
- margin[1] = sw - margin[1];
- margin[3] = sh - margin[2];
-
- // Overrides processing
- diag->ParseASSTags();
-
- if (!get_value(diag, "\\pos", 2, &x, &y)) {
- if (get_value(diag, "\\an", 1, &align) == ALT_TAG_FOUND) {
- switch(align) {
- case 1: case 2: case 3:
- break;
- case 5: case 6: case 7:
- align += 2;
- break;
- case 9: case 10: case 11:
- align -= 5;
- break;
- default:
- align = 2;
- break;
- }
- }
- // Alignment type
- int hor = (align - 1) % 3;
- int vert = (align - 1) / 3;
-
- // Calculate positions
- if (hor == 0) x = margin[0];
- else if (hor == 1) x = (margin[0] + margin[1])/2;
- else if (hor == 2) x = margin[1];
- if (vert == 0) y = margin[3];
- else if (vert == 1) y = (margin[2] + margin[3])/2;
- else if (vert == 2) y = margin[2];
+ // \a -> \an values mapping
+ static int align_mapping[] = { 2, 1, 2, 3, 7, 7, 8, 9, 7, 4, 5, 6 };
+ if (static_cast(align) < sizeof(align_mapping) / sizeof(int))
+ align = align_mapping[align];
+ else
+ align = 2;
}
- parent->FromScriptCoords(&x, &y);
+ // Alignment type
+ int hor = (align - 1) % 3;
+ int vert = (align - 1) / 3;
- if (!get_value(diag, "\\org", 2, &orgx, &orgy)) {
- orgx = x;
- orgy = y;
- }
- else {
- parent->FromScriptCoords(&orgx, &orgy);
- }
+ // Calculate positions
+ int x, y;
+ if (hor == 0)
+ x = margin[0];
+ else if (hor == 1)
+ x = (script_res.X() + margin[0] - margin[1]) / 2;
+ else if (hor == 2)
+ x = margin[1];
- diag->ClearBlocks();
+ if (vert == 0)
+ y = script_res.Y() - margin[2];
+ else if (vert == 1)
+ y = script_res.Y() / 2;
+ else if (vert == 2)
+ y = margin[2];
+
+ return Vector2D(x, y);
}
-template
-void VisualTool::GetLineMove(AssDialogue *diag,bool &hasMove,int &x1,int &y1,int &x2,int &y2,int &t1,int &t2) {
- diag->ParseASSTags();
-
- hasMove =
- get_value(diag, "\\move", 6, &x1, &y1, &x2, &y2, &t1, &t2) ||
- get_value(diag, "\\move", 4, &x1, &y1, &x2, &y2);
-
- if (hasMove) {
- parent->FromScriptCoords(&x1, &y1);
- parent->FromScriptCoords(&x2, &y2);
- }
-
- diag->ClearBlocks();
+Vector2D VisualToolBase::GetLineOrigin(AssDialogue *diag) {
+ scoped_tag_parse parse(diag);
+ return vec_or_bad(find_tag(diag, "\\org"), 0, 1);
}
-template
-void VisualTool::GetLineRotation(AssDialogue *diag,float &rx,float &ry,float &rz) {
+bool VisualToolBase::GetLineMove(AssDialogue *diag, Vector2D &p1, Vector2D &p2, int &t1, int &t2) {
+ scoped_tag_parse parse(diag);
+
+ param_vec tag = find_tag(diag, "\\move");
+ if (!tag)
+ return false;
+
+ p1 = vec_or_bad(tag, 0, 1);
+ p2 = vec_or_bad(tag, 2, 3);
+ // VSFilter actually defaults to -1, but it uses <= 0 to check for default and 0 seems less bug-prone
+ t1 = (*tag)[4]->Get(0);
+ t2 = (*tag)[5]->Get(0);
+
+ return p1 && p2;
+}
+
+void VisualToolBase::GetLineRotation(AssDialogue *diag, float &rx, float &ry, float &rz) {
rx = ry = rz = 0.f;
- AssStyle *style = c->ass->GetStyle(diag->Style);
- if (style) {
+ if (AssStyle *style = c->ass->GetStyle(diag->Style))
rz = style->angle;
- }
- diag->ParseASSTags();
+ scoped_tag_parse parse(diag);
- get_value(diag, "\\frx", 1, &rx);
- get_value(diag, "\\fry", 1, &ry);
- get_value(diag, "\\frz", 1, &rz);
-
- diag->ClearBlocks();
+ if (param_vec tag = find_tag(diag, "\\frx"))
+ rx = tag->front()->Get(rx);
+ if (param_vec tag = find_tag(diag, "\\fry"))
+ ry = tag->front()->Get(ry);
+ if (param_vec tag = find_tag(diag, "\\frz"))
+ rz = tag->front()->Get(rz);
+ else if (param_vec tag = find_tag(diag, "\\fr"))
+ rz = tag->front()->Get(rz);
}
-template
-void VisualTool::GetLineScale(AssDialogue *diag,float &scalX,float &scalY) {
- scalX = scalY = 100.f;
+void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
+ float x = 100.f, y = 100.f;
- AssStyle *style = c->ass->GetStyle(diag->Style);
- if (style) {
- scalX = style->scalex;
- scalY = style->scaley;
+ if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
+ x = style->scalex;
+ y = style->scaley;
}
- diag->ParseASSTags();
+ scoped_tag_parse parse(diag);
- get_value(diag, "\\fscx", 1, &scalX);
- get_value(diag, "\\fscy", 1, &scalY);
+ if (param_vec tag = find_tag(diag, "\\fscx"))
+ x = tag->front()->Get(x);
+ if (param_vec tag = find_tag(diag, "\\fscy"))
+ y = tag->front()->Get(y);
- diag->ClearBlocks();
+ scale = Vector2D(x, y);
}
-template
-void VisualTool::GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2,bool &inverse) {
- x1 = y1 = 0;
- int sw,sh;
- c->videoController->GetScriptSize(sw,sh);
- x2 = sw-1;
- y2 = sh-1;
+void VisualToolBase::GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse) {
inverse = false;
- diag->ParseASSTags();
- inverse = get_value(diag, "\\clip", 4, &x1, &y1, &x2, &y2) == ALT_TAG_FOUND;
- diag->ClearBlocks();
+ scoped_tag_parse parse(diag);
+ param_vec tag = find_tag(diag, "\\iclip");
+ if (tag)
+ inverse = true;
+ else
+ tag = find_tag(diag, "\\clip");
- parent->FromScriptCoords(&x1, &y1);
- parent->FromScriptCoords(&x2, &y2);
+ if (tag && tag->size() == 4) {
+ p1 = vec_or_bad(tag, 0, 1);
+ p2 = vec_or_bad(tag, 2, 3);
+ }
+ else {
+ p1 = Vector2D();
+ p2 = script_res - 1;
+ }
}
-template
-wxString VisualTool::GetLineVectorClip(AssDialogue *diag,int &scale,bool &inverse) {
+wxString VisualToolBase::GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse) {
+ scoped_tag_parse parse(diag);
+
scale = 1;
inverse = false;
- diag->ParseASSTags();
- int x1, y1, x2, y2;
- TagFoundType res = get_value(diag, "\\clip", 4, &x1, &y1, &x2, &y2);
- if (res) {
- inverse = res == ALT_TAG_FOUND;
- diag->ClearBlocks();
- return wxString::Format("m %d %d l %d %d %d %d %d %d", x1, y1, x2, y1, x2, y2, x1, y2);
+ param_vec tag = find_tag(diag, "\\iclip");
+ if (tag)
+ inverse = true;
+ else
+ tag = find_tag(diag, "\\clip");
+
+ if (tag && tag->size() == 4) {
+ return wxString::Format("m %d %d l %d %d %d %d %d %d",
+ (*tag)[0]->Get(), (*tag)[1]->Get(),
+ (*tag)[2]->Get(), (*tag)[1]->Get(),
+ (*tag)[2]->Get(), (*tag)[3]->Get(),
+ (*tag)[0]->Get(), (*tag)[3]->Get());
}
- wxString result;
- wxString scaleStr;
- res = get_value(diag, "\\clip", 2, &scaleStr, &result);
- inverse = res == ALT_TAG_FOUND;
- if (!scaleStr.empty()) {
- long s;
- scaleStr.ToLong(&s);
- scale = s;
+ if (tag) {
+ scale = (*tag)[0]->Get(scale);
+ return (*tag)[1]->Get("");
}
- diag->ClearBlocks();
- return result;
+
+ return "";
}
-/// @brief Set override
-/// @param tag
-/// @param value
-template
-void VisualTool::SetOverride(AssDialogue* line, wxString tag, wxString value) {
+void VisualToolBase::SetSelectedOverride(wxString const& tag, wxString const& value) {
+ for_each(c->selectionController->GetSelectedSet(),
+ bind(&VisualToolBase::SetOverride, this, _1, tag, value));
+}
+
+void VisualToolBase::SetOverride(AssDialogue* line, wxString const& tag, wxString const& value) {
if (!line) return;
wxString removeTag;
if (tag == "\\1c") removeTag = "\\c";
- else if (tag == "\\fr") removeTag = "\\frz";
+ else if (tag == "\\frz") removeTag = "\\fr";
else if (tag == "\\pos") removeTag = "\\move";
else if (tag == "\\move") removeTag = "\\pos";
else if (tag == "\\clip") removeTag = "\\iclip";
@@ -607,17 +578,14 @@ void VisualTool::SetOverride(AssDialogue* line, wxString tag, wxStr
// Get block at start
line->ParseASSTags();
- AssDialogueBlock *block = line->Blocks.at(0);
+ AssDialogueBlock *block = line->Blocks.front();
// Get current block as plain or override
- AssDialogueBlockPlain *plain = dynamic_cast(block);
- AssDialogueBlockOverride *ovr = dynamic_cast(block);
assert(dynamic_cast(block) == NULL);
- if (plain) {
+ if (dynamic_cast(block))
line->Text = "{" + insert + "}" + line->Text;
- }
- else if (ovr) {
+ else if (AssDialogueBlockOverride *ovr = dynamic_cast(block)) {
// Remove old of same
for (size_t i = 0; i < ovr->Tags.size(); i++) {
wxString name = ovr->Tags[i]->Name;
@@ -631,8 +599,6 @@ void VisualTool::SetOverride(AssDialogue* line, wxString tag, wxStr
line->UpdateText();
}
-
- parent->SetFocus();
}
// If only export worked
diff --git a/aegisub/src/visual_tool.h b/aegisub/src/visual_tool.h
index 7f7d6fed0..1b305150a 100644
--- a/aegisub/src/visual_tool.h
+++ b/aegisub/src/visual_tool.h
@@ -1,29 +1,16 @@
-// Copyright (c) 2007, Rodrigo Braz Monteiro
-// All rights reserved.
+// Copyright (c) 2011, Thomas Goyne
//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
//
-// * 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.
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
//
@@ -36,6 +23,7 @@
#pragma once
#ifndef AGI_PRE
+#include
#include