Browse Source

Incorporate the rest of cairo changes, CairoImageKnob works now

pull/272/head
falkTX 4 years ago
parent
commit
a4b06f3b88
17 changed files with 2862 additions and 23 deletions
  1. +17
    -1
      dgl/Cairo.hpp
  2. +179
    -4
      dgl/src/Cairo.cpp
  3. +6
    -1
      dgl/src/Common.hpp
  4. +2
    -4
      dgl/src/ImageBaseWidgets.cpp
  5. +11
    -8
      dgl/src/OpenGL.cpp
  6. +2600
    -0
      examples/CairoUI/Artwork.cpp
  7. +19
    -0
      examples/CairoUI/Artwork.hpp
  8. +1
    -0
      examples/CairoUI/CairoExamplePlugin.cpp
  9. +22
    -5
      examples/CairoUI/CairoExampleUI.cpp
  10. +1
    -0
      examples/CairoUI/DemoWidgetBanner.cpp
  11. +1
    -0
      examples/CairoUI/DemoWidgetBanner.hpp
  12. +1
    -0
      examples/CairoUI/DemoWidgetClickable.cpp
  13. +1
    -0
      examples/CairoUI/DemoWidgetClickable.hpp
  14. +1
    -0
      examples/CairoUI/Makefile
  15. BIN
      examples/CairoUI/artwork/buttonOff.png
  16. BIN
      examples/CairoUI/artwork/buttonOn.png
  17. BIN
      examples/CairoUI/artwork/knob.png

+ 17
- 1
dgl/Cairo.hpp View File

@@ -72,18 +72,34 @@ public:
~CairoImage() override; ~CairoImage() override;


/** /**
Load image data from memory.
Load raw image data from memory.
@note @a rawData must remain valid for the lifetime of this Image. @note @a rawData must remain valid for the lifetime of this Image.
*/ */
void loadFromMemory(const char* rawData, void loadFromMemory(const char* rawData,
const Size<uint>& size, const Size<uint>& size,
ImageFormat format = kImageFormatBGRA) noexcept override; ImageFormat format = kImageFormatBGRA) noexcept override;


/**
Load PNG image from memory.
Image size is read from PNG contents.
@note @a pngData must remain valid for the lifetime of this Image.
*/
void loadFromPNG(const char* pngData, uint dataSize) noexcept;

/** /**
Draw this image at position @a pos using the graphics context @a context. Draw this image at position @a pos using the graphics context @a context.
*/ */
void drawAt(const GraphicsContext& context, const Point<int>& pos) override; void drawAt(const GraphicsContext& context, const Point<int>& pos) override;


/**
Get the cairo surface currently associated with this image.
FIXME might be removed
*/
inline cairo_surface_t* getSurface() const noexcept
{
return surface;
}

/** /**
TODO document this. TODO document this.
*/ */


+ 179
- 4
dgl/src/Cairo.cpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this
@@ -275,7 +276,7 @@ template class Rectangle<ushort>;
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// CairoImage // CairoImage


static cairo_format_t asCairoImageFormat(const ImageFormat format)
static cairo_format_t asCairoImageFormat(const ImageFormat format) noexcept
{ {
switch (format) switch (format)
{ {
@@ -294,6 +295,31 @@ static cairo_format_t asCairoImageFormat(const ImageFormat format)
return CAIRO_FORMAT_INVALID; return CAIRO_FORMAT_INVALID;
} }


/*
static ImageFormat asCairoImageFormat(const cairo_format_t format) noexcept
{
switch (format)
{
case CAIRO_FORMAT_INVALID:
break;
case CAIRO_FORMAT_ARGB32:
break;
case CAIRO_FORMAT_RGB24:
break;
case CAIRO_FORMAT_A8:
break;
case CAIRO_FORMAT_A1:
break;
case CAIRO_FORMAT_RGB16_565:
break;
case CAIRO_FORMAT_RGB30:
break;
}

return kImageFormatNull;
}
*/

CairoImage::CairoImage() CairoImage::CairoImage()
: ImageBase(), : ImageBase(),
surface(nullptr), surface(nullptr),
@@ -403,6 +429,51 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, co
ImageBase::loadFromMemory(rdata, s, fmt); ImageBase::loadFromMemory(rdata, s, fmt);
} }


