Logo Search packages:      
Sourcecode: ardour version File versions  Download package

fastmeter.cc

/*
    Copyright (C) 2003 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
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id: fastmeter.cc,v 1.10 2005/04/18 19:08:06 pauld Exp $
*/

#include <iostream>
#include <cmath>
#include <algorithm>
#include <gtkmmext/fastmeter.h>
#include <gtk--/style.h>

using namespace Gtk;
using namespace Gtkmmext;
using namespace std;

GdkPixmap *FastMeter::v_pixmap = 0;
GdkBitmap *FastMeter::v_mask = 0;
gint       FastMeter::v_pixheight = 0;
gint       FastMeter::v_pixwidth = 0;

GdkPixmap *FastMeter::h_pixmap = 0;
GdkBitmap *FastMeter::h_mask = 0;
gint       FastMeter::h_pixheight = 0;
gint       FastMeter::h_pixwidth = 0;

FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o)
{
      orientation = o;
      hold_cnt = hold;
      hold_state = 0;
      current_peak = 0;
      current_level = 0;
      current_user_level = -100.0f;
      
      set_events (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
      
      pixrect.x = 0;
      pixrect.y = 0;

      if (orientation == Vertical) {
            pixrect.width = min (v_pixwidth, (gint) dimen);
            pixrect.height = v_pixheight;
      } else {
            pixrect.width = h_pixwidth;
            pixrect.height = min (h_pixheight, (gint) dimen);
      }

      request_width = pixrect.width;
      request_height = pixrect.height;

      backing = 0;
}

FastMeter::~FastMeter ()
{
      if (backing) {
            gdk_pixmap_unref (backing);
      }
}

void
FastMeter::set_vertical_xpm (const char **xpm)
{
      if (v_pixmap == 0) {
            gint w, h;
            
            v_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,  gdk_colormap_get_system(),
                                                  &v_mask, NULL, (gchar **) xpm);

            gdk_window_get_size (v_pixmap, &w, &h);
            
            v_pixheight = h;
            v_pixwidth = w;
      }
}

void
FastMeter::set_horizontal_xpm (const char **xpm)
{
      if (h_pixmap == 0) {
            gint w, h;
            
            h_pixmap = gdk_pixmap_colormap_create_from_xpm_d (NULL,  gdk_colormap_get_system(),
                                                  &h_mask, NULL, (gchar **) xpm);

            gdk_window_get_size (h_pixmap, &w, &h);
            
            h_pixheight = h;
            h_pixwidth = w;
      }
}

void
FastMeter::set_hold_count (long val)
{
      if (val < 1) {
            val = 1;
      }
      
      hold_cnt = val;
      hold_state = 0;
      current_peak = 0;
      
      queue_draw ();
}

void
FastMeter::size_request_impl (GtkRequisition* req)
{
      req->width = request_width;
      req->height = request_height;
}

gint
FastMeter::expose_event_impl (GdkEventExpose* ev)
{
      if (orientation == Vertical) {
            return vertical_expose (ev);
      } else {
            return horizontal_expose (ev);
      }
}

gint
FastMeter::vertical_expose (GdkEventExpose* ev)
{
      GdkRectangle intersect;
      gint top_of_meter;
      int blit = FALSE;

      top_of_meter = (gint) floor (v_pixheight * current_level);
      pixrect.height = v_pixheight - top_of_meter; /* bottom of background */

      if (backing == 0) {
            backing = gdk_pixmap_new (get_window(), width(), height(), -1);
      }

      if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersect)) {

            /* paint the background (black). */
            
            gdk_draw_rectangle (backing, get_style()->get_black_gc(), TRUE, 
                            intersect.x, intersect.y, intersect.width, intersect.height);
            blit = TRUE;
      }
      
      pixrect.height = top_of_meter;

      if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersect)) {

            /* draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom)
             */
            
            gdk_draw_pixmap (backing, get_style()->get_fg_gc(get_state()), 
                         v_pixmap,
                         intersect.x, v_pixheight - top_of_meter,
                         intersect.x, v_pixheight - top_of_meter,
                         intersect.width, intersect.height);
            
            blit = TRUE;
      }

      /* draw peak bar */
            
      if (hold_state) {
            gdk_draw_pixmap (backing, get_style()->get_fg_gc(get_state()), 
                         v_pixmap,
                         intersect.x, v_pixheight - (gint) floor (v_pixheight * current_peak),
                         intersect.x, v_pixheight - (gint) floor (v_pixheight * current_peak),
                         intersect.width, 3);
      }

      /* bilt to on-screen drawable */

      if (blit) {
            gdk_draw_pixmap (get_window(), get_style()->get_fg_gc(get_state()), 
                         backing,
                         ev->area.x, ev->area.y,
                         ev->area.x, ev->area.y,
                         ev->area.width, ev->area.height);
      }

      return TRUE;
}

gint
FastMeter::horizontal_expose (GdkEventExpose* ev)
{
      GdkRectangle intersect;
      gint right_of_meter;
      int blit = FALSE;

      right_of_meter = (gint) floor (h_pixwidth * current_level);

      pixrect.x = right_of_meter;
      pixrect.y = 0;
      pixrect.width = h_pixwidth - right_of_meter; 
      
      if (backing == 0) {
            backing = gdk_pixmap_new (get_window(), width(), height(), -1);
      }

      if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersect)) {

            /* paint the background (black). */
            
            gdk_draw_rectangle (backing, get_style()->get_black_gc(), TRUE, 
                            intersect.x, intersect.y, intersect.width, intersect.height);
            blit = TRUE;
      }
      
      pixrect.x = 0;
      pixrect.width = right_of_meter;

      if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersect)) {

            /* draw the part of the meter image that we need. 
             */

            gdk_draw_pixmap (backing, get_style()->get_fg_gc(get_state()), 
                         h_pixmap,
                         intersect.x, intersect.y,
                         intersect.x, intersect.y,
                         intersect.width, intersect.height);
            
            blit = TRUE;
      }

      /* draw peak bar */
            
      if (hold_state) {
            gdk_draw_pixmap (backing, get_style()->get_fg_gc(get_state()), 
                         h_pixmap,
                         right_of_meter, intersect.y,
                         right_of_meter, intersect.y,
                         3, intersect.height);
      }

      /* bilt to on-screen drawable */

      if (blit) {
            gdk_draw_pixmap (get_window(), get_style()->get_fg_gc(get_state()), 
                         backing,
                         ev->area.x, ev->area.y,
                         ev->area.x, ev->area.y,
                         ev->area.width, ev->area.height);
      }

      return TRUE;
}

void
FastMeter::set (float lvl, float usrlvl)
{
      current_level = lvl;
      current_user_level = usrlvl;
      
      if (lvl > current_peak) {
            current_peak = lvl;
            hold_state = hold_cnt;
      }
      
      if (hold_state > 0) {
            if (--hold_state == 0) {
                  current_peak = lvl;
            }
      }

      queue_draw ();
}

void
FastMeter::clear ()
{
      current_level = 0;
      current_peak = 0;
      hold_state = 0;
      queue_draw ();
}

Generated by  Doxygen 1.6.0   Back to index