Standardize drawing of PixFader and BarController; implement flat_buttons and prelight.
authorBen Loftis <ben@harrisonconsoles.com>
Wed, 27 Aug 2014 16:58:09 +0000 (11:58 -0500)
committerBen Loftis <ben@harrisonconsoles.com>
Wed, 27 Aug 2014 16:58:09 +0000 (11:58 -0500)
Prepare for using Controllable interfaces, instead of passing in Adjustments.
ToDo:  reimplement image caching in a standardized way across widgets

gtk2_ardour/level_meter.cc
gtk2_ardour/panner_ui.cc
libs/gtkmm2ext/barcontroller.cc
libs/gtkmm2ext/gtkmm2ext/barcontroller.h
libs/gtkmm2ext/gtkmm2ext/pixfader.h
libs/gtkmm2ext/pixfader.cc

index 1a6f59f1b04f9347dc0362e591a414f4ef8c75c6..41cc29c3707641971721327ee1032a4c64bb2266 100644 (file)
@@ -22,7 +22,6 @@
 #include "ardour/meter.h"
 
 #include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/barcontroller.h>
 #include "pbd/fastlog.h"
 
 #include "ardour_ui.h"
index ec25fad32ca1b5b0ac08f17062d87132785b3c4d..f35c79d4fe7cc2ba77184048cb1032e987480835 100644 (file)
@@ -19,7 +19,6 @@
 #include <limits.h>
 
 #include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/barcontroller.h>
 
 #include "pbd/fastlog.h"
 
index 693151aaed120042eff57b1c1bbd6307b6f30170..7c420a680f0e6159214bb6d73c0f47524b35f8d4 100644 (file)
@@ -31,6 +31,7 @@
 #include "gtkmm2ext/utils.h"
 #include "gtkmm2ext/keyboard.h"
 #include "gtkmm2ext/barcontroller.h"
+#include "gtkmm2ext/cairo_widget.h"
 
 #include "i18n.h"
 
@@ -41,10 +42,10 @@ using namespace Gtkmm2ext;
 BarController::BarController (Gtk::Adjustment& adj,
                              boost::shared_ptr<PBD::Controllable> mc)
 
-       : adjustment (adj),
-         binding_proxy (mc),
-         spinner (adjustment)
-
+       : adjustment (adj)
+         , binding_proxy (mc)
+         , _hovering (false)
+         , spinner (adjustment)
 {                        
        _style = LeftToRight;
        grabbed = false;
@@ -74,6 +75,8 @@ BarController::BarController (Gtk::Adjustment& adj,
        darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press), false);
        darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release), false);
        darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll));
+       darea.signal_enter_notify_event().connect (mem_fun (*this, &BarController::on_enter_notify_event));
+       darea.signal_leave_notify_event().connect (mem_fun (*this, &BarController::on_leave_notify_event));
 
        spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated));
        spinner.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out));
@@ -89,8 +92,24 @@ BarController::BarController (Gtk::Adjustment& adj,
 
 BarController::~BarController ()
 {
-//     delete pattern;
-//     delete shine_pattern;
+}
+
+bool
+BarController::on_enter_notify_event (GdkEventCrossing*)
+{
+       _hovering = true;
+       Keyboard::magic_widget_grab_focus ();
+       queue_draw ();
+       return false;
+}
+
+bool
+BarController::on_leave_notify_event (GdkEventCrossing*)
+{
+       _hovering = false;
+       Keyboard::magic_widget_drop_focus();
+       queue_draw ();
+       return false;
 }
 
 void
@@ -270,36 +289,34 @@ BarController::mouse_control (double x, GdkWindow* window, double scaling)
        return TRUE;
 }
 