// const GraphicsContext& context
void CairoImage::loadFromPNG(const char* const pngData, const uint pngSize) noexcept
{
struct PngReaderData
{
const char* dataPtr;
uint sizeLeft;

static cairo_status_t read(void* const closure, uchar* const data, const uint length) noexcept
{
PngReaderData& readerData = *reinterpret_cast<PngReaderData*>(closure);

if (readerData.sizeLeft < length)
return CAIRO_STATUS_READ_ERROR;

std::memcpy(data, readerData.dataPtr, length);
readerData.dataPtr += length;
readerData.sizeLeft -= length;
return CAIRO_STATUS_SUCCESS;
}
};

PngReaderData readerData;
readerData.dataPtr = pngData;
readerData.sizeLeft = pngSize;

cairo_surface_t* const newsurface = cairo_image_surface_create_from_png_stream(PngReaderData::read, &readerData);
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);

cairo_surface_destroy(surface);

if (datarefcount != nullptr && --(*datarefcount) == 0)
std::free(surfacedata);
else
datarefcount = (int*)malloc(sizeof(*datarefcount));

surface = newsurface;
surfacedata = nullptr; // cairo_image_surface_get_data(newsurface);
*datarefcount = 1;

rawData = nullptr;
format = kImageFormatNull; // asCairoImageFormat(cairo_image_surface_get_format(newsurface));
size = Size<uint>(cairo_image_surface_get_width(newsurface), cairo_image_surface_get_height(newsurface));
}

void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos) void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos)
{ {
if (surface == nullptr) if (surface == nullptr)
@@ -418,14 +489,23 @@ CairoImage& CairoImage::operator=(const CairoImage& image) noexcept
{ {
cairo_surface_t* newsurface = cairo_surface_reference(image.surface); cairo_surface_t* newsurface = cairo_surface_reference(image.surface);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);

if (datarefcount != nullptr && --(*datarefcount) == 0)
{
std::free(surfacedata);
std::free(datarefcount);
}

surface = newsurface; surface = newsurface;
rawData = image.rawData; rawData = image.rawData;
size = image.size; size = image.size;
format = image.format; format = image.format;
surfacedata = image.surfacedata; surfacedata = image.surfacedata;
datarefcount = image.datarefcount; datarefcount = image.datarefcount;

if (datarefcount != nullptr) if (datarefcount != nullptr)
++(*datarefcount); ++(*datarefcount);

return *this; return *this;
} }


@@ -484,19 +564,114 @@ template class ImageBaseButton<CairoImage>;
template <> template <>
void ImageBaseKnob<CairoImage>::PrivateData::init() void ImageBaseKnob<CairoImage>::PrivateData::init()
{ {
notImplemented("ImageBaseKnob::PrivateData::init");
// new (&cairoDisplayImage) CairoImage();
cairoSurface = nullptr;
} }


template <> template <>
void ImageBaseKnob<CairoImage>::PrivateData::cleanup() void ImageBaseKnob<CairoImage>::PrivateData::cleanup()
{ {
notImplemented("ImageBaseKnob::PrivateData::cleanup");
// cairoDisplayImage.~CairoImage();
cairo_surface_destroy((cairo_surface_t*)cairoSurface);
cairoSurface = nullptr;
}

/**
Get the pixel size in bytes.
@return pixel size, or 0 if the format is unknown, or pixels are not aligned to bytes.
*/
static uint getBytesPerPixel(cairo_format_t format) noexcept
{
switch (format)
{
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB30:
return 4;
case CAIRO_FORMAT_RGB16_565:
return 2;
case CAIRO_FORMAT_A8:
return 1;
case CAIRO_FORMAT_A1:
return 0;
default:
DISTRHO_SAFE_ASSERT(false);
return 0;
}
}

static cairo_surface_t* getRegion(cairo_surface_t* origsurface, uint x, uint y, uint width, uint height) noexcept
{
const cairo_format_t format = cairo_image_surface_get_format(origsurface);
const uint bpp = getBytesPerPixel(format);

if (bpp == 0)
return nullptr;

const uint fullWidth = cairo_image_surface_get_width(origsurface);
const uint fullHeight = cairo_image_surface_get_height(origsurface);
const uint stride = cairo_image_surface_get_stride(origsurface);
uchar* const fullData = cairo_image_surface_get_data(origsurface);

x = (x < fullWidth) ? x : fullWidth;
y = (y < fullHeight) ? y : fullHeight;
width = (x + width < fullWidth) ? width : (fullWidth - x);
height = (x + height < fullHeight) ? height : (fullHeight - x);

uchar* const data = fullData + x * bpp + y * stride;
return cairo_image_surface_create_for_data(data, format, width, height, stride);
} }


template <> template <>
void ImageBaseKnob<CairoImage>::onDisplay() void ImageBaseKnob<CairoImage>::onDisplay()
{ {
notImplemented("ImageBaseKnob::onDisplay");
const GraphicsContext& context(getGraphicsContext());
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle;
const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum)
/ (pData->maximum - pData->minimum);

cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface;

if (! pData->isReady)
{
const uint layerW = pData->imgLayerWidth;
const uint layerH = pData->imgLayerHeight;
uint layerNum = 0;

if (pData->rotationAngle == 0)
layerNum = uint(normValue * float(pData->imgLayerCount-1));

const uint layerX = pData->isImgVertical ? 0 : layerNum * layerW;
const uint layerY = !pData->isImgVertical ? 0 : layerNum * layerH;

cairo_surface_t* const newsurface = getRegion(pData->image.getSurface(), layerX, layerY, layerW, layerH);
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,);

if (pData->rotationAngle != 0)
{
// TODO
/*
CairoImage rotated(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layerW, layerH), false);
cairo_t* cr = cairo_create(rotated.getSurface());
cairo_translate(cr, 0.5 * layerW, 0.5 * layerH);
cairo_rotate(cr, normValue * angle * (float)(M_PI / 180));
cairo_set_source_surface(cr, displayImage.getSurface(), -0.5f * layerW, -0.5f * layerH);
cairo_paint(cr);
cairo_destroy(cr);
pData->cairoDisplayImage = rotated;
*/
}

cairo_surface_destroy(surface);
pData->cairoSurface = surface = newsurface;
pData->isReady = true;
}

if (surface != nullptr)
{
cairo_set_source_surface(handle, surface, 0, 0);
cairo_paint(handle);
}
} }


