folding: Simplify fold operation code

This commit is contained in:
arch1t3cht 2023-05-11 23:51:23 +02:00
parent 1bd426f69a
commit 64b92a95ac
4 changed files with 44 additions and 62 deletions

View File

@ -54,13 +54,6 @@ struct ExtradataEntry {
std::string value; std::string value;
}; };
// Both start and end are inclusive
struct LineFold {
int start;
int end;
bool collapsed;
};
struct AssFileCommit { struct AssFileCommit {
wxString const& message; wxString const& message;
int *commit_id; int *commit_id;

View File

@ -79,16 +79,13 @@ void FoldController::AddFold(AssDialogue& start, AssDialogue& end, bool collapse
} }
} }
bool FoldController::DoForAllFolds(bool action(AssDialogue& line)) { void FoldController::DoForAllFolds(std::function<void(AssDialogue&)> action) {
for (AssDialogue& line : context->ass->Events) { for (AssDialogue& line : context->ass->Events) {
if (line.Fold.valid) { if (line.Fold.valid) {
bool result = action(line); action(line);
UpdateLineExtradata(line); UpdateLineExtradata(line);
if (result)
return true;
} }
} }
return false;
} }
void FoldController::FixFoldsPreCommit(int type, const AssDialogue *single_line) { void FoldController::FixFoldsPreCommit(int type, const AssDialogue *single_line) {
@ -98,24 +95,22 @@ void FoldController::FixFoldsPreCommit(int type, const AssDialogue *single_line)
} }
// For each line in lines, applies action() to the opening delimiter of the innermost fold containing this line. // For each line in lines, applies action() to the opening delimiter of the innermost fold containing this line.
// Returns true as soon as any action() call returned true.
// //
// In general, this can leave the folds in an inconsistent state, so unless action() is read-only this should always // In general, this can leave the folds in an inconsistent state, so unless action() is read-only this should always
// be followed by a commit. // be followed by a commit.
bool FoldController::DoForFoldsAt(std::vector<AssDialogue *> const& lines, bool action(AssDialogue& line)) { void FoldController::DoForFoldsAt(std::vector<AssDialogue *> const& lines, std::function<void(AssDialogue&)> action) {
std::map<int, bool> visited;
for (AssDialogue *line : lines) { for (AssDialogue *line : lines) {
if (line->Fold.parent != nullptr && !(line->Fold.valid && !line->Fold.side)) { if (line->Fold.parent != nullptr && !(line->Fold.valid && !line->Fold.side)) {
line = line->Fold.parent; line = line->Fold.parent;
} }
if (!line->Fold.visited) { if (visited.count(line->Row))
bool result = action(*line); continue;
UpdateLineExtradata(*line);
if (result) action(*line);
return true; UpdateLineExtradata(*line);
} visited[line->Row] = true;
line->Fold.visited = true;
} }
return false;
} }
void FoldController::UpdateFoldInfo() { void FoldController::UpdateFoldInfo() {
@ -263,7 +258,6 @@ void FoldController::LinkFolds() {
line->Fold.parent = foldStack.empty() ? nullptr : foldStack.back(); line->Fold.parent = foldStack.empty() ? nullptr : foldStack.back();
line->Fold.nextVisible = nullptr; line->Fold.nextVisible = nullptr;
line->Fold.visible = highestFolded > (int) foldStack.size(); line->Fold.visible = highestFolded > (int) foldStack.size();
line->Fold.visited = false;
line->Fold.visibleRow = visibleRow; line->Fold.visibleRow = visibleRow;
if (line->Fold.visible) { if (line->Fold.visible) {
@ -299,56 +293,68 @@ int FoldController::GetMaxDepth() {
return maxdepth; return maxdepth;
} }
bool FoldController::ActionHasFold(AssDialogue& line) { return line.Fold.valid; }
bool FoldController::ActionClearFold(AssDialogue& line) { line.Fold.extraExists = false; line.Fold.valid = false; return false; }
bool FoldController::ActionOpenFold(AssDialogue& line) { line.Fold.collapsed = false; return false; }
bool FoldController::ActionCloseFold(AssDialogue& line) { line.Fold.collapsed = true; return false; }
bool FoldController::ActionToggleFold(AssDialogue& line) { line.Fold.collapsed = !line.Fold.collapsed; return false; }
void FoldController::ClearAllFolds() { void FoldController::ClearAllFolds() {
FoldController::DoForAllFolds(FoldController::ActionClearFold); DoForAllFolds([&](AssDialogue &line) {
line.Fold.extraExists = false; line.Fold.valid = false;
});
context->ass->Commit(_("clear all folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("clear all folds"), AssFile::COMMIT_FOLD);
} }
void FoldController::OpenAllFolds() { void FoldController::OpenAllFolds() {
FoldController::DoForAllFolds(FoldController::ActionOpenFold); DoForAllFolds([&](AssDialogue &line) {
line.Fold.collapsed = false;
});
context->ass->Commit(_("open all folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("open all folds"), AssFile::COMMIT_FOLD);
} }
void FoldController::CloseAllFolds() { void FoldController::CloseAllFolds() {
FoldController::DoForAllFolds(FoldController::ActionCloseFold); DoForAllFolds([&](AssDialogue &line) {
line.Fold.collapsed = true;
});
context->ass->Commit(_("close all folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("close all folds"), AssFile::COMMIT_FOLD);
} }
bool FoldController::HasFolds() { bool FoldController::HasFolds() {
return FoldController::DoForAllFolds(FoldController::ActionHasFold); bool hasfold = false;
DoForAllFolds([&](AssDialogue &line) {
hasfold = hasfold || line.Fold.valid;
});
return hasfold;
} }
void FoldController::ClearFoldsAt(std::vector<AssDialogue *> const& lines) { void FoldController::ClearFoldsAt(std::vector<AssDialogue *> const& lines) {
FoldController::DoForFoldsAt(lines, FoldController::ActionClearFold); DoForFoldsAt(lines, [&](AssDialogue &line) {
line.Fold.extraExists = false; line.Fold.valid = false;
});
context->ass->Commit(_("clear folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("clear folds"), AssFile::COMMIT_FOLD);
} }
void FoldController::OpenFoldsAt(std::vector<AssDialogue *> const& lines) { void FoldController::OpenFoldsAt(std::vector<AssDialogue *> const& lines) {
FoldController::DoForFoldsAt(lines, FoldController::ActionOpenFold); DoForFoldsAt(lines, [&](AssDialogue &line) {
line.Fold.collapsed = false;
});
context->ass->Commit(_("open folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("open folds"), AssFile::COMMIT_FOLD);
} }
void FoldController::CloseFoldsAt(std::vector<AssDialogue *> const& lines) { void FoldController::CloseFoldsAt(std::vector<AssDialogue *> const& lines) {
FoldController::DoForFoldsAt(lines, FoldController::ActionCloseFold); DoForFoldsAt(lines, [&](AssDialogue &line) {
line.Fold.collapsed = true;
});
context->ass->Commit(_("close folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("close folds"), AssFile::COMMIT_FOLD);
} }
void FoldController::ToggleFoldsAt(std::vector<AssDialogue *> const& lines) { void FoldController::ToggleFoldsAt(std::vector<AssDialogue *> const& lines) {
FoldController::DoForFoldsAt(lines, FoldController::ActionToggleFold); DoForFoldsAt(lines, [&](AssDialogue &line) {
line.Fold.collapsed = !line.Fold.collapsed;
});
context->ass->Commit(_("toggle folds"), AssFile::COMMIT_FOLD); context->ass->Commit(_("toggle folds"), AssFile::COMMIT_FOLD);
} }
bool FoldController::AreFoldsAt(std::vector<AssDialogue *> const& lines) { bool FoldController::AreFoldsAt(std::vector<AssDialogue *> const& lines) {
return FoldController::DoForFoldsAt(lines, FoldController::ActionHasFold); bool hasfold = false;
DoForFoldsAt(lines, [&](AssDialogue &line) {
hasfold = hasfold || line.Fold.valid;
});
return hasfold;
} }

View File

@ -56,9 +56,6 @@ class FoldInfo {
/// False if a fold is started here, true otherwise. /// False if a fold is started here, true otherwise.
bool side = false; bool side = false;
// Used in DoForFoldsAt to ensure each line is visited only once
bool visited = false;
/// Whether the line is currently visible /// Whether the line is currently visible
bool visible = true; bool visible = true;
@ -106,24 +103,12 @@ class FoldController {
void RawAddFold(AssDialogue& start, AssDialogue& end, bool collapsed); void RawAddFold(AssDialogue& start, AssDialogue& end, bool collapsed);
bool DoForFoldsAt(std::vector<AssDialogue *> const& lines, bool action(AssDialogue& line)); void DoForFoldsAt(std::vector<AssDialogue *> const& lines, std::function<void(AssDialogue&)> action);
bool DoForAllFolds(bool action(AssDialogue& line)); void DoForAllFolds(std::function<void(AssDialogue&)> action);
void FixFoldsPreCommit(int type, const AssDialogue *single_line); void FixFoldsPreCommit(int type, const AssDialogue *single_line);
// These are used for the DoForAllFolds action and should not be used as ordinary getters/setters
static bool ActionHasFold(AssDialogue& line);
static bool ActionClearFold(AssDialogue& line);
static bool ActionOpenFold(AssDialogue& line);
static bool ActionCloseFold(AssDialogue& line);
static bool ActionToggleFold(AssDialogue& line);
/// Updates the line's extradata entry from the values in FoldInfo. Used after actions like toggling folds. /// Updates the line's extradata entry from the values in FoldInfo. Used after actions like toggling folds.
void UpdateLineExtradata(AssDialogue& line); void UpdateLineExtradata(AssDialogue& line);

View File

@ -150,9 +150,7 @@ struct GridColumnFolds final : GridColumn {
bool OnMouseEvent(AssDialogue *d, agi::Context *c, wxMouseEvent &event) const override { bool OnMouseEvent(AssDialogue *d, agi::Context *c, wxMouseEvent &event) const override {
if ((event.LeftDown() || event.LeftDClick()) && !event.ShiftDown() && !event.CmdDown() && !event.AltDown()) { if ((event.LeftDown() || event.LeftDClick()) && !event.ShiftDown() && !event.CmdDown() && !event.AltDown()) {
if (d->Fold.hasFold() && !d->Fold.isEnd()) { if (d->Fold.hasFold() && !d->Fold.isEnd()) {
std::vector<AssDialogue *> lines; c->foldController->ToggleFoldsAt({d});
lines.push_back(d);
c->foldController->ToggleFoldsAt(lines);
return true; return true;
} }
} }