fix load+save of plugin parameter automation
[ardour.git] / gtk2_ardour / export_multiplicator.cc
1 /* This file is not used at the moment. It includes code related to export a
2  * multiplication graph system that can be used together with the code in
3  * libs/ardour/export_multiplication.cc and libs/ardour/ardour/export_multiplication.h
4  * - Sakari Bergen 6.8.2008 -
5  */
6
7 /*
8     Copyright (C) 2008 Paul Davis
9     Author: Sakari Bergen
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
22     along with this program; if not, write to the Free Software
23     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25 */
26
27 #include "export_multiplicator.h"
28
29 #include <cassert>
30
31 #include "pbd/compose.h"
32
33 #include "i18n.h"
34
35 using namespace ARDOUR;
36 using namespace PBD;
37
38 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
39
40 ExportMultiplicator::ExportMultiplicator () :
41   graph (0)
42 {
43         add (table);
44 }
45
46 ExportMultiplicator::~ExportMultiplicator ()
47 {}
48
49 void
50 ExportMultiplicator::set_manager (boost::shared_ptr<ARDOUR::ExportProfileManager> _manager)
51 {
52         manager = _manager;
53         manager->GraphChanged.connect (sigc::mem_fun (*this, &ExportMultiplicator::redraw));
54
55         redraw();
56 }
57
58 void
59 ExportMultiplicator::redraw ()
60 {
61         if (!manager) { return; }
62
63         graph = &manager->get_graph();
64
65         /* Empty table */
66
67         table.foreach (sigc::mem_fun (table, &Gtk::Table::remove));
68         widget_map.clear();
69
70         /* Calculate table dimensions */
71
72         uint32_t max_width = 0;
73         GraphLevel max_level = NoLevel;
74
75         if (graph->timespans.size() > max_width) {
76                 max_width = graph->timespans.size();
77                 max_level = Timespans;
78         }
79
80         if (graph->channel_configs.size() > max_width) {
81                 max_width = graph->channel_configs.size();
82                 max_level = ChannelConfigs;
83         }
84
85         if (graph->formats.size() > max_width) {
86                 max_width = graph->formats.size();
87                 max_level = Formats;
88         }
89
90         if (graph->filenames.size() > max_width) {
91                 max_width = graph->filenames.size();
92                 max_level = Filenames;
93         }
94
95         table.resize (4, max_width);
96
97         std::cout << "Table width: " << max_width << std::endl;
98
99         /* Fill table */
100
101         for (list<ExportProfileManager::TimespanNodePtr>::const_iterator it = graph->timespans.begin(); it != graph->timespans.end(); ++it) {
102                 draw_timespan (*it, get_bounds (it->get(), Timespans, max_level));
103         }
104
105         for (list<ExportProfileManager::ChannelConfigNodePtr>::const_iterator it = graph->channel_configs.begin(); it != graph->channel_configs.end(); ++it) {
106                 draw_channel_config (*it, get_bounds (it->get(), ChannelConfigs, max_level));
107         }
108
109         for (list<ExportProfileManager::FormatNodePtr>::const_iterator it = graph->formats.begin(); it != graph->formats.end(); ++it) {
110                 draw_format (*it, get_bounds (it->get(), Formats, max_level));
111         }
112
113         for (list<ExportProfileManager::FilenameNodePtr>::const_iterator it = graph->filenames.begin(); it != graph->filenames.end(); ++it) {
114                 draw_filename (*it, get_bounds (it->get(), Filenames, max_level));
115         }
116
117         show_all_children ();
118 }
119
120 std::pair<uint32_t, uint32_t>
121 ExportMultiplicator::get_bounds (ARDOUR::ExportProfileManager::GraphNode * node, GraphLevel current_level, GraphLevel max_level) const
122 {
123         assert (current_level != NoLevel && max_level != NoLevel && graph);
124
125         uint32_t left_bound = 0;
126         uint32_t right_bound = 0;
127
128         bool left_bound_found = false;
129
130         bool (ExportProfileManager::GraphNode::*relation_func) (ExportProfileManager::GraphNode const *) const;
131         if (max_level < current_level) {
132                 std::cout << "using 'is_ancestor_of'" << std::endl;
133                 relation_func = &ExportProfileManager::GraphNode::is_ancestor_of;
134         } else if (max_level > current_level) {
135                 std::cout << "using 'is_descendant_of'" << std::endl;
136                 relation_func = &ExportProfileManager::GraphNode::is_descendant_of;
137         } else {
138                 std::cout << "using 'equals'" << std::endl;
139                 relation_func = &ExportProfileManager::GraphNode::equals;
140         }
141
142         switch (max_level) {
143           case Timespans:
144                 for (list<ExportProfileManager::TimespanNodePtr>::const_iterator it = graph->timespans.begin(); it != graph->timespans.end(); ++it) {
145                         if (CALL_MEMBER_FN(**it, relation_func) (node)) {
146                                 left_bound_found = true;
147                         } else if (!left_bound_found) {
148                                 ++left_bound;
149                         }
150
151                         if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) {
152                                 break;
153                         } else {
154                                 ++right_bound;
155                         }
156                 }
157                 break;
158
159           case ChannelConfigs:
160                 for (list<ExportProfileManager::ChannelConfigNodePtr>::const_iterator it = graph->channel_configs.begin(); it != graph->channel_configs.end(); ++it) {
161                         if (CALL_MEMBER_FN(**it, relation_func) (node)) {
162                                 left_bound_found = true;
163                         } else if (!left_bound_found) {
164                                 ++left_bound;
165                         }
166
167                         if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) {
168                                 break;
169                         } else {
170                                 ++right_bound;
171                         }
172                 }
173                 break;
174
175           case Formats:
176                 for (list<ExportProfileManager::FormatNodePtr>::const_iterator it = graph->formats.begin(); it != graph->formats.end(); ++it) {
177                         if (CALL_MEMBER_FN(**it, relation_func) (node)) {
178                                 left_bound_found = true;
179                         } else if (!left_bound_found) {
180                                 ++left_bound;
181                         }
182
183                         if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) {
184                                 break;
185                         } else {
186                                 ++right_bound;
187                         }
188                 }
189                 break;
190
191           case Filenames:
192                 for (list<ExportProfileManager::FilenameNodePtr>::const_iterator it = graph->filenames.begin(); it != graph->filenames.end(); ++it) {
193                         if (CALL_MEMBER_FN(**it, relation_func) (node)) {
194                                 std::cout << "filename relation check returned true" << std::endl;
195                                 left_bound_found = true;
196                         } else if (!left_bound_found) {
197                                 std::cout << "filename relation check returned false" << std::endl;
198                                 ++left_bound;
199                         }
200
201                         if (left_bound_found && !CALL_MEMBER_FN(**it, relation_func) (node)) {
202                                 break;
203                         } else {
204                                 ++right_bound;
205                         }
206                 }
207                 break;
208
209           case NoLevel:
210                 // Not reached !
211                 break;
212         }
213
214         return std::pair<uint32_t, uint32_t> (left_bound, right_bound);
215 }
216
217 void
218 ExportMultiplicator::draw_timespan (ARDOUR::ExportProfileManager::TimespanNodePtr node, std::pair<uint32_t, uint32_t> bounds)
219 {
220         ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Timespan %1", node->id()), manager, node.get()));
221         get_hbox (TablePosition (bounds.first, bounds.second, Timespans))->pack_end (*button, true, true);
222 }
223
224 void
225 ExportMultiplicator::draw_channel_config (ARDOUR::ExportProfileManager::ChannelConfigNodePtr node, std::pair<uint32_t, uint32_t> bounds)
226 {
227         ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Channel config %1", node->id()), manager, node.get()));
228         get_hbox (TablePosition (bounds.first, bounds.second, ChannelConfigs))->pack_end (*button, true, true);
229 }
230
231 void
232 ExportMultiplicator::draw_format (ARDOUR::ExportProfileManager::FormatNodePtr node, std::pair<uint32_t, uint32_t> bounds)
233 {
234         ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Format %1", node->id()), manager, node.get()));
235         get_hbox (TablePosition (bounds.first, bounds.second, Formats))->pack_end (*button, true, true);
236 }
237
238 void
239 ExportMultiplicator::draw_filename (ARDOUR::ExportProfileManager::FilenameNodePtr node, std::pair<uint32_t, uint32_t> bounds)
240 {
241         ButtonWidget * button = Gtk::manage (new ButtonWidget (string_compose ("Filename %1", node->id()), manager, node.get()));
242         get_hbox (TablePosition (bounds.first, bounds.second, Filenames))->pack_end (*button, true, true);
243 }
244
245 boost::shared_ptr<Gtk::HBox>
246 ExportMultiplicator::get_hbox (TablePosition position)
247 {
248         WidgetMap::iterator it = widget_map.find (position);
249         if (it != widget_map.end()) { return it->second; }
250
251         boost::shared_ptr<Gtk::HBox> widget = widget_map.insert (WidgetPair (position, boost::shared_ptr<Gtk::HBox> (new Gtk::HBox ()))).first->second;
252         table.attach (*widget, position.left, position.right, position.row - 1, position.row);
253
254         return widget;
255 }
256
257 ExportMultiplicator::ButtonWidget::ButtonWidget (Glib::ustring name, boost::shared_ptr<ExportProfileManager> m, ExportProfileManager::GraphNode * node) :
258   label (name),
259   node (node),
260   split_position (0.5)
261 {
262         manager = m;
263
264         menu_actions = Gtk::ActionGroup::create();
265         menu_actions->add (Gtk::Action::create ("Split", _("_Split here")), sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::split));
266         menu_actions->add (Gtk::Action::create ("Remove", _("_Remove")), sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::remove));
267
268         ui_manager = Gtk::UIManager::create();
269         ui_manager->insert_action_group (menu_actions);
270
271         Glib::ustring ui_info =
272                 "<ui>"
273                 "  <popup name='PopupMenu'>"
274                 "    <menuitem action='Split'/>"
275                 "    <menuitem action='Remove'/>"
276                 "  </popup>"
277                 "</ui>";
278
279         ui_manager->add_ui_from_string (ui_info);
280         menu = dynamic_cast<Gtk::Menu*> (ui_manager->get_widget ("/PopupMenu"));
281
282         add_events (Gdk::BUTTON_PRESS_MASK);
283         signal_button_press_event ().connect (sigc::mem_fun (*this, &ExportMultiplicator::ButtonWidget::on_button_press_event));
284
285         modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#0000"));
286         set_border_width (1);
287         vbox.pack_start (label, true, true, 4);
288         add (vbox);
289 }
290
291 bool
292 ExportMultiplicator::ButtonWidget::on_button_press_event (GdkEventButton* event)
293 {
294         if(event->type != GDK_BUTTON_PRESS) { return false; }
295         if (event->button == 1) {
296                 node->select (!node->selected ());
297
298                 if (node->selected ()) {
299                         unset_bg (Gtk::STATE_NORMAL);
300                         modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#194756"));
301                 } else {
302                         unset_bg (Gtk::STATE_NORMAL);
303                         modify_bg (Gtk::STATE_NORMAL, Gdk::Color ("#0000"));
304                 }
305
306                 return true;
307
308         } else if (event->button == 3) {
309                 int x, y;
310                 get_pointer (x, y);
311                 split_position = (float) x / get_width();
312
313                 menu->popup (event->button, event->time);
314                 return true;
315         }
316
317         return false;
318 }
319
320 void
321 ExportMultiplicator::ButtonWidget::split ()
322 {
323         manager->split_node (node, split_position);
324 }
325
326 void
327 ExportMultiplicator::ButtonWidget::remove ()
328 {
329         manager->remove_node (node);
330 }