@@ -9,6 +9,7 @@ | |||
.kdev_include_paths | |||
examples/app | |||
examples/cairo | |||
examples/color | |||
examples/images | |||
examples/nekobi-ui |
@@ -21,6 +21,8 @@ | |||
#include <cairo.h> | |||
#include <cstdio> | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
@@ -36,56 +38,63 @@ public: | |||
{ | |||
} | |||
protected: | |||
virtual void cairoDisplay(cairo_t* const context) = 0; | |||
private: | |||
void onReshape(int width, int height) override | |||
virtual void setWidth(int width) override | |||
{ | |||
// handle resize | |||
setSize(width, height); | |||
Widget::onReshape(width, height); | |||
if (fArea.getWidth() == width) | |||
return; | |||
// free previous if needed | |||
onClose(); | |||
Widget::setWidth(width); | |||
_recreateSurface(); | |||
} | |||
// create new | |||
fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); | |||
fContext = cairo_create(fSurface); | |||
virtual void setHeight(int height) override | |||
{ | |||
if (fArea.getHeight() == height) | |||
return; | |||
glGenTextures(1, &fTextureId); | |||
Widget::setHeight(height); | |||
_recreateSurface(); | |||
} | |||
void onClose() override | |||
virtual void setSize(const Size<int>& size) override | |||
{ | |||
if (fContext != nullptr) | |||
{ | |||
cairo_destroy(fContext); | |||
fContext = nullptr; | |||
} | |||
if (fArea.getSize() == size) | |||
return; | |||
if (fSurface != nullptr) | |||
{ | |||
cairo_surface_destroy(fSurface); | |||
fSurface = nullptr; | |||
} | |||
Widget::setSize(size); | |||
_recreateSurface(); | |||
} | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
void setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
protected: | |||
virtual void cairoDisplay(cairo_t* const context) = 0; | |||
private: | |||
void onDisplay() override | |||
{ | |||
// wait for first resize | |||
// wait for sizing | |||
if (fSurface == nullptr || fContext == nullptr) | |||
{ | |||
glClear(GL_COLOR_BUFFER_BIT); | |||
printf("invalid surface\n"); | |||
return; | |||
} | |||
if (fTextureId == 0) | |||
glGenTextures(1, &fTextureId); | |||
if (fTextureId == 0) | |||
{ | |||
// TODO: invalidate widget | |||
printf("invalid texture\n"); | |||
return; | |||
} | |||
#if 1 | |||
const int x = getX(); | |||
const int y = getY(); | |||
const int width = getWidth(); | |||
const int height = getHeight(); | |||
@@ -108,25 +117,80 @@ private: | |||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceData); | |||
// draw the texture | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
glBegin(GL_QUADS); | |||
glTexCoord2i(0, height); | |||
glVertex2i(0, height); | |||
// glBegin(GL_QUADS); | |||
// glTexCoord2f(0.0f, 0.0f); | |||
// glVertex2i(x, y); | |||
// | |||
// glTexCoord2f(1.0f, 0.0f); | |||
// glVertex2i(x+width, y); | |||
// | |||
// glTexCoord2f(1.0f, 1.0f); | |||
// glVertex2i(x+width, y+height); | |||
// | |||
// glTexCoord2f(0.0f, 1.0f); | |||
// glVertex2i(x, y+height); | |||
// glEnd(); | |||
glTexCoord2i(width, height); | |||
glVertex2i(width, height); | |||
glBegin(GL_QUADS); | |||
//glTexCoord2i(x, y); | |||
glTexCoord2i(0, 0); | |||
glVertex2i(x, y); | |||
//glTexCoord2i(x+width, y); | |||
glTexCoord2i(width, 0); | |||
glVertex2i(width, 0); | |||
glVertex2i(x+width, y); | |||
glTexCoord2i(0, 0); | |||
glVertex2i(0, 0); | |||
//glTexCoord2i(x+width, y+height); | |||
glTexCoord2i(width, height); | |||
glVertex2i(x+width, y+height); | |||
//glTexCoord2i(x, y+height); | |||
glTexCoord2i(0, height); | |||
glVertex2i(x, y+height); | |||
glEnd(); | |||
// cleanup | |||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); | |||
glDisable(GL_TEXTURE_RECTANGLE_ARB); | |||
#endif | |||
} | |||
void onClose() override | |||
{ | |||
if (fContext != nullptr) | |||
{ | |||
cairo_destroy(fContext); | |||
fContext = nullptr; | |||
} | |||
if (fSurface != nullptr) | |||
{ | |||
cairo_surface_destroy(fSurface); | |||
fSurface = nullptr; | |||
} | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
} | |||
void _recreateSurface() | |||
{ | |||
if (fContext != nullptr) | |||
cairo_destroy(fContext); | |||
if (fSurface != nullptr) | |||
cairo_surface_destroy(fSurface); | |||
fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, fArea.getWidth(), fArea.getHeight()); | |||
if (fSurface != nullptr) | |||
fContext = cairo_create(fSurface); | |||
else | |||
fContext = nullptr; | |||
} | |||
private: | |||
@@ -60,10 +60,15 @@ public: | |||
int getHeight() const noexcept; | |||
const Size<int>& getSize() const noexcept; | |||
void setWidth(int width); | |||
void setHeight(int height); | |||
void setSize(int width, int height); | |||
void setSize(const Size<int>& size); | |||
// virtual needed by cairo | |||
virtual void setWidth(int width); | |||
virtual void setHeight(int height); | |||
virtual void setSize(const Size<int>& size); | |||
void setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
const Rectangle<int>& getArea() const noexcept; | |||
@@ -90,6 +95,7 @@ private: | |||
bool fVisible; | |||
Rectangle<int> fArea; | |||
friend class CairoWidget; | |||
friend class Window; | |||
}; | |||
@@ -153,11 +153,6 @@ void Widget::setHeight(int height) | |||
fParent.repaint(); | |||
} | |||
void Widget::setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
void Widget::setSize(const Size<int>& size) | |||
{ | |||
if (fArea.getSize() == size) | |||
@@ -14,9 +14,9 @@ LINK_FLAGS += -L.. -ldgl $(DGL_LIBS) | |||
# -------------------------------------------------------------- | |||
ifeq ($(WIN32),true) | |||
TARGETS = app.exe color images.exe nekobi-ui.exe | |||
TARGETS = app.exe cairo.exe color images.exe nekobi-ui.exe | |||
else | |||
TARGETS = app color images nekobi-ui | |||
TARGETS = app cairo color images nekobi-ui | |||
endif | |||
# -------------------------------------------------------------- | |||
@@ -35,6 +35,9 @@ all: ../libdgl.a $(TARGETS) | |||
app: app.cpp ../dgl/* | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
cairo: cairo.cpp ../dgl/* | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(shell pkg-config --cflags --libs cairo) $(LINK_FLAGS) -o $@ | |||
color: color.cpp ../dgl/* | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
@@ -0,0 +1,213 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
// ------------------------------------------------------ | |||
// DGL Stuff | |||
#include "App.hpp" | |||
#include "CairoWidget.hpp" | |||
#include "Window.hpp" | |||
#include <cstdio> | |||
// ------------------------------------------------------ | |||
// use namespace | |||
using namespace DGL; | |||
// ------------------------------------------------------ | |||
// Background widget (cairo will be painted on top) | |||
class BackgroundWidget : public Widget | |||
{ | |||
public: | |||
BackgroundWidget(Window& parent) | |||
: Widget(parent) | |||
{ | |||
} | |||
private: | |||
void onDisplay() override | |||
{ | |||
int x = 0; | |||
int y = 0; | |||
int width = getWidth(); | |||
int height = getHeight(); | |||
// paint bg color (in full size) | |||
glColor3b(20, 80, 20); | |||
glBegin(GL_QUADS); | |||
glTexCoord2f(0.0f, 0.0f); | |||
glVertex2i(x, y); | |||
glTexCoord2f(1.0f, 0.0f); | |||
glVertex2i(x+width, y); | |||
glTexCoord2f(1.0f, 1.0f); | |||
glVertex2i(x+width, y+height); | |||
glTexCoord2f(0.0f, 1.0f); | |||
glVertex2i(x, y+height); | |||
glEnd(); | |||
} | |||
void onReshape(int width, int height) override | |||
{ | |||
// make this widget same size as window | |||
setSize(width, height); | |||
Widget::onReshape(width, height); | |||
} | |||
}; | |||
// ------------------------------------------------------ | |||
// Custom Cairo Widget | |||
class CustomCairoWidget : public App::IdleCallback, | |||
CairoWidget | |||
{ | |||
public: | |||
CustomCairoWidget(Window& parent) | |||
: CairoWidget(parent), | |||
value(0.0f), | |||
pressed(false) | |||
{ | |||
setSize(100, 100); | |||
} | |||
private: | |||
void idleCallback() override | |||
{ | |||
value += 0.001f; | |||
if (value > 1.0f) | |||
value = 0; | |||
repaint(); | |||
} | |||
void cairoDisplay(cairo_t* const context) override | |||
{ | |||
const int w = getWidth(); | |||
const int h = getHeight(); | |||
float radius = 40.0f; | |||
// * 0.9 for line width to remain inside redraw area | |||
if (w > h) | |||
radius = (h / 2.0f)*0.9f; | |||
else | |||
radius = (w / 2.0f)*0.9f; | |||
cairo_save(context); | |||
cairo_rectangle(context, 0, 0, w, h ); | |||
cairo_set_source_rgba(context, 1.1, 0.1, 0.1, 0 ); | |||
cairo_fill(context); | |||
cairo_set_line_join(context, CAIRO_LINE_JOIN_ROUND); | |||
cairo_set_line_cap(context, CAIRO_LINE_CAP_ROUND); | |||
cairo_set_line_width(context, 5-0.2); | |||
cairo_move_to(context, w/2, h/2); | |||
cairo_line_to(context, w/2, h/2); | |||
cairo_set_source_rgba(context, 0.1, 0.1, 0.1, 0 ); | |||
cairo_stroke(context); | |||
cairo_arc(context, w/2, h/2, radius, 2.46, 0.75 ); | |||
cairo_set_source_rgb(context, 0.1, 0.1, 0.1 ); | |||
cairo_stroke(context); | |||
float angle = 2.46 + ( 4.54 * value ); | |||
cairo_set_line_width(context, 5); | |||
cairo_arc(context, w/2, h/2, radius, 2.46, angle ); | |||
cairo_line_to(context, w/2, h/2); | |||
cairo_set_source_rgba(context, 1.0, 0.48, 0, 0.8); | |||
cairo_stroke(context); | |||
cairo_restore(context); | |||
} | |||
bool onMouse(int button, bool press, int x, int y) | |||
{ | |||
if (button == 1) | |||
{ | |||
pressed = press; | |||
if (press) | |||
{ | |||
setX(x-100/2); | |||
setY(y-100/2); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool onMotion(int x, int y) | |||
{ | |||
if (pressed) | |||
{ | |||
setX(x-100/2); | |||
setY(y-100/2); | |||
return true; | |||
} | |||
return false; | |||
} | |||
float value; | |||
bool pressed; | |||
}; | |||
// ------------------------------------------------------ | |||
// Custom window, with bg + cairo + image | |||
class CustomWindow : public Window | |||
{ | |||
public: | |||
CustomWindow(App& app) | |||
: Window(app), | |||
bg(*this), | |||
cairo(*this) | |||
{ | |||
app.addIdleCallback(&cairo); | |||
} | |||
private: | |||
BackgroundWidget bg; | |||
CustomCairoWidget cairo; | |||
}; | |||
// ------------------------------------------------------ | |||
// main entry point | |||
int main() | |||
{ | |||
App app; | |||
CustomWindow win(app); | |||
win.setSize(300, 300); | |||
win.setTitle("Cairo"); | |||
win.show(); | |||
app.exec(); | |||
return 0; | |||
} | |||
// ------------------------------------------------------ |
@@ -35,7 +35,7 @@ using namespace DGL; | |||
// our widget | |||
class ExampleImagesWidget : public App::IdleCallback, | |||
Widget | |||
Widget | |||
{ | |||
public: | |||
static const int kImg1y = 0; | |||