-void
-BarController::create_patterns ()
+Gdk::Color
+BarController::get_parent_bg ()
 {
-       Glib::RefPtr<Gdk::Window> win (darea.get_window());
-    Cairo::RefPtr<Cairo::Context> context = win->create_cairo_context();
-
-       Gdk::Color c = get_style()->get_fg (get_state());
-    float r, g, b;
-       r = c.get_red_p ();
-       g = c.get_green_p ();
-       b = c.get_blue_p ();
-
-       float rheight = darea.get_height()-2;
-
-       cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, rheight);
-       cairo_pattern_add_color_stop_rgba (pat, 0, r*0.8,g*0.8,b*0.8, 1.0);
-       cairo_pattern_add_color_stop_rgba (pat, 1, r*0.6,g*0.6,b*0.6, 1.0);
-       Cairo::RefPtr<Cairo::Pattern> p (new Cairo::Pattern (pat, false));
-       pattern = p;
-       cairo_pattern_destroy(pat);
-
-       pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, rheight);
-       cairo_pattern_add_color_stop_rgba (pat, 0, 1,1,1,0.0);
-       cairo_pattern_add_color_stop_rgba (pat, 0.2, 1,1,1,0.3);
-       cairo_pattern_add_color_stop_rgba (pat, 0.5, 1,1,1,0.0);
-       cairo_pattern_add_color_stop_rgba (pat, 1, 1,1,1,0.0);
-       Cairo::RefPtr<Cairo::Pattern> p2 (new Cairo::Pattern (pat, false));
-       shine_pattern = p2;
-       cairo_pattern_destroy(pat);
+        Widget* parent;
+
+       parent = get_parent ();
+
+        while (parent) {
+               static const char* has_cairo_widget_background_info = "has_cairo_widget_background_info";
+               void* p = g_object_get_data (G_OBJECT(parent->gobj()), has_cairo_widget_background_info);
+
+               if (p) {
+                       Glib::RefPtr<Gtk::Style> style = parent->get_style();
+                       return style->get_bg (get_state());
+               }
+               
+               if (!parent->get_has_window()) {
+                       parent = parent->get_parent();
+               } else {
+                       break;
+               }
+        }
+
+        if (parent && parent->get_has_window()) {
+               return parent->get_style ()->get_bg (parent->get_state());
+        } 
 
+       return get_style ()->get_bg (get_state());
 }
 
 bool
