1 /*
2  * Copyright (C) 2016-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2016-2019 Robin Gareus <robin@gareus.org>
4  * Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #ifndef __libardour_presentation_info_h__
22 #define __libardour_presentation_info_h__
23 
24 #include <iostream>
25 #include <string>
26 
27 #include <stdint.h>
28 
29 #include "pbd/signals.h"
30 #include "pbd/stateful.h"
31 #include "pbd/properties.h"
32 #include "pbd/g_atomic_compat.h"
33 
34 #include "ardour/libardour_visibility.h"
35 
36 class XMLNode;
37 
38 namespace ARDOUR {
39 
40 namespace Properties {
41 	LIBARDOUR_API extern PBD::PropertyDescriptor<uint32_t> order;
42 	LIBARDOUR_API extern PBD::PropertyDescriptor<uint32_t> color;
43 	LIBARDOUR_API extern PBD::PropertyDescriptor<bool> selected;
44 	/* we use this; declared in region.cc */
45 	LIBARDOUR_API extern PBD::PropertyDescriptor<bool> hidden;
46 }
47 
48 class LIBARDOUR_API PresentationInfo : public PBD::Stateful
49 {
50   public:
51 
52 	/* a PresentationInfo object exists to share information between
53 	 * different user interfaces (e.g. GUI and a Mackie Control surface)
54 	 * about:
55 	 *
56 	 *     - ordering
57 	 *     - selection status
58 	 *     - visibility
59 	 *     - object identity
60 	 *
61 	 * ORDERING
62 	 *
63 	 * One UI takes control of ordering by setting the "order" value for
64 	 * the PresentationInfo component of every Stripable object. In Ardour,
65 	 * this is done by the GUI (mostly because it is very hard for the user
66 	 * to re-order things on a control surface).
67 	 *
68 	 * Ordering is a complex beast, however. Different user interfaces may
69 	 * display things in different ways. For example, the GUI of Ardour
70 	 * allows the user to mix busses in between tracks. A control surface
71 	 * may do the same, but may also allow the user to press a button that
72 	 * makes it show only busses, or only MIDI tracks. At that point, the
73 	 * ordering on the surface differs from the ordering in the GUI.
74 	 *
75 	 * There are several pathways for the order being set:
76 	 *
77 	 *   - object created during session loading from XML
78 	 *   - numeric order will be set during ::set_state(), based on
79 	 *   - type will be set during ctor call
80 	 *
81 	 *   - object created in response to user request
82 	 *   - numeric order will be set by Session, before adding to container.
83 	 *   - type set during ctor call
84 	 *
85 	 *
86 	 * OBJECT IDENTITY
87 	 *
88 	 * Control surfaces/protocols often need to be able to get a handle on
89 	 * an object identified only abstractly, such as the "5th audio track"
90 	 * or "the master out". A PresentationInfo object uniquely identifies
91 	 * all objects in this way through the combination of its _order member
92 	 * and part of its _flags member. The _flags member identifies the type
93 	 * of object, as well as selection/hidden status. The type may never
94 	 * change after construction (not strictly the constructor itself, but
95 	 * a more generalized notion of construction, as in "ready to use").
96 	 *
97 	 * VISIBILITY
98 	 *
99 	 * When an object is hidden, its _flags member will have the Hidden
100 	 * bit set.
101 	 *
102 	 *
103 	 */
104 
105 	enum Flag {
106 		/* Type information */
107 		AudioTrack = 0x1,
108 		MidiTrack = 0x2,
109 		AudioBus = 0x4,
110 		MidiBus = 0x8,
111 		VCA = 0x10,
112 		MasterOut = 0x20,
113 		MonitorOut = 0x40,
114 		Auditioner = 0x80,
115 #ifdef MIXBUS
116 		Mixbus = 0x1000,
117 #endif
118 		/* These are for sharing Stripable states between the GUI and other
119 		 * user interfaces/control surfaces
120 		 */
121 		Hidden = 0x100,
122 #ifdef MIXBUS
123 		MixbusEditorHidden = 0x800,
124 #endif
125 		/* single bit indicates that the group order is set */
126 		OrderSet = 0x400,
127 
128 		/* bus type for monitor mixes */
129 		FoldbackBus = 0x2000,
130 
131 		/* special mask to delect out "state" bits */
132 		StatusMask = (Hidden),
133 		/* special mask to delect select type bits */
134 		TypeMask = (AudioBus|AudioTrack|MidiTrack|MidiBus|VCA|MasterOut|MonitorOut|Auditioner|FoldbackBus)
135 	};
136 
137 	static const Flag AllStripables; /* mask to use for any route or VCA (but not auditioner) */
138 	static const Flag MixerStripables; /* mask to use for any route or VCA (but not auditioner or foldbackbus) */
139 	static const Flag AllRoutes; /* mask to use for any route include master+monitor, but not auditioner */
140 	static const Flag MixerRoutes; /* mask to use for any route include master+monitor, but not auditioner or foldbackbus*/
141 	static const Flag Route;     /* mask for any route (bus or track */
142 	static const Flag Track;     /* mask to use for any track */
143 	static const Flag Bus;       /* mask to use for any bus */
144 
145 	typedef uint32_t order_t;
146 	typedef uint32_t color_t;
147 
148 	PresentationInfo (Flag f);
149 	PresentationInfo (order_t o, Flag f);
150 	PresentationInfo (PresentationInfo const &);
151 
152 	static const order_t max_order;
153 
flags()154 	PresentationInfo::Flag flags() const { return _flags; }
order()155 	order_t  order() const { return _order; }
color()156 	color_t  color() const { return _color; }
157 
158 	bool color_set() const;
159 
160 	void set_color (color_t);
161 	void set_hidden (bool yn);
set_flags(Flag f)162 	void set_flags (Flag f) { _flags = f; }
163 
order_set()164 	bool order_set() const { return _flags & OrderSet; }
165 
selection_cnt()166 	int selection_cnt() const { return _selection_cnt; }
167 
hidden()168 	bool hidden() const { return _flags & Hidden; }
169 	bool special(bool with_master = true) const { return _flags & ((with_master ? MasterOut : 0)|MonitorOut|Auditioner); }
170 
flag_match(Flag f)171 	bool flag_match (Flag f) const {
172 		/* no flags, match all */
173 
174 		if (f == Flag (0)) {
175 			return true;
176 		}
177 
178 		if (f & StatusMask) {
179 			/* status bits set, must match them */
180 			if ((_flags & StatusMask) != (f & StatusMask)) {
181 				return false;
182 			}
183 		}
184 
185 		/* Generic flags in f, match the right stuff */
186 
187 		if (f == Bus && (_flags & Bus)) {
188 			/* some kind of bus */
189 			return true;
190 		}
191 		if (f == Track && (_flags & Track)) {
192 			/* some kind of track */
193 			return true;
194 		}
195 		if (f == Route && (_flags & Route)) {
196 			/* any kind of route, but not master, monitor in
197 			   or auditioner.
198 			 */
199 			return true;
200 		}
201 
202 		if (f == AllRoutes && (_flags & AllRoutes)) {
203 			/* any kind of route, but not auditioner. Ask for that
204 			   specifically.
205 			*/
206 			return true;
207 		}
208 
209 		if (f == AllStripables && (_flags & AllStripables)) {
210 			/* any kind of stripable, but not auditioner. Ask for that
211 			   specifically.
212 			*/
213 			return true;
214 		}
215 
216 		/* check for any matching type bits.
217 		 *
218 		 * Do comparisoon without status mask or order set bits - we
219 		 * already checked that above.
220 		 */
221 
222 		return ((f & TypeMask) & _flags);
223 	}
224 
225 	int set_state (XMLNode const&, int);
226 	XMLNode& get_state ();
227 
228 	bool operator==(PresentationInfo const& other) {
229 		return (_order == other.order()) && (_flags == other.flags());
230 	}
231 
232 	bool operator!=(PresentationInfo const& other) {
233 		return (_order != other.order()) || (_flags != other.flags());
234 	}
235 
236 	PresentationInfo& operator= (PresentationInfo const& other);
237 
238 	static Flag get_flags (XMLNode const& node);
239 	static Flag get_flags2X3X (XMLNode const& node);
240 	static std::string state_node_name;
241 
242 	/* for things concerned about *any* PresentationInfo.
243 	 */
244 
245 	static PBD::Signal1<void,PBD::PropertyChange const &> Change;
246 	static void send_static_change (const PBD::PropertyChange&);
247 
248 	static void make_property_quarks ();
249 
250   protected:
251 	friend class ChangeSuspender;
252 	static void suspend_change_signal ();
253 	static void unsuspend_change_signal ();
254 
255   public:
256 	class ChangeSuspender {
257           public:
ChangeSuspender()258 		ChangeSuspender() {
259 			PresentationInfo::suspend_change_signal ();
260 		}
~ChangeSuspender()261 		~ChangeSuspender() {
262 			PresentationInfo::unsuspend_change_signal ();
263 		}
264 	};
265 
266   protected:
267 	friend class Stripable;
268 	void set_order (order_t order);
269 
270   private:
271 	order_t _order;
272 	Flag    _flags;
273 	color_t _color;
274 	int     _selection_cnt;
275 
276 	static PBD::PropertyChange _pending_static_changes;
277 	static Glib::Threads::Mutex static_signal_lock;
278 	static GATOMIC_QUAL gint   _change_signal_suspended;
279 
280 	static int selection_counter;
281 };
282 
283 }
284 
285 std::ostream& operator<<(std::ostream& o, ARDOUR::PresentationInfo const& rid);
286 
287 #endif /* __libardour_presentation_info_h__ */
288