X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_canvas.cc;h=d9fe6f529fd2186cc1ac1d1c6a31f089c8d876c4;hb=8d1775b4582a4fe96b254dd3877377406ee51642;hp=bd6c1c99abde35870f96ab09d9e7cc5eb268a3df;hpb=17b18acda3447214bd739107d9a46eecfaa6ef70;p=ardour.git diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index bd6c1c99ab..d9fe6f529f 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -15,7 +15,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include @@ -46,12 +45,13 @@ using namespace std; using namespace sigc; using namespace ARDOUR; +using namespace PBD; using namespace Gtk; using namespace Glib; using namespace Gtkmm2ext; using namespace Editing; -/* XXX this is a hack. it ought to be the maximum value of an jack_nframes_t */ +/* XXX this is a hack. it ought to be the maximum value of an nframes_t */ const double max_canvas_coordinate = (double) JACK_MAX_FRAMES; @@ -91,6 +91,7 @@ Editor::initialize_canvas () /* don't try to center the canvas */ track_canvas.set_center_scroll_region (false); + track_canvas.set_dither (Gdk::RGB_DITHER_NONE); track_canvas.signal_event().connect (bind (mem_fun (*this, &Editor::track_canvas_event), (ArdourCanvas::Item*) 0)); track_canvas.set_name ("EditorMainCanvas"); @@ -127,11 +128,12 @@ Editor::initialize_canvas () time_line_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); cursor_group = new ArdourCanvas::Group (*track_canvas.root(), 0.0, 0.0); - + time_canvas.set_name ("EditorTimeCanvas"); time_canvas.add_events (Gdk::POINTER_MOTION_HINT_MASK); time_canvas.set_flags (CAN_FOCUS); time_canvas.set_center_scroll_region (false); + time_canvas.set_dither (Gdk::RGB_DITHER_NONE); meter_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, 0.0); tempo_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height); @@ -139,33 +141,33 @@ Editor::initialize_canvas () range_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 3.0); transport_marker_group = new ArdourCanvas::Group (*time_canvas.root(), 0.0, timebar_height * 4.0); - tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + tempo_bar = new ArdourCanvas::SimpleRect (*tempo_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); tempo_bar->property_fill_color_rgba() = color_map[cTempoBar]; tempo_bar->property_outline_pixels() = 0; - meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + meter_bar = new ArdourCanvas::SimpleRect (*meter_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); meter_bar->property_fill_color_rgba() = color_map[cMeterBar]; meter_bar->property_outline_pixels() = 0; - marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + marker_bar = new ArdourCanvas::SimpleRect (*marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); marker_bar->property_fill_color_rgba() = color_map[cMarkerBar]; marker_bar->property_outline_pixels() = 0; - range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); range_marker_bar->property_fill_color_rgba() = color_map[cRangeMarkerBar]; range_marker_bar->property_outline_pixels() = 0; - transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); transport_marker_bar->property_fill_color_rgba() = color_map[cTransportMarkerBar]; transport_marker_bar->property_outline_pixels() = 0; - range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + range_bar_drag_rect = new ArdourCanvas::SimpleRect (*range_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); range_bar_drag_rect->property_fill_color_rgba() = color_map[cRangeDragBarRectFill]; range_bar_drag_rect->property_outline_color_rgba() = color_map[cRangeDragBarRect]; range_bar_drag_rect->property_outline_pixels() = 0; range_bar_drag_rect->hide (); - transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height); + transport_bar_drag_rect = new ArdourCanvas::SimpleRect (*transport_marker_group, 0.0, 0.0, max_canvas_coordinate, timebar_height-1.0); transport_bar_drag_rect ->property_fill_color_rgba() = color_map[cTransportDragRectFill]; transport_bar_drag_rect->property_outline_color_rgba() = color_map[cTransportDragRect]; transport_bar_drag_rect->property_outline_pixels() = 0; @@ -261,53 +263,71 @@ Editor::initialize_canvas () double time_width = FLT_MAX/frames_per_unit; time_canvas.set_scroll_region(0.0, 0.0, time_width, time_height); - edit_cursor = new Cursor (*this, "blue", &Editor::canvas_edit_cursor_event); - playhead_cursor = new Cursor (*this, "red", &Editor::canvas_playhead_cursor_event); - + if (!color_map[cEditCursor]) { + warning << _("edit cursor color not defined, check your ardour.colors file!") << endmsg; + color_map[cEditCursor] = RGBA_TO_UINT (30,30,30,255); + } + + if (!color_map[cPlayHead]) { + warning << _("playhead color not defined, check your ardour.colors file!") << endmsg; + color_map[cPlayHead] = RGBA_TO_UINT (0,0,0,255); + } + + edit_cursor = new Cursor (*this, &Editor::canvas_edit_cursor_event); + edit_cursor->canvas_item.property_fill_color_rgba() = color_map[cEditCursor]; + playhead_cursor = new Cursor (*this, &Editor::canvas_playhead_cursor_event); + playhead_cursor->canvas_item.property_fill_color_rgba() = color_map[cPlayHead]; + + initial_ruler_update_required = true; track_canvas.signal_size_allocate().connect (mem_fun(*this, &Editor::track_canvas_allocate)); + } void Editor::track_canvas_allocate (Gtk::Allocation alloc) { - static bool first_time = true; + canvas_allocation = alloc; - canvas_width = alloc.get_width(); - canvas_height = alloc.get_height(); + if (!initial_ruler_update_required) { + if (!canvas_idle_queued) { + /* call this first so that we do stuff before any pending redraw */ + Glib::signal_idle().connect (mem_fun (*this, &Editor::track_canvas_size_allocated), false); + canvas_idle_queued = true; + } + return; + } - if (session == 0 && !ARDOUR_UI::instance()->will_create_new_session_automatically()) { + initial_ruler_update_required = false; + + track_canvas_size_allocated (); +} - /* this mess of code is here to find out how wide this text is and - position the message in the center of the editor window. - */ - - ustring msg = string_compose ("%1%2", - _("Start a new session\n"), _("via Session menu")); - - RefPtr layout = create_pango_layout (msg); - Pango::FontDescription font = get_font_for_style (N_("FirstActionMessage")); - int width, height; - get_ink_pixel_size (layout, width, height); - - if (first_action_message == 0) { - - first_action_message = new ArdourCanvas::Text (*track_canvas.root()); - first_action_message->property_font_desc() = font; - first_action_message->property_fill_color_rgba() = color_map[cFirstActionMessage]; - first_action_message->property_x() = (canvas_width - width) / 2.0; - first_action_message->property_y() = (canvas_height/2.0) - height; - first_action_message->property_anchor() = ANCHOR_NORTH_WEST; - first_action_message->property_markup() = msg; - - } else { +bool +Editor::track_canvas_size_allocated () +{ + if (canvas_idle_queued) { + canvas_idle_queued = false; + } + + canvas_width = canvas_allocation.get_width(); + canvas_height = canvas_allocation.get_height(); + + full_canvas_height = canvas_height; + + if (session) { + TrackViewList::iterator i; + double height = 0; - /* center it */ - first_action_message->property_x() = (canvas_width - width) / 2.0; - first_action_message->property_y() = (canvas_height/2.0) - height; + for (i = track_views.begin(); i != track_views.end(); ++i) { + if ((*i)->control_parent) { + height += (*i)->effective_height; + } } + + full_canvas_height = height; } - zoom_range_clock.set ((jack_nframes_t) floor ((canvas_width * frames_per_unit))); + zoom_range_clock.set ((nframes_t) floor ((canvas_width * frames_per_unit))); edit_cursor->set_position (edit_cursor->current_frame); playhead_cursor->set_position (playhead_cursor->current_frame); @@ -318,7 +338,7 @@ Editor::track_canvas_allocate (Gtk::Allocation alloc) if (playhead_cursor) playhead_cursor->set_length (canvas_height); if (marker_drag_line) { - marker_drag_line_points.back().set_x(canvas_height); + marker_drag_line_points.back().set_y(canvas_height); marker_drag_line->property_points() = marker_drag_line_points; } @@ -347,16 +367,12 @@ Editor::track_canvas_allocate (Gtk::Allocation alloc) transport_punchout_line->property_y2() = canvas_height; } - update_fixed_rulers (); - - if (is_visible() && first_time) { - tempo_map_changed (Change (0)); - first_time = false; - } else { - redisplay_tempo (); - } + update_fixed_rulers(); + tempo_map_changed (Change (0), true); Resized (); /* EMIT_SIGNAL */ + + return false; } void @@ -368,21 +384,12 @@ Editor::reset_scrolling_region (Gtk::Allocation* alloc) for (pos = 0, i = rows.begin(); i != rows.end(); ++i) { TimeAxisView *tv = (*i)[route_display_columns.tv]; - if (tv != 0) { + if (tv != 0 && !tv->hidden()) { pos += tv->effective_height; - pos += track_spacing; } } - // old: ceil ((double) max_frames / frames_per_unit); - - double last_canvas_unit; - - if (session) { - last_canvas_unit = (session->get_maximum_extent() + (current_page_frames() * 0.10f)) / frames_per_unit; - } else { - last_canvas_unit = 0; - } + double last_canvas_unit = last_canvas_frame / frames_per_unit; track_canvas.set_scroll_region (0.0, 0.0, max (last_canvas_unit, canvas_width), pos); @@ -403,7 +410,6 @@ Editor::controls_layout_size_request (Requisition* req) TimeAxisView *tv = (*i)[route_display_columns.tv]; if (tv != 0) { pos += tv->effective_height; - pos += track_spacing; } } @@ -418,6 +424,10 @@ Editor::controls_layout_size_request (Requisition* req) edit_controls_vbox.check_resize(); req->width = max (edit_controls_vbox.get_width(), controls_layout.get_width()); + + /* don't get too big. the fudge factors here are just guesses */ + + req->width = min (req->width, screen->get_width() - 300); req->height = min ((gint) pos, (screen->get_height() - 400)); /* this one is important: it determines how big the layout thinks it really is, as @@ -466,7 +476,7 @@ Editor::drop_paths (const RefPtr& context, vector paths; string spath; GdkEvent ev; - jack_nframes_t frame; + nframes_t frame; if (convert_drop_to_paths (paths, context, x, y, data, info, time)) { goto out; @@ -494,7 +504,7 @@ Editor::drop_paths (const RefPtr& context, /* drop onto canvas background: create new tracks */ - jack_nframes_t pos = 0; + nframes_t pos = 0; do_embed (paths, false, ImportAsTrack, 0, pos, false); } else if ((tv = dynamic_cast(tvp)) != 0) { @@ -516,18 +526,203 @@ Editor::drop_regions (const RefPtr& context, const SelectionData& data, guint info, guint time) { - const DnDTreeView::SerializedObjectPointers* sr = reinterpret_cast (data.get_data()); + const SerializedObjectPointers >* sr = + reinterpret_cast > *> (data.get_data()); for (uint32_t i = 0; i < sr->cnt; ++i) { - Region* r = reinterpret_cast (sr->ptr[i]); - AudioRegion* ar; + boost::shared_ptr r = sr->data[i]; + boost::shared_ptr ar; - if ((ar = dynamic_cast(r)) != 0) { - insert_region_list_drag (*ar, x, y); + if ((ar = boost::dynamic_pointer_cast(r)) != 0) { + insert_region_list_drag (ar, x, y); } } context->drag_finish (true, false, time); } +void +Editor::maybe_autoscroll (GdkEvent* event) +{ + nframes_t rightmost_frame = leftmost_frame + current_page_frames(); + nframes_t frame = drag_info.current_pointer_frame; + bool startit = false; + + static int last_autoscroll_direction = 0; + + if (frame > rightmost_frame) { + + if (rightmost_frame < max_frames) { + autoscroll_direction = 1; + startit = true; + } + + } else if (frame < leftmost_frame) { + + if (leftmost_frame > 0) { + autoscroll_direction = -1; + startit = true; + } + + } else { + + if (drag_info.last_pointer_frame > drag_info.current_pointer_frame) { + autoscroll_direction = -1; + } else { + autoscroll_direction = 1; + } + } + + + if ((autoscroll_direction != last_autoscroll_direction) || (leftmost_frame < frame < rightmost_frame)) { + stop_canvas_autoscroll (); + } + + if (startit && autoscroll_timeout_tag < 0) { + start_canvas_autoscroll (autoscroll_direction); + } + + last_autoscroll_direction = autoscroll_direction; +} + +gint +Editor::_autoscroll_canvas (void *arg) +{ + return ((Editor *) arg)->autoscroll_canvas (); +} + +bool +Editor::autoscroll_canvas () +{ + nframes_t new_frame; + nframes_t limit = max_frames - current_page_frames(); + GdkEventMotion ev; + nframes_t target_frame; + + if (autoscroll_direction < 0) { + if (leftmost_frame < autoscroll_distance) { + new_frame = 0; + } else { + new_frame = leftmost_frame - autoscroll_distance; + } + target_frame = drag_info.current_pointer_frame - autoscroll_distance; + } else { + if (leftmost_frame > limit - autoscroll_distance) { + new_frame = limit; + } else { + new_frame = leftmost_frame + autoscroll_distance; + } + target_frame = drag_info.current_pointer_frame + autoscroll_distance; + } + + /* now fake a motion event to get the object that is being dragged to move too */ + + ev.type = GDK_MOTION_NOTIFY; + ev.state &= Gdk::BUTTON1_MASK; + ev.x = frame_to_unit (target_frame); + ev.y = drag_info.current_pointer_y; + motion_handler (drag_info.item, (GdkEvent*) &ev, drag_info.item_type, true); + + if (new_frame == 0 || new_frame == limit) { + /* we are done */ + return false; + } + + autoscroll_cnt++; + + if (autoscroll_cnt == 1) { + + /* connect the timeout so that we get called repeatedly */ + + autoscroll_timeout_tag = g_idle_add ( _autoscroll_canvas, this); + return false; + + } + + if (new_frame != leftmost_frame) { + reset_x_origin (new_frame); + } + + if (autoscroll_cnt == 50) { /* 0.5 seconds */ + + /* after about a while, speed up a bit by changing the timeout interval */ + + autoscroll_distance = (nframes_t) floor (current_page_frames()/30.0f); + + } else if (autoscroll_cnt == 150) { /* 1.0 seconds */ + + autoscroll_distance = (nframes_t) floor (current_page_frames()/20.0f); + + } else if (autoscroll_cnt == 300) { /* 1.5 seconds */ + + /* after about another while, speed up by increasing the shift per callback */ + + autoscroll_distance = (nframes_t) floor (current_page_frames()/10.0f); + + } + + return true; +} + +void +Editor::start_canvas_autoscroll (int dir) +{ + if (!session || autoscroll_active) { + return; + } + + stop_canvas_autoscroll (); + + autoscroll_active = true; + autoscroll_direction = dir; + autoscroll_distance = (nframes_t) floor (current_page_frames()/50.0); + autoscroll_cnt = 0; + + /* do it right now, which will start the repeated callbacks */ + + autoscroll_canvas (); +} + +void +Editor::stop_canvas_autoscroll () +{ + if (autoscroll_timeout_tag >= 0) { + g_source_remove (autoscroll_timeout_tag); + autoscroll_timeout_tag = -1; + } + + autoscroll_active = false; +} + +gint +Editor::left_track_canvas (GdkEventCrossing *ev) +{ + set_entered_track (0); + set_entered_regionview (0); + return FALSE; +} + + +void +Editor::canvas_horizontally_scrolled () +{ + /* this is the core function that controls horizontal scrolling of the canvas. it is called + whenever the horizontal_adjustment emits its "value_changed" signal. it typically executes in an + idle handler, which is important because tempo_map_changed() should issue redraws immediately + and not defer them to an idle handler. + */ + + leftmost_frame = (nframes_t) floor (horizontal_adjustment.get_value() * frames_per_unit); + nframes_t rightmost_frame = leftmost_frame + current_page_frames (); + + if (rightmost_frame > last_canvas_frame) { + last_canvas_frame = rightmost_frame; + reset_scrolling_region (); + } + + update_fixed_rulers (); + + tempo_map_changed (Change (0), !_dragging_hscrollbar); +} +