@@ -307,157 +324,37 @@ BarController::expose (GdkEventExpose* /*event*/)
 {
        Glib::RefPtr<Gdk::Window> win (darea.get_window());
        Cairo::RefPtr<Cairo::Context> context = win->create_cairo_context();
+       cairo_t* cr = context->cobj();
 
-       if( !pattern )
-               create_patterns();
+       Gdk::Color fg_col = get_style()->get_fg (get_state());
 
-       Gdk::Color c;
-       Widget* parent;
-       gint x1=0, x2=0, y2=0;
-       gint w, h;
-       double fract, radius;
-    float r, g, b;
-
-       fract = ((adjustment.get_value() - adjustment.get_lower()) /
+       double fract = ((adjustment.get_value() - adjustment.get_lower()) /
                 (adjustment.get_upper() - adjustment.get_lower()));
        
+       gint w = darea.get_width() ;
+       gint h = darea.get_height();
+       gint bar_start, bar_width;
+       double radius = 4;
+
        switch (_style) {
        case Line:
-               w = darea.get_width() - 1;
-               h = darea.get_height();
-               x1 = (gint) floor (w * fract);
-               x2 = x1;
-               y2 = h - 1;
-
-               if (use_parent) {
-                       parent = get_parent();
-                        
-                       if (parent) {
-                                c = parent->get_style()->get_fg (parent->get_state());
-                                r = c.get_red_p ();
-                                g = c.get_green_p ();
-                                b = c.get_blue_p ();
-                                context->set_source_rgb (r, g, b);
-                                context->rectangle (0, 0, darea.get_width(), darea.get_height());
-                                context->fill ();
-                       }
-
-               } else {
-
-                        c = get_style()->get_bg (get_state());
-                        r = c.get_red_p ();
-                        g = c.get_green_p ();
-                        b = c.get_blue_p ();
-                        context->set_source_rgb (r, g, b);
-                        context->rectangle (0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height());
-                        context->fill ();
-               }
-                
-                c = get_style()->get_fg (get_state());
-                r = c.get_red_p ();
-                g = c.get_green_p ();
-                b = c.get_blue_p ();
-                context->set_source_rgb (r, g, b);
-                context->move_to (x1, 0);
-                context->line_to (x1, h);
-                context->stroke ();
+               bar_start = (gint) floor ((w-1) * fract);
+               bar_width = 1;
                break;
 
-        case Blob:
-               w = darea.get_width() - 1;
-               h = darea.get_height();
-               x1 = (gint) floor (w * fract);
-               x2 = min (w-2,h-2);
-
-               if (use_parent) {
-                       parent = get_parent();
-                       
-                       if (parent) {
-                                c = parent->get_style()->get_fg (parent->get_state());
-                                r = c.get_red_p ();
-                                g = c.get_green_p ();
-                                b = c.get_blue_p ();
-                                context->set_source_rgb (r, g, b);
-                                context->rectangle (0, 0, darea.get_width(), darea.get_height());
-                                context->fill ();
-                       }
-
-               } else {
-
-                        c = get_style()->get_bg (get_state());
-                        r = c.get_red_p ();
-                        g = c.get_green_p ();
-                        b = c.get_blue_p ();
-                        context->set_source_rgb (r, g, b);
-                        context->rectangle (0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height());
-                        context->fill ();
-               }
-               
-                c = get_style()->get_fg (get_state());
-                r = c.get_red_p ();
-                g = c.get_green_p ();
-                b = c.get_blue_p ();
-                context->arc (x1, ((h-2)/2)-1, x2, 0, 2*M_PI);
+       case Blob:
+               // ????
                break;
 
        case CenterOut:
-               w = darea.get_width();
-               h = darea.get_height()-2;
-                if (use_parent) {
-                        parent = get_parent();
-                        if (parent) {
-                                c = parent->get_style()->get_fg (parent->get_state());
-                                r = c.get_red_p ();
-                                g = c.get_green_p ();
-                                b = c.get_blue_p ();
-                                context->set_source_rgb (r, g, b);
-                                context->rectangle (0, 0, darea.get_width(), darea.get_height());
-                                context->fill ();
-                        }
-                } else {
-                        c = get_style()->get_bg (get_state());
-                        r = c.get_red_p ();
-                        g = c.get_green_p ();
-                        b = c.get_blue_p ();
-                        context->set_source_rgb (r, g, b);
-                        context->rectangle (0, 0, darea.get_width(), darea.get_height());
-                        context->fill ();
-                }
-                c = get_style()->get_fg (get_state());
-                r = c.get_red_p ();
-                g = c.get_green_p ();
-                b = c.get_blue_p ();
-                x1 = (w/2) - ((w*fract)/2); // center, back up half the bar width
-                context->set_source_rgb (r, g, b);
-                context->rectangle (x1, 1, w*fract, h);
-                context->fill ();
-               break;
+        bar_width = (w*fract);
+        bar_start = (w/2) - bar_width/2; // center, back up half the bar width
+               break;
 
        case LeftToRight:
+               bar_start = 1;
+               bar_width = floor((w-2)*fract);
 
-               w = darea.get_width() - 2;
-               h = darea.get_height() - 2;
-
-               x2 = (gint) floor (w * fract);
-               y2 = h;
-               radius = 4;
-               if (x2 < 8) x2 = 8;
-
-               /* border */
-
-               context->set_source_rgb (0,0,0);
-               cairo_rectangle (context->cobj(), 0, 0, darea.get_width(), darea.get_height());
-               context->fill ();
-
-               /* draw active box */
-
-               context->set_source (pattern);
-               rounded_rectangle (context, 1, 1, x2, y2, radius-1.5);
-               context->fill ();
-
-//             context->set_source (shine_pattern);
-//             rounded_rectangle (context, 2, 3, x2-2, y2-8, radius-2);
-//             context->fill ();
                break;
 
        case RightToLeft:
@@ -468,10 +365,85 @@ BarController::expose (GdkEventExpose* /*event*/)
                break;
        }
 
+       //fill in the bg rect ... 
+       Gdk::Color c = get_parent_bg(); //get_style()->get_bg (Gtk::STATE_PRELIGHT);  //why prelight?  Shouldn't we be using the parent's color?  maybe   get_parent_bg  ?
+       CairoWidget::set_source_rgb_a (cr, c);
+       cairo_rectangle (cr, 0, 0, w, h);
+       cairo_fill(cr);
+
+       //"slot"
+       cairo_set_source_rgba (cr, 0.17, 0.17, 0.17, 1.0);
+       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, radius-0.5);
+       cairo_fill(cr);
+
+       //mask off the corners
+       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, radius-0.5);
+       cairo_clip(cr);
+       
+               //background gradient
+               if ( !CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t *bg_gradient = cairo_pattern_create_linear (0.0, 0.0, 0, h);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0, 0, 0, 0, 0.4);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0.2, 0, 0, 0, 0.2);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 1, 0, 0, 0, 0.0);
+                       cairo_set_source (cr, bg_gradient);
+                       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, radius-1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(bg_gradient);
+               }
+               
+               //fg color
+               CairoWidget::set_source_rgb_a (cr, fg_col, 1.0);
+               Gtkmm2ext::rounded_rectangle (cr, bar_start, 1, bar_width, h-2, radius - 1.5);
+               cairo_fill(cr);
+
+               //fg gradient
+               if (!CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t * fg_gradient = cairo_pattern_create_linear (0.0, 0.0, 0, h);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0.1, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 1, 0, 0, 0, 0.3);
+                       cairo_set_source (cr, fg_gradient);
+                       Gtkmm2ext::rounded_rectangle (cr, bar_start, 1, bar_width, h-2, radius - 1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(fg_gradient);
+               }
+               
+       cairo_reset_clip(cr);
+
+       //black border
+       cairo_set_line_width (cr, 1.0);
+       cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+       Gtkmm2ext::rounded_rectangle (cr, 0.5, 0.5, w-1, h-1, radius);
+       cairo_stroke(cr);
+
+       /* draw the unity-position line if it's not at either end*/
+/*     if (unity_loc > 0) {
+               context->set_line_width (1);
+               cairo_set_source_rgba (cr, 1,1,1, 1.0);
+               if ( _orien == VERT) {
+                       if (unity_loc < h ) {
+                               context->move_to (2.5, unity_loc + radius + .5);
+                               context->line_to (girth-2.5, unity_loc + radius + .5);
+                               context->stroke ();
+                       }
+               } else {
+                       if ( unity_loc < w ){
+                               context->move_to (unity_loc - radius + .5, 3.5);
+                               context->line_to (unity_loc - radius + .5, girth-3.5);
+                               context->stroke ();
+                       }
+               }
+       }*/
+       
        if (!darea.get_sensitive()) {
                rounded_rectangle (context, 0, 0, darea.get_width(), darea.get_height(), 3);
                context->set_source_rgba (0.505, 0.517, 0.525, 0.6);
                context->fill ();
+       } else if (_hovering) {
+               Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, radius);
+               cairo_set_source_rgba (cr, 0.905, 0.917, 0.925, 0.1);
+               cairo_fill (cr);
        }
 
        /* draw label */
