Fix selection issues with visual features

Selections in drag mode now follow the following rules:

 * If a line is selected in the grid, at least one visual feature
   corresponding to the line is selected.

 * If a line has any features selected, that line is selected in the
   grid.

In addition, all control points now start out selected in the vector
clip tool, and all tools should no longer discard the current selection
at unpredictable or unintended times.

Updates #513.

Originally committed to SVN as r4363.
This commit is contained in:
Thomas Goyne 2010-05-26 07:17:39 +00:00
parent d2a81d871b
commit 877eabdce7
15 changed files with 332 additions and 216 deletions

View File

@ -80,6 +80,7 @@ BaseGrid::BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wx
holding = false;
byFrame = false;
lineHeight = 1; // non-zero to avoid div by 0
selChangeSub = NULL;
// Set scrollbar
scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL);
@ -206,9 +207,8 @@ void BaseGrid::MakeCellVisible(int row, int col,bool center) {
/// @param select
///
void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
if (!addToSelected) ClearSelection();
if (row < 0 || (size_t)row >= selMap.size()) return;
if (!addToSelected) ClearSelection();
if (select != selMap[row]) {
selMap[row] = select;
@ -222,6 +222,8 @@ void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
GetClientSize(&w,&h);
RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false);
}
if (selChangeSub) selChangeSub->OnSelectionChange(!addToSelected, row, select);
}
}

View File

@ -35,7 +35,7 @@
///
#pragma once
////////////
// Includes
@ -58,6 +58,11 @@ class FrameMain;
/// DOCME
typedef std::list<AssEntry*>::iterator entryIter;
class SelectionChangeSubscriber {
public:
virtual void OnSelectionChange(bool clear, int row, bool selected) = 0;
};
/// DOCME
@ -92,6 +97,8 @@ private:
/// DOCME
wxBitmap *bmp;
SelectionChangeSubscriber* selChangeSub;
void OnPaint(wxPaintEvent &event);
void OnSize(wxSizeEvent &event);
void OnScroll(wxScrollEvent &event);
@ -162,6 +169,10 @@ public:
AssDialogue *GetDialogue(int n) const;
void RegisterSelectionChange(SelectionChangeSubscriber* sel) {
selChangeSub = sel;
}
BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxWANTS_CHARS, const wxString& name = wxPanelNameStr);
~BaseGrid();

View File

