diff options
author | Sampo Savolainen <v2@iki.fi> | 2006-06-07 21:21:21 +0000 |
---|---|---|
committer | Sampo Savolainen <v2@iki.fi> | 2006-06-07 21:21:21 +0000 |
commit | 9d01165d3d9a163a9a70a8fe3fae4c66987bb86d (patch) | |
tree | 3412405e567d26f77d1f452fad7f5df63362f4e9 /libs/gtkmm2ext | |
parent | d6cf62e911afb45c28873718972744ded3efc533 (diff) |
Dynamically generated meter gradients
git-svn-id: svn://localhost/ardour2/trunk@570 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r-- | libs/gtkmm2ext/fastmeter.cc | 337 | ||||
-rw-r--r-- | libs/gtkmm2ext/gtkmm2ext/fastmeter.h | 27 |
2 files changed, 286 insertions, 78 deletions
diff --git a/libs/gtkmm2ext/fastmeter.cc b/libs/gtkmm2ext/fastmeter.cc index 2e20c49868..f0ee0ddea1 100644 --- a/libs/gtkmm2ext/fastmeter.cc +++ b/libs/gtkmm2ext/fastmeter.cc @@ -25,6 +25,7 @@ #include <gtkmm2ext/fastmeter.h> #include <gtkmm2ext/utils.h> #include <gtkmm/style.h> +#include <string.h> using namespace Gtk; using namespace Gdk; @@ -32,15 +33,15 @@ using namespace Glib; using namespace Gtkmm2ext; using namespace std; -string FastMeter::v_image_path; -string FastMeter::h_image_path; -RefPtr<Pixbuf> FastMeter::v_pixbuf; -gint FastMeter::v_pixheight = 0; -gint FastMeter::v_pixwidth = 0; -RefPtr<Pixbuf> FastMeter::h_pixbuf; -gint FastMeter::h_pixheight = 0; -gint FastMeter::h_pixwidth = 0; +int FastMeter::min_v_pixbuf_size = 50; +int FastMeter::max_v_pixbuf_size = 1024; +Glib::RefPtr<Gdk::Pixbuf>* FastMeter::v_pixbuf_cache = 0; + +int FastMeter::min_h_pixbuf_size = 50; +int FastMeter::max_h_pixbuf_size = 1024; +Glib::RefPtr<Gdk::Pixbuf>* FastMeter::h_pixbuf_cache = 0; + FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o) { @@ -56,44 +57,182 @@ FastMeter::FastMeter (long hold, unsigned long dimen, Orientation o) pixrect.x = 0; pixrect.y = 0; - if (!v_image_path.empty() && v_pixbuf == 0) { - v_pixbuf = Pixbuf::create_from_file (v_image_path); - v_pixheight = v_pixbuf->get_height(); - v_pixwidth = v_pixbuf->get_width(); - } - if (!h_image_path.empty() && h_pixbuf == 0) { - h_pixbuf = Pixbuf::create_from_file (h_image_path); - h_pixheight = h_pixbuf->get_height(); - h_pixwidth = h_pixbuf->get_width(); + if (orientation == Vertical) { + pixbuf = request_vertical_meter(250); + } else { + pixbuf = request_horizontal_meter(186); } + pixheight = pixbuf->get_height(); + pixwidth = pixbuf->get_width(); + if (orientation == Vertical) { - pixrect.width = min (v_pixwidth, (gint) dimen); - pixrect.height = v_pixheight; + pixrect.width = min (pixwidth, (gint) dimen); + pixrect.height = pixheight; } else { - pixrect.width = h_pixwidth; - pixrect.height = min (h_pixheight, (gint) dimen); + pixrect.width = pixwidth; + pixrect.height = min (pixheight, (gint) dimen); } request_width = pixrect.width; request_height= pixrect.height; } -FastMeter::~FastMeter () +Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_vertical_meter(int length) { + if (length < min_v_pixbuf_size) + length = min_v_pixbuf_size; + if (length > max_v_pixbuf_size) + length = max_v_pixbuf_size; + + int index = length - 1; + + if (v_pixbuf_cache == 0) { + v_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size); + memset(v_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_v_pixbuf_size); + } + Glib::RefPtr<Gdk::Pixbuf> ret = v_pixbuf_cache[index]; + if (ret) + return ret; + + guint8* data; + int width = 5; + int height = length; + + data = (guint8*) malloc(width*height * 3); + + guint8 r,g,b; + r=0; + g=255; + b=0; + + // fake log calculation copied from log_meter.h + // actual calculation: + // log_meter(0.0f) = + // def = (0.0f + 20.0f) * 2.5f + 50f + // return def / 115.0f + int knee = (int)floor((float)height * 100.0f / 115.0f); + + int y; + + for (y = 0; y < knee / 2; y++) { + + r = (guint8)floor(255.0 * (float)y/(float)(knee / 2)); + + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + for (; y < knee; y++) { + + g = 255 - (guint8)floor(170.0 * (float)(y - knee/ 2)/(float)(knee / 2)); + + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + r=255; + g=0; + b=0; + for (; y < height; y++) { + for (int x = 0; x < width; x++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3); + v_pixbuf_cache[index] = ret; + + return ret; } -void -FastMeter::set_vertical_xpm (std::string path) +Glib::RefPtr<Gdk::Pixbuf> FastMeter::request_horizontal_meter(int length) { - v_image_path = path; + if (length < min_h_pixbuf_size) + length = min_h_pixbuf_size; + if (length > max_h_pixbuf_size) + length = max_h_pixbuf_size; + + int index = length - 1; + + if (h_pixbuf_cache == 0) { + h_pixbuf_cache = (Glib::RefPtr<Gdk::Pixbuf>*) malloc(sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size); + memset(h_pixbuf_cache,0,sizeof(Glib::RefPtr<Gdk::Pixbuf>) * max_h_pixbuf_size); + } + Glib::RefPtr<Gdk::Pixbuf> ret = h_pixbuf_cache[index]; + if (ret) + return ret; + + guint8* data; + int width = length; + int height = 5; + + data = (guint8*) malloc(width*height * 3); + + guint8 r,g,b; + r=0; + g=255; + b=0; + + // fake log calculation copied from log_meter.h + // actual calculation: + // log_meter(0.0f) = + // def = (0.0f + 20.0f) * 2.5f + 50f + // return def / 115.0f + int knee = (int)floor((float)width * 100.0f / 115.0f); + + int x; + + for (x = 0; x < knee / 2; x++) { + + r = (guint8)floor(255.0 * (float)x/(float)(knee / 2)); + + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + for (; x < knee; x++) { + + g = 255 - (guint8)floor(170.0 * (float)(x - knee/ 2)/(float)(knee / 2)); + + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + r=255; + g=0; + b=0; + for (; x < width; x++) { + for (int y = 0; y < height; y++) { + data[ (x+(height-y-1)*width) * 3 + 0 ] = r; + data[ (x+(height-y-1)*width) * 3 + 1 ] = g; + data[ (x+(height-y-1)*width) * 3 + 2 ] = b; + } + } + + ret = Pixbuf::create_from_data(data, COLORSPACE_RGB, false, 8, width, height, width * 3); + h_pixbuf_cache[index] = ret; + + return ret; } -void -FastMeter::set_horizontal_xpm (std::string path) +FastMeter::~FastMeter () { - h_image_path = path; } void @@ -113,8 +252,63 @@ FastMeter::set_hold_count (long val) void FastMeter::on_size_request (GtkRequisition* req) { - req->width = request_width; - req->height = request_height; + if (orientation == Vertical) { + req->height = request_height; + + req->height = max(req->height, min_v_pixbuf_size); + req->height = min(req->height, max_v_pixbuf_size); + + req->width = 5; + } else { + req->width = request_width; + + req->width = max(req->width, min_h_pixbuf_size); + req->width = min(req->width, max_h_pixbuf_size); + + req->height = 5; + } + +} + +void +FastMeter::on_size_allocate (Gtk::Allocation &alloc) +{ + if (orientation == Vertical) { + if (alloc.get_width() != 5) { + alloc.set_width(5); + } + + int h = alloc.get_height(); + h = max(h, min_v_pixbuf_size); + h = min(h, max_v_pixbuf_size); + + if ( h != alloc.get_height()) + alloc.set_height(h); + + if (pixheight != h) { + pixbuf = request_vertical_meter(h); + } + } else { + if (alloc.get_height() != 5) { + alloc.set_height(5); + } + + int w = alloc.get_width(); + w = max(w, min_h_pixbuf_size); + w = min(w, max_h_pixbuf_size); + + if ( w != alloc.get_width()) + alloc.set_width(w); + + if (pixwidth != w) { + pixbuf = request_horizontal_meter(w); + } + } + + pixheight = pixbuf->get_height(); + pixwidth = pixbuf->get_width(); + + DrawingArea::on_size_allocate(alloc); } bool @@ -134,78 +328,87 @@ FastMeter::vertical_expose (GdkEventExpose* ev) GdkRectangle intersection; GdkRectangle background; - top_of_meter = (gint) floor (v_pixheight * current_level); + top_of_meter = (gint) floor (pixheight * current_level); pixrect.height = top_of_meter; background.x = 0; background.y = 0; background.width = pixrect.width; - background.height = v_pixheight - top_of_meter; + background.height = pixheight - top_of_meter; - if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) { + if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) { get_window()->draw_rectangle (get_style()->get_black_gc(), true, intersection.x, intersection.y, intersection.width, intersection.height); } if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) { - - /* draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) - */ - - get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), v_pixbuf, - intersection.x, v_pixheight - top_of_meter, - intersection.x, v_pixheight - top_of_meter, + // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) + get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf, + intersection.x, pixheight - top_of_meter, + intersection.x, pixheight - top_of_meter, intersection.width, intersection.height, Gdk::RGB_DITHER_NONE, 0, 0); } - /* draw peak bar */ - - if (hold_state) { - get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), v_pixbuf, - intersection.x, v_pixheight - (gint) floor (v_pixheight * current_peak), - intersection.x, v_pixheight - (gint) floor (v_pixheight * current_peak), + // draw peak bar + if (hold_state && intersection.width > 0) { + gint y = pixheight - (gint) floor (pixheight * current_peak); + + get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf, + intersection.x, y, + intersection.x, y, intersection.width, 3, Gdk::RGB_DITHER_NONE, 0, 0); } - return true; + return TRUE; } bool FastMeter::horizontal_expose (GdkEventExpose* ev) { - GdkRectangle intersection; gint right_of_meter; + GdkRectangle intersection; + GdkRectangle background; - right_of_meter = (gint) floor (h_pixwidth * current_level); + right_of_meter = (gint) floor (pixwidth * current_level); pixrect.width = right_of_meter; - if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) { - - /* draw the part of the meter image that we need. - */ - - get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), h_pixbuf, - intersection.x, intersection.y, - intersection.x, intersection.y, - intersection.width, intersection.height, - Gdk::RGB_DITHER_NONE, 0, 0); + background.x = 0; + background.y = 0; + background.width = pixwidth - right_of_meter; + background.height = pixrect.height; + if (gdk_rectangle_intersect (&background, &ev->area, &intersection)) { + get_window()->draw_rectangle (get_style()->get_black_gc(), true, + intersection.x + right_of_meter, intersection.y, + intersection.width, intersection.height); } - /* draw peak bar */ - - if (hold_state) { - get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), h_pixbuf, - right_of_meter, intersection.y, - right_of_meter, intersection.y, + if (gdk_rectangle_intersect (&pixrect, &ev->area, &intersection)) { + // draw the part of the meter image that we need. the area we draw is bounded "in reverse" (top->bottom) + get_window()->draw_pixbuf(get_style()->get_fg_gc(get_state()), pixbuf, + intersection.x, intersection.y, + intersection.x, intersection.y, + intersection.width, intersection.height, + Gdk::RGB_DITHER_NONE, 0, 0); + } + + // draw peak bar + // XXX: peaks don't work properly + /* + if (hold_state && intersection.height > 0) { + gint x = (gint) floor(pixwidth * current_peak); + + get_window()->draw_pixbuf (get_style()->get_fg_gc(get_state()), pixbuf, + x, intersection.y, + x, intersection.y, 3, intersection.height, Gdk::RGB_DITHER_NONE, 0, 0); - } - + */ + return true; } diff --git a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h index c59e85b674..d624f29afb 100644 --- a/libs/gtkmm2ext/gtkmm2ext/fastmeter.h +++ b/libs/gtkmm2ext/gtkmm2ext/fastmeter.h @@ -46,23 +46,16 @@ class FastMeter : public Gtk::DrawingArea { long hold_count() { return hold_cnt; } void set_hold_count (long); - static void set_horizontal_xpm (std::string); - static void set_vertical_xpm (std::string); - protected: bool on_expose_event (GdkEventExpose*); void on_size_request (GtkRequisition*); + void on_size_allocate (Gtk::Allocation&); private: - static std::string h_image_path; - static std::string v_image_path; - static Glib::RefPtr<Gdk::Pixbuf> h_pixbuf; - static gint h_pixheight; - static gint h_pixwidth; - static Glib::RefPtr<Gdk::Pixbuf> v_pixbuf; - static gint v_pixheight; - static gint v_pixwidth; + Glib::RefPtr<Gdk::Pixbuf> pixbuf; + gint pixheight; + gint pixwidth; Orientation orientation; GdkRectangle pixrect; @@ -76,6 +69,18 @@ class FastMeter : public Gtk::DrawingArea { bool vertical_expose (GdkEventExpose*); bool horizontal_expose (GdkEventExpose*); + + static Glib::RefPtr<Gdk::Pixbuf> request_vertical_meter(int); + + static Glib::RefPtr<Gdk::Pixbuf> *v_pixbuf_cache; + static int min_v_pixbuf_size; + static int max_v_pixbuf_size; + + static Glib::RefPtr<Gdk::Pixbuf> request_horizontal_meter(int); + + static Glib::RefPtr<Gdk::Pixbuf> *h_pixbuf_cache; + static int min_h_pixbuf_size; + static int max_h_pixbuf_size; }; |