summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <drobilla@leibniz.local>2014-12-20 01:11:28 -0500
committerDavid Robillard <drobilla@leibniz.local>2014-12-20 01:13:25 -0500
commit670938c8c455f2ded443d0ea222ed1cd07ecc528 (patch)
tree9c58aae398dafb1eb2d8b106a91130c27f88991f
parent5d8021bf44c066ad9b5ee4e8ab824267824be738 (diff)
Fix various cursor problems.
Add a new scoped cursor system that makes it much harder to screw up and end up with stick cursors and so on.
-rw-r--r--gtk2_ardour/cursor_context.cc62
-rw-r--r--gtk2_ardour/cursor_context.h75
-rw-r--r--gtk2_ardour/editor.cc13
-rw-r--r--gtk2_ardour/editor.h32
-rw-r--r--gtk2_ardour/editor_audio_import.cc37
-rw-r--r--gtk2_ardour/editor_canvas.cc77
-rw-r--r--gtk2_ardour/editor_drag.cc4
-rw-r--r--gtk2_ardour/editor_drag.h2
-rw-r--r--gtk2_ardour/editor_mouse.cc32
-rw-r--r--gtk2_ardour/editor_ops.cc18
-rw-r--r--gtk2_ardour/midi_region_view.cc44
-rw-r--r--gtk2_ardour/midi_region_view.h6
-rw-r--r--gtk2_ardour/wscript1
13 files changed, 254 insertions, 149 deletions
diff --git a/gtk2_ardour/cursor_context.cc b/gtk2_ardour/cursor_context.cc
new file mode 100644
index 0000000000..fed9460018
--- /dev/null
+++ b/gtk2_ardour/cursor_context.cc
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2014 Paul Davis
+ Author: David Robillard
+
+ 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 <pbd/error.h>
+
+#include "editor.h"
+#include "cursor_context.h"
+
+CursorContext::CursorContext(Editor& editor, Gdk::Cursor* cursor)
+ : _editor(editor)
+ , _index(editor.push_canvas_cursor(cursor))
+{}
+
+CursorContext::~CursorContext()
+{
+ if (_index == _editor._cursor_stack.size() - 1) {
+ _editor.pop_canvas_cursor();
+ } else {
+ _editor._cursor_stack[_index] = NULL;
+ }
+}
+
+CursorContext::Handle
+CursorContext::create(Editor& editor, Gdk::Cursor* cursor)
+{
+ return CursorContext::Handle(new CursorContext(editor, cursor));
+}
+
+void
+CursorContext::change(Gdk::Cursor* cursor)
+{
+ _editor._cursor_stack[_index] = cursor;
+ if (_index == _editor._cursor_stack.size() - 1) {
+ _editor.set_canvas_cursor(cursor);
+ }
+}
+
+void
+CursorContext::set(Handle* handle, Editor& editor, Gdk::Cursor* cursor)
+{
+ if (*handle) {
+ (*handle)->change(cursor);
+ } else {
+ *handle = CursorContext::create(editor, cursor);
+ }
+}
diff --git a/gtk2_ardour/cursor_context.h b/gtk2_ardour/cursor_context.h
new file mode 100644
index 0000000000..9ce086218f
--- /dev/null
+++ b/gtk2_ardour/cursor_context.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2014 Paul Davis
+ Author: David Robillard
+
+ 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.
+*/
+
+#ifndef __ardour_gtk_cursor_context_h__
+#define __ardour_gtk_cursor_context_h__
+
+#include <boost/shared_ptr.hpp>
+#include <gdkmm/cursor.h>
+
+class Editor;
+
+/**
+ A scoped handle for changing the editor mouse cursor.
+
+ This is a safe way to change the cursor that ensures it is only modified in
+ a strict stack-like fashion. Whenever this handle goes out of scope, the
+ cursor is restored to the previous one.
+
+ This is not quite entirely fool-proof, there is one case to be careful of:
+ if a cursor context handle exists, to change it, you must first reset that
+ handle (destroying the context) then set it. Assigning a new context to a
+ non-NULL handle will create the new context (pushing a cursor), then destroy
+ the old one, which would attempt to pop a non-top context which is an
+ error. To account for this, when replacing a possibly existing context, use
+ set() which will automatically do the right thing.
+*/
+class CursorContext
+{
+public:
+ /** A smart handle for a cursor change context. */
+ typedef boost::shared_ptr<CursorContext> Handle;
+
+ ~CursorContext();
+
+ /** Change the editor cursor and return a cursor context handle.
+ *
+ * When the returned handle goes out of scope, the cursor will be reset to
+ * the previous value.
+ */
+ static Handle create(Editor& editor, Gdk::Cursor* cursor);
+
+ /** Change the editor cursor of an existing cursor context. */
+ void change(Gdk::Cursor* cursor);
+
+ /** Set a context handle to a new context.
+ *
+ * If the handle points to an existing context, it will first be reset
+ * before the new context is created.
+ */
+ static void set(Handle* handle, Editor& editor, Gdk::Cursor* cursor);
+
+private:
+ Editor& _editor;
+ size_t _index;
+
+ CursorContext(Editor& editor, Gdk::Cursor* cursor);
+};
+
+#endif /* __ardour_gtk_cursor_context_h__ */
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 5e5c323f6a..cdc77dcc85 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -313,7 +313,6 @@ Editor::Editor ()
clicked_routeview = 0;
clicked_control_point = 0;
last_update_frame = 0;
- pre_press_cursor = 0;
last_paste_pos = 0;
paste_count = 0;
_drags = new DragManager (this);
@@ -374,6 +373,7 @@ Editor::Editor ()
current_stepping_trackview = 0;
entered_track = 0;
entered_regionview = 0;
+ _entered_item_type = NoItem;
entered_marker = 0;
clear_entered_track = false;
current_timefx = 0;
@@ -400,7 +400,6 @@ Editor::Editor ()
zoom_focus = ZoomFocusLeft;
_edit_point = EditAtMouse;
- current_canvas_cursor = 0;
_visible_track_count = -1;
samples_per_pixel = 2048; /* too early to use reset_zoom () */
@@ -520,6 +519,9 @@ Editor::Editor ()
_cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
+ /* Push default cursor to ever-present bottom of cursor stack. */
+ push_canvas_cursor(_cursors->grabber);
+
ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
@@ -2120,7 +2122,9 @@ Editor::set_edit_point_preference (EditPoint ep, bool force)
edit_point_selector.set_text (str);
}
- reset_canvas_cursor ();
+ if (_entered_item_type != NoItem) {
+ choose_canvas_cursor_on_entry (_entered_item_type);
+ }
if (!force && !changed) {
return;
@@ -5744,9 +5748,10 @@ Editor::ui_parameter_changed (string parameter)
{
if (parameter == "icon-set") {
while (!_cursor_stack.empty()) {
- _cursor_stack.pop();
+ _cursor_stack.pop_back();
}
_cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
+ _cursor_stack.push_back(_cursors->grabber);
} else if (parameter == "draggable-playhead") {
if (_verbose_cursor) {
playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index d1639d819e..b511bd0dde 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -20,13 +20,14 @@
#ifndef __ardour_editor_h__
#define __ardour_editor_h__
+#include <sys/time.h>
+
+#include <cmath>
#include <list>
#include <map>
#include <set>
-#include <stack>
#include <string>
-#include <sys/time.h>
-#include <cmath>
+#include <vector>
#include <boost/optional.hpp>
@@ -97,6 +98,7 @@ class AutomationTimeAxisView;
class BundleManager;
class ButtonJoiner;
class ControlPoint;
+class CursorContext;
class DragManager;
class EditNoteDialog;
class EditorCursor;
@@ -439,11 +441,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void maybe_autoscroll (bool, bool, bool);
bool autoscroll_active() const;
- Gdk::Cursor* get_canvas_cursor () const { return current_canvas_cursor; }
- void set_canvas_cursor (Gdk::Cursor*, bool save=false);
-
- void push_canvas_cursor (Gdk::Cursor*);
- void pop_canvas_cursor ();
+ Gdk::Cursor* get_canvas_cursor () const;
void set_current_trimmable (boost::shared_ptr<ARDOUR::Trimmable>);
void set_current_movable (boost::shared_ptr<ARDOUR::Movable>);
@@ -726,14 +724,18 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
Gtk::VBox global_vpacker;
Gtk::VBox vpacker;
- std::stack<Gdk::Cursor*> _cursor_stack;
- Gdk::Cursor* current_canvas_cursor;
+ /* Cursor stuff. Do not use directly, use via CursorContext. */
+ friend class CursorContext;
+ std::vector<Gdk::Cursor*> _cursor_stack;
+ void set_canvas_cursor (Gdk::Cursor*);
+ size_t push_canvas_cursor (Gdk::Cursor*);
+ void pop_canvas_cursor ();
+
Gdk::Cursor* which_grabber_cursor () const;
Gdk::Cursor* which_track_cursor () const;
Gdk::Cursor* which_mode_cursor () const;
Gdk::Cursor* which_trim_cursor (bool left_side) const;
- bool reset_canvas_cursor ();
- void choose_canvas_cursor_on_entry (GdkEventCrossing*, ItemType);
+ void choose_canvas_cursor_on_entry (ItemType);
ArdourCanvas::GtkCanvas* _track_canvas;
ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport;
@@ -1095,7 +1097,9 @@ 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::shared_ptr<CursorContext> _press_cursor_ctx; ///< Button press cursor context
+ boost::shared_ptr<CursorContext> _enter_cursor_ctx; ///< Entered item cursor context
+
boost::weak_ptr<ARDOUR::Trimmable> _trimmable;
boost::weak_ptr<ARDOUR::Movable> _movable;
@@ -1978,6 +1982,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
*/
RegionView* entered_regionview;
+ ItemType _entered_item_type;
+
bool clear_entered_track;
bool left_track_canvas (GdkEventCrossing*);
bool entered_track_canvas (GdkEventCrossing*);
diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc
index bb4d8c2283..7d9c2d4c8d 100644
--- a/gtk2_ardour/editor_audio_import.cc
+++ b/gtk2_ardour/editor_audio_import.cc
@@ -46,6 +46,7 @@
#include "pbd/memento_command.h"
#include "ardour_ui.h"
+#include "cursor_context.h"
#include "editor.h"
#include "sfdb_ui.h"
#include "editing.h"
@@ -475,7 +476,7 @@ Editor::import_sndfiles (vector<string> paths, ImportDisposition disposition, Im
import_status.track = track;
import_status.replace = replace;
- set_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
gdk_flush ();
/* start import thread for this spec. this will ultimately call Session::import_files()
@@ -512,7 +513,6 @@ Editor::import_sndfiles (vector<string> paths, ImportDisposition disposition, Im
}
import_status.sources.clear();
- set_canvas_cursor (current_canvas_cursor);
return result;
}
@@ -526,9 +526,8 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
SourceList sources;
string linked_path;
SoundFileInfo finfo;
- int ret = 0;
- push_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
gdk_flush ();
for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
@@ -540,7 +539,7 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
if (!AudioFileSource::get_soundfile_info (path, finfo, error_msg)) {
error << string_compose(_("Editor: cannot open file \"%1\", (%2)"), path, error_msg ) << endmsg;
- goto out;
+ return -3;
}
if (check_sample_rate && (finfo.samplerate != (int) _session->frame_rate())) {
@@ -562,19 +561,16 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
switch (resx) {
case 0: /* stop a multi-file import */
- ret = -2;
- goto out;
+ return -2;
case 1: /* don't embed this one */
- ret = -1;
- goto out;
+ return -1;
case 2: /* do it, and the rest without asking */
check_sample_rate = false;
break;
case 3: /* do it */
break;
default:
- ret = -2;
- goto out;
+ return -2;
}
} else {
choices.push_back (_("Cancel"));
@@ -590,13 +586,11 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
switch (resx) {
case 0: /* don't import */
- ret = -1;
- goto out;
+ return -1;
case 1: /* do it */
break;
default:
- ret = -2;
- goto out;
+ return -2;
}
}
}
@@ -627,23 +621,18 @@ Editor::embed_sndfiles (vector<string> paths, bool multifile,
catch (failed_constructor& err) {
error << string_compose(_("could not open %1"), path) << endmsg;
- goto out;
+ return -3;
}
gtk_main_iteration();
}
}
- if (sources.empty()) {
- goto out;
+ if (!sources.empty()) {
+ return add_sources (paths, sources, pos, disposition, mode, target_regions, target_tracks, track, true);
}
-
- ret = add_sources (paths, sources, pos, disposition, mode, target_regions, target_tracks, track, true);
-
- out:
- pop_canvas_cursor ();
- return ret;
+ return 0;
}
int
diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc
index d923489d7c..2476cdaf0c 100644
--- a/gtk2_ardour/editor_canvas.cc
+++ b/gtk2_ardour/editor_canvas.cc
@@ -27,6 +27,8 @@
#include "ardour/rc_configuration.h"
#include "ardour/smf_source.h"
+#include "pbd/error.h"
+
#include "canvas/canvas.h"
#include "canvas/rectangle.h"
#include "canvas/pixbuf.h"
@@ -367,8 +369,10 @@ Editor::reset_controls_layout_height (int32_t h)
bool
Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
{
- if (current_canvas_cursor) {
- set_canvas_cursor (current_canvas_cursor);
+ if (!_cursor_stack.empty()) {
+ set_canvas_cursor (get_canvas_cursor());
+ } else {
+ PBD::error << "cursor stack is empty" << endmsg;
}
return false;
}
@@ -985,13 +989,16 @@ Editor::get_track_canvas() const
return _track_canvas_viewport;
}
-void
-Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
+Gdk::Cursor*
+Editor::get_canvas_cursor () const
{
- if (save) {
- current_canvas_cursor = cursor;
- }
+ /* The top of the cursor stack is always the currently visible cursor. */
+ return _cursor_stack.back();
+}
+void
+Editor::set_canvas_cursor (Gdk::Cursor* cursor)
+{
Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
if (win && cursor) {
@@ -999,22 +1006,32 @@ Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
}
}
-void
+size_t
Editor::push_canvas_cursor (Gdk::Cursor* cursor)
{
if (cursor) {
- _cursor_stack.push (cursor);
- set_canvas_cursor (cursor, false);
+ _cursor_stack.push_back (cursor);
+ set_canvas_cursor (cursor);
}
+ return _cursor_stack.size() - 1;
}
void
Editor::pop_canvas_cursor ()
{
- if (!_cursor_stack.empty()) {
- Gdk::Cursor* cursor = _cursor_stack.top ();
- _cursor_stack.pop ();
- set_canvas_cursor (cursor, false);
+ while (true) {
+ if (_cursor_stack.size() <= 1) {
+ PBD::error << "attempt to pop default cursor" << endmsg;
+ return;
+ }
+
+ _cursor_stack.pop_back();
+ if (_cursor_stack.back()) {
+ /* Popped to an existing cursor, we're done. Otherwise, the
+ context that created this cursor has been destroyed, so we need
+ to skip to the next down the stack. */
+ return;
+ }
}
}
@@ -1147,29 +1164,8 @@ Editor::which_track_cursor () const
return cursor;
}
-bool
-Editor::reset_canvas_cursor ()
-{
- if (!is_drawable()) {
- return false;
- }
-
- Gdk::Cursor* cursor = which_mode_cursor ();
-
- if (!cursor) {
- cursor = which_grabber_cursor ();
- }
-
- if (cursor) {
- set_canvas_cursor (cursor);
- return true;
- }
-
- return false;
-}
-
void
-Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType type)
+Editor::choose_canvas_cursor_on_entry (ItemType type)
{
Gdk::Cursor* cursor = 0;
@@ -1179,7 +1175,8 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
cursor = which_mode_cursor ();
- if (mouse_mode == MouseObject || get_smart_mode ()) {
+ if ((mouse_mode == MouseObject || get_smart_mode ()) ||
+ mouse_mode == MouseContent) {
/* find correct cursor to use in object/smart mode */
@@ -1238,9 +1235,6 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
case FadeOutTrimHandleItem:
cursor = _cursors->fade_out;
break;
- case NoteItem:
- cursor = which_grabber_cursor();
- break;
case FeatureLineItem:
cursor = _cursors->cross_hair;
break;
@@ -1313,7 +1307,8 @@ Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType typ
}
if (cursor) {
- set_canvas_cursor (cursor, true);
+ CursorContext::set(&_enter_cursor_ctx, *this, cursor);
+ _entered_item_type = type;
}
}
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 73a6e4dad6..2470580436 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -274,7 +274,7 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
} else {
/* CAIROCANVAS need a variant here that passes *cursor */
_item->grab ();
- _editor->push_canvas_cursor (cursor);
+ _cursor_ctx = CursorContext::create(*_editor, cursor);
}
if (_editor->session() && _editor->session()->transport_rolling()) {
@@ -311,7 +311,7 @@ Drag::end_grab (GdkEvent* event)
finished (event, _move_threshold_passed);
_editor->verbose_cursor()->hide ();
- _editor->pop_canvas_cursor ();
+ _cursor_ctx.reset();
return _move_threshold_passed;
}
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index 78b541d4f5..260a333ce9 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -27,6 +27,7 @@
#include "ardour/types.h"
+#include "cursor_context.h"
#include "editor_items.h"
namespace ARDOUR {
@@ -240,6 +241,7 @@ private:
ARDOUR::framepos_t _raw_grab_frame; ///< unsnapped frame that the mouse was at when start_grab was called, or 0
ARDOUR::framepos_t _grab_frame; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
ARDOUR::framepos_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred
+ CursorContext::Handle _cursor_ctx; ///< cursor change context
};
class RegionDrag;
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index dc84a6ea45..038eea5747 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -705,7 +705,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case RegionViewName:
case StreamItem:
case AutomationTrackItem:
- _drags->set (new RegionCutDrag (this, item, canvas_event_sample (event)), event, current_canvas_cursor);
+ _drags->set (new RegionCutDrag (this, item, canvas_event_sample (event)), event, get_canvas_cursor());
return true;
break;
default:
@@ -719,7 +719,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
/* Existing note: allow trimming/motion */
if ((note = reinterpret_cast<NoteBase*> (item->get_data ("notebase")))) {
if (note->big_enough_to_trim() && note->mouse_near_ends()) {
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
} else {
_drags->set (new NoteDrag (this, item), event);
}
@@ -938,7 +938,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
if (note->big_enough_to_trim() && note->mouse_near_ends()) {
/* Note is big and pointer is near the end, trim */
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
} else {
/* Drag note */
_drags->set (new NoteDrag (this, item), event);
@@ -964,7 +964,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
/* resize-drag notes */
if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
if (note->big_enough_to_trim()) {
- _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
+ _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
}
}
return true;
@@ -976,12 +976,11 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case MouseAudition:
- _drags->set (new ScrubDrag (this, item), event);
+ _drags->set (new ScrubDrag (this, item), event, _cursors->transparent);
scrub_reversals = 0;
scrub_reverse_distance = 0;
last_scrub_x = event->button.x;
scrubbing_direction = 0;
- push_canvas_cursor (_cursors->transparent);
return true;
break;
@@ -1068,8 +1067,6 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
return false;
}
- pre_press_cursor = current_canvas_cursor;
-
_track_canvas->grab_focus();
if (_session && _session->actively_recording()) {
@@ -1141,10 +1138,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
framepos_t where = canvas_event_sample (event);
AutomationTimeAxisView* atv = 0;
- if (pre_press_cursor) {
- set_canvas_cursor (pre_press_cursor);
- pre_press_cursor = 0;
- }
+ _press_cursor_ctx.reset();
/* no action if we're recording */
@@ -1441,7 +1435,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case MouseAudition:
- pop_canvas_cursor ();
if (scrubbing_direction == 0) {
/* no drag, just a click */
switch (item_type) {
@@ -1529,7 +1522,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
* (e.g. the actual entered regionview)
*/
- choose_canvas_cursor_on_entry (&event->crossing, item_type);
+ choose_canvas_cursor_on_entry (item_type);
switch (item_type) {
case ControlPointItem:
@@ -1649,7 +1642,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
bool is_start;
bool ret = true;
- reset_canvas_cursor ();
+ _enter_cursor_ctx.reset();
+ _entered_item_type = NoItem;
switch (item_type) {
case ControlPointItem:
@@ -2321,8 +2315,8 @@ Editor::update_join_object_range_location (double y)
_join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
- if (_join_object_range_state != old) {
- set_canvas_cursor (which_track_cursor ());
+ if (_join_object_range_state != old && _enter_cursor_ctx) {
+ _enter_cursor_ctx->change(which_track_cursor());
}
} else if (entered_track) {
@@ -2354,8 +2348,8 @@ Editor::update_join_object_range_location (double y)
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
}
- if (_join_object_range_state != old) {
- set_canvas_cursor (which_track_cursor ());
+ if (_join_object_range_state != old && _enter_cursor_ctx) {
+ _enter_cursor_ctx->change(which_track_cursor());
}
}
}
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 221a1f7254..692ef93c7f 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -3689,14 +3689,13 @@ Editor::freeze_route ()
pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
- set_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
while (!itt.done && !itt.cancel) {
gtk_main_iteration ();
}
current_interthread_info = 0;
- set_canvas_cursor (current_canvas_cursor);
}
void
@@ -4734,7 +4733,7 @@ Editor::normalize_region ()
return;
}
- set_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
gdk_flush ();
/* XXX: should really only count audio regions here */
@@ -4753,7 +4752,6 @@ Editor::normalize_region ()
if (a == -1) {
/* the user cancelled the operation */
- set_canvas_cursor (current_canvas_cursor);
return;
}
@@ -4784,7 +4782,6 @@ Editor::normalize_region ()
}
commit_reversible_command ();
- set_canvas_cursor (current_canvas_cursor);
}
@@ -4955,7 +4952,7 @@ Editor::fork_region ()
begin_reversible_command (_("Fork Region(s)"));
- set_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
gdk_flush ();
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
@@ -4982,8 +4979,6 @@ Editor::fork_region ()
}
commit_reversible_command ();
-
- set_canvas_cursor (current_canvas_cursor);
}
void
@@ -5102,7 +5097,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
begin_reversible_command (command);
- set_canvas_cursor (_cursors->wait);
+ CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
gdk_flush ();
int n = 0;
@@ -5155,7 +5150,7 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
_session->add_command(new StatefulDiffCommand (playlist));
} else {
- goto out;
+ return;
}
if (progress) {
@@ -5168,9 +5163,6 @@ Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress
}
commit_reversible_command ();
-
- out:
- set_canvas_cursor (current_canvas_cursor);
}
void
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index d88a1efb22..f7d0cc41f8 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -122,9 +122,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
- , pre_enter_cursor (0)
- , pre_press_cursor (0)
- , pre_note_enter_cursor (0)
, _note_player (0)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
@@ -171,9 +168,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
- , pre_enter_cursor (0)
- , pre_press_cursor (0)
- , pre_note_enter_cursor (0)
, _note_player (0)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
@@ -225,9 +219,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
- , pre_enter_cursor (0)
- , pre_press_cursor (0)
- , pre_note_enter_cursor (0)
, _note_player (0)
{
init (false);
@@ -258,9 +249,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
- , pre_enter_cursor (0)
- , pre_press_cursor (0)
- , pre_note_enter_cursor (0)
, _note_player (0)
{
init (true);
@@ -427,6 +415,8 @@ bool
MidiRegionView::leave_notify (GdkEventCrossing*)
{
leave_internal();
+ _note_cursor_ctx.reset();
+ _press_cursor_ctx.reset();
_entered = false;
return false;
@@ -487,8 +477,7 @@ MidiRegionView::button_press (GdkEventButton* ev)
MouseMode m = editor->current_mouse_mode();
if (m == MouseContent && Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
- pre_press_cursor = editor->get_canvas_cursor ();
- editor->set_canvas_cursor (editor->cursors()->midi_pencil);
+ _press_cursor_ctx = CursorContext::create(*editor, editor->cursors()->midi_pencil);
}
if (_mouse_state != SelectTouchDragging) {
@@ -521,10 +510,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
PublicEditor& editor = trackview.editor ();
- if (pre_press_cursor) {
- dynamic_cast<Editor*>(&editor)->set_canvas_cursor (pre_press_cursor, false);
- pre_press_cursor = 0;
- }
+ _press_cursor_ctx.reset();
switch (_mouse_state) {
case Pressed: // Clicked
@@ -3154,13 +3140,14 @@ MidiRegionView::note_entered(NoteBase* ev)
{
Editor* editor = dynamic_cast<Editor*>(&trackview.editor());
- pre_note_enter_cursor = editor->get_canvas_cursor ();
-
if (_mouse_state == SelectTouchDragging) {
note_selected (ev, true);
+ } else if (editor->current_mouse_mode() == MouseContent) {
+ CursorContext::set(&_note_cursor_ctx, *editor, editor->cursors()->grabber_note);
+ show_verbose_cursor (ev->note ());
+ } else if (editor->current_mouse_mode() == MouseDraw) {
+ show_verbose_cursor (ev->note ());
}
-
- show_verbose_cursor (ev->note ());
}
void
@@ -3174,10 +3161,7 @@ MidiRegionView::note_left (NoteBase*)
editor->verbose_cursor()->hide ();
- if (pre_note_enter_cursor) {
- editor->set_canvas_cursor (pre_note_enter_cursor);
- pre_note_enter_cursor = 0;
- }
+ _note_cursor_ctx.reset();
}
void
@@ -3230,11 +3214,11 @@ MidiRegionView::note_mouse_position (float x_fraction, float /*y_fraction*/, boo
if (can_set_cursor) {
if (trimmable && x_fraction > 0.0 && x_fraction < 0.2) {
- editor->set_canvas_cursor (editor->cursors()->left_side_trim);
+ CursorContext::set(&_note_cursor_ctx, *editor, editor->cursors()->left_side_trim);
} else if (trimmable && x_fraction >= 0.8 && x_fraction < 1.0) {
- editor->set_canvas_cursor (editor->cursors()->right_side_trim);
- } else if (pre_note_enter_cursor) {
- editor->set_canvas_cursor (pre_note_enter_cursor);
+ CursorContext::set(&_note_cursor_ctx, *editor, editor->cursors()->right_side_trim);
+ } else {
+ CursorContext::set(&_note_cursor_ctx, *editor, editor->cursors()->grabber_note);
}
}
}
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index d7c8c29058..2c81f51122 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -61,6 +61,7 @@ class EditNoteDialog;
class NotePlayer;
class PatchChange;
class ItemCounts;
+class CursorContext;
class MidiRegionView : public RegionView
{
@@ -496,9 +497,8 @@ private:
PBD::ScopedConnection _mouse_mode_connection;
- Gdk::Cursor* pre_enter_cursor;
- Gdk::Cursor* pre_press_cursor;
- Gdk::Cursor* pre_note_enter_cursor;
+ boost::shared_ptr<CursorContext> _note_cursor_ctx;
+ boost::shared_ptr<CursorContext> _press_cursor_ctx;
NotePlayer* _note_player;
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index 165cd2f82b..390ebfbba6 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -55,6 +55,7 @@ gtk2_ardour_sources = [
'configinfo.cc',
'control_point.cc',
'control_point_dialog.cc',
+ 'cursor_context.cc',
'curvetest.cc',
'debug.cc',
'edit_note_dialog.cc',