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