an awful lot of tweaks to drawing details
[ardour.git] / gtk2_ardour / tempo_lines.cc
index c234cb4c51f1445ede4ed79597b0f01dc51b5348..6bf7dfbde9081e472f441309545cf9ab95978550 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002-2007 Paul Davis 
+    Copyright (C) 2002-2007 Paul Davis
 
     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
 
 */
 
-#include <libgnomecanvasmm/canvas.h>
-#include <libgnomecanvasmm/group.h>
+#include "canvas/line.h"
+#include "canvas/canvas.h"
+#include "canvas/debug.h"
 #include "tempo_lines.h"
 #include "ardour_ui.h"
 
-ArdourCanvas::SimpleLine *
-TempoLines::get_line ()
+using namespace std;
+
+TempoLines::TempoLines (ArdourCanvas::Canvas& canvas, ArdourCanvas::Group* group, double screen_height)
+       : _canvas (canvas)
+       , _group (group)
+       , _height (screen_height)
 {
-       ArdourCanvas::SimpleLine *line;
-
-       if (_free_lines.empty()) {
-               line = new ArdourCanvas::SimpleLine (*_group);
-               _used_lines.push_back (line);
-       } else {
-               line = _free_lines.front();
-               _free_lines.erase (_free_lines.begin());
-               _used_lines.push_back (line);
-       }
+}
 
-       return line;
+void
+TempoLines::tempo_map_changed()
+{
+       /* remove all lines from the group, put them in the cache (to avoid
+        * unnecessary object destruction+construction later), and clear _lines
+        */
+        
+       _group->clear ();
+       _cache.insert (_cache.end(), _lines.begin(), _lines.end());
+       _lines.clear ();
 }
 
+void
+TempoLines::show ()
+{
+       _group->show ();
+}
 
 void
 TempoLines::hide ()
 {
-       for (Lines::iterator i = _used_lines.begin(); i != _used_lines.end(); ++i) {
-       (*i)->hide();
-               _free_lines.push_back (*i);
-       }
-       _used_lines.clear ();
+       _group->hide ();
 }
 
-
 void
-TempoLines::draw (ARDOUR::TempoMap::BBTPointList& points, double frames_per_unit)
+TempoLines::draw (const ARDOUR::TempoMap::BBTPointList::const_iterator& begin, 
+                 const ARDOUR::TempoMap::BBTPointList::const_iterator& end, 
+                 double samples_per_pixel)
 {
-       ARDOUR::TempoMap::BBTPointList::iterator i;
-       ArdourCanvas::SimpleLine *line;
-       gdouble xpos;
-       double who_cares;
-       double x1, x2, y1, y2, beat_density;
+       ARDOUR::TempoMap::BBTPointList::const_iterator i;
+       ArdourCanvas::Rect const visible = _canvas.visible_area ();
+       double  beat_density;
 
        uint32_t beats = 0;
        uint32_t bars = 0;
        uint32_t color;
 
-       _canvas.get_scroll_region (x1, y1, x2, who_cares);
-       _canvas.root()->get_bounds(who_cares, who_cares, who_cares, y2);
-
        /* get the first bar spacing */
 
-       i = points.end();
+       i = end;
        i--;
-       bars = (*i).bar - (*points.begin()).bar;
-       beats = points.size() - bars;
+       bars = (*i).bar - (*begin).bar; 
+       beats = distance (begin, end) - bars;
 
-       beat_density =  (beats * 10.0f) / _canvas.get_width ();
+       beat_density = (beats * 10.0f) / visible.width ();
 
        if (beat_density > 4.0f) {
-               /* if the lines are too close together, they become useless
-                */
+               /* if the lines are too close together, they become useless */
+               tempo_map_changed();
                return;
        }
 
-       for (i = points.begin(); i != points.end(); ++i) {
-
-               switch ((*i).type) {
-               case ARDOUR::TempoMap::Bar:
-                       break;
+       tempo_map_changed ();
 
-               case ARDOUR::TempoMap::Beat:
-                       
-                       if ((*i).beat == 1) {
-                               color = ARDOUR_UI::config()->canvasvar_MeasureLineBar.get();
-                       } else {
-                               color = ARDOUR_UI::config()->canvasvar_MeasureLineBeat.get();
+       for (i = begin; i != end; ++i) {
 
-                               if (beat_density > 2.0) {
-                                       /* only draw beat lines if the gaps between beats are large.
-                                       */
-                                       break;
-                               }
+               if ((*i).is_bar()) {
+                       color = ARDOUR_UI::config()->get_canvasvar_MeasureLineBar();
+               } else {
+                       if (beat_density > 2.0) {
+                               continue; /* only draw beat lines if the gaps between beats are large. */
                        }
+                       color = ARDOUR_UI::config()->get_canvasvar_MeasureLineBeat();
+               }
+
+               ArdourCanvas::Coord xpos = rint(((framepos_t)(*i).frame) / (double)samples_per_pixel);
 
-                       xpos = rint(((nframes64_t)(*i).frame) / (double)frames_per_unit);
-                       line = get_line ();
-                       line->property_x1() = xpos;
-                       line->property_x2() = xpos;
-                       line->property_y2() = y2;
-                       line->property_color_rgba() = color;
-                       //line->raise_to_top();
-                       line->show();   
-                       break;
+               ArdourCanvas::Line* line;
+
+               if (!_cache.empty()) {
+                       line = _cache.back ();
+                       _cache.pop_back ();
+                       line->reparent (_group);
+               } else {
+                       line = new ArdourCanvas::Line (_group);
+                       CANVAS_DEBUG_NAME (line, "tempo measure line");
+                       line->set_ignore_events (true);
                }
+
+               /* move to 0.5 offset to ensure single pixel lines (see Cairo
+                * FAQ for info on why we do this).
+                */
+
+               line->set_x0 (xpos + 0.5);
+               line->set_x1 (xpos + 0.5);
+               line->set_y0 (0.0);
+               line->set_y1 (_height);
+               line->set_outline_color (color);
+               line->show ();
        }
 }
+