Make visual tools pass around iterators for everything related to visual features rather than a mix of pointers and indices, and clean up feature creation. Fixes a large pile of selection-related bugs.

Originally committed to SVN as r4648.
This commit is contained in:
Thomas Goyne 2010-06-30 06:29:14 +00:00
parent 8bd5b16699
commit be1ed9e672
14 changed files with 373 additions and 379 deletions

View file

@ -47,7 +47,6 @@ VisualDraggableFeature::VisualDraggableFeature()
, origY(INT_MIN) , origY(INT_MIN)
, layer(0) , layer(0)
, line(NULL) , line(NULL)
, lineN(-1)
{ {
} }

View file

@ -81,7 +81,6 @@ public:
int layer; /// Layer; Higher = above int layer; /// Layer; Higher = above
AssDialogue* line; /// The dialogue line this feature is for AssDialogue* line; /// The dialogue line this feature is for
int lineN; /// The line's index in the file
/// @brief Is the given point over this feature? /// @brief Is the given point over this feature?
/// @param mx x coordinate to test /// @param mx x coordinate to test

View file

@ -75,13 +75,12 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
, dragStartX(0) , dragStartX(0)
, dragStartY(0) , dragStartY(0)
, selChanged(false) , selChanged(false)
, selectedFeatures(selFeatures)
, grid(VideoContext::Get()->grid) , grid(VideoContext::Get()->grid)
, parent(parent) , parent(parent)
, holding(false) , holding(false)
, dragging(false) , dragging(false)
, externalChange(true) , externalChange(true)
, curFeature(NULL)
, dragListOK(false)
, video(video) , video(video)
, leftClick(false) , leftClick(false)
, leftDClick(false) , leftDClick(false)
@ -92,6 +91,7 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
frameNumber = VideoContext::Get()->GetFrameN(); frameNumber = VideoContext::Get()->GetFrameN();
curDiag = GetActiveDialogueLine(); curDiag = GetActiveDialogueLine();
grid->AddSelectionListener(this); grid->AddSelectionListener(this);
curFeature = features.begin();
} }
template<class FeatureType> template<class FeatureType>
@ -124,35 +124,30 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
#endif #endif
altDown = event.m_altDown; altDown = event.m_altDown;
if (!dragListOK) {
PopulateFeatureList();
dragListOK = true;
needRender = true;
}
if (!dragging) { if (!dragging) {
unsigned oldHigh = curFeatureI; feature_iterator oldHigh = curFeature;
GetHighlightedFeature(); GetHighlightedFeature();
if (curFeatureI != oldHigh) needRender = true; if (curFeature != oldHigh) needRender = true;
} }
if (dragging) { if (dragging) {
// continue drag // continue drag
if (event.LeftIsDown()) { if (event.LeftIsDown()) {
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) { for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
features[*cur].x = (video.x - dragStartX + features[*cur].origX); (*cur)->x = (video.x - dragStartX + (*cur)->origX);
features[*cur].y = (video.y - dragStartY + features[*cur].origY); (*cur)->y = (video.y - dragStartY + (*cur)->origY);
if (shiftDown) { if (shiftDown) {
if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) { if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) {
features[*cur].y = features[*cur].origY; (*cur)->y = (*cur)->origY;
} }
else { else {
features[*cur].x = features[*cur].origX; (*cur)->x = (*cur)->origX;
} }
} }
UpdateDrag(&features[*cur]); UpdateDrag(*cur);
if (realTime) { if (realTime) {
CommitDrag(&features[*cur]); CommitDrag(*cur);
} }
} }
if (realTime) { if (realTime) {
@ -172,21 +167,21 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
if (!selChanged) { if (!selChanged) {
if (ctrlDown) { if (ctrlDown) {
// deselect this feature // deselect this feature
RemoveSelection(curFeatureI); RemoveSelection(curFeature);
} }
else { else {
SetSelection(curFeatureI); SetSelection(curFeature);
} }
} }
} }
else { else {
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) { for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
CommitDrag(&features[*cur]); CommitDrag(*cur);
} }
Commit(true); Commit(true);
} }
curFeature = NULL; curFeature = features.end();
parent->ReleaseMouse(); parent->ReleaseMouse();
parent->SetFocus(); parent->SetFocus();
} }
@ -216,27 +211,27 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
} }
else if (leftClick) { else if (leftClick) {
// start drag // start drag
if (curFeature) { if (curFeature != features.end()) {
if (InitializeDrag(curFeature)) { if (selFeatures.find(curFeature) == selFeatures.end()) {
if (selFeatures.find(curFeatureI) == selFeatures.end()) { selChanged = true;
selChanged = true; if (ctrlDown) {
if (ctrlDown) { AddSelection(curFeature);
AddSelection(curFeatureI);
}
else {
SetSelection(curFeatureI);
}
} }
else { else {
selChanged = false; SetSelection(curFeature);
} }
if (curFeature->line) grid->SetActiveLine(curFeature->line); }
else {
selChanged = false;
}
if (curFeature->line) grid->SetActiveLine(curFeature->line);
if (InitializeDrag(curFeature)) {
dragStartX = video.x; dragStartX = video.x;
dragStartY = video.y; dragStartY = video.y;
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) { for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
features[*cur].origX = features[*cur].x; (*cur)->origX = (*cur)->x;
features[*cur].origY = features[*cur].y; (*cur)->origY = (*cur)->y;
} }
dragging = true; dragging = true;
@ -291,13 +286,10 @@ AssDialogue* VisualTool<FeatureType>::GetActiveDialogueLine() {
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::GetHighlightedFeature() { void VisualTool<FeatureType>::GetHighlightedFeature() {
int highestLayerFound = INT_MIN; int highestLayerFound = INT_MIN;
curFeature = NULL; curFeature = features.end();
curFeatureI = -1; for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
unsigned i = 0;
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur, ++i) {
if (cur->IsMouseOver(video.x, video.y) && cur->layer > highestLayerFound) { if (cur->IsMouseOver(video.x, video.y) && cur->layer > highestLayerFound) {
curFeature = &*cur; curFeature = cur;
curFeatureI = i;
highestLayerFound = cur->layer; highestLayerFound = cur->layer;
} }
} }
@ -305,30 +297,25 @@ void VisualTool<FeatureType>::GetHighlightedFeature() {
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::DrawAllFeatures() { void VisualTool<FeatureType>::DrawAllFeatures() {
if (!dragListOK) {
PopulateFeatureList();
dragListOK = true;
}
SetLineColour(colour[0],1.0f,2); SetLineColour(colour[0],1.0f,2);
for (unsigned i = 0; i < features.size(); ++i) { for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
int fill; int fill;
if (&features[i] == curFeature) if (cur == curFeature)
fill = 2; fill = 2;
else if (selFeatures.find(i) != selFeatures.end()) else if (selFeatures.find(cur) != selFeatures.end())
fill = 3; fill = 3;
else else
fill = 1; fill = 1;
SetFillColour(colour[fill],0.6f); SetFillColour(colour[fill],0.6f);
features[i].Draw(*this); cur->Draw(*this);
} }
} }
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::Refresh() { void VisualTool<FeatureType>::Refresh() {
if (externalChange) { if (externalChange) {
dragListOK = false;
curDiag = GetActiveDialogueLine(); curDiag = GetActiveDialogueLine();
curFeature = features.end();
OnFileChanged(); OnFileChanged();
} }
} }
@ -336,6 +323,8 @@ void VisualTool<FeatureType>::Refresh() {
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::SetFrame(int newFrameNumber) { void VisualTool<FeatureType>::SetFrame(int newFrameNumber) {
if (frameNumber == newFrameNumber) return; if (frameNumber == newFrameNumber) return;
frameNumber = newFrameNumber;
curFeature = features.end();
OnFrameChanged(); OnFrameChanged();
AssDialogue *newCurDiag = GetActiveDialogueLine(); AssDialogue *newCurDiag = GetActiveDialogueLine();
if (newCurDiag != curDiag) { if (newCurDiag != curDiag) {
@ -357,14 +346,13 @@ void VisualTool<FeatureType>::OnActiveLineChanged(AssDialogue *new_line) {
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::SetSelection(unsigned i) { void VisualTool<FeatureType>::SetSelection(feature_iterator feat) {
assert(i < features.size());
selFeatures.clear(); selFeatures.clear();
lineSelCount.clear(); lineSelCount.clear();
selFeatures.insert(i);
AssDialogue *line = features[i].line; selFeatures.insert(feat);
AssDialogue *line = feat->line;
if (line) { if (line) {
lineSelCount[line] = 1; lineSelCount[line] = 1;
@ -376,23 +364,22 @@ void VisualTool<FeatureType>::SetSelection(unsigned i) {
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::AddSelection(unsigned i) { void VisualTool<FeatureType>::AddSelection(feature_iterator feat) {
assert(i < features.size()); if (selFeatures.insert(feat).second && feat->line) {
lineSelCount[feat->line] += 1;
if (selFeatures.insert(i).second && features[i].line) { Selection sel = grid->GetSelectedSet();
lineSelCount[features[i].line] += 1; if (sel.insert(feat->line).second) {
grid->SelectRow(features[i].lineN, true); grid->SetSelectedSet(sel);
}
} }
} }
template<class FeatureType> template<class FeatureType>
void VisualTool<FeatureType>::RemoveSelection(unsigned i) { void VisualTool<FeatureType>::RemoveSelection(feature_iterator feat) {
assert(i < features.size()); if (selFeatures.erase(feat) > 0 && feat->line) {
if (selFeatures.erase(i) > 0 && features[i].line) {
// Deselect a line only if all features for that line have been // Deselect a line only if all features for that line have been
// deselected // deselected
AssDialogue* line = features[i].line; AssDialogue* line = feat->line;
lineSelCount[line] -= 1; lineSelCount[line] -= 1;
assert(lineSelCount[line] >= 0); assert(lineSelCount[line] >= 0);
if (lineSelCount[line] <= 0) { if (lineSelCount[line] <= 0) {

View file

@ -76,28 +76,39 @@ public:
virtual ~IVisualTool() { }; virtual ~IVisualTool() { };
}; };
struct ltaddr {
template<class T>
bool operator()(T lft, T rgt) const {
return &*lft < &*rgt;
}
};
/// DOCME /// DOCME
/// @class VisualTool /// @class VisualTool
/// @brief DOCME /// @brief DOCME
/// DOCME /// DOCME
template<class FeatureType> template<class FeatureType>
class VisualTool : public IVisualTool, protected SubtitleSelectionListener { class VisualTool : public IVisualTool, protected SubtitleSelectionListener {
protected:
typedef typename FeatureType Feature;
typedef typename std::list<FeatureType>::iterator feature_iterator;
typedef typename std::list<FeatureType>::const_iterator feature_const_iterator;
private: private:
agi::OptionValue* realtime; /// Realtime updating option agi::OptionValue* realtime; /// Realtime updating option
int dragStartX; /// Starting x coordinate of the current drag, if any int dragStartX; /// Starting x coordinate of the current drag, if any
int dragStartY; /// Starting y coordinate of the current drag, if any int dragStartY; /// Starting y coordinate of the current drag, if any
/// Set curFeature and curFeatureI to the topmost feature under the mouse, /// Set curFeature to the topmost feature under the mouse, or end() if there
/// or NULL and -1 if there are none /// are none
void GetHighlightedFeature(); void GetHighlightedFeature();
/// @brief Get the dialogue line currently in the edit box /// @brief Get the dialogue line currently in the edit box
/// @return NULL if the line is not active on the current frame /// @return NULL if the line is not active on the current frame
AssDialogue *GetActiveDialogueLine(); AssDialogue *GetActiveDialogueLine();
typedef typename std::set<int>::iterator selection_iterator; typedef typename std::set<feature_iterator, ltaddr>::iterator selection_iterator;
std::set<int> selFeatures; /// Currently selected visual features std::set<feature_iterator, ltaddr> selFeatures; /// Currently selected visual features
std::map<AssDialogue*, int> lineSelCount; /// Number of selected features for each line std::map<AssDialogue*, int> lineSelCount; /// Number of selected features for each line
bool selChanged; /// Has the selection already been changed in the current click? bool selChanged; /// Has the selection already been changed in the current click?
@ -110,18 +121,15 @@ private:
/// @brief Called at the end of a hold /// @brief Called at the end of a hold
virtual void CommitHold() { } virtual void CommitHold() { }
/// @brief Called when the feature list needs to be (re)generated
virtual void PopulateFeatureList() { }
/// @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(FeatureType* feature) { return true; } virtual bool InitializeDrag(feature_iterator 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(FeatureType* feature) { } virtual void UpdateDrag(feature_iterator feature) { }
/// @brief Called at the end of a drag /// @brief Called at the end of a drag
virtual void CommitDrag(FeatureType* feature) { } virtual void CommitDrag(feature_iterator feature) { }
/// Called when the file is changed by something other than a visual tool /// Called when the file is changed by something other than a visual tool
virtual void OnFileChanged() { DoRefresh(); } virtual void OnFileChanged() { DoRefresh(); }
@ -141,6 +149,9 @@ private:
virtual void Draw()=0; virtual void Draw()=0;
protected: protected:
/// Read-only reference to the set of selected features for subclasses
const std::set<feature_iterator, ltaddr> &selectedFeatures;
typedef typename std::set<feature_iterator, ltaddr>::const_iterator sel_iterator;
SubtitlesGrid *grid; SubtitlesGrid *grid;
VideoDisplay *parent; /// VideoDisplay which this belongs to, used to frame conversion VideoDisplay *parent; /// VideoDisplay which this belongs to, used to frame conversion
bool holding; /// Is a hold currently in progress? bool holding; /// Is a hold currently in progress?
@ -148,10 +159,8 @@ protected:
bool dragging; /// Is a drag currently in progress? bool dragging; /// Is a drag currently in progress?
bool externalChange; /// Only invalid drag lists when refreshing due to external changes bool externalChange; /// Only invalid drag lists when refreshing due to external changes
FeatureType* curFeature; /// Topmost feature under the mouse; generally only valid during a drag feature_iterator curFeature; /// Topmost feature under the mouse; generally only valid during a drag
unsigned curFeatureI; /// Index of the current feature in the list std::list<FeatureType> features; /// List of features which are drawn and can be clicked on
std::vector<FeatureType> features; /// List of features which are drawn and can be clicked on
bool dragListOK; /// Do the features not need to be regenerated?
int frameNumber; /// Current frame number int frameNumber; /// Current frame number
VideoState const& video; /// Mouse and video information VideoState const& video; /// Mouse and video information
@ -179,24 +188,20 @@ protected:
/// @brief Add a feature (and its line) to the selection /// @brief Add a feature (and its line) to the selection
/// @param i Index in the feature list /// @param i Index in the feature list
void AddSelection(unsigned i); void AddSelection(feature_iterator feat);
/// @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(unsigned i); void RemoveSelection(feature_iterator 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(unsigned i); void SetSelection(feature_iterator feat);
/// @brief Clear the selection /// @brief Clear the selection
void ClearSelection(); void ClearSelection();
typedef typename std::vector<FeatureType>::iterator feature_iterator;
typedef typename std::vector<FeatureType>::const_iterator feature_const_iterator;
protected:
// SubtitleSelectionListener implementation // SubtitleSelectionListener implementation
void OnActiveLineChanged(AssDialogue *new_line); void OnActiveLineChanged(AssDialogue *new_line);
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { } virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { }

View file

@ -58,6 +58,38 @@ VisualToolClip::VisualToolClip(VideoDisplay *parent, VideoState const& video, wx
if (curDiag) { if (curDiag) {
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse); GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
} }
Feature feat;
feat.type = DRAG_SMALL_CIRCLE;
features.resize(4, feat);
feature_iterator cur = features.begin();
feats[0] = &*(cur++);
feats[1] = &*(cur++);
feats[2] = &*(cur++);
feats[3] = &*(cur++);
// Top-left
int i = 0;
feats[i]->horiz = feats[1];
feats[i]->vert = feats[2];
i++;
// Top-right
feats[i]->horiz = feats[0];
feats[i]->vert = feats[3];
i++;
// Bottom-left
feats[i]->horiz = feats[3];
feats[i]->vert = feats[0];
i++;
// Bottom-right
feats[i]->horiz = feats[2];
feats[i]->vert = feats[1];
i++;
} }
void VisualToolClip::Draw() { void VisualToolClip::Draw() {
@ -101,7 +133,6 @@ bool VisualToolClip::InitializeHold() {
} }
void VisualToolClip::UpdateHold() { void VisualToolClip::UpdateHold() {
// Coordinates
curX1 = startX; curX1 = startX;
curY1 = startY; curY1 = startY;
curX2 = video.x; curX2 = video.x;
@ -117,7 +148,7 @@ void VisualToolClip::UpdateHold() {
curY1 = MID(0,curY1,video.h); curY1 = MID(0,curY1,video.h);
curY2 = MID(0,curY2,video.h); curY2 = MID(0,curY2,video.h);
PopulateFeatureList(); SetFeaturePositions();
} }
void VisualToolClip::CommitHold() { void VisualToolClip::CommitHold() {
@ -130,83 +161,57 @@ void VisualToolClip::CommitHold() {
SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip",wxString::Format(L"(%i,%i,%i,%i)",x1,y1,x2,y2)); SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip",wxString::Format(L"(%i,%i,%i,%i)",x1,y1,x2,y2));
} }
void VisualToolClip::PopulateFeatureList() { bool VisualToolClip::InitializeDrag(feature_iterator) {
if (features.size() != 4) {
ClearSelection();
features.clear();
features.resize(4);
}
// Top-left
int i = 0;
features[i].x = curX1;
features[i].y = curY1;
features[i].horiz = &features[1];
features[i].vert = &features[2];
features[i].type = DRAG_SMALL_CIRCLE;
i++;
// Top-right
features[i].x = curX2;
features[i].y = curY1;
features[i].horiz = &features[0];
features[i].vert = &features[3];
features[i].type = DRAG_SMALL_CIRCLE;
i++;
// Bottom-left
features[i].x = curX1;
features[i].y = curY2;
features[i].horiz = &features[3];
features[i].vert = &features[0];
features[i].type = DRAG_SMALL_CIRCLE;
i++;
// Bottom-right
features[i].x = curX2;
features[i].y = curY2;
features[i].horiz = &features[2];
features[i].vert = &features[1];
features[i].type = DRAG_SMALL_CIRCLE;
i++;
}
bool VisualToolClip::InitializeDrag(ClipCorner*) {
curDiag->StripTag(L"\\clip"); curDiag->StripTag(L"\\clip");
curDiag->StripTag(L"\\iclip"); curDiag->StripTag(L"\\iclip");
return true; return true;
} }
void VisualToolClip::UpdateDrag(ClipCorner* feature) { void VisualToolClip::UpdateDrag(feature_iterator feature) {
// Update brothers // Update brothers
feature->horiz->y = feature->y; feature->horiz->y = feature->y;
feature->vert->x = feature->x; feature->vert->x = feature->x;
// Get "cur" from features // Get "cur" from features
curX1 = features[0].x; curX1 = feats[0]->x;
curX2 = features[3].x; curX2 = feats[3]->x;
curY1 = features[0].y; curY1 = feats[0]->y;
curY2 = features[3].y; curY2 = feats[3]->y;
// Make sure p1 < p2 // Make sure p1 < p2
if (curX1 > curX2) std::swap(curX1,curX2); if (curX1 > curX2) std::swap(curX1,curX2);
if (curY1 > curY2) std::swap(curY1,curY2); if (curY1 > curY2) std::swap(curY1,curY2);
} }
void VisualToolClip::CommitDrag(ClipCorner*) { void VisualToolClip::CommitDrag(feature_iterator) {
CommitHold(); CommitHold();
} }
void VisualToolClip::OnLineChanged() { void VisualToolClip::SetFeaturePositions() {
if (curDiag) { // Top-left
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse); int i = 0;
PopulateFeatureList(); feats[i]->x = curX1;
} feats[i]->y = curY1;
i++;
// Top-right
feats[i]->x = curX2;
feats[i]->y = curY1;
i++;
// Bottom-left
feats[i]->x = curX1;
feats[i]->y = curY2;
i++;
// Bottom-right
feats[i]->x = curX2;
feats[i]->y = curY2;
} }
void VisualToolClip::OnFileChanged() { void VisualToolClip::DoRefresh() {
if (curDiag) { if (curDiag) {
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse); GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
PopulateFeatureList(); SetFeaturePositions();
} }
} }

View file

@ -59,19 +59,20 @@ public:
class VisualToolClip : public VisualTool<ClipCorner> { class VisualToolClip : public VisualTool<ClipCorner> {
int startX,startY,curX1,curY1,curX2,curY2; int startX,startY,curX1,curY1,curX2,curY2;
ClipCorner *feats[4];
bool inverse; bool inverse;
bool InitializeHold(); bool InitializeHold();
void UpdateHold(); void UpdateHold();
void CommitHold(); void CommitHold();
void OnLineChanged(); void DoRefresh();
void OnFileChanged(); void SetFeaturePositions();
void PopulateFeatureList(); bool InitializeDrag(feature_iterator feature);
bool InitializeDrag(ClipCorner* feature); void UpdateDrag(feature_iterator feature);
void UpdateDrag(ClipCorner* feature); void CommitDrag(feature_iterator feature);
void CommitDrag(ClipCorner* feature);
void Draw(); void Draw();
public: public:

View file

@ -65,6 +65,9 @@ VisualToolDrag::VisualToolDrag(VideoDisplay *parent, VideoState const& video, wx
toolBar->AddTool(BUTTON_TOGGLE_MOVE, _("Toggle between \\move and \\pos"), GETIMAGE(visual_move_conv_move_24)); toolBar->AddTool(BUTTON_TOGGLE_MOVE, _("Toggle between \\move and \\pos"), GETIMAGE(visual_move_conv_move_24));
toolBar->Realize(); toolBar->Realize();
toolBar->Show(true); toolBar->Show(true);
grid->GetSelectedSet(selection);
OnFileChanged();
} }
void VisualToolDrag::UpdateToggleButtons() { void VisualToolDrag::UpdateToggleButtons() {
@ -93,9 +96,8 @@ void VisualToolDrag::UpdateToggleButtons() {
/// @brief Toggle button pressed /// @brief Toggle button pressed
/// @param event /// @param event
void VisualToolDrag::OnSubTool(wxCommandEvent &) { void VisualToolDrag::OnSubTool(wxCommandEvent &) {
Selection sel = grid->GetSelectedSet();
// Toggle \move <-> \pos // Toggle \move <-> \pos
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) { for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
AssDialogue *line = *cur; AssDialogue *line = *cur;
int x1,y1,x2,y2,t1,t2; int x1,y1,x2,y2,t1,t2;
bool hasMove; bool hasMove;
@ -118,31 +120,62 @@ void VisualToolDrag::OnLineChanged() {
} }
void VisualToolDrag::OnFileChanged() { void VisualToolDrag::OnFileChanged() {
/// @todo be less dumb and preserve selections when possible /// @todo it should be possible to preserve the selection in some cases
PopulateFeatureList(); features.clear();
ClearSelection();
primary = NULL;
for (int i = grid->GetRows() - 1; i >=0; i--) {
AssDialogue *diag = grid->GetDialogue(i);
if (BaseGrid::IsDisplayed(diag)) {
MakeFeatures(diag);
}
}
} }
void VisualToolDrag::OnFrameChanged() { void VisualToolDrag::OnFrameChanged() {
/// @todo be less dumb and preserve selections when possible if (primary && !BaseGrid::IsDisplayed(primary->line)) primary = NULL;
PopulateFeatureList();
feature_iterator feat = features.begin();
feature_iterator end = features.end();
for (int i = grid->GetRows() - 1; i >=0; i--) {
AssDialogue *diag = grid->GetDialogue(i);
if (BaseGrid::IsDisplayed(diag)) {
// Features don't exist and should
if (feat == end || feat->line != diag) {
MakeFeatures(diag, feat);
}
// Move past already existing features for the line
else {
while (feat != end && feat->line == diag) ++feat;
}
}
else {
// Remove all features for this line (if any)
while (feat != end && feat->line == diag) {
feat->line = NULL;
RemoveSelection(feat);
feat = features.erase(feat);
}
}
}
} }
void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) { void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) {
grid->GetSelectedSet(selection);
if (!externalChange) return; if (!externalChange) return;
externalChange = false; externalChange = false;
grid->BeginBatch(); grid->BeginBatch();
// Remove all deselected lines for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
for (size_t i = 0; i < features.size(); i++) { // Remove all deselected lines
if (removed.find(features[i].line) != removed.end()) { if (removed.find(cur->line) != removed.end()) {
RemoveSelection(i); RemoveSelection(cur);
} }
} // And add all newly selected lines
else if (added.find(cur->line) != added.end() && cur->type == DRAG_START) {
// And add all newly selected lines AddSelection(cur);
for (size_t i = 0; i < features.size(); i++) {
if (added.find(features[i].line) != added.end() && features[i].type == DRAG_START) {
AddSelection(i);
} }
} }
@ -156,8 +189,8 @@ void VisualToolDrag::Draw() {
// Draw arrows // Draw arrows
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) { for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
if (cur->type == DRAG_START) continue; if (cur->type == DRAG_START) continue;
VisualDraggableFeature *p2 = &*cur; feature_iterator p2 = cur;
VisualDraggableFeature *p1 = &features[cur->parent]; feature_iterator p1 = cur->parent;
// Has arrow? // Has arrow?
bool hasArrow = p2->type == DRAG_END; bool hasArrow = p2->type == DRAG_END;
@ -199,89 +232,77 @@ void VisualToolDrag::Draw() {
} }
} }
} }
void VisualToolDrag::MakeFeatures(AssDialogue *diag) {
void VisualToolDrag::PopulateFeatureList() { MakeFeatures(diag, features.end());
ClearSelection();
primary = -1;
GenerateFeatures();
} }
void VisualToolDrag::GenerateFeatures() { void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_iterator pos) {
features.clear(); // Get position
int x1,x2,y1,y2;
int t1=0;
int t2=diag->End.GetMS()-diag->Start.GetMS();
int torgx,torgy;
bool hasMove;
GetLinePosition(diag,x1,y1,torgx,torgy);
GetLineMove(diag,hasMove,x1,y1,x2,y2,t1,t2);
// Get video data // Create \pos feature
BaseGrid* grid = VideoContext::Get()->grid; Feature feat;
int numRows = grid->GetRows(); feat.x = x1;
feat.y = y1;
feat.layer = 0;
feat.type = DRAG_START;
feat.time = t1;
feat.line = diag;
feat.parent = features.end();
features.insert(pos, feat);
feature_iterator cur = pos; --cur;
feat.parent = cur;
if (selection.find(diag) != selection.end()) {
AddSelection(cur);
}
for (int i=numRows;--i>=0;) { // Create move destination feature
AssDialogue *diag = grid->GetDialogue(i); if (hasMove) {
if (!diag || !BaseGrid::IsDisplayed(diag)) continue; feat.x = x2;
feat.y = y2;
// Get position feat.layer = 1;
int x1,x2,y1,y2; feat.type = DRAG_END;
int t1=0; feat.time = t2;
int t2=diag->End.GetMS()-diag->Start.GetMS();
int torgx,torgy;
bool hasMove;
GetLinePosition(diag,x1,y1,torgx,torgy);
GetLineMove(diag,hasMove,x1,y1,x2,y2,t1,t2);
// Create \pos feature
VisualToolDragDraggableFeature feat;
feat.x = x1;
feat.y = y1;
feat.layer = 0;
feat.type = DRAG_START;
feat.time = t1;
feat.line = diag; feat.line = diag;
feat.lineN = i; features.insert(pos, feat);
features.push_back(feat); feat.parent->parent = --pos; ++pos;
feat.parent = features.size() - 1; }
if (grid->IsInSelection(i)) { // Create org feature
AddSelection(features.size() - 1); if (torgx != x1 || torgy != y1) {
} feat.x = torgx;
feat.y = torgy;
// Create move destination feature feat.layer = -1;
if (hasMove) { feat.type = DRAG_ORIGIN;
feat.x = x2; feat.time = 0;
feat.y = y2; feat.line = diag;
feat.layer = 1; features.insert(pos, feat);
feat.type = DRAG_END;
feat.time = t2;
feat.line = diag;
feat.lineN = i;
features.push_back(feat);
features[feat.parent].parent = features.size() - 1;
}
// Create org feature
if (torgx != x1 || torgy != y1) {
feat.x = torgx;
feat.y = torgy;
feat.layer = -1;
feat.type = DRAG_ORIGIN;
feat.time = 0;
feat.line = diag;
feat.lineN = i;
features.push_back(feat);
}
} }
} }
bool VisualToolDrag::InitializeDrag(VisualToolDragDraggableFeature *feature) { bool VisualToolDrag::InitializeDrag(feature_iterator feature) {
primary = feature - &features[0]; primary = &*feature;
// Set time of clicked feature to the current frame and shift all other
// selected features by the same amount
if (feature->type != DRAG_ORIGIN) {
int time = VFR_Output.GetTimeAtFrame(frameNumber,true,true) - feature->line->Start.GetMS();
int change = time - feature->time;
for (sel_iterator cur = selectedFeatures.begin(); cur != selectedFeatures.end(); ++cur) {
if ((*cur)->type != DRAG_ORIGIN) {
(*cur)->time += change;
}
}
}
return true; return true;
} }
/// @brief Update drag void VisualToolDrag::CommitDrag(feature_iterator feature) {
/// @param feature
void VisualToolDrag::UpdateDrag(VisualToolDragDraggableFeature* feature) {
// Update "time" to reflect the time of the frame in which the feature is being dragged
int time = VFR_Output.GetTimeAtFrame(frameNumber,true,true);
feature->time = MID(0,time - feature->line->Start.GetMS(),feature->line->End.GetMS()-feature->line->Start.GetMS());
}
/// @brief Commit drag
/// @param feature
void VisualToolDrag::CommitDrag(VisualToolDragDraggableFeature* feature) {
if (feature->type == DRAG_ORIGIN) { if (feature->type == DRAG_ORIGIN) {
int x = feature->x; int x = feature->x;
int y = feature->y; int y = feature->y;
@ -290,7 +311,7 @@ void VisualToolDrag::CommitDrag(VisualToolDragDraggableFeature* feature) {
return; return;
} }
VisualToolDragDraggableFeature *p = feature->parent > -1 ? &features[feature->parent] : NULL; feature_iterator p = feature->parent;
if (feature->type == DRAG_END) { if (feature->type == DRAG_END) {
std::swap(feature, p); std::swap(feature, p);
} }
@ -300,7 +321,7 @@ void VisualToolDrag::CommitDrag(VisualToolDragDraggableFeature* feature) {
parent->ToScriptCoords(&x1, &y1); parent->ToScriptCoords(&x1, &y1);
// Position // Position
if (!p) { if (feature->parent == features.end()) {
SetOverride(feature->line, L"\\pos", wxString::Format(L"(%i,%i)", x1, y1)); SetOverride(feature->line, L"\\pos", wxString::Format(L"(%i,%i)", x1, y1));
} }
// Move // Move
@ -309,7 +330,6 @@ void VisualToolDrag::CommitDrag(VisualToolDragDraggableFeature* feature) {
int y2 = p->y; int y2 = p->y;
parent->ToScriptCoords(&x2, &y2); parent->ToScriptCoords(&x2, &y2);
// Set override
SetOverride(feature->line, L"\\move", wxString::Format(L"(%i,%i,%i,%i,%i,%i)", x1, y1, x2, y2, feature->time, p->time)); SetOverride(feature->line, L"\\move", wxString::Format(L"(%i,%i,%i,%i,%i,%i)", x1, y1, x2, y2, feature->time, p->time));
} }
} }
@ -320,9 +340,9 @@ bool VisualToolDrag::Update() {
int vx = video.x; int vx = video.x;
int vy = video.y; int vy = video.y;
parent->ToScriptCoords(&vx, &vy); parent->ToScriptCoords(&vx, &vy);
if (primary > -1) { if (primary) {
dx = features[primary].x; dx = primary->x;
dy = features[primary].y; dy = primary->y;
} }
else { else {
if (!curDiag) return false; if (!curDiag) return false;
@ -332,8 +352,7 @@ bool VisualToolDrag::Update() {
dx -= vx; dx -= vx;
dy -= vy; dy -= vy;
Selection sel = grid->GetSelectedSet(); for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, t1 = INT_MIN, t2 = INT_MIN, orgx, orgy; int x1 = 0, y1 = 0, x2 = 0, y2 = 0, t1 = INT_MIN, t2 = INT_MIN, orgx, orgy;
bool isMove; bool isMove;
@ -359,6 +378,6 @@ bool VisualToolDrag::Update() {
Commit(true, _("positioning")); Commit(true, _("positioning"));
GenerateFeatures(); OnFileChanged();
return false; return false;
} }

View file

@ -47,12 +47,8 @@
class VisualToolDragDraggableFeature : public VisualDraggableFeature { class VisualToolDragDraggableFeature : public VisualDraggableFeature {
public: public:
int time; int time;
int parent; std::list<VisualToolDragDraggableFeature>::iterator parent;
VisualToolDragDraggableFeature() VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0) { }
: VisualDraggableFeature()
, time(0)
, parent(-1)
{ }
}; };
@ -62,21 +58,29 @@ public:
/// ///
/// DOCME /// DOCME
class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> { class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
private: /// The subtoolbar for the move/pos conversion button
wxToolBar *toolBar; /// The subtoolbar wxToolBar *toolBar;
int primary; /// The feature last clicked on /// The feature last clicked on for the double-click handler
/// Equal to curFeature during drags; possibly different at all other times
/// Null if no features have been clicked on or the last clicked on one no
/// longer exists
Feature *primary;
/// The last announced selection set
Selection selection;
int change;
/// When the button is pressed, will it convert the line to a move (vs. from /// When the button is pressed, will it convert the line to a move (vs. from
/// move to pos)? Used to avoid changing the button's icon unnecessarily /// move to pos)? Used to avoid changing the button's icon unnecessarily
bool toggleMoveOnMove; bool toggleMoveOnMove;
/// Regenerage features without touching the selection /// @brief Create the features for a line
void GenerateFeatures(); /// @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);
void PopulateFeatureList(); bool InitializeDrag(feature_iterator feature);
bool InitializeDrag(VisualToolDragDraggableFeature* feature); void CommitDrag(feature_iterator feature);
void UpdateDrag(VisualToolDragDraggableFeature* feature);
void CommitDrag(VisualToolDragDraggableFeature* feature);
/// Set the pos/move button to the correct icon based on the active line /// Set the pos/move button to the correct icon based on the active line
void UpdateToggleButtons(); void UpdateToggleButtons();

View file

@ -51,6 +51,9 @@
VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, VideoState const& video, wxToolBar *) VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, VideoState const& video, wxToolBar *)
: VisualTool<VisualDraggableFeature>(parent, video) : VisualTool<VisualDraggableFeature>(parent, video)
{ {
features.resize(1);
org = &features.back();
org->type = DRAG_BIG_TRIANGLE;
DoRefresh(); DoRefresh();
} }
@ -60,9 +63,9 @@ void VisualToolRotateXY::Draw() {
// Pivot coordinates // Pivot coordinates
int dx=0,dy=0; int dx=0,dy=0;
if (dragging) GetLinePosition(curDiag,dx,dy); if (dragging) GetLinePosition(curDiag,dx,dy);
else GetLinePosition(curDiag,dx,dy,orgx,orgy); else GetLinePosition(curDiag,dx,dy,org->x,org->y);
dx = orgx; dx = org->x;
dy = orgy; dy = org->y;
SetLineColour(colour[0]); SetLineColour(colour[0]);
SetFillColour(colour[1],0.3f); SetFillColour(colour[1],0.3f);
@ -152,8 +155,8 @@ void VisualToolRotateXY::Draw() {
} }
bool VisualToolRotateXY::InitializeHold() { bool VisualToolRotateXY::InitializeHold() {
startAngleX = (orgy-video.y)*2.f; startAngleX = (org->y-video.y)*2.f;
startAngleY = (video.x-orgx)*2.f; startAngleY = (video.x-org->x)*2.f;
origAngleX = curAngleX; origAngleX = curAngleX;
origAngleY = curAngleY; origAngleY = curAngleY;
@ -161,8 +164,8 @@ bool VisualToolRotateXY::InitializeHold() {
} }
void VisualToolRotateXY::UpdateHold() { void VisualToolRotateXY::UpdateHold() {
float screenAngleX = (orgy-video.y)*2.f; float screenAngleX = (org->y-video.y)*2.f;
float screenAngleY = (video.x-orgx)*2.f; float screenAngleY = (video.x-org->x)*2.f;
// Deltas // Deltas
float deltaX = screenAngleX - startAngleX; float deltaX = screenAngleX - startAngleX;
@ -193,36 +196,16 @@ void VisualToolRotateXY::CommitHold() {
} }
} }
void VisualToolRotateXY::PopulateFeatureList() { void VisualToolRotateXY::CommitDrag(feature_iterator feature) {
if (!curDiag) return;
int posx, posy;
GetLinePosition(curDiag,posx,posy,orgx,orgy);
// Set features
features.resize(1);
VisualDraggableFeature &feat = features.back();
feat.x = orgx;
feat.y = orgy;
feat.line = curDiag;
feat.type = DRAG_BIG_TRIANGLE;
}
void VisualToolRotateXY::UpdateDrag(VisualDraggableFeature* feature) {
orgx = feature->x;
orgy = feature->y;
}
void VisualToolRotateXY::CommitDrag(VisualDraggableFeature* feature) {
int x = feature->x; int x = feature->x;
int y = feature->y; int y = feature->y;
parent->ToScriptCoords(&x, &y); parent->ToScriptCoords(&x, &y);
SetOverride(feature->line, L"\\org",wxString::Format(L"(%i,%i)",x,y)); SetOverride(curDiag, L"\\org",wxString::Format(L"(%i,%i)",x,y));
} }
void VisualToolRotateXY::DoRefresh() { void VisualToolRotateXY::DoRefresh() {
if (!curDiag) return; if (!curDiag) return;
int posx, posy; int posx, posy;
GetLinePosition(curDiag,posx,posy,orgx,orgy); GetLinePosition(curDiag,posx,posy,org->x,org->y);
GetLineRotation(curDiag,curAngleX,curAngleY,curAngleZ); GetLineRotation(curDiag,curAngleX,curAngleY,curAngleZ);
} }

View file

@ -44,16 +44,13 @@ class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
float curAngleX,startAngleX,origAngleX; float curAngleX,startAngleX,origAngleX;
float curAngleY,startAngleY,origAngleY; float curAngleY,startAngleY,origAngleY;
float curAngleZ; float curAngleZ;
int orgx,orgy; Feature *org;
bool InitializeHold(); bool InitializeHold();
void UpdateHold(); void UpdateHold();
void CommitHold(); void CommitHold();
void CommitDrag(feature_iterator feature);
void PopulateFeatureList();
void UpdateDrag(VisualDraggableFeature* feature);
void CommitDrag(VisualDraggableFeature* feature);
void DoRefresh(); void DoRefresh();

View file

@ -54,6 +54,9 @@ static const float rad2deg = 180.f / 3.1415926536f;
VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, VideoState const& video, wxToolBar *) VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, VideoState const& video, wxToolBar *)
: VisualTool<VisualDraggableFeature>(parent, video) : VisualTool<VisualDraggableFeature>(parent, video)
{ {
features.resize(1);
org = &features.back();
org->type = DRAG_BIG_TRIANGLE;
DoRefresh(); DoRefresh();
} }
@ -63,7 +66,7 @@ void VisualToolRotateZ::Draw() {
// Draw pivot // Draw pivot
DrawAllFeatures(); DrawAllFeatures();
int radius = (int)sqrt(double((posx-orgx)*(posx-orgx)+(posy-orgy)*(posy-orgy))); int radius = (int)sqrt(double((posx-org->x)*(posx-org->x)+(posy-org->y)*(posy-org->y)));
int oRadius = radius; int oRadius = radius;
if (radius < 50) radius = 50; if (radius < 50) radius = 50;
@ -78,7 +81,7 @@ void VisualToolRotateZ::Draw() {
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
glTranslatef(orgx,orgy,-1.f); glTranslatef(org->x,org->y,-1.f);
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 }; float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
glMultMatrixf(matrix); glMultMatrixf(matrix);
glScalef(1.f,1.f,8.f); glScalef(1.f,1.f,8.f);
@ -103,8 +106,8 @@ void VisualToolRotateZ::Draw() {
DrawLine(deltax,deltay,-deltax,-deltay); DrawLine(deltax,deltay,-deltax,-deltay);
// Draw the connection line // Draw the connection line
if (orgx != posx || orgy != posy) { if (org->x != posx || org->y != posy) {
double angle = atan2(double(orgy-posy),double(posx-orgx)) + curAngle*deg2rad; double angle = atan2(double(org->y-posy),double(posx-org->x)) + curAngle*deg2rad;
int fx = int(cos(angle)*oRadius); int fx = int(cos(angle)*oRadius);
int fy = -int(sin(angle)*oRadius); int fy = -int(sin(angle)*oRadius);
DrawLine(0,0,fx,fy); DrawLine(0,0,fx,fy);
@ -121,14 +124,14 @@ void VisualToolRotateZ::Draw() {
glPopMatrix(); glPopMatrix();
// Draw line to mouse // Draw line to mouse
if (!dragging && !curFeature && video.x > INT_MIN && video.y > INT_MIN) { if (!dragging && curFeature == features.end() && video.x > INT_MIN && video.y > INT_MIN) {
SetLineColour(colour[0]); SetLineColour(colour[0]);
DrawLine(orgx,orgy,video.x,video.y); DrawLine(org->x,org->y,video.x,video.y);
} }
} }
bool VisualToolRotateZ::InitializeHold() { bool VisualToolRotateZ::InitializeHold() {
startAngle = atan2(double(orgy-video.y),double(video.x-orgx)) * rad2deg; startAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
origAngle = curAngle; origAngle = curAngle;
curDiag->StripTag(L"\\frz"); curDiag->StripTag(L"\\frz");
curDiag->StripTag(L"\\fr"); curDiag->StripTag(L"\\fr");
@ -137,7 +140,7 @@ bool VisualToolRotateZ::InitializeHold() {
} }
void VisualToolRotateZ::UpdateHold() { void VisualToolRotateZ::UpdateHold() {
float screenAngle = atan2(double(orgy-video.y),double(video.x-orgx)) * rad2deg; float screenAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
curAngle = fmodf(screenAngle - startAngle + origAngle + 360.f, 360.f); curAngle = fmodf(screenAngle - startAngle + origAngle + 360.f, 360.f);
// Oh Snap // Oh Snap
@ -154,33 +157,16 @@ void VisualToolRotateZ::CommitHold() {
} }
} }
void VisualToolRotateZ::PopulateFeatureList() { void VisualToolRotateZ::CommitDrag(feature_iterator feature) {
if (!curDiag) return;
// Set features
features.resize(1);
VisualDraggableFeature &feat = features.back();
feat.x = orgx;
feat.y = orgy;
feat.line = curDiag;
feat.type = DRAG_BIG_TRIANGLE;
}
void VisualToolRotateZ::UpdateDrag(VisualDraggableFeature* feature) {
orgx = feature->x;
orgy = feature->y;
}
void VisualToolRotateZ::CommitDrag(VisualDraggableFeature* feature) {
int x = feature->x; int x = feature->x;
int y = feature->y; int y = feature->y;
parent->ToScriptCoords(&x, &y); parent->ToScriptCoords(&x, &y);
SetOverride(feature->line, L"\\org",wxString::Format(L"(%i,%i)",x,y)); SetOverride(curDiag, L"\\org",wxString::Format(L"(%i,%i)",x,y));
} }
void VisualToolRotateZ::DoRefresh() { void VisualToolRotateZ::DoRefresh() {
if (!curDiag) return; if (!curDiag) return;
GetLinePosition(curDiag, posx, posy, orgx, orgy); GetLinePosition(curDiag, posx, posy, org->x, org->y);
GetLineRotation(curDiag, rx, ry, curAngle); GetLineRotation(curDiag, rx, ry, curAngle);
GetLineScale(curDiag, scaleX, scaleY); GetLineScale(curDiag, scaleX, scaleY);
} }

View file

@ -45,7 +45,7 @@
/// DOCME /// DOCME
class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> { class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
float curAngle, startAngle, origAngle; float curAngle, startAngle, origAngle;
int orgx, orgy; Feature *org;
int posx, posy; int posx, posy;
float rx, ry; float rx, ry;
float scaleX, scaleY; float scaleX, scaleY;
@ -54,9 +54,7 @@ class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
void UpdateHold(); void UpdateHold();
void CommitHold(); void CommitHold();
void PopulateFeatureList(); void CommitDrag(feature_iterator feature);
void UpdateDrag(VisualDraggableFeature* feature);
void CommitDrag(VisualDraggableFeature* feature);
void DoRefresh(); void DoRefresh();

View file

@ -53,6 +53,7 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "libresrc/libresrc.h" #include "libresrc/libresrc.h"
#include "utils.h"
#include "video_display.h" #include "video_display.h"
#include "visual_tool_vector_clip.h" #include "visual_tool_vector_clip.h"
@ -69,12 +70,19 @@ enum {
BUTTON_LAST // Leave this at the end and don't use it BUTTON_LAST // Leave this at the end and don't use it
}; };
template<class C, class O, class M>
static void for_each_iter(C &container, O obj, M method) {
C::iterator end = container.end();
for (C::iterator cur = container.begin(); cur != end; ++cur) {
(obj ->* method)(cur);
}
}
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, VideoState const& video, wxToolBar * toolBar) VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, VideoState const& video, wxToolBar * toolBar)
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, video) : VisualTool<VisualToolVectorClipDraggableFeature>(parent, video)
, spline(*parent) , spline(*parent)
, toolBar(toolBar) , toolBar(toolBar)
{ {
// Create toolbar
toolBar->AddTool(BUTTON_DRAG,_("Drag"),GETIMAGE(visual_vector_clip_drag_24),_("Drag control points."),wxITEM_CHECK); toolBar->AddTool(BUTTON_DRAG,_("Drag"),GETIMAGE(visual_vector_clip_drag_24),_("Drag control points."),wxITEM_CHECK);
toolBar->AddTool(BUTTON_LINE,_("Line"),GETIMAGE(visual_vector_clip_line_24),_("Appends a line."),wxITEM_CHECK); toolBar->AddTool(BUTTON_LINE,_("Line"),GETIMAGE(visual_vector_clip_line_24),_("Appends a line."),wxITEM_CHECK);
toolBar->AddTool(BUTTON_BICUBIC,_("Bicubic"),GETIMAGE(visual_vector_clip_bicubic_24),_("Appends a bezier bicubic curve."),wxITEM_CHECK); toolBar->AddTool(BUTTON_BICUBIC,_("Bicubic"),GETIMAGE(visual_vector_clip_bicubic_24),_("Appends a bezier bicubic curve."),wxITEM_CHECK);
@ -184,7 +192,7 @@ void VisualToolVectorClip::Draw() {
spline.GetClosestParametricPoint(Vector2D(video.x, video.y), highCurve, t, pt); spline.GetClosestParametricPoint(Vector2D(video.x, video.y), highCurve, t, pt);
// Draw highlighted line // Draw highlighted line
if ((mode == 3 || mode == 4) && !curFeature && points.size() > 2) { if ((mode == 3 || mode == 4) && curFeature == features.end() && points.size() > 2) {
std::vector<float> highPoints; std::vector<float> highPoints;
spline.GetPointList(highPoints, highCurve); spline.GetPointList(highPoints, highCurve);
if (!highPoints.empty()) { if (!highPoints.empty()) {
@ -223,7 +231,7 @@ void VisualToolVectorClip::Draw() {
} }
void VisualToolVectorClip::MakeFeature(Spline::iterator cur) { void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
VisualToolVectorClipDraggableFeature feat; Feature feat;
if (cur->type == CURVE_POINT) { if (cur->type == CURVE_POINT) {
feat.x = (int)cur->p1.x; feat.x = (int)cur->p1.x;
feat.y = (int)cur->p1.y; feat.y = (int)cur->p1.y;
@ -250,6 +258,7 @@ void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
feat.point = 1; feat.point = 1;
feat.type = DRAG_SMALL_SQUARE; feat.type = DRAG_SMALL_SQUARE;
features.push_back(feat); features.push_back(feat);
feat.x = (int)cur->p3.x; feat.x = (int)cur->p3.x;
feat.y = (int)cur->p3.y; feat.y = (int)cur->p3.y;
feat.point = 2; feat.point = 2;
@ -264,28 +273,33 @@ void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
} }
} }
void VisualToolVectorClip::PopulateFeatureList() { void VisualToolVectorClip::MakeFeatures() {
ClearSelection();
features.clear(); features.clear();
// This is perhaps a bit conservative as there can be up to 3N+1 features for_each_iter(spline, this, &VisualToolVectorClip::MakeFeature);
features.reserve(spline.size());
for (Spline::iterator cur = spline.begin(); cur != spline.end(); ++cur) {
MakeFeature(cur);
}
} }
void VisualToolVectorClip::UpdateDrag(VisualToolVectorClipDraggableFeature* feature) { void VisualToolVectorClip::Save() {
spline.MovePoint(feature->curve,feature->point,Vector2D(feature->x,feature->y));
}
void VisualToolVectorClip::CommitDrag(VisualToolVectorClipDraggableFeature*) {
SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")"); SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")");
} }
bool VisualToolVectorClip::InitializeDrag(VisualToolVectorClipDraggableFeature* feature) { void VisualToolVectorClip::UpdateDrag(feature_iterator feature) {
// Delete a control point spline.MovePoint(feature->curve,feature->point,Vector2D(feature->x,feature->y));
if (mode == 5) { }
// Update next
void VisualToolVectorClip::CommitDrag(feature_iterator) {
Save();
}
bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
if (mode != 5) return true;
if (feature->curve->type == CURVE_BICUBIC && (feature->point == 1 || feature->point == 2)) {
// Deleting bicubic curve handles, so convert to line
feature->curve->type = CURVE_LINE;
feature->curve->p2 = feature->curve->p4;
}
else {
Spline::iterator next = feature->curve; Spline::iterator next = feature->curve;
next++; next++;
if (next != spline.end()) { if (next != spline.end()) {
@ -298,16 +312,15 @@ bool VisualToolVectorClip::InitializeDrag(VisualToolVectorClipDraggableFeature*
} }
} }
// Erase and save changes
spline.erase(feature->curve); spline.erase(feature->curve);
CommitDrag(feature);
curFeature = NULL;
PopulateFeatureList();
ClearSelection();
Commit(true);
return false;
} }
return true; curFeature = features.end();
Save();
MakeFeatures();
Commit(true, _("delete control point"));
return false;
} }
bool VisualToolVectorClip::InitializeHold() { bool VisualToolVectorClip::InitializeHold() {
@ -318,8 +331,7 @@ bool VisualToolVectorClip::InitializeHold() {
// Set start position // Set start position
if (!spline.empty()) { if (!spline.empty()) {
curve.p1 = spline.back().EndPoint(); curve.p1 = spline.back().EndPoint();
if (mode == 1) curve.type = CURVE_LINE; curve.type = mode == 1 ? CURVE_LINE : CURVE_BICUBIC;
else curve.type = CURVE_BICUBIC;
} }
// First point // First point
@ -383,9 +395,9 @@ bool VisualToolVectorClip::InitializeHold() {
} }
// Commit // Commit
SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")"); Save();
MakeFeatures();
Commit(true); Commit(true);
DoRefresh();
return false; return false;
} }
@ -430,7 +442,7 @@ void VisualToolVectorClip::UpdateHold() {
} }
else curve.p2 = curve.p1 * 0.75 + curve.p4 * 0.25; else curve.p2 = curve.p1 * 0.75 + curve.p4 * 0.25;
curve.p3 = curve.p1 * 0.25 + curve.p4 * 0.75; curve.p3 = curve.p1 * 0.25 + curve.p4 * 0.75;
PopulateFeatureList(); MakeFeatures();
} }
// Freehand // Freehand
@ -452,21 +464,19 @@ void VisualToolVectorClip::UpdateHold() {
} }
void VisualToolVectorClip::CommitHold() { void VisualToolVectorClip::CommitHold() {
if (mode == 3 || mode == 4) return;
// Smooth spline // Smooth spline
if (!holding && mode == 7) { if (!holding && mode == 7) {
spline.Smooth(); spline.Smooth();
PopulateFeatureList();
} }
// Save it Save();
if (mode != 3 && mode != 4) {
SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")");
}
// End freedraw // End freedraw
if (!holding && (mode == 6 || mode == 7)) { if (!holding && (mode == 6 || mode == 7)) {
SetMode(0); SetMode(0);
SelectAll(); MakeFeatures();
} }
} }
@ -477,13 +487,12 @@ void VisualToolVectorClip::DoRefresh() {
int scale; int scale;
vect = GetLineVectorClip(curDiag,scale,inverse); vect = GetLineVectorClip(curDiag,scale,inverse);
spline.DecodeFromASS(vect); spline.DecodeFromASS(vect);
MakeFeatures();
SelectAll(); SelectAll();
PopulateFeatureList();
} }
void VisualToolVectorClip::SelectAll() { void VisualToolVectorClip::SelectAll() {
ClearSelection(); ClearSelection();
for (size_t i = 0; i < features.size(); ++i) { for_each_iter(features, this, &VisualToolVectorClip::AddSelection);
AddSelection(i);
}
} }

View file

@ -69,17 +69,19 @@ class VisualToolVectorClip : public VisualTool<VisualToolVectorClipDraggableFeat
/// @param mode 0-7 /// @param mode 0-7
void SetMode(int mode); void SetMode(int mode);
void Save();
void SelectAll(); void SelectAll();
void MakeFeature(Spline::iterator cur); void MakeFeature(Spline::iterator cur);
void MakeFeatures();
bool InitializeHold(); bool InitializeHold();
void UpdateHold(); void UpdateHold();
void CommitHold(); void CommitHold();
void PopulateFeatureList(); void UpdateDrag(feature_iterator feature);
void UpdateDrag(VisualToolVectorClipDraggableFeature* feature); void CommitDrag(feature_iterator feature);
void CommitDrag(VisualToolVectorClipDraggableFeature* feature); bool InitializeDrag(feature_iterator feature);
bool InitializeDrag(VisualToolVectorClipDraggableFeature* feature);
void DoRefresh(); void DoRefresh();
void Draw(); void Draw();