summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/audio_region_view.cc6
-rw-r--r--gtk2_ardour/canvas-note-event.cc5
-rw-r--r--gtk2_ardour/canvas-note-event.h3
-rw-r--r--gtk2_ardour/editor.cc12
-rw-r--r--gtk2_ardour/editor.h10
-rw-r--r--gtk2_ardour/editor_audio_import.cc12
-rw-r--r--gtk2_ardour/editor_canvas.cc17
-rw-r--r--gtk2_ardour/editor_drag.cc10
-rw-r--r--gtk2_ardour/editor_mouse.cc117
-rw-r--r--gtk2_ardour/editor_ops.cc16
-rw-r--r--gtk2_ardour/icons/grabber.pngbin0 -> 488 bytes
-rw-r--r--gtk2_ardour/midi_region_view.cc19
-rw-r--r--gtk2_ardour/midi_region_view.h6
-rw-r--r--gtk2_ardour/public_editor.h7
-rw-r--r--libs/ardour/ardour/movable.h15
-rw-r--r--libs/ardour/ardour/region.h6
-rw-r--r--libs/ardour/ardour/trimmable.h36
-rw-r--r--libs/ardour/region.cc28
-rw-r--r--libs/pbd/enumwriter.cc51
-rw-r--r--libs/pbd/pbd/enumwriter.h3
20 files changed, 297 insertions, 82 deletions
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index c3e0bd0898..24a33893db 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -1242,6 +1242,9 @@ AudioRegionView::add_ghost (TimeAxisView& tv)
void
AudioRegionView::entered (bool internal_editing)
{
+ trackview.editor().set_current_trimmable (_region);
+ trackview.editor().set_current_movable (_region);
+
if (gain_line && _flags & EnvelopeVisible) {
gain_line->show_all_control_points ();
}
@@ -1259,6 +1262,9 @@ AudioRegionView::entered (bool internal_editing)
void
AudioRegionView::exited ()
{
+ trackview.editor().set_current_trimmable (boost::shared_ptr<Trimmable>());
+ trackview.editor().set_current_movable (boost::shared_ptr<Movable>());
+
if (gain_line) {
gain_line->hide_all_but_selected_control_points ();
}
diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc
index b1bfa49ab4..a3a5dd9a1a 100644
--- a/gtk2_ardour/canvas-note-event.cc
+++ b/gtk2_ardour/canvas-note-event.cc
@@ -230,15 +230,18 @@ CanvasNoteEvent::set_mouse_fractions (GdkEvent* ev)
{
double ix, iy;
double bx1, bx2, by1, by2;
+ bool set_cursor = false;
switch (ev->type) {
case GDK_MOTION_NOTIFY:
ix = ev->motion.x;
iy = ev->motion.y;
+ set_cursor = true;
break;
case GDK_ENTER_NOTIFY:
ix = ev->crossing.x;
iy = ev->crossing.y;
+ set_cursor = true;
break;
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
@@ -275,7 +278,7 @@ CanvasNoteEvent::set_mouse_fractions (GdkEvent* ev)
_mouse_y_fraction = yf;
if (notify) {
- _region.note_mouse_position (_mouse_x_fraction, _mouse_y_fraction);
+ _region.note_mouse_position (_mouse_x_fraction, _mouse_y_fraction, set_cursor);
}
}
diff --git a/gtk2_ardour/canvas-note-event.h b/gtk2_ardour/canvas-note-event.h
index 5267398488..191b9e2ad8 100644
--- a/gtk2_ardour/canvas-note-event.h
+++ b/gtk2_ardour/canvas-note-event.h
@@ -100,6 +100,9 @@ class CanvasNoteEvent : virtual public sigc::trackable
virtual double x2() = 0;
virtual double y2() = 0;
+ float mouse_x_fraction() const { return _mouse_x_fraction; }
+ float mouse_y_fraction() const { return _mouse_y_fraction; }
+
const boost::shared_ptr<NoteType> note() const { return _note; }
MidiRegionView& region_view() const { return _region; }
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 65130dc6de..aad0f7b11a 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -325,6 +325,7 @@ Editor::Editor ()
clicked_crossfadeview = 0;
clicked_control_point = 0;
last_update_frame = 0;
+ pre_press_cursor = 0;
_drags = new DragManager (this);
current_mixer_strip = 0;
current_bbt_points = 0;
@@ -1240,8 +1241,10 @@ Editor::build_cursors ()
transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
}
-
- grabber_cursor = new Gdk::Cursor (HAND2);
+ {
+ Glib::RefPtr<Gdk::Pixbuf> grabber_pixbuf (::get_icon ("grabber"));
+ grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0);
+ }
{
Glib::RefPtr<Gdk::Pixbuf> grabber_note_pixbuf (::get_icon ("grabber_note"));
@@ -3626,7 +3629,7 @@ Editor::clamp_verbose_cursor_y (double y)
}
void
-Editor::show_verbose_canvas_cursor_with (const string & txt)
+Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
{
verbose_canvas_cursor->property_text() = txt.c_str();
@@ -3636,6 +3639,9 @@ Editor::show_verbose_canvas_cursor_with (const string & txt)
track_canvas->get_pointer (x, y);
track_canvas->window_to_world (x, y, wx, wy);
+ wx += xoffset;
+ wy += yoffset;
+
/* don't get too close to the edge */
verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 56abdee431..f99ab00189 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -428,7 +428,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void get_regions_corresponding_to (boost::shared_ptr<ARDOUR::Region> region, std::vector<RegionView*>& regions);
- void show_verbose_canvas_cursor_with (const std::string& txt);
+ void show_verbose_canvas_cursor_with (const std::string& txt, int32_t xoffset = 0, int32_t yoffset = 0);
void hide_verbose_canvas_cursor();
void center_screen (framepos_t);
@@ -477,7 +477,9 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
static Gdk::Cursor* transparent_cursor;
Gdk::Cursor* get_canvas_cursor () const { return current_canvas_cursor; }
- void set_canvas_cursor (Gdk::Cursor*);
+ void set_canvas_cursor (Gdk::Cursor*, bool save=false);
+ void set_current_trimmable (boost::shared_ptr<ARDOUR::Trimmable>);
+ void set_current_movable (boost::shared_ptr<ARDOUR::Movable>);
protected:
void map_transport_state ();
@@ -1032,6 +1034,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
framepos_t cut_buffer_start;
framecnt_t cut_buffer_length;
+ Gdk::Cursor* pre_press_cursor;
+ boost::weak_ptr<ARDOUR::Trimmable> _trimmable;
+ boost::weak_ptr<ARDOUR::Movable> _movable;
+
bool typed_event (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool button_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool button_press_handler_1 (ArdourCanvas::Item *, GdkEvent *, ItemType);
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index d3a2dd6608..5a250a09b8 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -509,8 +509,8 @@ Editor::import_sndfiles (vector<string> paths, ImportMode mode, SrcQuality quali
import_status.target_regions = target_regions;
import_status.track = track;
import_status.replace = replace;
-
- track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
+
+ set_canvas_cursor (wait_cursor);
gdk_flush ();
/* start import thread for this spec. this will ultimately call Session::import_audiofiles()
@@ -544,7 +544,7 @@ Editor::import_sndfiles (vector<string> paths, ImportMode mode, SrcQuality quali
}
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
return 0;
}
@@ -560,7 +560,7 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
int ret = 0;
string path_to_use;
- track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
+ set_canvas_cursor (wait_cursor);
gdk_flush ();
for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
@@ -671,7 +671,7 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
}
}
- track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
+ set_canvas_cursor (wait_cursor);
for (int n = 0; n < finfo.channels; ++n) {
try {
@@ -712,7 +712,7 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
ret = add_sources (paths, sources, pos, mode, target_regions, target_tracks, track, true);
out:
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
return ret;
}
diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc
index faf2c7e19e..7da1464bf8 100644
--- a/gtk2_ardour/editor_canvas.cc
+++ b/gtk2_ardour/editor_canvas.cc
@@ -426,7 +426,7 @@ bool
Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
{
if (current_canvas_cursor) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
return false;
}
@@ -568,7 +568,7 @@ Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert)
}
}
- if ((autoscroll_x != last_autoscroll_x) || (autoscroll_y != last_autoscroll_y) || (autoscroll_x == 0 && autoscroll_y == 0)) {
+ if (autoscroll_active && ((autoscroll_x != last_autoscroll_x) || (autoscroll_y != last_autoscroll_y) || (autoscroll_x == 0 && autoscroll_y == 0))) {
stop_canvas_autoscroll ();
}
@@ -918,12 +918,15 @@ Editor::horizontal_position () const
return frame_to_unit (leftmost_frame);
}
void
-Editor::set_canvas_cursor (Gdk::Cursor* cursor)
+Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
{
+ if (save) {
+ current_canvas_cursor = cursor;
+ }
+
if (is_drawable()) {
- track_canvas->get_window()->set_cursor(*cursor);
+ track_canvas->get_window()->set_cursor (*cursor);
}
-
}
bool
@@ -931,7 +934,7 @@ Editor::track_canvas_key_press (GdkEventKey* event)
{
/* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
- track_canvas->get_window()->set_cursor (*zoom_out_cursor);
+ set_canvas_cursor (zoom_out_cursor);
}
return false;
@@ -941,7 +944,7 @@ bool
Editor::track_canvas_key_release (GdkEventKey* event)
{
if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
- track_canvas->get_window()->set_cursor (*zoom_in_cursor);
+ set_canvas_cursor (zoom_in_cursor);
}
return false;
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index c4040c346d..33ff839ec5 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -94,7 +94,6 @@ DragManager::add (Drag* d)
void
DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
{
- assert (_drags.empty ());
d->set_manager (this);
_drags.push_back (d);
start_grab (e, c);
@@ -1403,8 +1402,15 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
{
Gdk::Cursor* cursor;
ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
+ float x_fraction = cnote->mouse_x_fraction ();
- Drag::start_grab (event);
+ if (x_fraction > 0.0 && x_fraction < 0.25) {
+ cursor = _editor->left_side_trim_cursor;
+ } else {
+ cursor = _editor->right_side_trim_cursor;
+ }
+
+ Drag::start_grab (event, cursor);
region = &cnote->region_view();
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index 45e71e7058..95fde99826 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -198,6 +198,10 @@ Editor::which_grabber_cursor ()
c = grabber_edit_point_cursor;
break;
default:
+ boost::shared_ptr<Movable> m = _movable.lock();
+ if (m && m->locked()) {
+ c = speaker_cursor;
+ }
break;
}
}
@@ -206,6 +210,29 @@ Editor::which_grabber_cursor ()
}
void
+Editor::set_current_trimmable (boost::shared_ptr<Trimmable> t)
+{
+ boost::shared_ptr<Trimmable> st = _trimmable.lock();
+
+ if (!st || st == t) {
+ _trimmable = t;
+ set_canvas_cursor ();
+ }
+
+}
+
+void
+Editor::set_current_movable (boost::shared_ptr<Movable> m)
+{
+ boost::shared_ptr<Movable> sm = _movable.lock();
+
+ if (!sm || sm != m) {
+ _movable = m;
+ set_canvas_cursor ();
+ }
+}
+
+void
Editor::set_canvas_cursor ()
{
if (_internal_editing) {
@@ -277,9 +304,7 @@ Editor::set_canvas_cursor ()
}
}
- if (is_drawable()) {
- track_canvas->get_window()->set_cursor(*current_canvas_cursor);
- }
+ set_canvas_cursor (current_canvas_cursor, true);
}
void
@@ -679,8 +704,9 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
if (internal_editing()) {
/* trim notes if we're in internal edit mode and near the ends of the note */
ArdourCanvas::CanvasNote* cn = dynamic_cast<ArdourCanvas::CanvasNote*> (item);
+ cerr << "NoteItem button press, cursor = " << current_canvas_cursor << endl;
if (cn->mouse_near_ends()) {
- _drags->set (new NoteResizeDrag (this, item), event);
+ _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
} else {
_drags->set (new NoteDrag (this, item), event);
}
@@ -702,12 +728,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case RegionViewNameHighlight:
case LeftFrameHandle:
case RightFrameHandle:
- {
- RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
- _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
- return true;
+ if (!clicked_regionview->region()->locked()) {
+ RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
+ _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
+ return true;
+ }
break;
- }
default:
if (!internal_editing()) {
@@ -723,7 +749,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
if (internal_editing()) {
ArdourCanvas::CanvasNote* cn = dynamic_cast<ArdourCanvas::CanvasNote*> (item);
if (cn->mouse_near_ends()) {
- _drags->set (new NoteResizeDrag (this, item), event);
+ _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
} else {
_drags->set (new NoteDrag (this, item), event);
}
@@ -802,7 +828,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case RegionViewNameHighlight:
case LeftFrameHandle:
case RightFrameHandle:
- if (!internal_editing ()) {
+ if (!internal_editing () && !clicked_regionview->region()->locked()) {
RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
_drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
return true;
@@ -977,7 +1003,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case MouseTimeFX:
if (internal_editing() && item_type == NoteItem) {
/* drag notes if we're in internal edit mode */
- _drags->set (new NoteResizeDrag (this, item), event);
+ _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
return true;
} else if ((!internal_editing() || dynamic_cast<AudioRegionView*> (clicked_regionview)) && clicked_regionview) {
/* do time-FX if we're not in internal edit mode, or we are but we clicked on an audio region */
@@ -992,7 +1018,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
scrub_reverse_distance = 0;
last_scrub_x = event->button.x;
scrubbing_direction = 0;
- track_canvas->get_window()->set_cursor (*transparent_cursor);
+ set_canvas_cursor (transparent_cursor);
return true;
break;
@@ -1093,6 +1119,8 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
}
}
+ pre_press_cursor = current_canvas_cursor;
+
track_canvas->grab_focus();
if (_session && _session->actively_recording()) {
@@ -1136,6 +1164,11 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
framepos_t where = event_frame (event, 0, 0);
AutomationTimeAxisView* atv = 0;
+ if (pre_press_cursor) {
+ set_canvas_cursor (pre_press_cursor);
+ pre_press_cursor = 0;
+ }
+
/* no action if we're recording */
if (_session && _session->actively_recording()) {
@@ -1411,7 +1444,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case MouseAudition:
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
if (scrubbing_direction == 0) {
/* no drag, just a click */
switch (item_type) {
@@ -1505,7 +1538,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
fraction = 1.0 - (cp->get_y() / cp->line().height());
if (is_drawable() && !_drags->active ()) {
- track_canvas->get_window()->set_cursor (*fader_cursor);
+ set_canvas_cursor (fader_cursor);
}
set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
@@ -1519,7 +1552,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (line)
line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get();
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*fader_cursor);
+ set_canvas_cursor (fader_cursor);
}
}
break;
@@ -1532,26 +1565,36 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get();
}
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*fader_cursor);
+ set_canvas_cursor (fader_cursor);
}
}
break;
case RegionViewNameHighlight:
if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) {
- track_canvas->get_window()->set_cursor (*trimmer_cursor);
+ set_canvas_cursor (trimmer_cursor);
}
break;
case LeftFrameHandle:
if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) {
- track_canvas->get_window()->set_cursor (*left_side_trim_cursor);
+ if (entered_regionview) {
+ Trimmable::CanTrim ct = entered_regionview->region()->can_trim();
+ if ((ct & Trimmable::EndTrimEarlier) || (ct & Trimmable::EndTrimLater)) {
+ set_canvas_cursor (left_side_trim_cursor);
+ }
+ }
}
break;
case RightFrameHandle:
if (is_drawable() && mouse_mode == MouseObject && !internal_editing()) {
- track_canvas->get_window()->set_cursor (*right_side_trim_cursor);
+ if (entered_regionview) {
+ Trimmable::CanTrim ct = entered_regionview->region()->can_trim();
+ if ((ct & Trimmable::FrontTrimEarlier) || (ct & Trimmable::FrontTrimLater)) {
+ set_canvas_cursor (right_side_trim_cursor);
+ }
+ }
}
break;
@@ -1566,7 +1609,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
#endif
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*trimmer_cursor);
+ set_canvas_cursor (trimmer_cursor);
}
break;
@@ -1574,10 +1617,10 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (is_drawable()) {
switch (_edit_point) {
case EditAtMouse:
- track_canvas->get_window()->set_cursor (*grabber_edit_point_cursor);
+ set_canvas_cursor (grabber_edit_point_cursor);
break;
default:
- track_canvas->get_window()->set_cursor (*grabber_cursor);
+ set_canvas_cursor (grabber_cursor);
break;
}
}
@@ -1589,7 +1632,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
if (mouse_mode == MouseObject && is_drawable()) {
- track_canvas->get_window()->set_cursor (*trimmer_cursor);
+ set_canvas_cursor (trimmer_cursor);
}
}
break;
@@ -1610,7 +1653,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
}
- track_canvas->get_window()->set_cursor (*cursor);
+ set_canvas_cursor (cursor);
AutomationTimeAxisView* atv;
if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
@@ -1627,7 +1670,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
case MeterBarItem:
case TempoBarItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*timebar_cursor);
+ set_canvas_cursor (timebar_cursor);
}
break;
@@ -1641,7 +1684,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
case MeterMarkerItem:
case TempoMarkerItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*timebar_cursor);
+ set_canvas_cursor (timebar_cursor);
}
break;
@@ -1651,7 +1694,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (rect) {
rect->property_fill_color_rgba() = 0xBBBBBBAA;
}
- track_canvas->get_window()->set_cursor (*fade_in_cursor);
+ set_canvas_cursor (fade_in_cursor);
}
break;
@@ -1661,7 +1704,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (rect) {
rect->property_fill_color_rgba() = 0xBBBBBBAA;
}
- track_canvas->get_window()->set_cursor (*fade_out_cursor);
+ set_canvas_cursor (fade_out_cursor);
}
break;
case FeatureLineItem:
@@ -1724,7 +1767,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
}
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
hide_verbose_canvas_cursor ();
@@ -1745,7 +1788,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
#endif
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
break;
@@ -1758,7 +1801,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
line->property_fill_color_rgba() = al->get_line_color();
}
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
break;
@@ -1766,7 +1809,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
/* see enter_handler() for notes */
if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
if (is_drawable() && mouse_mode == MouseObject) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
}
break;
@@ -1778,7 +1821,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
case TempoBarItem:
case MarkerBarItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
break;
@@ -1795,7 +1838,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
case TempoMarkerItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*timebar_cursor);
+ set_canvas_cursor (timebar_cursor);
}
break;
@@ -1810,12 +1853,12 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
rect->property_outline_pixels() = 0;
}
}
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
break;
case AutomationTrackItem:
if (is_drawable()) {
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
clear_entered_track = true;
Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track));
}
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index abd319583b..751c94fefa 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -3708,14 +3708,14 @@ Editor::freeze_route ()
pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
- track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
+ set_canvas_cursor (wait_cursor);
while (!itt.done && !itt.cancel) {
gtk_main_iteration ();
}
current_interthread_info = 0;
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
void
@@ -4585,7 +4585,7 @@ Editor::normalize_region ()
begin_reversible_command (_("normalize"));
- track_canvas->get_window()->set_cursor (*wait_cursor);
+ set_canvas_cursor (wait_cursor);
gdk_flush ();
double maxamp = 0;
@@ -4613,7 +4613,7 @@ Editor::normalize_region ()
}
commit_reversible_command ();
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
_last_normalization_value = spin.get_value ();
}
@@ -4804,7 +4804,7 @@ Editor::fork_region ()
begin_reversible_command (_("Fork Region(s)"));
- track_canvas->get_window()->set_cursor (*wait_cursor);
+ set_canvas_cursor (wait_cursor);
gdk_flush ();
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
@@ -4828,7 +4828,7 @@ Editor::fork_region ()
commit_reversible_command ();
rs.clear ();
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
void
@@ -4867,7 +4867,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
begin_reversible_command (command);
- track_canvas->get_window()->set_cursor (*wait_cursor);
+ set_canvas_cursor (wait_cursor);
gdk_flush ();
int n = 0;
@@ -4929,7 +4929,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
rs.clear ();
out:
- track_canvas->get_window()->set_cursor (*current_canvas_cursor);
+ set_canvas_cursor (current_canvas_cursor);
}
void
diff --git a/gtk2_ardour/icons/grabber.png b/gtk2_ardour/icons/grabber.png
new file mode 100644
index 0000000000..4a449e752d
--- /dev/null
+++ b/gtk2_ardour/icons/grabber.png
Binary files differ
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 94083bf73d..136515c08e 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -99,6 +99,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
, _optimization_iterator (_events.end())
, _list_editor (0)
, no_sound_notes (false)
+ , pre_enter_cursor (0)
{
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
@@ -2222,7 +2223,7 @@ MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron
len = 0;
}
} else {
- if (beats >= canvas_note->note()->end_time()) {
+ if (beats >= canvas_note->note()->time()) {
len = beats - canvas_note->note()->time();
} else {
len = 0;
@@ -2479,7 +2480,7 @@ MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush)
char buf[24];
snprintf (buf, sizeof (buf), "Vel %d",
(int) (*_selection.begin())->note()->velocity());
- trackview.editor().show_verbose_canvas_cursor_with (buf);
+ trackview.editor().show_verbose_canvas_cursor_with (buf, 10, 10);
}
}
@@ -2668,11 +2669,15 @@ MidiRegionView::note_left (ArdourCanvas::CanvasNoteEvent* note)
}
editor->hide_verbose_canvas_cursor ();
- editor->set_canvas_cursor (pre_enter_cursor);
+
+ if (pre_enter_cursor) {
+ editor->set_canvas_cursor (pre_enter_cursor);
+ pre_enter_cursor = 0;
+ }
}
void
-MidiRegionView::note_mouse_position (float x_fraction, float y_fraction)
+MidiRegionView::note_mouse_position (float x_fraction, float y_fraction, bool can_set_cursor)
{
Editor* editor = dynamic_cast<Editor*>(&trackview.editor());
@@ -2681,7 +2686,9 @@ MidiRegionView::note_mouse_position (float x_fraction, float y_fraction)
} else if (x_fraction >= 0.75 && x_fraction < 1.0) {
editor->set_canvas_cursor (editor->right_side_trim_cursor);
} else {
- editor->set_canvas_cursor (pre_enter_cursor);
+ if (pre_enter_cursor && can_set_cursor) {
+ editor->set_canvas_cursor (pre_enter_cursor);
+ }
}
}
@@ -3001,7 +3008,7 @@ MidiRegionView::show_verbose_canvas_cursor (boost::shared_ptr<NoteType> n) const
Evoral::midi_note_name (n->note()).c_str(),
(int) n->note (),
(int) n->velocity());
- trackview.editor().show_verbose_canvas_cursor_with (buf);
+ trackview.editor().show_verbose_canvas_cursor_with (buf, 10, 20);
}
void
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index b2b54c5f3c..29ad2f7821 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -190,11 +190,9 @@ class MidiRegionView : public RegionView
void apply_diff_as_subcommand();
void abort_command();
- Gdk::Cursor* pre_enter_cursor;
-
void note_entered(ArdourCanvas::CanvasNoteEvent* ev);
void note_left(ArdourCanvas::CanvasNoteEvent* ev);
- void note_mouse_position (float xfraction, float yfraction);
+ void note_mouse_position (float xfraction, float yfraction, bool can_set_cursor=true);
void unique_select(ArdourCanvas::CanvasNoteEvent* ev);
void note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add, bool extend=false);
void note_deselected(ArdourCanvas::CanvasNoteEvent* ev);
@@ -434,6 +432,8 @@ class MidiRegionView : public RegionView
void get_events (Events& e, Evoral::Sequence<Evoral::MusicalTime>::NoteOperator op, uint8_t val, int chan_mask = 0);
void display_program_changes_on_channel (uint8_t);
+
+ Gdk::Cursor* pre_enter_cursor;
};
diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h
index 9c7750adca..e19ba14836 100644
--- a/gtk2_ardour/public_editor.h
+++ b/gtk2_ardour/public_editor.h
@@ -45,6 +45,8 @@ namespace ARDOUR {
class Region;
class Playlist;
class RouteGroup;
+ class Trimmable;
+ class Movable;
}
namespace Gtk {
@@ -353,9 +355,12 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible {
virtual TimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const = 0;
- virtual void show_verbose_canvas_cursor_with (const std::string& txt) = 0;
+ virtual void show_verbose_canvas_cursor_with (const std::string& txt, int32_t xoffset = 0, int32_t yoffset = 0) = 0;
virtual void hide_verbose_canvas_cursor() = 0;
+ virtual void set_current_trimmable (boost::shared_ptr<ARDOUR::Trimmable>) = 0;
+ virtual void set_current_movable (boost::shared_ptr<ARDOUR::Movable>) = 0;
+
virtual void center_screen (framepos_t) = 0;
virtual TrackViewList axis_views_from_routes (boost::shared_ptr<ARDOUR::RouteList>) const = 0;
diff --git a/libs/ardour/ardour/movable.h b/libs/ardour/ardour/movable.h
new file mode 100644
index 0000000000..26b6125888
--- /dev/null
+++ b/libs/ardour/ardour/movable.h
@@ -0,0 +1,15 @@
+#ifndef __libardour_movable_h__
+#define __libardour_movable_h__
+
+namespace ARDOUR {
+
+class Movable {
+ public:
+ Movable() {}
+
+ bool locked () const { return false; }
+};
+
+}
+
+#endif /* __libardour_movable_h__ */
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 0ae325d124..ef86dce4b2 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -31,8 +31,10 @@
#include "ardour/ardour.h"
#include "ardour/data_type.h"
#include "ardour/automatable.h"
+#include "ardour/movable.h"
#include "ardour/readable.h"
#include "ardour/session_object.h"
+#include "ardour/trimmable.h"
class XMLNode;
@@ -81,6 +83,8 @@ class Region
: public SessionObject
, public boost::enable_shared_from_this<Region>
, public Readable
+ , public Trimmable
+ , public Movable
{
public:
typedef std::vector<boost::shared_ptr<Source> > SourceList;
@@ -147,6 +151,8 @@ class Region
bool sync_marked() const { return _sync_marked; }
bool external() const { return _external; }
bool import() const { return _import; }
+
+ Trimmable::CanTrim can_trim() const;
PositionLockStyle position_lock_style() const { return _position_lock_style; }
void set_position_lock_style (PositionLockStyle ps);
diff --git a/libs/ardour/ardour/trimmable.h b/libs/ardour/ardour/trimmable.h
new file mode 100644
index 0000000000..e053a2deed
--- /dev/null
+++ b/libs/ardour/ardour/trimmable.h
@@ -0,0 +1,36 @@
+#ifndef __libardour_trimmable_h__
+#define __libardour_trimmable_h__
+
+namespace ARDOUR {
+
+class Trimmable {
+ public:
+ Trimmable() {}
+ virtual ~Trimmable() {}
+
+ enum CanTrim {
+ FrontTrimEarlier,
+ FrontTrimLater,
+ EndTrimEarlier,
+ EndTrimLater,
+ TopTrimUp,
+ TopTrimDown,
+ BottomTrimUp,
+ BottomTrimDown
+ } ;
+
+ virtual CanTrim can_trim() const {
+ return CanTrim (FrontTrimEarlier |
+ FrontTrimLater |
+ EndTrimEarlier |
+ EndTrimLater |
+ TopTrimUp |
+ TopTrimDown |
+ BottomTrimUp |
+ BottomTrimDown);
+ }
+};
+
+}
+
+#endif /* __libardour_trimmable_h__ */
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 7e78475eb3..6d4be37b6d 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -1587,3 +1587,31 @@ Region::use_sources (SourceList const & s)
}
}
}
+
+Trimmable::CanTrim
+Region::can_trim () const
+{
+ CanTrim ct = CanTrim (0);
+
+ if (locked()) {
+ return ct;
+ }
+
+ /* if not locked, we can always move the front later, and the end earlier
+ */
+
+ ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
+
+ if (start() != 0) {
+ ct = CanTrim (ct | FrontTrimEarlier);
+ }
+
+ if (!_sources.empty()) {
+ if (last_frame() < _sources.front()->length (0)) {
+ ct = CanTrim (ct | EndTrimLater);
+ }
+ }
+
+ return ct;
+}
+
diff --git a/libs/pbd/enumwriter.cc b/libs/pbd/enumwriter.cc
index 2c6e5c73c8..5263a886fb 100644
--- a/libs/pbd/enumwriter.cc
+++ b/libs/pbd/enumwriter.cc
@@ -182,6 +182,41 @@ EnumWriter::write_distinct (EnumRegistration& er, int value)
}
int
+EnumWriter::validate (EnumRegistration& er, int val)
+{
+ if (er.values.empty()) {
+ return val;
+ }
+
+ if (val == 0) {
+ /* zero is always a legal value for our enumerations, just about
+ */
+ return val;
+ }
+
+ vector<int>::iterator i;
+ string enum_name = _("unknown enumeration");
+
+ for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
+ if (&er == &(*x).second) {
+ enum_name = (*x).first;
+ }
+ }
+
+
+ for (i = er.values.begin(); i != er.values.end(); ++i) {
+ if (*i == val) {
+ return val;
+ }
+ }
+
+ warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"),
+ enum_name, val, er.names.front())
+ << endmsg;
+ return er.values.front();
+}
+
+int
EnumWriter::read_bits (EnumRegistration& er, string str)
{
vector<int>::iterator i;
@@ -193,14 +228,16 @@ EnumWriter::read_bits (EnumRegistration& er, string str)
/* catch old-style hex numerics */
if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
- return strtol (str.c_str(), (char **) 0, 16);
+ int val = strtol (str.c_str(), (char **) 0, 16);
+ return validate (er, val);
}
/* catch old style dec numerics */
if (strspn (str.c_str(), "0123456789") == str.length()) {
- return strtol (str.c_str(), (char **) 0, 10);
- }
+ int val = strtol (str.c_str(), (char **) 0, 10);
+ return validate (er, val);
+ }
do {
@@ -238,14 +275,16 @@ EnumWriter::read_distinct (EnumRegistration& er, string str)
/* catch old-style hex numerics */
if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
- return strtol (str.c_str(), (char **) 0, 16);
+ int val = strtol (str.c_str(), (char **) 0, 16);
+ return validate (er, val);
}
/* catch old style dec numerics */
if (strspn (str.c_str(), "0123456789") == str.length()) {
- return strtol (str.c_str(), (char **) 0, 10);
- }
+ int val = strtol (str.c_str(), (char **) 0, 10);
+ return validate (er, val);
+ }
for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
if (str == (*s) || nocase_cmp (str, *s) == 0) {
diff --git a/libs/pbd/pbd/enumwriter.h b/libs/pbd/pbd/enumwriter.h
index 461665d739..a253719c85 100644
--- a/libs/pbd/pbd/enumwriter.h
+++ b/libs/pbd/pbd/enumwriter.h
@@ -71,6 +71,9 @@ class EnumWriter {
static EnumWriter* _instance;
static std::map<std::string,std::string> hack_table;
+
+
+ int validate (EnumRegistration& er, int value);
};
}