diff --git a/aegisub/src/base_grid.cpp b/aegisub/src/base_grid.cpp index e8a098265..8eb31f54e 100644 --- a/aegisub/src/base_grid.cpp +++ b/aegisub/src/base_grid.cpp @@ -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); } } diff --git a/aegisub/src/base_grid.h b/aegisub/src/base_grid.h index 7b8598f67..600c22b07 100644 --- a/aegisub/src/base_grid.h +++ b/aegisub/src/base_grid.h @@ -35,7 +35,7 @@ /// - +#pragma once //////////// // Includes @@ -58,6 +58,11 @@ class FrameMain; /// DOCME typedef std::list::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(); diff --git a/aegisub/src/subs_edit_box.cpp b/aegisub/src/subs_edit_box.cpp index edb8786c4..f3cf61216 100644 --- a/aegisub/src/subs_edit_box.cpp +++ b/aegisub/src/subs_edit_box.cpp @@ -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) { diff --git a/aegisub/src/subs_edit_box.h b/aegisub/src/subs_edit_box.h index 96e62a6a5..68b5951b2 100644 --- a/aegisub/src/subs_edit_box.h +++ b/aegisub/src/subs_edit_box.h @@ -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(); diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index 395de508b..837ea6262 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -530,6 +530,7 @@ double VideoDisplay::GetZoom() const { template void VideoDisplay::SetTool() { + tool.reset(); tool.reset(new T(this, video, toolBar)); box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &T::OnSubTool, static_cast(tool.get()), VISUAL_SUB_TOOL_START, VISUAL_SUB_TOOL_END); } diff --git a/aegisub/src/visual_feature.cpp b/aegisub/src/visual_feature.cpp index 61bc0a5ce..08fa62307 100644 --- a/aegisub/src/visual_feature.cpp +++ b/aegisub/src/visual_feature.cpp @@ -45,7 +45,6 @@ VisualDraggableFeature::VisualDraggableFeature() , y(INT_MIN) , origX(INT_MIN) , origY(INT_MIN) -, selected(false) , layer(0) , line(NULL) , lineN(-1) diff --git a/aegisub/src/visual_feature.h b/aegisub/src/visual_feature.h index 9330a3fde..e4ff6c545 100644 --- a/aegisub/src/visual_feature.h +++ b/aegisub/src/visual_feature.h @@ -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 diff --git a/aegisub/src/visual_tool.cpp b/aegisub/src/visual_tool.cpp index 44c15335e..0225406e1 100644 --- a/aegisub/src/visual_tool.cpp +++ b/aegisub/src/visual_tool.cpp @@ -72,12 +72,12 @@ template VisualTool::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::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::VisualTool(VideoDisplay *parent, VideoState const& vide template VisualTool::~VisualTool() { + VideoContext::Get()->grid->RegisterSelectionChange(NULL); } template @@ -125,25 +127,28 @@ void VisualTool::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::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::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::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::OnMouseEvent (wxMouseEvent &event) { } template -void VisualTool::Commit(bool full) { +void VisualTool::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 AssDialogue* VisualTool::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 -FeatureType* VisualTool::GetHighlightedFeature() { +void VisualTool::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 @@ -308,31 +302,96 @@ void VisualTool::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 void VisualTool::Refresh() { frame_n = VideoContext::Get()->GetFrameN(); - if (externalChange) dragListOK = false; - DoRefresh(); + if (externalChange) { + dragListOK = false; + DoRefresh(); + } +} +template +void VisualTool::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 -void VisualTool::ClearSelection() { - for (SelFeatureIter cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) { - (*cur)->selected = false; +void VisualTool::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 +wxArrayInt VisualTool::GetSelection() { + return VideoContext::Get()->grid->GetSelection(); +} + + +template +void VisualTool::ClearSelection(bool hard) { + if (hard) { + VideoContext::Get()->grid->SelectRow(0, false, false); } selFeatures.clear(); + lineSelCount.clear(); +} + +template +void VisualTool::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 diff --git a/aegisub/src/visual_tool.h b/aegisub/src/visual_tool.h index 7924c73fc..41247767b 100644 --- a/aegisub/src/visual_tool.h +++ b/aegisub/src/visual_tool.h @@ -36,14 +36,15 @@ #pragma once #ifndef AGI_PRE -#include -#include +#include +#include #include #include #include #endif +#include "base_grid.h" #include "gl_wrap.h" class VideoDisplay; @@ -74,30 +75,40 @@ public: /// @brief DOCME /// DOCME template -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::iterator SelFeatureIter; - typedef typename std::list::iterator FeatureIter; - typedef typename std::list::const_iterator FeatureCIter; + typedef typename std::set::iterator selection_iterator; - std::list selFeatures; /// Currently selected visual features + std::set selFeatures; /// Currently selected visual features + std::map 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 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 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::iterator feature_iterator; + typedef typename std::vector::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(); }; - diff --git a/aegisub/src/visual_tool_clip.cpp b/aegisub/src/visual_tool_clip.cpp index 708128c21..6d7a77293 100644 --- a/aegisub/src/visual_tool_clip.cpp +++ b/aegisub/src/visual_tool_clip.cpp @@ -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::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); diff --git a/aegisub/src/visual_tool_clip.h b/aegisub/src/visual_tool_clip.h index 83fc19b96..566c72edc 100644 --- a/aegisub/src/visual_tool_clip.h +++ b/aegisub/src/visual_tool_clip.h @@ -75,9 +75,6 @@ private: /// DOCME bool inverse; - ClipCorner* feat[4]; - - /// @brief DOCME /// @return /// diff --git a/aegisub/src/visual_tool_cross.cpp b/aegisub/src/visual_tool_cross.cpp index 020530eff..f2cdea7bd 100644 --- a/aegisub/src/visual_tool_cross.cpp +++ b/aegisub/src/visual_tool_cross.cpp @@ -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 diff --git a/aegisub/src/visual_tool_drag.cpp b/aegisub/src/visual_tool_drag.cpp index 7e6defd63..992ba29cf 100644 --- a/aegisub/src/visual_tool_drag.cpp +++ b/aegisub/src/visual_tool_drag.cpp @@ -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::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(); } diff --git a/aegisub/src/visual_tool_drag.h b/aegisub/src/visual_tool_drag.h index f2abffb94..74ce2fd52 100644 --- a/aegisub/src/visual_tool_drag.h +++ b/aegisub/src/visual_tool_drag.h @@ -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 { 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); diff --git a/aegisub/src/visual_tool_vector_clip.cpp b/aegisub/src/visual_tool_vector_clip.cpp index 5c3eb2544..9d2948a7d 100644 --- a/aegisub/src/visual_tool_vector_clip.cpp +++ b/aegisub/src/visual_tool_vector_clip.cpp @@ -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::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