comparison DPF-Prymula-audioplugins/dpf/dgl/src/Cairo.cpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 /*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
4 * Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any purpose with
7 * or without fee is hereby granted, provided that the above copyright notice and this
8 * permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
11 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
12 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifdef _MSC_VER
19 // instantiated template classes whose methods are defined elsewhere
20 # pragma warning(disable:4661)
21 #endif
22
23 #include "../Cairo.hpp"
24 #include "../Color.hpp"
25 #include "../ImageBaseWidgets.hpp"
26
27 #include "SubWidgetPrivateData.hpp"
28 #include "TopLevelWidgetPrivateData.hpp"
29 #include "WidgetPrivateData.hpp"
30 #include "WindowPrivateData.hpp"
31
32 // templated classes
33 #include "ImageBaseWidgets.cpp"
34
35 START_NAMESPACE_DGL
36
37 // -----------------------------------------------------------------------
38
39 static void notImplemented(const char* const name)
40 {
41 d_stderr2("cairo function not implemented: %s", name);
42 }
43
44 // -----------------------------------------------------------------------
45 // Color
46
47 void Color::setFor(const GraphicsContext& context, const bool includeAlpha)
48 {
49 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
50
51 if (includeAlpha)
52 cairo_set_source_rgba(handle, red, green, blue, alpha);
53 else
54 cairo_set_source_rgb(handle, red, green, blue);
55 }
56
57 // -----------------------------------------------------------------------
58 // Line
59
60 template<typename T>
61 void Line<T>::draw(const GraphicsContext& context, const T width)
62 {
63 DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,);
64 DISTRHO_SAFE_ASSERT_RETURN(width != 0,);
65
66 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
67
68 cairo_set_line_width(handle, width);
69 cairo_move_to(handle, posStart.getX(), posStart.getY());
70 cairo_line_to(handle, posEnd.getX(), posEnd.getY());
71 cairo_stroke(handle);
72 }
73
74 template<typename T>
75 void Line<T>::draw()
76 {
77 notImplemented("Line::draw");
78 }
79
80 template class Line<double>;
81 template class Line<float>;
82 template class Line<int>;
83 template class Line<uint>;
84 template class Line<short>;
85 template class Line<ushort>;
86
87 // -----------------------------------------------------------------------
88 // Circle
89
90 template<typename T>
91 static void drawCircle(cairo_t* const handle,
92 const Point<T>& pos,
93 const uint numSegments,
94 const float size,
95 const float sin,
96 const float cos,
97 const bool outline)
98 {
99 DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,);
100
101 const T origx = pos.getX();
102 const T origy = pos.getY();
103 double t, x = size, y = 0.0;
104
105 // TODO use arc
106 /*
107 cairo_arc(handle, origx, origy, size, sin, cos);
108 */
109
110 cairo_move_to(handle, x + origx, y + origy);
111
112 for (uint i=1; i<numSegments; ++i)
113 {
114 cairo_line_to(handle, x + origx, y + origy);
115
116 t = x;
117 x = cos * x - sin * y;
118 y = sin * t + cos * y;
119 }
120
121 cairo_line_to(handle, x + origx, y + origy);
122
123 if (outline)
124 cairo_stroke(handle);
125 else
126 cairo_fill(handle);
127 }
128
129 template<typename T>
130 void Circle<T>::draw(const GraphicsContext& context)
131 {
132 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
133
134 drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, false);
135 }
136
137 template<typename T>
138 void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
139 {
140 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
141
142 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
143
144 cairo_set_line_width(handle, lineWidth);
145 drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, true);
146 }
147
148 template<typename T>
149 void Circle<T>::draw()
150 {
151 notImplemented("Circle::draw");
152 }
153
154 template<typename T>
155 void Circle<T>::drawOutline()
156 {
157 notImplemented("Circle::drawOutline");
158 }
159
160 template class Circle<double>;
161 template class Circle<float>;
162 template class Circle<int>;
163 template class Circle<uint>;
164 template class Circle<short>;
165 template class Circle<ushort>;
166
167 // -----------------------------------------------------------------------
168 // Triangle
169
170 template<typename T>
171 static void drawTriangle(cairo_t* const handle,
172 const Point<T>& pos1,
173 const Point<T>& pos2,
174 const Point<T>& pos3,
175 const bool outline)
176 {
177 DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,);
178
179 cairo_move_to(handle, pos1.getX(), pos1.getY());
180 cairo_line_to(handle, pos2.getX(), pos2.getY());
181 cairo_line_to(handle, pos3.getX(), pos3.getY());
182 cairo_line_to(handle, pos1.getX(), pos1.getY());
183
184 if (outline)
185 cairo_stroke(handle);
186 else
187 cairo_fill(handle);
188 }
189
190 template<typename T>
191 void Triangle<T>::draw(const GraphicsContext& context)
192 {
193 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
194
195 drawTriangle<T>(handle, pos1, pos2, pos3, false);
196 }
197
198 template<typename T>
199 void Triangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
200 {
201 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
202
203 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
204
205 cairo_set_line_width(handle, lineWidth);
206 drawTriangle<T>(handle, pos1, pos2, pos3, true);
207 }
208
209 template<typename T>
210 void Triangle<T>::draw()
211 {
212 notImplemented("Triangle::draw");
213 }
214
215 template<typename T>
216 void Triangle<T>::drawOutline()
217 {
218 notImplemented("Triangle::drawOutline");
219 }
220
221 template class Triangle<double>;
222 template class Triangle<float>;
223 template class Triangle<int>;
224 template class Triangle<uint>;
225 template class Triangle<short>;
226 template class Triangle<ushort>;
227
228 // -----------------------------------------------------------------------
229 // Rectangle
230
231 template<typename T>
232 static void drawRectangle(cairo_t* const handle, const Rectangle<T>& rect, const bool outline)
233 {
234 cairo_rectangle(handle, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
235
236 if (outline)
237 cairo_stroke(handle);
238 else
239 cairo_fill(handle);
240 }
241
242 template<typename T>
243 void Rectangle<T>::draw(const GraphicsContext& context)
244 {
245 DISTRHO_SAFE_ASSERT_RETURN(isValid(),);
246
247 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
248
249 drawRectangle(handle, *this, false);
250 }
251
252 template<typename T>
253 void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth)
254 {
255 DISTRHO_SAFE_ASSERT_RETURN(isValid(),);
256 DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,);
257
258 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
259
260 cairo_set_line_width(handle, lineWidth);
261 drawRectangle(handle, *this, true);
262 }
263
264 template<typename T>
265 void Rectangle<T>::draw()
266 {
267 notImplemented("Rectangle::draw");
268 }
269
270 template<typename T>
271 void Rectangle<T>::drawOutline()
272 {
273 notImplemented("Rectangle::drawOutline");
274 }
275
276 template class Rectangle<double>;
277 template class Rectangle<float>;
278 template class Rectangle<int>;
279 template class Rectangle<uint>;
280 template class Rectangle<short>;
281 template class Rectangle<ushort>;
282
283 // -----------------------------------------------------------------------
284 // CairoImage
285
286 static cairo_format_t asCairoImageFormat(const ImageFormat format) noexcept
287 {
288 switch (format)
289 {
290 case kImageFormatNull:
291 break;
292 case kImageFormatGrayscale:
293 return CAIRO_FORMAT_A8;
294 case kImageFormatBGR:
295 case kImageFormatRGB:
296 return CAIRO_FORMAT_RGB24;
297 case kImageFormatBGRA:
298 case kImageFormatRGBA:
299 return CAIRO_FORMAT_ARGB32;
300 }
301
302 return CAIRO_FORMAT_INVALID;
303 }
304
305 /*
306 static ImageFormat asCairoImageFormat(const cairo_format_t format) noexcept
307 {
308 switch (format)
309 {
310 case CAIRO_FORMAT_INVALID:
311 break;
312 case CAIRO_FORMAT_ARGB32:
313 break;
314 case CAIRO_FORMAT_RGB24:
315 break;
316 case CAIRO_FORMAT_A8:
317 break;
318 case CAIRO_FORMAT_A1:
319 break;
320 case CAIRO_FORMAT_RGB16_565:
321 break;
322 case CAIRO_FORMAT_RGB30:
323 break;
324 }
325
326 return kImageFormatNull;
327 }
328 */
329
330 CairoImage::CairoImage()
331 : ImageBase(),
332 surface(nullptr),
333 surfacedata(nullptr),
334 datarefcount(nullptr) {}
335
336 CairoImage::CairoImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt)
337 : ImageBase(rdata, w, h, fmt),
338 surface(nullptr),
339 surfacedata(nullptr),
340 datarefcount(nullptr)
341 {
342 loadFromMemory(rdata, w, h, fmt);
343 }
344
345 CairoImage::CairoImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt)
346 : ImageBase(rdata, s, fmt),
347 surface(nullptr),
348 surfacedata(nullptr),
349 datarefcount(nullptr)
350 {
351 loadFromMemory(rdata, s, fmt);
352 }
353
354 CairoImage::CairoImage(const CairoImage& image)
355 : ImageBase(image.rawData, image.size, image.format),
356 surface(cairo_surface_reference(image.surface)),
357 surfacedata(image.surfacedata),
358 datarefcount(image.datarefcount)
359 {
360 if (datarefcount != nullptr)
361 ++(*datarefcount);
362 }
363
364 CairoImage::~CairoImage()
365 {
366 cairo_surface_destroy(surface);
367
368 if (datarefcount != nullptr && --(*datarefcount) == 0)
369 {
370 std::free(surfacedata);
371 std::free(datarefcount);
372 }
373 }
374
375 void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept
376 {
377 const cairo_format_t cairoformat = asCairoImageFormat(fmt);
378 const int width = static_cast<int>(s.getWidth());
379 const int height = static_cast<int>(s.getHeight());
380 const int stride = cairo_format_stride_for_width(cairoformat, width);
381
382 uchar* const newdata = (uchar*)std::malloc(static_cast<size_t>(width * height * stride * 4));
383 DISTRHO_SAFE_ASSERT_RETURN(newdata != nullptr,);
384
385 cairo_surface_t* const newsurface = cairo_image_surface_create_for_data(newdata, cairoformat, width, height, stride);
386 DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);
387 DISTRHO_SAFE_ASSERT_RETURN(static_cast<int>(s.getWidth()) == cairo_image_surface_get_width(newsurface),);
388 DISTRHO_SAFE_ASSERT_RETURN(static_cast<int>(s.getHeight()) == cairo_image_surface_get_height(newsurface),);
389
390 cairo_surface_destroy(surface);
391
392 if (datarefcount != nullptr && --(*datarefcount) == 0)
393 std::free(surfacedata);
394 else
395 datarefcount = (int*)malloc(sizeof(*datarefcount));
396
397 surface = newsurface;
398 surfacedata = newdata;
399 *datarefcount = 1;
400
401 switch (fmt)
402 {
403 case kImageFormatNull:
404 break;
405 case kImageFormatGrayscale:
406 // Grayscale to A8
407 // TODO
408 break;
409 case kImageFormatBGR:
410 // BGR8 to CAIRO_FORMAT_RGB24
411 for (int h = 0; h < height; ++h)
412 {
413 for (int w = 0; w < width; ++w)
414 {
415 newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*3+w*3+0]);
416 newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*3+w*3+1]);
417 newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*3+w*3+2]);
418 newdata[h*width*4+w*4+3] = 0;
419 }
420 }
421 break;
422 case kImageFormatBGRA:
423 // BGRA8 to CAIRO_FORMAT_ARGB32
424 // FIXME something is wrong here...
425 for (int h = 0, t; h < height; ++h)
426 {
427 for (int w = 0; w < width; ++w)
428 {
429 if ((t = rdata[h*width*4+w*4+3]) != 0)
430 {
431 newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*4+w*4+0]);
432 newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*4+w*4+1]);
433 newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*4+w*4+2]);
434 newdata[h*width*4+w*4+3] = static_cast<uchar>(t);
435 }
436 else
437 {
438 // make all pixels zero, cairo does not render full transparency otherwise
439 memset(&newdata[h*width*4+w*4], 0, 4);
440 }
441 }
442 }
443 break;
444 case kImageFormatRGB:
445 // RGB8 to CAIRO_FORMAT_RGB24
446 // TODO
447 break;
448 case kImageFormatRGBA:
449 // RGBA8 to CAIRO_FORMAT_ARGB32
450 // TODO
451 break;
452 }
453
454 ImageBase::loadFromMemory(rdata, s, fmt);
455 }
456
457 // const GraphicsContext& context
458 void CairoImage::loadFromPNG(const char* const pngData, const uint pngSize) noexcept
459 {
460 struct PngReaderData
461 {
462 const char* dataPtr;
463 uint sizeLeft;
464
465 static cairo_status_t read(void* const closure, uchar* const data, const uint length) noexcept
466 {
467 PngReaderData& readerData = *reinterpret_cast<PngReaderData*>(closure);
468
469 if (readerData.sizeLeft < length)
470 return CAIRO_STATUS_READ_ERROR;
471
472 std::memcpy(data, readerData.dataPtr, length);
473 readerData.dataPtr += length;
474 readerData.sizeLeft -= length;
475 return CAIRO_STATUS_SUCCESS;
476 }
477 };
478
479 PngReaderData readerData;
480 readerData.dataPtr = pngData;
481 readerData.sizeLeft = pngSize;
482
483 cairo_surface_t* const newsurface = cairo_image_surface_create_from_png_stream(PngReaderData::read, &readerData);
484 DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);
485
486 const int newwidth = cairo_image_surface_get_width(newsurface);
487 const int newheight = cairo_image_surface_get_height(newsurface);
488 DISTRHO_SAFE_ASSERT_INT_RETURN(newwidth > 0, newwidth,);
489 DISTRHO_SAFE_ASSERT_INT_RETURN(newheight > 0, newheight,);
490
491 cairo_surface_destroy(surface);
492
493 if (datarefcount != nullptr && --(*datarefcount) == 0)
494 std::free(surfacedata);
495 else
496 datarefcount = (int*)malloc(sizeof(*datarefcount));
497
498 surface = newsurface;
499 surfacedata = nullptr; // cairo_image_surface_get_data(newsurface);
500 *datarefcount = 1;
501
502 rawData = nullptr;
503 format = kImageFormatNull; // asCairoImageFormat(cairo_image_surface_get_format(newsurface));
504 size = Size<uint>(static_cast<uint>(newwidth), static_cast<uint>(newheight));
505 }
506
507 void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos)
508 {
509 if (surface == nullptr)
510 return;
511
512 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
513
514 cairo_set_source_surface(handle, surface, pos.getX(), pos.getY());
515 cairo_paint(handle);
516 }
517
518 CairoImage& CairoImage::operator=(const CairoImage& image) noexcept
519 {
520 cairo_surface_t* newsurface = cairo_surface_reference(image.surface);
521 cairo_surface_destroy(surface);
522
523 if (datarefcount != nullptr && --(*datarefcount) == 0)
524 {
525 std::free(surfacedata);
526 std::free(datarefcount);
527 }
528
529 surface = newsurface;
530 rawData = image.rawData;
531 size = image.size;
532 format = image.format;
533 surfacedata = image.surfacedata;
534 datarefcount = image.datarefcount;
535
536 if (datarefcount != nullptr)
537 ++(*datarefcount);
538
539 return *this;
540 }
541
542 // -----------------------------------------------------------------------
543 // CairoSubWidget
544
545 template <>
546 CairoBaseWidget<SubWidget>::CairoBaseWidget(Widget* const parent)
547 : SubWidget(parent) {}
548
549 template class CairoBaseWidget<SubWidget>;
550
551 // -----------------------------------------------------------------------
552 // CairoTopLevelWidget
553
554 template <>
555 CairoBaseWidget<TopLevelWidget>::CairoBaseWidget(Window& windowToMapTo)
556 : TopLevelWidget(windowToMapTo) {}
557
558 template class CairoBaseWidget<TopLevelWidget>;
559
560 // -----------------------------------------------------------------------
561 // CairoStandaloneWindow
562
563 template <>
564 CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app)
565 : StandaloneWindow(app) {}
566
567 template <>
568 CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app, Window& parentWindow)
569 : StandaloneWindow(app, parentWindow) {}
570
571 template class CairoBaseWidget<StandaloneWindow>;
572
573 // -----------------------------------------------------------------------
574 // ImageBaseAboutWindow
575
576 #if 0
577 template <>
578 void ImageBaseAboutWindow<CairoImage>::onDisplay()
579 {
580 img.draw(getGraphicsContext());
581 }
582 #endif
583
584 template class ImageBaseAboutWindow<CairoImage>;
585
586 // -----------------------------------------------------------------------
587 // ImageBaseButton
588
589 template class ImageBaseButton<CairoImage>;
590
591 // -----------------------------------------------------------------------
592 // ImageBaseKnob
593
594 template <>
595 void ImageBaseKnob<CairoImage>::PrivateData::init()
596 {
597 alwaysRepaint = true;
598 cairoSurface = nullptr;
599 }
600
601 template <>
602 void ImageBaseKnob<CairoImage>::PrivateData::cleanup()
603 {
604 cairo_surface_destroy((cairo_surface_t*)cairoSurface);
605 cairoSurface = nullptr;
606 }
607
608 /**
609 Get the pixel size in bytes.
610 @return pixel size, or 0 if the format is unknown, or pixels are not aligned to bytes.
611 */
612 static int getBytesPerPixel(const cairo_format_t format) noexcept
613 {
614 switch (format)
615 {
616 case CAIRO_FORMAT_ARGB32:
617 case CAIRO_FORMAT_RGB24:
618 case CAIRO_FORMAT_RGB30:
619 return 4;
620 case CAIRO_FORMAT_RGB16_565:
621 return 2;
622 case CAIRO_FORMAT_A8:
623 return 1;
624 case CAIRO_FORMAT_A1:
625 return 0;
626 default:
627 DISTRHO_SAFE_ASSERT(false);
628 return 0;
629 }
630 }
631
632 static cairo_surface_t* getRegion(cairo_surface_t* origsurface, int x, int y, int width, int height) noexcept
633 {
634 const cairo_format_t format = cairo_image_surface_get_format(origsurface);
635 const int bpp = getBytesPerPixel(format);
636
637 if (bpp == 0)
638 return nullptr;
639
640 const int fullWidth = cairo_image_surface_get_width(origsurface);
641 const int fullHeight = cairo_image_surface_get_height(origsurface);
642 const int stride = cairo_image_surface_get_stride(origsurface);
643 uchar* const fullData = cairo_image_surface_get_data(origsurface);
644
645 x = (x < fullWidth) ? x : fullWidth;
646 y = (y < fullHeight) ? y : fullHeight;
647 width = (x + width < fullWidth) ? width : (fullWidth - x);
648 height = (x + height < fullHeight) ? height : (fullHeight - x);
649
650 uchar* const data = fullData + (x * bpp + y * stride);
651 return cairo_image_surface_create_for_data(data, format, width, height, stride);
652 }
653
654 template <>
655 void ImageBaseKnob<CairoImage>::onDisplay()
656 {
657 const GraphicsContext& context(getGraphicsContext());
658 cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
659 const double normValue = getNormalizedValue();
660
661 cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface;
662
663 if (! pData->isReady)
664 {
665 const int layerW = static_cast<int>(pData->imgLayerWidth);
666 const int layerH = static_cast<int>(pData->imgLayerHeight);
667 int layerNum = 0;
668
669 if (pData->rotationAngle == 0)
670 layerNum = static_cast<int>(normValue * static_cast<double>(pData->imgLayerCount - 1) + 0.5);
671
672 const int layerX = pData->isImgVertical ? 0 : layerNum * layerW;
673 const int layerY = !pData->isImgVertical ? 0 : layerNum * layerH;
674
675 cairo_surface_t* newsurface;
676
677 if (pData->rotationAngle == 0)
678 {
679 newsurface = getRegion(pData->image.getSurface(), layerX, layerY, layerW, layerH);
680 }
681 else
682 {
683 newsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layerW, layerH);
684 cairo_t* const cr = cairo_create(newsurface);
685 cairo_translate(cr, 0.5 * layerW, 0.5 * layerH);
686 cairo_rotate(cr, normValue * pData->rotationAngle * (M_PI / 180));
687 cairo_set_source_surface(cr, pData->image.getSurface(), -0.5 * layerW, -0.5 * layerH);
688 cairo_paint(cr);
689 cairo_destroy(cr);
690 }
691
692 DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);
693
694 cairo_surface_destroy(surface);
695 pData->cairoSurface = surface = newsurface;
696 pData->isReady = true;
697 }
698
699 if (surface != nullptr)
700 {
701 cairo_set_source_surface(handle, surface, 0, 0);
702 cairo_paint(handle);
703 }
704 }
705
706 template class ImageBaseKnob<CairoImage>;
707
708 // -----------------------------------------------------------------------
709 // ImageBaseSlider
710
711 template class ImageBaseSlider<CairoImage>;
712
713 // -----------------------------------------------------------------------
714 // ImageBaseSwitch
715
716 template class ImageBaseSwitch<CairoImage>;
717
718 // -----------------------------------------------------------------------
719
720 void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor)
721 {
722 cairo_t* const handle = static_cast<const CairoGraphicsContext&>(self->getGraphicsContext()).handle;
723
724 bool needsResetClip = false;
725
726 cairo_matrix_t matrix;
727 cairo_get_matrix(handle, &matrix);
728
729 if (needsViewportScaling)
730 {
731 // limit viewport to widget bounds
732 // NOTE only used for nanovg for now, which is not relevant here
733 }
734 else if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height)))
735 {
736 // full viewport size
737 cairo_translate(handle, 0, 0);
738 cairo_scale(handle, autoScaleFactor, autoScaleFactor);
739 }
740 else
741 {
742 // set viewport pos
743 cairo_translate(handle, absolutePos.getX() * autoScaleFactor, absolutePos.getY() * autoScaleFactor);
744
745 // then cut the outer bounds
746 cairo_rectangle(handle,
747 0,
748 0,
749 std::round(self->getWidth() * autoScaleFactor),
750 std::round(self->getHeight() * autoScaleFactor));
751
752 cairo_clip(handle);
753 needsResetClip = true;
754
755 // set viewport scaling
756 cairo_scale(handle, autoScaleFactor, autoScaleFactor);
757 }
758
759 // display widget
760 self->onDisplay();
761
762 if (needsResetClip)
763 cairo_reset_clip(handle);
764
765 cairo_set_matrix(handle, &matrix);
766
767 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
768 }
769
770 // -----------------------------------------------------------------------
771
772 void TopLevelWidget::PrivateData::display()
773 {
774 if (! selfw->pData->visible)
775 return;
776
777 cairo_t* const handle = static_cast<const CairoGraphicsContext&>(self->getGraphicsContext()).handle;
778
779 const Size<uint> size(window.getSize());
780 const uint width = size.getWidth();
781 const uint height = size.getHeight();
782
783 const double autoScaleFactor = window.pData->autoScaleFactor;
784
785 cairo_matrix_t matrix;
786 cairo_get_matrix(handle, &matrix);
787
788 // full viewport size
789 if (window.pData->autoScaling)
790 {
791 cairo_translate(handle, 0, 0);
792 cairo_scale(handle, autoScaleFactor, autoScaleFactor);
793 }
794 else
795 {
796 cairo_translate(handle, 0, 0);
797 cairo_scale(handle, 1.0, 1.0);
798 }
799
800 // main widget drawing
801 self->onDisplay();
802
803 cairo_set_matrix(handle, &matrix);
804
805 // now draw subwidgets if there are any
806 selfw->pData->displaySubWidgets(width, height, autoScaleFactor);
807 }
808
809 // -----------------------------------------------------------------------
810
811 void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint)
812 {
813 notImplemented("Window::PrivateData::renderToPicture");
814 }
815
816 // -----------------------------------------------------------------------
817
818 const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
819 {
820 GraphicsContext& context((GraphicsContext&)graphicsContext);
821 ((CairoGraphicsContext&)context).handle = (cairo_t*)puglGetContext(view);
822 return context;
823 }
824
825 // -----------------------------------------------------------------------
826
827 END_NAMESPACE_DGL