@@ -479,7 +451,7 @@ BarController::expose (GdkEventExpose* /*event*/)
        double xpos = -1;
        std::string const label = get_label (xpos);
 
-       if (!label.empty()) {
+/*     if (!label.empty()) {
                
                layout->set_text (label);
                
@@ -490,8 +462,8 @@ BarController::expose (GdkEventExpose* /*event*/)
                        x = max (3, 1 + (x2 - (width/2)));
                        x = min (darea.get_width() - width - 3, (int) lrint (xpos));
                } else {
-                        x = lrint (darea.get_width() * xpos);
-                }
+                       x = lrint (darea.get_width() * xpos);
+               }
 
                 c = get_style()->get_text (get_state());
                 r = c.get_red_p ();
@@ -500,7 +472,7 @@ BarController::expose (GdkEventExpose* /*event*/)
                 context->set_source_rgb (r, g, b);
                 context->move_to (x, (darea.get_height()/2) - (height/2));
                 layout->show_in_cairo_context (context);
-       }
+       }*/
        
        return true;
 }
index 094d4c67f45426432ce67a399a3d1ecddbd51f7e..5fc3c17aeaa2ef292306ff604b76f49edf72107e 100644 (file)
@@ -91,19 +91,19 @@ class LIBGTKMM2EXT_API BarController : public Gtk::Frame
                return "";
        }
        
-       void create_patterns();
-       Cairo::RefPtr<Cairo::Pattern> pattern;
-       Cairo::RefPtr<Cairo::Pattern> shine_pattern;
-
        virtual bool button_press (GdkEventButton *);
        virtual bool button_release (GdkEventButton *);
        virtual bool motion (GdkEventMotion *);
        virtual bool expose (GdkEventExpose *);
        virtual bool scroll (GdkEventScroll *);
        virtual bool entry_focus_out (GdkEventFocus*);
+       bool on_enter_notify_event (GdkEventCrossing* ev);
+       bool on_leave_notify_event (GdkEventCrossing* ev);
 
        gint mouse_control (double x, GdkWindow* w, double scaling);
 
+       Gdk::Color get_parent_bg ();
+
        gint switch_to_bar ();
        gint switch_to_spinner ();
 
@@ -112,6 +112,9 @@ class LIBGTKMM2EXT_API BarController : public Gtk::Frame
        
        int entry_input (double* new_value);
        bool entry_output ();
+
+       bool _hovering;
+
 };
 
 
index 26942371d36612a0c04644775ffd94da3e0afc54..abbcbb0f70cccb3d90ad4731e19c4efd9829ed95 100644 (file)
@@ -45,9 +45,6 @@ class LIBGTKMM2EXT_API PixFader : public Gtk::DrawingArea
        std::string                 _text;
        int   _text_width;
        int   _text_height;
-       double text_r;
-       double text_g;
-       double text_b;
 
        Gtk::Adjustment& adjustment;
 
@@ -61,8 +58,9 @@ class LIBGTKMM2EXT_API PixFader : public Gtk::DrawingArea
        bool on_scroll_event (GdkEventScroll* ev);
        bool on_enter_notify_event (GdkEventCrossing* ev);
        bool on_leave_notify_event (GdkEventCrossing* ev);