@ -261,11 +261,10 @@ void SubsEditBox::SetSplitLineMode(wxSize newSize) {
/// @brief Update function
/// @param timeOnly If true, only update the time fields
/// @param weak ?
/// @param video If true, update the video display
/// @param timeOnly
/// @param weak
///
void SubsEditBox::Update (bool timeOnly,bool weak,bool video) {
void SubsEditBox::Update (bool timeOnly,bool weak) {
if (enabled) {
AssDialogue *curdiag = grid->GetDialogue(linen);
if (curdiag) {
@ -301,7 +300,7 @@ void SubsEditBox::Update (bool timeOnly,bool weak,bool video) {
// Video
VideoContext::Get()->curLine = curdiag;
if (video) VideoContext::Get()->UpdateDisplays(false);
VideoContext::Get()->UpdateDisplays(false);
TextEdit->EmptyUndoBuffer();
}
@ -353,12 +352,10 @@ void SubsEditBox::SetToLine(int n,bool weak) {
// Set to nothing
if (n == -1) {
enabled = false;
SetControlsState(false);
return;
}
// Set line
if (grid->GetDialogue(n)) {
else if (grid->GetDialogue(n)) {
enabled = true;
if (n != linen) {
linen = n;
@ -369,7 +366,7 @@ void SubsEditBox::SetToLine(int n,bool weak) {
}
// Update controls
Update(false, false, false);
Update();
// Set video
if (VideoContext::Get()->IsLoaded() && !weak) {

View File

@ -251,7 +251,7 @@ public:
void SetSplitLineMode(wxSize size=wxSize(-1,-1));
void CommitText(bool weak=false);
void Update(bool timeOnly=false,bool weak=false,bool video=true);
void Update(bool timeOnly=false,bool weak=false);
void UpdateGlobals();
void SetToLine(int n,bool weak=false);
void UpdateFrameTiming();

View File

@ -530,6 +530,7 @@ double VideoDisplay::GetZoom() const {
template<class T>
void VideoDisplay::SetTool() {
tool.reset();
tool.reset(new T(this, video, toolBar));
box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &T::OnSubTool, static_cast<T*>(tool.get()), VISUAL_SUB_TOOL_START, VISUAL_SUB_TOOL_END);
}

View File

@ -45,7 +45,6 @@ VisualDraggableFeature::VisualDraggableFeature()
, y(INT_MIN)
, origX(INT_MIN)
, origY(INT_MIN)
, selected(false)
, layer(0)
, line(NULL)
, lineN(-1)

View File

@ -78,8 +78,6 @@ public:
int origX; /// x coordindate before the last operation began
int origY; /// y coordindate before the last operation began
bool selected; ///Iis this feature selected?
int layer; /// Layer; Higher = above
AssDialogue* line; /// The dialogue line this feature is for

View File

@ -72,12 +72,12 @@ template<class FeatureType>
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& video)
: dragStartX(0)
, dragStartY(0)
, externalChange(true)
, selChanged(false)
, parent(parent)
, holding(false)
, curDiag(NULL)
, dragging(false)
, externalChange(true)
, curFeature(NULL)
, dragListOK(false)
, frame_n(0)
@ -90,6 +90,7 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
{
if (VideoContext::Get()->IsLoaded()) {
frame_n = VideoContext::Get()->GetFrameN();
VideoContext::Get()->grid->RegisterSelectionChange(this);
}
PopulateFeatureList();
@ -97,6 +98,7 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
template<class FeatureType>
VisualTool<FeatureType>::~VisualTool() {
VideoContext::Get()->grid->RegisterSelectionChange(NULL);
}
template<class FeatureType>
@ -125,25 +127,28 @@ void VisualTool<FeatureType>::OnMouseEvent (wxMouseEvent &event) {
PopulateFeatureList();
dragListOK = true;
}
if (!dragging) {
GetHighlightedFeature();
}
if (dragging) {
// continue drag
if (event.LeftIsDown()) {
for (SelFeatureIter cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
(*cur)->x = (video.x - dragStartX + (*cur)->origX);
(*cur)->y = (video.y - dragStartY + (*cur)->origY);
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
features[*cur].x = (video.x - dragStartX + features[*cur].origX);
features[*cur].y = (video.y - dragStartY + features[*cur].origY);
if (shiftDown) {
if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) {
(*cur)->y = (*cur)->origY;
features[*cur].y = features[*cur].origY;
}
else {
(*cur)->x = (*cur)->origX;
features[*cur].x = features[*cur].origX;
}
}
UpdateDrag(*cur);
UpdateDrag(&features[*cur]);
if (realTime) {
CommitDrag(*cur);
CommitDrag(&features[*cur]);
}
}
if (realTime) Commit();
@ -160,26 +165,18 @@ void VisualTool<FeatureType>::OnMouseEvent (wxMouseEvent &event) {
if (!selChanged) {
if (ctrlDown) {
// deselect this feature
selFeatures.remove(curFeature);
curFeature->selected = false;
if (curFeature->lineN > -1) {
con->grid->SelectRow(curFeature->lineN, true, false);
}
RemoveSelection(curFeatureI);
}
else {
// deselect everything else
ClearSelection();
selFeatures.push_back(curFeature);
curFeature->selected = true;
if (curFeature->lineN > -1) {
con->grid->SelectRow(curFeature->lineN, false);
}
AddSelection(curFeatureI);
}
}
}
else {
for (SelFeatureIter cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
CommitDrag(*cur);
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
CommitDrag(&features[*cur]);
}
Commit(true);
}
@ -213,34 +210,28 @@ void VisualTool<FeatureType>::OnMouseEvent (wxMouseEvent &event) {
}
}
else if (leftClick) {
curFeature = GetHighlightedFeature();
// start drag
if (curFeature) {
if (InitializeDrag(curFeature)) {
if (!curFeature->selected) {
if (selFeatures.find(curFeatureI) == selFeatures.end()) {
selChanged = true;
if (!ctrlDown) {
ClearSelection();
}
selFeatures.push_back(curFeature);
curFeature->selected = true;
if (curFeature->lineN != -1) {
con->grid->editBox->SetToLine(curFeature->lineN,true);
con->grid->SelectRow(curFeature->lineN, ctrlDown);
}
AddSelection(curFeatureI);
}
else {
selChanged = false;
if (curFeature->lineN != -1) {
con->grid->editBox->SetToLine(curFeature->lineN,true);
}
}
if (curFeature->lineN != -1) {
SetEditbox(curFeature->lineN);
}
dragStartX = video.x;
dragStartY = video.y;
for (SelFeatureIter cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
(*cur)->origX = (*cur)->x;
(*cur)->origY = (*cur)->y;
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
features[*cur].origX = features[*cur].x;
features[*cur].origY = features[*cur].y;
}
dragging = true;
@ -250,7 +241,10 @@ void VisualTool<FeatureType>::OnMouseEvent (wxMouseEvent &event) {
}
// start hold
else {
if (!altDown) ClearSelection();
if (!altDown) {
ClearSelection();
SetEditbox();
}
curDiag = GetActiveDialogueLine();
if (curDiag && InitializeHold()) {
holding = true;
@ -265,40 +259,40 @@ void VisualTool<FeatureType>::OnMouseEvent (wxMouseEvent &event) {
}
template<class FeatureType>
void VisualTool<FeatureType>::Commit(bool full) {
void VisualTool<FeatureType>::Commit(bool full, wxString message) {
SubtitlesGrid *grid = VideoContext::Get()->grid;
if (full) grid->ass->FlagAsModified(_("visual typesetting"));
if (full) {
if (message.empty()) {
message = _("visual typesetting");
}
grid->ass->FlagAsModified(message);
}
grid->CommitChanges(false,!full);
grid->editBox->Update(false, true, false);
grid->editBox->Update(false, true);
}
template<class FeatureType>
AssDialogue* VisualTool<FeatureType>::GetActiveDialogueLine() {
SubtitlesGrid *grid = VideoContext::Get()->grid;
AssDialogue *diag = grid->GetDialogue(grid->editBox->linen);
// Check if it's within range
if (diag) {
int f1 = VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true);
int f2 = VFR_Output.GetFrameAtTime(diag->End.GetMS(),false);
if (f1 > frame_n || f2 < frame_n) return NULL;
}
return diag;
if (grid->IsDisplayed(diag))
return diag;
return NULL;
}
template<class FeatureType>
FeatureType* VisualTool<FeatureType>::GetHighlightedFeature() {
void VisualTool<FeatureType>::GetHighlightedFeature() {
int highestLayerFound = INT_MIN;
FeatureType* bestMatch = NULL;
for (FeatureIter cur = features.begin(); cur != features.end(); ++cur) {
curFeature = NULL;
curFeatureI = -1;
unsigned i = 0;
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur, ++i) {
if (cur->IsMouseOver(video.x, video.y) && cur->layer > highestLayerFound) {
bestMatch = &*cur;
curFeature = &*cur;
curFeatureI = i;
highestLayerFound = cur->layer;
}
}
return bestMatch;
}
template<class FeatureType>
@ -308,31 +302,96 @@ void VisualTool<FeatureType>::DrawAllFeatures() {
dragListOK = true;
}
FeatureType* mouseOver = curFeature ? curFeature : GetHighlightedFeature();
for (FeatureCIter cur = features.begin(); cur != features.end(); ++cur) {
int fill = &*cur == mouseOver ? 2 :
cur->selected ? 3 :
1;
for (unsigned i = 0; i < features.size(); ++i) {
int fill;
if (&features[i] == curFeature)
fill = 2;
else if (selFeatures.find(i) != selFeatures.end())
fill = 3;
else
fill = 1;
SetFillColour(colour[fill],0.6f);
SetLineColour(colour[0],1.0f,2);
cur->Draw(*this);
features[i].Draw(*this);
}
}
template<class FeatureType>
void VisualTool<FeatureType>::Refresh() {
frame_n = VideoContext::Get()->GetFrameN();
if (externalChange) dragListOK = false;
DoRefresh();
if (externalChange) {
dragListOK = false;
DoRefresh();
}
}
template<class FeatureType>
void VisualTool<FeatureType>::AddSelection(unsigned i) {
assert(i < features.size());
if (selFeatures.insert(i).second && features[i].line) {
lineSelCount[features[i].lineN] += 1;
SubtitlesGrid *grid = VideoContext::Get()->grid;
grid->SelectRow(features[i].lineN, true);
}
}
template<class FeatureType>
void VisualTool<FeatureType>::ClearSelection() {
for (SelFeatureIter cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
(*cur)->selected = false;
void VisualTool<FeatureType>::RemoveSelection(unsigned i) {
assert(i < features.size());
if (selFeatures.erase(i) > 0 && features[i].line) {
// Deselect a line only if all features for that line have been
// deselected
int lineN = features[i].lineN;
lineSelCount[lineN] -= 1;
assert(lineSelCount[lineN] >= 0);
if (lineSelCount[lineN] <= 0) {
SubtitlesGrid *grid = VideoContext::Get()->grid;
grid->SelectRow(lineN, true, false);
// We may have just deselected the active line, so make sure the
// edit box is set to something sane
SetEditbox();
}
}
}
template<class FeatureType>
wxArrayInt VisualTool<FeatureType>::GetSelection() {
return VideoContext::Get()->grid->GetSelection();
}
template<class FeatureType>
void VisualTool<FeatureType>::ClearSelection(bool hard) {
if (hard) {
VideoContext::Get()->grid->SelectRow(0, false, false);
}
selFeatures.clear();
lineSelCount.clear();
}
template<class FeatureType>
void VisualTool<FeatureType>::SetEditbox(int lineN) {
VideoContext* con = VideoContext::Get();
if (lineN > -1) {
con->grid->editBox->SetToLine(lineN);
con->grid->SelectRow(lineN, true);
}
else {
wxArrayInt sel = GetSelection();
// If there is a selection and the edit box's line is in it, do nothing
// Otherwise set the edit box if there is a selection or the selection
// to the edit box if there is no selection
if (sel.empty()) {
con->grid->SelectRow(con->grid->editBox->linen, true);
return;
}
else if (!std::binary_search(sel.begin(), sel.end(), con->grid->editBox->linen)) {
con->grid->editBox->SetToLine(sel[0]);
}
}
}
/// @brief Get position of line

View File

@ -36,14 +36,15 @@
#pragma once
#ifndef AGI_PRE
#include <list>
#include <vector>
#include <deque>
#include <set>
#include <wx/log.h>
#include <wx/event.h>
#include <wx/button.h>
#endif
#include "base_grid.h"
#include "gl_wrap.h"
class VideoDisplay;
@ -74,30 +75,40 @@ public:
/// @brief DOCME
/// DOCME
template<class FeatureType>
class VisualTool : public IVisualTool {
class VisualTool : public IVisualTool, public SelectionChangeSubscriber {
private:
int dragStartX; /// Starting x coordinate of the current drag, if any
int dragStartY; /// Starting y coordinate of the current drag, if any
/// @brief Get the topmost visual feature under the mouse, or NULL if none are under the mouse
FeatureType* GetHighlightedFeature();
/// Set curFeature and curFeatureI to the topmost feature under the mouse,
/// or NULL and -1 if there are none
void GetHighlightedFeature();
typedef typename std::list<FeatureType*>::iterator SelFeatureIter;
typedef typename std::list<FeatureType>::iterator FeatureIter;
typedef typename std::list<FeatureType>::const_iterator FeatureCIter;
typedef typename std::set<int>::iterator selection_iterator;
std::list<FeatureType*> selFeatures; /// Currently selected visual features
std::set<int> selFeatures; /// Currently selected visual features
std::map<int, int> lineSelCount; /// Number of selected features for each line
/// @brief Set the edit box's active line, ensuring proper sync with grid
/// @param lineN Line number or -1 for automatic selection
///
/// This function ensures that the selection is not empty and that the line
/// displayed in the edit box is part of the selection, by either setting
/// the edit box to the selection or setting the selection to the edit
/// box's line, as is appropriate.
void SetEditbox(int lineN = -1);
bool externalChange; /// Only invalid drag lists when refreshing due to external changes
bool selChanged; /// Has the selection already been changed in the current click?
protected:
VideoDisplay *parent; /// VideoDisplay which this belongs to, used to frame conversion
bool holding; /// Is a hold currently in progress?
AssDialogue *curDiag; /// Active dialogue line for a hold; only valid when holding = true
bool dragging; /// Is a drag currently in progress?
bool externalChange; /// Only invalid drag lists when refreshing due to external changes
FeatureType* curFeature; /// Topmost feature under the mouse; only valid during a drag?
std::list<FeatureType> features; /// List of features which are drawn and can be clicked on
FeatureType* curFeature; /// Topmost feature under the mouse; generally only valid during a drag
unsigned curFeatureI; /// Index of the current feature in the list
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 frame_n; /// Current frame number
@ -121,8 +132,11 @@ protected:
/// @brief Get the dialogue line currently in the edit box
/// @return NULL if the line is not active on the current frame
AssDialogue *GetActiveDialogueLine();
/// Draw all of the features in the list
void DrawAllFeatures();
void Commit(bool full=false);
/// @brief Commit the current file state
/// @param message Description of changes for undo
void Commit(bool full=false, wxString message = L"");
/// @brief Called when a hold is begun
/// @return Should the hold actually happen?
@ -152,8 +166,21 @@ protected:
/// @brief Called when there's stuff
virtual void DoRefresh() { }
/// @brief Must be called before removing entries from features
void ClearSelection();
/// @brief Add a feature (and its line) to the selection
/// @param i Index in the feature list
void AddSelection(unsigned i);
/// @brief Remove a feature from the selection
/// @param i Index in the feature list
/// Also deselects lines if all features for that line have been deselected
void RemoveSelection(unsigned i);
/// @brief Clear the selection
/// @param hard Should the grid's selection be cleared as well?
void ClearSelection(bool hard=true);
/// @brief Get the currently selected lines
wxArrayInt GetSelection();
typedef typename std::vector<FeatureType>::iterator feature_iterator;
typedef typename std::vector<FeatureType>::const_iterator feature_const_iterator;
public:
/// @brief Handler for all mouse events
@ -166,9 +193,12 @@ public:
virtual void Update() { };
/// @brief Draw stuff
virtual void Draw()=0;
/// @brief Called when there's stuff
/// @brief Called by stuff when there's stuff
void Refresh();
/// Called by the grid when the selection changes
virtual void OnSelectionChange(bool, int, bool) { }
/// @brief Constructor
/// @param parent The VideoDisplay to use for coordinate conversion
/// @param video Video and mouse information passing blob
@ -177,4 +207,3 @@ public:
/// @brief Destructor
virtual ~VisualTool();
};

View File

@ -140,46 +140,42 @@ void VisualToolClip::CommitHold() {
void VisualToolClip::PopulateFeatureList() {
// Clear
if (features.size() != 4) {
ClearSelection();
ClearSelection(false);
features.clear();
features.resize(4);
int i = 0;
for (std::list<ClipCorner>::iterator cur = features.begin(); cur != features.end(); ++cur, ++i) {
feat[i] = &*cur;
}
}
// Top-left
int i = 0;
feat[i]->x = curX1;
feat[i]->y = curY1;
feat[i]->horiz = feat[1];
feat[i]->vert = feat[2];
feat[i]->type = DRAG_SMALL_CIRCLE;
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
feat[i]->x = curX2;
feat[i]->y = curY1;
feat[i]->horiz = feat[0];
feat[i]->vert = feat[3];
feat[i]->type = DRAG_SMALL_CIRCLE;
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
feat[i]->x = curX1;
feat[i]->y = curY2;
feat[i]->horiz = feat[3];
feat[i]->vert = feat[0];
feat[i]->type = DRAG_SMALL_CIRCLE;
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
feat[i]->x = curX2;
feat[i]->y = curY2;
feat[i]->horiz = feat[2];
feat[i]->vert = feat[1];
feat[i]->type = DRAG_SMALL_CIRCLE;
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++;
}
@ -200,10 +196,10 @@ void VisualToolClip::UpdateDrag(ClipCorner* feature) {
feature->vert->x = feature->x;
// Get "cur" from features
curX1 = feat[0]->x;
curX2 = feat[3]->x;
curY1 = feat[0]->y;
curY2 = feat[3]->y;
curX1 = features[0].x;
curX2 = features[3].x;
curY1 = features[0].y;
curY2 = features[3].y;
// Make sure p1 < p2
if (curX1 > curX2) IntSwap(curX1,curX2);

View File

@ -75,9 +75,6 @@ private:
/// DOCME
bool inverse;
ClipCorner* feat[4];
/// @brief DOCME
/// @return
///

View File

@ -79,9 +79,7 @@ void VisualToolCross::Update() {
SetOverride(line, L"\\pos", wxString::Format(L"(%i,%i)", x1 - dx, y1 - dy));
}
grid->ass->FlagAsModified(_("positioning"));
grid->CommitChanges(false,true);
grid->editBox->Update(false, true, false);
Commit(false, _("positioning"));
}
/// @brief Draw

View File

@ -122,14 +122,38 @@ void VisualToolDrag::DoRefresh() {
UpdateToggleButtons();
}
void VisualToolDrag::OnSelectionChange(bool clear, int row, bool selected) {
if (!externalChange) return;
externalChange = false;
if (clear) {
ClearSelection(false);
}
if (selected) {
for (size_t i = 0; i < features.size(); i++) {
if (features[i].lineN == row && features[i].type == DRAG_START) {
AddSelection(i);
break;
}
}
}
else {
for (size_t i = 0; i < features.size(); i++) {
if (features[i].lineN == row) {
RemoveSelection(i);
}
}
}
externalChange = true;
}
void VisualToolDrag::Draw() {
DrawAllFeatures();
// Draw arrows
for (std::list<VisualToolDragDraggableFeature>::iterator cur = features.begin(); cur != features.end(); ++cur) {
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
if (cur->type == DRAG_START) continue;
VisualDraggableFeature *p2 = &*cur;
VisualDraggableFeature *p1 = cur->parent;
VisualDraggableFeature *p1 = &features[cur->parent];
// Has arrow?
bool hasArrow = p2->type == DRAG_END;
@ -172,77 +196,74 @@ void VisualToolDrag::Draw() {
}
}
/// @brief Populate list
void VisualToolDrag::PopulateFeatureList() {
ClearSelection();
primary = NULL;
ClearSelection(false);
primary = -1;
GenerateFeatures();
}
void VisualToolDrag::GenerateFeatures() {
features.clear();
// Get video data
VideoContext* con = VideoContext::Get();
int numRows = con->grid->GetRows();
int framen = con->GetFrameN();
wxArrayInt sel = GetSelection();
BaseGrid* grid = VideoContext::Get()->grid;
int numRows = grid->GetRows();
// For each line
AssDialogue *diag;
for (int i=numRows;--i>=0;) {
diag = VideoContext::Get()->grid->GetDialogue(i);
if (diag) {
// Line visible?
int f1 = VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true);
int f2 = VFR_Output.GetFrameAtTime(diag->End.GetMS(),false);
if (f1 <= framen && f2 >= framen) {
// 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);
AssDialogue *diag = grid->GetDialogue(i);
if (!diag || !BaseGrid::IsDisplayed(diag)) continue;
// 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.lineN = i;
features.push_back(feat);
feat.parent = &features.back();
// 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);
// Create move destination feature
if (hasMove) {
feat.x = x2;
feat.y = y2;
feat.layer = 1;
feat.type = DRAG_END;
feat.time = t2;
feat.line = diag;
feat.lineN = i;
features.push_back(feat);
feat.parent->parent = &features.back();
}
// 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);
}
}
// 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.lineN = i;
features.push_back(feat);
feat.parent = features.size() - 1;
if (grid->IsInSelection(i)) {
AddSelection(features.size() - 1);
}
// Create move destination feature
if (hasMove) {
feat.x = x2;
feat.y = y2;
feat.layer = 1;
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) {
primary = feature;
primary = feature - &features[0];
return true;
}
@ -265,7 +286,7 @@ void VisualToolDrag::CommitDrag(VisualToolDragDraggableFeature* feature) {
return;
}
VisualToolDragDraggableFeature *p = feature->parent;
VisualToolDragDraggableFeature *p = feature->parent > -1 ? &features[feature->parent] : NULL;
if (feature->type == DRAG_END) {
std::swap(feature, p);
}
@ -295,9 +316,9 @@ void VisualToolDrag::Update() {
int vx = video.x;
int vy = video.y;
parent->ToScriptCoords(&vx, &vy);
if (primary) {
dx = primary->x;
dy = primary->y;
if (primary > -1) {
dx = features[primary].x;
dy = features[primary].y;
}
else {
AssDialogue* line = GetActiveDialogueLine();
@ -336,10 +357,7 @@ void VisualToolDrag::Update() {
}
}
grid->ass->FlagAsModified(_("positioning"));
grid->CommitChanges(false,true);
grid->editBox->Update(false, true, false);
Commit(false, _("positioning"));
/// @todo: should just move the existing features rather than remaking them all
PopulateFeatureList();
GenerateFeatures();
}

View File

@ -47,11 +47,11 @@
class VisualToolDragDraggableFeature : public VisualDraggableFeature {
public:
int time;
VisualToolDragDraggableFeature* parent;
int parent;
VisualToolDragDraggableFeature()
: VisualDraggableFeature()
, time(0)
, parent(NULL)
, parent(-1)
{ }
};
@ -64,12 +64,15 @@ public:
class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
private:
wxToolBar *toolBar; /// The subtoolbar
VisualToolDragDraggableFeature* primary; /// The feature last clicked on
int primary; /// The feature last clicked on
/// 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
bool toggleMoveOnMove;
/// Regenerage features without touching the selection
void GenerateFeatures();
void PopulateFeatureList();
bool InitializeDrag(VisualToolDragDraggableFeature* feature);
void UpdateDrag(VisualToolDragDraggableFeature* feature);
@ -82,6 +85,8 @@ private:
public:
VisualToolDrag(VideoDisplay *parent, VideoState const& video, wxToolBar *toolbar);
void OnSelectionChange(bool clear, int row, bool selected);
void Draw();
void Update();
void OnSubTool(wxCommandEvent &event);

View File

@ -206,14 +206,16 @@ void VisualToolVectorClip::Draw() {
/// @brief Populate feature list
void VisualToolVectorClip::PopulateFeatureList() {
// Clear
ClearSelection();
ClearSelection(false);
features.clear();
// This is perhaps a bit conservative as there can be up to 3N+1 features
features.reserve(spline.curves.size());
VisualToolVectorClipDraggableFeature feat;
// Go through each curve
bool isFirst = true;
int i = 0;
int j = 0;
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++,i++) {
// First point
if (isFirst) {
@ -224,9 +226,9 @@ void VisualToolVectorClip::PopulateFeatureList() {
feat.index = i;
feat.point = 0;
features.push_back(feat);
AddSelection(j++);
}
// Line
if (cur->type == CURVE_LINE) {
feat.x = (int)cur->p2.x;
feat.y = (int)cur->p2.y;
@ -234,13 +236,10 @@ void VisualToolVectorClip::PopulateFeatureList() {
feat.index = i;
feat.point = 1;
features.push_back(feat);
AddSelection(j++);
}
// Bicubic
if (cur->type == CURVE_BICUBIC) {
// Current size
int size = features.size();
else if (cur->type == CURVE_BICUBIC) {
// Control points
feat.x = (int)cur->p2.x;
feat.y = (int)cur->p2.y;
@ -259,6 +258,10 @@ void VisualToolVectorClip::PopulateFeatureList() {
feat.type = DRAG_SMALL_CIRCLE;
feat.point = 3;
features.push_back(feat);
AddSelection(j++);
AddSelection(j++);
AddSelection(j++);
}
}
}
@ -294,6 +297,7 @@ bool VisualToolVectorClip::InitializeDrag(VisualToolVectorClipDraggableFeature*
// Erase and save changes
spline.curves.erase(cur);
CommitDrag(feature);
PopulateFeatureList();
curFeature = NULL;
Commit(true);
return false;
@ -390,7 +394,7 @@ bool VisualToolVectorClip::InitializeHold() {
// Freehand
if (mode == 6 || mode == 7) {
ClearSelection();
ClearSelection(false);
features.clear();
spline.curves.clear();
lastX = INT_MIN;
@ -456,11 +460,13 @@ void VisualToolVectorClip::CommitHold() {
// Save it
if (mode != 3 && mode != 4) {
SetOverride(GetActiveDialogueLine(), inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")");
SetOverride(curDiag, inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")");
}
// End freedraw
if (!holding && (mode == 6 || mode == 7)) SetMode(0);
PopulateFeatureList();
}
/// @brief Refresh