Tidy up RegionLayeringOrderEditor a bit. Add GPL boilerplate. Make it respect edit...
[ardour.git] / gtk2_ardour / region_layering_order_editor.cc
1 /*
2     Copyright (C) 2011-2012 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 #include <gtkmm/table.h>
21 #include <gtkmm/stock.h>
22 #include <gtkmm/alignment.h>
23 #include "ardour/region.h"
24
25 #include "gui_thread.h"
26 #include "keyboard.h"
27 #include "public_editor.h"
28 #include "region_layering_order_editor.h"
29 #include "region_view.h"
30 #include "utils.h"
31 #include "i18n.h"
32
33 using namespace std;
34 using namespace Gtk;
35 using namespace ARDOUR;
36
37 RegionLayeringOrderEditor::RegionLayeringOrderEditor (PublicEditor& pe)
38         : ArdourWindow (_("RegionLayeringOrderEditor"))
39         , position (0)
40         , in_row_change (false)
41         , regions_at_position (0)
42         , layering_order_model (Gtk::ListStore::create (layering_order_columns))
43         , clock ("layer dialog", true, "", false, false, false)
44         , editor (pe)
45         , _time_axis_view (0)
46 {
47         set_name ("RegionLayeringOrderEditorWindow");
48
49         layering_order_display.set_model (layering_order_model);
50
51         layering_order_display.append_column (_("Region Name"), layering_order_columns.name);
52         layering_order_display.set_headers_visible (true);
53         layering_order_display.set_reorderable (false);
54         layering_order_display.set_rules_hint (true);
55
56         scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
57         scroller.add (layering_order_display);
58
59         clock.set_mode (AudioClock::BBT);
60
61         Gtk::Table* scroller_table = manage (new Gtk::Table);
62         scroller_table->set_size_request (300, 250);
63         scroller_table->attach (scroller, 0, 1, 0, 1);
64         scroller_table->set_col_spacings (5);
65         scroller_table->set_row_spacings (5);
66
67         track_label.set_name ("RegionLayeringOrderEditorLabel");
68         track_label.set_text (_("Track:"));
69         track_label.set_alignment (0, 0.5);
70         clock_label.set_name ("RegionLayeringOrderEditorLabel");
71         clock_label.set_text (_("Position:"));
72         clock_label.set_alignment (0, 0.5);
73         track_name_label.set_name ("RegionLayeringOrderEditorNameLabel");
74         track_name_label.set_alignment (0, 0.5);
75         clock.set_mode (AudioClock::BBT);
76
77         Gtk::Table* info_table = manage (new Gtk::Table (2, 2));
78         info_table->set_col_spacings (5);
79         info_table->set_row_spacings (5);
80         info_table->attach (track_label, 0, 1, 0, 1, FILL, FILL);
81         info_table->attach (track_name_label, 1, 2, 0, 1, FILL, FILL);
82         info_table->attach (clock_label, 0, 1, 1, 2, FILL, FILL);
83         info_table->attach (clock, 1, 2, 1, 2, FILL, FILL);
84
85         Gtk::VBox* vbox = Gtk::manage (new Gtk::VBox ());
86         vbox->set_spacing (12);
87         vbox->pack_start (*info_table, false, false);
88         vbox->pack_start (*scroller_table, true, true);
89         add (*vbox);
90
91         info_table->set_name ("RegionLayeringOrderTable");
92         scroller_table->set_name ("RegionLayeringOrderTable");
93
94         layering_order_display.set_name ("RegionLayeringOrderDisplay");
95
96         layering_order_display.signal_row_activated ().connect (mem_fun (*this, &RegionLayeringOrderEditor::row_activated));
97
98         layering_order_display.grab_focus ();
99
100         set_title (_("Choose Top Region"));
101         show_all();
102 }
103
104 RegionLayeringOrderEditor::~RegionLayeringOrderEditor ()
105 {
106         
107 }
108
109 void
110 RegionLayeringOrderEditor::row_activated (const TreeModel::Path& path, TreeViewColumn*)
111 {
112         if (in_row_change) {
113                 return;
114         }
115
116         TreeModel::iterator iter = layering_order_model->get_iter (path);
117
118         if (!iter) {
119                 return;
120         }
121         
122         TreeModel::Row row = *iter;
123         RegionView* rv = row[layering_order_columns.region_view];
124         
125         vector<RegionView*> eq;
126         editor.get_equivalent_regions (rv, eq, Properties::edit.property_id);
127         
128         for (vector<RegionView*>::iterator i = eq.begin(); i != eq.end(); ++i) {
129                 (*i)->region()->raise_to_top ();
130         }
131 }
132
133 struct RegionViewCompareByLayer {
134         bool operator() (RegionView* a, RegionView* b) const {
135                 return a->region()->layer() > b->region()->layer();
136         }
137 };
138
139 void
140 RegionLayeringOrderEditor::refill ()
141 {
142         assert (_time_axis_view);
143         
144         regions_at_position = 0;
145         in_row_change = true;
146         layering_order_model->clear ();
147
148         RegionSelection region_list;
149         TrackViewList ts;
150         ts.push_back (_time_axis_view);
151         editor.get_regions_at (region_list, position, ts);
152
153         regions_at_position = region_list.size ();
154
155         if (regions_at_position < 2) {
156                 playlist_modified_connection.disconnect ();
157                 hide ();
158                 in_row_change = false;
159                 return;
160         }
161
162         RegionViewCompareByLayer cmp;
163         region_list.sort (cmp);
164
165         for (RegionSelection::const_iterator i = region_list.begin(); i != region_list.end(); ++i) {
166                 TreeModel::Row newrow = *(layering_order_model->append());
167                 newrow[layering_order_columns.name] = (*i)->region()->name();
168                 newrow[layering_order_columns.region_view] = *i;
169
170                if (i == region_list.begin()) {
171                        layering_order_display.get_selection()->select(newrow);
172                }
173         }
174
175         in_row_change = false;
176 }
177
178 void
179 RegionLayeringOrderEditor::set_context (const string& a_name, Session* s, TimeAxisView* tav, boost::shared_ptr<Playlist> pl, framepos_t pos)
180 {
181         track_name_label.set_text (a_name);
182
183         clock.set_session (s);
184         clock.set (pos, true);
185
186         playlist_modified_connection.disconnect ();
187         pl->ContentsChanged.connect (playlist_modified_connection, invalidator (*this), boost::bind
188                                      (&RegionLayeringOrderEditor::playlist_modified, this), gui_context());
189
190         _time_axis_view = tav;
191
192         position = pos;
193         refill ();
194 }
195
196 bool
197 RegionLayeringOrderEditor::on_key_press_event (GdkEventKey* ev)
198 {
199         bool handled = false;
200
201         /* in general, we want shortcuts working while in this
202            dialog. However, we'd like to treat "return" specially
203            since it is used for row activation. So ..
204
205            for return: try normal handling first
206            then try the editor (to get accelerators/shortcuts)
207            then try normal handling (for keys other than return)
208         */
209
210         if (ev->keyval == GDK_Return) {
211                 handled = ArdourWindow::on_key_press_event (ev);
212         }
213
214         if (!handled) {
215                 handled = key_press_focus_accelerator_handler (editor, ev);
216         }
217
218         if (!handled) {
219                 handled = ArdourWindow::on_key_press_event (ev);
220         }
221
222         return handled;
223 }
224
225 void
226 RegionLayeringOrderEditor::maybe_present ()
227 {
228         if (regions_at_position < 2) {
229                 hide ();
230                 return;
231         }
232
233         present ();
234 }
235
236 void
237 RegionLayeringOrderEditor::playlist_modified ()
238 {
239         refill ();
240 }