-        void on_state_changed (Gtk::StateType);
-        void on_style_changed (const Glib::RefPtr<Gtk::Style>&);
+
+       void on_state_changed (Gtk::StateType);
+       void on_style_changed (const Glib::RefPtr<Gtk::Style>&);
 
        enum Orientation {
                VERT,
@@ -72,52 +70,9 @@ class LIBGTKMM2EXT_API PixFader : public Gtk::DrawingArea
   private:
        int span, girth;
        int _orien;
-        cairo_pattern_t* pattern;
-
-        struct FaderImage {
-           cairo_pattern_t* pattern;
-           double fr;
-           double fg;
-           double fb;
-           double br;
-           double bg;
-           double bb;
-           int width;
-           int height;
-
-           FaderImage (cairo_pattern_t* p, 
-                       double afr, double afg, double afb, 
-                       double abr, double abg, double abb,
-                       int w, int h) 
-                   : pattern (p)
-                   , fr (afr)
-                   , fg (afg)
-                   , fb (afb)
-                   , br (abr)
-                   , bg (abg)
-                   , bb (abb)
-                   , width (w)
-                   , height (h)
-           {}
-
-           bool matches (double afr, double afg, double afb, 
-                         double abr, double abg, double abb,
-                         int w, int h) {
-                   return width == w && 
-                           height == h &&
-                           afr == fr &&
-                           afg == fg && 
-                           afb == fb &&
-                           abr == br &&
-                           abg == bg && 
-                           abb == bb;
-           }
-       };
-
-        static std::list<FaderImage*> _patterns;
-        static cairo_pattern_t* find_pattern (double afr, double afg, double afb, 
-                                             double abr, double abg, double abb, 
-                                             int w, int h);
+       
+       cairo_pattern_t* fg_gradient;
+       cairo_pattern_t* bg_gradient;
 
        bool _hovering;
 
@@ -130,10 +85,9 @@ class LIBGTKMM2EXT_API PixFader : public Gtk::DrawingArea
        int unity_loc;
 
        void adjustment_changed ();
-       int display_span ();
+       float display_span ();
        void set_adjustment_from_event (GdkEventButton *);
        void update_unity_position ();
-       void create_patterns();
 };
 
 
index ef1dffc1dd70e04775606f909595d29fb17a00ee..d6b051373b8708b82ae9e2e76fccb11ef2ce4283 100644 (file)
@@ -27,6 +27,7 @@
 #include "gtkmm2ext/keyboard.h"
 #include "gtkmm2ext/rgb_macros.h"
 #include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/cairo_widget.h"
 
 using namespace Gtkmm2ext;
 using namespace Gtk;
@@ -37,18 +38,18 @@ using namespace std;
 #define CORNER_OFFSET 1
 #define FADER_RESERVE 5
 
-std::list<PixFader::FaderImage*> PixFader::_patterns;
-
 PixFader::PixFader (Gtk::Adjustment& adj, int orientation, int fader_length, int fader_girth)
        : adjustment (adj)
        , span (fader_length)
        , girth (fader_girth)
        , _orien (orientation)
