summaryrefslogtreecommitdiff
path: root/libs/surfaces
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2016-09-16 08:39:28 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2016-09-27 14:59:31 -0500
commit7c9f3acc60fb29a562d28d1f43a9e22298545bf1 (patch)
tree7418a4922ff7670d6ffc08dce39432afd1e5669c /libs/surfaces
parent2810e5619a1926a286c6192143ada4973066efd8 (diff)
first compiling and theoretically correct version of Push2 canvas display.
Not tested with device at this point
Diffstat (limited to 'libs/surfaces')
-rw-r--r--libs/surfaces/push2/canvas.cc190
-rw-r--r--libs/surfaces/push2/canvas.h95
-rw-r--r--libs/surfaces/push2/knob.cc354
-rw-r--r--libs/surfaces/push2/knob.h90
-rw-r--r--libs/surfaces/push2/layout.cc27
-rw-r--r--libs/surfaces/push2/layout.h15
-rw-r--r--libs/surfaces/push2/menu.cc110
-rw-r--r--libs/surfaces/push2/menu.h29
-rw-r--r--libs/surfaces/push2/mix.cc218
-rw-r--r--libs/surfaces/push2/mix.h21
-rw-r--r--libs/surfaces/push2/push2.cc204
-rw-r--r--libs/surfaces/push2/push2.h39
-rw-r--r--libs/surfaces/push2/scale.cc28
-rw-r--r--libs/surfaces/push2/scale.h6
-rw-r--r--libs/surfaces/push2/splash.cc98
-rw-r--r--libs/surfaces/push2/splash.h47
-rw-r--r--libs/surfaces/push2/track_mix.cc111
-rw-r--r--libs/surfaces/push2/track_mix.h15
-rw-r--r--libs/surfaces/push2/wscript2
19 files changed, 1198 insertions, 501 deletions
diff --git a/libs/surfaces/push2/canvas.cc b/libs/surfaces/push2/canvas.cc
new file mode 100644
index 0000000000..e178e0d8b5
--- /dev/null
+++ b/libs/surfaces/push2/canvas.cc
@@ -0,0 +1,190 @@
+/*
+ Copyright (C) 2016 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.
+
+*/
+
+#include <cairomm/region.h>
+#include <cairomm/surface.h>
+#include <cairomm/context.h>
+
+#include "canvas.h"
+#include "layout.h"
+#include "push2.h"
+
+using namespace ArdourCanvas;
+using namespace ArdourSurface;
+
+const int Push2Canvas::pixels_per_row = 1024;
+
+Push2Canvas::Push2Canvas (Push2& pr, int c, int r)
+ : p2 (pr)
+ , _cols (c)
+ , _rows (r)
+ , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _cols, _rows))
+{
+ context = Cairo::Context::create (frame_buffer);
+ expose_region = Cairo::Region::create ();
+
+ device_frame_buffer = new uint16_t[pixel_area()];
+ memset (device_frame_buffer, 0, sizeof (uint16_t) * pixel_area());
+
+ frame_header[0] = 0xef;
+ frame_header[1] = 0xcd;
+ frame_header[2] = 0xab;
+ frame_header[3] = 0x89;
+
+ memset (&frame_header[4], 0, 12);
+}
+
+Push2Canvas::~Push2Canvas ()
+{
+ delete [] device_frame_buffer;
+ device_frame_buffer = 0;
+}
+
+bool
+Push2Canvas::vblank ()
+{
+ /* re-render dirty areas, if any */
+
+ if (expose ()) {
+ /* something rendered, update device_frame_buffer */
+ blit_to_device_frame_buffer ();
+ }
+
+ int transferred = 0;
+ const int timeout_msecs = 1000;
+ int err;
+
+ /* transfer to device */
+
+ if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
+ return false;
+ }
+
+ if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, (uint8_t*) device_frame_buffer, 2 * pixel_area (), &transferred, timeout_msecs))) {
+ return false;
+ }
+
+ return true;
+}
+
+void
+Push2Canvas::request_redraw ()
+{
+ request_redraw (Rect (0, 0, _cols, _rows));
+}
+
+void
+Push2Canvas::request_redraw (Rect const & r)
+{
+ Cairo::RectangleInt cr;
+
+ cr.x = r.x1;
+ cr.y = r.y1;
+ cr.width = r.width();
+ cr.width = r.height();
+
+ expose_region->do_union (cr);
+
+ /* next vblank will redraw */
+}
+
+bool
+Push2Canvas::expose ()
+{
+ if (expose_region->empty()) {
+ return false; /* nothing drawn */
+ }
+
+ /* set up clipping */
+
+ const int nrects = expose_region->get_num_rectangles ();
+
+ for (int n = 0; n < nrects; ++n) {
+ Cairo::RectangleInt r = expose_region->get_rectangle (n);
+ context->rectangle (r.x, r.y, r.width, r.height);
+ }
+
+ context->clip ();
+
+ Push2Layout* layout = p2.current_layout();
+
+ if (layout) {
+ Cairo::RectangleInt r = expose_region->get_extents();
+ layout->render (Rect (r.x, r.y, r.x + r.width, r.y + r.height), context);
+ }
+
+ context->reset_clip ();
+
+ return true;
+}
+
+/** render host-side frame buffer (a Cairo ImageSurface) to the current
+ * device-side frame buffer. The device frame buffer will be pushed to the
+ * device on the next call to vblank()
+ */
+
+int
+Push2Canvas::blit_to_device_frame_buffer ()
+{
+ /* ensure that all drawing has been done before we fetch pixel data */
+
+ frame_buffer->flush ();
+
+ const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
+ const uint8_t* data = frame_buffer->get_data ();
+
+ /* fill frame buffer (320kB) */
+
+ uint16_t* fb = (uint16_t*) device_frame_buffer;
+
+ for (int row = 0; row < _rows; ++row) {
+
+ const uint8_t* dp = data + row * stride;
+
+ for (int col = 0; col < _cols; ++col) {
+
+ /* fetch r, g, b (range 0..255). Ignore alpha */
+
+ const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
+ const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
+ const int b = *((const uint32_t*)dp) & 0xff;
+
+ /* convert to 5 bits, 6 bits, 5 bits, respectively */
+ /* generate 16 bit BGB565 value */
+
+ *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
+
+ /* the push2 docs state that we should xor the pixel
+ * data. Doing so doesn't work correctly, and not doing
+ * so seems to work fine (colors roughly match intended
+ * values).
+ */
+
+ dp += 4;
+ }
+
+ /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
+ byte USB buffers
+ */
+
+ fb += 64; /* 128 bytes = 64 int16_t */
+ }
+
+ return 0;
+}
diff --git a/libs/surfaces/push2/canvas.h b/libs/surfaces/push2/canvas.h
new file mode 100644
index 0000000000..853b93f778
--- /dev/null
+++ b/libs/surfaces/push2/canvas.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2016 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.
+
+*/
+
+#ifndef __ardour_push2_canvas_h__
+#define __ardour_push2_canvas_h__
+
+#include <cairomm/refptr.h>
+#include <glibmm/threads.h>
+
+#include "canvas/canvas.h"
+
+namespace Cairo {
+ class ImageSurface;
+ class Context;
+ class Region;
+}
+
+namespace ArdourSurface {
+
+class Push2;
+
+/* A canvas which renders to the Push2 display */
+
+class Push2Canvas : public ArdourCanvas::Canvas
+{
+ public:
+ Push2Canvas (Push2& p2, int cols, int rows);
+ ~Push2Canvas();
+
+ void request_redraw ();
+ void request_redraw (ArdourCanvas::Rect const &);
+ bool vblank ();
+
+ void splash ();
+
+ Cairo::RefPtr<Cairo::Context> image_context() { return context; }
+
+ int rows() const { return _rows; }
+ int cols() const { return _cols; }
+
+ static double inter_button_spacing() { return 120.0; }
+
+ ArdourCanvas::Coord width() const { return cols(); }
+ ArdourCanvas::Coord height() const { return rows(); }
+ void request_size (ArdourCanvas::Duple);
+ ArdourCanvas::Rect visible_area () const;
+
+ /* API that does nothing since we have no input events */
+ void ungrab () {}
+ void grab (ArdourCanvas::Item*) {}
+ void focus (ArdourCanvas::Item*) {}
+ void unfocus (ArdourCanvas::Item*) {}
+ void re_enter() {}
+ void pick_current_item (int) {}
+ void pick_current_item (ArdourCanvas::Duple const &, int) {}
+ bool get_mouse_position (ArdourCanvas::Duple&) const { return false; }
+
+ private:
+ Push2& p2;
+ int _cols;
+ int _rows;
+
+ static const int pixels_per_row;
+ int pixel_area () const { return _rows * pixels_per_row; }
+
+ uint8_t frame_header[16];
+ uint16_t* device_frame_buffer;
+
+ Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
+ Cairo::RefPtr<Cairo::Context> context;
+ Cairo::RefPtr<Cairo::Region> expose_region;
+
+ bool expose ();
+ int blit_to_device_frame_buffer ();
+};
+
+} /* namespace ArdourSurface */
+
+#endif /* __ardour_push2_canvas_h__ */
diff --git a/libs/surfaces/push2/knob.cc b/libs/surfaces/push2/knob.cc
new file mode 100644
index 0000000000..71edaf5b5c
--- /dev/null
+++ b/libs/surfaces/push2/knob.cc
@@ -0,0 +1,354 @@
+/*
+ Copyright (C) 2016 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.
+*/
+
+#include <cmath>
+
+#include <cairomm/context.h>
+#include <cairomm/pattern.h>
+
+#include "ardour/automation_control.h"
+#include "ardour/dB.h"
+
+#include "gtkmm2ext/gui_thread.h"
+#include "gtkmm2ext/rgb_macros.h"
+
+#include "canvas/colors.h"
+
+#include "knob.h"
+#include "push2.h"
+#include "utils.h"
+
+#include "pbd/i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+using namespace ArdourSurface;
+using namespace ArdourCanvas;
+
+Push2Knob::Element Push2Knob::default_elements = Push2Knob::Element (Push2Knob::Arc);
+
+Push2Knob::Push2Knob (Push2& p, Item* parent, Element e, Flags flags)
+ : Item (parent)
+ , p2 (p)
+ , _elements (e)
+ , _flags (flags)
+ , _r (0)
+ , _val (0)
+ , _normal (0)
+ , text (this)
+{
+ Pango::FontDescription fd ("Sans 10");
+ text.set_font_description (fd);
+ text.set_position (Duple (0, -20)); /* changed when radius changes */
+
+ /* typically over-ridden */
+
+ text_color = p2.get_color (Push2::ParameterName);
+ arc_start_color = p2.get_color (Push2::KnobArcStart);
+ arc_end_color = p2.get_color (Push2::KnobArcEnd);
+}
+
+Push2Knob::~Push2Knob ()
+{
+}
+
+void
+Push2Knob::set_text_color (Color c)
+{
+ text.set_color (c);
+}
+
+void
+Push2Knob::set_radius (double r)
+{
+ _r = r;
+ text.set_position (Duple (-_r, -_r - 20));
+ redraw ();
+}
+
+void
+Push2Knob::compute_bounding_box () const
+{
+ if (!_canvas || _r == 0) {
+ _bounding_box = boost::optional<Rect> ();
+ _bounding_box_dirty = false;
+ return;
+ }
+
+ if (_bounding_box_dirty) {
+ Rect r = Rect (0, 0, _r * 2.0, _r * 2.0);
+ _bounding_box = r;
+ _bounding_box_dirty = false;
+ }
+
+ add_child_bounding_boxes ();
+}
+
+void
+Push2Knob::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
+{
+ if (!_controllable) {
+ /* no controllable, nothing to draw */
+ return;
+ }
+
+ const float scale = 2.0 * _r;
+ const float pointer_thickness = 3.0 * (scale/80); //(if the knob is 80 pixels wide, we want a 3-pix line on it)
+
+ const float start_angle = ((180 - 65) * G_PI) / 180;
+ const float end_angle = ((360 + 65) * G_PI) / 180;
+
+ float zero = 0;
+
+ if (_flags & ArcToZero) {
+ zero = _normal;
+ }
+
+ const float value_angle = start_angle + (_val * (end_angle - start_angle));
+ const float zero_angle = start_angle + (zero * (end_angle - start_angle));
+
+ float value_x = cos (value_angle);
+ float value_y = sin (value_angle);
+
+ context->translate (_position.x, _position.y); //after this, everything is based on the center of the knob
+ context->begin_new_path ();
+
+ float center_radius = 0.48*scale;
+ float border_width = 0.8;
+
+ const bool arc = (_elements & Arc)==Arc;
+ const bool flat = false;
+
+ if (arc) {
+ center_radius = scale*0.33;
+
+ float inner_progress_radius = scale*0.38;
+ float outer_progress_radius = scale*0.48;
+ float progress_width = (outer_progress_radius-inner_progress_radius);
+ float progress_radius = inner_progress_radius + progress_width/2.0;
+
+ //dark arc background
+ set_source_rgb (context, p2.get_color (Push2::KnobArcBackground));
+ context->set_line_width (progress_width);
+ context->arc (0, 0, progress_radius, start_angle, end_angle);
+ context->stroke ();
+
+
+ double red_start, green_start, blue_start, astart;
+ double red_end, green_end, blue_end, aend;
+
+ ArdourCanvas::color_to_rgba (arc_start_color, red_start, green_start, blue_start, astart);
+ ArdourCanvas::color_to_rgba (arc_end_color, red_end, green_end, blue_end, aend);
+
+ //vary the arc color over the travel of the knob
+ float intensity = fabsf (_val - zero) / std::max(zero, (1.f - zero));
+ const float intensity_inv = 1.0 - intensity;
+ float r = intensity_inv * red_end + intensity * red_start;
+ float g = intensity_inv * green_end + intensity * green_start;
+ float b = intensity_inv * blue_end + intensity * blue_start;
+
+ //draw the arc
+ context->set_source_rgb (r,g,b);
+ context->set_line_width (progress_width);
+ if (zero_angle > value_angle) {
+ context->arc (0, 0, progress_radius, value_angle, zero_angle);
+ } else {
+ context->arc (0, 0, progress_radius, zero_angle, value_angle);
+ }
+ context->stroke ();
+
+ //shade the arc
+ if (!flat) {
+ //note we have to offset the pattern from our centerpoint
+ Cairo::RefPtr<Cairo::LinearGradient> pattern = Cairo::LinearGradient::create (0.0, -_position.y, 0.0, _position.y);
+ pattern->add_color_stop_rgba (0.0, 1,1,1, 0.15);
+ pattern->add_color_stop_rgba (0.5, 1,1,1, 0.0);
+ pattern->add_color_stop_rgba (1.0, 1,1,1, 0.0);
+ context->set_source (pattern);
+ context->arc (0, 0, outer_progress_radius-1, 0, 2.0*G_PI);
+ context->fill ();
+ }
+ }
+
+ if (!flat) {
+ //knob shadow
+ context->save();
+ context->translate(pointer_thickness+1, pointer_thickness+1 );
+ set_source_rgba (context, p2.get_color (Push2::KnobShadow));
+ context->arc (0, 0, center_radius-1, 0, 2.0*G_PI);
+ context->fill ();
+ context->restore();
+
+ //inner circle
+ set_source_rgb (context, p2.get_color (Push2::KnobForeground));
+ context->arc (0, 0, center_radius, 0, 2.0*G_PI);
+ context->fill ();
+
+ //radial gradient as a lightness shade
+ Cairo::RefPtr<Cairo::RadialGradient> pattern = Cairo::RadialGradient::create (-center_radius, -center_radius, 1, -center_radius, -center_radius, center_radius*2.5 ); //note we have to offset the gradient from our centerpoint
+ pattern->add_color_stop_rgba (0.0, 0, 0, 0, 0.2);
+ pattern->add_color_stop_rgba (1.0, 1, 1, 1, 0.3);
+ context->set_source (pattern);
+ context->arc (0, 0, center_radius, 0, 2.0*G_PI);
+ context->fill ();
+
+ }
+
+ //black knob border
+ context->set_line_width (border_width);
+ set_source_rgba (context, p2.get_color (Push2::KnobBorder));
+ context->set_source_rgba (0, 0, 0, 1 );
+ context->arc (0, 0, center_radius, 0, 2.0*G_PI);
+ context->stroke ();
+
+ //line shadow
+ if (!flat) {
+ context->save();
+ context->translate(1, 1 );
+ set_source_rgba (context, p2.get_color (Push2::KnobLineShadow));
+ context->set_line_cap (Cairo::LINE_CAP_ROUND);
+ context->set_line_width (pointer_thickness);
+ context->move_to ((center_radius * value_x), (center_radius * value_y));
+ context->line_to (((center_radius*0.4) * value_x), ((center_radius*0.4) * value_y));
+ context->stroke ();
+ context->restore();
+ }
+
+ //line
+ set_source_rgba (context, p2.get_color (Push2::KnobLine));
+ context->set_line_cap (Cairo::LINE_CAP_ROUND);
+ context->set_line_width (pointer_thickness);
+ context->move_to ((center_radius * value_x), (center_radius * value_y));
+ context->line_to (((center_radius*0.4) * value_x), ((center_radius*0.4) * value_y));
+ context->stroke ();
+
+ /* reset all translations, scaling etc. */
+ context->set_identity_matrix();
+
+ render_children (area, context);
+}
+
+void
+Push2Knob::set_controllable (boost::shared_ptr<AutomationControl> c)
+{
+ watch_connection.disconnect (); //stop watching the old controllable
+
+ if (!c) {
+ _controllable.reset ();
+ return;
+ }
+
+ _controllable = c;
+ _controllable->Changed.connect (watch_connection, invalidator(*this), boost::bind (&Push2Knob::controllable_changed, this), &p2);
+
+ controllable_changed ();
+}
+
+void
+Push2Knob::set_pan_azimuth_text (double pos)
+{
+ /* We show the position of the center of the image relative to the left & right.
+ This is expressed as a pair of percentage values that ranges from (100,0)
+ (hard left) through (50,50) (hard center) to (0,100) (hard right).
+
+ This is pretty wierd, but its the way audio engineers expect it. Just remember that
+ the center of the USA isn't Kansas, its (50LA, 50NY) and it will all make sense.
+ */
+
+ char buf[64];
+ snprintf (buf, sizeof (buf), _("L:%3d R:%3d"), (int) rint (100.0 * (1.0 - pos)), (int) rint (100.0 * pos));
+ text.set (buf);
+}
+
+void
+Push2Knob::set_pan_width_text (double val)
+{
+ char buf[16];
+ snprintf (buf, sizeof (buf), "%d%%", (int) floor (val*100));
+ text.set (buf);
+}
+
+void
+Push2Knob::set_gain_text (double)
+{
+ char buf[16];
+
+ /* need to ignore argument, because it has already been converted into
+ the "interface" (0..1) range.
+ */
+
+ snprintf (buf, sizeof (buf), "%.1f dB", accurate_coefficient_to_dB (_controllable->get_value()));
+ text.set (buf);
+}
+
+void
+Push2Knob::controllable_changed ()
+{
+ if (_controllable) {
+ _normal = _controllable->internal_to_interface (_controllable->normal());
+ _val = _controllable->internal_to_interface (_controllable->get_value());
+
+ switch (_controllable->parameter().type()) {
+ case ARDOUR::PanAzimuthAutomation:
+ set_pan_azimuth_text (_val);
+ break;
+
+ case ARDOUR::PanWidthAutomation:
+ set_pan_width_text (_val);
+ break;
+
+ case ARDOUR::GainAutomation:
+ case ARDOUR::BusSendLevel:
+ set_gain_text (_val);
+ break;
+
+ default:
+ text.set (std::string());
+ }
+ }
+
+ redraw ();
+}
+
+void
+Push2Knob::add_flag (Flags f)
+{
+ _flags = Flags (_flags | f);
+ redraw ();
+}
+
+void
+Push2Knob::remove_flag (Flags f)
+{
+ _flags = Flags (_flags & ~f);
+ redraw ();
+}
+
+void
+Push2Knob::set_arc_start_color (uint32_t c)
+{
+ arc_start_color = c;
+ redraw ();
+}
+
+void
+Push2Knob::set_arc_end_color (uint32_t c)
+{
+ arc_end_color = c;
+ redraw ();
+}
diff --git a/libs/surfaces/push2/knob.h b/libs/surfaces/push2/knob.h
new file mode 100644
index 0000000000..54b0236155
--- /dev/null
+++ b/libs/surfaces/push2/knob.h
@@ -0,0 +1,90 @@
+#ifndef __ardour_push2_knob_h__
+#define __ardour_push2_knob_h__
+
+#include <boost/shared_ptr.hpp>
+#include <sigc++/trackable.h>
+
+#include <cairomm/refptr.h>
+
+#include "pbd/signals.h"
+
+#include "canvas/item.h"
+#include "canvas/text.h"
+
+namespace ARDOUR {
+ class AutomationControl;
+}
+
+namespace Cairo {
+ class Context;
+ class Region;
+}
+
+namespace ArdourSurface {
+
+class Push2;
+
+class Push2Knob : public sigc::trackable, public ArdourCanvas::Item
+{
+public:
+ enum Element {
+ Arc = 0x1,
+ Bevel = 0x2,
+ unused2 = 0x4,
+ unused3 = 0x8,
+ unused4 = 0x10,
+ unused5 = 0x20,
+ };
+
+ enum Flags {
+ NoFlags = 0,
+ Detent = 0x1,
+ ArcToZero = 0x2,
+ };
+
+ Push2Knob (Push2& p, ArdourCanvas::Item*, Element e = default_elements, Flags flags = NoFlags);
+ virtual ~Push2Knob ();
+
+ static Element default_elements;
+
+ void add_flag (Flags);
+ void remove_flag (Flags);
+
+ void set_controllable (boost::shared_ptr<ARDOUR::AutomationControl> c);
+ boost::shared_ptr<ARDOUR::AutomationControl> controllable() const { return _controllable; }
+
+ void set_text_color (ArdourCanvas::Color);
+ void set_arc_start_color (ArdourCanvas::Color);
+ void set_arc_end_color (ArdourCanvas::Color);
+ void set_position (double x, double y);
+ void set_radius (double r);
+
+ void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
+ void compute_bounding_box() const;
+
+ protected:
+ void controllable_changed ();
+ PBD::ScopedConnection watch_connection;
+ boost::shared_ptr<ARDOUR::AutomationControl> _controllable;
+
+ private:
+ Push2& p2;
+ Element _elements;
+ Flags _flags;
+ double _r;
+ float _val; // current value [0..1]
+ float _normal; // default value, arc
+
+ ArdourCanvas::Color text_color;
+ ArdourCanvas::Color arc_start_color;
+ ArdourCanvas::Color arc_end_color;
+ ArdourCanvas::Text text;
+
+ void set_pan_azimuth_text (double);
+ void set_pan_width_text (double);
+ void set_gain_text (double);
+};
+
+} // namespace
+
+#endif /* __ardour_push2_knob_h__ */
diff --git a/libs/surfaces/push2/layout.cc b/libs/surfaces/push2/layout.cc
index f675e3ddbb..be5ff6fdaf 100644
--- a/libs/surfaces/push2/layout.cc
+++ b/libs/surfaces/push2/layout.cc
@@ -16,14 +16,17 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "canvas.h"
#include "layout.h"
#include "push2.h"
using namespace ARDOUR;
using namespace ArdourSurface;
+using namespace ArdourCanvas;
Push2Layout::Push2Layout (Push2& p, Session& s)
- : p2 (p)
+ : Container (p.canvas())
+ , p2 (p)
, session (s)
{
}
@@ -32,8 +35,24 @@ Push2Layout::~Push2Layout ()
{
}
-bool
-Push2Layout::mapped () const
+void
+Push2Layout::compute_bounding_box () const
{
- return p2.current_layout() == this;
+ /* all layouts occupy at least the full screen, even if their combined
+ * child boxes do not.
+ */
+ _bounding_box = Rect (0, 0, display_width(), display_height());
+ _bounding_box_dirty = false;
+}
+
+int
+Push2Layout::display_height() const
+{
+ return p2.canvas()->rows();
+}
+
+int
+Push2Layout::display_width() const
+{
+ return p2.canvas()->cols();
}
diff --git a/libs/surfaces/push2/layout.h b/libs/surfaces/push2/layout.h
index 30e52da5a8..b4f3703f9a 100644
--- a/libs/surfaces/push2/layout.h
+++ b/libs/surfaces/push2/layout.h
@@ -25,6 +25,12 @@
#include <cairomm/refptr.h>
+#include "canvas/container.h"
+
+namespace Cairo {
+ class Region;
+}
+
namespace ARDOUR {
class Session;
}
@@ -37,17 +43,16 @@ namespace ArdourSurface {
class Push2;
-class Push2Layout : public sigc::trackable
+class Push2Layout : public sigc::trackable, public ArdourCanvas::Container
{
public:
Push2Layout (Push2& p, ARDOUR::Session& s);
virtual ~Push2Layout ();
- bool mapped() const;
+ int display_width () const;
+ int display_height () const;
- virtual bool redraw (Cairo::RefPtr<Cairo::Context>, bool force) const = 0;
- virtual void on_show () {}
- virtual void on_hide () {}
+ void compute_bounding_box () const;
virtual void button_upper (uint32_t n) {}
virtual void button_lower (uint32_t n) {}
diff --git a/libs/surfaces/push2/menu.cc b/libs/surfaces/push2/menu.cc
index cdb5d60e91..da1c98ac04 100644
--- a/libs/surfaces/push2/menu.cc
+++ b/libs/surfaces/push2/menu.cc
@@ -18,38 +18,59 @@
#include <cairomm/context.h>
#include <cairomm/surface.h>
+#include <cairomm/region.h>
#include <pangomm/layout.h>
-#include "push2.h"
+#include "canvas/text.h"
+#include "canvas/rectangle.h"
+#include "canvas/colors.h"
+
+#include "canvas.h"
#include "gui.h"
+#include "push2.h"
using namespace ARDOUR;
using namespace std;
using namespace PBD;
using namespace Glib;
using namespace ArdourSurface;
+using namespace ArdourCanvas;
#include "pbd/i18n.h"
#include "menu.h"
-Push2Menu::Push2Menu (Cairo::RefPtr<Cairo::Context> context)
- : _dirty (true)
+Push2Menu::Push2Menu (Item* parent)
+ : Container (parent)
+ , baseline (-1)
{
Pango::FontDescription fd2 ("Sans 10");
- {
- Glib::RefPtr<Pango::Layout> throwaway = Pango::Layout::create (context);
+ if (baseline < 0) {
+ Push2Canvas* p2c = dynamic_cast<Push2Canvas*> (canvas());
+ Glib::RefPtr<Pango::Layout> throwaway = Pango::Layout::create (p2c->image_context());
throwaway->set_font_description (fd2);
throwaway->set_text (X_("Hg")); /* ascender + descender) */
int h, w;
throwaway->get_pixel_size (w, h);
baseline = h;
- nrows = Push2::rows / baseline;
+ // nrows = Push2::rows / baseline;
}
+
for (int n = 0; n < 8; ++n) {
- columns[n].layout = Pango::Layout::create (context);
- columns[n].layout->set_font_description (fd2);
+ Text* t = new Text (this);
+ t->set_font_description (fd2);
+ t->set_color (rgba_to_color (0.23, 0.0, 0.349, 1.0));
+
+ const double x = 10.0 + (n * Push2Canvas::inter_button_spacing());
+ const double y = 2.0;
+ t->set_position (Duple (x, y));
+
+ Rectangle* r = new Rectangle (this);
+ r->set (Rect (x, y, x + Push2Canvas::inter_button_spacing(), y + baseline));
+
+ columns[n].lines = t;
+ columns[n].active_bg = r;
columns[n].top = -1;
columns[n].active = -1;
}
@@ -71,8 +92,6 @@ Push2Menu::fill_column (int col, vector<string> v)
}
set_text (col, 0);
-
- _dirty = true;
}
void
@@ -86,6 +105,7 @@ Push2Menu::set_text (int col, int top_row)
return;
}
+
vector<string>::iterator s = columns[col].text.begin();
s += top_row;
@@ -101,10 +121,10 @@ Push2Menu::set_text (int col, int top_row)
}
}
- columns[col].layout->set_text (rows);
+ columns[col].lines->set (rows);
columns[col].top = top_row;
- _dirty = true;
+ redraw ();
}
void
@@ -115,24 +135,43 @@ Push2Menu::scroll (int col, int dir)
} else {
set_text (col, columns[col].top - 1);
}
+
+ redraw ();
}
void
Push2Menu::set_active (int col, int index)
{
if (col < 0 || col > 7) {
+ columns[col].active_bg->hide ();
return;
}
if (index < 0 || index > (int) columns[col].text.size()) {
+ columns[col].active_bg->hide ();
return;
}
columns[col].active = index;
+ int effective_row = columns[col].active - columns[col].top;
+
+ /* Move active bg */
+
+ Duple p (columns[col].active_bg->position());
+
+ columns[col].active_bg->set (Rect (p.x, p.y + (effective_row * baseline),
+ p.x + Push2Canvas::inter_button_spacing(), p.y + baseline));
+ columns[col].active_bg->show ();
+
+ if (columns[col].active < nrows/2) {
+ set_text (col, 0);
+ } else {
+ set_text (col, columns[col].active - (nrows/2) + 1);
+ }
ActiveChanged (); /* emit signal */
- _dirty = true;
+ redraw ();
}
void
@@ -149,31 +188,25 @@ Push2Menu::step_active (int col, int dir)
if (dir < 0) {
if (columns[col].active == -1) {
- columns[col].active = 0;
+ set_active (col, -1);
} else {
columns[col].active = columns[col].active - 1;
if (columns[col].active < 0) {
- columns[col].active = columns[col].text.size() - 1;
+ set_active (col, columns[col].text.size() - 1);
}
}
} else {
if (columns[col].active == -1) {
- columns[col].active = 0;
+ set_active (col, 0);
} else {
columns[col].active = columns[col].active + 1;
if (columns[col].active >= (int) columns[col].text.size()) {
- columns[col].active = 0;
+ set_active (col, 0);
}
}
}
- if (columns[col].active < nrows/2) {
- set_text (col, 0);
- } else {
- set_text (col, columns[col].active - (nrows/2) + 1);
- }
-
- _dirty = true;
+ redraw ();
}
int
@@ -187,32 +220,7 @@ Push2Menu::get_active (int col)
}
void
-Push2Menu::redraw (Cairo::RefPtr<Cairo::Context> context, bool force) const
+Push2Menu::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
{
- for (int n = 0; n < 8; ++n) {
-
- /* Active: move to column/now, draw background indicator
- for active row.
- */
-
- const double x = 10.0 + (n * 120.0);
- const double y = 2.0;
-
- if (columns[n].active >= 0) {
- int effective_row = columns[n].active - columns[n].top;
- context->rectangle (x, y + (effective_row * baseline), 120.0, baseline);
- context->set_source_rgb (1.0, 1.0, 1.0);
- context->fill ();
- }
-
- /* now draw all the text, in one go */
-
- context->move_to (x, y);
- context->set_source_rgb (0.23, 0.0, 0.349);
- columns[n].layout->update_from_cairo_context (context);
- columns[n].layout->show_in_cairo_context (context);
-
- }
-
- _dirty = false;
+ render_children (area, context);
}
diff --git a/libs/surfaces/push2/menu.h b/libs/surfaces/push2/menu.h
index 946d2df56d..1e6e3d6d10 100644
--- a/libs/surfaces/push2/menu.h
+++ b/libs/surfaces/push2/menu.h
@@ -19,20 +19,30 @@
#ifndef __ardour_push2_menu_h__
#define __ardour_push2_menu_h__
-#include <cairomm/context.h>
-#include <cairomm/surface.h>
+namespace Cairo {
+ class Context;
+ class Region;
+}
+
#include <pangomm/layout.h>
#include "pbd/signals.h"
+#include "canvas/container.h"
+
+namespace ArdourCanvas {
+ class Text;
+ class Rectangle;
+}
+
namespace ArdourSurface {
-class Push2Menu {
+class Push2Menu : public ArdourCanvas::Container
+{
public:
- Push2Menu (Cairo::RefPtr<Cairo::Context>);
+ Push2Menu (ArdourCanvas::Item* parent);
- void redraw (Cairo::RefPtr<Cairo::Context>, bool force) const;
- bool dirty () const { return _dirty; }
+ void render (ArdourCanvas::Rect const& area, Cairo::RefPtr<Cairo::Context> context) const;
void fill_column (int col, std::vector<std::string>);
void set_active (int col, int index);
@@ -45,7 +55,8 @@ class Push2Menu {
private:
struct Column {
std::vector<std::string> text;
- Glib::RefPtr<Pango::Layout> layout;
+ ArdourCanvas::Rectangle* active_bg;
+ ArdourCanvas::Text* lines;
int top;
int active;
};
@@ -56,9 +67,7 @@ class Push2Menu {
void set_text (int col, int top);
int nrows;
- double baseline;
-
- mutable bool _dirty;
+ mutable double baseline;
};
} // namespace
diff --git a/libs/surfaces/push2/mix.cc b/libs/surfaces/push2/mix.cc
index 09d92e0a91..bf10abf30a 100644
--- a/libs/surfaces/push2/mix.cc
+++ b/libs/surfaces/push2/mix.cc
@@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <cairomm/region.h>
#include <pangomm/layout.h>
#include "pbd/compose.h"
@@ -42,9 +43,11 @@
#include "ardour/vca_manager.h"
#include "canvas/colors.h"
+#include "canvas/rectangle.h"
#include "gtkmm2ext/gui_thread.h"
+#include "canvas.h"
#include "mix.h"
#include "knob.h"
#include "push2.h"
@@ -57,17 +60,22 @@ using namespace std;
using namespace PBD;
using namespace Glib;
using namespace ArdourSurface;
+using namespace ArdourCanvas;
-MixLayout::MixLayout (Push2& p, Session& s, Cairo::RefPtr<Cairo::Context> context)
+MixLayout::MixLayout (Push2& p, Session& s)
: Push2Layout (p, s)
- , _dirty (true)
, bank_start (0)
, vpot_mode (Volume)
{
+ selection_bg = new Rectangle (this);
+ selection_bg->hide ();
+
Pango::FontDescription fd2 ("Sans 10");
for (int n = 0; n < 8; ++n) {
- upper_layout[n] = Pango::Layout::create (context);
- upper_layout[n]->set_font_description (fd2);
+ Text* t = new Text (this);
+ upper_text.push_back (t);
+ t->set_font_description (fd2);
+ t->set_color (p2.get_color (Push2::ParameterName));
string txt;
switch (n) {
@@ -96,18 +104,19 @@ MixLayout::MixLayout (Push2& p, Session& s, Cairo::RefPtr<Cairo::Context> contex
txt = _("E Sends");
break;
}
- upper_layout[n]->set_text (txt);
- }
+ t->set (txt);
- Pango::FontDescription fd3 ("Sans 10");
- for (int n = 0; n < 8; ++n) {
- lower_layout[n] = Pango::Layout::create (context);
- lower_layout[n]->set_font_description (fd3);
- }
+ t = new Text (this);
+ lower_text.push_back (t);
+ t->set_font_description (fd2);
+ t->set_color (p2.get_color (Push2::ParameterName));
- for (int n = 0; n < 8; ++n) {
- knobs[n] = new Push2Knob (p2, context);
- knobs[n]->set_position (60 + (n*120), 95);
+ Rectangle* r = new Rectangle (this);
+ r->set (Rect (10 + (n*Push2Canvas::inter_button_spacing()) - 5, 2, Push2Canvas::inter_button_spacing(), 21));
+ backgrounds.push_back (r);
+
+ knobs[n] = new Push2Knob (p2, this);
+ knobs[n]->set_position (60 + (n*Push2Canvas::inter_button_spacing()), 95);
knobs[n]->set_radius (25);
}
@@ -119,14 +128,14 @@ MixLayout::MixLayout (Push2& p, Session& s, Cairo::RefPtr<Cairo::Context> contex
MixLayout::~MixLayout ()
{
- for (int n = 0; n < 8; ++n) {
- delete knobs[n];
- }
+ // Item destructor deletes all children
}
void
-MixLayout::on_show ()
+MixLayout::show ()
{
+ Item::show ();
+
mode_button->set_color (Push2::LED::White);
mode_button->set_state (Push2::LED::OneShot24th);
p2.write (mode_button->state_msg());
@@ -134,116 +143,19 @@ MixLayout::on_show ()
switch_bank (bank_start);
}
-bool
-MixLayout::redraw (Cairo::RefPtr<Cairo::Context> context, bool force) const
+void
+MixLayout::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
{
- bool children_dirty = false;
-
- for (int n = 0; n < 8; ++n) {
- if (knobs[n]->dirty()) {
- children_dirty = true;
- break;
- }
- }
-
- for (int n = 0; n < 8; ++n) {
- if (stripable[n]) {
-
- string shortname = short_version (stripable[n]->name(), 10);
- string text;
- boost::shared_ptr<AutomationControl> ac;
- ac = stripable[n]->solo_control();
- if (ac && ac->get_value()) {
- text += "* ";
- }
- boost::shared_ptr<MuteControl> mc;
- mc = stripable[n]->mute_control ();
- if (mc) {
- if (mc->muted_by_self_or_masters()) {
- text += "! ";
- } else if (mc->muted_by_others_soloing()) {
- text += "- "; // it would be nice to use Unicode mute"\uD83D\uDD07 ";
- }
- }
- text += shortname;
-
- if (text != lower_layout[n]->get_text()) {
- lower_layout[n]->set_text (text);
- children_dirty = true;
- }
- }
- }
-
- if (!children_dirty && !_dirty && !force) {
- return false;
- }
-
set_source_rgb (context, p2.get_color (Push2::DarkBackground));
- context->rectangle (0, 0, p2.cols, p2.rows);
+ context->rectangle (0, 0, display_width(), display_height());
context->fill ();
- set_source_rgb (context, p2.get_color (Push2::ParameterName));
-
- for (int n = 0; n < 8; ++n) {
-
- if (upper_layout[n]->get_text().empty()) {
- continue;
- }
-
- /* Draw highlight box */
-
- uint32_t color = p2.get_color (Push2::ParameterName);
-
- if (n == (int) vpot_mode) {
- set_source_rgb (context, color);
- context->rectangle (10 + (n*120) - 5, 2, 120, 21);
- context->fill();
- set_source_rgb (context, ArdourCanvas::contrasting_text_color (color));
- } else {
- set_source_rgb (context, color);
- }
-
- context->move_to (10 + (n*120), 2);
- upper_layout[n]->update_from_cairo_context (context);
- upper_layout[n]->show_in_cairo_context (context);
- }
-
context->move_to (0, 22.5);
- context->line_to (p2.cols, 22.5);
+ context->line_to (display_width(), 22.5);
context->set_line_width (1.0);
context->stroke ();
- for (int n = 0; n < 8; ++n) {
- knobs[n]->redraw (context, force);
- }
-
- for (int n = 0; n < 8; ++n) {
-
- if (lower_layout[n]->get_text().empty()) {
- continue;
- }
-
- if (stripable[n]) {
- uint32_t color = stripable[n]->presentation_info().color();
-
- if (stripable[n]->presentation_info().selected()) {
- set_source_rgb (context, color);
- context->rectangle (10 + (n*120) - 5, 137, 120, 21);
- context->fill();
- set_source_rgb (context, ArdourCanvas::contrasting_text_color (color));
- } else {
- set_source_rgb (context, color);
- }
-
- context->move_to (10 + (n*120), 140);
- lower_layout[n]->update_from_cairo_context (context);
- lower_layout[n]->show_in_cairo_context (context);
- }
- }
-
- _dirty = false;
-
- return true;
+ render_children (area, context);
}
void
@@ -466,12 +378,53 @@ MixLayout::stripable_property_change (PropertyChange const& what_changed, int wh
return;
}
- /* cancel string, which will cause a redraw on the next update
- * cycle. The redraw will reflect selected status
- */
+ if (stripable[which]->presentation_info().selected()) {
+ selection_bg->show ();
+ selection_bg->set_fill_color (stripable[which]->presentation_info().color());
+ selection_bg->set (Rect (10 + (which*Push2Canvas::inter_button_spacing()) - 5, 137,
+ 10 + (which*Push2Canvas::inter_button_spacing()) - 5 + Push2Canvas::inter_button_spacing(),
+ 137 + 21));
+ lower_text[which]->set_color (ArdourCanvas::contrasting_text_color (selection_bg->fill_color()));
+ } else {
+ selection_bg->hide ();
+ lower_text[which]->set_color (stripable[which]->presentation_info().color());
+ }
+ }
+}
+
+void
+MixLayout::solo_changed (uint32_t n)
+{
+ solo_mute_changed (n);
+}
- lower_layout[which]->set_text (string());
+void
+MixLayout::mute_changed (uint32_t n)
+{
+ solo_mute_changed (n);
+}
+
+void
+MixLayout::solo_mute_changed (uint32_t n)
+{
+ string shortname = short_version (stripable[n]->name(), 10);
+ string text;
+ boost::shared_ptr<AutomationControl> ac;
+ ac = stripable[n]->solo_control();
+ if (ac && ac->get_value()) {
+ text += "* ";
}
+ boost::shared_ptr<MuteControl> mc;
+ mc = stripable[n]->mute_control ();
+ if (mc) {
+ if (mc->muted_by_self_or_masters()) {
+ text += "! ";
+ } else if (mc->muted_by_others_soloing()) {
+ text += "- "; // it would be nice to use Unicode mute"\uD83D\uDD07 ";
+ }
+ }
+ text += shortname;
+ lower_text[n]->set (text);
}
void
@@ -499,6 +452,11 @@ MixLayout::switch_bank (uint32_t base)
/* some missing strips; new bank the same or more empty stripables than the old one, do
nothing since we had already reached the end.
*/
+ for (int n = 0; n < 8; ++n) {
+ upper_text[n]->hide ();
+ lower_text[n]->hide ();
+ backgrounds[n]->hide ();
+ }
return;
}
@@ -512,13 +470,25 @@ MixLayout::switch_bank (uint32_t base)
for (int n = 0; n < 8; ++n) {
if (!stripable[n]) {
+ upper_text[n]->hide ();
+ lower_text[n]->hide ();
+ backgrounds[n]->hide ();
continue;
}
+ upper_text[n]->show ();
+ lower_text[n]->show ();
+ backgrounds[n]->show ();
+ backgrounds[n]->set_fill_color (stripable[n]->presentation_info().color());
+
/* stripable goes away? refill the bank, starting at the same point */
stripable[n]->DropReferences.connect (stripable_connections, invalidator (*this), boost::bind (&MixLayout::switch_bank, this, bank_start), &p2);
stripable[n]->presentation_info().PropertyChanged.connect (stripable_connections, invalidator (*this), boost::bind (&MixLayout::stripable_property_change, this, _1, n), &p2);
+ stripable[n]->solo_control()->Changed.connect (stripable_connections, invalidator (*this), boost::bind (&MixLayout::solo_changed, this, n), &p2);
+ stripable[n]->mute_control()->Changed.connect (stripable_connections, invalidator (*this), boost::bind (&MixLayout::mute_changed, this, n), &p2);
+
+ solo_mute_changed (n);
Push2::Button* b;
diff --git a/libs/surfaces/push2/mix.h b/libs/surfaces/push2/mix.h
index ebd936aff1..85b1feba10 100644
--- a/libs/surfaces/push2/mix.h
+++ b/libs/surfaces/push2/mix.h
@@ -26,6 +26,11 @@ namespace ARDOUR {
class Stripable;
}
+namespace ArdourCanvas {
+ class Rectangle;
+ class Text;
+}
+
namespace ArdourSurface {
class Push2Knob;
@@ -33,11 +38,11 @@ class Push2Knob;
class MixLayout : public Push2Layout
{
public:
- MixLayout (Push2& p, ARDOUR::Session&, Cairo::RefPtr<Cairo::Context>);
+ MixLayout (Push2& p, ARDOUR::Session&);
~MixLayout ();
- bool redraw (Cairo::RefPtr<Cairo::Context>, bool force) const;
- void on_show ();
+ void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
+ void show ();
void button_upper (uint32_t n);
void button_lower (uint32_t n);
@@ -53,8 +58,10 @@ class MixLayout : public Push2Layout
private:
mutable bool _dirty;
- Glib::RefPtr<Pango::Layout> upper_layout[8];
- Glib::RefPtr<Pango::Layout> lower_layout[8];
+ std::vector<ArdourCanvas::Text*> upper_text;
+ std::vector<ArdourCanvas::Text*> lower_text;
+ std::vector<ArdourCanvas::Rectangle*> backgrounds;
+ ArdourCanvas::Rectangle* selection_bg;
Push2Knob* knobs[8];
/* stripables */
@@ -80,6 +87,10 @@ class MixLayout : public Push2Layout
Push2::Button* mode_button;
VPotMode vpot_mode;
void show_vpot_mode ();
+
+ void solo_changed (uint32_t n);
+ void mute_changed (uint32_t n);
+ void solo_mute_changed (uint32_t n);
};
} /* namespace */
diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc
index caa3f1e102..0cf7ceee96 100644
--- a/libs/surfaces/push2/push2.cc
+++ b/libs/surfaces/push2/push2.cc
@@ -33,7 +33,6 @@
#include "ardour/async_midi_port.h"
#include "ardour/audioengine.h"
#include "ardour/debug.h"
-#include "ardour/filesystem_paths.h"
#include "ardour/midiport_manager.h"
#include "ardour/midi_track.h"
#include "ardour/midi_port.h"
@@ -45,13 +44,14 @@
#include "canvas/colors.h"
-#include "push2.h"
+#include "canvas.h"
#include "gui.h"
#include "layout.h"
-#include "scale.h"
+#include "menu.h"
#include "mix.h"
+#include "push2.h"
+#include "scale.h"
#include "track_mix.h"
-#include "menu.h"
#include "pbd/i18n.h"
@@ -63,10 +63,6 @@ using namespace ArdourSurface;
#include "pbd/abstract_ui.cc" // instantiate template
-const int Push2::cols = 960;
-const int Push2::rows = 160;
-const int Push2::pixels_per_row = 1024;
-
#define ABLETON 0x2982
#define PUSH2 0x1967
@@ -127,8 +123,6 @@ Push2::Push2 (ARDOUR::Session& s)
: ControlProtocol (s, string (X_("Ableton Push 2")))
, AbstractUI<Push2Request> (name())
, handle (0)
- , device_buffer (0)
- , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
, _modifier_state (None)
, splash_start (0)
, _current_layout (0)
@@ -143,7 +137,6 @@ Push2::Push2 (ARDOUR::Session& s)
, percussion (false)
, _pressure_mode (AfterTouch)
{
- context = Cairo::Context::create (frame_buffer);
build_maps ();
build_color_map ();
@@ -234,15 +227,17 @@ Push2::open ()
return -1;
}
- device_frame_buffer = new uint16_t[rows*pixels_per_row];
-
- memset (device_frame_buffer, 0, sizeof (uint16_t) * rows * pixels_per_row);
-
- frame_header[0] = 0xef;
- frame_header[1] = 0xcd;
- frame_header[2] = 0xab;
- frame_header[3] = 0x89;
- memset (&frame_header[4], 0, 12);
+ try {
+ _canvas = new Push2Canvas (*this, 160, 960);
+ mix_layout = new MixLayout (*this, *session);
+ scale_layout = new ScaleLayout (*this, *session);
+ track_mix_layout = new TrackMixLayout (*this, *session);
+ } catch (...) {
+ error << _("Cannot construct Canvas for display") << endmsg;
+ libusb_release_interface (handle, 0x00);
+ libusb_close (handle);
+ return -1;
+ }
/* setup ports */
@@ -284,9 +279,7 @@ Push2::open ()
connect_to_parser ();
- mix_layout = new MixLayout (*this, *session, context);
- scale_layout = new ScaleLayout (*this, *session, context);
- track_mix_layout = new TrackMixLayout (*this, *session, context);
+ _canvas->splash ();
return 0;
}
@@ -321,7 +314,6 @@ Push2::close ()
_input_port = 0;
_output_port = 0;
- vblank_connection.disconnect ();
periodic_connection.disconnect ();
session_connections.drop_connections ();
@@ -338,9 +330,6 @@ Push2::close ()
handle = 0;
}
- delete [] device_frame_buffer;
- device_frame_buffer = 0;
-
return 0;
}
@@ -460,63 +449,8 @@ Push2::stop ()
return 0;
}
-/** render host-side frame buffer (a Cairo ImageSurface) to the current
- * device-side frame buffer. The device frame buffer will be pushed to the
- * device on the next call to vblank()
- */
-
-int
-Push2::blit_to_device_frame_buffer ()
-{
- /* ensure that all drawing has been done before we fetch pixel data */
-
- frame_buffer->flush ();
-
- const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
- const uint8_t* data = frame_buffer->get_data ();
-
- /* fill frame buffer (320kB) */
-
- uint16_t* fb = (uint16_t*) device_frame_buffer;
-
- for (int row = 0; row < rows; ++row) {
-
- const uint8_t* dp = data + row * stride;
-
- for (int col = 0; col < cols; ++col) {
-
- /* fetch r, g, b (range 0..255). Ignore alpha */
-
- const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
- const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
- const int b = *((const uint32_t*)dp) & 0xff;
-
- /* convert to 5 bits, 6 bits, 5 bits, respectively */
- /* generate 16 bit BGB565 value */
-
- *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
-
- /* the push2 docs state that we should xor the pixel
- * data. Doing so doesn't work correctly, and not doing
- * so seems to work fine (colors roughly match intended
- * values).
- */
-
- dp += 4;
- }
-
- /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
- byte USB buffers
- */
-
- fb += 64; /* 128 bytes = 64 int16_t */
- }
-
- return 0;
-}
-
bool
-Push2::redraw ()
+Push2::vblank ()
{
if (splash_start) {
@@ -524,50 +458,15 @@ Push2::redraw ()
if (get_microseconds() - splash_start > 3000000) {
splash_start = 0;
- } else {
- return false;
}
- }
-
- Glib::Threads::Mutex::Lock lm (layout_lock, Glib::Threads::TRY_LOCK);
-
- if (!lm.locked()) {
- /* can't get layout, no re-render needed */
- return false;
- }
-
- bool render_needed = false;
-
- if (drawn_layout != _current_layout) {
- render_needed = true;
- }
- bool dirty = _current_layout->redraw (context, render_needed);
- drawn_layout = _current_layout;
+ return true;
- return dirty || render_needed;
-}
-
-bool
-Push2::vblank ()
-{
- int transferred = 0;
- const int timeout_msecs = 1000;
- int err;
-
- if ((err = libusb_bulk_transfer (handle, 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
- return false;
- }
+ } else {
- if (redraw()) {
- /* things changed */
- blit_to_device_frame_buffer ();
- }
+ _canvas->vblank();
- if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
- return false;
}
-
return true;
}
@@ -1210,60 +1109,6 @@ Push2::end_shift ()
void
Push2::splash ()
{
- std::string splash_file;
-
- Searchpath rc (ARDOUR::ardour_data_search_path());
- rc.add_subdirectory_to_paths ("resources");
-
- if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
- cerr << "Cannot find splash screen image file\n";
- throw failed_constructor();
- }
-
- Cairo::RefPtr<Cairo::ImageSurface> img = Cairo::ImageSurface::create_from_png (splash_file);
-
- double x_ratio = (double) img->get_width() / (cols - 20);
- double y_ratio = (double) img->get_height() / (rows - 20);
- double scale = min (x_ratio, y_ratio);
-
- /* background */
-
- context->set_source_rgb (0.764, 0.882, 0.882);
- context->paint ();
-
- /* image */
-
- context->save ();
- context->translate (5, 5);
- context->scale (scale, scale);
- context->set_source (img, 0, 0);
- context->paint ();
- context->restore ();
-
- /* text */
-
- Glib::RefPtr<Pango::Layout> some_text = Pango::Layout::create (context);
-
- Pango::FontDescription fd ("Sans 38");
- some_text->set_font_description (fd);
- some_text->set_text (string_compose ("%1 %2", PROGRAM_NAME, VERSIONSTRING));
-
- context->move_to (200, 10);
- context->set_source_rgb (0, 0, 0);
- some_text->update_from_cairo_context (context);
- some_text->show_in_cairo_context (context);
-
- Pango::FontDescription fd2 ("Sans Italic 18");
- some_text->set_font_description (fd2);
- some_text->set_text (_("Ableton Push 2 Support"));
-
- context->move_to (200, 80);
- context->set_source_rgb (0, 0, 0);
- some_text->update_from_cairo_context (context);
- some_text->show_in_cairo_context (context);
-
- splash_start = get_microseconds ();
- blit_to_device_frame_buffer ();
}
bool
@@ -1730,7 +1575,7 @@ Push2::fill_color_table ()
}
-uint32_t
+ArdourCanvas::Color
Push2::get_color (ColorName name)
{
Colors::iterator c = colors.find (name);
@@ -1745,14 +1590,15 @@ void
Push2::set_current_layout (Push2Layout* layout)
{
if (_current_layout) {
- _current_layout->on_hide ();
+ _current_layout->hide ();
+ _canvas->root()->remove (_current_layout);
}
_current_layout = layout;
- drawn_layout = 0;
if (_current_layout) {
- _current_layout->on_show ();
+ _current_layout->show ();
+ _canvas->root()->add (_current_layout);
}
}
diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h
index be4c116895..4704ce9a30 100644
--- a/libs/surfaces/push2/push2.h
+++ b/libs/surfaces/push2/push2.h
@@ -27,8 +27,6 @@
#include <libusb.h>
-#include <cairomm/refptr.h>
-
#define ABSTRACT_UI_EXPORTS
#include "pbd/abstract_ui.h"
@@ -42,11 +40,6 @@
#include "midi_byte_array.h"
#include "mode.h"
-namespace Cairo {
- class ImageSurface;
- class Context;
-}
-
namespace Pango {
class Layout;
}
@@ -74,6 +67,7 @@ public:
class P2GUI;
class Push2Menu;
class Push2Layout;
+class Push2Canvas;
class Push2 : public ARDOUR::ControlProtocol
, public AbstractUI<Push2Request>
@@ -341,6 +335,7 @@ class Push2 : public ARDOUR::ControlProtocol
bool in_key() const { return _in_key; }
Push2Layout* current_layout() const;
+ Push2Canvas* canvas() const { return _canvas; }
enum ModifierState {
None = 0,
@@ -357,33 +352,20 @@ class Push2 : public ARDOUR::ControlProtocol
uint8_t get_color_index (uint32_t rgb);
uint32_t get_color (ColorName);
- static const int cols;
- static const int rows;
-
PressureMode pressure_mode () const { return _pressure_mode; }
void set_pressure_mode (PressureMode);
PBD::Signal1<void,PressureMode> PressureModeChange;
-
+
+ libusb_device_handle* usb_handle() const { return handle; }
+
private:
libusb_device_handle *handle;
- uint8_t frame_header[16];
- uint16_t* device_frame_buffer;
- int device_buffer;
- Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
- sigc::connection vblank_connection;
- sigc::connection periodic_connection;
-
ModifierState _modifier_state;
- static const int pixels_per_row;
-
void do_request (Push2Request*);
int stop ();
int open ();
int close ();
- bool redraw ();
- int blit_to_device_frame_buffer ();
- bool vblank ();
void relax () {}
@@ -431,6 +413,8 @@ class Push2 : public ARDOUR::ControlProtocol
void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
+
+ sigc::connection periodic_connection;
bool periodic ();
void thread_init ();
@@ -517,13 +501,16 @@ class Push2 : public ARDOUR::ControlProtocol
boost::shared_ptr<ARDOUR::Stripable> master;
boost::shared_ptr<ARDOUR::Stripable> monitor;
- /* Cairo graphics context */
-
- Cairo::RefPtr<Cairo::Context> context;
+ sigc::connection vblank_connection;
+ bool vblank ();
void splash ();
ARDOUR::microseconds_t splash_start;
+ /* the canvas */
+
+ Push2Canvas* _canvas;
+
/* Layouts */
mutable Glib::Threads::Mutex layout_lock;
diff --git a/libs/surfaces/push2/scale.cc b/libs/surfaces/push2/scale.cc
index 8f04b22635..97b59220c3 100644
--- a/libs/surfaces/push2/scale.cc
+++ b/libs/surfaces/push2/scale.cc
@@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <cairomm/region.h>
#include <pangomm/layout.h>
#include "pbd/compose.h"
@@ -51,37 +52,26 @@ using namespace std;
using namespace PBD;
using namespace Glib;
using namespace ArdourSurface;
+using namespace ArdourCanvas;
-ScaleLayout::ScaleLayout (Push2& p, Session& s, Cairo::RefPtr<Cairo::Context> context)
+ScaleLayout::ScaleLayout (Push2& p, Session& s)
: Push2Layout (p, s)
{
- build_scale_menu (context);
+ build_scale_menu ();
}
ScaleLayout::~ScaleLayout ()
{
}
-bool
-ScaleLayout::redraw (Cairo::RefPtr<Cairo::Context> context, bool force) const
+void
+ScaleLayout::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
{
- bool draw = false;
-
- if (scale_menu->dirty()) {
- draw = true;
- }
-
- if (!draw) {
- return false;
- }
-
context->set_source_rgb (0.764, 0.882, 0.882);
context->rectangle (0, 0, 960, 160);
context->fill ();
- scale_menu->redraw (context, force);
-
- return true;
+ scale_menu->render (area, context);
}
void
@@ -109,11 +99,11 @@ ScaleLayout::strip_vpot_touch (int, bool)
}
void
-ScaleLayout::build_scale_menu (Cairo::RefPtr<Cairo::Context> context)
+ScaleLayout::build_scale_menu ()
{
vector<string> v;
- scale_menu = new Push2Menu (context);
+ scale_menu = new Push2Menu (this);
v.push_back ("Dorian");
v.push_back ("IonianMajor");
diff --git a/libs/surfaces/push2/scale.h b/libs/surfaces/push2/scale.h
index 6df6abf921..7d7b1f870a 100644
--- a/libs/surfaces/push2/scale.h
+++ b/libs/surfaces/push2/scale.h
@@ -30,10 +30,10 @@ namespace ArdourSurface {
class ScaleLayout : public Push2Layout
{
public:
- ScaleLayout (Push2& p, ARDOUR::Session&, Cairo::RefPtr<Cairo::Context>);
+ ScaleLayout (Push2& p, ARDOUR::Session&);
~ScaleLayout ();
- bool redraw (Cairo::RefPtr<Cairo::Context>, bool force) const;
+ void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
void button_upper (uint32_t n);
void button_lower (uint32_t n);
@@ -43,7 +43,7 @@ class ScaleLayout : public Push2Layout
private:
Push2Menu* scale_menu;
- void build_scale_menu (Cairo::RefPtr<Cairo::Context>);
+ void build_scale_menu ();
};
} /* namespace */
diff --git a/libs/surfaces/push2/splash.cc b/libs/surfaces/push2/splash.cc
new file mode 100644
index 0000000000..d03205e3a6
--- /dev/null
+++ b/libs/surfaces/push2/splash.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2016 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.
+*/
+
+#include <pangomm/layout.h>
+
+#include "pbd/compose.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/file_utils.h"
+#include "pbd/i18n.h"
+#include "pbd/search_path.h"
+
+#include "ardour/filesystem_paths.h"
+
+#include "splash.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+using namespace ArdourSurface;
+using namespace ArdourCanvas;
+
+SplashLayout::SplashLayout (Push2& p, Session& s)
+ : Push2Layout (p, s)
+{
+ std::string splash_file;
+
+ Searchpath rc (ARDOUR::ardour_data_search_path());
+ rc.add_subdirectory_to_paths ("resources");
+
+ if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
+ cerr << "Cannot find splash screen image file\n";
+ throw failed_constructor();
+ }
+
+ img = Cairo::ImageSurface::create_from_png (splash_file);
+}
+
+void
+SplashLayout::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
+{
+ int rows = display_height ();
+ int cols = display_width ();
+
+ double x_ratio = (double) img->get_width() / (cols - 20);
+ double y_ratio = (double) img->get_height() / (rows - 20);
+ double scale = min (x_ratio, y_ratio);
+
+ /* background */
+
+ context->set_source_rgb (0.764, 0.882, 0.882);
+ context->paint ();
+
+ /* image */
+
+ context->save ();
+ context->translate (5, 5);
+ context->scale (scale, scale);
+ context->set_source (img, 0, 0);
+ context->paint ();
+ context->restore ();
+
+ /* text */
+
+ Glib::RefPtr<Pango::Layout> some_text = Pango::Layout::create (context);
+
+ Pango::FontDescription fd ("Sans 38");
+ some_text->set_font_description (fd);
+ some_text->set_text (string_compose ("%1 %2", PROGRAM_NAME, VERSIONSTRING));
+
+ context->move_to (200, 10);
+ context->set_source_rgb (0, 0, 0);
+ some_text->update_from_cairo_context (context);
+ some_text->show_in_cairo_context (context);
+
+ Pango::FontDescription fd2 ("Sans Italic 18");
+ some_text->set_font_description (fd2);
+ some_text->set_text (_("Ableton Push 2 Support"));
+
+ context->move_to (200, 80);
+ context->set_source_rgb (0, 0, 0);
+ some_text->update_from_cairo_context (context);
+ some_text->show_in_cairo_context (context);
+}
diff --git a/libs/surfaces/push2/splash.h b/libs/surfaces/push2/splash.h
new file mode 100644
index 0000000000..c58a383f52
--- /dev/null
+++ b/libs/surfaces/push2/splash.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2016 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.
+*/
+
+#ifndef __ardour_push2_splash_h__
+#define __ardour_push2_splash_h__
+
+#include <cairomm/surface.h>
+
+#include "layout.h"
+#include "push2.h"
+
+namespace ARDOUR {
+ class Stripable;
+}
+
+namespace ArdourSurface {
+
+class SplashLayout : public Push2Layout
+{
+ public:
+ SplashLayout (Push2& p, ARDOUR::Session&);
+ ~SplashLayout ();
+
+ void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
+
+ private:
+ Cairo::RefPtr<Cairo::ImageSurface> img;
+};
+
+} /* namespace */
+
+#endif /* __ardour_push2_splash_h__ */
diff --git a/libs/surfaces/push2/track_mix.cc b/libs/surfaces/push2/track_mix.cc
index f313435635..cdb1bacd95 100644
--- a/libs/surfaces/push2/track_mix.cc
+++ b/libs/surfaces/push2/track_mix.cc
@@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <cairomm/region.h>
#include <pangomm/layout.h>
#include "pbd/compose.h"
@@ -23,6 +24,7 @@
#include "pbd/debug.h"
#include "pbd/failed_constructor.h"
#include "pbd/file_utils.h"
+#include "pbd/i18n.h"
#include "pbd/search_path.h"
#include "pbd/enumwriter.h"
@@ -43,70 +45,77 @@
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/rgb_macros.h"
+#include "canvas.h"
#include "knob.h"
#include "menu.h"
#include "push2.h"
#include "track_mix.h"
#include "utils.h"
-#include "pbd/i18n.h"
-
using namespace ARDOUR;
using namespace std;
using namespace PBD;
using namespace Glib;
using namespace ArdourSurface;
+using namespace ArdourCanvas;
-TrackMixLayout::TrackMixLayout (Push2& p, Session& s, Cairo::RefPtr<Cairo::Context> context)
+TrackMixLayout::TrackMixLayout (Push2& p, Session& s)
: Push2Layout (p, s)
- , _dirty (true)
{
Pango::FontDescription fd2 ("Sans 10");
for (int n = 0; n < 8; ++n) {
- upper_layout[n] = Pango::Layout::create (context);
- upper_layout[n]->set_font_description (fd2);
+ Text* t = new Text (this);
+ t->set_font_description (fd2);
+ t->set_color (p2.get_color (Push2::ParameterName));
+ t->set_position ( Duple (10 + (n*Push2Canvas::inter_button_spacing()), 2));
+
+ upper_text.push_back (t);
- lower_layout[n] = Pango::Layout::create (context);
- lower_layout[n]->set_font_description (fd2);
+ t = new Text (this);
+ t->set_font_description (fd2);
+ t->set_color (p2.get_color (Push2::ParameterName));
+ t->set_position (Duple (10 + (n*Push2Canvas::inter_button_spacing()), 140));
+
+ lower_text.push_back (t);
switch (n) {
case 0:
- upper_layout[n]->set_text (_("TRACK VOLUME"));
- lower_layout[n]->set_text (_("MUTE"));
+ upper_text[n]->set (_("TRACK VOLUME"));
+ lower_text[n]->set (_("MUTE"));
break;
case 1:
- upper_layout[n]->set_text (_("TRACK PAN"));
- lower_layout[n]->set_text (_("SOLO"));
+ upper_text[n]->set (_("TRACK PAN"));
+ lower_text[n]->set (_("SOLO"));
break;
case 2:
- upper_layout[n]->set_text (_("TRACK WIDTH"));
- lower_layout[n]->set_text (_("REC-ENABLE"));
+ upper_text[n]->set (_("TRACK WIDTH"));
+ lower_text[n]->set (_("REC-ENABLE"));
break;
case 3:
- upper_layout[n]->set_text (_("TRACK TRIM"));
- lower_layout[n]->set_text (_("IN"));
+ upper_text[n]->set (_("TRACK TRIM"));
+ lower_text[n]->set (_("IN"));
break;
case 4:
- upper_layout[n]->set_text (_(""));
- lower_layout[n]->set_text (_("DISK"));
+ upper_text[n]->set (_(""));
+ lower_text[n]->set (_("DISK"));
break;
case 5:
- upper_layout[n]->set_text (_(""));
- lower_layout[n]->set_text (_("SOLO ISO"));
+ upper_text[n]->set (_(""));
+ lower_text[n]->set (_("SOLO ISO"));
break;
case 6:
- upper_layout[n]->set_text (_(""));
- lower_layout[n]->set_text (_("SOLO LOCK"));
+ upper_text[n]->set (_(""));
+ lower_text[n]->set (_("SOLO LOCK"));
break;
case 7:
- upper_layout[n]->set_text (_(""));
- lower_layout[n]->set_text (_(""));
+ upper_text[n]->set (_(""));
+ lower_text[n]->set (_(""));
break;
}
- knobs[n] = new Push2Knob (p2, context);
- knobs[n]->set_position (60 + (120*n), 95);
+ knobs[n] = new Push2Knob (p2, this);
+ knobs[n]->set_position (60 + (Push2Canvas::inter_button_spacing()*n), 95);
knobs[n]->set_radius (25);
}
@@ -129,62 +138,24 @@ TrackMixLayout::selection_changed ()
}
}
void
-TrackMixLayout::on_show ()
+TrackMixLayout::show ()
{
selection_changed ();
}
-bool
-TrackMixLayout::redraw (Cairo::RefPtr<Cairo::Context> context, bool force) const
+void
+TrackMixLayout::render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
{
- bool children_dirty = false;
-
- for (int n = 0; n < 8; ++n) {
- if (knobs[n]->dirty()) {
- children_dirty = true;
- break;
- }
- }
-
- if (!children_dirty) {
- return false;
- }
-
set_source_rgb (context, p2.get_color (Push2::DarkBackground));
- context->rectangle (0, 0, p2.cols, p2.rows);
+ context->rectangle (0, 0, display_width(), display_height());
context->fill ();
- for (int n = 0; n < 8; ++n) {
-
- if (!upper_layout[n]->get_text().empty()) {
-
- /* Draw highlight box */
-
- uint32_t color = p2.get_color (Push2::ParameterName);
- set_source_rgb (context, color);
-
- context->move_to (10 + (n*120), 2);
- upper_layout[n]->update_from_cairo_context (context);
- upper_layout[n]->show_in_cairo_context (context);
- }
-
- if (!lower_layout[n]->get_text().empty()) {
- context->move_to (10 + (n*120), 140);
- lower_layout[n]->update_from_cairo_context (context);
- lower_layout[n]->show_in_cairo_context (context);
- }
- }
-
context->move_to (0, 22.5);
- context->line_to (p2.cols, 22.5);
+ context->line_to (display_width(), 22.5);
context->set_line_width (1.0);
context->stroke ();
- for (int n = 0; n < 8; ++n) {
- knobs[n]->redraw (context, force);
- }
-
- return true;
+ Container::render_children (area, context);
}
void
diff --git a/libs/surfaces/push2/track_mix.h b/libs/surfaces/push2/track_mix.h
index 102b9940da..e2f3d8707c 100644
--- a/libs/surfaces/push2/track_mix.h
+++ b/libs/surfaces/push2/track_mix.h
@@ -27,6 +27,10 @@ namespace ARDOUR {
class Stripable;
}
+namespace ArdourCanvas {
+ class Text;
+}
+
namespace ArdourSurface {
class Push2Knob;
@@ -34,13 +38,14 @@ class Push2Knob;
class TrackMixLayout : public Push2Layout
{
public:
- TrackMixLayout (Push2& p, ARDOUR::Session&, Cairo::RefPtr<Cairo::Context>);
+ TrackMixLayout (Push2& p, ARDOUR::Session&);
~TrackMixLayout ();
void set_stripable (boost::shared_ptr<ARDOUR::Stripable>);
- bool redraw (Cairo::RefPtr<Cairo::Context>, bool force) const;
- void on_show ();
+ void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
+
+ void show ();
void button_upper (uint32_t n);
void button_lower (uint32_t n);
@@ -53,8 +58,8 @@ class TrackMixLayout : public Push2Layout
PBD::ScopedConnectionList stripable_connections;
bool _dirty;
- Glib::RefPtr<Pango::Layout> upper_layout[8];
- Glib::RefPtr<Pango::Layout> lower_layout[8];
+ std::vector<ArdourCanvas::Text*> upper_text;
+ std::vector<ArdourCanvas::Text*> lower_text;
Push2Knob* knobs[8];
diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript
index 0f1b1c3b7d..07f095ed82 100644
--- a/libs/surfaces/push2/wscript
+++ b/libs/surfaces/push2/wscript
@@ -22,6 +22,7 @@ def build(bld):
obj.source = '''
push2.cc
buttons.cc
+ canvas.cc
interface.cc
midi_byte_array.cc
leds.cc
@@ -32,6 +33,7 @@ def build(bld):
menu.cc
mix.cc
scale.cc
+ splash.cc
track_mix.cc
utils.cc
'''