a whole slew of changes related to centralizing and rationalizing cursor management.

Debugging output left in place to help address the reports that will come in as people test this more
This commit is contained in:
Paul Davis 2014-06-18 10:24:59 -04:00
parent 47efeb9f21
commit becf857f48
11 changed files with 504 additions and 494 deletions

View File

@ -407,7 +407,7 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
RegionView::reset_width_dependent_items(pixel_width);
assert(_pixel_width == pixel_width);
if (pixel_width <= 6.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) {
if (pixel_width <= 20.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) {
if (fade_in_handle) { fade_in_handle->hide(); }
if (fade_out_handle) { fade_out_handle->hide(); }
if (fade_in_trim_handle) { fade_in_trim_handle->hide(); }
@ -1144,6 +1144,8 @@ AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
wave->set_samples_per_pixel (samples_per_pixel);
wave->set_show_zero_line (true);
wave->set_clip_level (Config->get_waveform_clip_level ());
wave->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_wave_view_event), wave, this));
switch (Config->get_waveform_shape()) {
case Rectified:

View File

@ -743,7 +743,6 @@ Editor::Editor ()
_popup_region_menu_item = 0;
_show_marker_lines = false;
_over_region_trim_target = false;
/* Button bindings */
@ -794,7 +793,7 @@ Editor::add_toplevel_controls (Container& cont)
bool
Editor::get_smart_mode () const
{
return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
}
void
@ -819,8 +818,6 @@ Editor::catch_vanishing_regionview (RegionView *rv)
if (!_all_region_actions_sensitized) {
sensitize_all_region_actions (true);
}
_over_region_trim_target = false;
}
void
@ -834,7 +831,9 @@ Editor::set_entered_regionview (RegionView* rv)
entered_regionview->exited ();
}
if ((entered_regionview = rv) != 0) {
entered_regionview = rv;
if (entered_regionview != 0) {
entered_regionview->entered (internal_editing ());
}
@ -853,7 +852,9 @@ Editor::set_entered_track (TimeAxisView* tav)
entered_track->exited ();
}
if ((entered_track = tav) != 0) {
entered_track = tav;
if (entered_track) {
entered_track->entered ();
}
}
@ -2010,7 +2011,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force)
edit_point_selector.set_text (str);
}
set_canvas_cursor ();
reset_canvas_cursor ();
if (!force && !changed) {
return;
@ -2416,7 +2417,7 @@ Editor::get_state ()
* in stacked or expanded region display mode, otherwise 0.
*/
std::pair<TimeAxisView *, double>
Editor::trackview_by_y_position (double y, bool trackview_relative_offset)
Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
{
if (!trackview_relative_offset) {
y -= _trackview_group->canvas_origin().y;
@ -2426,7 +2427,7 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset)
return std::make_pair ( (TimeAxisView *) 0, 0);
}
for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);

View File

@ -535,7 +535,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
JoinObjectRangeState _join_object_range_state;
void update_join_object_range_location (double, double);
void update_join_object_range_location (double);
boost::optional<int> pre_notebook_shrink_pane_width;
@ -703,8 +703,12 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
std::stack<Gdk::Cursor*> _cursor_stack;
Gdk::Cursor* current_canvas_cursor;
Gdk::Cursor* which_grabber_cursor ();
void set_canvas_cursor ();
Gdk::Cursor* which_grabber_cursor () const;
Gdk::Cursor* which_region_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);
ArdourCanvas::GtkCanvas* _track_canvas;
ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport;
@ -1041,7 +1045,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
/* track views */
TrackViewList track_views;
std::pair<TimeAxisView*, double> trackview_by_y_position (double, bool trackview_relative_offset = true);
std::pair<TimeAxisView*, double> trackview_by_y_position (double, bool trackview_relative_offset = true) const;
RouteTimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const;
TrackViewList get_tracks_for_range_action () const;
@ -1402,6 +1406,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*);
bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*, bool trim = false);
bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*);
bool canvas_wave_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*);
bool canvas_frame_handle_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*);
bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*);
bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*);
@ -1439,9 +1444,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
friend class EditorRouteGroups;
friend class EditorRegions;
/** true if the mouse is over a place where region trim can happen */
bool _over_region_trim_target;
/* non-public event handlers */
bool canvas_playhead_cursor_event (GdkEvent* event, ArdourCanvas::Item*);
@ -2059,8 +2061,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
Gtk::MenuItem& action_menu_item (std::string const &);
void action_pre_activated (Glib::RefPtr<Gtk::Action> const &);
void set_canvas_cursor_for_region_view (double, RegionView *);
MouseCursors* _cursors;
void follow_mixer_selection ();

