Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
selection.hpp
Go to the documentation of this file.
1#pragma once
2
5
7
8#include <algorithm>
9#include <optional>
10#include <span>
11#include <vector>
12
13namespace pulp::timeline_editor {
14
18
20class Selection {
21 public:
23 std::span<const timeline::ItemId> items() const noexcept {
24 return items_;
25 }
26
27 std::optional<timeline::ItemId> anchor() const noexcept {
28 return anchor_;
29 }
30
31 bool contains(timeline::ItemId item) const noexcept {
32 return std::binary_search(items_.begin(), items_.end(), item);
33 }
34
35 bool empty() const noexcept {
36 return items_.empty();
37 }
38
40 void clear() noexcept {
41 items_.clear();
42 anchor_.reset();
43 }
44
46 void replace(std::span<const timeline::ItemId> items) {
47 anchor_.reset();
48 items_.clear();
49 items_.reserve(items.size());
50 for (const auto item : items) {
51 if (!item.valid())
52 continue;
53 if (!anchor_)
54 anchor_ = item;
55 items_.push_back(item);
56 }
57 canonicalize();
58 }
59
61 void add(timeline::ItemId item) {
62 if (!item.valid() || contains(item))
63 return;
64 items_.insert(std::lower_bound(items_.begin(), items_.end(), item), item);
65 if (!anchor_)
66 anchor_ = item;
67 }
68
71 if (!item.valid())
72 return;
73 const auto found = std::lower_bound(items_.begin(), items_.end(), item);
74 if (found == items_.end() || *found != item) {
75 items_.insert(found, item);
76 if (!anchor_)
77 anchor_ = item;
78 return;
79 }
80 items_.erase(found);
81 if (anchor_ == item)
82 anchor_ =
83 items_.empty() ? std::nullopt : std::optional<timeline::ItemId>{items_.front()};
84 }
85
91 std::span<const timeline::ItemId> ordered_items) {
92 if (!item.valid())
93 return false;
94 const auto target = std::find(ordered_items.begin(), ordered_items.end(), item);
95 if (target == ordered_items.end())
96 return false;
97 if (!anchor_) {
98 replace(std::span<const timeline::ItemId>(&*target, 1));
99 return true;
100 }
101 const auto start = std::find(ordered_items.begin(), ordered_items.end(), *anchor_);
102 if (start == ordered_items.end())
103 return false;
104
105 const auto first = std::min(start, target);
106 const auto last = std::max(start, target);
107 items_.assign(first, last + 1);
108 canonicalize();
109 return true;
110 }
111
113 void prune(const timeline::Project& project) {
114 const auto dead = [&](timeline::ItemId item) {
115 const auto location = project.locate(item);
116 return !location || !location->active;
117 };
118 items_.erase(std::remove_if(items_.begin(), items_.end(), dead), items_.end());
119 if (anchor_ && dead(*anchor_))
120 anchor_.reset();
121 }
122
123 private:
124 void canonicalize() {
125 items_.erase(std::remove_if(items_.begin(), items_.end(),
126 [](timeline::ItemId item) { return !item.valid(); }),
127 items_.end());
128 std::sort(items_.begin(), items_.end());
129 items_.erase(std::unique(items_.begin(), items_.end()), items_.end());
130 }
131
132 std::vector<timeline::ItemId> items_;
133 std::optional<timeline::ItemId> anchor_;
134};
135
137
138} // namespace pulp::timeline_editor
Immutable root of a Timeline document and its monotonic identity domain.
Definition model.hpp:1079
std::optional< ItemLocation > locate(ItemId id) const noexcept
Returns canonical location data for active or inactive id, if known.
Identity-only editor state that never enters the document or its undo history.
Definition selection.hpp:20
bool extend_from_anchor(timeline::ItemId item, std::span< const timeline::ItemId > ordered_items)
Replaces the selection with the inclusive ordered range from the anchor to item.
Definition selection.hpp:90
std::span< const timeline::ItemId > items() const noexcept
Returns selected identities in ascending order without duplicates.
Definition selection.hpp:23
void prune(const timeline::Project &project)
Removes identities missing from project or retained only as inactive tombstones.
Definition selection.hpp:113
bool contains(timeline::ItemId item) const noexcept
Returns whether item is selected.
Definition selection.hpp:31
void replace(std::span< const timeline::ItemId > items)
Replaces the selection, retaining the first valid input as the range anchor.
Definition selection.hpp:46
void toggle(timeline::ItemId item)
Adds an absent identity or removes a selected one.
Definition selection.hpp:70
void add(timeline::ItemId item)
Adds one identity while preserving an existing range anchor.
Definition selection.hpp:61
std::optional< timeline::ItemId > anchor() const noexcept
Returns the identity from which range extension begins, when one exists.
Definition selection.hpp:27
bool empty() const noexcept
Returns whether no identities are selected.
Definition selection.hpp:35
void clear() noexcept
Clears the selected identities and range anchor.
Definition selection.hpp:40
ScriptedUiHost is a SequencerUiHost whose playhead is written by the caller instead of an engine,...
Definition edit_intent.hpp:14
Nonzero monotonic identity for a Timeline-owned object.
Definition item_id.hpp:19
constexpr bool valid() const noexcept
Returns whether this value names an object rather than a sentinel.
Definition item_id.hpp:23