1 /*
2  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
3  * Copyright (C) 2008-2012 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009-2011 David Robillard <d@drobilla.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 __gtk_ardour_port_matrix_h__
22 #define __gtk_ardour_port_matrix_h__
23 
24 #include <list>
25 #include <gtkmm/box.h>
26 #include <gtkmm/scrollbar.h>
27 #include <gtkmm/table.h>
28 #include <gtkmm/label.h>
29 #include <gtkmm/checkbutton.h>
30 #include <gtkmm/notebook.h>
31 #include <boost/shared_ptr.hpp>
32 
33 #include "ardour/bundle.h"
34 #include "ardour/types.h"
35 #include "ardour/session_handle.h"
36 
37 #include "port_group.h"
38 #include "port_matrix_types.h"
39 
40 /** The `port matrix' UI.  This is a widget which lets the user alter
41  *  associations between one set of ports and another.  e.g. to connect
42  *  things together.
43  *
44  *  It is made up of a body, PortMatrixBody, which is rendered using cairo,
45  *  and some scrollbars and other stuff.  All of this is arranged inside the
46  *  Table that we inherit from.
47  */
48 
49 namespace ARDOUR {
50 	class Bundle;
51 }
52 
53 namespace Gtk {
54 	namespace Menu_Helpers {
55 		class MenuList;
56 	}
57 }
58 
59 class PortMatrixBody;
60 
61 class PortMatrix : public Gtk::Table, public ARDOUR::SessionHandlePtr
62 {
63 public:
64 	PortMatrix (Gtk::Window*, ARDOUR::Session *, ARDOUR::DataType);
65 	~PortMatrix ();
66 
67 	void set_type (ARDOUR::DataType);
68 
type()69 	ARDOUR::DataType type () const {
70 		return _type;
71 	}
72 
73 	void disassociate_all ();
74 	void setup_scrollbars ();
75 	void popup_menu (ARDOUR::BundleChannel, ARDOUR::BundleChannel, uint32_t);
76 
min_height_divisor()77 	int min_height_divisor () const {
78 		return _min_height_divisor;
79 	}
set_min_height_divisor(int f)80 	void set_min_height_divisor (int f) {
81 		_min_height_divisor = f;
82 	}
83 
84 	enum Arrangement {
85 		TOP_TO_RIGHT,  ///< column labels on top, row labels to the right
86 		LEFT_TO_BOTTOM ///< row labels to the left, column labels on the bottom
87 	};
88 
89 
90 	/** @return Arrangement in use */
arrangement()91 	Arrangement arrangement () const {
92 		return _arrangement;
93 	}
94 
show_only_bundles()95 	bool show_only_bundles () const {
96 		return _show_only_bundles;
97 	}
98 
99 	PortGroupList const * columns () const;
100 	boost::shared_ptr<const PortGroup> visible_columns () const;
101 
102 	/** @return index into the _ports array for the list which is displayed as columns */
column_index()103 	int column_index () const {
104 		return _column_index;
105 	}
106 
107 	PortGroupList const * rows () const;
108 	boost::shared_ptr<const PortGroup> visible_rows () const;
109 
110 	/** @return index into the _ports array for the list which is displayed as rows */
row_index()111 	int row_index () const {
112 		return _row_index;
113 	}
114 
ports(int d)115 	PortGroupList const * ports (int d) const {
116 		return &_ports[d];
117 	}
118 
119 	boost::shared_ptr<const PortGroup> visible_ports (int d) const;
120 
121 	void init ();
122 	void setup ();
123 	virtual void setup_ports (int) = 0;
124 	void setup_all_ports ();
125 
126 	std::pair<uint32_t, uint32_t> max_size () const;
127 
128 	bool should_show (ARDOUR::DataType) const;
129 	uint32_t count_of_our_type (ARDOUR::ChanCount) const;
130 	uint32_t count_of_our_type_min_1 (ARDOUR::ChanCount) const;
131 
132 	PortMatrixNode::State get_association (PortMatrixNode) const;
133 
134 	void flip ();
135 	bool key_press (GdkEventKey *);
136 
137 	/** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1].
138 	 *  @param s New state.
139 	 */
140 	virtual void set_state (ARDOUR::BundleChannel c[2], bool s) = 0;
141 
142 	/** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1].
143 	 *  @return state
144 	 */
145 	virtual PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const = 0;
146 	virtual bool list_is_global (int) const = 0;
147 
148 	virtual bool can_add_channels (boost::shared_ptr<ARDOUR::Bundle>) const;
149 	virtual void add_channel (boost::shared_ptr<ARDOUR::Bundle>, ARDOUR::DataType);
150 	virtual bool can_remove_channels (boost::shared_ptr<ARDOUR::Bundle>) const;
151 	virtual void remove_channel (ARDOUR::BundleChannel);
152 	virtual void remove_all_channels (boost::weak_ptr<ARDOUR::Bundle>);
can_rename_channels(boost::shared_ptr<ARDOUR::Bundle>)153 	virtual bool can_rename_channels (boost::shared_ptr<ARDOUR::Bundle>) const {
154 		return false;
155 	}
156 	virtual bool can_add_port (boost::shared_ptr<ARDOUR::Bundle>, ARDOUR::DataType t) const;
rename_channel(ARDOUR::BundleChannel)157 	virtual void rename_channel (ARDOUR::BundleChannel) {}
158 	virtual std::string disassociation_verb () const = 0;
159 	virtual std::string channel_noun () const;
160 
161 	enum Result {
162 		Cancelled,
163 		Accepted
164 	};
165 
166 	sigc::signal<void, Result> Finished;
167 
168 	static bool bundle_with_channels (boost::shared_ptr<ARDOUR::Bundle>);
169 
170 protected:
171 
172 	/** We have two port group lists.  One will be presented on the rows of the matrix,
173 	    the other on the columns.  The PortMatrix chooses the arrangement based on which has
174 	    more ports in it.  Subclasses must fill these two lists with the port groups that they
175 	    wish to present.  The PortMatrix will arrange its layout such that signal flow is vaguely
176 	    from left to right as you go from list 0 to list 1.  Hence subclasses which deal with
177 	    inputs and outputs should put outputs in list 0 and inputs in list 1. */
178 	PortGroupList _ports[2];
179 
180 private:
181 
182 	void hscroll_changed ();
183 	void vscroll_changed ();
184 	void routes_changed ();
185 	void reconnect_to_routes ();
186 	void select_arrangement ();
187 	bool can_add_port_proxy (boost::weak_ptr<ARDOUR::Bundle>, ARDOUR::DataType) const;
188 	void add_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, ARDOUR::DataType);
189 	void remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
190 	void rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
191 	void disassociate_all_on_channel (boost::weak_ptr<ARDOUR::Bundle>, uint32_t, int);
192 	void disassociate_all_on_bundle (boost::weak_ptr<ARDOUR::Bundle>, int);
193 	void setup_global_ports ();
194         void setup_global_ports_proxy ();
195 	void toggle_show_only_bundles ();
196 	bool on_scroll_event (GdkEventScroll *);
197 	boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const;
198 	void setup_notebooks ();
199 	void remove_notebook_pages (Gtk::Notebook &);
200 	void notebook_page_selected (GtkNotebookPage *, guint);
201 	void route_processors_changed (ARDOUR::RouteProcessorChange);
202 	void body_dimensions_changed ();
203 	void session_going_away ();
204 	void add_remove_option (Gtk::Menu_Helpers::MenuList &, boost::weak_ptr<ARDOUR::Bundle>, int);
205 	void add_disassociate_option (Gtk::Menu_Helpers::MenuList &, boost::weak_ptr<ARDOUR::Bundle>, int, int);
206 	void port_connected_or_disconnected ();
207 	void update_tab_highlighting ();
208 	std::pair<int, int> check_flip () const;
209 	bool can_flip () const;
210 	void parameter_changed (std::string);
211 
212 	Gtk::Window* _parent;
213 
214 	/** port type that we are working with, or NIL if we are working with all of them */
215 	ARDOUR::DataType _type;
216 	PBD::ScopedConnectionList _route_connections;
217 	PBD::ScopedConnectionList _changed_connections;
218 	PBD::ScopedConnectionList _bundle_changed_connections;
219 
220 	PortMatrixBody* _body;
221 	Gtk::HScrollbar _hscroll;
222 	Gtk::VScrollbar _vscroll;
223 	Gtk::Notebook _vnotebook;
224 	Gtk::Notebook _hnotebook;
225 	Gtk::Label _vlabel;
226 	Gtk::Label _hlabel;
227 	Gtk::VBox _vbox;
228 	Gtk::HBox _hbox;
229 	Gtk::Label _hspacer;
230 	Gtk::Label _vspacer;
231 	Gtk::Menu* _menu;
232 	Arrangement _arrangement;
233 	int _row_index;
234 	int _column_index;
235 	int _min_height_divisor;
236 	bool _show_only_bundles;
237 	bool _inhibit_toggle_show_only_bundles;
238 	bool _ignore_notebook_page_selected;
239 };
240 
241 #endif
242