2005-09-25 14:42:24 -04:00
|
|
|
/*
|
|
|
|
Copyright (C) 2000 Paul Davis
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cmath>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <string>
|
|
|
|
#include <list>
|
|
|
|
|
2006-03-07 01:23:12 -05:00
|
|
|
#include <libgnomecanvasmm.h>
|
2005-11-14 11:24:21 -05:00
|
|
|
#include <libgnomecanvasmm/canvas.h>
|
|
|
|
#include <libgnomecanvasmm/item.h>
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <pbd/error.h>
|
|
|
|
|
2005-09-25 16:33:00 -04:00
|
|
|
#include <gtkmm2ext/utils.h>
|
|
|
|
#include <gtkmm2ext/selector.h>
|
|
|
|
#include <gtkmm2ext/stop_signal.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include <ardour/session.h>
|
|
|
|
#include <ardour/utils.h>
|
|
|
|
#include <ardour/ladspa_plugin.h>
|
2007-06-27 16:23:48 -04:00
|
|
|
#include <ardour/processor.h>
|
2005-09-25 14:42:24 -04:00
|
|
|
#include <ardour/location.h>
|
|
|
|
|
|
|
|
#include "ardour_ui.h"
|
|
|
|
#include "public_editor.h"
|
|
|
|
#include "time_axis_view.h"
|
2008-02-10 13:16:25 -05:00
|
|
|
#include "region_view.h"
|
|
|
|
#include "ghostregion.h"
|
2005-11-13 13:13:50 -05:00
|
|
|
#include "simplerect.h"
|
2008-02-01 22:57:35 -05:00
|
|
|
#include "simpleline.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
#include "selection.h"
|
|
|
|
#include "keyboard.h"
|
|
|
|
#include "rgb_macros.h"
|
2005-11-28 17:36:26 -05:00
|
|
|
#include "utils.h"
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
using namespace Gtk;
|
2005-12-23 10:34:02 -05:00
|
|
|
using namespace Gdk;
|
2005-11-12 22:53:51 -05:00
|
|
|
using namespace sigc;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace ARDOUR;
|
Large nasty commit in the form of a 5000 line patch chock-full of completely
unecessary changes. (Sorry, doing a "sprint" based thing, this is the end of the first one)
Achieved MIDI track and bus creation, associated Jack port and diskstream creation, and minimal GUI stuff for creating them. Should be set to start work on actually recording and playing midi to/from disk now.
Relevant (significant) changes:
- Creation of a Buffer class. Base class is type agnostic so things can point to a buffer but not care what kind it is (otherwise it'd be a template). Derived into AudioBuffer and MidiBuffer, with a type tag because checking type is necessary in parts of the code where dynamic_cast wouldn't be wise. Originally I considered this a hack, but passing around a type proved to be a very good solution to all the other problems (below). There is a 1:1 mapping between jack port data types and ardour Buffer types (with a conversion function), but that's easily removed if it ever becomes necessary. Having the type scoped in the Buffer class is maybe not the best spot for it, but whatever (this is proof of concept kinda stuff right now...)
- IO now has a "default" port type (passed to the constructor and stored as a member), used by ensure_io (and similar) to create n ports. IO::register_***_port has a type argument that defaults to the default type if not passed. Rationale: previous IO API is identical, no changes needed to existing code, but path is paved for multiple port types in one IO, which we will need for eg synth plugin inserts, among other things. This is not quite ideal (best would be to only have the two port register functions and have them take a type), but the alternative is a lot of work (namely destroying the 'ensure' functions and everything that uses them) for very little gain. (I am convinced after quite a few tries at the whiteboard that subclassing IO in any way is not a feasible option, look at it's inheritance diagram in Doxygen and you can see why)
- AudioEngine::register_audio_input_port is now register_input_port and takes a type argument. Ditto for output.
- (Most significant change) AudioDiskstream abstracted into Distream, and sibling MidiDiskstream created. Very much still a work in progress, but Diskstream is there to switch references over to (most already are), which is the important part. It is still unclear what the MIDI diskstream's relation to channels is, but I'm pretty sure they will be single channel only (so SMF Type 0) since noone can come up with a reason otherwise.
- MidiTrack creation. Same thing as AudioTrack but with a different default type basically. No big deal here.
- Random cleanups and variable renamings etc. because I have OCD and can't help myself. :)
Known broken: Loading of sessions containing MIDI tracks.
git-svn-id: svn://localhost/ardour2/branches/midi@641 d708f5d6-7413-0410-9779-e7cbd77b26cf
2006-06-26 12:01:34 -04:00
|
|
|
using namespace PBD;
|
2005-09-25 14:42:24 -04:00
|
|
|
using namespace Editing;
|
2005-11-14 11:24:21 -05:00
|
|
|
using namespace ArdourCanvas;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
const double trim_handle_size = 6.0; /* pixels */
|
|
|
|
|
2006-01-17 21:56:51 -05:00
|
|
|
uint32_t TimeAxisView::hLargest = 0;
|
|
|
|
uint32_t TimeAxisView::hLarge = 0;
|
|
|
|
uint32_t TimeAxisView::hLarger = 0;
|
|
|
|
uint32_t TimeAxisView::hNormal = 0;
|
|
|
|
uint32_t TimeAxisView::hSmaller = 0;
|
|
|
|
uint32_t TimeAxisView::hSmall = 0;
|
|
|
|
bool TimeAxisView::need_size_info = true;
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView* rent, Canvas& canvas)
|
|
|
|
: AxisView (sess),
|
|
|
|
editor (ed),
|
2007-06-06 22:07:49 -04:00
|
|
|
height_style(Small),
|
2007-06-05 12:39:23 -04:00
|
|
|
y_position(0),
|
|
|
|
order(0),
|
2008-02-16 17:43:18 -05:00
|
|
|
controls_table (2, 8)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2006-01-17 21:56:51 -05:00
|
|
|
if (need_size_info) {
|
|
|
|
compute_controls_size_info ();
|
|
|
|
need_size_info = false;
|
|
|
|
}
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
canvas_display = new Group (*canvas.root(), 0.0, 0.0);
|
2008-02-10 13:16:25 -05:00
|
|
|
|
|
|
|
ghost_group = new Group (*canvas_display);
|
|
|
|
ghost_group->lower_to_bottom();
|
|
|
|
ghost_group->show();
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
selection_group = new Group (*canvas_display);
|
|
|
|
selection_group->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
control_parent = 0;
|
|
|
|
display_menu = 0;
|
|
|
|
size_menu = 0;
|
|
|
|
_marked_for_display = false;
|
|
|
|
_hidden = false;
|
2008-02-10 13:16:25 -05:00
|
|
|
in_destructor = false;
|
2005-09-25 14:42:24 -04:00
|
|
|
height = 0;
|
|
|
|
effective_height = 0;
|
|
|
|
parent = rent;
|
|
|
|
_has_state = false;
|
2005-12-12 15:54:55 -05:00
|
|
|
last_name_entry_key_press_event = 0;
|
2006-01-17 21:56:51 -05:00
|
|
|
name_packing = NamePackingBits (0);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
Create the standard LHS Controls
|
|
|
|
We create the top-level container and name add the name label here,
|
|
|
|
subclasses can add to the layout as required
|
|
|
|
*/
|
|
|
|
|
|
|
|
name_entry.set_name ("EditorTrackNameDisplay");
|
2005-09-26 14:24:59 -04:00
|
|
|
name_entry.signal_button_release_event().connect (mem_fun (*this, &TimeAxisView::name_entry_button_release));
|
|
|
|
name_entry.signal_button_press_event().connect (mem_fun (*this, &TimeAxisView::name_entry_button_press));
|
2005-12-12 15:54:55 -05:00
|
|
|
name_entry.signal_key_release_event().connect (mem_fun (*this, &TimeAxisView::name_entry_key_release));
|
|
|
|
name_entry.signal_activate().connect (mem_fun(*this, &TimeAxisView::name_entry_activated));
|
|
|
|
name_entry.signal_focus_in_event().connect (mem_fun (*this, &TimeAxisView::name_entry_focus_in));
|
|
|
|
name_entry.signal_focus_out_event().connect (mem_fun (*this, &TimeAxisView::name_entry_focus_out));
|
2006-04-20 14:14:00 -04:00
|
|
|
Gtkmm2ext::set_size_request_to_display_given_text (name_entry, N_("gTortnam"), 10, 10); // just represents a short name
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
name_label.set_name ("TrackLabel");
|
|
|
|
name_label.set_alignment (0.0, 0.5);
|
|
|
|
|
|
|
|
/* typically, either name_label OR name_entry are visible,
|
|
|
|
but not both. its up to derived classes to show/hide them as they
|
|
|
|
wish.
|
|
|
|
*/
|
|
|
|
|
|
|
|
name_hbox.show ();
|
|
|
|
|
|
|
|
controls_table.set_border_width (2);
|
|
|
|
controls_table.set_row_spacings (0);
|
|
|
|
controls_table.set_col_spacings (0);
|
|
|
|
controls_table.set_homogeneous (true);
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
controls_table.attach (name_hbox, 0, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 3, 0);
|
2006-01-17 21:56:51 -05:00
|
|
|
controls_table.show_all ();
|
2006-08-09 21:22:45 -04:00
|
|
|
controls_table.set_no_show_all ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
controls_vbox.pack_start (controls_table, false, false);
|
|
|
|
controls_vbox.show ();
|
2006-07-06 15:45:23 -04:00
|
|
|
|
|
|
|
//controls_ebox.set_name ("TimeAxisViewControlsBaseUnselected");
|
2005-09-25 14:42:24 -04:00
|
|
|
controls_ebox.add (controls_vbox);
|
2005-12-23 10:34:02 -05:00
|
|
|
controls_ebox.add_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|SCROLL_MASK);
|
|
|
|
controls_ebox.set_flags (CAN_FOCUS);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-09-26 14:24:59 -04:00
|
|
|
controls_ebox.signal_button_release_event().connect (mem_fun (*this, &TimeAxisView::controls_ebox_button_release));
|
2006-01-03 00:40:21 -05:00
|
|
|
controls_ebox.signal_scroll_event().connect (mem_fun (*this, &TimeAxisView::controls_ebox_scroll), true);
|
2005-12-23 10:34:02 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
controls_hbox.pack_start (controls_ebox,true,true);
|
|
|
|
controls_hbox.show ();
|
|
|
|
|
2008-01-13 12:45:17 -05:00
|
|
|
//controls_frame.add (controls_hbox);
|
|
|
|
//controls_frame.set_name ("TimeAxisViewControlsBaseUnselected");
|
2008-02-16 17:43:18 -05:00
|
|
|
//controls_vbox.set_name ("TimeAxisViewControlsBaseUnselected");
|
2008-01-13 12:45:17 -05:00
|
|
|
//controls_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
|
2006-02-14 12:19:58 -05:00
|
|
|
|
2007-06-15 18:08:27 -04:00
|
|
|
ColorsChanged.connect (mem_fun (*this, &TimeAxisView::color_handler));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView::~TimeAxisView()
|
|
|
|
{
|
2008-02-10 13:16:25 -05:00
|
|
|
in_destructor = true;
|
|
|
|
|
|
|
|
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
|
|
|
|
delete *i;
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
|
2005-11-28 17:36:26 -05:00
|
|
|
delete (*i)->rect;
|
|
|
|
delete (*i)->start_trim;
|
|
|
|
delete (*i)->end_trim;
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
|
2005-11-28 17:36:26 -05:00
|
|
|
delete (*i)->rect;
|
|
|
|
delete (*i)->start_trim;
|
|
|
|
delete (*i)->end_trim;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
for (list<SimpleLine*>::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
|
|
|
|
delete (*i);
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (selection_group) {
|
2005-11-13 13:13:50 -05:00
|
|
|
delete selection_group;
|
2005-09-25 14:42:24 -04:00
|
|
|
selection_group = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canvas_display) {
|
2005-11-13 13:13:50 -05:00
|
|
|
delete canvas_display;
|
2005-09-25 14:42:24 -04:00
|
|
|
canvas_display = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (display_menu) {
|
|
|
|
delete display_menu;
|
|
|
|
display_menu = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
guint32
|
|
|
|
TimeAxisView::show_at (double y, int& nth, VBox *parent)
|
|
|
|
{
|
|
|
|
gdouble ix1, ix2, iy1, iy2;
|
|
|
|
effective_height = 0;
|
2005-12-17 08:39:27 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (control_parent) {
|
2008-01-13 12:45:17 -05:00
|
|
|
control_parent->reorder_child (controls_hbox, nth);
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
|
|
|
control_parent = parent;
|
2008-01-13 12:45:17 -05:00
|
|
|
parent->pack_start (controls_hbox, false, false);
|
|
|
|
parent->reorder_child (controls_hbox, nth);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2008-01-13 12:45:17 -05:00
|
|
|
controls_hbox.show ();
|
2005-09-25 14:42:24 -04:00
|
|
|
controls_ebox.show ();
|
2005-12-17 08:39:27 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* the coordinates used here are in the system of the
|
|
|
|
item's parent ...
|
|
|
|
*/
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
canvas_display->get_bounds (ix1, iy1, ix2, iy2);
|
2005-11-13 13:13:50 -05:00
|
|
|
Group* pg = canvas_display->property_parent();
|
|
|
|
pg->i2w (ix1, iy1);
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
if (iy1 < 0) {
|
|
|
|
iy1 = 0;
|
|
|
|
}
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
canvas_display->move (0.0, y - iy1);
|
|
|
|
canvas_display->show();/* XXX not necessary */
|
2005-09-25 14:42:24 -04:00
|
|
|
y_position = y;
|
|
|
|
order = nth;
|
|
|
|
_hidden = false;
|
|
|
|
|
2007-04-22 14:01:10 -04:00
|
|
|
/* height in pixels depends on _order, so update it now we've changed _order */
|
|
|
|
set_height (height_style);
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
effective_height = height;
|
|
|
|
|
|
|
|
/* now show children */
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((*i)->marked_for_display()) {
|
2005-11-12 22:53:51 -05:00
|
|
|
(*i)->canvas_display->show();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-11-28 17:36:26 -05:00
|
|
|
if (canvas_item_visible ((*i)->canvas_display)) {
|
2005-09-25 14:42:24 -04:00
|
|
|
++nth;
|
2007-03-19 03:07:38 -04:00
|
|
|
effective_height += (*i)->show_at (y + effective_height, nth, parent);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return effective_height;
|
|
|
|
}
|
|
|
|
|
2005-12-23 10:34:02 -05:00
|
|
|
bool
|
|
|
|
TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev)
|
|
|
|
{
|
|
|
|
switch (ev->direction) {
|
|
|
|
case GDK_SCROLL_UP:
|
2008-01-10 16:20:59 -05:00
|
|
|
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
|
2005-12-23 10:34:02 -05:00
|
|
|
step_height (true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDK_SCROLL_DOWN:
|
2008-01-10 16:20:59 -05:00
|
|
|
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
|
2005-12-23 10:34:02 -05:00
|
|
|
step_height (false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* no handling for left/right, yet */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2005-09-25 14:42:24 -04:00
|
|
|
TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
|
|
|
|
{
|
|
|
|
switch (ev->button) {
|
|
|
|
case 1:
|
|
|
|
selection_click (ev);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
popup_display_menu (ev->time);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-12-23 10:34:02 -05:00
|
|
|
return true;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::selection_click (GdkEventButton* ev)
|
|
|
|
{
|
2006-11-19 11:45:16 -05:00
|
|
|
Selection::Operation op = Keyboard::selection_type (ev->state);
|
|
|
|
editor.set_selected_track (*this, op, false);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide ()
|
|
|
|
{
|
|
|
|
if (_hidden) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
canvas_display->hide();
|
2008-01-13 12:45:17 -05:00
|
|
|
controls_hbox.hide ();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (control_parent) {
|
2008-01-13 12:45:17 -05:00
|
|
|
control_parent->remove (controls_hbox);
|
2005-09-25 14:42:24 -04:00
|
|
|
control_parent = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
y_position = -1;
|
|
|
|
_hidden = true;
|
|
|
|
|
|
|
|
/* now hide children */
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->hide ();
|
|
|
|
}
|
|
|
|
|
|
|
|
Hiding ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::step_height (bool bigger)
|
|
|
|
{
|
2006-04-09 22:14:05 -04:00
|
|
|
|
|
|
|
if (height == hLargest) {
|
|
|
|
if (!bigger) set_height (Large);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (height == hLarge) {
|
|
|
|
if (bigger) set_height (Largest);
|
|
|
|
else set_height (Larger);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (height == hLarger) {
|
|
|
|
if (bigger) set_height (Large);
|
|
|
|
else set_height (Normal);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (height == hNormal) {
|
|
|
|
if (bigger) set_height (Larger);
|
|
|
|
else set_height (Smaller);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (height == hSmaller) {
|
|
|
|
if (bigger) set_height (Normal);
|
|
|
|
else set_height (Small);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (height == hSmall) {
|
|
|
|
if (bigger) set_height (Smaller);
|
|
|
|
return;
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
void
|
|
|
|
TimeAxisView::set_heights (TrackHeight h)
|
|
|
|
{
|
|
|
|
TrackSelection& ts (editor.get_selection().tracks);
|
|
|
|
|
|
|
|
for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
|
|
|
|
(*i)->set_height (h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
TimeAxisView::set_height (TrackHeight h)
|
|
|
|
{
|
2006-01-17 21:56:51 -05:00
|
|
|
height_style = h;
|
|
|
|
set_height_pixels (height_to_pixels (h));
|
2008-02-10 13:16:25 -05:00
|
|
|
|
|
|
|
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
|
|
|
|
(*i)->set_height ();
|
|
|
|
}
|
2006-01-17 21:56:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::set_height_pixels (uint32_t h)
|
|
|
|
{
|
|
|
|
height = h;
|
2008-01-13 12:45:17 -05:00
|
|
|
controls_hbox.set_size_request (-1, height + ((order == 0) ? 1 : 0));
|
2008-01-10 16:20:59 -05:00
|
|
|
//cerr << "TimeAxisView::set_height_pixels() called h = " << h << endl;//DEBUG
|
2005-11-28 17:36:26 -05:00
|
|
|
if (canvas_item_visible (selection_group)) {
|
2005-09-25 14:42:24 -04:00
|
|
|
/* resize the selection rect */
|
|
|
|
show_selection (editor.get_selection().time);
|
|
|
|
}
|
2008-01-10 16:20:59 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
bool
|
|
|
|
TimeAxisView::name_entry_key_release (GdkEventKey* ev)
|
|
|
|
{
|
2006-11-19 11:45:16 -05:00
|
|
|
PublicEditor::TrackViewList *allviews = 0;
|
|
|
|
PublicEditor::TrackViewList::iterator i;
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
switch (ev->keyval) {
|
2006-11-19 11:45:16 -05:00
|
|
|
case GDK_Escape:
|
|
|
|
name_entry.select_region (0,0);
|
|
|
|
controls_ebox.grab_focus ();
|
|
|
|
name_entry_changed ();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
|
|
|
|
* generates a different ev->keyval, rather than setting
|
|
|
|
* ev->state.
|
|
|
|
*/
|
|
|
|
case GDK_ISO_Left_Tab:
|
2005-12-12 15:54:55 -05:00
|
|
|
case GDK_Tab:
|
2006-11-19 11:45:16 -05:00
|
|
|
name_entry_changed ();
|
|
|
|
allviews = editor.get_valid_views (0);
|
|
|
|
if (allviews != 0) {
|
|
|
|
i = find (allviews->begin(), allviews->end(), this);
|
|
|
|
if (ev->keyval == GDK_Tab) {
|
|
|
|
if (i != allviews->end()) {
|
|
|
|
do {
|
|
|
|
if (++i == allviews->end()) { return true; }
|
|
|
|
} while((*i)->hidden());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (i != allviews->begin()) {
|
|
|
|
do {
|
|
|
|
if (--i == allviews->begin()) { return true; }
|
|
|
|
} while ((*i)->hidden());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*i)->height_style == Small) {
|
|
|
|
(*i)->set_height(Smaller);
|
|
|
|
}
|
|
|
|
|
|
|
|
(*i)->name_entry.grab_focus();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2005-12-12 15:54:55 -05:00
|
|
|
case GDK_Up:
|
|
|
|
case GDK_Down:
|
|
|
|
name_entry_changed ();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TIMEOUT_NAME_EDIT
|
|
|
|
/* adapt the timeout to reflect the user's typing speed */
|
|
|
|
|
|
|
|
guint32 name_entry_timeout;
|
|
|
|
|
|
|
|
if (last_name_entry_key_press_event) {
|
|
|
|
/* timeout is 1/2 second or 5 times their current inter-char typing speed */
|
|
|
|
name_entry_timeout = std::max (500U, (5 * (ev->time - last_name_entry_key_press_event)));
|
|
|
|
} else {
|
|
|
|
/* start with a 1 second timeout */
|
|
|
|
name_entry_timeout = 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_name_entry_key_press_event = ev->time;
|
|
|
|
|
|
|
|
/* wait 1 seconds and if no more keys are pressed, act as if they pressed enter */
|
|
|
|
|
|
|
|
name_entry_key_timeout.disconnect();
|
|
|
|
name_entry_key_timeout = Glib::signal_timeout().connect (mem_fun (*this, &TimeAxisView::name_entry_key_timed_out), name_entry_timeout);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TimeAxisView::name_entry_focus_in (GdkEventFocus* ev)
|
|
|
|
{
|
|
|
|
name_entry.select_region (0, -1);
|
|
|
|
name_entry.set_name ("EditorActiveTrackNameDisplay");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TimeAxisView::name_entry_focus_out (GdkEventFocus* ev)
|
|
|
|
{
|
|
|
|
/* clean up */
|
|
|
|
|
|
|
|
last_name_entry_key_press_event = 0;
|
|
|
|
name_entry_key_timeout.disconnect ();
|
|
|
|
name_entry.set_name ("EditorTrackNameDisplay");
|
2006-11-19 11:45:16 -05:00
|
|
|
name_entry.select_region (0,0);
|
2005-12-12 15:54:55 -05:00
|
|
|
|
|
|
|
/* do the real stuff */
|
|
|
|
|
|
|
|
name_entry_changed ();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TimeAxisView::name_entry_key_timed_out ()
|
|
|
|
{
|
|
|
|
name_entry_activated();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::name_entry_activated ()
|
|
|
|
{
|
|
|
|
controls_ebox.grab_focus();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::name_entry_changed ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
bool
|
2005-09-25 14:42:24 -04:00
|
|
|
TimeAxisView::name_entry_button_press (GdkEventButton *ev)
|
|
|
|
{
|
|
|
|
if (ev->button == 3) {
|
2005-11-12 17:07:07 -05:00
|
|
|
return true;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2005-11-12 22:53:51 -05:00
|
|
|
return false;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-11-12 17:07:07 -05:00
|
|
|
bool
|
2005-09-25 14:42:24 -04:00
|
|
|
TimeAxisView::name_entry_button_release (GdkEventButton *ev)
|
|
|
|
{
|
|
|
|
if (ev->button == 3) {
|
|
|
|
popup_display_menu (ev->time);
|
2005-11-12 17:07:07 -05:00
|
|
|
return true;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2005-11-12 17:07:07 -05:00
|
|
|
return false;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2008-04-11 10:06:50 -04:00
|
|
|
void
|
|
|
|
TimeAxisView::conditionally_add_to_selection ()
|
|
|
|
{
|
|
|
|
Selection& s (editor.get_selection());
|
|
|
|
|
|
|
|
if (!s.selected (this)) {
|
|
|
|
cerr << "set selected track\n";
|
|
|
|
editor.set_selected_track (*this, Selection::Set);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
void
|
|
|
|
TimeAxisView::popup_display_menu (guint32 when)
|
|
|
|
{
|
|
|
|
if (display_menu == 0) {
|
|
|
|
build_display_menu ();
|
|
|
|
}
|
2007-04-12 19:20:37 -04:00
|
|
|
|
2008-04-11 10:06:50 -04:00
|
|
|
conditionally_add_to_selection ();
|
2005-09-25 14:42:24 -04:00
|
|
|
display_menu->popup (1, when);
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
TimeAxisView::size_click (GdkEventButton *ev)
|
|
|
|
{
|
2008-04-11 10:06:50 -04:00
|
|
|
conditionally_add_to_selection ();
|
2005-09-25 14:42:24 -04:00
|
|
|
popup_size_menu (ev->time);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::popup_size_menu (guint32 when)
|
|
|
|
{
|
|
|
|
if (size_menu == 0) {
|
|
|
|
build_size_menu ();
|
|
|
|
}
|
|
|
|
size_menu->popup (1, when);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::set_selected (bool yn)
|
|
|
|
{
|
2007-11-07 20:40:25 -05:00
|
|
|
if (yn == _selected) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Selectable::set_selected (yn);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if (_selected) {
|
|
|
|
controls_ebox.set_name (controls_base_selected_name);
|
2008-01-13 12:45:17 -05:00
|
|
|
controls_hbox.set_name (controls_base_selected_name);
|
2008-02-16 17:43:18 -05:00
|
|
|
controls_vbox.set_name (controls_base_selected_name);
|
2005-09-25 14:42:24 -04:00
|
|
|
/* propagate any existing selection, if the mode is right */
|
|
|
|
|
|
|
|
if (editor.current_mouse_mode() == Editing::MouseRange && !editor.get_selection().time.empty()) {
|
|
|
|
show_selection (editor.get_selection().time);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
controls_ebox.set_name (controls_base_unselected_name);
|
2008-01-13 12:45:17 -05:00
|
|
|
controls_hbox.set_name (controls_base_unselected_name);
|
2008-02-16 17:43:18 -05:00
|
|
|
controls_vbox.set_name (controls_base_unselected_name);
|
2005-09-25 14:42:24 -04:00
|
|
|
hide_selection ();
|
|
|
|
|
|
|
|
/* children will be set for the yn=true case. but when deselecting
|
|
|
|
the editor only has a list of top-level trackviews, so we
|
|
|
|
have to do this here.
|
|
|
|
*/
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->set_selected (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::build_size_menu ()
|
|
|
|
{
|
|
|
|
using namespace Menu_Helpers;
|
|
|
|
|
|
|
|
size_menu = new Menu;
|
|
|
|
size_menu->set_name ("ArdourContextMenu");
|
|
|
|
MenuList& items = size_menu->items();
|
|
|
|
|
2008-02-16 17:43:18 -05:00
|
|
|
items.push_back (MenuElem (_("Largest"), bind (mem_fun (*this, &TimeAxisView::set_heights), Largest)));
|
|
|
|
items.push_back (MenuElem (_("Large"), bind (mem_fun (*this, &TimeAxisView::set_heights), Large)));
|
|
|
|
items.push_back (MenuElem (_("Larger"), bind (mem_fun (*this, &TimeAxisView::set_heights), Larger)));
|
|
|
|
items.push_back (MenuElem (_("Normal"), bind (mem_fun (*this, &TimeAxisView::set_heights), Normal)));
|
|
|
|
items.push_back (MenuElem (_("Smaller"), bind (mem_fun (*this, &TimeAxisView::set_heights),Smaller)));
|
|
|
|
items.push_back (MenuElem (_("Small"), bind (mem_fun (*this, &TimeAxisView::set_heights), Small)));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::build_display_menu ()
|
|
|
|
{
|
|
|
|
using namespace Menu_Helpers;
|
|
|
|
|
|
|
|
display_menu = new Menu;
|
|
|
|
display_menu->set_name ("ArdourContextMenu");
|
|
|
|
|
|
|
|
// Just let implementing classes define what goes into the manu
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::set_samples_per_unit (double spu)
|
|
|
|
{
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->set_samples_per_unit (spu);
|
|
|
|
}
|
2008-03-17 16:54:03 -04:00
|
|
|
|
|
|
|
AnalysisFeatureList::const_iterator i;
|
|
|
|
list<ArdourCanvas::SimpleLine*>::iterator l;
|
|
|
|
|
|
|
|
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
|
|
|
|
(*l)->property_x1() = editor.frame_to_pixel (*i);
|
|
|
|
(*l)->property_x2() = editor.frame_to_pixel (*i);
|
|
|
|
}
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
TimeAxisView::show_timestretch (nframes_t start, nframes_t end)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->show_timestretch (start, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide_timestretch ()
|
|
|
|
{
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->hide_timestretch ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::show_selection (TimeSelection& ts)
|
|
|
|
{
|
|
|
|
double x1;
|
|
|
|
double x2;
|
|
|
|
double y2;
|
|
|
|
SelectionRect *rect;
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->show_selection (ts);
|
|
|
|
}
|
|
|
|
|
2005-11-28 17:36:26 -05:00
|
|
|
if (canvas_item_visible (selection_group)) {
|
2005-09-25 14:42:24 -04:00
|
|
|
while (!used_selection_rects.empty()) {
|
|
|
|
free_selection_rects.push_front (used_selection_rects.front());
|
|
|
|
used_selection_rects.pop_front();
|
2005-11-13 13:13:50 -05:00
|
|
|
free_selection_rects.front()->rect->hide();
|
|
|
|
free_selection_rects.front()->start_trim->hide();
|
|
|
|
free_selection_rects.front()->end_trim->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2005-11-12 22:53:51 -05:00
|
|
|
selection_group->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-11-12 22:53:51 -05:00
|
|
|
selection_group->show();
|
|
|
|
selection_group->raise_to_top();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
for (list<AudioRange>::iterator i = ts.begin(); i != ts.end(); ++i) {
|
2006-10-21 15:01:50 -04:00
|
|
|
nframes_t start, end, cnt;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
start = (*i).start;
|
|
|
|
end = (*i).end;
|
|
|
|
cnt = end - start + 1;
|
|
|
|
|
|
|
|
rect = get_selection_rect ((*i).id);
|
|
|
|
|
2006-02-07 08:58:33 -05:00
|
|
|
x1 = editor.frame_to_unit (start);
|
|
|
|
x2 = editor.frame_to_unit (start + cnt - 1);
|
2005-09-25 14:42:24 -04:00
|
|
|
y2 = height;
|
|
|
|
|
2005-11-28 17:36:26 -05:00
|
|
|
rect->rect->property_x1() = x1;
|
|
|
|
rect->rect->property_y1() = 1.0;
|
|
|
|
rect->rect->property_x2() = x2;
|
|
|
|
rect->rect->property_y2() = y2;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
// trim boxes are at the top for selections
|
|
|
|
|
|
|
|
if (x2 > x1) {
|
2005-11-28 17:36:26 -05:00
|
|
|
rect->start_trim->property_x1() = x1;
|
|
|
|
rect->start_trim->property_y1() = 1.0;
|
|
|
|
rect->start_trim->property_x2() = x1 + trim_handle_size;
|
|
|
|
rect->start_trim->property_y2() = 1.0 + trim_handle_size;
|
|
|
|
|
|
|
|
rect->end_trim->property_x1() = x2 - trim_handle_size;
|
|
|
|
rect->end_trim->property_y1() = 1.0;
|
|
|
|
rect->end_trim->property_x2() = x2;
|
|
|
|
rect->end_trim->property_y2() = 1.0 + trim_handle_size;
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->start_trim->show();
|
|
|
|
rect->end_trim->show();
|
2005-09-25 14:42:24 -04:00
|
|
|
} else {
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->start_trim->hide();
|
|
|
|
rect->end_trim->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->rect->show ();
|
2005-09-25 14:42:24 -04:00
|
|
|
used_selection_rects.push_back (rect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::reshow_selection (TimeSelection& ts)
|
|
|
|
{
|
|
|
|
show_selection (ts);
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->show_selection (ts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide_selection ()
|
|
|
|
{
|
2005-11-28 17:36:26 -05:00
|
|
|
if (canvas_item_visible (selection_group)) {
|
2005-09-25 14:42:24 -04:00
|
|
|
while (!used_selection_rects.empty()) {
|
|
|
|
free_selection_rects.push_front (used_selection_rects.front());
|
|
|
|
used_selection_rects.pop_front();
|
2005-11-13 13:13:50 -05:00
|
|
|
free_selection_rects.front()->rect->hide();
|
|
|
|
free_selection_rects.front()->start_trim->hide();
|
|
|
|
free_selection_rects.front()->end_trim->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
2005-11-12 22:53:51 -05:00
|
|
|
selection_group->hide();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2005-09-25 14:42:24 -04:00
|
|
|
(*i)->hide_selection ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2005-11-14 11:24:21 -05:00
|
|
|
TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on_top)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
/* find the selection rect this is for. we have the item corresponding to one
|
|
|
|
of the trim handles.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
|
2005-11-13 13:13:50 -05:00
|
|
|
if ((*i)->start_trim == item || (*i)->end_trim == item) {
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
/* make one trim handle be "above" the other so that if they overlap,
|
|
|
|
the top one is the one last used.
|
|
|
|
*/
|
2005-11-13 13:13:50 -05:00
|
|
|
|
|
|
|
(*i)->rect->raise_to_top ();
|
|
|
|
(put_start_on_top ? (*i)->start_trim : (*i)->end_trim)->raise_to_top ();
|
|
|
|
(put_start_on_top ? (*i)->end_trim : (*i)->start_trim)->raise_to_top ();
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SelectionRect *
|
|
|
|
TimeAxisView::get_selection_rect (uint32_t id)
|
|
|
|
{
|
|
|
|
SelectionRect *rect;
|
|
|
|
|
|
|
|
/* check to see if we already have a visible rect for this particular selection ID */
|
|
|
|
|
|
|
|
for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
|
|
|
|
if ((*i)->id == id) {
|
|
|
|
return (*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ditto for the free rect list */
|
|
|
|
|
|
|
|
for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
|
|
|
|
if ((*i)->id == id) {
|
2007-01-09 18:24:54 -05:00
|
|
|
SelectionRect* ret = (*i);
|
2005-09-25 14:42:24 -04:00
|
|
|
free_selection_rects.erase (i);
|
2007-01-09 18:24:54 -05:00
|
|
|
return ret;
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no existing matching rect, so go get a new one from the free list, or create one if there are none */
|
|
|
|
|
|
|
|
if (free_selection_rects.empty()) {
|
|
|
|
|
|
|
|
rect = new SelectionRect;
|
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->rect = new SimpleRect (*selection_group);
|
|
|
|
rect->rect->property_x1() = 0.0;
|
|
|
|
rect->rect->property_y1() = 0.0;
|
|
|
|
rect->rect->property_x2() = 0.0;
|
|
|
|
rect->rect->property_y2() = 0.0;
|
2007-06-29 13:13:09 -04:00
|
|
|
rect->rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectionRect.get();
|
|
|
|
rect->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->start_trim = new SimpleRect (*selection_group);
|
|
|
|
rect->start_trim->property_x1() = 0.0;
|
|
|
|
rect->start_trim->property_x2() = 0.0;
|
2007-06-29 13:13:09 -04:00
|
|
|
rect->start_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
rect->start_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2005-11-13 13:13:50 -05:00
|
|
|
rect->end_trim = new SimpleRect (*selection_group);
|
|
|
|
rect->end_trim->property_x1() = 0.0;
|
|
|
|
rect->end_trim->property_x2() = 0.0;
|
2007-06-29 13:13:09 -04:00
|
|
|
rect->end_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
rect->end_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2005-11-13 13:13:50 -05:00
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
free_selection_rects.push_front (rect);
|
|
|
|
|
2005-11-14 11:24:21 -05:00
|
|
|
rect->rect->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_rect_event), rect->rect, rect));
|
|
|
|
rect->start_trim->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_start_trim_event), rect->rect, rect));
|
|
|
|
rect->end_trim->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_end_trim_event), rect->rect, rect));
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
rect = free_selection_rects.front();
|
|
|
|
rect->id = id;
|
|
|
|
free_selection_rects.pop_front();
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
struct null_deleter { void operator()(void const *) const {} };
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
bool
|
|
|
|
TimeAxisView::is_child (TimeAxisView* tav)
|
|
|
|
{
|
2007-06-30 14:41:50 -04:00
|
|
|
return find (children.begin(), children.end(), boost::shared_ptr<TimeAxisView>(tav, null_deleter())) != children.end();
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-06-30 14:41:50 -04:00
|
|
|
TimeAxisView::add_child (boost::shared_ptr<TimeAxisView> child)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
children.push_back (child);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-06-30 14:41:50 -04:00
|
|
|
TimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> child)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
2007-06-30 14:41:50 -04:00
|
|
|
Children::iterator i;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
if ((i = find (children.begin(), children.end(), child)) != children.end()) {
|
|
|
|
children.erase (i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-10-21 15:01:50 -04:00
|
|
|
TimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& result)
|
2005-09-25 14:42:24 -04:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-10 13:16:25 -05:00
|
|
|
void
|
|
|
|
TimeAxisView::add_ghost (RegionView* rv) {
|
|
|
|
GhostRegion* gr = rv->add_ghost (*this);
|
|
|
|
|
|
|
|
if(gr) {
|
|
|
|
ghosts.push_back(gr);
|
|
|
|
gr->GoingAway.connect (mem_fun(*this, &TimeAxisView::erase_ghost));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::remove_ghost (RegionView* rv) {
|
|
|
|
rv->remove_ghost_in (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::erase_ghost (GhostRegion* gr) {
|
|
|
|
if(in_destructor) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
list<GhostRegion*>::iterator i;
|
|
|
|
|
|
|
|
for (i = ghosts.begin(); i != ghosts.end(); ++i) {
|
|
|
|
if ((*i) == gr) {
|
|
|
|
ghosts.erase (i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-25 14:42:24 -04:00
|
|
|
bool
|
|
|
|
TimeAxisView::touched (double top, double bot)
|
|
|
|
{
|
|
|
|
/* remember: this is X Window - coordinate space starts in upper left and moves down.
|
|
|
|
y_position is the "origin" or "top" of the track.
|
|
|
|
*/
|
|
|
|
|
2007-03-19 03:07:38 -04:00
|
|
|
double mybot = y_position + height;
|
2005-09-25 14:42:24 -04:00
|
|
|
|
|
|
|
return ((y_position <= bot && y_position >= top) ||
|
|
|
|
((mybot <= bot) && (top < mybot)) ||
|
|
|
|
(mybot >= bot && y_position < top));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::set_parent (TimeAxisView& p)
|
|
|
|
{
|
|
|
|
parent = &p;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TimeAxisView::has_state () const
|
|
|
|
{
|
|
|
|
return _has_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
TimeAxisView*
|
|
|
|
TimeAxisView::get_parent_with_state ()
|
|
|
|
{
|
|
|
|
if (parent == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent->has_state()) {
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent->get_parent_with_state ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::set_state (const XMLNode& node)
|
|
|
|
{
|
|
|
|
const XMLProperty *prop;
|
|
|
|
|
|
|
|
if ((prop = node.property ("track_height")) != 0) {
|
|
|
|
|
|
|
|
if (prop->value() == "largest") {
|
|
|
|
set_height (Largest);
|
|
|
|
} else if (prop->value() == "large") {
|
|
|
|
set_height (Large);
|
|
|
|
} else if (prop->value() == "larger") {
|
|
|
|
set_height (Larger);
|
|
|
|
} else if (prop->value() == "normal") {
|
|
|
|
set_height (Normal);
|
|
|
|
} else if (prop->value() == "smaller") {
|
|
|
|
set_height (Smaller);
|
|
|
|
} else if (prop->value() == "small") {
|
|
|
|
set_height (Small);
|
|
|
|
} else {
|
2005-10-06 15:10:57 -04:00
|
|
|
error << string_compose(_("unknown track height name \"%1\" in XML GUI information"), prop->value()) << endmsg;
|
2005-09-25 14:42:24 -04:00
|
|
|
set_height (Normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
set_height (Normal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::reset_height()
|
|
|
|
{
|
2006-01-17 21:56:51 -05:00
|
|
|
set_height_pixels (height);
|
2005-09-25 14:42:24 -04:00
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2006-07-13 23:43:32 -04:00
|
|
|
(*i)->set_height_pixels ((TrackHeight)(*i)->height);
|
2005-09-25 14:42:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-17 21:56:51 -05:00
|
|
|
uint32_t
|
|
|
|
TimeAxisView::height_to_pixels (TrackHeight h)
|
|
|
|
{
|
|
|
|
switch (h) {
|
|
|
|
case Largest:
|
|
|
|
return hLargest;
|
|
|
|
case Large:
|
|
|
|
return hLarge;
|
|
|
|
case Larger:
|
|
|
|
return hLarger;
|
|
|
|
case Normal:
|
|
|
|
return hNormal;
|
|
|
|
case Smaller:
|
|
|
|
return hSmaller;
|
|
|
|
case Small:
|
|
|
|
return hSmall;
|
|
|
|
}
|
|
|
|
|
|
|
|
// what is wrong with gcc ?
|
|
|
|
|
|
|
|
return hNormal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::compute_controls_size_info ()
|
|
|
|
{
|
|
|
|
Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
|
2006-01-19 22:03:15 -05:00
|
|
|
Gtk::Table two_row_table (2, 8);
|
|
|
|
Gtk::Table one_row_table (1, 8);
|
2006-01-17 21:56:51 -05:00
|
|
|
Button* buttons[5];
|
2006-03-30 20:48:13 -05:00
|
|
|
const int border_width = 2;
|
|
|
|
const int extra_height = (2 * border_width) + 2; // 2 pixels for the controls frame
|
2006-01-17 21:56:51 -05:00
|
|
|
|
|
|
|
window.add (one_row_table);
|
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
one_row_table.set_border_width (border_width);
|
2006-01-17 21:56:51 -05:00
|
|
|
one_row_table.set_row_spacings (0);
|
|
|
|
one_row_table.set_col_spacings (0);
|
|
|
|
one_row_table.set_homogeneous (true);
|
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
two_row_table.set_border_width (border_width);
|
2006-01-17 21:56:51 -05:00
|
|
|
two_row_table.set_row_spacings (0);
|
|
|
|
two_row_table.set_col_spacings (0);
|
|
|
|
two_row_table.set_homogeneous (true);
|
|
|
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
buttons[i] = manage (new Button (X_("f")));
|
|
|
|
buttons[i]->set_name ("TrackMuteButton");
|
|
|
|
}
|
|
|
|
|
|
|
|
one_row_table.attach (*buttons[0], 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
|
|
|
|
|
|
|
|
one_row_table.show_all ();
|
2007-03-18 02:07:08 -04:00
|
|
|
Gtk::Requisition req(one_row_table.size_request ());
|
2006-01-17 21:56:51 -05:00
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
|
2006-01-17 21:56:51 -05:00
|
|
|
// height required to show 1 row of buttons
|
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
hSmaller = req.height + extra_height;
|
2006-01-17 21:56:51 -05:00
|
|
|
|
|
|
|
window.remove ();
|
|
|
|
window.add (two_row_table);
|
|
|
|
|
2006-01-19 22:03:15 -05:00
|
|
|
two_row_table.attach (*buttons[1], 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
|
|
|
|
two_row_table.attach (*buttons[2], 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
|
|
|
|
two_row_table.attach (*buttons[3], 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
|
|
|
|
two_row_table.attach (*buttons[4], 8, 9, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
|
2006-01-17 21:56:51 -05:00
|
|
|
|
|
|
|
two_row_table.show_all ();
|
2007-03-18 02:07:08 -04:00
|
|
|
req = two_row_table.size_request ();
|
2006-01-17 21:56:51 -05:00
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
// height required to show all normal buttons
|
2006-01-17 21:56:51 -05:00
|
|
|
|
2006-03-30 20:48:13 -05:00
|
|
|
hNormal = req.height + extra_height;
|
2006-01-17 21:56:51 -05:00
|
|
|
|
|
|
|
// these heights are all just larger than normal. no more
|
|
|
|
// elements are visible (yet).
|
|
|
|
|
|
|
|
hLarger = hNormal + 50;
|
|
|
|
hLarge = hNormal + 150;
|
|
|
|
hLargest = hNormal + 250;
|
|
|
|
|
|
|
|
// height required to show track name
|
|
|
|
|
|
|
|
hSmall = 27;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::show_name_label ()
|
|
|
|
{
|
|
|
|
if (!(name_packing & NameLabelPacked)) {
|
|
|
|
name_hbox.pack_start (name_label, true, true);
|
|
|
|
name_packing = NamePackingBits (name_packing | NameLabelPacked);
|
|
|
|
name_hbox.show ();
|
|
|
|
name_label.show ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-03 00:40:21 -05:00
|
|
|
void
|
2006-01-17 21:56:51 -05:00
|
|
|
TimeAxisView::show_name_entry ()
|
2006-01-03 00:40:21 -05:00
|
|
|
{
|
2006-01-17 21:56:51 -05:00
|
|
|
if (!(name_packing & NameEntryPacked)) {
|
|
|
|
name_hbox.pack_start (name_entry, true, true);
|
|
|
|
name_packing = NamePackingBits (name_packing | NameEntryPacked);
|
|
|
|
name_hbox.show ();
|
|
|
|
name_entry.show ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide_name_label ()
|
|
|
|
{
|
|
|
|
if (name_packing & NameLabelPacked) {
|
|
|
|
name_hbox.remove (name_label);
|
|
|
|
name_packing = NamePackingBits (name_packing & ~NameLabelPacked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide_name_entry ()
|
|
|
|
{
|
|
|
|
if (name_packing & NameEntryPacked) {
|
|
|
|
name_hbox.remove (name_entry);
|
|
|
|
name_packing = NamePackingBits (name_packing & ~NameEntryPacked);
|
|
|
|
}
|
2006-01-03 00:40:21 -05:00
|
|
|
}
|
2006-02-14 12:19:58 -05:00
|
|
|
|
|
|
|
void
|
2007-06-15 18:08:27 -04:00
|
|
|
TimeAxisView::color_handler ()
|
2006-02-14 12:19:58 -05:00
|
|
|
{
|
2008-02-10 13:16:25 -05:00
|
|
|
for (list<GhostRegion*>::iterator i=ghosts.begin(); i != ghosts.end(); i++ ) {
|
|
|
|
(*i)->set_colors();
|
|
|
|
}
|
|
|
|
|
2007-06-15 18:08:27 -04:00
|
|
|
for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
|
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectionRect.get();
|
|
|
|
(*i)->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2007-06-15 18:08:27 -04:00
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->start_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
(*i)->start_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2007-06-15 18:08:27 -04:00
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->end_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
(*i)->end_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2007-06-15 18:08:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
|
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectionRect.get();
|
|
|
|
(*i)->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2007-06-15 18:08:27 -04:00
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->start_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
(*i)->start_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2007-06-15 18:08:27 -04:00
|
|
|
|
2007-06-29 13:13:09 -04:00
|
|
|
(*i)->end_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
|
|
|
(*i)->end_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
|
2006-02-14 12:19:58 -05:00
|
|
|
}
|
|
|
|
}
|
2006-07-23 08:03:19 -04:00
|
|
|
|
2007-01-09 18:24:54 -05:00
|
|
|
TimeAxisView*
|
|
|
|
TimeAxisView::covers_y_position (double y)
|
|
|
|
{
|
|
|
|
if (hidden()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (y_position <= y && y < (y_position + height)) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2007-06-30 14:41:50 -04:00
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
|
2007-01-09 18:24:54 -05:00
|
|
|
TimeAxisView* tv;
|
|
|
|
|
|
|
|
if ((tv = (*i)->covers_y_position (y)) != 0) {
|
|
|
|
return tv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-02-01 22:57:35 -05:00
|
|
|
|
|
|
|
void
|
2008-03-17 16:54:03 -04:00
|
|
|
TimeAxisView::show_feature_lines (const AnalysisFeatureList& pos)
|
2008-02-01 22:57:35 -05:00
|
|
|
{
|
2008-03-17 16:54:03 -04:00
|
|
|
analysis_features = pos;
|
|
|
|
reshow_feature_lines ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::hide_feature_lines ()
|
|
|
|
{
|
|
|
|
list<ArdourCanvas::SimpleLine*>::iterator l;
|
|
|
|
|
|
|
|
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
|
|
|
|
(*l)->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TimeAxisView::reshow_feature_lines ()
|
|
|
|
{
|
|
|
|
while (feature_lines.size()< analysis_features.size()) {
|
2008-02-01 22:57:35 -05:00
|
|
|
ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*canvas_display);
|
|
|
|
l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
|
|
|
|
l->property_y1() = 0;
|
|
|
|
l->property_y2() = height;
|
2008-03-17 16:54:03 -04:00
|
|
|
feature_lines.push_back (l);
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
while (feature_lines.size() > analysis_features.size()) {
|
|
|
|
ArdourCanvas::SimpleLine *line = feature_lines.back();
|
|
|
|
feature_lines.pop_back ();
|
2008-02-01 22:57:35 -05:00
|
|
|
delete line;
|
|
|
|
}
|
|
|
|
|
2008-02-02 12:22:04 -05:00
|
|
|
AnalysisFeatureList::const_iterator i;
|
2008-02-01 22:57:35 -05:00
|
|
|
list<ArdourCanvas::SimpleLine*>::iterator l;
|
|
|
|
|
2008-03-17 16:54:03 -04:00
|
|
|
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
|
2008-02-01 22:57:35 -05:00
|
|
|
(*l)->property_x1() = editor.frame_to_pixel (*i);
|
|
|
|
(*l)->property_x2() = editor.frame_to_pixel (*i);
|
2008-03-17 16:54:03 -04:00
|
|
|
(*l)->show ();
|
2008-02-01 22:57:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|