+}
+
+static
+void clip (wxDC& dc, wxGraphicsContext* gc, int x, int y, int w, int h)
+{
+ dc.SetClippingRegion (x, y, w, h);
+ gc->Clip (x, y, w, h);
+}
+
+static
+void translate (wxDC& dc, wxGraphicsContext* gc, int x, int y)
+{
+ gc->PushState ();
+ gc->Translate (-x, -y);
+ dc.SetLogicalOrigin (x, y);
+}
+
+static
+void restore (wxDC& dc, wxGraphicsContext* gc)
+{
+ dc.SetLogicalOrigin (0, 0);
+ gc->PopState ();
+ dc.DestroyClippingRegion ();
+ gc->ResetClip ();
+}
+
+void
+AudioMappingView::paint ()
+{
+ wxPaintDC dc (_body);
+
+ wxGraphicsContext* gc = wxGraphicsContext::Create (dc);
+ if (!gc) {
+ return;
+ }
+
+ int const hs = _horizontal_scroll->GetThumbPosition ();
+ int const vs = _vertical_scroll->GetThumbPosition ();
+
+ paint_static (dc, gc);
+
+ clip (dc, gc, LEFT_WIDTH, 0, GRID_SPACING * _output_channels.size(), GRID_SPACING * (2 + _input_channels.size()));
+ translate (dc, gc, hs, 0);
+ paint_column_labels (dc, gc);
+ restore (dc, gc);
+
+ clip (dc, gc, 0, TOP_HEIGHT, GRID_SPACING * (3 + _output_channels.size()), GRID_SPACING * _input_channels.size());
+ translate (dc, gc, 0, vs);
+ paint_row_labels (dc, gc);
+ restore (dc, gc);
+
+ clip (dc, gc, GRID_SPACING * 2, TOP_HEIGHT, GRID_SPACING * (1 + _output_channels.size()), GRID_SPACING * _input_channels.size());
+ translate (dc, gc, hs, vs);
+ paint_row_lines (gc);
+ restore (dc, gc);
+
+ clip (dc, gc, LEFT_WIDTH, GRID_SPACING, GRID_SPACING * (1 + _output_channels.size()), GRID_SPACING * _input_channels.size());
+ translate (dc, gc, hs, vs);
+ paint_column_lines (gc);
+ restore (dc, gc);
+
+ clip (dc, gc, LEFT_WIDTH, TOP_HEIGHT, GRID_SPACING * _output_channels.size(), GRID_SPACING * _input_channels.size());
+ translate (dc, gc, hs, vs);
+ paint_indicators (dc);
+ restore (dc, gc);