View File

@ -35,6 +35,7 @@
#include "canvas/debug.h"
#include "ardour_ui.h"
#include "automation_time_axis.h"
#include "editor.h"
#include "global_signals.h"
#include "editing.h"
@ -926,39 +927,6 @@ Editor::horizontal_position () const
return sample_to_pixel (leftmost_frame);
}
void
Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
{
if (save) {
current_canvas_cursor = cursor;
}
Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
if (win) {
_track_canvas->get_window()->set_cursor (*cursor);
}
}
void
Editor::push_canvas_cursor (Gdk::Cursor* cursor)
{
if (cursor) {
_cursor_stack.push (cursor);
set_canvas_cursor (cursor, false);
}
}
void
Editor::pop_canvas_cursor ()
{
if (!_cursor_stack.empty()) {
Gdk::Cursor* cursor = _cursor_stack.top ();
_cursor_stack.pop ();
set_canvas_cursor (cursor, false);
}
}
bool
Editor::track_canvas_key_press (GdkEventKey*)
{
@ -1004,3 +972,352 @@ Editor::get_track_canvas() const
{
return _track_canvas_viewport;
}
void
Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
{
if (save) {
current_canvas_cursor = cursor;
}
Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
if (win) {
_track_canvas->get_window()->set_cursor (*cursor);
}
}
void
Editor::push_canvas_cursor (Gdk::Cursor* cursor)
{
if (cursor) {
_cursor_stack.push (cursor);
set_canvas_cursor (cursor, false);
}
}
void
Editor::pop_canvas_cursor ()
{
if (!_cursor_stack.empty()) {
Gdk::Cursor* cursor = _cursor_stack.top ();
_cursor_stack.pop ();
set_canvas_cursor (cursor, false);
}
}
Gdk::Cursor*
Editor::which_grabber_cursor () const
{
Gdk::Cursor* c = _cursors->grabber;
if (_internal_editing) {
switch (mouse_mode) {
case MouseDraw:
c = _cursors->midi_pencil;
break;
case MouseObject:
c = _cursors->grabber_note;
break;
case MouseTimeFX:
c = _cursors->midi_resize;
break;
case MouseRange:
c = _cursors->grabber_note;
break;
default:
break;
}
} else {
switch (_edit_point) {
case EditAtMouse:
c = _cursors->grabber_edit_point;
break;
default:
boost::shared_ptr<Movable> m = _movable.lock();
if (m && m->locked()) {
c = _cursors->speaker;
}
break;
}
}
return c;
}
Gdk::Cursor*
Editor::which_trim_cursor (bool left) const
{
if (!entered_regionview) {
return 0;
}
Trimmable::CanTrim ct = entered_regionview->region()->can_trim ();
if (left) {
if (ct & Trimmable::FrontTrimEarlier) {
return _cursors->left_side_trim;
} else {
return _cursors->left_side_trim_right_only;
}
} else {
if (ct & Trimmable::EndTrimLater) {
return _cursors->right_side_trim;
} else {
return _cursors->right_side_trim_left_only;
}
}
}
Gdk::Cursor*
Editor::which_mode_cursor () const
{
Gdk::Cursor* mode_cursor = 0;
switch (mouse_mode) {
case MouseRange:
mode_cursor = _cursors->selector;
if (_internal_editing) {
mode_cursor = which_grabber_cursor();
}
break;
case MouseObject:
/* don't use mode cursor, pick a grabber cursor based on the item */
break;
case MouseDraw:
mode_cursor = _cursors->midi_pencil;
break;
case MouseGain:
mode_cursor = _cursors->cross_hair;
break;
case MouseZoom:
if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
mode_cursor = _cursors->zoom_out;
} else {
mode_cursor = _cursors->zoom_in;
}
break;
case MouseTimeFX:
mode_cursor = _cursors->time_fx; // just use playhead
break;
case MouseAudition:
mode_cursor = _cursors->speaker;
break;
}
/* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
if (!_internal_editing && get_smart_mode() ) {
double x, y;
get_pointer_position (x, y);
if (x >= 0 && y >= 0) {
vector<ArdourCanvas::Item const *> items;
/* Note how we choose a specific scroll group to get
* items from. This could be problematic.
*/
hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items);
// first item will be the upper most
if (!items.empty()) {
const ArdourCanvas::Item* i = items.front();
if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) {
pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y);
if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) {
mode_cursor = _cursors->up_down;
}
}
}
}
}
return mode_cursor;
}
Gdk::Cursor*
Editor::which_region_cursor () const
{
Gdk::Cursor* cursor = 0;
assert (mouse_mode == MouseObject || get_smart_mode());
if (!_internal_editing) {
switch (_join_object_range_state) {
case JOIN_OBJECT_RANGE_NONE:
case JOIN_OBJECT_RANGE_OBJECT:
cursor = which_grabber_cursor ();
cerr << "region use grabber\n";
break;
case JOIN_OBJECT_RANGE_RANGE:
cursor = _cursors->selector;
cerr << "region use selector\n";
break;
}
}
return cursor;
}
bool
Editor::reset_canvas_cursor ()
{
if (!is_drawable()) {
return false;
}
Gdk::Cursor* cursor = which_mode_cursor ();
if (cursor) {
set_canvas_cursor (cursor);
return true;
}
return false;
}
void
Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType type)
{
Gdk::Cursor* cursor = 0;
cerr << "entered new item type " << enum_2_string (type) << endl;
if (_drags->active()) {
return;
}
cursor = which_mode_cursor ();
if (mouse_mode == MouseObject || get_smart_mode ()) {
/* find correct cursor to use in object/smart mode */
switch (type) {
case RegionItem:
case RegionViewNameHighlight:
case RegionViewName:
case WaveItem:
cursor = which_region_cursor ();
break;
case PlayheadCursorItem:
switch (_edit_point) {
case EditAtMouse:
cursor = _cursors->grabber_edit_point;
break;
default:
cursor = _cursors->grabber;
break;
}
break;
case SelectionItem:
cursor = _cursors->selector;
break;
case ControlPointItem:
cursor = _cursors->fader;
break;
case GainLineItem:
cursor = _cursors->fader;
break;
case AutomationLineItem:
cursor = _cursors->cross_hair;
break;
case StartSelectionTrimItem:
break;
case EndSelectionTrimItem:
break;
case AutomationTrackItem:
cursor = _cursors->cross_hair;
break;
case FadeInItem:
cursor = _cursors->fade_in;
break;
case FadeInHandleItem:
cursor = _cursors->fade_in;
break;
case FadeInTrimHandleItem:
cursor = _cursors->fade_in;
break;
case FadeOutItem:
cursor = _cursors->fade_out;
break;
case FadeOutHandleItem:
cursor = _cursors->fade_out;
break;
case FadeOutTrimHandleItem:
cursor = _cursors->fade_out;
break;
case NoteItem:
cursor = which_grabber_cursor();
break;
case FeatureLineItem:
cursor = _cursors->cross_hair;
break;
case LeftFrameHandle:
cursor = which_trim_cursor (true);
break;
case RightFrameHandle:
cursor = which_trim_cursor (false);
break;
case StartCrossFadeItem:
cursor = _cursors->fade_in;
break;
case EndCrossFadeItem:
cursor = _cursors->fade_out;
break;
case CrossfadeViewItem:
cursor = _cursors->cross_hair;
break;
default:
break;
}
}
switch (type) {
/* These items use the timebar cursor at all times */
case TimecodeRulerItem:
case MinsecRulerItem:
case BBTRulerItem:
case SamplesRulerItem:
cursor = _cursors->timebar;
break;
/* These items use the grabber cursor at all times */
case MeterMarkerItem:
case TempoMarkerItem:
case MeterBarItem:
case TempoBarItem:
case MarkerItem:
case MarkerBarItem:
case RangeMarkerBarItem:
case CdMarkerBarItem:
case VideoBarItem:
case TransportMarkerBarItem:
cursor = which_grabber_cursor();
break;
default:
break;
}
if (cursor) {
set_canvas_cursor (cursor, false);
}
}

