Remove LocaleGuard from ARDOUR::IO class state methods
[ardour.git] / libs / canvas / meter.cc
index d71370ad48d97e25018860f42094bc22ecf34315..833ab8c4041d3beb745a4fedc20fc75d1950534d 100644 (file)
@@ -140,9 +140,6 @@ Meter::init (int clr0, int clr1, int clr2, int clr3,
        _stp[2] = stp2;
        _stp[3] = stp3;
 
-       pixrect.x = 1;
-       pixrect.y = 1;
-
        if (!len) {
                len = 250;
        }
@@ -159,15 +156,23 @@ Meter::init (int clr0, int clr1, int clr2, int clr3,
                bgpattern = horizontal_background (pixwidth + 2, pixheight + 2, _bgc, false);
        }
 
-       pixrect.width = pixwidth;
        pixrect.height = pixheight;
+       pixrect.x = 1;
+
+       if (orientation == Vertical) {
+               pixrect.width = pixwidth;
+               pixrect.y = pixheight; /* bottom of meter, so essentially "show zero" */
+       } else {
+               pixrect.width = 0; /* right of meter, so essentially "show zero" */
+               pixrect.y = 1;
+       }
 }
 
 void
 Meter::compute_bounding_box () const
 {
        if (!_canvas) {
-               _bounding_box = boost::optional<Rect> ();
+               _bounding_box = Rect ();
                _bounding_box_dirty = false;
                return;
        }
@@ -505,10 +510,13 @@ Meter::vertical_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Co
        Cairo::RectangleInt background;
        Cairo::RectangleInt area_r;
 
-       area_r.x = area.x0;
-       area_r.y = area.y0;
-       area_r.width = area.width();
-       area_r.height = area.height();
+       /* convert expose area back to item coordinate space */
+       Rect area2 = window_to_item (area);
+
+       area_r.x = area2.x0;
+       area_r.y = area2.y0;
+       area_r.width = area2.width();
+       area_r.height = area2.height();
 
        context->set_source_rgb (0, 0, 0); // black
        rounded_rectangle (context, 0, 0, pixwidth + 2, pixheight + 2, 2);
@@ -516,10 +524,17 @@ Meter::vertical_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Co
 
        top_of_meter = (gint) floor (pixheight * current_level);
 
-       /* reset the height & origin of the rect that needs to show the pixbuf
+       /* reset the height & origin of the rect that needs to show the meter pattern
         */
-
        pixrect.height = top_of_meter;
+
+       /* X/cairo coordinates; y grows down so y origin of pixrect (pattern
+          fill area) is the TOP of the pattern area, which we compute like this:
+
+          - start at 1
+           - go to bottom of meter (pixheight)
+           - back up by current meter height (top_of_meter)
+       */
        pixrect.y = 1 + pixheight - top_of_meter;
 
        background.x = 1;
@@ -537,8 +552,8 @@ Meter::vertical_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Co
 
        if (!r1->empty()) {
                Cairo::RectangleInt i (r1->get_extents ());
-               context->rectangle (i.x, i.y, i.width, i.height);
                context->set_source (bgpattern);
+               context->rectangle (i.x, i.y, i.width, i.height);
                context->fill ();
        }
 
@@ -548,8 +563,8 @@ Meter::vertical_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Co
        if (!r2->empty()) {
                // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
                Cairo::RectangleInt i (r2->get_extents ());
-               context->rectangle (i.x, i.y, i.width, i.height);
                context->set_source (fgpattern);
+               context->rectangle (i.x, i.y, i.width, i.height);
                context->fill ();
        }
 
@@ -595,7 +610,6 @@ Meter::horizontal_expose (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::
        /* convert expose area back to item coordinate space */
        Rect area2 = window_to_item (area);
 
-
        /* create a Cairo object so that we can use intersect and Region */
        area_r.x = area2.x0;
        area_r.y = area2.y0;
@@ -715,12 +729,10 @@ Meter::set (float lvl, float peak)
        }
 
        if (orientation == Vertical) {
-               //queue_vertical_redraw (old_level);
+               queue_vertical_redraw (old_level);
        } else {
-               //queue_horizontal_redraw (old_level);
+               queue_horizontal_redraw (old_level);
        }
-
-       redraw ();
 }
 
 void
@@ -728,19 +740,47 @@ Meter::queue_vertical_redraw (float old_level)
 {
        Cairo::RectangleInt rect;
 
-       gint new_top = (gint) floor (pixheight * current_level);
+       gint new_height = (gint) floor (pixheight * current_level);
+
+       /* this is the nominal area that needs to be filled by the meter
+        * pattern
+        */
 
        rect.x = 1;
        rect.width = pixwidth;
-       rect.height = new_top;
-       rect.y = 1 + pixheight - new_top;
+
+       /* compute new top of meter (rect.y) by starting at one (border
+        * offset), go down the full height of the meter (X/Cairo coordinates
+        * grow down) to get to the bottom coordinate, then back up by the
+        * height of the patterned area.
+        */
+       rect.y = 1 + pixheight - new_height;
+       /* remember: height extends DOWN thanks to X/Cairo */
+       rect.height = new_height;
+
+       /* now lets optimize redrawing by figuring out which part needs to be
+          actually redrawn (i.e. re-use the last drawn state).
+       */
 
        if (current_level > old_level) {
-               /* colored/pixbuf got larger, just draw the new section */
-               /* rect.y stays where it is because of X coordinates */
-               /* height of invalidated area is between new.y (smaller) and old.y
-                  (larger).
-                  X coordinates just make my brain hurt.
+               /* filled area got taller, just draw the new section */
+
+               /* rect.y (new y origin) is smaller or equal to pixrect.y (old
+                * y origin) because the top of the meter is higher (X/Cairo:
+                * coordinates grow down). 
+                *
+                * Leave rect.y alone, and recompute the height to be just the
+                * difference between the new bottom and the top of the previous
+                * pattern area.
+                *
+                * The old pattern area extended DOWN from pixrect.y to
+                * pixrect.y + pixrect.height.
+                *
+                * The new pattern area extends DOWN from rect.y to 
+                * rect.y + rect.height
+                *
+                * The area needing to be drawn is the difference between the
+                * old top (pixrect.y) and the new top (rect.y)
                */
                rect.height = pixrect.y - rect.y;
        } else {