template class ImageBaseKnob<CairoImage>; template class ImageBaseKnob<CairoImage>;


+ 6
- 1
dgl/src/Common.hpp View File

@@ -145,7 +145,12 @@ struct ImageBaseKnob<ImageType>::PrivateData {
uint imgLayerHeight; uint imgLayerHeight;
uint imgLayerCount; uint imgLayerCount;
bool isReady; bool isReady;
/*GL*/uint textureId;

union {
uint glTextureId;
// ImageType cairoDisplayImage;
void* cairoSurface;
};


explicit PrivateData(const ImageType& img, const Orientation o); explicit PrivateData(const ImageType& img, const Orientation o);
explicit PrivateData(PrivateData* const other); explicit PrivateData(PrivateData* const other);


+ 2
- 4
dgl/src/ImageBaseWidgets.cpp View File

@@ -208,8 +208,7 @@ ImageBaseKnob<ImageType>::PrivateData::PrivateData(const ImageType& img, const O
imgLayerWidth(isImgVertical ? img.getWidth() : img.getHeight()), imgLayerWidth(isImgVertical ? img.getWidth() : img.getHeight()),
imgLayerHeight(imgLayerWidth), imgLayerHeight(imgLayerWidth),
imgLayerCount(isImgVertical ? img.getHeight()/imgLayerHeight : img.getWidth()/imgLayerWidth), imgLayerCount(isImgVertical ? img.getHeight()/imgLayerHeight : img.getWidth()/imgLayerWidth),
isReady(false),
textureId(0)
isReady(false)
{ {
init(); init();
} }
@@ -235,8 +234,7 @@ ImageBaseKnob<ImageType>::PrivateData::PrivateData(PrivateData* const other)
imgLayerWidth(other->imgLayerWidth), imgLayerWidth(other->imgLayerWidth),
imgLayerHeight(other->imgLayerHeight), imgLayerHeight(other->imgLayerHeight),
imgLayerCount(other->imgLayerCount), imgLayerCount(other->imgLayerCount),
isReady(false),
textureId(0)
isReady(false)
{ {
init(); init();
} }


+ 11
- 8
dgl/src/OpenGL.cpp View File

@@ -460,27 +460,29 @@ template class ImageBaseButton<OpenGLImage>;
template <> template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::init() void ImageBaseKnob<OpenGLImage>::PrivateData::init()
{ {
glGenTextures(1, &textureId);
glTextureId = 0;
glGenTextures(1, &glTextureId);
} }


template <> template <>
void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup() void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup()
{ {
if (textureId != 0)
{
glDeleteTextures(1, &textureId);
textureId = 0;
}
if (glTextureId == 0)
return;
glDeleteTextures(1, &glTextureId);
glTextureId = 0;
} }


template <> template <>
void ImageBaseKnob<OpenGLImage>::onDisplay() void ImageBaseKnob<OpenGLImage>::onDisplay()
{ {
const GraphicsContext& context(getGraphicsContext()); const GraphicsContext& context(getGraphicsContext());
const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum) / (pData->maximum - pData->minimum);
const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum)
/ (pData->maximum - pData->minimum);


glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pData->textureId);
glBindTexture(GL_TEXTURE_2D, pData->glTextureId);


if (! pData->isReady) if (! pData->isReady)
{ {
@@ -505,6 +507,7 @@ void ImageBaseKnob<OpenGLImage>::onDisplay()
const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight);
const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth);


// TODO kImageFormatGreyscale
const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA ||
pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3);
/* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1));


+ 2600
- 0
examples/CairoUI/Artwork.cpp
File diff suppressed because it is too large
View File


+ 19
- 0
examples/CairoUI/Artwork.hpp View File

@@ -0,0 +1,19 @@
/* (Auto-generated binary data file). */