View File

@ -278,16 +278,14 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg
break;
case GDK_ENTER_NOTIFY:
if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
set_entered_regionview (rv);
ret = true;
}
set_entered_regionview (rv);
ret = enter_handler (item, event, RegionItem);
break;
case GDK_LEAVE_NOTIFY:
if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
set_entered_regionview (0);
ret = true;
ret = leave_handler (item, event, RegionItem);
}
break;
@ -298,6 +296,42 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg
return ret;
}
bool
Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
{
/* we only care about enter events here, required for mouse/cursor
* tracking. there is a non-linear (non-child/non-parent) relationship
* between various components of a regionview and so when we leave one
* of them (e.g. a trim handle) and enter another (e.g. the waveview)
* no other items get notified. enter/leave handling does not propagate
* in the same way as other events, so we need to catch this because
* entering (and leaving) the waveview is equivalent to
* entering/leaving the regionview (which is why it is passed in as a
* third argument).
*
* And in fact, we really only care about enter events.
*/
bool ret = false;
if (!rv->sensitive ()) {
return false;
}
switch (event->type) {
case GDK_ENTER_NOTIFY:
set_entered_regionview (rv);
ret = enter_handler (item, event, WaveItem);
break;
default:
break;
}
return ret;
}
bool
Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
{
@ -324,11 +358,14 @@ Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, Rou
case GDK_ENTER_NOTIFY:
set_entered_track (tv);
ret = true;
ret = enter_handler (item, event, StreamItem);
break;
case GDK_LEAVE_NOTIFY:
set_entered_track (0);
if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
set_entered_track (0);
}
ret = leave_handler (item, event, StreamItem);
break;
default:

View File

@ -23,6 +23,7 @@
enum ItemType {
RegionItem,
StreamItem,
WaveItem,
PlayheadCursorItem,
MarkerItem,
MarkerBarItem,

View File

@ -185,51 +185,6 @@ Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) c
return pixel_to_sample_from_event (x);
}
Gdk::Cursor*
Editor::which_grabber_cursor ()
{
Gdk::Cursor* c = _cursors->grabber;
if (_internal_editing) {
switch (mouse_mode) {
case MouseDraw:
c = _cursors->midi_pencil;
break;
case MouseObject:
c = _cursors->grabber_note;
break;
case MouseTimeFX:
c = _cursors->midi_resize;
break;
case MouseRange:
c = _cursors->grabber_note;
break;
default:
break;
}
} else {
switch (_edit_point) {
case EditAtMouse:
c = _cursors->grabber_edit_point;
break;
default:
boost::shared_ptr<Movable> m = _movable.lock();
if (m && m->locked()) {
c = _cursors->speaker;
}
break;
}
}
return c;
}
void
Editor::set_current_trimmable (boost::shared_ptr<Trimmable> t)
{
@ -237,7 +192,6 @@ Editor::set_current_trimmable (boost::shared_ptr<Trimmable> t)
if (!st || st == t) {
_trimmable = t;
set_canvas_cursor ();
}
}
@ -248,97 +202,9 @@ Editor::set_current_movable (boost::shared_ptr<Movable> m)
if (!sm || sm != m) {
_movable = m;
set_canvas_cursor ();
}
}
void
Editor::set_canvas_cursor ()
{
switch (mouse_mode) {
case MouseRange:
current_canvas_cursor = _cursors->selector;
if (_internal_editing) {
current_canvas_cursor = which_grabber_cursor();
}
break;
case MouseObject:
current_canvas_cursor = which_grabber_cursor();
break;
case MouseDraw:
current_canvas_cursor = _cursors->midi_pencil;
break;
case MouseGain:
current_canvas_cursor = _cursors->cross_hair;
break;
case MouseZoom:
if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
current_canvas_cursor = _cursors->zoom_out;
} else {
current_canvas_cursor = _cursors->zoom_in;
}
break;
case MouseTimeFX:
current_canvas_cursor = _cursors->time_fx; // just use playhead
break;
case MouseAudition:
current_canvas_cursor = _cursors->speaker;
break;
}
if (!_internal_editing) {
switch (_join_object_range_state) {
case JOIN_OBJECT_RANGE_NONE:
break;
case JOIN_OBJECT_RANGE_OBJECT:
current_canvas_cursor = which_grabber_cursor ();
break;
case JOIN_OBJECT_RANGE_RANGE:
current_canvas_cursor = _cursors->selector;
break;
}
}
/* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
if (!_internal_editing && get_smart_mode() ) {
double x, y;
get_pointer_position (x, y);
if (x >= 0 && y >= 0) {
vector<ArdourCanvas::Item const *> items;
/* Note how we choose a specific scroll group to get
* items from. This could be problematic.
*/
hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items);
// first item will be the upper most
if (!items.empty()) {
const ArdourCanvas::Item* i = items.front();
if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) {
pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y);
if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) {
current_canvas_cursor = _cursors->up_down;
}
}
}
}
}
set_canvas_cursor (current_canvas_cursor, true);
}
void
Editor::mouse_mode_object_range_toggled()
{
@ -499,7 +365,7 @@ Editor::mouse_mode_toggled (MouseMode m)
}
*/
set_canvas_cursor ();
reset_canvas_cursor ();
set_gain_envelope_visibility ();
update_time_selection_display ();
@ -1247,7 +1113,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;
set_canvas_cursor (_cursors->transparent);
push_canvas_cursor (_cursors->transparent);
return true;
break;
@ -1777,7 +1643,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
break;
case MouseAudition:
set_canvas_cursor (current_canvas_cursor);
pop_canvas_cursor ();
if (scrubbing_direction == 0) {
/* no drag, just a click */
switch (item_type) {
@ -1858,6 +1724,15 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
double fraction;
bool ret = true;
/* by the time we reach here, entered_regionview and entered trackview
* will have already been set as appropriate. Things are done this
* way because this method isn't passed a pointer to a variable type of
* thing that is entered (which may or may not be canvas item).
* (e.g. the actual entered regionview)
*/
choose_canvas_cursor_on_entry (&event->crossing, item_type);
switch (item_type) {
case ControlPointItem:
if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
@ -1873,10 +1748,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
fraction = 1.0 - (cp->get_y() / cp->line().height());
if (is_drawable() && !_drags->active ()) {
set_canvas_cursor (_cursors->fader);
}
_verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
_verbose_cursor->show ();
}
@ -1888,9 +1759,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (line) {
line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredGainLine());
}
if (is_drawable()) {
set_canvas_cursor (_cursors->fader);
}
}
break;
@ -1900,112 +1768,14 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (line) {
line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredAutomationLine());
}
if (is_drawable()) {
set_canvas_cursor (_cursors->fader);
}
}
break;
case RegionViewNameHighlight:
if (is_drawable() && effective_mouse_mode() == MouseObject && entered_regionview) {
set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
_over_region_trim_target = true;
}
break;
case LeftFrameHandle:
case RightFrameHandle:
if (is_drawable() && effective_mouse_mode() == MouseObject && !internal_editing() && entered_regionview) {
set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
}
break;
case RegionItem:
switch (effective_mouse_mode()) {
case MouseRange:
set_canvas_cursor (_cursors->selector);
break;
default:
set_canvas_cursor (which_grabber_cursor());
break;
}
break;
case StartSelectionTrimItem:
if (is_drawable()) {
set_canvas_cursor (_cursors->left_side_trim);
}
break;
case EndSelectionTrimItem:
if (is_drawable()) {
set_canvas_cursor (_cursors->right_side_trim);
}
break;
case PlayheadCursorItem:
if (is_drawable()) {
switch (_edit_point) {
case EditAtMouse:
set_canvas_cursor (_cursors->grabber_edit_point);
break;
default:
set_canvas_cursor (_cursors->grabber);
break;
}
}
break;
case RegionViewName:
/* when the name is not an active item, the entire name highlight is for trimming */
if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
if (mouse_mode == MouseObject && is_drawable()) {
set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
_over_region_trim_target = true;
}
}
break;
case AutomationTrackItem:
if (is_drawable()) {
Gdk::Cursor *cursor;
switch (mouse_mode) {
case MouseRange:
cursor = _cursors->selector;
break;
case MouseZoom:
cursor = _cursors->zoom_in;
break;
default:
cursor = _cursors->cross_hair;
break;
}
set_canvas_cursor (cursor);
AutomationTimeAxisView* atv;
if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
clear_entered_track = false;
set_entered_track (atv);
}
}
break;
case MarkerBarItem:
case RangeMarkerBarItem:
case TransportMarkerBarItem:
case CdMarkerBarItem:
case MeterBarItem:
case TempoBarItem:
case TimecodeRulerItem:
case SamplesRulerItem:
case MinsecRulerItem:
case BBTRulerItem:
if (is_drawable()) {
set_canvas_cursor (_cursors->timebar);
AutomationTimeAxisView* atv;
if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
clear_entered_track = false;
set_entered_track (atv);
}
break;
@ -2018,9 +1788,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
// fall through
case MeterMarkerItem:
case TempoMarkerItem:
if (is_drawable()) {
set_canvas_cursor (_cursors->timebar);
}
break;
case FadeInHandleItem:
@ -2030,7 +1797,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (rect) {
RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
rect->set_fill_color (rv->get_fill_color());
set_canvas_cursor (_cursors->fade_in);
}
}
break;
@ -2042,7 +1808,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
if (rect) {
RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
rect->set_fill_color (rv->get_fill_color ());
set_canvas_cursor (_cursors->fade_out);
}
}
break;
@ -2055,16 +1820,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
case SelectionItem:
if ( get_smart_mode() ) {
set_canvas_cursor ();
}
break;
default:
break;
}
/* second pass to handle entered track status in a comprehensible way.
/* third pass to handle entered track status in a comprehensible way.
*/
switch (item_type) {
@ -2080,7 +1842,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
default:
set_entered_track (0);
break;
}
@ -2098,27 +1860,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
switch (item_type) {
case ControlPointItem:
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
}
_verbose_cursor->hide ();
break;
case RegionViewNameHighlight:
case LeftFrameHandle:
case RightFrameHandle:
case StartSelectionTrimItem:
case EndSelectionTrimItem:
case PlayheadCursorItem:
_over_region_trim_target = false;
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
}
break;
case GainLineItem:
case AutomationLineItem:
al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
@ -2128,35 +1872,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
line->set_outline_color (al->get_line_color());
}
}
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
}
break;
case RegionViewName:
/* see enter_handler() for notes */
_over_region_trim_target = false;
if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
if (is_drawable() && mouse_mode == MouseObject) {
set_canvas_cursor (current_canvas_cursor);
}
}
break;
case RangeMarkerBarItem:
case TransportMarkerBarItem:
case CdMarkerBarItem:
case MeterBarItem:
case TempoBarItem:
case MarkerBarItem:
case TimecodeRulerItem:
case SamplesRulerItem:
case MinsecRulerItem:
case BBTRulerItem:
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
}
break;
case MarkerItem:
@ -2170,39 +1885,29 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
// fall through
case MeterMarkerItem:
case TempoMarkerItem:
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
}
break;
case FadeInTrimHandleItem:
case FadeOutTrimHandleItem:
case FadeInHandleItem:
case FadeOutHandleItem:
{
ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
if (rect) {
rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle());
}
{
ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
if (rect) {
rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle());
}
set_canvas_cursor (current_canvas_cursor);
break;
}
break;
case AutomationTrackItem:
if (is_drawable()) {
set_canvas_cursor (current_canvas_cursor);
clear_entered_track = true;
Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track));
}
break;
case FeatureLineItem:
{
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine());
}
break;
{
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine());
}
break;
default:
break;
@ -2211,16 +1916,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
return ret;
}
gint
Editor::left_automation_track ()
{
if (clear_entered_track) {
set_entered_track (0);
clear_entered_track = false;
}
return false;
}
void
Editor::scrub (framepos_t frame, double current_x)
{
@ -2331,16 +2026,7 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from
return true;
}
JoinObjectRangeState const old = _join_object_range_state;
update_join_object_range_location (event->motion.x, event->motion.y);
if (!_internal_editing && _join_object_range_state != old) {
set_canvas_cursor ();
}
if (!_internal_editing && _over_region_trim_target) {
set_canvas_cursor_for_region_view (event->motion.x, entered_regionview);
}
update_join_object_range_location (event->motion.y);
bool handled = false;
if (_drags->active ()) {
@ -2427,19 +2113,19 @@ Editor::edit_notes (TimeAxisViewItem& tavi)
if (s.empty ()) {
return;
}
EditNoteDialog* d = new EditNoteDialog (&(*s.begin())->region_view(), s);
d->show_all ();
d->show_all ();
ensure_float (*d);
d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d));
d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d));
}
void
Editor::note_edit_done (int r, EditNoteDialog* d)
{
d->done (r);
delete d;
d->done (r);
delete d;
}
void
@ -2509,7 +2195,7 @@ Editor::collect_new_region_view (RegionView* rv)
void
Editor::collect_and_select_new_region_view (RegionView* rv)
{
selection->add(rv);
selection->add(rv);
latest_regionviews.push_back (rv);
}
@ -2527,7 +2213,7 @@ Editor::cancel_selection ()
void
Editor::cancel_time_selection ()
{
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->hide_selection ();
}
selection->time.clear ();
@ -2831,15 +2517,15 @@ Editor::set_internal_edit (bool yn)
}
_internal_editing = yn;
if (yn) {
pre_internal_mouse_mode = mouse_mode;
pre_internal_mouse_mode = mouse_mode;
pre_internal_snap_type = _snap_type;
pre_internal_snap_mode = _snap_mode;
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->enter_internal_edit_mode ();
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->enter_internal_edit_mode ();
}
set_snap_to (internal_snap_type);
set_snap_mode (internal_snap_mode);
@ -2849,62 +2535,71 @@ Editor::set_internal_edit (bool yn)
internal_snap_mode = _snap_mode;
internal_snap_type = _snap_type;
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->leave_internal_edit_mode ();
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
(*i)->leave_internal_edit_mode ();
}
if (mouse_mode == MouseDraw && pre_internal_mouse_mode != MouseDraw) {
/* we were drawing .. flip back to something sensible */
set_mouse_mode (pre_internal_mouse_mode);
}
if (mouse_mode == MouseDraw && pre_internal_mouse_mode != MouseDraw) {
/* we were drawing .. flip back to something sensible */
set_mouse_mode (pre_internal_mouse_mode);
}
set_snap_to (pre_internal_snap_type);
set_snap_mode (pre_internal_snap_mode);
}
set_canvas_cursor ();
reset_canvas_cursor ();
}
/** Update _join_object_range_state which indicate whether we are over the top or bottom half of a region view,
* used by the `join object/range' tool mode. Coordinates in canvas space.
/** Update _join_object_range_state which indicate whether we are over the top
* or bottom half of a route view, used by the `join object/range' tool
* mode. Coordinates in canvas space.
*/
void
Editor::update_join_object_range_location (double /*x*/, double y)
Editor::update_join_object_range_location (double y)
{
/* XXX: actually, this decides based on whether the mouse is in the top
or bottom half of a the waveform part RouteTimeAxisView;
Note that entered_{track,regionview} is not always setup (e.g. if
the mouse is over a TimeSelection), and to get a Region
that we're over requires searching the playlist.
*/
if ( !get_smart_mode() ) {
if (_internal_editing || !get_smart_mode()) {
_join_object_range_state = JOIN_OBJECT_RANGE_NONE;
return;
}
JoinObjectRangeState const old = _join_object_range_state;
if (mouse_mode == MouseObject) {
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
} else if (mouse_mode == MouseRange) {
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
}
/* XXX: maybe we should make entered_track work in all cases, rather than resorting to this */
pair<TimeAxisView*, int> tvp = trackview_by_y_position (y, false);
cerr << "Entered RV = " << entered_regionview << " track = " << entered_track << endl;
if (tvp.first) {
if (entered_regionview) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
if (rtv) {
ArdourCanvas::Duple const item_space = entered_regionview->get_canvas_group()->canvas_to_item (ArdourCanvas::Duple (0, y));
double const c = item_space.y / entered_regionview->height();
_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_region_cursor ());
}
double cx = 0;
double cy = y;
rtv->canvas_display()->canvas_to_item (cx, cy);
} else if (entered_track) {
double const c = cy / (rtv->view()->child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE);
_join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
RouteTimeAxisView* entered_route_view = dynamic_cast<RouteTimeAxisView*> (entered_track);
if (entered_route_view) {
/* track/bus ... but not in a region ... use range mode */
_join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
if (_join_object_range_state != old) {
set_canvas_cursor (which_region_cursor ());
}
} else {
/* Other kinds of tracks use object mode */
_join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
if (_join_object_range_state != old) {
set_canvas_cursor (which_region_cursor ());
}
}
}
}
@ -2930,51 +2625,6 @@ Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *)
e->region_view().delete_note (e->note ());
}
void
Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
{
/* XXX: this check should not be necessary */
if (rv == 0) {
return;
}
ArdourCanvas::Group* g = rv->get_canvas_group ();
ArdourCanvas::Group* p = g->parent ();
/* Compute x in region view parent coordinates */
double dy = 0;
p->canvas_to_item (x, dy);
boost::optional<ArdourCanvas::Rect> item_bbox = g->bounding_box ();
assert (item_bbox);
ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ());
/* First or last 10% of region is used for trimming, if the whole
region is wider than 20 pixels at the current zoom level.
*/
double const w = parent_bbox.width();
if (w > 20.0 && x >= parent_bbox.x0 && x < parent_bbox.x1) {
Trimmable::CanTrim ct = rv->region()->can_trim ();
if (((x - parent_bbox.x0) / w) < 0.10) {
if (ct & Trimmable::FrontTrimEarlier) {
set_canvas_cursor (_cursors->left_side_trim, true);
} else {
set_canvas_cursor (_cursors->left_side_trim_right_only, true);
}
} else if (((parent_bbox.x1 - x) / w) < 0.10) {
if (ct & Trimmable::EndTrimLater) {
set_canvas_cursor (_cursors->right_side_trim, true);
} else {
set_canvas_cursor (_cursors->right_side_trim_left_only, true);
}
}
}
}
/** Obtain the pointer position in canvas coordinates */
void
Editor::get_pointer_position (double& x, double& y) const

