basics of autoscroll for pianoroll (mostly shared with Editor)
More work to do moving/testing pianoroll autoscroll variant back into EditingContext and sharing it with Editor.
This commit is contained in:
parent
d6dcb1c575
commit
d191330235
|
@ -141,16 +141,6 @@ CueEditor::get_y_origin () const
|
|||
return 0.;
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::reset_x_origin (samplepos_t)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::reset_y_origin (double)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CueEditor::set_zoom_focus (Editing::ZoomFocus)
|
||||
{
|
||||
|
@ -163,7 +153,7 @@ CueEditor::get_zoom_focus () const
|
|||
}
|
||||
|
||||
void
|
||||
CueEditor::reset_zoom (samplecnt_t n)
|
||||
CueEditor::set_samples_per_pixel (samplecnt_t n)
|
||||
{
|
||||
samples_per_pixel = n;
|
||||
ZoomChanged(); /* EMIT SIGNAL */
|
||||
|
|
|
@ -65,13 +65,11 @@ class CueEditor : public EditingContext
|
|||
void redo_selection_op ();
|
||||
|
||||
double get_y_origin () const;
|
||||
void reset_x_origin (samplepos_t);
|
||||
void reset_y_origin (double);
|
||||
|
||||
void set_zoom_focus (Editing::ZoomFocus);
|
||||
Editing::ZoomFocus get_zoom_focus () const;
|
||||
samplecnt_t get_current_zoom () const;
|
||||
void reset_zoom (samplecnt_t);
|
||||
void set_samples_per_pixel (samplecnt_t);
|
||||
void reposition_and_zoom (samplepos_t, double);
|
||||
|
||||
void set_mouse_mode (Editing::MouseMode, bool force = false);
|
||||
|
|
|
@ -124,6 +124,10 @@ EditingContext::EditingContext (std::string const & name)
|
|||
, vertical_adjustment (0.0, 0.0, 10.0, 400.0)
|
||||
, horizontal_adjustment (0.0, 0.0, 1e16)
|
||||
, mouse_mode (MouseObject)
|
||||
, visual_change_queued (false)
|
||||
, autoscroll_horizontal_allowed (false)
|
||||
, autoscroll_vertical_allowed (false)
|
||||
, autoscroll_cnt (0)
|
||||
{
|
||||
if (!button_bindings) {
|
||||
button_bindings = new Bindings ("editor-mouse");
|
||||
|
@ -2362,3 +2366,89 @@ EditingContext::register_grid_actions ()
|
|||
|
||||
ActionManager::register_radio_action (snap_actions, grid_choice_group, X_("grid-type-none"), grid_type_strings[(int)GridTypeNone].c_str(), (sigc::bind (sigc::mem_fun(*this, &EditingContext::grid_type_chosen), Editing::GridTypeNone)));
|
||||
}
|
||||
|
||||
void
|
||||
EditingContext::ensure_visual_change_idle_handler ()
|
||||
{
|
||||
if (pending_visual_change.idle_handler_id < 0) {
|
||||
/* see comment in add_to_idle_resize above. */
|
||||
pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
|
||||
pending_visual_change.being_handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EditingContext::_idle_visual_changer (void* arg)
|
||||
{
|
||||
return static_cast<EditingContext*>(arg)->idle_visual_changer ();
|
||||
}
|
||||
|
||||
int
|
||||
EditingContext::idle_visual_changer ()
|
||||
{
|
||||
pending_visual_change.idle_handler_id = -1;
|
||||
|
||||
if (pending_visual_change.pending == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set_horizontal_position() below (and maybe other calls) call
|
||||
gtk_main_iteration(), so it's possible that a signal will be handled
|
||||
half-way through this method. If this signal wants an
|
||||
idle_visual_changer we must schedule another one after this one, so
|
||||
mark the idle_handler_id as -1 here to allow that. Also make a note
|
||||
that we are doing the visual change, so that changes in response to
|
||||
super-rapid-screen-update can be dropped if we are still processing
|
||||
the last one.
|
||||
*/
|
||||
|
||||
if (visual_change_queued) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pending_visual_change.being_handled = true;
|
||||
|
||||
VisualChange vc = pending_visual_change;
|
||||
|
||||
pending_visual_change.pending = (VisualChange::Type) 0;
|
||||
|
||||
visual_changer (vc);
|
||||
|
||||
pending_visual_change.being_handled = false;
|
||||
|
||||
visual_change_queued = true;
|
||||
|
||||
return 0; /* this is always a one-shot call */
|
||||
}
|
||||
|
||||
|
||||
/** Queue up a change to the viewport x origin.
|
||||
* @param sample New x origin.
|
||||
*/
|
||||
void
|
||||
EditingContext::reset_x_origin (samplepos_t sample)
|
||||
{
|
||||
pending_visual_change.add (VisualChange::TimeOrigin);
|
||||
pending_visual_change.time_origin = sample;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
EditingContext::reset_y_origin (double y)
|
||||
{
|
||||
pending_visual_change.add (VisualChange::YOrigin);
|
||||
pending_visual_change.y_origin = y;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
EditingContext::reset_zoom (samplecnt_t spp)
|
||||
{
|
||||
if (spp == samples_per_pixel) {
|
||||
return;
|
||||
}
|
||||
|
||||
pending_visual_change.add (VisualChange::ZoomLevel);
|
||||
pending_visual_change.samples_per_pixel = spp;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
|
|
@ -269,12 +269,15 @@ public:
|
|||
ARDOUR::SnapPref gpref) const;
|
||||
|
||||
virtual double get_y_origin () const = 0;
|
||||
virtual void reset_x_origin (samplepos_t) = 0;
|
||||
virtual void reset_y_origin (double) = 0;
|
||||
|
||||
void reset_x_origin (samplepos_t);
|
||||
void reset_y_origin (double);
|
||||
void reset_zoom (samplecnt_t);
|
||||
void set_samples_per_pixel (samplecnt_t);
|
||||
virtual void on_samples_per_pixel_changed () {}
|
||||
|
||||
virtual void set_zoom_focus (Editing::ZoomFocus) = 0;
|
||||
virtual Editing::ZoomFocus get_zoom_focus () const = 0;
|
||||
virtual void reset_zoom (samplecnt_t) = 0;
|
||||
virtual void reposition_and_zoom (samplepos_t, double) = 0;
|
||||
|
||||
sigc::signal<void> ZoomChanged;
|
||||
|
@ -343,7 +346,7 @@ public:
|
|||
virtual samplecnt_t current_page_samples() const = 0;
|
||||
|
||||
virtual ArdourCanvas::GtkCanvasViewport* get_canvas_viewport() const = 0;
|
||||
virtual ArdourCanvas::Canvas* get_canvas() const = 0;
|
||||
virtual ArdourCanvas::GtkCanvas* get_canvas() const = 0;
|
||||
|
||||
virtual size_t push_canvas_cursor (Gdk::Cursor*);
|
||||
virtual void pop_canvas_cursor ();
|
||||
|
@ -563,6 +566,43 @@ public:
|
|||
void set_common_editing_state (XMLNode const & node);
|
||||
void get_common_editing_state (XMLNode& node) const;
|
||||
|
||||
struct VisualChange {
|
||||
enum Type {
|
||||
TimeOrigin = 0x1,
|
||||
ZoomLevel = 0x2,
|
||||
YOrigin = 0x4,
|
||||
VideoTimeline = 0x8
|
||||
};
|
||||
|
||||
Type pending;
|
||||
samplepos_t time_origin;
|
||||
samplecnt_t samples_per_pixel;
|
||||
double y_origin;
|
||||
|
||||
int idle_handler_id;
|
||||
/** true if we are currently in the idle handler */
|
||||
bool being_handled;
|
||||
|
||||
VisualChange() : pending ((VisualChange::Type) 0), time_origin (0), samples_per_pixel (0), idle_handler_id (-1), being_handled (false) {}
|
||||
void add (Type t) {
|
||||
pending = Type (pending | t);
|
||||
}
|
||||
};
|
||||
|
||||
VisualChange pending_visual_change;
|
||||
bool visual_change_queued;
|
||||
|
||||
static int _idle_visual_changer (void* arg);
|
||||
int idle_visual_changer ();
|
||||
void ensure_visual_change_idle_handler ();
|
||||
virtual void visual_changer (const VisualChange&) = 0;
|
||||
|
||||
sigc::connection autoscroll_connection;
|
||||
bool autoscroll_horizontal_allowed;
|
||||
bool autoscroll_vertical_allowed;
|
||||
uint32_t autoscroll_cnt;
|
||||
ArdourCanvas::Rect autoscroll_boundary;
|
||||
|
||||
private:
|
||||
static std::queue<EditingContext*> ec_stack;
|
||||
|
||||
|
|
|
@ -317,7 +317,6 @@ Editor::Editor ()
|
|||
, _full_canvas_height (0)
|
||||
, edit_controls_left_menu (0)
|
||||
, edit_controls_right_menu (0)
|
||||
, visual_change_queued(false)
|
||||
, _tvl_no_redisplay(false)
|
||||
, _tvl_redisplay_on_resume(false)
|
||||
, _last_update_time (0)
|
||||
|
@ -378,10 +377,6 @@ Editor::Editor ()
|
|||
, _sections (0)
|
||||
, _snapshots (0)
|
||||
, _locations (0)
|
||||
, autoscroll_horizontal_allowed (false)
|
||||
, autoscroll_vertical_allowed (false)
|
||||
, autoscroll_cnt (0)
|
||||
, autoscroll_widget (0)
|
||||
, show_gain_after_trim (false)
|
||||
, _no_not_select_reimported_tracks (false)
|
||||
, selection_op_cmd_depth (0)
|
||||
|
@ -4018,36 +4013,6 @@ Editor::get_y_origin () const
|
|||
return vertical_adjustment.get_value ();
|
||||
}
|
||||
|
||||
/** Queue up a change to the viewport x origin.
|
||||
* @param sample New x origin.
|
||||
*/
|
||||
void
|
||||
Editor::reset_x_origin (samplepos_t sample)
|
||||
{
|
||||
pending_visual_change.add (VisualChange::TimeOrigin);
|
||||
pending_visual_change.time_origin = sample;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::reset_y_origin (double y)
|
||||
{
|
||||
pending_visual_change.add (VisualChange::YOrigin);
|
||||
pending_visual_change.y_origin = y;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::reset_zoom (samplecnt_t spp)
|
||||
{
|
||||
if (spp == samples_per_pixel) {
|
||||
return;
|
||||
}
|
||||
|
||||
pending_visual_change.add (VisualChange::ZoomLevel);
|
||||
pending_visual_change.samples_per_pixel = spp;
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::reposition_and_zoom (samplepos_t sample, double fpu)
|
||||
|
@ -4218,77 +4183,6 @@ Editor::playhead_cursor_sample () const
|
|||
return _playhead_cursor->current_sample();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::queue_visual_videotimeline_update ()
|
||||
{
|
||||
pending_visual_change.add (VisualChange::VideoTimeline);
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::ensure_visual_change_idle_handler ()
|
||||
{
|
||||
if (pending_visual_change.idle_handler_id < 0) {
|
||||
/* see comment in add_to_idle_resize above. */
|
||||
pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
|
||||
pending_visual_change.being_handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Editor::_idle_visual_changer (void* arg)
|
||||
{
|
||||
return static_cast<Editor*>(arg)->idle_visual_changer ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::pre_render ()
|
||||
{
|
||||
visual_change_queued = false;
|
||||
|
||||
if (pending_visual_change.pending != 0) {
|
||||
ensure_visual_change_idle_handler();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Editor::idle_visual_changer ()
|
||||
{
|
||||
pending_visual_change.idle_handler_id = -1;
|
||||
|
||||
if (pending_visual_change.pending == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set_horizontal_position() below (and maybe other calls) call
|
||||
gtk_main_iteration(), so it's possible that a signal will be handled
|
||||
half-way through this method. If this signal wants an
|
||||
idle_visual_changer we must schedule another one after this one, so
|
||||
mark the idle_handler_id as -1 here to allow that. Also make a note
|
||||
that we are doing the visual change, so that changes in response to
|
||||
super-rapid-screen-update can be dropped if we are still processing
|
||||
the last one.
|
||||
*/
|
||||
|
||||
if (visual_change_queued) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pending_visual_change.being_handled = true;
|
||||
|
||||
VisualChange vc = pending_visual_change;
|
||||
|
||||
pending_visual_change.pending = (VisualChange::Type) 0;
|
||||
|
||||
visual_changer (vc);
|
||||
|
||||
pending_visual_change.being_handled = false;
|
||||
|
||||
visual_change_queued = true;
|
||||
|
||||
return 0; /* this is always a one-shot call */
|
||||
}
|
||||
|
||||
void
|
||||
Editor::visual_changer (const VisualChange& vc)
|
||||
{
|
||||
|
@ -4346,6 +4240,23 @@ Editor::visual_changer (const VisualChange& vc)
|
|||
_summary->set_overlays_dirty ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::queue_visual_videotimeline_update ()
|
||||
{
|
||||
pending_visual_change.add (VisualChange::VideoTimeline);
|
||||
ensure_visual_change_idle_handler ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::pre_render ()
|
||||
{
|
||||
visual_change_queued = false;
|
||||
|
||||
if (pending_visual_change.pending != 0) {
|
||||
ensure_visual_change_idle_handler();
|
||||
}
|
||||
}
|
||||
|
||||
struct EditorOrderTimeAxisSorter {
|
||||
bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
|
||||
return a->order () < b->order ();
|
||||
|
|
|
@ -384,9 +384,6 @@ public:
|
|||
void restore_editing_space();
|
||||
|
||||
double get_y_origin () const;
|
||||
void reset_x_origin (samplepos_t);
|
||||
void reset_y_origin (double);
|
||||
void reset_zoom (samplecnt_t);
|
||||
void reposition_and_zoom (samplepos_t, double);
|
||||
|
||||
void reset_x_origin_to_follow_playhead ();
|
||||
|
@ -480,7 +477,7 @@ public:
|
|||
ArdourCanvas::Container* get_drag_motion_group () const { return _drag_motion_group; }
|
||||
|
||||
ArdourCanvas::GtkCanvasViewport* get_canvas_viewport () const;
|
||||
ArdourCanvas::Canvas* get_canvas () const;
|
||||
ArdourCanvas::GtkCanvas* get_canvas () const;
|
||||
|
||||
void override_visible_track_count ();
|
||||
|
||||
|
@ -1062,38 +1059,9 @@ private:
|
|||
|
||||
void tie_vertical_scrolling ();
|
||||
|
||||
struct VisualChange {
|
||||
enum Type {
|
||||
TimeOrigin = 0x1,
|
||||
ZoomLevel = 0x2,
|
||||
YOrigin = 0x4,
|
||||
VideoTimeline = 0x8
|
||||
};
|
||||
|
||||
Type pending;
|
||||
samplepos_t time_origin;
|
||||
samplecnt_t samples_per_pixel;
|
||||
double y_origin;
|
||||
|
||||
int idle_handler_id;
|
||||
/** true if we are currently in the idle handler */
|
||||
bool being_handled;
|
||||
|
||||
VisualChange() : pending ((VisualChange::Type) 0), time_origin (0), samples_per_pixel (0), idle_handler_id (-1), being_handled (false) {}
|
||||
void add (Type t) {
|
||||
pending = Type (pending | t);
|
||||
}
|
||||
};
|
||||
|
||||
VisualChange pending_visual_change;
|
||||
bool visual_change_queued;
|
||||
|
||||
void pre_render ();
|
||||
|
||||
static int _idle_visual_changer (void* arg);
|
||||
int idle_visual_changer ();
|
||||
void visual_changer (const VisualChange&);
|
||||
void ensure_visual_change_idle_handler ();
|
||||
|
||||
/* track views */
|
||||
TrackViewList track_views;
|
||||
|
@ -1918,13 +1886,6 @@ private:
|
|||
|
||||
/* autoscrolling */
|
||||
|
||||
sigc::connection autoscroll_connection;
|
||||
bool autoscroll_horizontal_allowed;
|
||||
bool autoscroll_vertical_allowed;
|
||||
uint32_t autoscroll_cnt;
|
||||
Gtk::Widget* autoscroll_widget;
|
||||
ArdourCanvas::Rect autoscroll_boundary;
|
||||
|
||||
bool autoscroll_canvas ();
|
||||
void start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary);
|
||||
void stop_canvas_autoscroll ();
|
||||
|
|
|
@ -1120,7 +1120,7 @@ Editor::get_canvas_viewport() const
|
|||
return _track_canvas_viewport;
|
||||
}
|
||||
|
||||
ArdourCanvas::Canvas*
|
||||
ArdourCanvas::GtkCanvas*
|
||||
Editor::get_canvas() const
|
||||
{
|
||||
return _track_canvas_viewport->canvas();
|
||||
|
|
|
@ -61,6 +61,7 @@ MidiCueEditor::MidiCueEditor()
|
|||
, bbt_metric (*this)
|
||||
{
|
||||
mouse_mode = Editing::MouseContent;
|
||||
autoscroll_vertical_allowed = false;
|
||||
|
||||
bindings = Bindings::get_bindings (editor_name());
|
||||
|
||||
|
@ -103,7 +104,7 @@ MidiCueEditor::get_canvas_viewport() const
|
|||
return _canvas_viewport;
|
||||
}
|
||||
|
||||
ArdourCanvas::Canvas*
|
||||
ArdourCanvas::GtkCanvas*
|
||||
MidiCueEditor::get_canvas() const
|
||||
{
|
||||
return _canvas;
|
||||
|
@ -360,9 +361,9 @@ MidiCueEditor::snap_to_internal (timepos_t& start, Temporal::RoundMode direction
|
|||
}
|
||||
|
||||
void
|
||||
MidiCueEditor::reset_zoom (samplecnt_t spp)
|
||||
MidiCueEditor::set_samples_per_pixel (samplecnt_t spp)
|
||||
{
|
||||
CueEditor::reset_zoom (spp);
|
||||
CueEditor::set_samples_per_pixel (spp);
|
||||
|
||||
if (view) {
|
||||
view->set_samples_per_pixel (spp);
|
||||
|
@ -1037,3 +1038,355 @@ MidiCueEditor::get_state () const
|
|||
get_common_editing_state (*node);
|
||||
return *node;
|
||||
}
|
||||
|
||||
/** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
|
||||
*
|
||||
* @param allow_vert true to allow vertical autoscroll, otherwise false.
|
||||
*
|
||||
*/
|
||||
void
|
||||
MidiCueEditor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
|
||||
{
|
||||
if (!UIConfiguration::instance().get_autoscroll_editor () || autoscroll_active ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* define a rectangular boundary for scrolling. If the mouse moves
|
||||
* outside of this area and/or continue to be outside of this area,
|
||||
* then we will continuously auto-scroll the canvas in the appropriate
|
||||
* direction(s)
|
||||
*
|
||||
* the boundary is defined in coordinates relative to canvas' own
|
||||
* window since that is what we're going to call ::get_pointer() on
|
||||
* during autoscrolling to determine if we're still outside the
|
||||
* boundary or not.
|
||||
*/
|
||||
|
||||
ArdourCanvas::Rect scrolling_boundary;
|
||||
Gtk::Allocation alloc;
|
||||
|
||||
alloc = get_canvas()->get_allocation ();
|
||||
|
||||
if (allow_vert) {
|
||||
/* reduce height by the height of the timebars, which happens
|
||||
to correspond to the position of the hv_scroll_group.
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - hv_scroll_group->position().y);
|
||||
alloc.set_y (alloc.get_y() + hv_scroll_group->position().y);
|
||||
|
||||
/* now reduce it again so that we start autoscrolling before we
|
||||
* move off the top or bottom of the canvas
|
||||
*/
|
||||
|
||||
alloc.set_height (alloc.get_height() - 20);
|
||||
alloc.set_y (alloc.get_y() + 10);
|
||||
}
|
||||
|
||||
/* the effective width of the autoscroll boundary so
|
||||
that we start scrolling before we hit the edge.
|
||||
|
||||
this helps when the window is slammed up against the
|
||||
right edge of the screen, making it hard to scroll
|
||||
effectively.
|
||||
*/
|
||||
|
||||
if (allow_horiz && (alloc.get_width() > 20)) {
|
||||
alloc.set_width (alloc.get_width() - 20);
|
||||
alloc.set_x (alloc.get_x() + 10);
|
||||
}
|
||||
|
||||
scrolling_boundary = ArdourCanvas::Rect (0., 0., alloc.get_width(), alloc.get_height());
|
||||
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
if ((allow_horiz && ((x < scrolling_boundary.x0 && _leftmost_sample > 0) || x >= scrolling_boundary.x1)) ||
|
||||
(allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
|
||||
start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MidiCueEditor::autoscroll_active () const
|
||||
{
|
||||
return autoscroll_connection.connected ();
|
||||
}
|
||||
|
||||
bool
|
||||
MidiCueEditor::autoscroll_canvas ()
|
||||
{
|
||||
using std::max;
|
||||
using std::min;
|
||||
int x, y;
|
||||
Gdk::ModifierType mask;
|
||||
sampleoffset_t dx = 0;
|
||||
bool no_stop = false;
|
||||
Gtk::Window* toplevel = dynamic_cast<Gtk::Window*>(_canvas_viewport->get_toplevel());
|
||||
|
||||
if (!toplevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_canvas()->get_window()->get_pointer (x, y, mask);
|
||||
|
||||
VisualChange vc;
|
||||
bool vertical_motion = false;
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
|
||||
samplepos_t new_sample = _leftmost_sample;
|
||||
|
||||
/* horizontal */
|
||||
|
||||
if (x > autoscroll_boundary.x1) {
|
||||
|
||||
/* bring it back into view */
|
||||
dx = x - autoscroll_boundary.x1;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample < max_samplepos - dx) {
|
||||
new_sample = _leftmost_sample + dx;
|
||||
} else {
|
||||
new_sample = max_samplepos;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
|
||||
} else if (x < autoscroll_boundary.x0) {
|
||||
|
||||
dx = autoscroll_boundary.x0 - x;
|
||||
dx += 10 + (2 * (autoscroll_cnt/2));
|
||||
|
||||
dx = pixel_to_sample (dx);
|
||||
|
||||
dx *= UIConfiguration::instance().get_draggable_playhead_speed();
|
||||
|
||||
if (_leftmost_sample >= dx) {
|
||||
new_sample = _leftmost_sample - dx;
|
||||
} else {
|
||||
new_sample = 0;
|
||||
}
|
||||
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
if (new_sample != _leftmost_sample) {
|
||||
vc.time_origin = new_sample;
|
||||
vc.add (VisualChange::TimeOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoscroll_vertical_allowed) {
|
||||
|
||||
// const double vertical_pos = vertical_adjustment.get_value();
|
||||
const int speed_factor = 10;
|
||||
|
||||
/* vertical */
|
||||
|
||||
if (y < autoscroll_boundary.y0) {
|
||||
|
||||
/* scroll to make higher tracks visible */
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL UP
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
|
||||
} else if (y > autoscroll_boundary.y1) {
|
||||
|
||||
if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
|
||||
// XXX SCROLL DOWN
|
||||
vertical_motion = true;
|
||||
}
|
||||
no_stop = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (vc.pending || vertical_motion) {
|
||||
|
||||
/* change horizontal first */
|
||||
|
||||
if (vc.pending) {
|
||||
visual_changer (vc);
|
||||
}
|
||||
|
||||
/* now send a motion event to notify anyone who cares
|
||||
that we have moved to a new location (because we scrolled)
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* we asked for the mouse position above (::get_pointer()) via
|
||||
* our own top level window (we being the Editor). Convert into
|
||||
* coordinates within the canvas window.
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
//toplevel->translate_coordinates (*get_canvas(), x, y, cx,
|
||||
//cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
/* clamp x and y to remain within the autoscroll boundary,
|
||||
* which is defined in window coordinates
|
||||
*/
|
||||
|
||||
x = min (max ((ArdourCanvas::Coord) cx, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
y = min (max ((ArdourCanvas::Coord) cy, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
/* now convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else if (no_stop) {
|
||||
|
||||
/* not changing visual state but pointer is outside the scrolling boundary
|
||||
* so we still need to deliver a fake motion event
|
||||
*/
|
||||
|
||||
GdkEventMotion ev;
|
||||
|
||||
ev.type = GDK_MOTION_NOTIFY;
|
||||
ev.state = Gdk::BUTTON1_MASK;
|
||||
|
||||
/* the motion handler expects events in canvas coordinate space */
|
||||
|
||||
/* first convert from Editor window coordinates to canvas
|
||||
* window coordinates
|
||||
*/
|
||||
|
||||
int cx;
|
||||
int cy;
|
||||
|
||||
/* clamp x and y to remain within the visible area. except
|
||||
* .. if horizontal scrolling is allowed, always allow us to
|
||||
* move back to zero
|
||||
*/
|
||||
|
||||
if (autoscroll_horizontal_allowed) {
|
||||
x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
|
||||
} else {
|
||||
x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
|
||||
}
|
||||
y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
|
||||
|
||||
// toplevel->translate_coordinates (*get_canvas_viewport(), x,
|
||||
// y, cx, cy);
|
||||
cx = x;
|
||||
cy = y;
|
||||
|
||||
ArdourCanvas::Duple d = get_canvas()->window_to_canvas (ArdourCanvas::Duple (cx, cy));
|
||||
ev.x = d.x;
|
||||
ev.y = d.y;
|
||||
ev.state = mask;
|
||||
|
||||
motion_handler (0, (GdkEvent*) &ev, true);
|
||||
|
||||
} else {
|
||||
stop_canvas_autoscroll ();
|
||||
return false;
|
||||
}
|
||||
|
||||
autoscroll_cnt++;
|
||||
|
||||
return true; /* call me again */
|
||||
}
|
||||
|
||||
void
|
||||
MidiCueEditor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
|
||||
{
|
||||
if (!_session) {
|
||||
return;
|
||||
}
|
||||
|
||||
stop_canvas_autoscroll ();
|
||||
|
||||
autoscroll_horizontal_allowed = allow_horiz;
|
||||
autoscroll_vertical_allowed = allow_vert;
|
||||
autoscroll_boundary = boundary;
|
||||
|
||||
/* do the first scroll right now
|
||||
*/
|
||||
|
||||
autoscroll_canvas ();
|
||||
|
||||
/* scroll again at very very roughly 30FPS */
|
||||
|
||||
autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &MidiCueEditor::autoscroll_canvas), 30);
|
||||
}
|
||||
|
||||
void
|
||||
MidiCueEditor::stop_canvas_autoscroll ()
|
||||
{
|
||||
autoscroll_connection.disconnect ();
|
||||
autoscroll_cnt = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MidiCueEditor::visual_changer (const VisualChange& vc)
|
||||
{
|
||||
/**
|
||||
* Changed first so the correct horizontal canvas position is calculated in
|
||||
* EditingContext::set_horizontal_position
|
||||
*/
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
set_samples_per_pixel (vc.samples_per_pixel);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::TimeOrigin) {
|
||||
double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
|
||||
set_horizontal_position (new_time_origin);
|
||||
}
|
||||
|
||||
if (vc.pending & VisualChange::YOrigin) {
|
||||
vertical_adjustment.set_value (vc.y_origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Now the canvas is in the final state before render the canvas items that
|
||||
* support the Item::prepare_for_render interface can calculate the correct
|
||||
* item to visible canvas intersection.
|
||||
*/
|
||||
if (vc.pending & VisualChange::ZoomLevel) {
|
||||
on_samples_per_pixel_changed ();
|
||||
|
||||
// update_tempo_based_rulers ();
|
||||
}
|
||||
|
||||
if (!(vc.pending & VisualChange::ZoomLevel)) {
|
||||
/* If the canvas is not being zoomed then the canvas items will not change
|
||||
* and cause Item::prepare_for_render to be called so do it here manually.
|
||||
* Not ideal, but I can't think of a better solution atm.
|
||||
*/
|
||||
get_canvas()->prepare_for_render();
|
||||
}
|
||||
|
||||
/* If we are only scrolling vertically there is no need to update these */
|
||||
if (vc.pending != VisualChange::YOrigin) {
|
||||
// XXX update_fixed_rulers ();
|
||||
// XXX redisplay_grid (true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ class MidiCueEditor : public CueEditor
|
|||
ArdourCanvas::ScrollGroup* get_hscroll_group () const { return h_scroll_group; }
|
||||
ArdourCanvas::ScrollGroup* get_cursor_scroll_group () const { return cursor_scroll_group; }
|
||||
|
||||
void reset_zoom (samplecnt_t);
|
||||
void set_samples_per_pixel (samplecnt_t);
|
||||
|
||||
void set_mouse_mode (Editing::MouseMode, bool force = false);
|
||||
void step_mouse_mode (bool next);
|
||||
|
@ -86,11 +86,14 @@ class MidiCueEditor : public CueEditor
|
|||
size_t n_timebars;
|
||||
|
||||
ArdourCanvas::GtkCanvasViewport* get_canvas_viewport() const;
|
||||
ArdourCanvas::Canvas* get_canvas() const;
|
||||
ArdourCanvas::GtkCanvas* get_canvas() const;
|
||||
|
||||
int set_state (const XMLNode&, int version);
|
||||
XMLNode& get_state () const;
|
||||
|
||||
void maybe_autoscroll (bool, bool, bool);
|
||||
bool autoscroll_active() const;
|
||||
|
||||
protected:
|
||||
void register_actions ();
|
||||
|
||||
|
@ -177,6 +180,14 @@ class MidiCueEditor : public CueEditor
|
|||
|
||||
bool canvas_pre_event (GdkEvent*);
|
||||
void setup_toolbar ();
|
||||
|
||||
/* autoscrolling */
|
||||
|
||||
bool autoscroll_canvas ();
|
||||
void start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary);
|
||||
void stop_canvas_autoscroll ();
|
||||
|
||||
void visual_changer (const VisualChange&);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -141,7 +141,8 @@ MidiView::MidiView (std::shared_ptr<MidiTrack> mt,
|
|||
|
||||
|
||||
MidiView::MidiView (MidiView const & other)
|
||||
: _midi_track (other._midi_track)
|
||||
: sigc::trackable ()
|
||||
, _midi_track (other._midi_track)
|
||||
, _editing_context (other.editing_context())
|
||||
, _midi_context (other.midi_context())
|
||||
, _midi_region (other.midi_region())
|
||||
|
|
Loading…
Reference in New Issue