Skeleton for NI Maschine2 Surface
[ardour.git] / libs / surfaces / maschine2 / canvas.cc
1 /*
2  * Copyright (C) 2016 Paul Davis
3  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <vector>
21
22 #include <cairomm/region.h>
23 #include <cairomm/surface.h>
24 #include <cairomm/context.h>
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/i18n.h"
29
30 #include "canvas.h"
31 #include "layout.h"
32
33 #include "maschine2.h"
34 #include "m2device.h"
35
36 #ifdef __APPLE__
37 #define Rect ArdourCanvas::Rect
38 #endif
39
40 using namespace ArdourCanvas;
41 using namespace ArdourSurface;
42 using namespace PBD;
43
44 Maschine2Canvas::Maschine2Canvas (Maschine2&m, M2Device* hw)
45         : m2 (m)
46 {
47         context = Cairo::Context::create (hw->surface ());
48         expose_region = Cairo::Region::create ();
49         _width = hw->surface ()->get_width ();
50         _height = hw->surface ()->get_height ();
51
52         hw->vblank.connect_same_thread (vblank_connections, boost::bind (&Maschine2Canvas::expose, this));
53 }
54
55 Maschine2Canvas::~Maschine2Canvas ()
56 {
57 }
58
59 void
60 Maschine2Canvas::request_redraw ()
61 {
62         request_redraw (Rect (0, 0, _width, _height));
63 }
64
65 void
66 Maschine2Canvas::request_redraw (Rect const & r)
67 {
68         Cairo::RectangleInt cr;
69
70         cr.x = r.x0;
71         cr.y = r.y0;
72         cr.width = r.width();
73         cr.height = r.height();
74
75         expose_region->do_union (cr);
76
77         /* next vblank will redraw */
78 }
79
80 bool
81 Maschine2Canvas::expose ()
82 {
83         if (expose_region->empty()) {
84                 return false; /* nothing drawn */
85         }
86
87         /* set up clipping */
88
89         const int nrects = expose_region->get_num_rectangles ();
90
91         for (int n = 0; n < nrects; ++n) {
92                 Cairo::RectangleInt r = expose_region->get_rectangle (n);
93                 context->rectangle (r.x, r.y, r.width, r.height);
94         }
95
96         context->clip ();
97
98         Maschine2Layout* layout = m2.current_layout();
99
100         if (layout) {
101                 /* all layouts cover (at least) the full size of the video
102                    display, so we do not need to check if the layout intersects
103                    the bounding box of the full expose region.
104                 */
105                 Cairo::RectangleInt r = expose_region->get_extents();
106                 Rect rr (r.x, r.y, r.x + r.width, r.y + r.height);
107                 layout->render (Rect (r.x, r.y, r.x + r.width, r.y + r.height), context);
108         }
109
110         context->reset_clip ();
111
112         /* why is there no "reset()" method for Cairo::Region? */
113         expose_region = Cairo::Region::create ();
114         return true;
115 }
116
117 void
118 Maschine2Canvas::request_size (Duple)
119 {
120         /* fixed size canvas */
121 }
122
123 Rect
124 Maschine2Canvas::visible_area () const
125 {
126         /* may need to get more sophisticated once we do scrolling */
127         return Rect (0, 0, _width, _height);
128 }
129
130 Glib::RefPtr<Pango::Context>
131 Maschine2Canvas::get_pango_context ()
132 {
133         if (!pango_context) {
134                 PangoFontMap* map = pango_cairo_font_map_get_default ();
135                 if (!map) {
136                         error << _("Default Cairo font map is null!") << endmsg;
137                         return Glib::RefPtr<Pango::Context> ();
138                 }
139
140                 PangoContext* context = pango_font_map_create_context (map);
141
142                 if (!context) {
143                         error << _("cannot create new PangoContext from cairo font map") << endmsg;
144                         return Glib::RefPtr<Pango::Context> ();
145                 }
146
147                 pango_context = Glib::wrap (context);
148         }
149
150         return pango_context;
151 }