View File

@ -135,6 +135,7 @@ setup_gtk_ardour_enums ()
REGISTER (zoom_focus);
REGISTER_ENUM (RegionItem);
REGISTER_ENUM (WaveItem);
REGISTER_ENUM (StreamItem);
REGISTER_ENUM (PlayheadCursorItem);
REGISTER_ENUM (MarkerItem);

View File

@ -331,6 +331,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi
virtual bool canvas_fade_out_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*) = 0;
virtual bool canvas_fade_out_handle_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*, bool) = 0;
virtual bool canvas_region_view_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0;
virtual bool canvas_wave_view_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0;
virtual bool canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0;
virtual bool canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0;
virtual bool canvas_region_view_name_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0;

View File

@ -71,6 +71,7 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList
TimeAxisView& get_time_axis_view () const;
void set_name_text(const std::string&);
virtual void set_height(double h);
virtual double height() const { return _height; }
void set_y (double);
void set_color (uint32_t);
void set_name_text_color ();

View File

@ -487,7 +487,6 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state)
enter_detail = GDK_NOTIFY_INFERIOR;
leave_detail = GDK_NOTIFY_ANCESTOR;
} else if (_new_current_item->is_descendant_of (*_current_item)) {
/* move from ancestor to descendant (X: "_new_current_item is
* an inferior ("child") of _current_item")