Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
track_collection.h
1// SPDX-FileCopyrightText: © 2025-2026 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <concepts>
7
8#include "structure/tracks/track_span.h"
9
10#include <QtQmlIntegration/qqmlintegration.h>
11
12namespace zrythm::structure::tracks
13{
14
22class TrackCollection : public QAbstractListModel
23{
24 Q_OBJECT
25 Q_PROPERTY (
26 int numSoloedTracks READ numSoloedTracks NOTIFY numSoloedTracksChanged)
27 Q_PROPERTY (
28 int numMutedTracks READ numMutedTracks NOTIFY numMutedTracksChanged)
29 Q_PROPERTY (
30 int numListenedTracks READ numListenedTracks NOTIFY numListenedTracksChanged)
31 QML_ELEMENT
32 QML_UNCREATABLE ("")
33
34public:
35 enum TrackRoles
36 {
37 TrackPtrRole = Qt::UserRole + 1,
38
39 // Whether a track is foldable
40 TrackFoldableRole,
41
42 // Whether a foldable track is expanded
43 TrackExpandedRole,
44
45 // A foldable track's depth
46 TrackDepthRole,
47
48 TrackNameRole,
49 };
50 Q_ENUM (TrackRoles)
51
52 TrackCollection (
53 TrackRegistry &track_registry,
54 QObject * parent = nullptr) noexcept;
55 ~TrackCollection () noexcept override;
56 Q_DISABLE_COPY_MOVE (TrackCollection)
57
58 // ========================================================================
59 // QML Interface
60 // ========================================================================
61
62 QHash<int, QByteArray> roleNames () const override;
63 int rowCount (const QModelIndex &parent = QModelIndex ()) const override;
64 QVariant
65 data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
66
67 Q_INVOKABLE void setTrackExpanded (const Track * track, bool expanded);
68
69 int numSoloedTracks () const;
70 Q_SIGNAL void numSoloedTracksChanged ();
71 int numMutedTracks () const;
72 Q_SIGNAL void numMutedTracksChanged ();
73 int numListenedTracks () const;
74 Q_SIGNAL void numListenedTracksChanged ();
75
82 Q_SIGNAL void tracksMoved (const QList<int> &rows);
83
84 Q_SIGNAL void trackRecordingArmedChanged (Track * track, bool armed);
85
86 // ========================================================================
87 // Track Management
88 // ========================================================================
89
93 TrackPtrVariant get_track_at_index (size_t index) const;
94
98 TrackUuidReference get_track_ref_at_index (size_t index) const;
99
100 /**
101 * @brief Get the index of the track with the given UUID.
102 */
103 auto get_track_index (const Track::Uuid &track_id) const
104 {
105 return std::distance (
106 tracks_.begin (),
107 std::ranges::find (tracks_, track_id, &TrackUuidReference::id));
108 }
109
110 TrackUuidReference track_ref_at_id (const Track::Uuid &track_id) const
111 {
112 return tracks ().at (get_track_index (track_id));
113 }
114
118 auto track_count () const { return tracks_.size (); }
119
123 bool contains (const Track::Uuid &track_id) const;
124
128 void add_track (const TrackUuidReference &track_id);
129
133 void insert_track (const TrackUuidReference &track_id, int pos);
134
138 void remove_track (const Track::Uuid &track_id);
139
148 void detach_track (const Track::Uuid &track_id);
149
157 void reattach_track (const TrackUuidReference &track_id, int pos);
158
167 template <typename Container>
168 requires requires (const Container &c, const Track::Uuid &uuid) {
169 { c.contains (uuid) } -> std::convertible_to<bool>;
170 }
171 void notify_tracks_moved (const Container &uuids)
172 {
173 QList<int> rows;
174 for (const auto &ref : tracks_)
175 {
176 if (uuids.contains (ref.id ()))
177 {
178 rows.push_back (static_cast<int> (get_track_index (ref.id ())));
179 }
180 }
181 if (!rows.isEmpty ())
182 {
183 Q_EMIT tracksMoved (rows);
184 }
185 }
186
190 void move_track (const Track::Uuid &track_id, int pos);
191
195 auto get_track_span () const { return TrackSpan{ tracks_ }; }
196
200 const std::vector<TrackUuidReference> &tracks () const { return tracks_; }
201
205 TrackRegistry &get_track_registry () const { return track_registry_; }
206
210 void set_track_expanded (const Track::Uuid &track_id, bool expanded);
211
215 bool get_track_expanded (const Track::Uuid &track_id) const;
216
224 void set_folder_parent (
225 const Track::Uuid &child_id,
226 const Track::Uuid &parent_id,
227 bool auto_reposition = false);
228
232 std::optional<Track::Uuid>
233 get_folder_parent (const Track::Uuid &child_id) const;
234
243 const Track::Uuid &child_id,
244 bool auto_reposition = false);
245
249 bool is_track_foldable (const Track::Uuid &track_id) const;
250
257 bool is_ancestor_of (
258 const Track::Uuid &possible_ancestor,
259 const Track::Uuid &track_id) const;
260
268 std::optional<Track::Uuid> get_enclosing_folder (size_t index) const;
269
273 size_t get_child_count (const Track::Uuid &parent_id) const;
274
282 std::vector<Track::Uuid>
283 get_all_descendants (const Track::Uuid &parent_id) const;
284
288 size_t get_last_child_index (const Track::Uuid &parent_id) const;
289
290private:
291 // ========================================================================
292 // Serialization
293 // ========================================================================
294
295 static constexpr auto kTracksKey = "tracks"sv;
296 static constexpr auto kExpandedTracksKey = "expandedTracks"sv;
297 static constexpr auto kFolderParentsKey = "folderParents"sv;
298 friend void to_json (nlohmann::json &j, const TrackCollection &collection);
299 friend void from_json (const nlohmann::json &j, TrackCollection &collection);
300
301private:
302 TrackRegistry &track_registry_;
303 std::vector<TrackUuidReference> tracks_;
304
310 std::unordered_set<Track::Uuid> expanded_tracks_;
311
317 std::unordered_map<Track::Uuid, Track::Uuid> folder_parent_;
318
319 std::unordered_map<Track::Uuid, QMetaObject::Connection>
320 recording_param_connections_;
321};
322
323} // namespace zrythm::structure::tracks
Q_SIGNAL void tracksMoved(const QList< int > &rows)
Emitted after tracks are moved within the collection.
auto get_track_index(const Track::Uuid &track_id) const
Get the index of the track with the given UUID.
auto track_count() const
Get the number of tracks in the collection.
void detach_track(const Track::Uuid &track_id)
Remove a track from the collection without clearing its folder metadata (expanded state and folder pa...
TrackRegistry & get_track_registry() const
Get the track registry.
void move_track(const Track::Uuid &track_id, int pos)
Move a track from one position to another.
void set_folder_parent(const Track::Uuid &child_id, const Track::Uuid &parent_id, bool auto_reposition=false)
Set the folder parent for a track.
void add_track(const TrackUuidReference &track_id)
Add a track to the collection.
bool get_track_expanded(const Track::Uuid &track_id) const
Get the expanded state of a foldable track.
auto get_track_span() const
Get a span view of all tracks.
std::optional< Track::Uuid > get_enclosing_folder(size_t index) const
Get the innermost enclosing folder at the given track index.
std::optional< Track::Uuid > get_folder_parent(const Track::Uuid &child_id) const
Get the folder parent for a track.
size_t get_last_child_index(const Track::Uuid &parent_id) const
Get the last child index for a foldable track.
TrackUuidReference get_track_ref_at_index(size_t index) const
Get the track reference at the given index.
bool is_track_foldable(const Track::Uuid &track_id) const
Check if a track is foldable.
bool contains(const Track::Uuid &track_id) const
Check if the collection contains a track with the given UUID.
size_t get_child_count(const Track::Uuid &parent_id) const
Get the number of children for a foldable track.
void set_track_expanded(const Track::Uuid &track_id, bool expanded)
Set the expanded state of a foldable track.
void notify_tracks_moved(const Container &uuids)
Notify that the given tracks have been moved.
void insert_track(const TrackUuidReference &track_id, int pos)
Insert a track at the given position.
void reattach_track(const TrackUuidReference &track_id, int pos)
Insert a track without initializing or modifying folder metadata.
bool is_ancestor_of(const Track::Uuid &possible_ancestor, const Track::Uuid &track_id) const
Check if possible_ancestor is an ancestor of track_id.
std::vector< Track::Uuid > get_all_descendants(const Track::Uuid &parent_id) const
Get all descendant track UUIDs of a folder, in list order.
void remove_track(const Track::Uuid &track_id)
Remove a track from the collection.
void remove_folder_parent(const Track::Uuid &child_id, bool auto_reposition=false)
Remove the folder parent for a track.
TrackPtrVariant get_track_at_index(size_t index) const
Get the track at the given index.
const std::vector< TrackUuidReference > & tracks() const
Get the underlying tracks vector.
Track span that offers helper methods on a range of tracks.
Definition track_span.h:14
Represents a track in the project.
Definition track.h:61