-       , pattern (0)
        , _hovering (false)
        , last_drawn (-1)
        , dragging (false)
 {
+       bg_gradient = 0;
+       fg_gradient = 0;
+
        default_value = adjustment.get_value();
        update_unity_position ();
 
@@ -68,239 +69,149 @@ PixFader::~PixFader ()
 {
 }
 
-cairo_pattern_t*
-PixFader::find_pattern (double afr, double afg, double afb, 
-                       double abr, double abg, double abb, 
-                       int w, int h)
-{
-       for (list<FaderImage*>::iterator f = _patterns.begin(); f != _patterns.end(); ++f) {
-               if ((*f)->matches (afr, afg, afb, abr, abg, abb, w, h)) {
-                       return (*f)->pattern;
-               }
-       }
-       return 0;
-}
-
-void
-PixFader::create_patterns ()
-{
-       Gdk::Color c = get_style()->get_fg (get_state());
-       float fr, fg, fb;
-       float br, bg, bb;
-
-       fr = c.get_red_p ();
-       fg = c.get_green_p ();
-       fb = c.get_blue_p ();
-
-       c = get_style()->get_bg (get_state());
-
-       br = c.get_red_p ();
-       bg = c.get_green_p ();
-       bb = c.get_blue_p ();
-
-       if ( !_text.empty()) {
-               _layout->get_pixel_size (_text_width, _text_height);
-       } else {
-               _text_width = 0;
-               _text_height = 0;
-       }
-
-       c = get_style()->get_text (get_state());
-
-       text_r = c.get_red_p ();
-       text_g = c.get_green_p ();
-       text_b = c.get_blue_p ();
-
-       cairo_surface_t* surface;
-       cairo_t* tc = 0;
-
-       if (get_width() <= 1 || get_height() <= 1) {
-               return;
-       }
-
-       if ((pattern = find_pattern (fr, fg, fb, br, bg, bb, get_width(), get_height())) != 0) {
-               /* found it - use it */
-               return;
-       }
-
-       if (_orien == VERT) {
-               
-               surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, get_width(), get_height() * 2.0);
-               tc = cairo_create (surface);
-
-               /* paint background + border */
-
-               cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, get_width(), 0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 0, br*0.8,bg*0.8,bb*0.8, 1.0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 1, br*0.6,bg*0.6,bb*0.6, 1.0);
-               cairo_set_source (tc, shade_pattern);
-               cairo_rectangle (tc, 0, 0, get_width(), get_height() * 2.0);
-               cairo_fill (tc);
-
-               cairo_pattern_destroy (shade_pattern);
-               
-               /* paint lower shade */
-               
-               shade_pattern = cairo_pattern_create_linear (0.0, 0.0, get_width() - 2 - CORNER_OFFSET , 0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 0, fr*0.8,fg*0.8,fb*0.8, 1.0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 1, fr*0.6,fg*0.6,fb*0.6, 1.0);
-               cairo_set_source (tc, shade_pattern);
-               Gtkmm2ext::rounded_top_half_rectangle (tc, CORNER_OFFSET, get_height() + CORNER_OFFSET,
-                               get_width() - CORNER_SIZE, get_height(), CORNER_RADIUS);
-               cairo_fill (tc);
-
-               cairo_pattern_destroy (shade_pattern);
-
-               pattern = cairo_pattern_create_for_surface (surface);
-
-       } else {
-
-               surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, get_width() * 2.0, get_height());
-               tc = cairo_create (surface);
-
-               /* paint right shade (background section)*/
-
-               cairo_pattern_t* shade_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height());
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 0, br*0.8,bg*0.8,bb*0.8, 1.0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 1, br*0.6,bg*0.6,bb*0.6, 1.0);
-               cairo_set_source (tc, shade_pattern);
-               cairo_rectangle (tc, 0, 0, get_width() * 2.0, get_height());
-               cairo_fill (tc);
-
-               /* paint left shade (active section/foreground) */
-               
-               shade_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, get_height());
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 0, fr*0.8,fg*0.8,fb*0.8, 1.0);
-               cairo_pattern_add_color_stop_rgba (shade_pattern, 1, fr*0.6,fg*0.6,fb*0.6, 1.0);
-               cairo_set_source (tc, shade_pattern);
-               Gtkmm2ext::rounded_right_half_rectangle (tc, CORNER_OFFSET, CORNER_OFFSET,
-                               get_width() - CORNER_OFFSET, get_height() - CORNER_SIZE, CORNER_RADIUS);
-               cairo_fill (tc);
-               cairo_pattern_destroy (shade_pattern);
-               
-               pattern = cairo_pattern_create_for_surface (surface);
-       }
-
-       /* cache it for others to use */
-
-       _patterns.push_back (new FaderImage (pattern, fr, fg, fb, br, bg, bb, get_width(), get_height()));
-
-       cairo_destroy (tc);
-       cairo_surface_destroy (surface);
-}
-
 bool
 PixFader::on_expose_event (GdkEventExpose* ev)
 {
        Cairo::RefPtr<Cairo::Context> context = get_window()->create_cairo_context();
        cairo_t* cr = context->cobj();
 
-       if (!pattern) {
-               create_patterns();
-       }
-
-       if (!pattern) {
+       Gdk::Color fg_col = get_style()->get_fg (get_state());
 
-               /* this isn't supposed to be happen, but some wackiness whereby
-                  the pixfader ends up with a 1xN or Nx1 size allocation
-                  leads to it. the basic wackiness needs fixing but we
-                  shouldn't crash. just fill in the expose area with 
-                  our bg color.
-               */
-
-               Gdk::Color c = get_style()->get_bg (get_state());
-               float br, bg, bb;
-
-               br = c.get_red_p ();
-               bg = c.get_green_p ();
-               bb = c.get_blue_p ();
-               cairo_set_source_rgb (cr, br, bg, bb);
-               cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
-               cairo_fill (cr);
-               return true;
-       }
-                  
-       cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
-       cairo_clip (cr);
-
-       int ds = display_span ();
+       float ds = display_span ();
        float w = get_width();
        float h = get_height();
 
-       Gdk::Color c = get_style()->get_bg (Gtk::STATE_PRELIGHT);
-       cairo_set_source_rgb (cr, c.get_red_p(), c.get_green_p(), c.get_blue_p());
+       //fill in the bg rect ... 
+       Gdk::Color c = get_style()->get_bg (Gtk::STATE_PRELIGHT);  //why prelight?  Shouldn't we be using the parent's color?
+       CairoWidget::set_source_rgb_a (cr, c);
        cairo_rectangle (cr, 0, 0, w, h);
        cairo_fill(cr);
 
-       cairo_set_line_width (cr, 1);
-       cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
-
-       cairo_matrix_t matrix;
-       Gtkmm2ext::rounded_rectangle (cr, CORNER_OFFSET, CORNER_OFFSET, w-CORNER_SIZE, h-CORNER_SIZE, CORNER_RADIUS);
-       cairo_stroke_preserve(cr);
+       //"slot"
+       cairo_set_source_rgba (cr, 0.17, 0.17, 0.17, 1.0);
+       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, CORNER_RADIUS-0.5);
+       cairo_fill(cr);
 