#ifndef BINARY_ARTWORK_HPP
#define BINARY_ARTWORK_HPP

namespace Artwork
{
extern const char* buttonOffData;
const unsigned int buttonOffDataSize = 970;

extern const char* buttonOnData;
const unsigned int buttonOnDataSize = 983;

extern const char* knobData;
const unsigned int knobDataSize = 52344;
}

#endif // BINARY_ARTWORK_HPP


+ 1
- 0
examples/CairoUI/CairoExamplePlugin.cpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this


+ 22
- 5
examples/CairoUI/CairoExampleUI.cpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this
@@ -15,6 +16,8 @@
*/ */


#include "DistrhoUI.hpp" #include "DistrhoUI.hpp"

#include "Artwork.hpp"
#include "DemoWidgetBanner.hpp" #include "DemoWidgetBanner.hpp"
#include "DemoWidgetClickable.hpp" #include "DemoWidgetClickable.hpp"


@@ -35,17 +38,29 @@ public:
fWidgetBanner = widgetBanner; fWidgetBanner = widgetBanner;
widgetBanner->setSize(180, 80); widgetBanner->setSize(180, 80);
widgetBanner->setAbsolutePos(10, 10); widgetBanner->setAbsolutePos(10, 10);
}


~CairoExampleUI()
{
CairoImage knobSkin;
knobSkin.loadFromPNG(Artwork::knobData, Artwork::knobDataSize);

CairoImageKnob* knob = new CairoImageKnob(this, knobSkin);
fKnob = knob;
knob->setSize(80, 80);
knob->setAbsolutePos(10, 100);

CairoImage buttonOn, buttonOff;
buttonOn.loadFromPNG(Artwork::buttonOnData, Artwork::buttonOnDataSize);
buttonOff.loadFromPNG(Artwork::buttonOffData, Artwork::buttonOffDataSize);

CairoImageButton* button = new CairoImageButton(this, buttonOff, buttonOn);
fButton = button;
button->setSize(60, 35);
button->setAbsolutePos(100, 160);
} }


protected: protected:
void onCairoDisplay(const CairoGraphicsContext& context) void onCairoDisplay(const CairoGraphicsContext& context)
{ {
cairo_t* cr = context.handle;

cairo_t* const cr = context.handle;
cairo_set_source_rgb(cr, 1.0, 0.8, 0.5); cairo_set_source_rgb(cr, 1.0, 0.8, 0.5);
cairo_paint(cr); cairo_paint(cr);
} }
@@ -60,6 +75,8 @@ protected:
private: private:
ScopedPointer<DemoWidgetClickable> fWidgetClickable; ScopedPointer<DemoWidgetClickable> fWidgetClickable;
ScopedPointer<DemoWidgetBanner> fWidgetBanner; ScopedPointer<DemoWidgetBanner> fWidgetBanner;
ScopedPointer<CairoImageKnob> fKnob;
ScopedPointer<CairoImageButton> fButton;
}; };


UI* createUI() UI* createUI()


+ 1
- 0
examples/CairoUI/DemoWidgetBanner.cpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this


+ 1
- 0
examples/CairoUI/DemoWidgetBanner.hpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this


+ 1
- 0
examples/CairoUI/DemoWidgetClickable.cpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this


+ 1
- 0
examples/CairoUI/DemoWidgetClickable.hpp View File

@@ -1,6 +1,7 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this * or without fee is hereby granted, provided that the above copyright notice and this


+ 1
- 0
examples/CairoUI/Makefile View File

@@ -16,6 +16,7 @@ FILES_DSP = \
CairoExamplePlugin.cpp CairoExamplePlugin.cpp


FILES_UI = \ FILES_UI = \
Artwork.cpp \
DemoWidgetBanner.cpp \ DemoWidgetBanner.cpp \
DemoWidgetClickable.cpp \ DemoWidgetClickable.cpp \
CairoExampleUI.cpp CairoExampleUI.cpp


BIN
examples/CairoUI/artwork/buttonOff.png View File

Before After
Width: 50  |  Height: 30  |  Size: 970B

BIN
examples/CairoUI/artwork/buttonOn.png View File

Before After
Width: 50  |  Height: 30  |  Size: 983B

BIN
examples/CairoUI/artwork/knob.png View File

Before After
Width: 64  |  Height: 4096  |  Size: 51KB

Loading…
Cancel
Save