Switch to using an intrusive list for the visual tool features
Slightly improves performance and eliminates a bunch of really clunky passing around and storing of iterators.
This commit is contained in:
parent
b4ba31fe45
commit
64ecd29169
17 changed files with 253 additions and 182 deletions
|
@ -67,6 +67,7 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\of_type_adaptor.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\option.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\option_value.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\owning_intrusive_list.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\path.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\scoped_ptr.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\signal.h" />
|
||||
|
|
|
@ -161,6 +161,9 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\kana_table.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\owning_intrusive_list.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(SrcDir)windows\lagi_pre.cpp">
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// 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/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
namespace agi {
|
||||
|
||||
template<typename T>
|
||||
class owning_intrusive_list : private boost::intrusive::make_list<T, boost::intrusive::constant_time_size<false>>::type {
|
||||
typedef typename boost::intrusive::make_list<T, boost::intrusive::constant_time_size<false>>::type base;
|
||||
public:
|
||||
using base::back;
|
||||
using base::begin;
|
||||
using base::cbegin;
|
||||
using base::cend;
|
||||
using base::crbegin;
|
||||
using base::crend;
|
||||
using base::empty;
|
||||
using base::end;
|
||||
using base::front;
|
||||
using base::insert;
|
||||
using base::iterator_to;
|
||||
using base::merge;
|
||||
using base::push_back;
|
||||
using base::push_front;
|
||||
using base::rbegin;
|
||||
using base::rend;
|
||||
using base::reverse;
|
||||
using base::s_iterator_to;
|
||||
using base::shift_backwards;
|
||||
using base::shift_forward;
|
||||
using base::size;
|
||||
using base::sort;
|
||||
using base::splice;
|
||||
using base::swap;
|
||||
|
||||
using typename base::const_node_ptr;
|
||||
using typename base::const_pointer;
|
||||
using typename base::const_reverse_iterator;
|
||||
using typename base::node;
|
||||
using typename base::node_algorithms;
|
||||
using typename base::node_ptr;
|
||||
using typename base::node_traits;
|
||||
using typename base::pointer;
|
||||
using typename base::reference;
|
||||
using typename base::reverse_iterator;
|
||||
using typename base::size_type;
|
||||
using typename base::value_type;
|
||||
using typename base::iterator;
|
||||
using typename base::const_iterator;
|
||||
using typename base::const_reference;
|
||||
using typename base::difference_type;
|
||||
|
||||
iterator erase(const_iterator b, const_iterator e) { return this->erase_and_dispose(b, e, [](T *e) { delete e; }); }
|
||||
iterator erase(const_iterator b, const_iterator e, difference_type n) { return this->erase_and_dispose(b, e, n, [](T *e) { delete e; }); }
|
||||
iterator erase(const_iterator i) { return this->erase_and_dispose(i, [](T *e) { delete e; }); }
|
||||
void clear() { this->clear_and_dispose([](T *e) { delete e; }); }
|
||||
void pop_back() { this->pop_back_and_dispose([](T *e) { delete e; }); }
|
||||
void pop_front() { this->pop_front_and_dispose([](T *e) { delete e; }); }
|
||||
void remove(const_reference value) { return this->remove_and_dispose(value, [](T *e) { delete e; }); }
|
||||
void unique() { this->unique_and_dispose([](T *e) { delete e; }); }
|
||||
|
||||
template<class Pred> void remove_if(Pred&& pred) {
|
||||
this->remove_if_and_dispose(std::forward<Pred>(pred), [](T *e) { delete e; });
|
||||
}
|
||||
|
||||
template<class BinaryPredicate> void unique(BinaryPredicate&& pred) {
|
||||
this->unique_and_dispose(std::forward<BinaryPredicate>(pred), [](T *e) { delete e; });
|
||||
}
|
||||
|
||||
~owning_intrusive_list() {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
VisualDraggableFeature::VisualDraggableFeature()
|
||||
: type(DRAG_NONE)
|
||||
, layer(0)
|
||||
, line(0)
|
||||
, line(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include "vector2d.h"
|
||||
|
||||
#include <boost/intrusive/list_hook.hpp>
|
||||
|
||||
class OpenGLWrapper;
|
||||
class AssDialogue;
|
||||
|
||||
|
@ -54,7 +56,7 @@ enum DraggableFeatureType {
|
|||
///
|
||||
/// By itself this class doesn't do much. It mostly just draws itself at a
|
||||
/// specified position and performs hit-testing.
|
||||
class VisualDraggableFeature {
|
||||
class VisualDraggableFeature : public boost::intrusive::make_list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>::type {
|
||||
Vector2D start; ///< position before the last drag operation began
|
||||
|
||||
public:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -43,7 +43,12 @@
|
|||
|
||||
using std::placeholders::_1;
|
||||
|
||||
const wxColour VisualToolBase::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
|
||||
const wxColour VisualToolBase::colour[] = {
|
||||
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)
|
||||
|
@ -165,8 +170,8 @@ template<class FeatureType>
|
|||
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualToolBase(parent, context)
|
||||
, sel_changed(false)
|
||||
, active_feature(nullptr)
|
||||
{
|
||||
active_feature = features.begin();
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
|
@ -179,30 +184,21 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
|
||||
mouse_pos = event.GetPosition();
|
||||
|
||||
bool need_render = false;
|
||||
|
||||
if (event.Leaving()) {
|
||||
mouse_pos = Vector2D();
|
||||
parent->Render();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.Entering() && OPT_GET("Tool/Visual/Autohide")->GetBool())
|
||||
need_render = true;
|
||||
|
||||
if (!dragging) {
|
||||
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;
|
||||
active_feature = nullptr;
|
||||
for (auto& feature : features) {
|
||||
if (feature.IsMouseOver(mouse_pos) && feature.layer >= max_layer) {
|
||||
active_feature = &feature;
|
||||
max_layer = feature.layer;
|
||||
}
|
||||
}
|
||||
|
||||
need_render |= active_feature != prev_feature;
|
||||
}
|
||||
|
||||
if (dragging) {
|
||||
|
@ -213,14 +209,13 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
for (auto sel : sel_features)
|
||||
UpdateDrag(sel);
|
||||
Commit();
|
||||
need_render = true;
|
||||
}
|
||||
// end drag
|
||||
else {
|
||||
dragging = false;
|
||||
|
||||
// mouse didn't move, fiddle with selection
|
||||
if (active_feature != features.end() && !active_feature->HasMoved()) {
|
||||
if (active_feature && !active_feature->HasMoved()) {
|
||||
// Don't deselect stuff that was selected in this click's mousedown event
|
||||
if (!sel_changed) {
|
||||
if (ctrl_down)
|
||||
|
@ -230,7 +225,7 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
}
|
||||
}
|
||||
|
||||
active_feature = features.end();
|
||||
active_feature = nullptr;
|
||||
parent->ReleaseMouse();
|
||||
parent->SetFocus();
|
||||
}
|
||||
|
@ -244,7 +239,6 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
}
|
||||
|
||||
UpdateHold();
|
||||
need_render = true;
|
||||
Commit();
|
||||
|
||||
}
|
||||
|
@ -252,7 +246,7 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
drag_start = mouse_pos;
|
||||
|
||||
// start drag
|
||||
if (active_feature != features.end()) {
|
||||
if (active_feature) {
|
||||
if (!sel_features.count(active_feature)) {
|
||||
sel_changed = true;
|
||||
SetSelection(active_feature, !ctrl_down);
|
||||
|
@ -276,7 +270,6 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
SubtitleSelection sel;
|
||||
sel.insert(c->selectionController->GetActiveLine());
|
||||
c->selectionController->SetSelectedSet(sel);
|
||||
need_render = true;
|
||||
}
|
||||
if (active_line && InitializeHold()) {
|
||||
holding = true;
|
||||
|
@ -288,8 +281,7 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
if (active_line && left_double)
|
||||
OnDoubleClick();
|
||||
|
||||
//if (need_render)
|
||||
parent->Render();
|
||||
parent->Render();
|
||||
|
||||
// Only coalesce the changes made in a single drag
|
||||
if (!event.LeftIsDown())
|
||||
|
@ -299,19 +291,19 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::DrawAllFeatures() {
|
||||
gl.SetLineColour(colour[0], 1.0f, 2);
|
||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||
for (auto& feature : features) {
|
||||
int fill = 1;
|
||||
if (cur == active_feature)
|
||||
if (&feature == active_feature)
|
||||
fill = 2;
|
||||
else if (sel_features.count(cur))
|
||||
else if (sel_features.count(&feature))
|
||||
fill = 3;
|
||||
gl.SetFillColour(colour[fill], 0.6f);
|
||||
cur->Draw(gl);
|
||||
feature.Draw(gl);
|
||||
}
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::SetSelection(feature_iterator feat, bool clear) {
|
||||
void VisualTool<FeatureType>::SetSelection(FeatureType *feat, bool clear) {
|
||||
if (clear)
|
||||
sel_features.clear();
|
||||
|
||||
|
@ -325,12 +317,10 @@ void VisualTool<FeatureType>::SetSelection(feature_iterator feat, bool clear) {
|
|||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::RemoveSelection(feature_iterator feat) {
|
||||
void VisualTool<FeatureType>::RemoveSelection(FeatureType *feat) {
|
||||
if (!sel_features.erase(feat) || !feat->line) return;
|
||||
|
||||
for (auto sel : sel_features) {
|
||||
for (auto sel : sel_features)
|
||||
if (sel->line == feat->line) return;
|
||||
}
|
||||
|
||||
SubtitleSelection sel = c->selectionController->GetSelectedSet();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
// Copyright (c) 2013, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -20,22 +20,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/container/list.hpp>
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
#include <libaegisub/signal.h>
|
||||
|
||||
#include "gl_wrap.h"
|
||||
#include "selection_controller.h"
|
||||
#include "vector2d.h"
|
||||
|
||||
#include <libaegisub/owning_intrusive_list.h>
|
||||
#include <libaegisub/signal.h>
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <wx/event.h>
|
||||
|
||||
class AssDialogue;
|
||||
class SubtitlesGrid;
|
||||
class VideoDisplay;
|
||||
|
@ -155,21 +150,9 @@ template<class FeatureType>
|
|||
class VisualTool : public VisualToolBase {
|
||||
protected:
|
||||
typedef FeatureType Feature;
|
||||
typedef typename boost::container::list<FeatureType>::iterator feature_iterator;
|
||||
typedef typename boost::container::list<FeatureType>::const_iterator feature_const_iterator;
|
||||
typedef agi::owning_intrusive_list<FeatureType> feature_list;
|
||||
|
||||
private:
|
||||
struct ltaddr {
|
||||
template<class T>
|
||||
bool operator()(T lft, T rgt) const {
|
||||
return &*lft < &*rgt;
|
||||
}
|
||||
};
|
||||
|
||||
boost::container::list<agi::signal::Connection> slots;
|
||||
|
||||
typedef typename std::set<feature_iterator, ltaddr>::iterator selection_iterator;
|
||||
|
||||
bool sel_changed; /// Has the selection already been changed in the current click?
|
||||
|
||||
/// @brief Called when a hold is begun
|
||||
|
@ -181,23 +164,22 @@ private:
|
|||
/// @brief Called at the beginning of a drag
|
||||
/// @param feature The visual feature clicked on
|
||||
/// @return Should the drag happen?
|
||||
virtual bool InitializeDrag(feature_iterator feature) { return true; }
|
||||
virtual bool InitializeDrag(FeatureType *feature) { return true; }
|
||||
/// @brief Called on every mouse event during a drag
|
||||
/// @param feature The current feature to process; not necessarily the one clicked on
|
||||
virtual void UpdateDrag(feature_iterator feature) { }
|
||||
virtual void UpdateDrag(FeatureType *feature) { }
|
||||
|
||||
/// @brief Draw stuff
|
||||
virtual void Draw()=0;
|
||||
|
||||
protected:
|
||||
std::set<feature_iterator, ltaddr> sel_features; ///< Currently selected visual features
|
||||
typedef typename std::set<feature_iterator, ltaddr>::const_iterator sel_iterator;
|
||||
std::set<FeatureType *> sel_features; ///< Currently selected visual features
|
||||
|
||||
/// Topmost feature under the mouse; generally only valid during a drag
|
||||
feature_iterator active_feature;
|
||||
FeatureType *active_feature;
|
||||
/// List of features which are drawn and can be clicked on
|
||||
/// List is used here for the iterator invalidation properties
|
||||
boost::container::list<FeatureType> features;
|
||||
feature_list features;
|
||||
|
||||
/// Draw all of the features in the list
|
||||
void DrawAllFeatures();
|
||||
|
@ -205,11 +187,11 @@ protected:
|
|||
/// @brief Remove a feature from the selection
|
||||
/// @param i Index in the feature list
|
||||
/// Also deselects lines if all features for that line have been deselected
|
||||
void RemoveSelection(feature_iterator feat);
|
||||
void RemoveSelection(FeatureType *feat);
|
||||
|
||||
/// @brief Set the selection to a single feature, deselecting everything else
|
||||
/// @param i Index in the feature list
|
||||
void SetSelection(feature_iterator feat, bool clear);
|
||||
void SetSelection(FeatureType *feat, bool clear);
|
||||
|
||||
public:
|
||||
/// @brief Handler for all mouse events
|
||||
|
|
|
@ -36,18 +36,11 @@ VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context)
|
|||
, cur_2(video_res)
|
||||
, inverse(false)
|
||||
{
|
||||
Feature feat;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
features.resize(4, feat);
|
||||
|
||||
// This is really awkward without being able to just index the list of
|
||||
// features, so copy them into a temporary array
|
||||
ClipCorner *feats[4];
|
||||
feature_iterator cur = features.begin();
|
||||
feats[0] = &*(cur++);
|
||||
feats[1] = &*(cur++);
|
||||
feats[2] = &*(cur++);
|
||||
feats[3] = &*(cur++);
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
feats[i] = new ClipCorner;
|
||||
features.push_back(*feats[i]);
|
||||
}
|
||||
|
||||
// Attach each feature to the two features it shares edges with
|
||||
// Top-left
|
||||
|
@ -123,11 +116,7 @@ void VisualToolClip::CommitHold() {
|
|||
}
|
||||
}
|
||||
|
||||
bool VisualToolClip::InitializeDrag(feature_iterator) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolClip::UpdateDrag(feature_iterator feature) {
|
||||
void VisualToolClip::UpdateDrag(ClipCorner *feature) {
|
||||
// Update features which share an edge with the dragged one
|
||||
feature->horiz->pos = Vector2D(feature->horiz->pos, feature->pos);
|
||||
feature->vert->pos = Vector2D(feature->pos, feature->vert->pos);
|
||||
|
@ -139,7 +128,7 @@ void VisualToolClip::UpdateDrag(feature_iterator feature) {
|
|||
}
|
||||
|
||||
void VisualToolClip::SetFeaturePositions() {
|
||||
feature_iterator it = features.begin();
|
||||
auto it = features.begin();
|
||||
(it++)->pos = cur_1; // Top-left
|
||||
(it++)->pos = Vector2D(cur_2, cur_1); // Top-right
|
||||
(it++)->pos = Vector2D(cur_1, cur_2); // Bottom-left
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
struct ClipCorner : public VisualDraggableFeature {
|
||||
ClipCorner *horiz; ///< Other corner on this corner's horizontal line
|
||||
ClipCorner *vert; ///< Other corner on this corner's vertical line
|
||||
ClipCorner() : VisualDraggableFeature() , horiz(0) , vert(0) { }
|
||||
ClipCorner() : VisualDraggableFeature() , horiz(0) , vert(0) { type = DRAG_SMALL_CIRCLE; }
|
||||
};
|
||||
|
||||
class VisualToolClip : public VisualTool<ClipCorner> {
|
||||
|
@ -42,8 +42,8 @@ class VisualToolClip : public VisualTool<ClipCorner> {
|
|||
void DoRefresh();
|
||||
void SetFeaturePositions();
|
||||
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
bool InitializeDrag(ClipCorner *feature) { return true; }
|
||||
void UpdateDrag(ClipCorner *feature);
|
||||
|
||||
void Draw();
|
||||
public:
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "video_display.h"
|
||||
|
||||
#include <libaegisub/of_type_adaptor.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/format.hpp>
|
||||
|
@ -47,7 +48,7 @@ static const DraggableFeatureType DRAG_END = DRAG_BIG_CIRCLE;
|
|||
|
||||
VisualToolDrag::VisualToolDrag(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualToolDragDraggableFeature>(parent, context)
|
||||
, primary(0)
|
||||
, primary(nullptr)
|
||||
, button_is_move(true)
|
||||
{
|
||||
c->selectionController->GetSelectedSet(selection);
|
||||
|
@ -112,7 +113,7 @@ void VisualToolDrag::OnFileChanged() {
|
|||
features.clear();
|
||||
sel_features.clear();
|
||||
primary = 0;
|
||||
active_feature = features.end();
|
||||
active_feature = nullptr;
|
||||
|
||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
||||
if (IsDisplayed(diag))
|
||||
|
@ -126,8 +127,8 @@ void VisualToolDrag::OnFrameChanged() {
|
|||
if (primary && !IsDisplayed(primary->line))
|
||||
primary = 0;
|
||||
|
||||
feature_iterator feat = features.begin();
|
||||
feature_iterator end = features.end();
|
||||
auto feat = features.begin();
|
||||
auto end = features.end();
|
||||
|
||||
for (auto diag : c->ass->Line | agi::of_type<AssDialogue>()) {
|
||||
if (IsDisplayed(diag)) {
|
||||
|
@ -141,9 +142,9 @@ void VisualToolDrag::OnFrameChanged() {
|
|||
else {
|
||||
// Remove all features for this line (if any)
|
||||
while (feat != end && feat->line == diag) {
|
||||
if (feat == active_feature) active_feature = features.end();
|
||||
feat->line = 0;
|
||||
RemoveSelection(feat);
|
||||
if (&*feat == active_feature) active_feature = nullptr;
|
||||
feat->line = nullptr;
|
||||
RemoveSelection(&*feat);
|
||||
feat = features.erase(feat);
|
||||
}
|
||||
}
|
||||
|
@ -151,21 +152,23 @@ void VisualToolDrag::OnFrameChanged() {
|
|||
}
|
||||
|
||||
template<class C, class T> static bool line_not_present(C const& set, T const& it) {
|
||||
return std::none_of(set.begin(), set.end(), [&](T const& cmp) { return cmp->line == it->line; });
|
||||
return std::none_of(set.begin(), set.end(), [&](typename C::value_type const& cmp) {
|
||||
return cmp->line == it->line;
|
||||
});
|
||||
}
|
||||
|
||||
void VisualToolDrag::OnSelectedSetChanged(const SubtitleSelection &added, const SubtitleSelection &removed) {
|
||||
c->selectionController->GetSelectedSet(selection);
|
||||
|
||||
bool any_changed = false;
|
||||
for (feature_iterator it = features.begin(); it != features.end(); ) {
|
||||
for (auto it = features.begin(); it != features.end(); ) {
|
||||
if (removed.count(it->line)) {
|
||||
sel_features.erase(it++);
|
||||
sel_features.erase(&*it++);
|
||||
any_changed = true;
|
||||
}
|
||||
else {
|
||||
if (added.count(it->line) && it->type == DRAG_START && line_not_present(sel_features, it)) {
|
||||
sel_features.insert(it);
|
||||
sel_features.insert(&*it);
|
||||
any_changed = true;
|
||||
}
|
||||
++it;
|
||||
|
@ -180,11 +183,11 @@ void VisualToolDrag::Draw() {
|
|||
DrawAllFeatures();
|
||||
|
||||
// Draw connecting lines
|
||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||
if (cur->type == DRAG_START) continue;
|
||||
for (auto& feature : features) {
|
||||
if (feature.type == DRAG_START) continue;
|
||||
|
||||
feature_iterator p2 = cur;
|
||||
feature_iterator p1 = cur->parent;
|
||||
Feature *p2 = &feature;
|
||||
Feature *p1 = feature.parent;
|
||||
|
||||
// Move end marker has an arrow; origin doesn't
|
||||
bool has_arrow = p2->type == DRAG_END;
|
||||
|
@ -221,51 +224,54 @@ void VisualToolDrag::MakeFeatures(AssDialogue *diag) {
|
|||
MakeFeatures(diag, features.end());
|
||||
}
|
||||
|
||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_iterator pos) {
|
||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_list::iterator pos) {
|
||||
Vector2D p1 = FromScriptCoords(GetLinePosition(diag));
|
||||
|
||||
// Create \pos feature
|
||||
Feature feat;
|
||||
feat.pos = p1;
|
||||
feat.layer = 0;
|
||||
feat.type = DRAG_START;
|
||||
feat.time = 0;
|
||||
feat.line = diag;
|
||||
feat.parent = features.end();
|
||||
features.insert(pos, feat);
|
||||
feature_iterator cur = prev(pos);
|
||||
feat.parent = cur;
|
||||
auto feat = agi::util::make_unique<Feature>();
|
||||
auto parent = feat.get();
|
||||
feat->pos = p1;
|
||||
feat->type = DRAG_START;
|
||||
feat->line = diag;
|
||||
|
||||
if (selection.count(diag))
|
||||
sel_features.insert(cur);
|
||||
sel_features.insert(feat.get());
|
||||
features.insert(pos, *feat.release());
|
||||
|
||||
Vector2D p2;
|
||||
int t1, t2;
|
||||
|
||||
// Create move destination feature
|
||||
if (GetLineMove(diag, p1, p2, t1, t2)) {
|
||||
feat.pos = FromScriptCoords(p2);
|
||||
feat.layer = 1;
|
||||
feat.type = DRAG_END;
|
||||
feat.parent->time = t1;
|
||||
feat.time = t2;
|
||||
feat.line = diag;
|
||||
features.insert(pos, feat);
|
||||
feat.parent->parent = prev(pos);
|
||||
feat = agi::util::make_unique<Feature>();
|
||||
feat->pos = FromScriptCoords(p2);
|
||||
feat->layer = 1;
|
||||
feat->type = DRAG_END;
|
||||
feat->time = t2;
|
||||
feat->line = diag;
|
||||
feat->parent = parent;
|
||||
|
||||
parent->time = t1;
|
||||
parent->parent = feat.get();
|
||||
|
||||
features.insert(pos, *feat.release());
|
||||
}
|
||||
|
||||
// Create org feature
|
||||
if (Vector2D org = GetLineOrigin(diag)) {
|
||||
feat.pos = FromScriptCoords(org);
|
||||
feat.layer = -1;
|
||||
feat.type = DRAG_ORIGIN;
|
||||
feat.time = 0;
|
||||
feat.line = diag;
|
||||
features.insert(pos, feat);
|
||||
feat = agi::util::make_unique<Feature>();
|
||||
feat->pos = FromScriptCoords(org);
|
||||
feat->layer = -1;
|
||||
feat->type = DRAG_ORIGIN;
|
||||
feat->time = 0;
|
||||
feat->line = diag;
|
||||
feat->parent = parent;
|
||||
features.insert(pos, *feat.release());
|
||||
}
|
||||
}
|
||||
|
||||
bool VisualToolDrag::InitializeDrag(feature_iterator feature) {
|
||||
primary = &*feature;
|
||||
bool VisualToolDrag::InitializeDrag(Feature *feature) {
|
||||
primary = feature;
|
||||
|
||||
// Set time of clicked feature to the current frame and shift all other
|
||||
// selected features by the same amount
|
||||
|
@ -279,17 +285,17 @@ bool VisualToolDrag::InitializeDrag(feature_iterator feature) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void VisualToolDrag::UpdateDrag(feature_iterator feature) {
|
||||
void VisualToolDrag::UpdateDrag(Feature *feature) {
|
||||
if (feature->type == DRAG_ORIGIN) {
|
||||
SetOverride(feature->line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
return;
|
||||
}
|
||||
|
||||
feature_iterator end_feature = feature->parent;
|
||||
Feature *end_feature = feature->parent;
|
||||
if (feature->type == DRAG_END)
|
||||
std::swap(feature, end_feature);
|
||||
|
||||
if (feature->parent == features.end())
|
||||
if (!feature->parent)
|
||||
SetOverride(feature->line, "\\pos", ToScriptCoords(feature->pos).PStr());
|
||||
else
|
||||
SetOverride(feature->line, "\\move",
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
class VisualToolDragDraggableFeature : public VisualDraggableFeature {
|
||||
public:
|
||||
int time;
|
||||
boost::container::list<VisualToolDragDraggableFeature>::iterator parent;
|
||||
VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0) { }
|
||||
VisualToolDragDraggableFeature *parent;
|
||||
VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0), parent(nullptr) { }
|
||||
};
|
||||
|
||||
class wxBitmapButton;
|
||||
|
@ -54,7 +54,7 @@ class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
|||
/// @brief Create the features for a line
|
||||
/// @param diag Line to create the features for
|
||||
/// @param pos Insertion point in the feature list
|
||||
void MakeFeatures(AssDialogue *diag, feature_iterator pos);
|
||||
void MakeFeatures(AssDialogue *diag, feature_list::iterator pos);
|
||||
void MakeFeatures(AssDialogue *diag);
|
||||
|
||||
void OnSelectedSetChanged(SubtitleSelection const& lines_added, SubtitleSelection const& lines_removed);
|
||||
|
@ -64,8 +64,8 @@ class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
|||
void OnLineChanged();
|
||||
void OnCoordinateSystemsChanged() { OnFileChanged(); }
|
||||
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
bool InitializeDrag(Feature *feature);
|
||||
void UpdateDrag(Feature *feature);
|
||||
void Draw();
|
||||
void OnDoubleClick();
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, agi::Context *conte
|
|||
, orig_x(0)
|
||||
, orig_y(0)
|
||||
{
|
||||
features.resize(1);
|
||||
org = &features.back();
|
||||
org = new Feature;
|
||||
org->type = DRAG_BIG_TRIANGLE;
|
||||
features.push_back(*org);
|
||||
}
|
||||
|
||||
void VisualToolRotateXY::Draw() {
|
||||
|
@ -161,7 +161,7 @@ void VisualToolRotateXY::UpdateHold() {
|
|||
SetSelectedOverride("\\fry", str(boost::format("%.4g") % angle_y));
|
||||
}
|
||||
|
||||
void VisualToolRotateXY::UpdateDrag(feature_iterator feature) {
|
||||
void VisualToolRotateXY::UpdateDrag(Feature *feature) {
|
||||
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
|
|||
|
||||
void DoRefresh();
|
||||
void Draw();
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
void UpdateDrag(Feature *feature);
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
public:
|
||||
|
|
|
@ -36,9 +36,9 @@ VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context
|
|||
, orig_angle(0)
|
||||
, rotation_x(0)
|
||||
, rotation_y(0)
|
||||
, org(new Feature)
|
||||
{
|
||||
features.resize(1);
|
||||
org = &features.back();
|
||||
features.push_back(*org);
|
||||
org->type = DRAG_BIG_TRIANGLE;
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ void VisualToolRotateZ::UpdateHold() {
|
|||
SetSelectedOverride("\\frz", str(boost::format("%.4g") % angle));
|
||||
}
|
||||
|
||||
void VisualToolRotateZ::UpdateDrag(feature_iterator feature) {
|
||||
void VisualToolRotateZ::UpdateDrag(Feature *feature) {
|
||||
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
|
|||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
void UpdateDrag(Feature *feature);
|
||||
|
||||
void DoRefresh();
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "selection_controller.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <wx/toolbar.h>
|
||||
|
||||
|
@ -111,7 +113,7 @@ void VisualToolVectorClip::Draw() {
|
|||
spline.GetClosestParametricPoint(mouse_pos, highlighted_curve, t, pt);
|
||||
|
||||
// Draw highlighted line
|
||||
if ((mode == 3 || mode == 4) && active_feature == features.end() && points.size() > 2) {
|
||||
if ((mode == 3 || mode == 4) && !active_feature && points.size() > 2) {
|
||||
std::vector<float> highlighted_points;
|
||||
spline.GetPointList(highlighted_points, highlighted_curve);
|
||||
if (!highlighted_points.empty()) {
|
||||
|
@ -148,42 +150,47 @@ void VisualToolVectorClip::Draw() {
|
|||
}
|
||||
|
||||
void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
|
||||
Feature feat;
|
||||
feat.curve = cur;
|
||||
auto feat = agi::util::make_unique<Feature>();
|
||||
feat->curve = cur;
|
||||
|
||||
if (cur->type == SplineCurve::POINT) {
|
||||
feat.pos = cur->p1;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.point = 0;
|
||||
feat->pos = cur->p1;
|
||||
feat->type = DRAG_SMALL_CIRCLE;
|
||||
feat->point = 0;
|
||||
}
|
||||
else if (cur->type == SplineCurve::LINE) {
|
||||
feat.pos = cur->p2;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.point = 1;
|
||||
feat->pos = cur->p2;
|
||||
feat->type = DRAG_SMALL_CIRCLE;
|
||||
feat->point = 1;
|
||||
}
|
||||
else if (cur->type == SplineCurve::BICUBIC) {
|
||||
// Control points
|
||||
feat.pos = cur->p2;
|
||||
feat.point = 1;
|
||||
feat.type = DRAG_SMALL_SQUARE;
|
||||
features.push_back(feat);
|
||||
feat->pos = cur->p2;
|
||||
feat->point = 1;
|
||||
feat->type = DRAG_SMALL_SQUARE;
|
||||
features.push_back(*feat.release());
|
||||
|
||||
feat.pos = cur->p3;
|
||||
feat.point = 2;
|
||||
features.push_back(feat);
|
||||
feat = agi::util::make_unique<Feature>();
|
||||
feat->curve = cur;
|
||||
feat->pos = cur->p3;
|
||||
feat->point = 2;
|
||||
feat->type = DRAG_SMALL_SQUARE;
|
||||
features.push_back(*feat.release());
|
||||
|
||||
// End point
|
||||
feat.pos = cur->p4;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.point = 3;
|
||||
feat = agi::util::make_unique<Feature>();
|
||||
feat->curve = cur;
|
||||
feat->pos = cur->p4;
|
||||
feat->point = 3;
|
||||
feat->type = DRAG_SMALL_CIRCLE;
|
||||
}
|
||||
features.push_back(feat);
|
||||
features.push_back(*feat.release());
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::MakeFeatures() {
|
||||
sel_features.clear();
|
||||
features.clear();
|
||||
active_feature = features.end();
|
||||
active_feature = nullptr;
|
||||
for (auto it = spline.begin(); it != spline.end(); ++it)
|
||||
MakeFeature(it);
|
||||
}
|
||||
|
@ -202,12 +209,12 @@ void VisualToolVectorClip::Save() {
|
|||
}
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::UpdateDrag(feature_iterator feature) {
|
||||
void VisualToolVectorClip::UpdateDrag(Feature *feature) {
|
||||
spline.MovePoint(feature->curve, feature->point, feature->pos);
|
||||
Save();
|
||||
}
|
||||
|
||||
bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
||||
bool VisualToolVectorClip::InitializeDrag(Feature *feature) {
|
||||
if (mode != 5) return true;
|
||||
|
||||
if (feature->curve->type == SplineCurve::BICUBIC && (feature->point == 1 || feature->point == 2)) {
|
||||
|
@ -229,7 +236,7 @@ bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
|||
|
||||
spline.erase(feature->curve);
|
||||
}
|
||||
active_feature = features.end();
|
||||
active_feature = nullptr;
|
||||
|
||||
Save();
|
||||
MakeFeatures();
|
||||
|
@ -313,16 +320,15 @@ bool VisualToolVectorClip::InitializeHold() {
|
|||
if (mode == 6 || mode == 7) {
|
||||
sel_features.clear();
|
||||
features.clear();
|
||||
active_feature = features.end();
|
||||
active_feature = nullptr;
|
||||
spline.clear();
|
||||
spline.emplace_back(mouse_pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @todo box selection?
|
||||
if (mode == 0) {
|
||||
if (mode == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nothing to do for mode 5 (remove)
|
||||
return false;
|
||||
|
@ -398,6 +404,6 @@ void VisualToolVectorClip::DoRefresh() {
|
|||
|
||||
void VisualToolVectorClip::SelectAll() {
|
||||
sel_features.clear();
|
||||
for (feature_iterator it = features.begin(); it != features.end(); ++it)
|
||||
sel_features.insert(it);
|
||||
for (auto& feature : features)
|
||||
sel_features.insert(&feature);
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ struct VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
|
|||
int point;
|
||||
/// @brief Constructor
|
||||
VisualToolVectorClipDraggableFeature()
|
||||
: VisualDraggableFeature()
|
||||
, point(0)
|
||||
: VisualDraggableFeature()
|
||||
, point(0)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -59,8 +59,8 @@ class VisualToolVectorClip : public VisualTool<VisualToolVectorClipDraggableFeat
|
|||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
void UpdateDrag(Feature *feature);
|
||||
bool InitializeDrag(Feature *feature);
|
||||
|
||||
void DoRefresh();
|
||||
void Draw();
|
||||
|
|
Loading…
Reference in a new issue