+       //mask off the corners
+       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, CORNER_RADIUS-0.5);
+       cairo_clip(cr);
+       
        if (_orien == VERT) {
 
-               if (ds > h - FADER_RESERVE - CORNER_OFFSET) {
-                       ds = h - FADER_RESERVE - CORNER_OFFSET;
+               int travel = h - 1;
+               int progress = travel * (1.0-ds);
+               int top = 1 + progress;
+               int bottom = h;
+               
+               //background gradient
+               if ( !CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t *bg_gradient = cairo_pattern_create_linear (0.0, 0.0, w, 0);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0, 0, 0, 0, 0.4);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0.2, 0, 0, 0, 0.2);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 1, 0, 0, 0, 0.0);
+                       cairo_set_source (cr, bg_gradient);
+                       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, CORNER_RADIUS-1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(bg_gradient);
+               }
+               
+               //fg color
+               CairoWidget::set_source_rgb_a (cr, fg_col, 1.0);
+               Gtkmm2ext::rounded_top_rectangle (cr, 1, top, w-2, bottom, CORNER_RADIUS - 1.5);
+               cairo_fill(cr);
+
+               //fg gradient
+               if (!CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t *fg_gradient = cairo_pattern_create_linear (0.0, 0.0, w, 0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0.1, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 1, 0, 0, 0, 0.3);
+                       cairo_set_source (cr, fg_gradient);
+                       Gtkmm2ext::rounded_rectangle (cr, 1, top, w-2, bottom, CORNER_RADIUS - 1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(fg_gradient);
                }
-
-               cairo_set_source (cr, pattern);
-               cairo_matrix_init_translate (&matrix, 0, (h - ds));
-               cairo_pattern_set_matrix (pattern, &matrix);
-               cairo_fill (cr);
-
        } else {
 
-               if (ds < FADER_RESERVE) {
-                       ds = FADER_RESERVE;
+               int travel = w - 1;
+               int progress = travel * ds;
+               int left = 1;
+               int length = progress;
+               
+               //background gradient
+               if ( !CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t *bg_gradient = cairo_pattern_create_linear (0.0, 0.0, 0, h);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0, 0, 0, 0, 0.4);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 0.2, 0, 0, 0, 0.2);
+                       cairo_pattern_add_color_stop_rgba (bg_gradient, 1, 0, 0, 0, 0.0);
+                       cairo_set_source (cr, bg_gradient);
+                       Gtkmm2ext::rounded_rectangle (cr, 1, 1, w-2, h-2, CORNER_RADIUS-1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(bg_gradient);
+               }
+               
+               //fg color
+               CairoWidget::set_source_rgb_a (cr, fg_col, 1.0);
+               Gtkmm2ext::rounded_rectangle (cr, left, 1, length, h-2, CORNER_RADIUS - 1.5);
+               cairo_fill(cr);
+
+               //fg gradient
+               if (!CairoWidget::flat_buttons() ) {
+                       cairo_pattern_t * fg_gradient = cairo_pattern_create_linear (0.0, 0.0, 0, h);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 0.1, 0, 0, 0, 0.0);
+                       cairo_pattern_add_color_stop_rgba (fg_gradient, 1, 0, 0, 0, 0.3);
+                       cairo_set_source (cr, fg_gradient);
+               Gtkmm2ext::rounded_rectangle (cr, left, 1, length, h-2, CORNER_RADIUS - 1.5);
+                       cairo_fill (cr);
+                       cairo_pattern_destroy(fg_gradient);
                }
