1 /*
2  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
4  * Copyright (C) 2005 Nick Mainsbridge <mainsbridge@gmail.com>
5  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
6  * Copyright (C) 2006 Hans Fugal <hans@fugal.net>
7  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8  * Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
9  * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 #ifndef __ardour_automation_line_h__
27 #define __ardour_automation_line_h__
28 
29 #include <vector>
30 #include <list>
31 #include <string>
32 #include <sys/types.h>
33 
34 #include <sigc++/signal.h>
35 
36 #include "evoral/TimeConverter.h"
37 
38 #include "pbd/undo.h"
39 #include "pbd/statefuldestructible.h"
40 #include "pbd/memento_command.h"
41 
42 #include "ardour/automation_list.h"
43 #include "ardour/parameter_descriptor.h"
44 #include "ardour/types.h"
45 
46 #include "canvas/types.h"
47 #include "canvas/container.h"
48 #include "canvas/poly_line.h"
49 
50 class AutomationLine;
51 class ControlPoint;
52 class PointSelection;
53 class TimeAxisView;
54 class AutomationTimeAxisView;
55 class Selectable;
56 class Selection;
57 class PublicEditor;
58 
59 
60 /** A GUI representation of an ARDOUR::AutomationList */
61 class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
62 {
63 public:
64 	enum VisibleAspects {
65 		Line = 0x1,
66 		ControlPoints = 0x2,
67 		SelectedControlPoints = 0x4
68 	};
69 
70 	AutomationLine (const std::string&                                 name,
71 	                TimeAxisView&                                      tv,
72 	                ArdourCanvas::Item&                                parent,
73 	                boost::shared_ptr<ARDOUR::AutomationList>          al,
74 	                const ARDOUR::ParameterDescriptor&                 desc,
75 	                Evoral::TimeConverter<double, ARDOUR::samplepos_t>* converter = 0);
76 
77 	virtual ~AutomationLine ();
78 
79 	void queue_reset ();
80 	void reset ();
81 	void clear ();
set_fill(bool f)82 	void set_fill (bool f) { _fill = f; } // owner needs to call set_height
83 
84 	void set_selected_points (PointSelection const &);
85 	void get_selectables (ARDOUR::samplepos_t, ARDOUR::samplepos_t, double, double, std::list<Selectable*>&);
86 	void get_inverted_selectables (Selection&, std::list<Selectable*>& results);
87 
88 	virtual void remove_point (ControlPoint&);
89 	bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after);
90 
91 	/* dragging API */
92 	virtual void start_drag_single (ControlPoint*, double, float);
93 	virtual void start_drag_line (uint32_t, uint32_t, float);
94 	virtual void start_drag_multiple (std::list<ControlPoint*>, float, XMLNode *);
95 	virtual std::pair<float, float> drag_motion (double, float, bool, bool with_push, uint32_t& final_index);
96 	virtual void end_drag (bool with_push, uint32_t final_index);
97 
98 	ControlPoint* nth (uint32_t);
99 	ControlPoint const * nth (uint32_t) const;
npoints()100 	uint32_t npoints() const { return control_points.size(); }
101 
name()102 	std::string  name()    const { return _name; }
visible()103 	bool    visible() const { return _visible != VisibleAspects(0); }
height()104 	guint32 height()  const { return _height; }
105 
106 	void     set_line_color (uint32_t);
get_line_color()107 	uint32_t get_line_color() const { return _line_color; }
108 
109 	void set_visibility (VisibleAspects);
110 	void add_visibility (VisibleAspects);
111 	void remove_visibility (VisibleAspects);
112 
113 	void hide ();
114 	void set_height (guint32);
115 
116 	bool get_uses_gain_mapping () const;
117 
118 	TimeAxisView& trackview;
119 
canvas_group()120 	ArdourCanvas::Container& canvas_group() const { return *group; }
parent_group()121 	ArdourCanvas::Item&  parent_group() const { return _parent_group; }
grab_item()122 	ArdourCanvas::Item&  grab_item() const { return *line; }
123 
124 	virtual std::string get_verbose_cursor_string (double) const;
125 	std::string get_verbose_cursor_relative_string (double, double) const;
126 	std::string fraction_to_string (double) const;
127 	std::string delta_to_string (double) const;
128 	double string_to_fraction (std::string const &) const;
129 	void   view_to_model_coord (double& x, double& y) const;
130 	void   view_to_model_coord_y (double &) const;
131 	void   model_to_view_coord (double& x, double& y) const;
132 	void   model_to_view_coord_y (double &) const;
133 
134 	double compute_delta (double from, double to) const;
135 	void   apply_delta (double& val, double delta) const;
136 
137 	void set_list(boost::shared_ptr<ARDOUR::AutomationList> list);
the_list()138 	boost::shared_ptr<ARDOUR::AutomationList> the_list() const { return alist; }
139 
140 	void track_entered();
141 	void track_exited();
142 
143 	bool is_last_point (ControlPoint &);
144 	bool is_first_point (ControlPoint &);
145 
146 	XMLNode& get_state (void);
147 	int set_state (const XMLNode&, int version);
148 	void set_colors();
149 
150 	void modify_point_y (ControlPoint&, double);
151 
152 	virtual MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder ();
153 
time_converter()154 	const Evoral::TimeConverter<double, ARDOUR::samplepos_t>& time_converter () const {
155 		return *_time_converter;
156 	}
157 
158 	std::pair<ARDOUR::samplepos_t, ARDOUR::samplepos_t> get_point_x_range () const;
159 
160 	void set_maximum_time (ARDOUR::samplecnt_t);
maximum_time()161 	ARDOUR::samplecnt_t maximum_time () const {
162 		return _maximum_time;
163 	}
164 
165 	void set_offset (ARDOUR::samplecnt_t);
offset()166 	ARDOUR::samplecnt_t offset () { return _offset; }
167 	void set_width (ARDOUR::samplecnt_t);
168 
169 	samplepos_t session_position (ARDOUR::AutomationList::const_iterator) const;
170 
171 protected:
172 
173 	std::string    _name;
174 	guint32        _height;
175 	uint32_t       _line_color;
176 
177 	boost::shared_ptr<ARDOUR::AutomationList> alist;
178 	Evoral::TimeConverter<double, ARDOUR::samplepos_t>* _time_converter;
179 	/** true if _time_converter belongs to us (ie we should delete it on destruction) */
180 	bool _our_time_converter;
181 
182 	VisibleAspects _visible;
183 
184 	bool    terminal_points_can_slide;
185 	bool    update_pending;
186 	bool    have_timeout;
187 	bool    no_draw;
188 	bool    _is_boolean;
189 	/** true if we did a push at any point during the current drag */
190 	bool    did_push;
191 
192 	ArdourCanvas::Item&         _parent_group;
193 	ArdourCanvas::Container*    group;
194 	ArdourCanvas::PolyLine*     line; /* line */
195 	ArdourCanvas::Points        line_points; /* coordinates for canvas line */
196 	std::vector<ControlPoint*>  control_points; /* visible control points */
197 
198 	class ContiguousControlPoints : public std::list<ControlPoint*> {
199 public:
200 		ContiguousControlPoints (AutomationLine& al);
201 		double clamp_dx (double dx);
202 		void move (double dx, double dvalue);
203 		void compute_x_bounds (PublicEditor& e);
204 private:
205 		AutomationLine& line;
206 		double before_x;
207 		double after_x;
208 	};
209 
210 	friend class ContiguousControlPoints;
211 
212 	typedef boost::shared_ptr<ContiguousControlPoints> CCP;
213 	std::vector<CCP> contiguous_points;
214 
215 	bool sync_model_with_view_point (ControlPoint&);
216 	bool sync_model_with_view_points (std::list<ControlPoint*>);
217 	void start_drag_common (double, float);
218 
219 	void reset_callback (const Evoral::ControlList&);
220 	void list_changed ();
221 
222 	virtual bool event_handler (GdkEvent*);
223 
224 private:
225 	std::list<ControlPoint*> _drag_points; ///< points we are dragging
226 	std::list<ControlPoint*> _push_points; ///< additional points we are dragging if "push" is enabled
227 	bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false
228 	double _drag_x; ///< last x position of the drag, in units
229 	double _drag_distance; ///< total x movement of the drag, in canvas units
230 	double _last_drag_fraction; ///< last y position of the drag, as a fraction
231 	/** offset from the start of the automation list to the start of the line, so that
232 	 *  a +ve offset means that the 0 on the line is at _offset in the list
233 	 */
234 	ARDOUR::samplecnt_t _offset;
235 
236 	bool is_stepped() const;
237 	void update_visibility ();
238 	void reset_line_coords (ControlPoint&);
239 	void add_visible_control_point (uint32_t, uint32_t, double, double, ARDOUR::AutomationList::iterator, uint32_t);
240 	double control_point_box_size ();
241 	void connect_to_list ();
242 	void interpolation_changed (ARDOUR::AutomationList::InterpolationStyle);
243 
244 	PBD::ScopedConnectionList _list_connections;
245 
246 	/** maximum time that a point on this line can be at, relative to the position of its region or start of its track */
247 	ARDOUR::samplecnt_t _maximum_time;
248 
249 	bool _fill;
250 
251 	const ARDOUR::ParameterDescriptor _desc;
252 
253 	friend class AudioRegionGainLine;
254 };
255 
256 #endif /* __ardour_automation_line_h__ */
257 
258