first vaguely working version using PresentationInfo
[ardour.git] / libs / ardour / ardour / presentation_info.h
1 /*
2     Copyright (C) 2016 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __libardour_presentation_info_h__
21 #define __libardour_presentation_info_h__
22
23 #include <iostream>
24 #include <string>
25
26 #include <stdint.h>
27
28 #include "ardour/libardour_visibility.h"
29
30 class XMLNode;
31
32 namespace ARDOUR {
33
34 class LIBARDOUR_API PresentationInfo
35 {
36   public:
37
38         /* a PresentationInfo object exists to share information between
39          * different user interfaces (e.g. GUI and a Mackie Control surface)
40          * about:
41          *
42          *     - ordering
43          *     - selection status
44          *     - visibility
45          *     - object identity
46          *
47          * ORDERING
48          *
49          * One UI takes control of ordering by setting the "order" value for
50          * the PresentationInfo component of every Stripable object. In Ardour,
51          * this is done by the GUI (mostly because it is very hard for the user
52          * to re-order things on a control surface).
53          *
54          * Ordering is a complex beast, however. Different user interfaces may
55          * display things in different ways. For example, the GUI of Ardour
56          * allows the user to mix busses in between tracks. A control surface
57          * may do the same, but may also allow the user to press a button that
58          * makes it show only busses, or only MIDI tracks. At that point, the
59          * ordering on the surface differs from the ordering in the GUI.
60          *
61          * The ordering is given via a combination of an object type and a
62          * simple numeric position within that type. The object types at this
63          * time are:
64          *
65          *     Route
66          *        - object has inputs and outputs; processes data
67          *     Output
68          *        - Route used to connect to outside the application (MasterOut, MonitorOut)
69          *     Special
70          *        - special type of Route (e.g. Auditioner)
71          *     VCA
72          *        - no data flows through; control only
73          *
74          * Objects with a numeric order of zero are considered unsorted. This
75          * applies (for now) to special objects such as the master out,
76          * auditioner and monitor out.  The rationale here is that the GUI
77          * presents these objects in special ways, rather than as part of some
78          * (potentially) re-orderable container. The same is true for hardware
79          * surfaces, where the master fader (for instance) is typically
80          * separate and distinct from anything else.
81          *
82          * There are several pathways for the order being set:
83          *
84          *   - object created during session loading from XML
85          *           - numeric order will be set during ::set_state(), based on
86          *           - type will be set during ctor call
87          *
88          *   - object created in response to user request
89          *              - numeric order will be set by Session, before adding
90          *                   to container.
91          *              - type set during ctor call
92          *
93          *
94          * OBJECT IDENTITY
95          *
96          * Control surfaces/protocols often need to be able to get a handle on
97          * an object identified only abstractly, such as the "5th audio track"
98          * or "the master out". A PresentationInfo object uniquely identifies
99          * all objects in this way through the combination of its _order member
100          * and part of its _flags member. The _flags member identifies the type
101          * of object, as well as selection/hidden status. The type may never
102          * change after construction (not strictly the constructor itself, but
103          * a more generalized notion of construction, as in "ready to use").
104          *
105          * SELECTION
106          *
107          * When an object is selected, its _flags member will have the Selected
108          * bit set.
109          *
110          * VISIBILITY
111          *
112          * When an object is hidden, its _flags member will have the Hidden
113          * bit set.
114          *
115          *
116          */
117
118
119         enum Flag {
120                 /* Type information */
121                 AudioTrack = 0x1,
122                 MidiTrack = 0x2,
123                 AudioBus = 0x4,
124                 MidiBus = 0x8,
125                 VCA = 0x10,
126
127                 /* These need to be at the high end */
128                 MasterOut = 0x800,
129                 MonitorOut = 0x1000,
130                 Auditioner = 0x2000,
131
132                 /* These are for sharing Stripable states between the GUI and other
133                  * user interfaces/control surfaces
134                  */
135                 Selected = 0x4000,
136                 Hidden = 0x8000,
137
138                 /* single bit indicates that the group order is set */
139                 GroupOrderSet = 0x100000000,
140
141                 /* Masks */
142
143                 GroupMask = (AudioTrack|MidiTrack|AudioBus|MidiBus|VCA),
144                 SpecialMask = (MasterOut|MonitorOut|Auditioner),
145                 StatusMask = (Selected|Hidden),
146         };
147
148         static const Flag Route;
149         static const Flag Track;
150         static const Flag Bus;
151
152         typedef uint32_t order_t;
153         typedef uint64_t global_order_t;
154
155         PresentationInfo (Flag f) : _order (0), _flags (Flag (f & ~GroupOrderSet)) { /* GroupOrderSet is not set */ }
156         PresentationInfo (order_t o, Flag f) : _order (o), _flags (Flag (f | GroupOrderSet)) { /* GroupOrderSet is set */ }
157
158         static const order_t max_order;
159
160         order_t  group_order() const { return _order; }
161         global_order_t global_order () const {
162                 if (_flags & Route) {
163
164                         /* set all bits related to Route so that all Routes
165                            sort together, with order() in the range of
166                            64424509440..68719476735
167
168                            Consider the following arrangement:
169
170                            Track   1
171                            Bus     1
172                            Track   2
173                            ---------
174                            VCA     1
175                            ---------
176                            Master
177                            ---------
178                            Monitor
179
180                            these translate into the following
181
182                            _order  |  _flags            | order()
183                            --------------------------------------
184                            1       |   0x1   AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|1 = 64424509441
185                            2       |   0x2   AudioBus   | ((0x1|0x2|0x4|0x8)<<32)|2 = 64424509442
186                            3       |   0x1   AudioTrack | ((0x1|0x2|0x4|0x8)<<32)|3 = 64424509443
187
188                            1       |   0x10  VCA        | ((0x10)<<32)|1 = 68719476737
189
190                            0       |   0x800 Master     | (0x800<<32) = 8796093022208
191
192                            0       |   0x1000 Monitor   | (0x1000<<32) = 17592186044416
193
194                         */
195
196                         return (((global_order_t) (_flags | Route)) << sizeof(order_t)) | _order;
197                 } else {
198                         return (((global_order_t) _flags) << sizeof(order_t)) | _order;
199                 }
200         }
201
202         PresentationInfo::Flag flags() const { return _flags; }
203
204         bool order_set() const { return _order != 0; }
205
206         /* these objects have no defined order */
207         bool special () const { return _flags & SpecialMask; }
208
209         /* detect group order set/not set */
210         bool unordered() const { return !(_flags & GroupOrderSet); }
211         bool ordered() const { return _flags & GroupOrderSet; }
212
213         void set_flag (PresentationInfo::Flag f) {
214                 _flags = PresentationInfo::Flag (_flags | f);
215         }
216
217         void unset_flag (PresentationInfo::Flag f) {
218                 _flags = PresentationInfo::Flag (_flags & ~f);
219         }
220
221         void set_flags (Flag f) {
222                 _flags = f;
223         }
224
225         bool flag_match (Flag f) const {
226                 /* no flags, match all */
227
228                 if (f == Flag (0)) {
229                         return true;
230                 }
231
232                 if (f & StatusMask) {
233                         /* status bits set, must match them */
234                         if ((_flags & StatusMask) != (f & StatusMask)) {
235                                 return false;
236                         }
237                 }
238
239                 /* Generic flags in f, match the right stuff */
240
241                 if (f == Bus && (_flags & Bus)) {
242                         /* some kind of bus */
243                         return true;
244                 }
245                 if (f == Track && (_flags & Track)) {
246                         /* some kind of track */
247                         return true;
248                 }
249                 if (f == Route && (_flags & Route)) {
250                         /* any kind of route */
251                         return true;
252                 }
253
254                 return f == _flags;
255         }
256
257         std::string to_string () const;
258
259         uint64_t to_integer () const {
260                 return ((uint64_t) _flags << sizeof(order_t)) | _order;
261         }
262
263         bool operator< (PresentationInfo const& other) const {
264                 return global_order() < other.global_order();
265         }
266
267         PresentationInfo& operator= (std::string const& str) {
268                 parse (str);
269                 return *this;
270         }
271
272         bool match (PresentationInfo const& other) const {
273                 return (_order == other.group_order()) && flag_match (other.flags());
274         }
275
276         bool operator==(PresentationInfo const& other) {
277                 return (_order == other.group_order()) && (_flags == other.flags());
278         }
279
280         bool operator!=(PresentationInfo const& other) {
281                 return (_order != other.group_order()) || (_flags != other.flags());
282         }
283
284         static Flag get_flags (XMLNode const& node);
285
286   protected:
287         friend class Stripable;
288         void set_group_order (order_t order) { _order = order; _flags = Flag (_flags|GroupOrderSet); }
289
290   private:
291         order_t _order;
292         Flag    _flags;
293
294         PresentationInfo (std::string const & str);
295         int parse (std::string const&);
296         int parse (order_t, Flag f);
297 };
298
299 }
300
301 std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid);
302
303 #endif /* __libardour_presentation_info_h__ */