-
-               /*
-                 if ds == w, the pattern does not need to be translated
-                 if ds == 0 (or FADER_RESERVE), the pattern needs to be moved
-                     w to the left, which is -w in pattern space, and w in
-                     user space
-                 if ds == 10, then the pattern needs to be moved w - 10
-                     to the left, which is -(w-10) in pattern space, which 
-                     is (w - 10) in user space
-
-                 thus: translation = (w - ds)
-                */
-
-               cairo_set_source (cr, pattern);
-               cairo_matrix_init_translate (&matrix, w - ds, 0);
-               cairo_pattern_set_matrix (pattern, &matrix);
-               cairo_fill (cr);
        }
                
+       cairo_reset_clip(cr);
+
+       //black border
+       cairo_set_line_width (cr, 1.0);
+       cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+       Gtkmm2ext::rounded_rectangle (cr, 0.5, 0.5, w-1, h-1, CORNER_RADIUS);
+       cairo_stroke(cr);
+
        /* draw the unity-position line if it's not at either end*/
        if (unity_loc > 0) {
                context->set_line_width (1);
-               context->set_line_cap (Cairo::LINE_CAP_ROUND);
                Gdk::Color c = get_style()->get_fg (Gtk::STATE_ACTIVE);
-               context->set_source_rgba (c.get_red_p()*1.5, c.get_green_p()*1.5, c.get_blue_p()*1.5, 0.85);
+               CairoWidget::set_source_rgb_a (cr, c, 1.0);
                if ( _orien == VERT) {
                        if (unity_loc < h ) {
-                               context->move_to (1.5, unity_loc + CORNER_OFFSET + .5);
-                               context->line_to (girth - 1.5, unity_loc + CORNER_OFFSET + .5);
+                               context->move_to (2.5, unity_loc + CORNER_OFFSET + .5);
+                               context->line_to (girth-2.5, unity_loc + CORNER_OFFSET + .5);
                                context->stroke ();
                        }
                } else {
                        if ( unity_loc < w ){
-                               context->move_to (unity_loc - CORNER_OFFSET + .5, 1.5);
-                               context->line_to (unity_loc - CORNER_OFFSET + .5, girth - 1.5);
+                               context->move_to (unity_loc - CORNER_OFFSET + .5, 3.5);
+                               context->line_to (unity_loc - CORNER_OFFSET + .5, girth-3.5);
                                context->stroke ();
                        }
                }
        }
-
+       
+       //draw text
        if ( !_text.empty() ) {
 
+               //calc text size
+               if ( !_text.empty()) {
+                       _layout->get_pixel_size (_text_width, _text_height);
+               } else {
+                       _text_width = 0;
+                       _text_height = 0;
+               }
+
                /* center text */
                cairo_new_path (cr);
                cairo_move_to (cr, (get_width() - _text_width)/2.0, get_height()/2.0 - _text_height/2.0);
-               cairo_set_source_rgba (cr, text_r, text_g, text_b, 0.9);
+               Gdk::Color c = get_style()->get_text (get_state());
+               CairoWidget::set_source_rgb_a (cr, c, 0.9);
                pango_cairo_show_layout (cr, _layout->gobj());
        } 
        
@@ -344,11 +255,6 @@ PixFader::on_size_allocate (Gtk::Allocation& alloc)
                span = alloc.get_width ();
        }
 
-       if (is_realized()) {
-               /* recreate patterns in case we've changed size */
-               create_patterns ();
-       }
-
        update_unity_position ();
 }
 
@@ -540,18 +446,12 @@ PixFader::adjustment_changed ()
 }
 
 /** @return pixel offset of the current value from the right or bottom of the fader */
-int
+float
 PixFader::display_span ()
 {
        float fract = (adjustment.get_value () - adjustment.get_lower()) / ((adjustment.get_upper() - adjustment.get_lower()));
-       int ds;
-       if (_orien == VERT) {
-               ds = (int)floor ( span * (1.0 - fract));
-       } else {
-               ds = (int)floor (span * fract);
-       }
        
-       return ds;
+       return fract;
 }
 
 void
@@ -625,7 +525,6 @@ void
 PixFader::on_state_changed (Gtk::StateType old_state)
 {
        Widget::on_state_changed (old_state);
-       create_patterns ();
        queue_draw ();
 }
 
@@ -638,10 +537,5 @@ PixFader::on_style_changed (const Glib::RefPtr<Gtk::Style>&)
                set_text (txt);
        }
 
-       /* remember that all patterns are cached and not owned by an individual
-          pixfader. we will lazily create a new pattern when needed.
-       */
-
-       pattern = 0;
        queue_draw ();
 }