@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -38,18 +38,18 @@ class Window; | |||
In standalone mode an application will automatically quit its | |||
event-loop when all its windows are closed. | |||
*/ | |||
class App | |||
class Application | |||
{ | |||
public: | |||
/** | |||
Constructor. | |||
*/ | |||
App(); | |||
Application(); | |||
/** | |||
Destructor. | |||
*/ | |||
~App(); | |||
~Application(); | |||
/** | |||
Idle function. | |||
@@ -60,7 +60,7 @@ public: | |||
/** | |||
Run the application event-loop until all Windows are closed. | |||
idle() is called at regular intervals. | |||
@note: This function is meant for standalones only, *never* call this from plugins. | |||
@note This function is meant for standalones only, *never* call this from plugins. | |||
*/ | |||
void exec(); | |||
@@ -81,7 +81,7 @@ private: | |||
PrivateData* const pData; | |||
friend class Window; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(App) | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | |||
}; | |||
// ----------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,8 +17,8 @@ | |||
#ifndef DGL_BASE_HPP_INCLUDED | |||
#define DGL_BASE_HPP_INCLUDED | |||
#include "../distrho/extra/d_leakdetector.hpp" | |||
#include "../distrho/extra/d_scopedpointer.hpp" | |||
#include "../distrho/extra/LeakDetector.hpp" | |||
#include "../distrho/extra/ScopedPointer.hpp" | |||
// ----------------------------------------------------------------------- | |||
// Define namespace | |||
@@ -121,50 +121,50 @@ START_NAMESPACE_DGL | |||
Convenience symbols for ASCII control characters. | |||
*/ | |||
enum Char { | |||
CHAR_BACKSPACE = 0x08, | |||
CHAR_ESCAPE = 0x1B, | |||
CHAR_DELETE = 0x7F | |||
kCharBackspace = 0x08, | |||
kCharEscape = 0x1B, | |||
kCharDelete = 0x7F | |||
}; | |||
/** | |||
Keyboard modifier flags. | |||
*/ | |||
enum Modifier { | |||
MODIFIER_SHIFT = 1 << 0, /**< Shift key */ | |||
MODIFIER_CTRL = 1 << 1, /**< Control key */ | |||
MODIFIER_ALT = 1 << 2, /**< Alt/Option key */ | |||
MODIFIER_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||
kModifierShift = 1 << 0, /**< Shift key */ | |||
kModifierControl = 1 << 1, /**< Control key */ | |||
kModifierAlt = 1 << 2, /**< Alt/Option key */ | |||
kModifierSuper = 1 << 3 /**< Mod4/Command/Windows key */ | |||
}; | |||
/** | |||
Special (non-Unicode) keyboard keys. | |||
*/ | |||
enum Key { | |||
KEY_F1 = 1, | |||
KEY_F2, | |||
KEY_F3, | |||
KEY_F4, | |||
KEY_F5, | |||
KEY_F6, | |||
KEY_F7, | |||
KEY_F8, | |||
KEY_F9, | |||
KEY_F10, | |||
KEY_F11, | |||
KEY_F12, | |||
KEY_LEFT, | |||
KEY_UP, | |||
KEY_RIGHT, | |||
KEY_DOWN, | |||
KEY_PAGE_UP, | |||
KEY_PAGE_DOWN, | |||
KEY_HOME, | |||
KEY_END, | |||
KEY_INSERT, | |||
KEY_SHIFT, | |||
KEY_CTRL, | |||
KEY_ALT, | |||
KEY_SUPER | |||
kKeyF1 = 1, | |||
kKeyF2, | |||
kKeyF3, | |||
kKeyF4, | |||
kKeyF5, | |||
kKeyF6, | |||
kKeyF7, | |||
kKeyF8, | |||
kKeyF9, | |||
kKeyF10, | |||
kKeyF11, | |||
kKeyF12, | |||
kKeyLeft, | |||
kKeyUp, | |||
kKeyRight, | |||
kKeyDown, | |||
kKeyPageUp, | |||
kKeyPageDown, | |||
kKeyHome, | |||
kKeyEnd, | |||
kKeyInsert, | |||
kKeyShift, | |||
kKeyControl, | |||
kKeyAlt, | |||
kKeySuper | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -184,4 +184,12 @@ public: | |||
END_NAMESPACE_DGL | |||
#ifndef DONT_SET_USING_DGL_NAMESPACE | |||
// If your code uses a lot of DGL classes, then this will obviously save you | |||
// a lot of typing, but can be disabled by setting DONT_SET_USING_DGL_NAMESPACE. | |||
using namespace DGL_NAMESPACE; | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#endif // DGL_BASE_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -25,8 +25,6 @@ START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
// TODO: create color from "#333" and "#112233" like strings | |||
/** | |||
A color made from red, green, blue and alpha floating-point values in [0..1] range. | |||
*/ | |||
@@ -40,7 +38,7 @@ struct Color { | |||
}; | |||
/** | |||
Create black color. | |||
Create solid black color. | |||
*/ | |||
Color() noexcept; | |||
@@ -85,7 +83,7 @@ struct Color { | |||
/** | |||
Check if this color matches another. | |||
@note: Comparison is forced within 8-bit color values. | |||
@note Comparison is forced within 8-bit color values. | |||
*/ | |||
bool isEqual(const Color& color, bool withAlpha = true) noexcept; | |||
bool isNotEqual(const Color& color, bool withAlpha = true) noexcept; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -45,13 +45,13 @@ public: | |||
/** | |||
Constructor using raw image data. | |||
@note: @a rawData must remain valid for the lifetime of this Image. | |||
@note @a rawData must remain valid for the lifetime of this Image. | |||
*/ | |||
Image(const char* const rawData, const uint width, const uint height, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE); | |||
/** | |||
Constructor using raw image data. | |||
@note: @a rawData must remain valid for the lifetime of this Image. | |||
@note @a rawData must remain valid for the lifetime of this Image. | |||
*/ | |||
Image(const char* const rawData, const Size<uint>& size, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE); | |||
@@ -67,13 +67,13 @@ public: | |||
/** | |||
Load 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* const rawData, const uint width, const uint height, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
/** | |||
Load 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* const rawData, const Size<uint>& size, const GLenum format = GL_BGRA, const GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,38 +17,7 @@ | |||
#ifndef DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED | |||
#define DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
#include "Window.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageAboutWindow : public Window, | |||
public Widget | |||
{ | |||
public: | |||
explicit ImageAboutWindow(Window& parent, const Image& image = Image()); | |||
explicit ImageAboutWindow(Widget* widget, const Image& image = Image()); | |||
void setImage(const Image& image); | |||
protected: | |||
void onDisplay() override; | |||
bool onKeyboard(const KeyboardEvent&) override; | |||
bool onMouse(const MouseEvent&) override; | |||
void onReshape(uint width, uint height) override; | |||
private: | |||
Image fImgBackground; | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ImageAboutWindow) | |||
//DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#warning This is a deprecated file, please include ImageWidgets.hpp instead. | |||
#include "ImageWidgets.hpp" | |||
#endif // DGL_IMAGE_ABOUT_WINDOW_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,51 +17,7 @@ | |||
#ifndef DGL_IMAGE_BUTTON_HPP_INCLUDED | |||
#define DGL_IMAGE_BUTTON_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageButton : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0; | |||
}; | |||
explicit ImageButton(Window& parent, const Image& image) noexcept; | |||
explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept; | |||
explicit ImageButton(Widget* widget, const Image& image) noexcept; | |||
explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept; | |||
explicit ImageButton(const ImageButton& imageButton) noexcept; | |||
ImageButton& operator=(const ImageButton& imageButton) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
private: | |||
Image fImageNormal; | |||
Image fImageHover; | |||
Image fImageDown; | |||
Image* fCurImage; | |||
int fCurButton; | |||
Callback* fCallback; | |||
DISTRHO_LEAK_DETECTOR(ImageButton) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#warning This is a deprecated file, please include ImageWidgets.hpp instead. | |||
#include "ImageWidgets.hpp" | |||
#endif // DGL_IMAGE_BUTTON_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,87 +17,7 @@ | |||
#ifndef DGL_IMAGE_KNOB_HPP_INCLUDED | |||
#define DGL_IMAGE_KNOB_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageKnob : public Widget | |||
{ | |||
public: | |||
enum Orientation { | |||
Horizontal, | |||
Vertical | |||
}; | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; | |||
}; | |||
explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical) noexcept; | |||
explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical) noexcept; | |||
explicit ImageKnob(const ImageKnob& imageKnob); | |||
ImageKnob& operator=(const ImageKnob& imageKnob); | |||
~ImageKnob() override; | |||
float getValue() const noexcept; | |||
void setDefault(float def) noexcept; | |||
void setRange(float min, float max) noexcept; | |||
void setStep(float step) noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setUsingLogScale(bool yesNo) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
void setOrientation(Orientation orientation) noexcept; | |||
void setRotationAngle(int angle); | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
bool onScroll(const ScrollEvent&) override; | |||
private: | |||
Image fImage; | |||
float fMinimum; | |||
float fMaximum; | |||
float fStep; | |||
float fValue; | |||
float fValueDef; | |||
float fValueTmp; | |||
bool fUsingDefault; | |||
bool fUsingLog; | |||
Orientation fOrientation; | |||
int fRotationAngle; | |||
bool fDragging; | |||
int fLastX; | |||
int fLastY; | |||
Callback* fCallback; | |||
bool fIsImgVertical; | |||
uint fImgLayerSize; | |||
uint fImgLayerCount; | |||
bool fIsReady; | |||
GLuint fTextureId; | |||
float _logscale(float value) const; | |||
float _invlogscale(float value) const; | |||
DISTRHO_LEAK_DETECTOR(ImageKnob) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#warning This is a deprecated file, please include ImageWidgets.hpp instead. | |||
#include "ImageWidgets.hpp" | |||
#endif // DGL_IMAGE_KNOB_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,82 +17,7 @@ | |||
#ifndef DGL_IMAGE_SLIDER_HPP_INCLUDED | |||
#define DGL_IMAGE_SLIDER_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageSlider : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; | |||
}; | |||
explicit ImageSlider(Window& parent, const Image& image) noexcept; | |||
explicit ImageSlider(Widget* widget, const Image& image) noexcept; | |||
explicit ImageSlider(const ImageSlider& imageSlider) noexcept; | |||
ImageSlider& operator=(const ImageSlider& imageSlider) noexcept; | |||
float getValue() const noexcept; | |||
void setStartPos(const Point<int>& startPos) noexcept; | |||
void setStartPos(int x, int y) noexcept; | |||
void setEndPos(const Point<int>& endPos) noexcept; | |||
void setEndPos(int x, int y) noexcept; | |||
void setInverted(bool inverted) noexcept; | |||
void setRange(float min, float max) noexcept; | |||
void setStep(float step) noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
private: | |||
Image fImage; | |||
float fMinimum; | |||
float fMaximum; | |||
float fStep; | |||
float fValue; | |||
float fValueTmp; | |||
bool fDragging; | |||
bool fInverted; | |||
int fStartedX; | |||
int fStartedY; | |||
Callback* fCallback; | |||
Point<int> fStartPos; | |||
Point<int> fEndPos; | |||
Rectangle<int> fSliderArea; | |||
void _recheckArea() noexcept; | |||
// these should not be used | |||
void setAbsoluteX(int) const noexcept {} | |||
void setAbsoluteY(int) const noexcept {} | |||
void setAbsolutePos(int, int) const noexcept {} | |||
void setAbsolutePos(const Point<int>&) const noexcept {} | |||
void setNeedsFullViewport(bool) const noexcept {} | |||
DISTRHO_LEAK_DETECTOR(ImageSlider) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#warning This is a deprecated file, please include ImageWidgets.hpp instead. | |||
#include "ImageWidgets.hpp" | |||
#endif // DGL_IMAGE_SLIDER_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,49 +17,7 @@ | |||
#ifndef DGL_IMAGE_SWITCH_HPP_INCLUDED | |||
#define DGL_IMAGE_SWITCH_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageSwitch : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageSwitchClicked(ImageSwitch* imageButton, bool down) = 0; | |||
}; | |||
explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept; | |||
explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept; | |||
explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept; | |||
ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept; | |||
bool isDown() const noexcept; | |||
void setDown(bool down) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
private: | |||
Image fImageNormal; | |||
Image fImageDown; | |||
bool fIsDown; | |||
Callback* fCallback; | |||
DISTRHO_LEAK_DETECTOR(ImageSwitch) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#warning This is a deprecated file, please include ImageWidgets.hpp instead. | |||
#include "ImageWidgets.hpp" | |||
#endif // DGL_IMAGE_SWITCH_HPP_INCLUDED |
@@ -0,0 +1,271 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifndef DGL_IMAGE_WIDGETS_HPP_INCLUDED | |||
#define DGL_IMAGE_WIDGETS_HPP_INCLUDED | |||
#include "Image.hpp" | |||
#include "Widget.hpp" | |||
#include "Window.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class ImageAboutWindow : public Window, | |||
public Widget | |||
{ | |||
public: | |||
explicit ImageAboutWindow(Window& parent, const Image& image = Image()); | |||
explicit ImageAboutWindow(Widget* widget, const Image& image = Image()); | |||
void setImage(const Image& image); | |||
protected: | |||
void onDisplay() override; | |||
bool onKeyboard(const KeyboardEvent&) override; | |||
bool onMouse(const MouseEvent&) override; | |||
void onReshape(uint width, uint height) override; | |||
private: | |||
Image fImgBackground; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
class ImageButton : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0; | |||
}; | |||
explicit ImageButton(Window& parent, const Image& image); | |||
explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageDown); | |||
explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown); | |||
explicit ImageButton(Widget* widget, const Image& image); | |||
explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageDown); | |||
explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown); | |||
~ImageButton() override; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
DISTRHO_LEAK_DETECTOR(ImageButton) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
class ImageKnob : public Widget | |||
{ | |||
public: | |||
enum Orientation { | |||
Horizontal, | |||
Vertical | |||
}; | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0; | |||
virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; | |||
}; | |||
explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical) noexcept; | |||
explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical) noexcept; | |||
explicit ImageKnob(const ImageKnob& imageKnob); | |||
ImageKnob& operator=(const ImageKnob& imageKnob); | |||
~ImageKnob() override; | |||
float getValue() const noexcept; | |||
void setDefault(float def) noexcept; | |||
void setRange(float min, float max) noexcept; | |||
void setStep(float step) noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setUsingLogScale(bool yesNo) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
void setOrientation(Orientation orientation) noexcept; | |||
void setRotationAngle(int angle); | |||
void setImageLayerCount(uint count) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
bool onScroll(const ScrollEvent&) override; | |||
private: | |||
Image fImage; | |||
float fMinimum; | |||
float fMaximum; | |||
float fStep; | |||
float fValue; | |||
float fValueDef; | |||
float fValueTmp; | |||
bool fUsingDefault; | |||
bool fUsingLog; | |||
Orientation fOrientation; | |||
int fRotationAngle; | |||
bool fDragging; | |||
int fLastX; | |||
int fLastY; | |||
Callback* fCallback; | |||
bool fIsImgVertical; | |||
uint fImgLayerWidth; | |||
uint fImgLayerHeight; | |||
uint fImgLayerCount; | |||
bool fIsReady; | |||
GLuint fTextureId; | |||
float _logscale(float value) const; | |||
float _invlogscale(float value) const; | |||
DISTRHO_LEAK_DETECTOR(ImageKnob) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// note set range and step before setting the value | |||
class ImageSlider : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0; | |||
virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; | |||
}; | |||
explicit ImageSlider(Window& parent, const Image& image) noexcept; | |||
explicit ImageSlider(Widget* widget, const Image& image) noexcept; | |||
float getValue() const noexcept; | |||
void setValue(float value, bool sendCallback = false) noexcept; | |||
void setStartPos(const Point<int>& startPos) noexcept; | |||
void setStartPos(int x, int y) noexcept; | |||
void setEndPos(const Point<int>& endPos) noexcept; | |||
void setEndPos(int x, int y) noexcept; | |||
void setInverted(bool inverted) noexcept; | |||
void setRange(float min, float max) noexcept; | |||
void setStep(float step) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
private: | |||
Image fImage; | |||
float fMinimum; | |||
float fMaximum; | |||
float fStep; | |||
float fValue; | |||
float fValueTmp; | |||
bool fDragging; | |||
bool fInverted; | |||
bool fValueIsSet; | |||
int fStartedX; | |||
int fStartedY; | |||
Callback* fCallback; | |||
Point<int> fStartPos; | |||
Point<int> fEndPos; | |||
Rectangle<int> fSliderArea; | |||
void _recheckArea() noexcept; | |||
// these should not be used | |||
void setAbsoluteX(int) const noexcept {} | |||
void setAbsoluteY(int) const noexcept {} | |||
void setAbsolutePos(int, int) const noexcept {} | |||
void setAbsolutePos(const Point<int>&) const noexcept {} | |||
DISTRHO_LEAK_DETECTOR(ImageSlider) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
class ImageSwitch : public Widget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void imageSwitchClicked(ImageSwitch* imageButton, bool down) = 0; | |||
}; | |||
explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept; | |||
explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept; | |||
explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept; | |||
ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept; | |||
bool isDown() const noexcept; | |||
void setDown(bool down) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
private: | |||
Image fImageNormal; | |||
Image fImageDown; | |||
bool fIsDown; | |||
Callback* fCallback; | |||
DISTRHO_LEAK_DETECTOR(ImageSwitch) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED |
@@ -15,19 +15,19 @@ BUILD_CXX_FLAGS += $(DGL_FLAGS) -Isrc | |||
# needed by sofd right now, fix later | |||
BUILD_CXX_FLAGS += -fpermissive | |||
# needed by oui-blendish | |||
BUILD_CXX_FLAGS += -Wno-unused-parameter | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
OBJS = \ | |||
$(OBJDIR)/App.cpp.o \ | |||
$(OBJDIR)/Application.cpp.o \ | |||
$(OBJDIR)/Color.cpp.o \ | |||
$(OBJDIR)/Geometry.cpp.o \ | |||
$(OBJDIR)/Image.cpp.o \ | |||
$(OBJDIR)/ImageAboutWindow.cpp.o \ | |||
$(OBJDIR)/ImageButton.cpp.o \ | |||
$(OBJDIR)/ImageKnob.cpp.o \ | |||
$(OBJDIR)/ImageSlider.cpp.o \ | |||
$(OBJDIR)/ImageSwitch.cpp.o \ | |||
$(OBJDIR)/ImageWidgets.cpp.o \ | |||
$(OBJDIR)/NanoVG.cpp.o \ | |||
$(OBJDIR)/NanoWidgets.cpp.o \ | |||
$(OBJDIR)/Widget.cpp.o | |||
ifeq ($(MACOS),true) | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -25,6 +25,11 @@ struct NVGpaint; | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
// Forward class names | |||
class NanoVG; | |||
// ----------------------------------------------------------------------- | |||
// NanoImage | |||
@@ -36,35 +41,62 @@ START_NAMESPACE_DGL | |||
*/ | |||
class NanoImage | |||
{ | |||
private: | |||
struct Handle { | |||
NVGcontext* context; | |||
int imageId; | |||
Handle() noexcept | |||
: context(nullptr), | |||
imageId(0) {} | |||
Handle(NVGcontext* c, int id) noexcept | |||
: context(c), | |||
imageId(id) {} | |||
}; | |||
public: | |||
/** | |||
Constructor for an invalid/null image. | |||
*/ | |||
NanoImage(); | |||
/** | |||
Constructor. | |||
*/ | |||
NanoImage(const Handle& handle); | |||
/** | |||
Destructor. | |||
*/ | |||
~NanoImage(); | |||
/** | |||
Get size. | |||
Create a new image without recreating the C++ class. | |||
*/ | |||
Size<uint> getSize() const noexcept; | |||
NanoImage& operator=(const Handle& handle); | |||
/** | |||
Update image data. | |||
Wherever this image is valid. | |||
*/ | |||
void updateImage(const uchar* const data); | |||
bool isValid() const noexcept; | |||
/** | |||
Get size. | |||
*/ | |||
Size<uint> getSize() const noexcept; | |||
protected: | |||
/** | |||
Constructors are protected. | |||
NanoImages must be created within a NanoVG or NanoWidget class. | |||
Get the OpenGL texture handle. | |||
*/ | |||
NanoImage(NVGcontext* const context, const int imageId) noexcept; | |||
GLuint getTextureHandle() const; | |||
private: | |||
NVGcontext* fContext; | |||
int fImageId; | |||
Handle fHandle; | |||
Size<uint> fSize; | |||
friend class NanoVG; | |||
/** @internal */ | |||
void _updateSize(); | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoImage) | |||
@@ -114,7 +146,7 @@ private: | |||
These can be used as paints for strokes and fills. | |||
@section Scissoring | |||
Scissoring allows you to clip the rendering into a rectangle. This is useful for varius | |||
Scissoring allows you to clip the rendering into a rectangle. This is useful for various | |||
user interface cases like rendering a text edit or a timeline. | |||
@section Paths | |||
@@ -168,6 +200,32 @@ private: | |||
class NanoVG | |||
{ | |||
public: | |||
enum CreateFlags { | |||
/** | |||
Flag indicating if geometry based anti-aliasing is used (may not be needed when using MSAA). | |||
*/ | |||
CREATE_ANTIALIAS = 1 << 0, | |||
/** | |||
Flag indicating if strokes should be drawn using stencil buffer. The rendering will be a little | |||
slower, but path overlaps (i.e. self-intersecting or sharp turns) will be drawn just once. | |||
*/ | |||
CREATE_STENCIL_STROKES = 1 << 1, | |||
/** | |||
Flag indicating that additional debug checks are done. | |||
*/ | |||
CREATE_DEBUG = 1 << 2, | |||
}; | |||
enum ImageFlags { | |||
IMAGE_GENERATE_MIPMAPS = 1 << 0, // Generate mipmaps during creation of the image. | |||
IMAGE_REPEAT_X = 1 << 1, // Repeat image in X direction. | |||
IMAGE_REPEAT_Y = 1 << 2, // Repeat image in Y direction. | |||
IMAGE_FLIP_Y = 1 << 3, // Flips (inverses) image in Y direction when rendered. | |||
IMAGE_PREMULTIPLIED = 1 << 4 // Image data has premultiplied alpha. | |||
}; | |||
enum Align { | |||
// Horizontal align | |||
ALIGN_LEFT = 1 << 0, // Align horizontally to left (default). | |||
@@ -180,11 +238,6 @@ public: | |||
ALIGN_BASELINE = 1 << 6 // Align vertically to baseline (default). | |||
}; | |||
enum Alpha { | |||
STRAIGHT_ALPHA, | |||
PREMULTIPLIED_ALPHA | |||
}; | |||
enum LineCap { | |||
BUTT, | |||
ROUND, | |||
@@ -193,12 +246,6 @@ public: | |||
MITER | |||
}; | |||
enum PatternRepeat { | |||
REPEAT_NONE = 0x0, // No repeat | |||
REPEAT_X = 0x1, // Repeat in X direction | |||
REPEAT_Y = 0x2 // Repeat in Y direction | |||
}; | |||
enum Solidity { | |||
SOLID = 1, // CCW | |||
HOLE = 2 // CW | |||
@@ -217,7 +264,6 @@ public: | |||
Color innerColor; | |||
Color outerColor; | |||
int imageId; | |||
PatternRepeat repeat; | |||
Paint() noexcept; | |||
@@ -246,14 +292,14 @@ public: | |||
/** | |||
Constructor. | |||
Uses 512x512 as default atlas size. | |||
@see CreateFlags | |||
*/ | |||
NanoVG(); | |||
NanoVG(int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor using custom text atlas size. | |||
Constructor reusing a NanoVG context, used for subwidgets. | |||
*/ | |||
NanoVG(const int textAtlasWidth, const int textAtlasHeight); | |||
NanoVG(NanoWidget* groupWidget); | |||
/** | |||
Destructor. | |||
@@ -271,15 +317,19 @@ public: | |||
/** | |||
Begin drawing a new frame. | |||
@param withAlha Controls if drawing the shapes to the render target should be done using straight or pre-multiplied alpha. | |||
*/ | |||
void beginFrame(const uint width, const uint height, const float scaleFactor = 1.0f, const Alpha alpha = PREMULTIPLIED_ALPHA); | |||
void beginFrame(const uint width, const uint height, const float scaleFactor = 1.0f); | |||
/** | |||
Begin drawing a new frame inside a widget. | |||
*/ | |||
void beginFrame(Widget* const widget); | |||
/** | |||
Cancels drawing the current frame. | |||
*/ | |||
void cancelFrame(); | |||
/** | |||
Ends drawing flushing remaining render state. | |||
*/ | |||
@@ -374,6 +424,12 @@ public: | |||
*/ | |||
void lineJoin(LineCap join = MITER); | |||
/** | |||
Sets the transparency applied to all rendered shapes. | |||
Already transparent paths will get proportionally more transparent as well. | |||
*/ | |||
void globalAlpha(float alpha); | |||
/* -------------------------------------------------------------------- | |||
* Transforms */ | |||
@@ -495,17 +551,50 @@ public: | |||
/** | |||
Creates image by loading it from the disk from specified file name. | |||
*/ | |||
NanoImage* createImage(const char* filename); | |||
NanoImage::Handle createImageFromFile(const char* filename, ImageFlags imageFlags); | |||
/** | |||
Creates image by loading it from the disk from specified file name. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
NanoImage::Handle createImageFromFile(const char* filename, int imageFlags); | |||
/** | |||
Creates image by loading it from the specified chunk of memory. | |||
*/ | |||
NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags); | |||
/** | |||
Creates image by loading it from the specified chunk of memory. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
NanoImage* createImageMem(uchar* data, int ndata); | |||
NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags); | |||
/** | |||
Creates image from specified image data. | |||
*/ | |||
NanoImage* createImageRGBA(uint w, uint h, const uchar* data); | |||
NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags); | |||
/** | |||
Creates image from specified image data. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags); | |||
/** | |||
Creates image from an OpenGL texture handle. | |||
*/ | |||
NanoImage::Handle createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture = false); | |||
/** | |||
Creates image from an OpenGL texture handle. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
NanoImage::Handle createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture = false); | |||
/* -------------------------------------------------------------------- | |||
* Paints */ | |||
@@ -535,21 +624,30 @@ public: | |||
/** | |||
Creates and returns an image pattern. Parameters (ox,oy) specify the left-top location of the image pattern, | |||
(ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render, | |||
and repeat tells if the image should be repeated across x or y. | |||
(ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. | |||
The gradient is transformed by the current transform when it is passed to fillPaint() or strokePaint(). | |||
*/ | |||
Paint imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage* image, PatternRepeat repeat); | |||
Paint imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha); | |||
/* -------------------------------------------------------------------- | |||
* Scissoring */ | |||
/** | |||
Sets the current | |||
Sets the current scissor rectangle. | |||
The scissor rectangle is transformed by the current transform. | |||
*/ | |||
void scissor(float x, float y, float w, float h); | |||
/** | |||
Intersects current scissor rectangle with the specified rectangle. | |||
The scissor rectangle is transformed by the current transform. | |||
Note: in case the rotation of previous scissor rect differs from | |||
the current one, the intersection will be done between the specified | |||
rectangle and the previous scissor rectangle transformed in the current | |||
transform space. The resulting shape is always rectangle. | |||
*/ | |||
void intersectScissor(float x, float y, float w, float h); | |||
/** | |||
Reset and disables scissoring. | |||
*/ | |||
@@ -574,10 +672,15 @@ public: | |||
void lineTo(float x, float y); | |||
/** | |||
Adds bezier segment from last point in the path via two control points to the specified point. | |||
Adds cubic bezier segment from last point in the path via two control points to the specified point. | |||
*/ | |||
void bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y); | |||
/** | |||
Adds quadratic bezier segment from last point in the path via a control point to the specified point. | |||
*/ | |||
void quadTo(float cx, float cy, float x, float y); | |||
/** | |||
Adds an arc segment at the corner defined by the last path point, and two specified points. | |||
*/ | |||
@@ -594,7 +697,9 @@ public: | |||
void pathWinding(Winding dir); | |||
/** | |||
Creates new arc shaped sub-path. | |||
Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, | |||
and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW or NVG_CW). | |||
Angles are specified in radians. | |||
*/ | |||
void arc(float cx, float cy, float r, float a0, float a1, Winding dir); | |||
@@ -635,13 +740,13 @@ public: | |||
Creates font by loading it from the disk from specified file name. | |||
Returns handle to the font. | |||
*/ | |||
FontId createFont(const char* name, const char* filename); | |||
FontId createFontFromFile(const char* name, const char* filename); | |||
/** | |||
Creates font by loading it from the specified memory chunk. | |||
Returns handle to the font. | |||
*/ | |||
FontId createFontMem(const char* name, const uchar* data, int ndata, bool freeData); | |||
FontId createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData); | |||
/** | |||
Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. | |||
@@ -696,11 +801,12 @@ public: | |||
float text(float x, float y, const char* string, const char* end); | |||
/** | |||
Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. | |||
Draws multi-line text string at specified location wrapped at the specified width. | |||
If end is specified only the sub-string up to the end is drawn. | |||
White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. | |||
Words longer than the max width are slit at nearest character (i.e. no hyphenation). | |||
*/ | |||
void textBox(float x, float y, float breakRowWidth, const char* string, const char* end); | |||
void textBox(float x, float y, float breakRowWidth, const char* string, const char* end = nullptr); | |||
/** | |||
Measures the specified text string. The bounds value are [xmin,ymin, xmax,ymax]. | |||
@@ -714,13 +820,13 @@ public: | |||
if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] | |||
Measured values are returned in local coordinate space. | |||
*/ | |||
void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); | |||
void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4]); | |||
/** | |||
Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. | |||
Measured values are returned in local coordinate space. | |||
*/ | |||
int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions); | |||
int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition& positions, int maxPositions); | |||
/** | |||
Returns the vertical metrics based on the current text style. | |||
@@ -733,11 +839,12 @@ public: | |||
White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. | |||
Words longer than the max width are slit at nearest character (i.e. no hyphenation). | |||
*/ | |||
int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows); | |||
int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow& rows, int maxRows); | |||
private: | |||
NVGcontext* const fContext; | |||
bool fInFrame; | |||
bool fIsSubWidget; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoVG) | |||
}; | |||
@@ -758,14 +865,24 @@ class NanoWidget : public Widget, | |||
public: | |||
/** | |||
Constructor. | |||
@see CreateFlags | |||
*/ | |||
NanoWidget(Window& parent) | |||
: Widget(parent), | |||
NanoVG(), | |||
leakDetector_NanoWidget() | |||
{ | |||
setNeedsScaling(true); | |||
} | |||
explicit NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor for a subwidget. | |||
*/ | |||
explicit NanoWidget(Widget* groupWidget, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor for a subwidget, reusing a NanoVG context. | |||
*/ | |||
explicit NanoWidget(NanoWidget* groupWidget); | |||
/** | |||
Destructor. | |||
*/ | |||
virtual ~NanoWidget(); | |||
protected: | |||
/** | |||
@@ -775,19 +892,21 @@ protected: | |||
virtual void onNanoDisplay() = 0; | |||
private: | |||
struct PrivateData; | |||
PrivateData* const nData; | |||
/** | |||
Widget display function. | |||
Implemented internally to wrap begin/endFrame() automatically. | |||
*/ | |||
void onDisplay() override | |||
{ | |||
//glPushAttrib(GL_PIXEL_MODE_BIT|GL_STENCIL_BUFFER_BIT|GL_ENABLE_BIT); | |||
beginFrame(getWidth(), getHeight()); | |||
onNanoDisplay(); | |||
endFrame(); | |||
//glPopAttrib(); | |||
glDisable(GL_CULL_FACE); | |||
} | |||
void onDisplay() override; | |||
// these should not be used | |||
void beginFrame(uint,uint) {} | |||
void beginFrame(uint,uint,float) {} | |||
void beginFrame(Widget*) {} | |||
void cancelFrame() {} | |||
void endFrame() {} | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoWidget) | |||
}; | |||
@@ -0,0 +1,67 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifndef DGL_NANO_WIDGETS_HPP_INCLUDED | |||
#define DGL_NANO_WIDGETS_HPP_INCLUDED | |||
#include "NanoVG.hpp" | |||
#include "../distrho/extra/String.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class BlendishButton : public NanoWidget | |||
{ | |||
public: | |||
class Callback | |||
{ | |||
public: | |||
virtual ~Callback() {} | |||
virtual void blendishButtonClicked(BlendishButton* blendishButton, int button) = 0; | |||
}; | |||
explicit BlendishButton(Window& parent, const char* text = "", int iconId = -1); | |||
explicit BlendishButton(NanoWidget* widget, const char* text = "", int iconId = -1); | |||
~BlendishButton() override; | |||
int getIconId() const noexcept; | |||
void setIconId(int iconId) noexcept; | |||
const char* getText() const noexcept; | |||
void setText(const char* text) noexcept; | |||
void setCallback(Callback* callback) noexcept; | |||
protected: | |||
void onNanoDisplay() override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
void _updateBounds(); | |||
DISTRHO_LEAK_DETECTOR(BlendishButton) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#endif // DGL_NANO_WIDGETS_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,7 +17,7 @@ | |||
#ifndef DGL_STANDALONE_WINDOW_HPP_INCLUDED | |||
#define DGL_STANDALONE_WINDOW_HPP_INCLUDED | |||
#include "App.hpp" | |||
#include "Application.hpp" | |||
#include "Widget.hpp" | |||
#include "Window.hpp" | |||
@@ -25,51 +25,31 @@ START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class StandaloneWindow : public App, | |||
class StandaloneWindow : public Application, | |||
public Window | |||
{ | |||
public: | |||
StandaloneWindow() | |||
: App(), | |||
Window((App&)*this), | |||
fWidget(nullptr) {} | |||
/** | |||
Constructor. | |||
*/ | |||
StandaloneWindow(); | |||
void exec() | |||
{ | |||
Window::show(); | |||
App::exec(); | |||
} | |||
protected: | |||
void onReshape(uint width, uint height) override | |||
{ | |||
if (fWidget != nullptr) | |||
fWidget->setSize(width, height); | |||
Window::onReshape(width, height); | |||
} | |||
/** | |||
Show window and execute application. | |||
*/ | |||
void exec(); | |||
private: | |||
Widget* fWidget; | |||
void _addWidget(Widget* widget) override | |||
{ | |||
if (fWidget == nullptr) | |||
{ | |||
fWidget = widget; | |||
fWidget->setNeedsFullViewport(true); | |||
} | |||
Window::_addWidget(widget); | |||
} | |||
/** @internal */ | |||
void onReshape(uint width, uint height) override; | |||
/** @internal */ | |||
void _addWidget(Widget* widget) override; | |||
void _removeWidget(Widget* widget) override | |||
{ | |||
if (fWidget == widget) | |||
{ | |||
fWidget->setNeedsFullViewport(false); | |||
fWidget = nullptr; | |||
} | |||
Window::_removeWidget(widget); | |||
} | |||
/** @internal */ | |||
void _removeWidget(Widget* widget) override; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -19,12 +19,20 @@ | |||
#include "Geometry.hpp" | |||
START_NAMESPACE_DGL | |||
#include <vector> | |||
// ----------------------------------------------------------------------- | |||
// Forward class names | |||
class App; | |||
START_NAMESPACE_DISTRHO | |||
class UI; | |||
END_NAMESPACE_DISTRHO | |||
START_NAMESPACE_DGL | |||
class Application; | |||
class ImageSlider; | |||
class NanoWidget; | |||
class Window; | |||
class StandaloneWindow; | |||
@@ -172,6 +180,11 @@ public: | |||
*/ | |||
explicit Widget(Window& parent); | |||
/** | |||
Constructor for a subwidget. | |||
*/ | |||
explicit Widget(Widget* groupWidget); | |||
/** | |||
Destructor. | |||
*/ | |||
@@ -274,7 +287,7 @@ public: | |||
Get this widget's window application. | |||
Same as calling getParentWindow().getApp(). | |||
*/ | |||
App& getParentApp() const noexcept; | |||
Application& getParentApp() const noexcept; | |||
/** | |||
Get parent window, as passed in the constructor. | |||
@@ -349,33 +362,18 @@ protected: | |||
*/ | |||
virtual void onResize(const ResizeEvent&); | |||
/** | |||
Tell the parent window this widget needs the full viewport. | |||
When enabled, the local widget coordinates are ignored. | |||
@note: This is an internal function; | |||
You do not need it under normal circumstances. | |||
*/ | |||
void setNeedsFullViewport(bool yesNo) noexcept; | |||
/** | |||
Tell the parent window this widget needs scaling. | |||
When enabled, the widget viewport is scaled to match width and height. | |||
@note: This is an internal function; | |||
You do not need it under normal circumstances. | |||
*/ | |||
void setNeedsScaling(bool yesNo) noexcept; | |||
private: | |||
Window& fParent; | |||
bool fNeedsFullViewport; | |||
bool fNeedsScaling; | |||
bool fVisible; | |||
uint fId; | |||
Point<int> fAbsolutePos; | |||
Size<uint> fSize; | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
/** @internal */ | |||
explicit Widget(Widget* groupWidget, bool addToSubWidgets); | |||
friend class ImageSlider; | |||
friend class NanoWidget; | |||
friend class Window; | |||
friend class StandaloneWindow; | |||
friend class DISTRHO_NAMESPACE::UI; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Widget) | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -23,7 +23,7 @@ START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
class App; | |||
class Application; | |||
class Widget; | |||
class StandaloneWindow; | |||
@@ -67,9 +67,9 @@ public: | |||
buttons() {} | |||
}; | |||
explicit Window(App& app); | |||
explicit Window(App& app, Window& parent); | |||
explicit Window(App& app, intptr_t parentId); | |||
explicit Window(Application& app); | |||
explicit Window(Application& app, Window& parent); | |||
explicit Window(Application& app, intptr_t parentId); | |||
virtual ~Window(); | |||
void show(); | |||
@@ -99,7 +99,7 @@ public: | |||
void setTransientWinId(uintptr_t winId); | |||
App& getApp() const noexcept; | |||
Application& getApp() const noexcept; | |||
intptr_t getWindowId() const noexcept; | |||
void addIdleCallback(IdleCallback* const callback); | |||
@@ -116,7 +116,7 @@ protected: | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class App; | |||
friend class Application; | |||
friend class Widget; | |||
friend class StandaloneWindow; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -14,23 +14,22 @@ | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "AppPrivateData.hpp" | |||
#include "ApplicationPrivateData.hpp" | |||
#include "../Window.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
App::App() | |||
: pData(new PrivateData()), | |||
leakDetector_App() {} | |||
Application::Application() | |||
: pData(new PrivateData()) {} | |||
App::~App() | |||
Application::~Application() | |||
{ | |||
delete pData; | |||
} | |||
void App::idle() | |||
void Application::idle() | |||
{ | |||
for (std::list<Window*>::iterator it = pData->windows.begin(), ite = pData->windows.end(); it != ite; ++it) | |||
{ | |||
@@ -45,7 +44,7 @@ void App::idle() | |||
} | |||
} | |||
void App::exec() | |||
void Application::exec() | |||
{ | |||
for (; pData->doLoop;) | |||
{ | |||
@@ -54,7 +53,7 @@ void App::exec() | |||
} | |||
} | |||
void App::quit() | |||
void Application::quit() | |||
{ | |||
pData->doLoop = false; | |||
@@ -65,7 +64,7 @@ void App::quit() | |||
} | |||
} | |||
bool App::isQuiting() const noexcept | |||
bool Application::isQuiting() const noexcept | |||
{ | |||
return !pData->doLoop; | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,8 +17,8 @@ | |||
#ifndef DGL_APP_PRIVATE_DATA_HPP_INCLUDED | |||
#define DGL_APP_PRIVATE_DATA_HPP_INCLUDED | |||
#include "../App.hpp" | |||
#include "../../distrho/extra/d_sleep.hpp" | |||
#include "../Application.hpp" | |||
#include "../../distrho/extra/Sleep.hpp" | |||
#include <list> | |||
@@ -26,7 +26,7 @@ START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
struct App::PrivateData { | |||
struct Application::PrivateData { | |||
bool doLoop; | |||
uint visibleWindows; | |||
std::list<Window*> windows; |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -0,0 +1,129 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifndef DGL_COMMON_HPP_INCLUDED | |||
#define DGL_COMMON_HPP_INCLUDED | |||
#include "../ImageWidgets.hpp" | |||
#include "../NanoWidgets.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
struct ButtonImpl { | |||
enum State { | |||
kStateNormal = 0, | |||
kStateHover, | |||
kStateDown | |||
}; | |||
int button; | |||
int state; | |||
Widget* self; | |||
BlendishButton::Callback* callback_b; | |||
ImageButton::Callback* callback_i; | |||
ButtonImpl(Widget* const s) noexcept | |||
: button(-1), | |||
state(kStateNormal), | |||
self(s), | |||
callback_b(nullptr), | |||
callback_i(nullptr) {} | |||
bool onMouse(const Widget::MouseEvent& ev) | |||
{ | |||
// button was released, handle it now | |||
if (button != -1 && ! ev.press) | |||
{ | |||
DISTRHO_SAFE_ASSERT(state == kStateDown); | |||
// release button | |||
const int button2 = button; | |||
button = -1; | |||
// cursor was moved outside the button bounds, ignore click | |||
if (! self->contains(ev.pos)) | |||
{ | |||
state = kStateNormal; | |||
self->repaint(); | |||
return true; | |||
} | |||
// still on bounds, register click | |||
state = kStateHover; | |||
self->repaint(); | |||
if (callback_b != nullptr) | |||
callback_b->blendishButtonClicked((BlendishButton*)self, button2); | |||
if (callback_i != nullptr) | |||
callback_i->imageButtonClicked((ImageButton*)self, button2); | |||
return true; | |||
} | |||
// button was pressed, wait for release | |||
if (ev.press && self->contains(ev.pos)) | |||
{ | |||
button = ev.button; | |||
state = kStateDown; | |||
self->repaint(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool onMotion(const Widget::MotionEvent& ev) | |||
{ | |||
// keep pressed | |||
if (button != -1) | |||
return true; | |||
if (self->contains(ev.pos)) | |||
{ | |||
// check if entering hover | |||
if (state == kStateNormal) | |||
{ | |||
state = kStateHover; | |||
self->repaint(); | |||
return true; | |||
} | |||
} | |||
else | |||
{ | |||
// check if exiting hover | |||
if (state == kStateHover) | |||
{ | |||
state = kStateNormal; | |||
self->repaint(); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
DISTRHO_DECLARE_NON_COPY_STRUCT(ButtonImpl) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#endif // DGL_APP_PRIVATE_DATA_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,89 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 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. | |||
*/ | |||
#include "../ImageAboutWindow.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image) | |||
: Window(parent.getApp(), parent), | |||
Widget((Window&)*this), | |||
fImgBackground(image)/*, | |||
leakDetector_ImageAboutWindow()*/ | |||
{ | |||
Window::setResizable(false); | |||
Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight())); | |||
Window::setTitle("About"); | |||
} | |||
ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image) | |||
: Window(widget->getParentApp(), widget->getParentWindow()), | |||
Widget((Window&)*this), | |||
fImgBackground(image)/*, | |||
leakDetector_ImageAboutWindow()*/ | |||
{ | |||
Window::setResizable(false); | |||
Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight())); | |||
Window::setTitle("About"); | |||
} | |||
void ImageAboutWindow::setImage(const Image& image) | |||
{ | |||
if (fImgBackground == image) | |||
return; | |||
fImgBackground = image; | |||
Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight())); | |||
} | |||
void ImageAboutWindow::onDisplay() | |||
{ | |||
fImgBackground.draw(); | |||
} | |||
bool ImageAboutWindow::onKeyboard(const KeyboardEvent& ev) | |||
{ | |||
if (ev.press && ev.key == CHAR_ESCAPE) | |||
{ | |||
Window::close(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool ImageAboutWindow::onMouse(const MouseEvent& ev) | |||
{ | |||
if (ev.press) | |||
{ | |||
Window::close(); | |||
return true; | |||
} | |||
return false; | |||
} | |||
void ImageAboutWindow::onReshape(uint width, uint height) | |||
{ | |||
Widget::setSize(width, height); | |||
Window::onReshape(width, height); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -1,190 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 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. | |||
*/ | |||
#include "../ImageButton.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
ImageButton::ImageButton(Window& parent, const Image& image) noexcept | |||
: Widget(parent), | |||
fImageNormal(image), | |||
fImageHover(image), | |||
fImageDown(image), | |||
fCurImage(&fImageNormal), | |||
fCurButton(-1), | |||
fCallback(nullptr), | |||
leakDetector_ImageButton() {} | |||
ImageButton::ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept | |||
: Widget(parent), | |||
fImageNormal(imageNormal), | |||
fImageHover(imageHover), | |||
fImageDown(imageDown), | |||
fCurImage(&fImageNormal), | |||
fCurButton(-1), | |||
fCallback(nullptr), | |||
leakDetector_ImageButton() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize()); | |||
setSize(fCurImage->getSize()); | |||
} | |||
ImageButton::ImageButton(Widget* widget, const Image& image) noexcept | |||
: Widget(widget->getParentWindow()), | |||
fImageNormal(image), | |||
fImageHover(image), | |||
fImageDown(image), | |||
fCurImage(&fImageNormal), | |||
fCurButton(-1), | |||
fCallback(nullptr), | |||
leakDetector_ImageButton() {} | |||
ImageButton::ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown) noexcept | |||
: Widget(widget->getParentWindow()), | |||
fImageNormal(imageNormal), | |||
fImageHover(imageHover), | |||
fImageDown(imageDown), | |||
fCurImage(&fImageNormal), | |||
fCurButton(-1), | |||
fCallback(nullptr), | |||
leakDetector_ImageButton() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize()); | |||
setSize(fCurImage->getSize()); | |||
} | |||
ImageButton::ImageButton(const ImageButton& imageButton) noexcept | |||
: Widget(imageButton.getParentWindow()), | |||
fImageNormal(imageButton.fImageNormal), | |||
fImageHover(imageButton.fImageHover), | |||
fImageDown(imageButton.fImageDown), | |||
fCurImage(&fImageNormal), | |||
fCurButton(-1), | |||
fCallback(imageButton.fCallback), | |||
leakDetector_ImageButton() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize()); | |||
setSize(fCurImage->getSize()); | |||
} | |||
ImageButton& ImageButton::operator=(const ImageButton& imageButton) noexcept | |||
{ | |||
fImageNormal = imageButton.fImageNormal; | |||
fImageHover = imageButton.fImageHover; | |||
fImageDown = imageButton.fImageDown; | |||
fCurImage = &fImageNormal; | |||
fCurButton = -1; | |||
fCallback = imageButton.fCallback; | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageHover.getSize() && fImageHover.getSize() == fImageDown.getSize()); | |||
setSize(fCurImage->getSize()); | |||
return *this; | |||
} | |||
void ImageButton::setCallback(Callback* callback) noexcept | |||
{ | |||
fCallback = callback; | |||
} | |||
void ImageButton::onDisplay() | |||
{ | |||
fCurImage->draw(); | |||
} | |||
bool ImageButton::onMouse(const MouseEvent& ev) | |||
{ | |||
if (fCurButton != -1 && ! ev.press) | |||
{ | |||
if (fCurImage != &fImageNormal) | |||
{ | |||
fCurImage = &fImageNormal; | |||
repaint(); | |||
} | |||
if (! contains(ev.pos)) | |||
{ | |||
fCurButton = -1; | |||
return false; | |||
} | |||
if (fCallback != nullptr) | |||
fCallback->imageButtonClicked(this, fCurButton); | |||
#if 0 | |||
if (contains(ev.pos)) | |||
{ | |||
fCurImage = &fImageHover; | |||
repaint(); | |||
} | |||
#endif | |||
fCurButton = -1; | |||
return true; | |||
} | |||
if (ev.press && contains(ev.pos)) | |||
{ | |||
if (fCurImage != &fImageDown) | |||
{ | |||
fCurImage = &fImageDown; | |||
repaint(); | |||
} | |||
fCurButton = ev.button; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool ImageButton::onMotion(const MotionEvent& ev) | |||
{ | |||
if (fCurButton != -1) | |||
return true; | |||
if (contains(ev.pos)) | |||
{ | |||
if (fCurImage != &fImageHover) | |||
{ | |||
fCurImage = &fImageHover; | |||
repaint(); | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
if (fCurImage != &fImageNormal) | |||
{ | |||
fCurImage = &fImageNormal; | |||
repaint(); | |||
} | |||
return false; | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -1,459 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 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. | |||
*/ | |||
#include "../ImageKnob.hpp" | |||
#include <cmath> | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation) noexcept | |||
: Widget(parent), | |||
fImage(image), | |||
fMinimum(0.0f), | |||
fMaximum(1.0f), | |||
fStep(0.0f), | |||
fValue(0.5f), | |||
fValueDef(fValue), | |||
fValueTmp(fValue), | |||
fUsingDefault(false), | |||
fUsingLog(false), | |||
fOrientation(orientation), | |||
fRotationAngle(0), | |||
fDragging(false), | |||
fLastX(0), | |||
fLastY(0), | |||
fCallback(nullptr), | |||
fIsImgVertical(image.getHeight() > image.getWidth()), | |||
fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), | |||
fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), | |||
fIsReady(false), | |||
fTextureId(0), | |||
leakDetector_ImageKnob() | |||
{ | |||
glGenTextures(1, &fTextureId); | |||
setSize(fImgLayerSize, fImgLayerSize); | |||
} | |||
ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation) noexcept | |||
: Widget(widget->getParentWindow()), | |||
fImage(image), | |||
fMinimum(0.0f), | |||
fMaximum(1.0f), | |||
fStep(0.0f), | |||
fValue(0.5f), | |||
fValueDef(fValue), | |||
fValueTmp(fValue), | |||
fUsingDefault(false), | |||
fUsingLog(false), | |||
fOrientation(orientation), | |||
fRotationAngle(0), | |||
fDragging(false), | |||
fLastX(0), | |||
fLastY(0), | |||
fCallback(nullptr), | |||
fIsImgVertical(image.getHeight() > image.getWidth()), | |||
fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), | |||
fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), | |||
fIsReady(false), | |||
fTextureId(0), | |||
leakDetector_ImageKnob() | |||
{ | |||
glGenTextures(1, &fTextureId); | |||
setSize(fImgLayerSize, fImgLayerSize); | |||
} | |||
ImageKnob::ImageKnob(const ImageKnob& imageKnob) | |||
: Widget(imageKnob.getParentWindow()), | |||
fImage(imageKnob.fImage), | |||
fMinimum(imageKnob.fMinimum), | |||
fMaximum(imageKnob.fMaximum), | |||
fStep(imageKnob.fStep), | |||
fValue(imageKnob.fValue), | |||
fValueDef(imageKnob.fValueDef), | |||
fValueTmp(fValue), | |||
fUsingDefault(imageKnob.fUsingDefault), | |||
fUsingLog(imageKnob.fUsingLog), | |||
fOrientation(imageKnob.fOrientation), | |||
fRotationAngle(imageKnob.fRotationAngle), | |||
fDragging(false), | |||
fLastX(0), | |||
fLastY(0), | |||
fCallback(imageKnob.fCallback), | |||
fIsImgVertical(imageKnob.fIsImgVertical), | |||
fImgLayerSize(imageKnob.fImgLayerSize), | |||
fImgLayerCount(imageKnob.fImgLayerCount), | |||
fIsReady(false), | |||
fTextureId(0), | |||
leakDetector_ImageKnob() | |||
{ | |||
glGenTextures(1, &fTextureId); | |||
setSize(fImgLayerSize, fImgLayerSize); | |||
} | |||
ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) | |||
{ | |||
fImage = imageKnob.fImage; | |||
fMinimum = imageKnob.fMinimum; | |||
fMaximum = imageKnob.fMaximum; | |||
fStep = imageKnob.fStep; | |||
fValue = imageKnob.fValue; | |||
fValueDef = imageKnob.fValueDef; | |||
fValueTmp = fValue; | |||
fUsingDefault = imageKnob.fUsingDefault; | |||
fUsingLog = imageKnob.fUsingLog; | |||
fOrientation = imageKnob.fOrientation; | |||
fRotationAngle = imageKnob.fRotationAngle; | |||
fDragging = false; | |||
fLastX = 0; | |||
fLastY = 0; | |||
fCallback = imageKnob.fCallback; | |||
fIsImgVertical = imageKnob.fIsImgVertical; | |||
fImgLayerSize = imageKnob.fImgLayerSize; | |||
fImgLayerCount = imageKnob.fImgLayerCount; | |||
fIsReady = false; | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
glGenTextures(1, &fTextureId); | |||
setSize(fImgLayerSize, fImgLayerSize); | |||
return *this; | |||
} | |||
ImageKnob::~ImageKnob() | |||
{ | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
} | |||
float ImageKnob::getValue() const noexcept | |||
{ | |||
return fValue; | |||
} | |||
// NOTE: value is assumed to be scaled if using log | |||
void ImageKnob::setDefault(float value) noexcept | |||
{ | |||
fValueDef = value; | |||
fUsingDefault = true; | |||
} | |||
void ImageKnob::setRange(float min, float max) noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(max > min,); | |||
if (fValue < min) | |||
{ | |||
fValue = min; | |||
repaint(); | |||
if (fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageKnobValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange < min"); | |||
} | |||
} | |||
else if (fValue > max) | |||
{ | |||
fValue = max; | |||
repaint(); | |||
if (fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageKnobValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange > max"); | |||
} | |||
} | |||
fMinimum = min; | |||
fMaximum = max; | |||
} | |||
void ImageKnob::setStep(float step) noexcept | |||
{ | |||
fStep = step; | |||
} | |||
// NOTE: value is assumed to be scaled if using log | |||
void ImageKnob::setValue(float value, bool sendCallback) noexcept | |||
{ | |||
if (d_isEqual(fValue, value)) | |||
return; | |||
fValue = value; | |||
if (d_isZero(fStep)) | |||
fValueTmp = value; | |||
if (fRotationAngle == 0) | |||
fIsReady = false; | |||
repaint(); | |||
if (sendCallback && fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageKnobValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageKnob::setValue"); | |||
} | |||
} | |||
void ImageKnob::setUsingLogScale(bool yesNo) noexcept | |||
{ | |||
fUsingLog = yesNo; | |||
} | |||
void ImageKnob::setCallback(Callback* callback) noexcept | |||
{ | |||
fCallback = callback; | |||
} | |||
void ImageKnob::setOrientation(Orientation orientation) noexcept | |||
{ | |||
if (fOrientation == orientation) | |||
return; | |||
fOrientation = orientation; | |||
} | |||
void ImageKnob::setRotationAngle(int angle) | |||
{ | |||
if (fRotationAngle == angle) | |||
return; | |||
fRotationAngle = angle; | |||
fIsReady = false; | |||
} | |||
void ImageKnob::onDisplay() | |||
{ | |||
const float normValue = ((fUsingLog ? _invlogscale(fValue) : fValue) - fMinimum) / (fMaximum - fMinimum); | |||
glEnable(GL_TEXTURE_2D); | |||
glBindTexture(GL_TEXTURE_2D, fTextureId); | |||
if (! fIsReady) | |||
{ | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
uint imageDataOffset = 0; | |||
if (fRotationAngle == 0) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fImgLayerCount > 0,); | |||
DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); | |||
const uint layerDataSize = fImgLayerSize * fImgLayerSize * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3); | |||
/* */ imageDataOffset = layerDataSize * uint(normValue * float(fImgLayerCount-1)); | |||
} | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||
static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||
fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset); | |||
fIsReady = true; | |||
} | |||
const int w = static_cast<int>(getWidth()); | |||
const int h = static_cast<int>(getHeight()); | |||
if (fRotationAngle != 0) | |||
{ | |||
glPushMatrix(); | |||
const int w2 = w/2; | |||
const int h2 = h/2; | |||
glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||
glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f); | |||
Rectangle<int>(-w2, -h2, w, h).draw(); | |||
glPopMatrix(); | |||
} | |||
else | |||
{ | |||
Rectangle<int>(0, 0, w, h).draw(); | |||
} | |||
glBindTexture(GL_TEXTURE_2D, 0); | |||
glDisable(GL_TEXTURE_2D); | |||
} | |||
bool ImageKnob::onMouse(const MouseEvent& ev) | |||
{ | |||
if (ev.button != 1) | |||
return false; | |||
if (ev.press) | |||
{ | |||
if (! contains(ev.pos)) | |||
return false; | |||
if ((ev.mod & MODIFIER_SHIFT) != 0 && fUsingDefault) | |||
{ | |||
setValue(fValueDef, true); | |||
fValueTmp = fValue; | |||
return true; | |||
} | |||
fDragging = true; | |||
fLastX = ev.pos.getX(); | |||
fLastY = ev.pos.getY(); | |||
if (fCallback != nullptr) | |||
fCallback->imageKnobDragStarted(this); | |||
return true; | |||
} | |||
else if (fDragging) | |||
{ | |||
if (fCallback != nullptr) | |||
fCallback->imageKnobDragFinished(this); | |||
fDragging = false; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool ImageKnob::onMotion(const MotionEvent& ev) | |||
{ | |||
if (! fDragging) | |||
return false; | |||
bool doVal = false; | |||
float d, value = 0.0f; | |||
if (fOrientation == ImageKnob::Horizontal) | |||
{ | |||
if (const int movX = ev.pos.getX() - fLastX) | |||
{ | |||
d = (ev.mod & MODIFIER_CTRL) ? 2000.0f : 200.0f; | |||
value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movX)); | |||
doVal = true; | |||
} | |||
} | |||
else if (fOrientation == ImageKnob::Vertical) | |||
{ | |||
if (const int movY = fLastY - ev.pos.getY()) | |||
{ | |||
d = (ev.mod & MODIFIER_CTRL) ? 2000.0f : 200.0f; | |||
value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movY)); | |||
doVal = true; | |||
} | |||
} | |||
if (! doVal) | |||
return false; | |||
if (fUsingLog) | |||
value = _logscale(value); | |||
if (value < fMinimum) | |||
{ | |||
fValueTmp = value = fMinimum; | |||
} | |||
else if (value > fMaximum) | |||
{ | |||
fValueTmp = value = fMaximum; | |||
} | |||
else if (d_isNotZero(fStep)) | |||
{ | |||
fValueTmp = value; | |||
const float rest = std::fmod(value, fStep); | |||
value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); | |||
} | |||
setValue(value, true); | |||
fLastX = ev.pos.getX(); | |||
fLastY = ev.pos.getY(); | |||
return true; | |||
} | |||
bool ImageKnob::onScroll(const ScrollEvent& ev) | |||
{ | |||
if (! contains(ev.pos)) | |||
return false; | |||
const float d = (ev.mod & MODIFIER_CTRL) ? 2000.0f : 200.0f; | |||
float value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * 10.f * ev.delta.getY()); | |||
if (fUsingLog) | |||
value = _logscale(value); | |||
if (value < fMinimum) | |||
{ | |||
fValueTmp = value = fMinimum; | |||
} | |||
else if (value > fMaximum) | |||
{ | |||
fValueTmp = value = fMaximum; | |||
} | |||
else if (d_isNotZero(fStep)) | |||
{ | |||
fValueTmp = value; | |||
const float rest = std::fmod(value, fStep); | |||
value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); | |||
} | |||
setValue(value, true); | |||
return true; | |||
} | |||
// ----------------------------------------------------------------------- | |||
float ImageKnob::_logscale(float value) const | |||
{ | |||
const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); | |||
const float a = fMaximum/std::exp(fMaximum*b); | |||
return a * std::exp(b*value); | |||
} | |||
float ImageKnob::_invlogscale(float value) const | |||
{ | |||
const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); | |||
const float a = fMaximum/std::exp(fMaximum*b); | |||
return std::log(value/a)/b; | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -1,399 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 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. | |||
*/ | |||
#include "../ImageSlider.hpp" | |||
#include <cmath> | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept | |||
: Widget(parent), | |||
fImage(image), | |||
fMinimum(0.0f), | |||
fMaximum(1.0f), | |||
fStep(0.0f), | |||
fValue(0.5f), | |||
fValueTmp(fValue), | |||
fDragging(false), | |||
fInverted(false), | |||
fStartedX(0), | |||
fStartedY(0), | |||
fCallback(nullptr), | |||
fStartPos(), | |||
fEndPos(), | |||
fSliderArea(), | |||
leakDetector_ImageSlider() | |||
{ | |||
Widget::setNeedsFullViewport(true); | |||
} | |||
ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept | |||
: Widget(widget->getParentWindow()), | |||
fImage(image), | |||
fMinimum(0.0f), | |||
fMaximum(1.0f), | |||
fStep(0.0f), | |||
fValue(0.5f), | |||
fValueTmp(fValue), | |||
fDragging(false), | |||
fInverted(false), | |||
fStartedX(0), | |||
fStartedY(0), | |||
fCallback(nullptr), | |||
fStartPos(), | |||
fEndPos(), | |||
fSliderArea(), | |||
leakDetector_ImageSlider() | |||
{ | |||
Widget::setNeedsFullViewport(true); | |||
} | |||
ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept | |||
: Widget(imageSlider.getParentWindow()), | |||
fImage(imageSlider.fImage), | |||
fMinimum(imageSlider.fMinimum), | |||
fMaximum(imageSlider.fMaximum), | |||
fStep(imageSlider.fStep), | |||
fValue(imageSlider.fValue), | |||
fValueTmp(fValue), | |||
fDragging(false), | |||
fInverted(imageSlider.fInverted), | |||
fStartedX(0), | |||
fStartedY(0), | |||
fCallback(imageSlider.fCallback), | |||
fStartPos(imageSlider.fStartPos), | |||
fEndPos(imageSlider.fEndPos), | |||
fSliderArea(imageSlider.fSliderArea), | |||
leakDetector_ImageSlider() | |||
{ | |||
Widget::setNeedsFullViewport(true); | |||
} | |||
ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept | |||
{ | |||
fImage = imageSlider.fImage; | |||
fMinimum = imageSlider.fMinimum; | |||
fMaximum = imageSlider.fMaximum; | |||
fStep = imageSlider.fStep; | |||
fValue = imageSlider.fValue; | |||
fValueTmp = fValue; | |||
fDragging = false; | |||
fInverted = imageSlider.fInverted; | |||
fStartedX = 0; | |||
fStartedY = 0; | |||
fCallback = imageSlider.fCallback; | |||
fStartPos = imageSlider.fStartPos; | |||
fEndPos = imageSlider.fEndPos; | |||
fSliderArea = imageSlider.fSliderArea; | |||
return *this; | |||
} | |||
float ImageSlider::getValue() const noexcept | |||
{ | |||
return fValue; | |||
} | |||
void ImageSlider::setStartPos(const Point<int>& startPos) noexcept | |||
{ | |||
fStartPos = startPos; | |||
_recheckArea(); | |||
} | |||
void ImageSlider::setStartPos(int x, int y) noexcept | |||
{ | |||
setStartPos(Point<int>(x, y)); | |||
} | |||
void ImageSlider::setEndPos(const Point<int>& endPos) noexcept | |||
{ | |||
fEndPos = endPos; | |||
_recheckArea(); | |||
} | |||
void ImageSlider::setEndPos(int x, int y) noexcept | |||
{ | |||
setEndPos(Point<int>(x, y)); | |||
} | |||
void ImageSlider::setInverted(bool inverted) noexcept | |||
{ | |||
if (fInverted == inverted) | |||
return; | |||
fInverted = inverted; | |||
repaint(); | |||
} | |||
void ImageSlider::setRange(float min, float max) noexcept | |||
{ | |||
if (fValue < min) | |||
{ | |||
fValue = min; | |||
repaint(); | |||
if (fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageSliderValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min"); | |||
} | |||
} | |||
else if (fValue > max) | |||
{ | |||
fValue = max; | |||
repaint(); | |||
if (fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageSliderValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max"); | |||
} | |||
} | |||
fMinimum = min; | |||
fMaximum = max; | |||
} | |||
void ImageSlider::setStep(float step) noexcept | |||
{ | |||
fStep = step; | |||
} | |||
void ImageSlider::setValue(float value, bool sendCallback) noexcept | |||
{ | |||
if (d_isEqual(fValue, value)) | |||
return; | |||
fValue = value; | |||
if (d_isZero(fStep)) | |||
fValueTmp = value; | |||
repaint(); | |||
if (sendCallback && fCallback != nullptr) | |||
{ | |||
try { | |||
fCallback->imageSliderValueChanged(this, fValue); | |||
} DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue"); | |||
} | |||
} | |||
void ImageSlider::setCallback(Callback* callback) noexcept | |||
{ | |||
fCallback = callback; | |||
} | |||
void ImageSlider::onDisplay() | |||
{ | |||
#if 0 // DEBUG, paints slider area | |||
glColor3f(0.4f, 0.5f, 0.1f); | |||
glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight()); | |||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
#endif | |||
const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); | |||
int x, y; | |||
if (fStartPos.getY() == fEndPos.getY()) | |||
{ | |||
// horizontal | |||
if (fInverted) | |||
x = fEndPos.getX() - static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||
else | |||
x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); | |||
y = fStartPos.getY(); | |||
} | |||
else | |||
{ | |||
// vertical | |||
x = fStartPos.getX(); | |||
if (fInverted) | |||
y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); | |||
else | |||
y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); | |||
} | |||
fImage.drawAt(x, y); | |||
} | |||
bool ImageSlider::onMouse(const MouseEvent& ev) | |||
{ | |||
if (ev.button != 1) | |||
return false; | |||
if (ev.press) | |||
{ | |||
if (! fSliderArea.contains(ev.pos)) | |||
return false; | |||
float vper; | |||
const int x = ev.pos.getX(); | |||
const int y = ev.pos.getY(); | |||
if (fStartPos.getY() == fEndPos.getY()) | |||
{ | |||
// horizontal | |||
vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); | |||
} | |||
else | |||
{ | |||
// vertical | |||
vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); | |||
} | |||
float value; | |||
if (fInverted) | |||
value = fMaximum - vper * (fMaximum - fMinimum); | |||
else | |||
value = fMinimum + vper * (fMaximum - fMinimum); | |||
if (value < fMinimum) | |||
{ | |||
fValueTmp = value = fMinimum; | |||
} | |||
else if (value > fMaximum) | |||
{ | |||
fValueTmp = value = fMaximum; | |||
} | |||
else if (d_isNotZero(fStep)) | |||
{ | |||
fValueTmp = value; | |||
const float rest = std::fmod(value, fStep); | |||
value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); | |||
} | |||
fDragging = true; | |||
fStartedX = x; | |||
fStartedY = y; | |||
if (fCallback != nullptr) | |||
fCallback->imageSliderDragStarted(this); | |||
setValue(value, true); | |||
return true; | |||
} | |||
else if (fDragging) | |||
{ | |||
if (fCallback != nullptr) | |||
fCallback->imageSliderDragFinished(this); | |||
fDragging = false; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool ImageSlider::onMotion(const MotionEvent& ev) | |||
{ | |||
if (! fDragging) | |||
return false; | |||
const bool horizontal = fStartPos.getY() == fEndPos.getY(); | |||
const int x = ev.pos.getX(); | |||
const int y = ev.pos.getY(); | |||
if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal)) | |||
{ | |||
float vper; | |||
if (horizontal) | |||
{ | |||
// horizontal | |||
vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); | |||
} | |||
else | |||
{ | |||
// vertical | |||
vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); | |||
} | |||
float value; | |||
if (fInverted) | |||
value = fMaximum - vper * (fMaximum - fMinimum); | |||
else | |||
value = fMinimum + vper * (fMaximum - fMinimum); | |||
if (value < fMinimum) | |||
{ | |||
fValueTmp = value = fMinimum; | |||
} | |||
else if (value > fMaximum) | |||
{ | |||
fValueTmp = value = fMaximum; | |||
} | |||
else if (d_isNotZero(fStep)) | |||
{ | |||
fValueTmp = value; | |||
const float rest = std::fmod(value, fStep); | |||
value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); | |||
} | |||
setValue(value, true); | |||
} | |||
else if (horizontal) | |||
{ | |||
if (x < fSliderArea.getX()) | |||
setValue(fInverted ? fMaximum : fMinimum, true); | |||
else | |||
setValue(fInverted ? fMinimum : fMaximum, true); | |||
} | |||
else | |||
{ | |||
if (y < fSliderArea.getY()) | |||
setValue(fInverted ? fMaximum : fMinimum, true); | |||
else | |||
setValue(fInverted ? fMinimum : fMaximum, true); | |||
} | |||
return true; | |||
} | |||
void ImageSlider::_recheckArea() noexcept | |||
{ | |||
if (fStartPos.getY() == fEndPos.getY()) | |||
{ | |||
// horizontal | |||
fSliderArea = Rectangle<int>(fStartPos.getX(), | |||
fStartPos.getY(), | |||
fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(), | |||
static_cast<int>(fImage.getHeight())); | |||
} | |||
else | |||
{ | |||
// vertical | |||
fSliderArea = Rectangle<int>(fStartPos.getX(), | |||
fStartPos.getY(), | |||
static_cast<int>(fImage.getWidth()), | |||
fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY()); | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -1,122 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 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. | |||
*/ | |||
#include "../ImageSwitch.hpp" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept | |||
: Widget(parent), | |||
fImageNormal(imageNormal), | |||
fImageDown(imageDown), | |||
fIsDown(false), | |||
fCallback(nullptr), | |||
leakDetector_ImageSwitch() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); | |||
setSize(fImageNormal.getSize()); | |||
} | |||
ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept | |||
: Widget(widget->getParentWindow()), | |||
fImageNormal(imageNormal), | |||
fImageDown(imageDown), | |||
fIsDown(false), | |||
fCallback(nullptr), | |||
leakDetector_ImageSwitch() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); | |||
setSize(fImageNormal.getSize()); | |||
} | |||
ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept | |||
: Widget(imageSwitch.getParentWindow()), | |||
fImageNormal(imageSwitch.fImageNormal), | |||
fImageDown(imageSwitch.fImageDown), | |||
fIsDown(imageSwitch.fIsDown), | |||
fCallback(imageSwitch.fCallback), | |||
leakDetector_ImageSwitch() | |||
{ | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); | |||
setSize(fImageNormal.getSize()); | |||
} | |||
ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept | |||
{ | |||
fImageNormal = imageSwitch.fImageNormal; | |||
fImageDown = imageSwitch.fImageDown; | |||
fIsDown = imageSwitch.fIsDown; | |||
fCallback = imageSwitch.fCallback; | |||
DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); | |||
setSize(fImageNormal.getSize()); | |||
return *this; | |||
} | |||
bool ImageSwitch::isDown() const noexcept | |||
{ | |||
return fIsDown; | |||
} | |||
void ImageSwitch::setDown(bool down) noexcept | |||
{ | |||
if (fIsDown == down) | |||
return; | |||
fIsDown = down; | |||
repaint(); | |||
} | |||
void ImageSwitch::setCallback(Callback* callback) noexcept | |||
{ | |||
fCallback = callback; | |||
} | |||
void ImageSwitch::onDisplay() | |||
{ | |||
if (fIsDown) | |||
fImageNormal.draw(); | |||
else | |||
fImageDown.draw(); | |||
} | |||
bool ImageSwitch::onMouse(const MouseEvent& ev) | |||
{ | |||
if (ev.press && contains(ev.pos)) | |||
{ | |||
fIsDown = !fIsDown; | |||
repaint(); | |||
if (fCallback != nullptr) | |||
fCallback->imageSwitchClicked(this, fIsDown); | |||
return true; | |||
} | |||
return false; | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -15,7 +15,7 @@ | |||
*/ | |||
#include "../NanoVG.hpp" | |||
#include "../Window.hpp" | |||
#include "WidgetPrivateData.hpp" | |||
// ----------------------------------------------------------------------- | |||
// Ignore some warnings if debugging | |||
@@ -43,7 +43,8 @@ | |||
// ----------------------------------------------------------------------- | |||
// Include NanoVG OpenGL implementation | |||
#define NANOVG_GL2_IMPLEMENTATION 1 | |||
//#define STB_IMAGE_STATIC | |||
#define NANOVG_GL2_IMPLEMENTATION | |||
#include "nanovg/nanovg_gl.h" | |||
#if defined(NANOVG_GL2) | |||
@@ -76,52 +77,41 @@ | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
// Paint | |||
// NanoImage | |||
NanoVG::Paint::Paint() noexcept | |||
: radius(0.0f), feather(0.0f), innerColor(), outerColor(), imageId(0), repeat(REPEAT_NONE) | |||
NanoImage::NanoImage() | |||
: fHandle(), | |||
fSize() {} | |||
NanoImage::NanoImage(const Handle& handle) | |||
: fHandle(handle), | |||
fSize() | |||
{ | |||
std::memset(xform, 0, sizeof(float)*6); | |||
std::memset(extent, 0, sizeof(float)*2); | |||
DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,); | |||
_updateSize(); | |||
} | |||
NanoVG::Paint::Paint(const NVGpaint& p) noexcept | |||
: radius(p.radius), feather(p.feather), innerColor(p.innerColor), outerColor(p.outerColor), imageId(p.image), repeat(static_cast<PatternRepeat>(p.repeat)) | |||
NanoImage::~NanoImage() | |||
{ | |||
std::memcpy(xform, p.xform, sizeof(float)*6); | |||
std::memcpy(extent, p.extent, sizeof(float)*2); | |||
if (fHandle.context != nullptr && fHandle.imageId != 0) | |||
nvgDeleteImage(fHandle.context, fHandle.imageId); | |||
} | |||
NanoVG::Paint::operator NVGpaint() const noexcept | |||
NanoImage& NanoImage::operator=(const Handle& handle) | |||
{ | |||
NVGpaint p; | |||
p.radius = radius; | |||
p.feather = feather; | |||
p.innerColor = innerColor; | |||
p.outerColor = outerColor; | |||
p.image = imageId; | |||
p.repeat = repeat; | |||
std::memcpy(p.xform, xform, sizeof(float)*6); | |||
std::memcpy(p.extent, extent, sizeof(float)*2); | |||
return p; | |||
} | |||
if (fHandle.context != nullptr && fHandle.imageId != 0) | |||
nvgDeleteImage(fHandle.context, fHandle.imageId); | |||
// ----------------------------------------------------------------------- | |||
// NanoImage | |||
fHandle.context = handle.context; | |||
fHandle.imageId = handle.imageId; | |||
NanoImage::NanoImage(NVGcontext* const context, const int imageId) noexcept | |||
: fContext(context), | |||
fImageId(imageId), | |||
fSize(), | |||
leakDetector_NanoImage() | |||
{ | |||
_updateSize(); | |||
return *this; | |||
} | |||
NanoImage::~NanoImage() | |||
bool NanoImage::isValid() const noexcept | |||
{ | |||
if (fContext != nullptr && fImageId != 0) | |||
nvgDeleteImage(fContext, fImageId); | |||
return (fHandle.context != nullptr && fHandle.imageId != 0); | |||
} | |||
Size<uint> NanoImage::getSize() const noexcept | |||
@@ -129,69 +119,91 @@ Size<uint> NanoImage::getSize() const noexcept | |||
return fSize; | |||
} | |||
void NanoImage::updateImage(const uchar* const data) | |||
GLuint NanoImage::getTextureHandle() const | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0, 0); | |||
if (fContext != nullptr && fImageId != 0) | |||
{ | |||
nvgUpdateImage(fContext, fImageId, data); | |||
_updateSize(); | |||
} | |||
return nvglImageHandle(fHandle.context, fHandle.imageId); | |||
} | |||
void NanoImage::_updateSize() | |||
{ | |||
int w=0, h=0; | |||
if (fContext != nullptr && fImageId != 0) | |||
{ | |||
nvgImageSize(fContext, fImageId, &w, &h); | |||
nvgImageSize(fHandle.context, fHandle.imageId, &w, &h); | |||
if (w < 0) w = 0; | |||
if (h < 0) h = 0; | |||
} | |||
if (w < 0) w = 0; | |||
if (h < 0) h = 0; | |||
fSize.setSize(static_cast<uint>(w), static_cast<uint>(h)); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Paint | |||
NanoVG::Paint::Paint() noexcept | |||
: radius(0.0f), feather(0.0f), innerColor(), outerColor(), imageId(0) | |||
{ | |||
std::memset(xform, 0, sizeof(float)*6); | |||
std::memset(extent, 0, sizeof(float)*2); | |||
} | |||
NanoVG::Paint::Paint(const NVGpaint& p) noexcept | |||
: radius(p.radius), feather(p.feather), innerColor(p.innerColor), outerColor(p.outerColor), imageId(p.image) | |||
{ | |||
std::memcpy(xform, p.xform, sizeof(float)*6); | |||
std::memcpy(extent, p.extent, sizeof(float)*2); | |||
} | |||
NanoVG::Paint::operator NVGpaint() const noexcept | |||
{ | |||
NVGpaint p; | |||
p.radius = radius; | |||
p.feather = feather; | |||
p.innerColor = innerColor; | |||
p.outerColor = outerColor; | |||
p.image = imageId; | |||
std::memcpy(p.xform, xform, sizeof(float)*6); | |||
std::memcpy(p.extent, extent, sizeof(float)*2); | |||
return p; | |||
} | |||
// ----------------------------------------------------------------------- | |||
// NanoVG | |||
NanoVG::NanoVG() | |||
: fContext(nvgCreateGL(512, 512, NVG_ANTIALIAS)), | |||
NanoVG::NanoVG(int flags) | |||
: fContext(nvgCreateGL(flags)), | |||
fInFrame(false), | |||
leakDetector_NanoVG() | |||
fIsSubWidget(false) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,); | |||
} | |||
NanoVG::NanoVG(const int textAtlasWidth, const int textAtlasHeight) | |||
: fContext(nvgCreateGL(textAtlasWidth, textAtlasHeight, NVG_ANTIALIAS)), | |||
NanoVG::NanoVG(NanoWidget* groupWidget) | |||
: fContext(groupWidget->fContext), | |||
fInFrame(false), | |||
leakDetector_NanoVG() | |||
fIsSubWidget(true) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,); | |||
} | |||
NanoVG::~NanoVG() | |||
{ | |||
DISTRHO_SAFE_ASSERT(! fInFrame); | |||
if (fContext != nullptr) | |||
if (fContext != nullptr && ! fIsSubWidget) | |||
nvgDeleteGL(fContext); | |||
} | |||
// ----------------------------------------------------------------------- | |||
void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor, const Alpha alpha) | |||
void NanoVG::beginFrame(const uint width, const uint height, const float scaleFactor) | |||
{ | |||
if (fContext == nullptr) return; | |||
DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,); | |||
DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); | |||
fInFrame = true; | |||
nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor, static_cast<NVGalpha>(alpha)); | |||
nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor); | |||
} | |||
void NanoVG::beginFrame(Widget* const widget) | |||
@@ -203,16 +215,41 @@ void NanoVG::beginFrame(Widget* const widget) | |||
Window& window(widget->getParentWindow()); | |||
fInFrame = true; | |||
nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f, NVG_PREMULTIPLIED_ALPHA); | |||
nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f); | |||
} | |||
void NanoVG::cancelFrame() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fInFrame,); | |||
if (fContext != nullptr) | |||
nvgCancelFrame(fContext); | |||
fInFrame = false; | |||
} | |||
void NanoVG::endFrame() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fInFrame,); | |||
// Save current blend state | |||
GLboolean blendEnabled; | |||
GLint blendSrc, blendDst; | |||
glGetBooleanv(GL_BLEND, &blendEnabled); | |||
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrc); | |||
glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDst); | |||
if (fContext != nullptr) | |||
nvgEndFrame(fContext); | |||
// Restore blend state | |||
if (blendEnabled) | |||
glEnable(GL_BLEND); | |||
else | |||
glDisable(GL_BLEND); | |||
glBlendFunc(blendSrc, blendDst); | |||
fInFrame = false; | |||
} | |||
@@ -336,6 +373,12 @@ void NanoVG::lineJoin(NanoVG::LineCap join) | |||
nvgLineJoin(fContext, join); | |||
} | |||
void NanoVG::globalAlpha(float alpha) | |||
{ | |||
if (fContext != nullptr) | |||
nvgGlobalAlpha(fContext, alpha); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Transforms | |||
@@ -459,38 +502,65 @@ float NanoVG::radToDeg(float rad) | |||
// ----------------------------------------------------------------------- | |||
// Images | |||
NanoImage* NanoVG::createImage(const char* filename) | |||
NanoImage::Handle NanoVG::createImageFromFile(const char* filename, ImageFlags imageFlags) | |||
{ | |||
return createImageFromFile(filename, static_cast<int>(imageFlags)); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromFile(const char* filename, int imageFlags) | |||
{ | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', NanoImage::Handle()); | |||
return NanoImage::Handle(fContext, nvgCreateImage(fContext, filename, imageFlags)); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags) | |||
{ | |||
return createImageFromMemory(data, dataSize, static_cast<int>(imageFlags)); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int imageFlags) | |||
{ | |||
if (fContext == nullptr) return nullptr; | |||
DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr); | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); | |||
DISTRHO_SAFE_ASSERT_RETURN(dataSize > 0, NanoImage::Handle()); | |||
if (const int imageId = nvgCreateImage(fContext, filename)) | |||
return new NanoImage(fContext, imageId); | |||
return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize))); | |||
} | |||
return nullptr; | |||
NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags) | |||
{ | |||
return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags)); | |||
} | |||
NanoImage* NanoVG::createImageMem(uchar* data, int ndata) | |||
NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags) | |||
{ | |||
if (fContext == nullptr) return nullptr; | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr); | |||
DISTRHO_SAFE_ASSERT_RETURN(ndata > 0, nullptr); | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); | |||
if (const int imageId = nvgCreateImageMem(fContext, data, ndata)) | |||
return new NanoImage(fContext, imageId); | |||
return NanoImage::Handle(fContext, nvgCreateImageRGBA(fContext, | |||
static_cast<int>(w), | |||
static_cast<int>(h), imageFlags, data)); | |||
} | |||
return nullptr; | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture) | |||
{ | |||
return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture); | |||
} | |||
NanoImage* NanoVG::createImageRGBA(uint w, uint h, const uchar* data) | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture) | |||
{ | |||
if (fContext == nullptr) return nullptr; | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr); | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle()); | |||
if (const int imageId = nvgCreateImageRGBA(fContext, static_cast<int>(w), static_cast<int>(h), data)) | |||
return new NanoImage(fContext, imageId); | |||
if (! deleteTexture) | |||
imageFlags |= NVG_IMAGE_NODELETE; | |||
return nullptr; | |||
return NanoImage::Handle(fContext, nvglCreateImageFromHandle(fContext, | |||
textureId, | |||
static_cast<int>(w), | |||
static_cast<int>(h), imageFlags)); | |||
} | |||
// ----------------------------------------------------------------------- | |||
@@ -514,12 +584,14 @@ NanoVG::Paint NanoVG::radialGradient(float cx, float cy, float inr, float outr, | |||
return nvgRadialGradient(fContext, cx, cy, inr, outr, icol, ocol); | |||
} | |||
NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage* image, NanoVG::PatternRepeat repeat) | |||
NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha) | |||
{ | |||
if (fContext == nullptr) return Paint(); | |||
DISTRHO_SAFE_ASSERT_RETURN(image != nullptr, Paint()); | |||
return nvgImagePattern(fContext, ox, oy, ex, ey, angle, image->fImageId, repeat); | |||
const int imageId(image.fHandle.imageId); | |||
DISTRHO_SAFE_ASSERT_RETURN(imageId != 0, Paint()); | |||
return nvgImagePattern(fContext, ox, oy, ex, ey, angle, imageId, alpha); | |||
} | |||
// ----------------------------------------------------------------------- | |||
@@ -531,6 +603,12 @@ void NanoVG::scissor(float x, float y, float w, float h) | |||
nvgScissor(fContext, x, y, w, h); | |||
} | |||
void NanoVG::intersectScissor(float x, float y, float w, float h) | |||
{ | |||
if (fContext != nullptr) | |||
nvgIntersectScissor(fContext, x, y, w, h); | |||
} | |||
void NanoVG::resetScissor() | |||
{ | |||
if (fContext != nullptr) | |||
@@ -564,6 +642,12 @@ void NanoVG::bezierTo(float c1x, float c1y, float c2x, float c2y, float x, float | |||
nvgBezierTo(fContext, c1x, c1y, c2x, c2y, x, y); | |||
} | |||
void NanoVG::quadTo(float cx, float cy, float x, float y) | |||
{ | |||
if (fContext != nullptr) | |||
nvgQuadTo(fContext, cx, cy, x, y); | |||
} | |||
void NanoVG::arcTo(float x1, float y1, float x2, float y2, float radius) | |||
{ | |||
if (fContext != nullptr) | |||
@@ -627,7 +711,7 @@ void NanoVG::stroke() | |||
// ----------------------------------------------------------------------- | |||
// Text | |||
NanoVG::FontId NanoVG::createFont(const char* name, const char* filename) | |||
NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename) | |||
{ | |||
if (fContext == nullptr) return -1; | |||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | |||
@@ -636,13 +720,13 @@ NanoVG::FontId NanoVG::createFont(const char* name, const char* filename) | |||
return nvgCreateFont(fContext, name, filename); | |||
} | |||
NanoVG::FontId NanoVG::createFontMem(const char* name, const uchar* data, int ndata, bool freeData) | |||
NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData) | |||
{ | |||
if (fContext == nullptr) return -1; | |||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1); | |||
return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), ndata, freeData); | |||
return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), static_cast<int>(dataSize), freeData); | |||
} | |||
NanoVG::FontId NanoVG::findFont(const char* name) | |||
@@ -740,7 +824,7 @@ float NanoVG::textBounds(float x, float y, const char* string, const char* end, | |||
return ret; | |||
} | |||
void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds) | |||
void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4]) | |||
{ | |||
if (fContext == nullptr) return; | |||
DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',); | |||
@@ -748,12 +832,12 @@ void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* st | |||
nvgTextBoxBounds(fContext, x, y, breakRowWidth, string, end, bounds); | |||
} | |||
int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition* positions, int maxPositions) | |||
int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition& positions, int maxPositions) | |||
{ | |||
if (fContext == nullptr) return 0; | |||
DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0); | |||
return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)positions, maxPositions); | |||
return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)&positions, maxPositions); | |||
} | |||
void NanoVG::textMetrics(float* ascender, float* descender, float* lineh) | |||
@@ -762,15 +846,75 @@ void NanoVG::textMetrics(float* ascender, float* descender, float* lineh) | |||
nvgTextMetrics(fContext, ascender, descender, lineh); | |||
} | |||
int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow* rows, int maxRows) | |||
int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow& rows, int maxRows) | |||
{ | |||
if (fContext != nullptr) | |||
return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)rows, maxRows); | |||
return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)&rows, maxRows); | |||
return 0; | |||
} | |||
// ----------------------------------------------------------------------- | |||
struct NanoWidget::PrivateData { | |||
NanoWidget* const self; | |||
std::vector<NanoWidget*> subWidgets; | |||
PrivateData(NanoWidget* const s) | |||
: self(s), | |||
subWidgets() {} | |||
~PrivateData() | |||
{ | |||
subWidgets.clear(); | |||
} | |||
}; | |||
NanoWidget::NanoWidget(Window& parent, int flags) | |||
: Widget(parent), | |||
NanoVG(flags), | |||
nData(new PrivateData(this)) | |||
{ | |||
pData->needsScaling = true; | |||
} | |||
NanoWidget::NanoWidget(Widget* groupWidget, int flags) | |||
: Widget(groupWidget, true), | |||
NanoVG(flags), | |||
nData(new PrivateData(this)) | |||
{ | |||
pData->needsScaling = true; | |||
} | |||
NanoWidget::NanoWidget(NanoWidget* groupWidget) | |||
: Widget(groupWidget, false), | |||
NanoVG(groupWidget), | |||
nData(new PrivateData(this)) | |||
{ | |||
pData->needsScaling = true; | |||
groupWidget->nData->subWidgets.push_back(this); | |||
} | |||
NanoWidget::~NanoWidget() | |||
{ | |||
delete nData; | |||
} | |||
void NanoWidget::onDisplay() | |||
{ | |||
NanoVG::beginFrame(getWidth(), getHeight()); | |||
onNanoDisplay(); | |||
for (std::vector<NanoWidget*>::iterator it = nData->subWidgets.begin(); it != nData->subWidgets.end(); ++it) | |||
{ | |||
NanoWidget* const widget(*it); | |||
widget->onNanoDisplay(); | |||
} | |||
NanoVG::endFrame(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
extern "C" { | |||
@@ -0,0 +1,144 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#include "../NanoWidgets.hpp" | |||
#include "Common.hpp" | |||
#define BLENDISH_IMPLEMENTATION | |||
#include "nanovg/nanovg.h" | |||
#include "oui-blendish/blendish.h" | |||
#include "oui-blendish/blendish_resources.h" | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
static void registerBlendishResourcesIfNeeded(NVGcontext* const context) | |||
{ | |||
if (nvgFindFont(context, "__dpf_blendish__") >= 0) | |||
return; | |||
using namespace blendish_resources; | |||
bndSetFont(nvgCreateFontMem(context, "__dpf_blendish__", (const uchar*)dejavusans_ttf, dejavusans_ttf_size, 0)); | |||
bndSetIconImage(nvgCreateImageMem(context, 0, (const uchar*)blender_icons16_png, blender_icons16_png_size)); | |||
} | |||
// ----------------------------------------------------------------------- | |||
struct BlendishButton::PrivateData { | |||
ButtonImpl impl; | |||
int iconId; | |||
DISTRHO_NAMESPACE::String text; | |||
PrivateData(Widget* const s, const char* const t, const int i) noexcept | |||
: impl(s), | |||
iconId(i), | |||
text(t) {} | |||
DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
BlendishButton::BlendishButton(Window& parent, const char* text, int iconId) | |||
: NanoWidget(parent), | |||
pData(new PrivateData(this, text, iconId)) | |||
{ | |||
registerBlendishResourcesIfNeeded(getContext()); | |||
_updateBounds(); | |||
} | |||
BlendishButton::BlendishButton(NanoWidget* widget, const char* text, int iconId) | |||
: NanoWidget(widget), | |||
pData(new PrivateData(this, text, iconId)) | |||
{ | |||
registerBlendishResourcesIfNeeded(getContext()); | |||
_updateBounds(); | |||
} | |||
BlendishButton::~BlendishButton() | |||
{ | |||
delete pData; | |||
} | |||
int BlendishButton::getIconId() const noexcept | |||
{ | |||
return pData->iconId; | |||
} | |||
void BlendishButton::setIconId(int iconId) noexcept | |||
{ | |||
if (pData->iconId == iconId) | |||
return; | |||
pData->iconId = iconId; | |||
_updateBounds(); | |||
repaint(); | |||
} | |||
const char* BlendishButton::getText() const noexcept | |||
{ | |||
return pData->text; | |||
} | |||
void BlendishButton::setText(const char* text) noexcept | |||
{ | |||
if (pData->text == text) | |||
return; | |||
pData->text = text; | |||
_updateBounds(); | |||
repaint(); | |||
} | |||
void BlendishButton::setCallback(Callback* callback) noexcept | |||
{ | |||
pData->impl.callback_b = callback; | |||
} | |||
void BlendishButton::onNanoDisplay() | |||
{ | |||
bndToolButton(getContext(), | |||
getAbsoluteX(), getAbsoluteY(), getWidth(), getHeight(), | |||
0, static_cast<BNDwidgetState>(pData->impl.state), pData->iconId, pData->text); | |||
} | |||
bool BlendishButton::onMouse(const MouseEvent& ev) | |||
{ | |||
return pData->impl.onMouse(ev); | |||
} | |||
bool BlendishButton::onMotion(const MotionEvent& ev) | |||
{ | |||
return pData->impl.onMotion(ev); | |||
} | |||
void BlendishButton::_updateBounds() | |||
{ | |||
const float width = bndLabelWidth (getContext(), pData->iconId, pData->text); | |||
const float height = bndLabelHeight(getContext(), pData->iconId, pData->text, width); | |||
setSize(width, height); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#include "oui-blendish/blendish_resources.cpp" | |||
// ----------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -14,8 +14,7 @@ | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#include "../Widget.hpp" | |||
#include "../Window.hpp" | |||
#include "WidgetPrivateData.hpp" | |||
START_NAMESPACE_DGL | |||
@@ -23,35 +22,41 @@ START_NAMESPACE_DGL | |||
// Widget | |||
Widget::Widget(Window& parent) | |||
: fParent(parent), | |||
fNeedsFullViewport(false), | |||
fNeedsScaling(false), | |||
fVisible(true), | |||
fId(0), | |||
fAbsolutePos(0, 0), | |||
fSize(0, 0), | |||
leakDetector_Widget() | |||
: pData(new PrivateData(this, parent, nullptr, false)) | |||
{ | |||
fParent._addWidget(this); | |||
parent._addWidget(this); | |||
} | |||
Widget::Widget(Widget* groupWidget) | |||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, true)) | |||
{ | |||
pData->parent._addWidget(this); | |||
} | |||
Widget::Widget(Widget* groupWidget, bool addToSubWidgets) | |||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, addToSubWidgets)) | |||
{ | |||
pData->parent._addWidget(this); | |||
} | |||
Widget::~Widget() | |||
{ | |||
fParent._removeWidget(this); | |||
pData->parent._removeWidget(this); | |||
delete pData; | |||
} | |||
bool Widget::isVisible() const noexcept | |||
{ | |||
return fVisible; | |||
return pData->visible; | |||
} | |||
void Widget::setVisible(bool yesNo) | |||
{ | |||
if (fVisible == yesNo) | |||
if (pData->visible == yesNo) | |||
return; | |||
fVisible = yesNo; | |||
fParent.repaint(); | |||
pData->visible = yesNo; | |||
pData->parent.repaint(); | |||
} | |||
void Widget::show() | |||
@@ -66,47 +71,47 @@ void Widget::hide() | |||
uint Widget::getWidth() const noexcept | |||
{ | |||
return fSize.getWidth(); | |||
return pData->size.getWidth(); | |||
} | |||
uint Widget::getHeight() const noexcept | |||
{ | |||
return fSize.getHeight(); | |||
return pData->size.getHeight(); | |||
} | |||
const Size<uint>& Widget::getSize() const noexcept | |||
{ | |||
return fSize; | |||
return pData->size; | |||
} | |||
void Widget::setWidth(uint width) noexcept | |||
{ | |||
if (fSize.getWidth() == width) | |||
if (pData->size.getWidth() == width) | |||
return; | |||
ResizeEvent ev; | |||
ev.oldSize = fSize; | |||
ev.size = Size<uint>(width, fSize.getHeight()); | |||
ev.oldSize = pData->size; | |||
ev.size = Size<uint>(width, pData->size.getHeight()); | |||
fSize.setWidth(width); | |||
pData->size.setWidth(width); | |||
onResize(ev); | |||
fParent.repaint(); | |||
pData->parent.repaint(); | |||
} | |||
void Widget::setHeight(uint height) noexcept | |||
{ | |||
if (fSize.getHeight() == height) | |||
if (pData->size.getHeight() == height) | |||
return; | |||
ResizeEvent ev; | |||
ev.oldSize = fSize; | |||
ev.size = Size<uint>(fSize.getWidth(), height); | |||
ev.oldSize = pData->size; | |||
ev.size = Size<uint>(pData->size.getWidth(), height); | |||
fSize.setHeight(height); | |||
pData->size.setHeight(height); | |||
onResize(ev); | |||
fParent.repaint(); | |||
pData->parent.repaint(); | |||
} | |||
void Widget::setSize(uint width, uint height) noexcept | |||
@@ -116,50 +121,50 @@ void Widget::setSize(uint width, uint height) noexcept | |||
void Widget::setSize(const Size<uint>& size) noexcept | |||
{ | |||
if (fSize == size) | |||
if (pData->size == size) | |||
return; | |||
ResizeEvent ev; | |||
ev.oldSize = fSize; | |||
ev.oldSize = pData->size; | |||
ev.size = size; | |||
fSize = size; | |||
pData->size = size; | |||
onResize(ev); | |||
fParent.repaint(); | |||
pData->parent.repaint(); | |||
} | |||
int Widget::getAbsoluteX() const noexcept | |||
{ | |||
return fAbsolutePos.getX(); | |||
return pData->absolutePos.getX(); | |||
} | |||
int Widget::getAbsoluteY() const noexcept | |||
{ | |||
return fAbsolutePos.getY(); | |||
return pData->absolutePos.getY(); | |||
} | |||
const Point<int>& Widget::getAbsolutePos() const noexcept | |||
{ | |||
return fAbsolutePos; | |||
return pData->absolutePos; | |||
} | |||
void Widget::setAbsoluteX(int x) noexcept | |||
{ | |||
if (fAbsolutePos.getX() == x) | |||
if (pData->absolutePos.getX() == x) | |||
return; | |||
fAbsolutePos.setX(x); | |||
fParent.repaint(); | |||
pData->absolutePos.setX(x); | |||
pData->parent.repaint(); | |||
} | |||
void Widget::setAbsoluteY(int y) noexcept | |||
{ | |||
if (fAbsolutePos.getY() == y) | |||
if (pData->absolutePos.getY() == y) | |||
return; | |||
fAbsolutePos.setY(y); | |||
fParent.repaint(); | |||
pData->absolutePos.setY(y); | |||
pData->parent.repaint(); | |||
} | |||
void Widget::setAbsolutePos(int x, int y) noexcept | |||
@@ -169,26 +174,26 @@ void Widget::setAbsolutePos(int x, int y) noexcept | |||
void Widget::setAbsolutePos(const Point<int>& pos) noexcept | |||
{ | |||
if (fAbsolutePos == pos) | |||
if (pData->absolutePos == pos) | |||
return; | |||
fAbsolutePos = pos; | |||
fParent.repaint(); | |||
pData->absolutePos = pos; | |||
pData->parent.repaint(); | |||
} | |||
App& Widget::getParentApp() const noexcept | |||
Application& Widget::getParentApp() const noexcept | |||
{ | |||
return fParent.getApp(); | |||
return pData->parent.getApp(); | |||
} | |||
Window& Widget::getParentWindow() const noexcept | |||
{ | |||
return fParent; | |||
return pData->parent; | |||
} | |||
bool Widget::contains(int x, int y) const noexcept | |||
{ | |||
return (x >= 0 && y >= 0 && static_cast<uint>(x) < fSize.getWidth() && static_cast<uint>(y) < fSize.getHeight()); | |||
return (x >= 0 && y >= 0 && static_cast<uint>(x) < pData->size.getWidth() && static_cast<uint>(y) < pData->size.getHeight()); | |||
} | |||
bool Widget::contains(const Point<int>& pos) const noexcept | |||
@@ -198,17 +203,17 @@ bool Widget::contains(const Point<int>& pos) const noexcept | |||
void Widget::repaint() noexcept | |||
{ | |||
fParent.repaint(); | |||
pData->parent.repaint(); | |||
} | |||
uint Widget::getId() const noexcept | |||
{ | |||
return fId; | |||
return pData->id; | |||
} | |||
void Widget::setId(uint id) noexcept | |||
{ | |||
fId = id; | |||
pData->id = id; | |||
} | |||
bool Widget::onKeyboard(const KeyboardEvent&) | |||
@@ -240,16 +245,6 @@ void Widget::onResize(const ResizeEvent&) | |||
{ | |||
} | |||
void Widget::setNeedsFullViewport(bool yesNo) noexcept | |||
{ | |||
fNeedsFullViewport = yesNo; | |||
} | |||
void Widget::setNeedsScaling(bool yesNo) noexcept | |||
{ | |||
fNeedsScaling = yesNo; | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL |
@@ -0,0 +1,133 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifndef DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||
#define DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||
#include "../Widget.hpp" | |||
#include "../Window.hpp" | |||
#include <vector> | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
struct Widget::PrivateData { | |||
Widget* const self; | |||
Window& parent; | |||
Point<int> absolutePos; | |||
Size<uint> size; | |||
std::vector<Widget*> subWidgets; | |||
uint id; | |||
bool needsFullViewport; | |||
bool needsScaling; | |||
bool skipDisplay; | |||
bool visible; | |||
PrivateData(Widget* const s, Window& p, Widget* groupWidget, bool addToSubWidgets) | |||
: self(s), | |||
parent(p), | |||
absolutePos(0, 0), | |||
size(0, 0), | |||
id(0), | |||
needsFullViewport(false), | |||
needsScaling(false), | |||
skipDisplay(false), | |||
visible(true) | |||
{ | |||
if (addToSubWidgets && groupWidget != nullptr) | |||
groupWidget->pData->subWidgets.push_back(self); | |||
} | |||
~PrivateData() | |||
{ | |||
subWidgets.clear(); | |||
} | |||
void display(const uint width, const uint height) | |||
{ | |||
if (skipDisplay || ! visible) | |||
return; | |||
bool needsDisableScissor = false; | |||
// reset color | |||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
if (needsFullViewport || (absolutePos.isZero() && size == Size<uint>(width, height))) | |||
{ | |||
// full viewport size | |||
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||
} | |||
else if (needsScaling) | |||
{ | |||
// limit viewport to widget bounds | |||
glViewport(absolutePos.getX(), | |||
height - static_cast<int>(self->getHeight()) - absolutePos.getY(), | |||
static_cast<GLsizei>(self->getWidth()), | |||
static_cast<GLsizei>(self->getHeight())); | |||
} | |||
else | |||
{ | |||
// only set viewport pos | |||
glViewport(absolutePos.getX(), | |||
/*height - static_cast<int>(self->getHeight())*/ - absolutePos.getY(), | |||
static_cast<GLsizei>(width), | |||
static_cast<GLsizei>(height)); | |||
// then cut the outer bounds | |||
glScissor(absolutePos.getX(), | |||
height - static_cast<int>(self->getHeight()) - absolutePos.getY(), | |||
static_cast<GLsizei>(self->getWidth()), | |||
static_cast<GLsizei>(self->getHeight())); | |||
glEnable(GL_SCISSOR_TEST); | |||
needsDisableScissor = true; | |||
} | |||
// display widget | |||
self->onDisplay(); | |||
if (needsDisableScissor) | |||
{ | |||
glDisable(GL_SCISSOR_TEST); | |||
needsDisableScissor = false; | |||
} | |||
displaySubWidgets(width, height); | |||
} | |||
void displaySubWidgets(const uint width, const uint height) | |||
{ | |||
for (std::vector<Widget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | |||
{ | |||
Widget* const widget(*it); | |||
DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | |||
widget->pData->display(width, height); | |||
} | |||
} | |||
DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#endif // DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,10 +17,11 @@ | |||
// we need this for now | |||
//#define PUGL_GRAB_FOCUS 1 | |||
#include "AppPrivateData.hpp" | |||
#include "../Widget.hpp" | |||
#include "../Window.hpp" | |||
#include "../../distrho/extra/d_string.hpp" | |||
#include "../../distrho/src/DistrhoDefines.h" | |||
#undef PUGL_HAVE_CAIRO | |||
#undef PUGL_HAVE_GL | |||
#define PUGL_HAVE_GL 1 | |||
#include "pugl/pugl.h" | |||
@@ -38,6 +39,11 @@ extern "C" { | |||
# error Unsupported platform | |||
#endif | |||
#include "ApplicationPrivateData.hpp" | |||
#include "WidgetPrivateData.hpp" | |||
#include "../StandaloneWindow.hpp" | |||
#include "../../distrho/extra/String.hpp" | |||
#define FOR_EACH_WIDGET(it) \ | |||
for (std::list<Widget*>::iterator it = fWidgets.begin(); it != fWidgets.end(); ++it) | |||
@@ -60,7 +66,7 @@ START_NAMESPACE_DGL | |||
// Window Private | |||
struct Window::PrivateData { | |||
PrivateData(App& app, Window* const self) | |||
PrivateData(Application& app, Window* const self) | |||
: fApp(app), | |||
fSelf(self), | |||
fView(puglInit()), | |||
@@ -74,22 +80,21 @@ struct Window::PrivateData { | |||
fWidgets(), | |||
fModal(), | |||
#if defined(DISTRHO_OS_WINDOWS) | |||
hwnd(0), | |||
hwnd(0) | |||
#elif defined(DISTRHO_OS_LINUX) | |||
xDisplay(nullptr), | |||
xWindow(0), | |||
xWindow(0) | |||
#elif defined(DISTRHO_OS_MAC) | |||
fNeedsIdle(true), | |||
mView(nullptr), | |||
mWindow(nullptr), | |||
mWindow(nullptr) | |||
#endif | |||
leakDetector_PrivateData() | |||
{ | |||
DBG("Creating window without parent..."); DBGF; | |||
init(); | |||
} | |||
PrivateData(App& app, Window* const self, Window& parent) | |||
PrivateData(Application& app, Window* const self, Window& parent) | |||
: fApp(app), | |||
fSelf(self), | |||
fView(puglInit()), | |||
@@ -103,16 +108,15 @@ struct Window::PrivateData { | |||
fWidgets(), | |||
fModal(parent.pData), | |||
#if defined(DISTRHO_OS_WINDOWS) | |||
hwnd(0), | |||
hwnd(0) | |||
#elif defined(DISTRHO_OS_LINUX) | |||
xDisplay(nullptr), | |||
xWindow(0), | |||
xWindow(0) | |||
#elif defined(DISTRHO_OS_MAC) | |||
fNeedsIdle(false), | |||
mView(nullptr), | |||
mWindow(nullptr), | |||
mWindow(nullptr) | |||
#endif | |||
leakDetector_PrivateData() | |||
{ | |||
DBG("Creating window with parent..."); DBGF; | |||
init(); | |||
@@ -128,7 +132,7 @@ struct Window::PrivateData { | |||
#endif | |||
} | |||
PrivateData(App& app, Window* const self, const intptr_t parentId) | |||
PrivateData(Application& app, Window* const self, const intptr_t parentId) | |||
: fApp(app), | |||
fSelf(self), | |||
fView(puglInit()), | |||
@@ -142,16 +146,15 @@ struct Window::PrivateData { | |||
fWidgets(), | |||
fModal(), | |||
#if defined(DISTRHO_OS_WINDOWS) | |||
hwnd(0), | |||
hwnd(0) | |||
#elif defined(DISTRHO_OS_LINUX) | |||
xDisplay(nullptr), | |||
xWindow(0), | |||
xWindow(0) | |||
#elif defined(DISTRHO_OS_MAC) | |||
fNeedsIdle(parentId == 0), | |||
mView(nullptr), | |||
mWindow(nullptr), | |||
mWindow(nullptr) | |||
#endif | |||
leakDetector_PrivateData() | |||
{ | |||
if (fUsingEmbed) | |||
{ | |||
@@ -182,7 +185,8 @@ struct Window::PrivateData { | |||
return; | |||
} | |||
puglInitResizable(fView, fResizable); | |||
puglInitContextType(fView, PUGL_GL); | |||
puglInitUserResizable(fView, fResizable); | |||
puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | |||
puglSetHandle(fView, this); | |||
@@ -223,6 +227,7 @@ struct Window::PrivateData { | |||
XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | |||
} | |||
#endif | |||
puglEnterContext(fView); | |||
fApp.pData->windows.push_back(fSelf); | |||
@@ -349,8 +354,24 @@ struct Window::PrivateData { | |||
fModal.enabled = false; | |||
if (fModal.parent != nullptr) | |||
{ | |||
fModal.parent->fModal.childFocus = nullptr; | |||
// the mouse position probably changed since the modal appeared, | |||
// so send a mouse motion event to the modal's parent window | |||
#if defined(DISTRHO_OS_WINDOWS) | |||
// TODO | |||
#elif defined(DISTRHO_OS_MAC) | |||
// TODO | |||
#elif defined(DISTRHO_OS_LINUX) | |||
int i, wx, wy; | |||
uint u; | |||
::Window w; | |||
if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True) | |||
fModal.parent->onPuglMotion(wx, wy); | |||
#endif | |||
} | |||
DBG("Ok\n"); | |||
} | |||
@@ -647,60 +668,10 @@ struct Window::PrivateData { | |||
{ | |||
fSelf->onDisplayBefore(); | |||
bool needsDisableScissor = false; | |||
FOR_EACH_WIDGET(it) | |||
{ | |||
Widget* const widget(*it); | |||
if (widget->isVisible()) | |||
{ | |||
// reset color | |||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
if (widget->fNeedsFullViewport || (widget->fAbsolutePos.isZero() && widget->fSize == Size<uint>(fWidth, fHeight))) | |||
{ | |||
// full viewport size | |||
glViewport(0, | |||
0, | |||
static_cast<GLsizei>(fWidth), | |||
static_cast<GLsizei>(fHeight)); | |||
} | |||
else if (! widget->fNeedsScaling) | |||
{ | |||
// only set viewport pos | |||
glViewport(widget->getAbsoluteX(), | |||
/*fView->height - static_cast<int>(widget->getHeight())*/ - widget->getAbsoluteY(), | |||
static_cast<GLsizei>(fWidth), | |||
static_cast<GLsizei>(fHeight)); | |||
// then cut the outer bounds | |||
glScissor(widget->getAbsoluteX(), | |||
fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||
static_cast<GLsizei>(widget->getWidth()), | |||
static_cast<GLsizei>(widget->getHeight())); | |||
glEnable(GL_SCISSOR_TEST); | |||
needsDisableScissor = true; | |||
} | |||
else | |||
{ | |||
// limit viewport to widget bounds | |||
glViewport(widget->getAbsoluteX(), | |||
fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), | |||
static_cast<GLsizei>(widget->getWidth()), | |||
static_cast<GLsizei>(widget->getHeight())); | |||
} | |||
// display widget | |||
widget->onDisplay(); | |||
if (needsDisableScissor) | |||
{ | |||
glDisable(GL_SCISSOR_TEST); | |||
needsDisableScissor = false; | |||
} | |||
} | |||
widget->pData->display(fWidth, fHeight); | |||
} | |||
fSelf->onDisplayAfter(); | |||
@@ -838,7 +809,7 @@ struct Window::PrivateData { | |||
{ | |||
Widget* const widget(*it); | |||
if (widget->fNeedsFullViewport) | |||
if (widget->pData->needsFullViewport) | |||
widget->setSize(fWidth, fHeight); | |||
} | |||
} | |||
@@ -860,9 +831,9 @@ struct Window::PrivateData { | |||
// ------------------------------------------------------------------- | |||
App& fApp; | |||
Window* fSelf; | |||
PuglView* fView; | |||
Application& fApp; | |||
Window* fSelf; | |||
PuglView* fView; | |||
bool fFirstInit; | |||
bool fVisible; | |||
@@ -966,17 +937,14 @@ struct Window::PrivateData { | |||
// ----------------------------------------------------------------------- | |||
// Window | |||
Window::Window(App& app) | |||
: pData(new PrivateData(app, this)), | |||
leakDetector_Window() {} | |||
Window::Window(Application& app) | |||
: pData(new PrivateData(app, this)) {} | |||
Window::Window(App& app, Window& parent) | |||
: pData(new PrivateData(app, this, parent)), | |||
leakDetector_Window() {} | |||
Window::Window(Application& app, Window& parent) | |||
: pData(new PrivateData(app, this, parent)) {} | |||
Window::Window(App& app, intptr_t parentId) | |||
: pData(new PrivateData(app, this, parentId)), | |||
leakDetector_Window() {} | |||
Window::Window(Application& app, intptr_t parentId) | |||
: pData(new PrivateData(app, this, parentId)) {} | |||
Window::~Window() | |||
{ | |||
@@ -1022,7 +990,7 @@ void Window::repaint() noexcept | |||
bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
{ | |||
#ifdef SOFD_HAVE_X11 | |||
using DISTRHO_NAMESPACE::d_string; | |||
using DISTRHO_NAMESPACE::String; | |||
// -------------------------------------------------------------------------- | |||
// configure start dir | |||
@@ -1030,7 +998,7 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
// TODO: get abspath if needed | |||
// TODO: cross-platform | |||
d_string startDir(options.startDir); | |||
String startDir(options.startDir); | |||
if (startDir.isEmpty()) | |||
{ | |||
@@ -1051,7 +1019,7 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
// -------------------------------------------------------------------------- | |||
// configure title | |||
d_string title(options.title); | |||
String title(options.title); | |||
if (title.isEmpty()) | |||
{ | |||
@@ -1145,7 +1113,7 @@ void Window::setTransientWinId(uintptr_t winId) | |||
pData->setTransientWinId(winId); | |||
} | |||
App& Window::getApp() const noexcept | |||
Application& Window::getApp() const noexcept | |||
{ | |||
return pData->fApp; | |||
} | |||
@@ -1220,6 +1188,46 @@ void Window::fileBrowserSelected(const char*) | |||
// ----------------------------------------------------------------------- | |||
StandaloneWindow::StandaloneWindow() | |||
: Application(), | |||
Window((Application&)*this), | |||
fWidget(nullptr) {} | |||
void StandaloneWindow::exec() | |||
{ | |||
Window::show(); | |||
Application::exec(); | |||
} | |||
void StandaloneWindow::onReshape(uint width, uint height) | |||
{ | |||
if (fWidget != nullptr) | |||
fWidget->setSize(width, height); | |||
Window::onReshape(width, height); | |||
} | |||
void StandaloneWindow::_addWidget(Widget* widget) | |||
{ | |||
if (fWidget == nullptr) | |||
{ | |||
fWidget = widget; | |||
fWidget->pData->needsFullViewport = true; | |||
} | |||
Window::_addWidget(widget); | |||
} | |||
void StandaloneWindow::_removeWidget(Widget* widget) | |||
{ | |||
if (fWidget == widget) | |||
{ | |||
fWidget->pData->needsFullViewport = false; | |||
fWidget = nullptr; | |||
} | |||
Window::_removeWidget(widget); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#undef DBG | |||
@@ -25,7 +25,12 @@ extern "C" { | |||
#define NVG_PI 3.14159265358979323846264338327f | |||
struct NVGcontext; | |||
#ifdef _MSC_VER | |||
#pragma warning(push) | |||
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union | |||
#endif | |||
typedef struct NVGcontext NVGcontext; | |||
struct NVGcolor { | |||
union { | |||
@@ -35,17 +40,18 @@ struct NVGcolor { | |||
}; | |||
}; | |||
}; | |||
typedef struct NVGcolor NVGcolor; | |||
struct NVGpaint { | |||
float xform[6]; | |||
float extent[2]; | |||
float radius; | |||
float feather; | |||
struct NVGcolor innerColor; | |||
struct NVGcolor outerColor; | |||
NVGcolor innerColor; | |||
NVGcolor outerColor; | |||
int image; | |||
int repeat; | |||
}; | |||
typedef struct NVGpaint NVGpaint; | |||
enum NVGwinding { | |||
NVG_CCW = 1, // Winding for solid shapes | |||
@@ -65,11 +71,6 @@ enum NVGlineCap { | |||
NVG_MITER, | |||
}; | |||
enum NVGpatternRepeat { | |||
NVG_REPEATX = 0x01, // Repeat image pattern in X direction | |||
NVG_REPEATY = 0x02, // Repeat image pattern in Y direction | |||
}; | |||
enum NVGalign { | |||
// Horizontal align | |||
NVG_ALIGN_LEFT = 1<<0, // Default, align text horizontally to left. | |||
@@ -78,13 +79,8 @@ enum NVGalign { | |||
// Vertical align | |||
NVG_ALIGN_TOP = 1<<3, // Align text vertically to top. | |||
NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle. | |||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. | |||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. | |||
}; | |||
enum NVGalpha { | |||
NVG_STRAIGHT_ALPHA, | |||
NVG_PREMULTIPLIED_ALPHA, | |||
NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. | |||
NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. | |||
}; | |||
struct NVGglyphPosition { | |||
@@ -92,6 +88,7 @@ struct NVGglyphPosition { | |||
float x; // The x-coordinate of the logical glyph position. | |||
float minx, maxx; // The bounds of the glyph shape. | |||
}; | |||
typedef struct NVGglyphPosition NVGglyphPosition; | |||
struct NVGtextRow { | |||
const char* start; // Pointer to the input text where the row starts. | |||
@@ -100,7 +97,15 @@ struct NVGtextRow { | |||
float width; // Logical width of the row. | |||
float minx, maxx; // Actual bounds of the row. Logical with and bounds can differ because of kerning and some parts over extending. | |||
}; | |||
typedef struct NVGtextRow NVGtextRow; | |||
enum NVGimageFlags { | |||
NVG_IMAGE_GENERATE_MIPMAPS = 1<<0, // Generate mipmaps during creation of the image. | |||
NVG_IMAGE_REPEATX = 1<<1, // Repeat image in X direction. | |||
NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction. | |||
NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered. | |||
NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha. | |||
}; | |||
// Begin drawing a new frame | |||
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() | |||
@@ -110,14 +115,13 @@ struct NVGtextRow { | |||
// For example, GLFW returns two dimension for an opened window: window size and | |||
// frame buffer size. In that case you would set windowWidth/Height to the window size | |||
// devicePixelRatio to: frameBufferWidth / windowWidth. | |||
// AlphaBlend controls if drawing the shapes to the render target should be done using straight or | |||
// premultiplied alpha. If rendering directly to framebuffer you probably want to use NVG_STRAIGHT_ALPHA, | |||
// if rendering to texture which should contain transparent regions NVG_PREMULTIPLIED_ALPHA is the | |||
// right choice. | |||
void nvgBeginFrame(struct NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio, int alphaBlend); | |||
void nvgBeginFrame(NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio); | |||
// Cancels drawing the current frame. | |||
void nvgCancelFrame(NVGcontext* ctx); | |||
// Ends drawing flushing remaining render state. | |||
void nvgEndFrame(struct NVGcontext* ctx); | |||
void nvgEndFrame(NVGcontext* ctx); | |||
// | |||
// Color utils | |||
@@ -125,35 +129,35 @@ void nvgEndFrame(struct NVGcontext* ctx); | |||
// Colors in NanoVG are stored as unsigned ints in ABGR format. | |||
// Returns a color value from red, green, blue values. Alpha will be set to 255 (1.0f). | |||
struct NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b); | |||
NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b); | |||
// Returns a color value from red, green, blue values. Alpha will be set to 1.0f. | |||
struct NVGcolor nvgRGBf(float r, float g, float b); | |||
NVGcolor nvgRGBf(float r, float g, float b); | |||
// Returns a color value from red, green, blue and alpha values. | |||
struct NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); | |||
NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a); | |||
// Returns a color value from red, green, blue and alpha values. | |||
struct NVGcolor nvgRGBAf(float r, float g, float b, float a); | |||
NVGcolor nvgRGBAf(float r, float g, float b, float a); | |||
// Linearly interpoaltes from color c0 to c1, and returns resulting color value. | |||
struct NVGcolor nvgLerpRGBA(struct NVGcolor c0, struct NVGcolor c1, float u); | |||
// Linearly interpolates from color c0 to c1, and returns resulting color value. | |||
NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u); | |||
// Sets transparency of a color value. | |||
struct NVGcolor nvgTransRGBA(struct NVGcolor c0, unsigned char a); | |||
NVGcolor nvgTransRGBA(NVGcolor c0, unsigned char a); | |||
// Sets transparency of a color value. | |||
struct NVGcolor nvgTransRGBAf(struct NVGcolor c0, float a); | |||
NVGcolor nvgTransRGBAf(NVGcolor c0, float a); | |||
// Returns color value specified by hue, saturation and lightness. | |||
// HSL values are all in range [0..1], alpha will be set to 255. | |||
struct NVGcolor nvgHSL(float h, float s, float l); | |||
NVGcolor nvgHSL(float h, float s, float l); | |||
// Returns color value specified by hue, saturation and lightness and alpha. | |||
// HSL values are all in range [0..1], alpha in range [0..255] | |||
struct NVGcolor nvgHSLA(float h, float s, float l, unsigned char a); | |||
NVGcolor nvgHSLA(float h, float s, float l, unsigned char a); | |||
// | |||
// State Handling | |||
@@ -164,13 +168,13 @@ struct NVGcolor nvgHSLA(float h, float s, float l, unsigned char a); | |||
// Pushes and saves the current render state into a state stack. | |||
// A matching nvgRestore() must be used to restore the state. | |||
void nvgSave(struct NVGcontext* ctx); | |||
void nvgSave(NVGcontext* ctx); | |||
// Pops and restores current render state. | |||
void nvgRestore(struct NVGcontext* ctx); | |||
void nvgRestore(NVGcontext* ctx); | |||
// Resets current render state to default values. Does not affect the render state stack. | |||
void nvgReset(struct NVGcontext* ctx); | |||
void nvgReset(NVGcontext* ctx); | |||
// | |||
// Render styles | |||
@@ -179,34 +183,38 @@ void nvgReset(struct NVGcontext* ctx); | |||
// Solid color is simply defined as a color value, different kinds of paints can be created | |||
// using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern(). | |||
// | |||
// Current render style can be saved and restored using nvgSave() and nvgRestore(). | |||
// Current render style can be saved and restored using nvgSave() and nvgRestore(). | |||
// Sets current stroke style to a solid color. | |||
void nvgStrokeColor(struct NVGcontext* ctx, struct NVGcolor color); | |||
void nvgStrokeColor(NVGcontext* ctx, NVGcolor color); | |||
// Sets current stroke style to a paint, which can be a one of the gradients or a pattern. | |||
void nvgStrokePaint(struct NVGcontext* ctx, struct NVGpaint paint); | |||
void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint); | |||
// Sets current fill cstyle to a solid color. | |||
void nvgFillColor(struct NVGcontext* ctx, struct NVGcolor color); | |||
// Sets current fill style to a solid color. | |||
void nvgFillColor(NVGcontext* ctx, NVGcolor color); | |||
// Sets current fill style to a paint, which can be a one of the gradients or a pattern. | |||
void nvgFillPaint(struct NVGcontext* ctx, struct NVGpaint paint); | |||
void nvgFillPaint(NVGcontext* ctx, NVGpaint paint); | |||
// Sets the miter limit of the stroke style. | |||
// Miter limit controls when a sharp corner is beveled. | |||
void nvgMiterLimit(struct NVGcontext* ctx, float limit); | |||
void nvgMiterLimit(NVGcontext* ctx, float limit); | |||
// Sets the stroke witdth of the stroke style. | |||
void nvgStrokeWidth(struct NVGcontext* ctx, float size); | |||
// Sets the stroke width of the stroke style. | |||
void nvgStrokeWidth(NVGcontext* ctx, float size); | |||
// Sets how the end of the line (cap) is drawn, | |||
// Can be one of: NVG_BUTT (default), NVG_ROUND, NVG_SQUARE. | |||
void nvgLineCap(struct NVGcontext* ctx, int cap); | |||
void nvgLineCap(NVGcontext* ctx, int cap); | |||
// Sets how sharp path corners are drawn. | |||
// Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL. | |||
void nvgLineJoin(struct NVGcontext* ctx, int join); | |||
void nvgLineJoin(NVGcontext* ctx, int join); | |||
// Sets the transparency applied to all rendered shapes. | |||
// Already transparent paths will get proportionally more transparent as well. | |||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha); | |||
// | |||
// Transforms | |||
@@ -223,43 +231,43 @@ void nvgLineJoin(struct NVGcontext* ctx, int join); | |||
// Apart from nvgResetTransform(), each transformation function first creates | |||
// specific transformation matrix and pre-multiplies the current transformation by it. | |||
// | |||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). | |||
// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). | |||
// Resets current transform to a identity matrix. | |||
void nvgResetTransform(struct NVGcontext* ctx); | |||
void nvgResetTransform(NVGcontext* ctx); | |||
// Premultiplies current coordinate system by specified matrix. | |||
// The parameters are interpreted as matrix as follows: | |||
// [a c e] | |||
// [b d f] | |||
// [0 0 1] | |||
void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, float e, float f); | |||
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f); | |||
// Translates current coordinate system. | |||
void nvgTranslate(struct NVGcontext* ctx, float x, float y); | |||
void nvgTranslate(NVGcontext* ctx, float x, float y); | |||
// Rotates current coordinate system. Angle is specifid in radians. | |||
void nvgRotate(struct NVGcontext* ctx, float angle); | |||
// Rotates current coordinate system. Angle is specified in radians. | |||
void nvgRotate(NVGcontext* ctx, float angle); | |||
// Skews the current coordinate system along X axis. Angle is specifid in radians. | |||
void nvgSkewX(struct NVGcontext* ctx, float angle); | |||
// Skews the current coordinate system along X axis. Angle is specified in radians. | |||
void nvgSkewX(NVGcontext* ctx, float angle); | |||
// Skews the current coordinate system along Y axis. Angle is specifid in radians. | |||
void nvgSkewY(struct NVGcontext* ctx, float angle); | |||
// Skews the current coordinate system along Y axis. Angle is specified in radians. | |||
void nvgSkewY(NVGcontext* ctx, float angle); | |||
// Scales the current coordinat system. | |||
void nvgScale(struct NVGcontext* ctx, float x, float y); | |||
// Scales the current coordinate system. | |||
void nvgScale(NVGcontext* ctx, float x, float y); | |||
// Stores the top part (a-f) of the current transformation matrix in to the specified buffer. | |||
// [a c e] | |||
// [b d f] | |||
// [0 0 1] | |||
// There should be space for 6 floats in the return buffer for the values a-f. | |||
void nvgCurrentTransform(struct NVGcontext* ctx, float* xform); | |||
void nvgCurrentTransform(NVGcontext* ctx, float* xform); | |||
// The following functions can be used to make calculations on 2x3 transformation matrices. | |||
// A 2x3 matrix is representated as float[6]. | |||
// A 2x3 matrix is represented as float[6]. | |||
// Sets the transform to identity matrix. | |||
void nvgTransformIdentity(float* dst); | |||
@@ -270,13 +278,13 @@ void nvgTransformTranslate(float* dst, float tx, float ty); | |||
// Sets the transform to scale matrix. | |||
void nvgTransformScale(float* dst, float sx, float sy); | |||
// Sets the transform to rotate matrix. Angle is specifid in radians. | |||
// Sets the transform to rotate matrix. Angle is specified in radians. | |||
void nvgTransformRotate(float* dst, float a); | |||
// Sets the transform to skew-x matrix. Angle is specifid in radians. | |||
// Sets the transform to skew-x matrix. Angle is specified in radians. | |||
void nvgTransformSkewX(float* dst, float a); | |||
// Sets the transform to skew-y matrix. Angle is specifid in radians. | |||
// Sets the transform to skew-y matrix. Angle is specified in radians. | |||
void nvgTransformSkewY(float* dst, float a); | |||
// Sets the transform to the result of multiplication of two transforms, of A = A*B. | |||
@@ -292,7 +300,7 @@ int nvgTransformInverse(float* dst, const float* src); | |||
// Transform a point by given transform. | |||
void nvgTransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy); | |||
// Converts degress to radians and vice versa. | |||
// Converts degrees to radians and vice versa. | |||
float nvgDegToRad(float deg); | |||
float nvgRadToDeg(float rad); | |||
@@ -301,27 +309,28 @@ float nvgRadToDeg(float rad); | |||
// | |||
// NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering. | |||
// In addition you can upload your own image. The image loading is provided by stb_image. | |||
// The parameter imageFlags is combination of flags defined in NVGimageFlags. | |||
// Creates image by loading it from the disk from specified file name. | |||
// Returns handle to the image. | |||
int nvgCreateImage(struct NVGcontext* ctx, const char* filename); | |||
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags); | |||
// Creates image by loading it from the specified chunk of memory. | |||
// Returns handle to the image. | |||
int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata); | |||
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, const unsigned char* data, int ndata); | |||
// Creates image from specified image data. | |||
// Returns handle to the image. | |||
int nvgCreateImageRGBA(struct NVGcontext* ctx, int w, int h, const unsigned char* data); | |||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); | |||
// Updates image data specified by image handle. | |||
void nvgUpdateImage(struct NVGcontext* ctx, int image, const unsigned char* data); | |||
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data); | |||
// Returns the domensions of a created image. | |||
void nvgImageSize(struct NVGcontext* ctx, int image, int* w, int* h); | |||
// Returns the dimensions of a created image. | |||
void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h); | |||
// Deletes created image. | |||
void nvgDeleteImage(struct NVGcontext* ctx, int image); | |||
void nvgDeleteImage(NVGcontext* ctx, int image); | |||
// | |||
// Paints | |||
@@ -332,42 +341,49 @@ void nvgDeleteImage(struct NVGcontext* ctx, int image); | |||
// Creates and returns a linear gradient. Parameters (sx,sy)-(ex,ey) specify the start and end coordinates | |||
// of the linear gradient, icol specifies the start color and ocol the end color. | |||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). | |||
struct NVGpaint nvgLinearGradient(struct NVGcontext* ctx, float sx, float sy, float ex, float ey, | |||
struct NVGcolor icol, struct NVGcolor ocol); | |||
NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey, | |||
NVGcolor icol, NVGcolor ocol); | |||
// Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering | |||
// drop shadows or hilights for boxes. Parameters (x,y) define the top-left corner of the rectangle, | |||
// drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle, | |||
// (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry | |||
// the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient. | |||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). | |||
struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx, float x, float y, float w, float h, | |||
float r, float f, struct NVGcolor icol, struct NVGcolor ocol); | |||
NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h, | |||
float r, float f, NVGcolor icol, NVGcolor ocol); | |||
// Creates and returns a radial gradient. Parameters (cx,cy) specify the center, inr and outr specify | |||
// the inner and outer radius of the gradient, icol specifies the start color and ocol the end color. | |||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). | |||
struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx, float cx, float cy, float inr, float outr, | |||
struct NVGcolor icol, struct NVGcolor ocol); | |||
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, | |||
NVGcolor icol, NVGcolor ocol); | |||
// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern, | |||
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render, | |||
// and repeat is combination of NVG_REPEATX and NVG_REPEATY which tells if the image should be repeated across x or y. | |||
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. | |||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). | |||
struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, float ox, float oy, float ex, float ey, | |||
float angle, int image, int repeat); | |||
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey, | |||
float angle, int image, float alpha); | |||
// | |||
// Scissoring | |||
// | |||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for varius | |||
// user interface cases like rendering a text edit or a timeline. | |||
// Scissoring allows you to clip the rendering into a rectangle. This is useful for various | |||
// user interface cases like rendering a text edit or a timeline. | |||
// Sets the current scissor rectangle. | |||
// The scissor rectangle is transformed by the current transform. | |||
void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h); | |||
// Sets the current | |||
// Intersects current scissor rectangle with the specified rectangle. | |||
// The scissor rectangle is transformed by the current transform. | |||
void nvgScissor(struct NVGcontext* ctx, float x, float y, float w, float h); | |||
// Note: in case the rotation of previous scissor rect differs from | |||
// the current one, the intersection will be done between the specified | |||
// rectangle and the previous scissor rectangle transformed in the current | |||
// transform space. The resulting shape is always rectangle. | |||
void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h); | |||
// Reset and disables scissoring. | |||
void nvgResetScissor(struct NVGcontext* ctx); | |||
void nvgResetScissor(NVGcontext* ctx); | |||
// | |||
// Paths | |||
@@ -387,46 +403,51 @@ void nvgResetScissor(struct NVGcontext* ctx); | |||
// The curve segments and sub-paths are transformed by the current transform. | |||
// Clears the current path and sub-paths. | |||
void nvgBeginPath(struct NVGcontext* ctx); | |||
void nvgBeginPath(NVGcontext* ctx); | |||
// Starts new sub-path with specified point as first point. | |||
void nvgMoveTo(struct NVGcontext* ctx, float x, float y); | |||
void nvgMoveTo(NVGcontext* ctx, float x, float y); | |||
// Adds line segment from the last point in the path to the specified point. | |||
void nvgLineTo(struct NVGcontext* ctx, float x, float y); | |||
void nvgLineTo(NVGcontext* ctx, float x, float y); | |||
// Adds bezier segment from last point in the path via two control points to the specified point. | |||
void nvgBezierTo(struct NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y); | |||
// Adds cubic bezier segment from last point in the path via two control points to the specified point. | |||
void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y); | |||
// Adds quadratic bezier segment from last point in the path via a control point to the specified point. | |||
void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y); | |||
// Adds an arc segment at the corner defined by the last path point, and two specified points. | |||
void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius); | |||
void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius); | |||
// Closes current sub-path with a line segment. | |||
void nvgClosePath(struct NVGcontext* ctx); | |||
void nvgClosePath(NVGcontext* ctx); | |||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity. | |||
void nvgPathWinding(struct NVGcontext* ctx, int dir); | |||
// Sets the current sub-path winding, see NVGwinding and NVGsolidity. | |||
void nvgPathWinding(NVGcontext* ctx, int dir); | |||
// Creates new arc shaped sub-path. | |||
void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir); | |||
// Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, | |||
// and the arc is drawn from angle a0 to a1, and swept in direction dir (NVG_CCW, or NVG_CW). | |||
// Angles are specified in radians. | |||
void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir); | |||
// Creates new rectangle shaped sub-path. | |||
void nvgRect(struct NVGcontext* ctx, float x, float y, float w, float h); | |||
void nvgRect(NVGcontext* ctx, float x, float y, float w, float h); | |||
// Creates new rounded rectangle shaped sub-path. | |||
void nvgRoundedRect(struct NVGcontext* ctx, float x, float y, float w, float h, float r); | |||
void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r); | |||
// Creates new ellipse shaped sub-path. | |||
void nvgEllipse(struct NVGcontext* ctx, float cx, float cy, float rx, float ry); | |||
void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry); | |||
// Creates new circle shaped sub-path. | |||
void nvgCircle(struct NVGcontext* ctx, float cx, float cy, float r); | |||
// Creates new circle shaped sub-path. | |||
void nvgCircle(NVGcontext* ctx, float cx, float cy, float r); | |||
// Fills the current path with current fill style. | |||
void nvgFill(struct NVGcontext* ctx); | |||
void nvgFill(NVGcontext* ctx); | |||
// Fills the current path with current stroke style. | |||
void nvgStroke(struct NVGcontext* ctx); | |||
void nvgStroke(NVGcontext* ctx); | |||
// | |||
@@ -464,67 +485,67 @@ void nvgStroke(struct NVGcontext* ctx); | |||
// Creates font by loading it from the disk from specified file name. | |||
// Returns handle to the font. | |||
int nvgCreateFont(struct NVGcontext* ctx, const char* name, const char* filename); | |||
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename); | |||
// Creates image by loading it from the specified memory chunk. | |||
// Returns handle to the font. | |||
int nvgCreateFontMem(struct NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData); | |||
int nvgCreateFontMem(NVGcontext* ctx, const char* name, const unsigned char* data, int ndata, int freeData); | |||
// Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. | |||
int nvgFindFont(struct NVGcontext* ctx, const char* name); | |||
int nvgFindFont(NVGcontext* ctx, const char* name); | |||
// Sets the font size of current text style. | |||
void nvgFontSize(struct NVGcontext* ctx, float size); | |||
void nvgFontSize(NVGcontext* ctx, float size); | |||
// Sets the blur of current text style. | |||
void nvgFontBlur(struct NVGcontext* ctx, float blur); | |||
void nvgFontBlur(NVGcontext* ctx, float blur); | |||
// Sets the letter spacing of current text style. | |||
void nvgTextLetterSpacing(struct NVGcontext* ctx, float spacing); | |||
void nvgTextLetterSpacing(NVGcontext* ctx, float spacing); | |||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size. | |||
void nvgTextLineHeight(struct NVGcontext* ctx, float lineHeight); | |||
// Sets the proportional line height of current text style. The line height is specified as multiple of font size. | |||
void nvgTextLineHeight(NVGcontext* ctx, float lineHeight); | |||
// Sets the text align of current text style, see NVGaling for options. | |||
void nvgTextAlign(struct NVGcontext* ctx, int align); | |||
// Sets the text align of current text style, see NVGalign for options. | |||
void nvgTextAlign(NVGcontext* ctx, int align); | |||
// Sets the font face based on specified id of current text style. | |||
void nvgFontFaceId(struct NVGcontext* ctx, int font); | |||
void nvgFontFaceId(NVGcontext* ctx, int font); | |||
// Sets the font face based on specified name of current text style. | |||
void nvgFontFace(struct NVGcontext* ctx, const char* font); | |||
void nvgFontFace(NVGcontext* ctx, const char* font); | |||
// Draws text string at specified location. If end is specified only the sub-string up to the end is drawn. | |||
float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end); | |||
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end); | |||
// Draws multi-line text string at specified location wrapped at the specified width. If end is specified only the sub-string up to the end is drawn. | |||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. | |||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation). | |||
void nvgTextBox(struct NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end); | |||
void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end); | |||
// Measures the specified text string. Parameter bounds should be a pointer to float[4], | |||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] | |||
// Returns the horizontal advance of the measured text (i.e. where the next character should drawn). | |||
// Measured values are returned in local coordinate space. | |||
float nvgTextBounds(struct NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds); | |||
float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds); | |||
// Measures the specified multi-text string. Parameter bounds should be a pointer to float[4], | |||
// if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] | |||
// Measured values are returned in local coordinate space. | |||
void nvgTextBoxBounds(struct NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); | |||
void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); | |||
// Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. | |||
// Measured values are returned in local coordinate space. | |||
int nvgTextGlyphPositions(struct NVGcontext* ctx, float x, float y, const char* string, const char* end, struct NVGglyphPosition* positions, int maxPositions); | |||
int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions); | |||
// Returns the vertical metrics based on the current text style. | |||
// Measured values are returned in local coordinate space. | |||
void nvgTextMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh); | |||
void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh); | |||
// Breaks the specified text into lines. If end is specified only the sub-string will be used. | |||
// White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. | |||
// Words longer than the max width are slit at nearest character (i.e. no hyphenation). | |||
int nvgTextBreakLines(struct NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, struct NVGtextRow* rows, int maxRows); | |||
int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows); | |||
// | |||
// Internal Render API | |||
@@ -534,54 +555,63 @@ enum NVGtexture { | |||
NVG_TEXTURE_RGBA = 0x02, | |||
}; | |||
struct NVGscissor | |||
{ | |||
struct NVGscissor { | |||
float xform[6]; | |||
float extent[2]; | |||
}; | |||
typedef struct NVGscissor NVGscissor; | |||
struct NVGvertex { | |||
float x,y,u,v; | |||
}; | |||
typedef struct NVGvertex NVGvertex; | |||
struct NVGpath { | |||
int first; | |||
int count; | |||
unsigned char closed; | |||
int nbevel; | |||
struct NVGvertex* fill; | |||
NVGvertex* fill; | |||
int nfill; | |||
struct NVGvertex* stroke; | |||
NVGvertex* stroke; | |||
int nstroke; | |||
int winding; | |||
int convex; | |||
}; | |||
typedef struct NVGpath NVGpath; | |||
struct NVGparams { | |||
void* userPtr; | |||
int atlasWidth, atlasHeight; | |||
int edgeAntiAlias; | |||
int (*renderCreate)(void* uptr); | |||
int (*renderCreateTexture)(void* uptr, int type, int w, int h, const unsigned char* data); | |||
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); | |||
int (*renderDeleteTexture)(void* uptr, int image); | |||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); | |||
int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); | |||
void (*renderViewport)(void* uptr, int width, int height, int alphaBlend); | |||
void (*renderFlush)(void* uptr, int alphaBlend); | |||
void (*renderFill)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe, const float* bounds, const struct NVGpath* paths, int npaths); | |||
void (*renderStroke)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe, float strokeWidth, const struct NVGpath* paths, int npaths); | |||
void (*renderTriangles)(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, const struct NVGvertex* verts, int nverts); | |||
void (*renderViewport)(void* uptr, int width, int height); | |||
void (*renderCancel)(void* uptr); | |||
void (*renderFlush)(void* uptr); | |||
void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); | |||
void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths); | |||
void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts); | |||
void (*renderDelete)(void* uptr); | |||
}; | |||
typedef struct NVGparams NVGparams; | |||
// Constructor and destructor, called by the render back-end. | |||
NVGcontext* nvgCreateInternal(NVGparams* params); | |||
void nvgDeleteInternal(NVGcontext* ctx); | |||
// Contructor and destructor, called by the render back-end. | |||
struct NVGcontext* nvgCreateInternal(struct NVGparams* params); | |||
void nvgDeleteInternal(struct NVGcontext* ctx); | |||
NVGparams* nvgInternalParams(NVGcontext* ctx); | |||
// Debug function to dump cached path data. | |||
void nvgDebugDumpPathCache(struct NVGcontext* ctx); | |||
void nvgDebugDumpPathCache(NVGcontext* ctx); | |||
#ifdef _MSC_VER | |||
#pragma warning(pop) | |||
#endif | |||
#define NVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) | |||
#define NVG_NOTUSED(v) for (;;) { (void)(1 ? (void)0 : ( (void)(v) ) ); break; } | |||
#ifdef __cplusplus | |||
} | |||
@@ -0,0 +1,132 @@ | |||
// | |||
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org | |||
// | |||
// This software is provided 'as-is', without any express or implied | |||
// warranty. In no event will the authors be held liable for any damages | |||
// arising from the use of this software. | |||
// Permission is granted to anyone to use this software for any purpose, | |||
// including commercial applications, and to alter it and redistribute it | |||
// freely, subject to the following restrictions: | |||
// 1. The origin of this software must not be misrepresented; you must not | |||
// claim that you wrote the original software. If you use this software | |||
// in a product, an acknowledgment in the product documentation would be | |||
// appreciated but is not required. | |||
// 2. Altered source versions must be plainly marked as such, and must not be | |||
// misrepresented as being the original software. | |||
// 3. This notice may not be removed or altered from any source distribution. | |||
// | |||
#ifndef NANOVG_GL_UTILS_H | |||
#define NANOVG_GL_UTILS_H | |||
struct NVGLUframebuffer { | |||
NVGcontext* ctx; | |||
GLuint fbo; | |||
GLuint rbo; | |||
GLuint texture; | |||
int image; | |||
}; | |||
typedef struct NVGLUframebuffer NVGLUframebuffer; | |||
// Helper function to create GL frame buffer to render to. | |||
void nvgluBindFramebuffer(NVGLUframebuffer* fb); | |||
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags); | |||
void nvgluDeleteFramebuffer(NVGcontext* ctx, NVGLUframebuffer* fb); | |||
#endif // NANOVG_GL_UTILS_H | |||
#ifdef NANOVG_GL_IMPLEMENTATION | |||
#if defined(NANOVG_GL3) || defined(NANOVG_GLES2) || defined(NANOVG_GLES3) | |||
// FBO is core in OpenGL 3>. | |||
# define NANOVG_FBO_VALID 1 | |||
#elif defined(NANOVG_GL2) | |||
// On OS X including glext defines FBO on GL2 too. | |||
# ifdef __APPLE__ | |||
# include <OpenGL/glext.h> | |||
# define NANOVG_FBO_VALID 1 | |||
# endif | |||
#endif | |||
static GLint defaultFBO = -1; | |||
NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imageFlags) | |||
{ | |||
#ifdef NANOVG_FBO_VALID | |||
GLint defaultFBO; | |||
GLint defaultRBO; | |||
NVGLUframebuffer* fb = NULL; | |||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); | |||
glGetIntegerv(GL_RENDERBUFFER_BINDING, &defaultRBO); | |||
fb = (NVGLUframebuffer*)malloc(sizeof(NVGLUframebuffer)); | |||
if (fb == NULL) goto error; | |||
memset(fb, 0, sizeof(NVGLUframebuffer)); | |||
fb->image = nvgCreateImageRGBA(ctx, w, h, imageFlags | NVG_IMAGE_FLIPY | NVG_IMAGE_PREMULTIPLIED, NULL); | |||
fb->texture = nvglImageHandle(ctx, fb->image); | |||
// frame buffer object | |||
glGenFramebuffers(1, &fb->fbo); | |||
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo); | |||
// render buffer object | |||
glGenRenderbuffers(1, &fb->rbo); | |||
glBindRenderbuffer(GL_RENDERBUFFER, fb->rbo); | |||
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, w, h); | |||
// combine all | |||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); | |||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); | |||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error; | |||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); | |||
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); | |||
return fb; | |||
error: | |||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); | |||
glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); | |||
nvgluDeleteFramebuffer(ctx, fb); | |||
return NULL; | |||
#else | |||
NVG_NOTUSED(ctx); | |||
NVG_NOTUSED(w); | |||
NVG_NOTUSED(h); | |||
NVG_NOTUSED(imageFlags); | |||
return NULL; | |||
#endif | |||
} | |||
void nvgluBindFramebuffer(NVGLUframebuffer* fb) | |||
{ | |||
#ifdef NANOVG_FBO_VALID | |||
if (defaultFBO == -1) glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); | |||
glBindFramebuffer(GL_FRAMEBUFFER, fb != NULL ? fb->fbo : defaultFBO); | |||
#else | |||
NVG_NOTUSED(fb); | |||
#endif | |||
} | |||
void nvgluDeleteFramebuffer(NVGcontext* ctx, NVGLUframebuffer* fb) | |||
{ | |||
#ifdef NANOVG_FBO_VALID | |||
if (fb == NULL) return; | |||
if (fb->fbo != 0) | |||
glDeleteFramebuffers(1, &fb->fbo); | |||
if (fb->rbo != 0) | |||
glDeleteRenderbuffers(1, &fb->rbo); | |||
if (fb->image >= 0) | |||
nvgDeleteImage(ctx, fb->image); | |||
fb->fbo = 0; | |||
fb->rbo = 0; | |||
fb->texture = 0; | |||
fb->image = -1; | |||
free(fb); | |||
#else | |||
NVG_NOTUSED(ctx); | |||
NVG_NOTUSED(fb); | |||
#endif | |||
} | |||
#endif // NANOVG_GL_IMPLEMENTATION |
@@ -1,5 +1,5 @@ | |||
// stb_truetype.h - v0.6c - public domain | |||
// authored from 2009-2012 by Sean Barrett / RAD Game Tools | |||
// stb_truetype.h - v0.8 - public domain | |||
// authored from 2009-2013 by Sean Barrett / RAD Game Tools | |||
// | |||
// This library processes TrueType files: | |||
// parse files | |||
@@ -27,9 +27,15 @@ | |||
// stoiko (Haemimont Games) | |||
// Brian Hook | |||
// Walter van Niftrik | |||
// David Gow | |||
// David Given | |||
// Ivan-Assen Ivanov | |||
// Anthony Pesch | |||
// | |||
// VERSION HISTORY | |||
// | |||
// 0.8 (2014-05-25) fix a few more warnings | |||
// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back | |||
// 0.6c (2012-07-24) improve documentation | |||
// 0.6b (2012-07-20) fix a few more warnings | |||
// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, | |||
@@ -222,7 +228,7 @@ void my_stbtt_print(float x, float y, char *text) | |||
while (*text) { | |||
if (*text >= 32 && *text < 128) { | |||
stbtt_aligned_quad q; | |||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl,0=old d3d | |||
stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 | |||
glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); | |||
glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); | |||
glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); | |||
@@ -291,7 +297,7 @@ int main(int arg, char **argv) | |||
{ | |||
stbtt_fontinfo font; | |||
int i,j,ascent,baseline,ch=0; | |||
float scale, xpos=0; | |||
float scale, xpos=2; // leave a little padding in case the character extends left | |||
char *text = "Heljo World!"; | |||
fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); | |||
@@ -363,10 +369,15 @@ int main(int arg, char **argv) | |||
#define STBTT_iceil(x) ((int) ceil(x)) | |||
#endif | |||
#ifndef STBTT_sqrt | |||
#include <math.h> | |||
#define STBTT_sqrt(x) sqrt(x) | |||
#endif | |||
// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h | |||
#ifndef STBTT_malloc | |||
#include <malloc.h> | |||
#define STBTT_malloc(x,u) malloc(x) | |||
#include <stdlib.h> | |||
#define STBTT_malloc(x,u) ((void)(u),malloc(x)) | |||
#define STBTT_free(x,u) free(x) | |||
#endif | |||
@@ -531,7 +542,6 @@ extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint | |||
extern int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); | |||
// an additional amount to add to the 'advance' value between ch1 and ch2 | |||
// @TODO; for now always returns 0! | |||
extern int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); | |||
// Gets the bounding box of the visible part of the glyph, in unscaled coordinates | |||
@@ -573,6 +583,13 @@ extern int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codep | |||
extern int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); | |||
// returns # of vertices and fills *vertices with the pointer to them | |||
// these are expressed in "unscaled" coordinates | |||
// | |||
// The shape is a series of countours. Each one starts with | |||
// a STBTT_moveto, then consists of a series of mixed | |||
// STBTT_lineto and STBTT_curveto segments. A lineto | |||
// draws a line from previous endpoint to its x,y; a curveto | |||
// draws a quadratic bezier from previous endpoint to | |||
// its x,y, using cx,cy as the bezier control point. | |||
extern void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); | |||
// frees the data allocated above | |||
@@ -916,8 +933,6 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) | |||
search -= 2; | |||
while (entrySelector) { | |||
searchRange >>= 1; | |||
start = ttUSHORT(data + search + 2 + segcount*2 + 2); | |||
end = ttUSHORT(data + search + 2); | |||
start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2); | |||
end = ttUSHORT(data + search + searchRange*2); | |||
if (unicode_codepoint > end) | |||
@@ -1222,8 +1237,8 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte | |||
} | |||
// Find transformation scales. | |||
m = (float) sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); | |||
n = (float) sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); | |||
m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); | |||
n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); | |||
// Get indexed glyph. | |||
comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); | |||
@@ -1246,8 +1261,8 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte | |||
if (comp_verts) STBTT_free(comp_verts, info->userdata); | |||
return 0; | |||
} | |||
if (num_vertices > 0) memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); | |||
memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); | |||
if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); | |||
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); | |||
if (vertices) STBTT_free(vertices, info->userdata); | |||
vertices = tmp; | |||
STBTT_free(comp_verts, info->userdata); | |||
@@ -1759,7 +1774,7 @@ unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float sc | |||
scale_y = scale_x; | |||
} | |||
stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,&ix1,&iy1); | |||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); | |||
// now we get the size | |||
gbm.w = (ix1 - ix0); | |||
@@ -1991,14 +2006,16 @@ static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, | |||
// is this a Unicode encoding? | |||
if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { | |||
stbtt_int32 slen = ttUSHORT(fc+loc+8), off = ttUSHORT(fc+loc+10); | |||
stbtt_int32 slen = ttUSHORT(fc+loc+8); | |||
stbtt_int32 off = ttUSHORT(fc+loc+10); | |||
// check if there's a prefix match | |||
stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); | |||
if (matchlen >= 0) { | |||
// check for target_id+1 immediately following, with same encoding & language | |||
if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { | |||
stbtt_int32 slen = ttUSHORT(fc+loc+12+8), off = ttUSHORT(fc+loc+12+10); | |||
slen = ttUSHORT(fc+loc+12+8); | |||
off = ttUSHORT(fc+loc+12+10); | |||
if (slen == 0) { | |||
if (matchlen == nlen) | |||
return 1; | |||
@@ -0,0 +1,21 @@ | |||
Blendish - Blender 2.5 UI based theming functions for NanoVG | |||
Copyright (c) 2014 Leonard Ritter <leonard.ritter@duangle.com> | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in | |||
all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. |
@@ -0,0 +1,15 @@ | |||
/* (Auto-generated binary data file). */ | |||
#ifndef BINARY_BLENDISH_RESOURCES_H | |||
#define BINARY_BLENDISH_RESOURCES_H | |||
namespace blendish_resources | |||
{ | |||
extern const char* blender_icons16_png; | |||
const unsigned int blender_icons16_png_size = 250706; | |||
extern const char* dejavusans_ttf; | |||
const unsigned int dejavusans_ttf_size = 741536; | |||
}; | |||
#endif |
@@ -0,0 +1,97 @@ | |||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. | |||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) | |||
Bitstream Vera Fonts Copyright | |||
------------------------------ | |||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is | |||
a trademark of Bitstream, Inc. | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of the fonts accompanying this license ("Fonts") and associated | |||
documentation files (the "Font Software"), to reproduce and distribute the | |||
Font Software, including without limitation the rights to use, copy, merge, | |||
publish, distribute, and/or sell copies of the Font Software, and to permit | |||
persons to whom the Font Software is furnished to do so, subject to the | |||
following conditions: | |||
The above copyright and trademark notices and this permission notice shall | |||
be included in all copies of one or more of the Font Software typefaces. | |||
The Font Software may be modified, altered, or added to, and in particular | |||
the designs of glyphs or characters in the Fonts may be modified and | |||
additional glyphs or characters may be added to the Fonts, only if the fonts | |||
are renamed to names not containing either the words "Bitstream" or the word | |||
"Vera". | |||
This License becomes null and void to the extent applicable to Fonts or Font | |||
Software that has been modified and is distributed under the "Bitstream | |||
Vera" names. | |||
The Font Software may be sold as part of a larger software package but no | |||
copy of one or more of the Font Software typefaces may be sold by itself. | |||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, | |||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME | |||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING | |||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, | |||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | |||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE | |||
FONT SOFTWARE. | |||
Except as contained in this notice, the names of Gnome, the Gnome | |||
Foundation, and Bitstream Inc., shall not be used in advertising or | |||
otherwise to promote the sale, use or other dealings in this Font Software | |||
without prior written authorization from the Gnome Foundation or Bitstream | |||
Inc., respectively. For further information, contact: fonts at gnome dot | |||
org. | |||
Arev Fonts Copyright | |||
------------------------------ | |||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. | |||
Permission is hereby granted, free of charge, to any person obtaining | |||
a copy of the fonts accompanying this license ("Fonts") and | |||
associated documentation files (the "Font Software"), to reproduce | |||
and distribute the modifications to the Bitstream Vera Font Software, | |||
including without limitation the rights to use, copy, merge, publish, | |||
distribute, and/or sell copies of the Font Software, and to permit | |||
persons to whom the Font Software is furnished to do so, subject to | |||
the following conditions: | |||
The above copyright and trademark notices and this permission notice | |||
shall be included in all copies of one or more of the Font Software | |||
typefaces. | |||
The Font Software may be modified, altered, or added to, and in | |||
particular the designs of glyphs or characters in the Fonts may be | |||
modified and additional glyphs or characters may be added to the | |||
Fonts, only if the fonts are renamed to names not containing either | |||
the words "Tavmjong Bah" or the word "Arev". | |||
This License becomes null and void to the extent applicable to Fonts | |||
or Font Software that has been modified and is distributed under the | |||
"Tavmjong Bah Arev" names. | |||
The Font Software may be sold as part of a larger software package but | |||
no copy of one or more of the Font Software typefaces may be sold by | |||
itself. | |||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF | |||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT | |||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL | |||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL | |||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM | |||
OTHER DEALINGS IN THE FONT SOFTWARE. | |||
Except as contained in this notice, the name of Tavmjong Bah shall not | |||
be used in advertising or otherwise to promote the sale, use or other | |||
dealings in this Font Software without prior written authorization | |||
from Tavmjong Bah. For further information, contact: tavmjong @ free | |||
. fr. |
@@ -0,0 +1,280 @@ | |||
GNU GENERAL PUBLIC LICENSE | |||
Version 2, June 1991 | |||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
Everyone is permitted to copy and distribute verbatim copies | |||
of this license document, but changing it is not allowed. | |||
Preamble | |||
The licenses for most software are designed to take away your | |||
freedom to share and change it. By contrast, the GNU General Public | |||
License is intended to guarantee your freedom to share and change free | |||
software--to make sure the software is free for all its users. This | |||
General Public License applies to most of the Free Software | |||
Foundation's software and to any other program whose authors commit to | |||
using it. (Some other Free Software Foundation software is covered by | |||
the GNU Library General Public License instead.) You can apply it to | |||
your programs, too. | |||
When we speak of free software, we are referring to freedom, not | |||
price. Our General Public Licenses are designed to make sure that you | |||
have the freedom to distribute copies of free software (and charge for | |||
this service if you wish), that you receive source code or can get it | |||
if you want it, that you can change the software or use pieces of it | |||
in new free programs; and that you know you can do these things. | |||
To protect your rights, we need to make restrictions that forbid | |||
anyone to deny you these rights or to ask you to surrender the rights. | |||
These restrictions translate to certain responsibilities for you if you | |||
distribute copies of the software, or if you modify it. | |||
For example, if you distribute copies of such a program, whether | |||
gratis or for a fee, you must give the recipients all the rights that | |||
you have. You must make sure that they, too, receive or can get the | |||
source code. And you must show them these terms so they know their | |||
rights. | |||
We protect your rights with two steps: (1) copyright the software, and | |||
(2) offer you this license which gives you legal permission to copy, | |||
distribute and/or modify the software. | |||
Also, for each author's protection and ours, we want to make certain | |||
that everyone understands that there is no warranty for this free | |||
software. If the software is modified by someone else and passed on, we | |||
want its recipients to know that what they have is not the original, so | |||
that any problems introduced by others will not reflect on the original | |||
authors' reputations. | |||
Finally, any free program is threatened constantly by software | |||
patents. We wish to avoid the danger that redistributors of a free | |||
program will individually obtain patent licenses, in effect making the | |||
program proprietary. To prevent this, we have made it clear that any | |||
patent must be licensed for everyone's free use or not licensed at all. | |||
The precise terms and conditions for copying, distribution and | |||
modification follow. | |||
GNU GENERAL PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. This License applies to any program or other work which contains | |||
a notice placed by the copyright holder saying it may be distributed | |||
under the terms of this General Public License. The "Program", below, | |||
refers to any such program or work, and a "work based on the Program" | |||
means either the Program or any derivative work under copyright law: | |||
that is to say, a work containing the Program or a portion of it, | |||
either verbatim or with modifications and/or translated into another | |||
language. (Hereinafter, translation is included without limitation in | |||
the term "modification".) Each licensee is addressed as "you". | |||
Activities other than copying, distribution and modification are not | |||
covered by this License; they are outside its scope. The act of | |||
running the Program is not restricted, and the output from the Program | |||
is covered only if its contents constitute a work based on the | |||
Program (independent of having been made by running the Program). | |||
Whether that is true depends on what the Program does. | |||
1. You may copy and distribute verbatim copies of the Program's | |||
source code as you receive it, in any medium, provided that you | |||
conspicuously and appropriately publish on each copy an appropriate | |||
copyright notice and disclaimer of warranty; keep intact all the | |||
notices that refer to this License and to the absence of any warranty; | |||
and give any other recipients of the Program a copy of this License | |||
along with the Program. | |||
You may charge a fee for the physical act of transferring a copy, and | |||
you may at your option offer warranty protection in exchange for a fee. | |||
2. You may modify your copy or copies of the Program or any portion | |||
of it, thus forming a work based on the Program, and copy and | |||
distribute such modifications or work under the terms of Section 1 | |||
above, provided that you also meet all of these conditions: | |||
a) You must cause the modified files to carry prominent notices | |||
stating that you changed the files and the date of any change. | |||
b) You must cause any work that you distribute or publish, that in | |||
whole or in part contains or is derived from the Program or any | |||
part thereof, to be licensed as a whole at no charge to all third | |||
parties under the terms of this License. | |||
c) If the modified program normally reads commands interactively | |||
when run, you must cause it, when started running for such | |||
interactive use in the most ordinary way, to print or display an | |||
announcement including an appropriate copyright notice and a | |||
notice that there is no warranty (or else, saying that you provide | |||
a warranty) and that users may redistribute the program under | |||
these conditions, and telling the user how to view a copy of this | |||
License. (Exception: if the Program itself is interactive but | |||
does not normally print such an announcement, your work based on | |||
the Program is not required to print an announcement.) | |||
These requirements apply to the modified work as a whole. If | |||
identifiable sections of that work are not derived from the Program, | |||
and can be reasonably considered independent and separate works in | |||
themselves, then this License, and its terms, do not apply to those | |||
sections when you distribute them as separate works. But when you | |||
distribute the same sections as part of a whole which is a work based | |||
on the Program, the distribution of the whole must be on the terms of | |||
this License, whose permissions for other licensees extend to the | |||
entire whole, and thus to each and every part regardless of who wrote it. | |||
Thus, it is not the intent of this section to claim rights or contest | |||
your rights to work written entirely by you; rather, the intent is to | |||
exercise the right to control the distribution of derivative or | |||
collective works based on the Program. | |||
In addition, mere aggregation of another work not based on the Program | |||
with the Program (or with a work based on the Program) on a volume of | |||
a storage or distribution medium does not bring the other work under | |||
the scope of this License. | |||
3. You may copy and distribute the Program (or a work based on it, | |||
under Section 2) in object code or executable form under the terms of | |||
Sections 1 and 2 above provided that you also do one of the following: | |||
a) Accompany it with the complete corresponding machine-readable | |||
source code, which must be distributed under the terms of Sections | |||
1 and 2 above on a medium customarily used for software interchange; or, | |||
b) Accompany it with a written offer, valid for at least three | |||
years, to give any third party, for a charge no more than your | |||
cost of physically performing source distribution, a complete | |||
machine-readable copy of the corresponding source code, to be | |||
distributed under the terms of Sections 1 and 2 above on a medium | |||
customarily used for software interchange; or, | |||
c) Accompany it with the information you received as to the offer | |||
to distribute corresponding source code. (This alternative is | |||
allowed only for noncommercial distribution and only if you | |||
received the program in object code or executable form with such | |||
an offer, in accord with Subsection b above.) | |||
The source code for a work means the preferred form of the work for | |||
making modifications to it. For an executable work, complete source | |||
code means all the source code for all modules it contains, plus any | |||
associated interface definition files, plus the scripts used to | |||
control compilation and installation of the executable. However, as a | |||
special exception, the source code distributed need not include | |||
anything that is normally distributed (in either source or binary | |||
form) with the major components (compiler, kernel, and so on) of the | |||
operating system on which the executable runs, unless that component | |||
itself accompanies the executable. | |||
If distribution of executable or object code is made by offering | |||
access to copy from a designated place, then offering equivalent | |||
access to copy the source code from the same place counts as | |||
distribution of the source code, even though third parties are not | |||
compelled to copy the source along with the object code. | |||
4. You may not copy, modify, sublicense, or distribute the Program | |||
except as expressly provided under this License. Any attempt | |||
otherwise to copy, modify, sublicense or distribute the Program is | |||
void, and will automatically terminate your rights under this License. | |||
However, parties who have received copies, or rights, from you under | |||
this License will not have their licenses terminated so long as such | |||
parties remain in full compliance. | |||
5. You are not required to accept this License, since you have not | |||
signed it. However, nothing else grants you permission to modify or | |||
distribute the Program or its derivative works. These actions are | |||
prohibited by law if you do not accept this License. Therefore, by | |||
modifying or distributing the Program (or any work based on the | |||
Program), you indicate your acceptance of this License to do so, and | |||
all its terms and conditions for copying, distributing or modifying | |||
the Program or works based on it. | |||
6. Each time you redistribute the Program (or any work based on the | |||
Program), the recipient automatically receives a license from the | |||
original licensor to copy, distribute or modify the Program subject to | |||
these terms and conditions. You may not impose any further | |||
restrictions on the recipients' exercise of the rights granted herein. | |||
You are not responsible for enforcing compliance by third parties to | |||
this License. | |||
7. If, as a consequence of a court judgment or allegation of patent | |||
infringement or for any other reason (not limited to patent issues), | |||
conditions are imposed on you (whether by court order, agreement or | |||
otherwise) that contradict the conditions of this License, they do not | |||
excuse you from the conditions of this License. If you cannot | |||
distribute so as to satisfy simultaneously your obligations under this | |||
License and any other pertinent obligations, then as a consequence you | |||
may not distribute the Program at all. For example, if a patent | |||
license would not permit royalty-free redistribution of the Program by | |||
all those who receive copies directly or indirectly through you, then | |||
the only way you could satisfy both it and this License would be to | |||
refrain entirely from distribution of the Program. | |||
If any portion of this section is held invalid or unenforceable under | |||
any particular circumstance, the balance of the section is intended to | |||
apply and the section as a whole is intended to apply in other | |||
circumstances. | |||
It is not the purpose of this section to induce you to infringe any | |||
patents or other property right claims or to contest validity of any | |||
such claims; this section has the sole purpose of protecting the | |||
integrity of the free software distribution system, which is | |||
implemented by public license practices. Many people have made | |||
generous contributions to the wide range of software distributed | |||
through that system in reliance on consistent application of that | |||
system; it is up to the author/donor to decide if he or she is willing | |||
to distribute software through any other system and a licensee cannot | |||
impose that choice. | |||
This section is intended to make thoroughly clear what is believed to | |||
be a consequence of the rest of this License. | |||
8. If the distribution and/or use of the Program is restricted in | |||
certain countries either by patents or by copyrighted interfaces, the | |||
original copyright holder who places the Program under this License | |||
may add an explicit geographical distribution limitation excluding | |||
those countries, so that distribution is permitted only in or among | |||
countries not thus excluded. In such case, this License incorporates | |||
the limitation as if written in the body of this License. | |||
9. The Free Software Foundation may publish revised and/or new versions | |||
of the General Public License from time to time. Such new versions will | |||
be similar in spirit to the present version, but may differ in detail to | |||
address new problems or concerns. | |||
Each version is given a distinguishing version number. If the Program | |||
specifies a version number of this License which applies to it and "any | |||
later version", you have the option of following the terms and conditions | |||
either of that version or of any later version published by the Free | |||
Software Foundation. If the Program does not specify a version number of | |||
this License, you may choose any version ever published by the Free Software | |||
Foundation. | |||
10. If you wish to incorporate parts of the Program into other free | |||
programs whose distribution conditions are different, write to the author | |||
to ask for permission. For software which is copyrighted by the Free | |||
Software Foundation, write to the Free Software Foundation; we sometimes | |||
make exceptions for this. Our decision will be guided by the two goals | |||
of preserving the free status of all derivatives of our free software and | |||
of promoting the sharing and reuse of software generally. | |||
NO WARRANTY | |||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||
REPAIR OR CORRECTION. | |||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||
POSSIBILITY OF SUCH DAMAGES. | |||
END OF TERMS AND CONDITIONS |
@@ -0,0 +1,121 @@ | |||
/* | |||
Copyright 2014 David Robillard <http://drobilla.net> | |||
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. | |||
THIS 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. | |||
*/ | |||
#ifndef PUGL_COMMON_H_INCLUDED | |||
#define PUGL_COMMON_H_INCLUDED | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
@addtogroup pugl | |||
@{ | |||
*/ | |||
/** | |||
A Pugl view. | |||
*/ | |||
typedef struct PuglViewImpl PuglView; | |||
/** | |||
A native window handle. | |||
On X11, this is a Window. | |||
On OSX, this is an NSView*. | |||
On Windows, this is a HWND. | |||
*/ | |||
typedef intptr_t PuglNativeWindow; | |||
/** | |||
Handle for opaque user data. | |||
*/ | |||
typedef void* PuglHandle; | |||
/** | |||
Return status code. | |||
*/ | |||
typedef enum { | |||
PUGL_SUCCESS = 0 | |||
} PuglStatus; | |||
/** | |||
Drawing context type. | |||
*/ | |||
typedef enum { | |||
PUGL_GL, | |||
PUGL_CAIRO | |||
} PuglContextType; | |||
/** | |||
Convenience symbols for ASCII control characters. | |||
*/ | |||
typedef enum { | |||
PUGL_CHAR_BACKSPACE = 0x08, | |||
PUGL_CHAR_ESCAPE = 0x1B, | |||
PUGL_CHAR_DELETE = 0x7F | |||
} PuglChar; | |||
/** | |||
Keyboard modifier flags. | |||
*/ | |||
typedef enum { | |||
PUGL_MOD_SHIFT = 1 << 0, /**< Shift key */ | |||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||
} PuglMod; | |||
/** | |||
Special (non-Unicode) keyboard keys. | |||
*/ | |||
typedef enum { | |||
PUGL_KEY_F1 = 1, | |||
PUGL_KEY_F2, | |||
PUGL_KEY_F3, | |||
PUGL_KEY_F4, | |||
PUGL_KEY_F5, | |||
PUGL_KEY_F6, | |||
PUGL_KEY_F7, | |||
PUGL_KEY_F8, | |||
PUGL_KEY_F9, | |||
PUGL_KEY_F10, | |||
PUGL_KEY_F11, | |||
PUGL_KEY_F12, | |||
PUGL_KEY_LEFT, | |||
PUGL_KEY_UP, | |||
PUGL_KEY_RIGHT, | |||
PUGL_KEY_DOWN, | |||
PUGL_KEY_PAGE_UP, | |||
PUGL_KEY_PAGE_DOWN, | |||
PUGL_KEY_HOME, | |||
PUGL_KEY_END, | |||
PUGL_KEY_INSERT, | |||
PUGL_KEY_SHIFT, | |||
PUGL_KEY_CTRL, | |||
PUGL_KEY_ALT, | |||
PUGL_KEY_SUPER | |||
} PuglKey; | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* PUGL_COMMON_H_INCLUDED */ |
@@ -0,0 +1,41 @@ | |||
/* | |||
Copyright 2014 David Robillard <http://drobilla.net> | |||
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. | |||
THIS 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. | |||
*/ | |||
#ifndef PUGL_EVENT_H_INCLUDED | |||
#define PUGL_EVENT_H_INCLUDED | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
#include "pugl/common.h" | |||
/** | |||
@addtogroup pugl | |||
@{ | |||
*/ | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* PUGL_EVENT_H_INCLUDED */ |
@@ -0,0 +1,32 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
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. | |||
THIS 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. | |||
*/ | |||
/** | |||
@file gl.h Portable header wrapper for gl.h. | |||
Unfortunately, GL includes vary across platforms so this header allows for | |||
pure portable programs. | |||
*/ | |||
#ifdef __APPLE__ | |||
# include "OpenGL/gl.h" | |||
#else | |||
# ifdef _WIN32 | |||
# include <windows.h> /* Broken Windows GL headers require this */ | |||
# endif | |||
# include "GL/gl.h" | |||
#endif | |||
@@ -0,0 +1,32 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
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. | |||
THIS 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. | |||
*/ | |||
/** | |||
@file glu.h Portable header wrapper for glu.h. | |||
Unfortunately, GL includes vary across platforms so this header allows for | |||
pure portable programs. | |||
*/ | |||
#ifdef __APPLE__ | |||
# include "OpenGL/glu.h" | |||
#else | |||
# ifdef _WIN32 | |||
# include <windows.h> /* Broken Windows GL headers require this */ | |||
# endif | |||
# include "GL/glu.h" | |||
#endif | |||
@@ -23,19 +23,8 @@ | |||
#include <stdint.h> | |||
/* | |||
This API is pure portable C and contains no platform specific elements, or | |||
even a GL dependency. However, unfortunately GL includes vary across | |||
platforms so they are included here to allow for pure portable programs. | |||
*/ | |||
#ifdef __APPLE__ | |||
# include "OpenGL/gl.h" | |||
#else | |||
# ifdef _WIN32 | |||
# include <windows.h> /* Broken Windows GL headers require this */ | |||
# endif | |||
# include "GL/gl.h" | |||
#endif | |||
#include "pugl/common.h" | |||
#include "pugl/event.h" | |||
#ifdef PUGL_SHARED | |||
# ifdef _WIN32 | |||
@@ -70,82 +59,6 @@ extern "C" { | |||
@{ | |||
*/ | |||
/** | |||
An OpenGL view. | |||
*/ | |||
typedef struct PuglViewImpl PuglView; | |||
/** | |||
A native window handle. | |||
On X11, this is a Window. | |||
On OSX, this is an NSView*. | |||
On Windows, this is a HWND. | |||
*/ | |||
typedef intptr_t PuglNativeWindow; | |||
/** | |||
Return status code. | |||
*/ | |||
typedef enum { | |||
PUGL_SUCCESS = 0 | |||
} PuglStatus; | |||
/** | |||
Convenience symbols for ASCII control characters. | |||
*/ | |||
typedef enum { | |||
PUGL_CHAR_BACKSPACE = 0x08, | |||
PUGL_CHAR_ESCAPE = 0x1B, | |||
PUGL_CHAR_DELETE = 0x7F | |||
} PuglChar; | |||
/** | |||
Special (non-Unicode) keyboard keys. | |||
*/ | |||
typedef enum { | |||
PUGL_KEY_F1 = 1, | |||
PUGL_KEY_F2, | |||
PUGL_KEY_F3, | |||
PUGL_KEY_F4, | |||
PUGL_KEY_F5, | |||
PUGL_KEY_F6, | |||
PUGL_KEY_F7, | |||
PUGL_KEY_F8, | |||
PUGL_KEY_F9, | |||
PUGL_KEY_F10, | |||
PUGL_KEY_F11, | |||
PUGL_KEY_F12, | |||
PUGL_KEY_LEFT, | |||
PUGL_KEY_UP, | |||
PUGL_KEY_RIGHT, | |||
PUGL_KEY_DOWN, | |||
PUGL_KEY_PAGE_UP, | |||
PUGL_KEY_PAGE_DOWN, | |||
PUGL_KEY_HOME, | |||
PUGL_KEY_END, | |||
PUGL_KEY_INSERT, | |||
PUGL_KEY_SHIFT, | |||
PUGL_KEY_CTRL, | |||
PUGL_KEY_ALT, | |||
PUGL_KEY_SUPER | |||
} PuglKey; | |||
/** | |||
Keyboard modifier flags. | |||
*/ | |||
typedef enum { | |||
PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||
} PuglMod; | |||
/** | |||
Handle for opaque user data. | |||
*/ | |||
typedef void* PuglHandle; | |||
/** | |||
A function called when the window is closed. | |||
*/ | |||
@@ -227,6 +140,12 @@ typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||
*/ | |||
typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); | |||
/** | |||
@name Initialization | |||
Configuration functions which must be called before creating a window. | |||
@{ | |||
*/ | |||
/** | |||
Create a Pugl context. | |||
@@ -248,12 +167,43 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent); | |||
PUGL_API void | |||
puglInitWindowSize(PuglView* view, int width, int height); | |||
/** | |||
Set the minimum window size before creating a window. | |||
*/ | |||
PUGL_API void | |||
puglInitWindowMinSize(PuglView* view, int width, int height); | |||
/** | |||
Enable or disable resizing before creating a window. | |||
*/ | |||
PUGL_API void | |||
puglInitUserResizable(PuglView* view, bool resizable); | |||
/** | |||
Set transient parent before creating a window. | |||
On X11, parent_id must be a Window. | |||
On OSX, parent_id must be an NSView*. | |||
*/ | |||
PUGL_API void | |||
puglInitTransientFor(PuglView* view, uintptr_t parent); | |||
/** | |||
Set the context type before creating a window. | |||
*/ | |||
PUGL_API void | |||
puglInitContextType(PuglView* view, PuglContextType type); | |||
/** | |||
@} | |||
*/ | |||
/** | |||
@name Windows | |||
Window management functions. | |||
@{ | |||
*/ | |||
/** | |||
Create a window with the settings given by the various puglInit functions. | |||
@@ -274,6 +224,16 @@ puglShowWindow(PuglView* view); | |||
PUGL_API void | |||
puglHideWindow(PuglView* view); | |||
/** | |||
Return the native window handle. | |||
*/ | |||
PUGL_API PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view); | |||
/** | |||
@} | |||
*/ | |||
/** | |||
Set the handle to be passed to all callbacks. | |||
@@ -292,6 +252,15 @@ puglSetHandle(PuglView* view, PuglHandle handle); | |||
PUGL_API PuglHandle | |||
puglGetHandle(PuglView* view); | |||
/** | |||
Get the drawing context. | |||
For PUGL_GL contexts, this is unused and returns NULL. | |||
For PUGL_CAIRO contexts, this returns a pointer to a cairo_t. | |||
*/ | |||
PUGL_API void* | |||
puglGetContext(PuglView* view); | |||
/** | |||
Return the timestamp (if any) of the currently-processing event. | |||
*/ | |||
@@ -312,6 +281,12 @@ puglGetModifiers(PuglView* view); | |||
PUGL_API void | |||
puglIgnoreKeyRepeat(PuglView* view, bool ignore); | |||
/** | |||
@name Event Callbacks | |||
Functions to set event callbacks for handling user input. | |||
@{ | |||
*/ | |||
/** | |||
Set the function to call when the window is closed. | |||
*/ | |||
@@ -367,10 +342,14 @@ PUGL_API void | |||
puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); | |||
/** | |||
Return the native window handle. | |||
@} | |||
*/ | |||
PUGL_API PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view); | |||
/** | |||
Grab the input focus. | |||
*/ | |||
PUGL_API void | |||
puglGrabFocus(PuglView* view); | |||
/** | |||
Process all pending window events. | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -24,11 +24,14 @@ | |||
If you are copying the pugl code into your source tree, the following | |||
symbols can be defined to tweak pugl behaviour: | |||
PUGL_HAVE_CAIRO: Include Cairo support code. | |||
PUGL_HAVE_GL: Include OpenGL support code. | |||
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||
PUGL_VERBOSE: Print GL information to console. | |||
*/ | |||
#include "pugl.h" | |||
#include "pugl/pugl.h" | |||
#include "pugl/event.h" | |||
#ifdef PUGL_VERBOSE | |||
# include <stdio.h> | |||
@@ -54,10 +57,15 @@ struct PuglViewImpl { | |||
PuglFileSelectedFunc fileSelectedFunc; | |||
PuglInternals* impl; | |||
PuglNativeWindow parent; | |||
PuglContextType ctx_type; | |||
uintptr_t transient_parent; | |||
int width; | |||
int height; | |||
int min_width; | |||
int min_height; | |||
int mods; | |||
bool mouse_in_view; | |||
bool ignoreKeyRepeat; | |||
@@ -96,6 +104,13 @@ puglInitWindowSize(PuglView* view, int width, int height) | |||
view->height = height; | |||
} | |||
void | |||
puglInitWindowMinSize(PuglView* view, int width, int height) | |||
{ | |||
view->min_width = width; | |||
view->min_height = height; | |||
} | |||
void | |||
puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||
{ | |||
@@ -103,11 +118,23 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||
} | |||
void | |||
puglInitResizable(PuglView* view, bool resizable) | |||
puglInitUserResizable(PuglView* view, bool resizable) | |||
{ | |||
view->resizable = resizable; | |||
} | |||
void | |||
puglInitTransientFor(PuglView* view, uintptr_t parent) | |||
{ | |||
view->transient_parent = parent; | |||
} | |||
void | |||
puglInitContextType(PuglView* view, PuglContextType type) | |||
{ | |||
view->ctx_type = type; | |||
} | |||
void | |||
puglSetHandle(PuglView* view, PuglHandle handle) | |||
{ | |||
@@ -132,22 +159,6 @@ puglGetModifiers(PuglView* view) | |||
return view->mods; | |||
} | |||
static void | |||
puglDefaultReshape(PuglView* view, int width, int height) | |||
{ | |||
glMatrixMode(GL_PROJECTION); | |||
glLoadIdentity(); | |||
glOrtho(0, width, height, 0, 0, 1); | |||
glViewport(0, 0, width, height); | |||
glMatrixMode(GL_MODELVIEW); | |||
glLoadIdentity(); | |||
return; | |||
// unused | |||
(void)view; | |||
} | |||
void | |||
puglIgnoreKeyRepeat(PuglView* view, bool ignore) | |||
{ | |||
@@ -207,3 +218,135 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc) | |||
{ | |||
view->fileSelectedFunc = fileSelectedFunc; | |||
} | |||
void | |||
puglEnterContext(PuglView* view); | |||
void | |||
puglLeaveContext(PuglView* view, bool flush); | |||
#if 0 | |||
/** Return the code point for buf, or the replacement character on error. */ | |||
static uint32_t | |||
puglDecodeUTF8(const uint8_t* buf) | |||
{ | |||
#define FAIL_IF(cond) { if (cond) return 0xFFFD; } | |||
/* http://en.wikipedia.org/wiki/UTF-8 */ | |||
if (buf[0] < 0x80) { | |||
return buf[0]; | |||
} else if (buf[0] < 0xC2) { | |||
return 0xFFFD; | |||
} else if (buf[0] < 0xE0) { | |||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||
return (buf[0] << 6) + buf[1] - 0x3080; | |||
} else if (buf[0] < 0xF0) { | |||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||
FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); | |||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||
return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080; | |||
} else if (buf[0] < 0xF5) { | |||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||
FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); | |||
FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); | |||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||
FAIL_IF((buf[3] & 0xC0) != 0x80); | |||
return ((buf[0] << 18) + | |||
(buf[1] << 12) + | |||
(buf[2] << 6) + | |||
buf[3] - 0x3C82080); | |||
} | |||
return 0xFFFD; | |||
} | |||
#endif | |||
static void | |||
puglDefaultReshape(PuglView* view, int width, int height) | |||
{ | |||
glMatrixMode(GL_PROJECTION); | |||
glLoadIdentity(); | |||
glOrtho(0, width, height, 0, 0, 1); | |||
glViewport(0, 0, width, height); | |||
glMatrixMode(GL_MODELVIEW); | |||
glLoadIdentity(); | |||
return; | |||
// unused | |||
(void)view; | |||
} | |||
#if 0 | |||
static void | |||
puglDispatchEvent(PuglView* view, const PuglEvent* event) | |||
{ | |||
if (view->eventFunc) { | |||
view->eventFunc(view, event); | |||
} | |||
switch (event->type) { | |||
case PUGL_CONFIGURE: | |||
puglEnterContext(view); | |||
view->width = event->configure.width; | |||
view->height = event->configure.height; | |||
if (view->reshapeFunc) { | |||
view->reshapeFunc(view, view->width, view->height); | |||
} | |||
puglLeaveContext(view, false); | |||
break; | |||
case PUGL_EXPOSE: | |||
if (event->expose.count == 0) { | |||
puglEnterContext(view); | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
view->redisplay = false; | |||
puglLeaveContext(view, true); | |||
} | |||
break; | |||
case PUGL_MOTION_NOTIFY: | |||
view->event_timestamp_ms = event->motion.time; | |||
view->mods = event->motion.state; | |||
if (view->motionFunc) { | |||
view->motionFunc(view, event->motion.x, event->motion.y); | |||
} | |||
break; | |||
case PUGL_SCROLL: | |||
if (view->scrollFunc) { | |||
view->scrollFunc(view, | |||
event->scroll.x, event->scroll.y, | |||
event->scroll.dx, event->scroll.dy); | |||
} | |||
break; | |||
case PUGL_BUTTON_PRESS: | |||
case PUGL_BUTTON_RELEASE: | |||
view->event_timestamp_ms = event->button.time; | |||
view->mods = event->button.state; | |||
if (view->mouseFunc) { | |||
view->mouseFunc(view, | |||
event->button.button, | |||
event->type == PUGL_BUTTON_PRESS, | |||
event->button.x, | |||
event->button.y); | |||
} | |||
break; | |||
case PUGL_KEY_PRESS: | |||
case PUGL_KEY_RELEASE: | |||
view->event_timestamp_ms = event->key.time; | |||
view->mods = event->key.state; | |||
if (event->key.special && view->specialFunc) { | |||
view->specialFunc(view, | |||
event->type == PUGL_KEY_PRESS, | |||
event->key.special); | |||
} else if (event->key.character && view->keyboardFunc) { | |||
view->keyboardFunc(view, | |||
event->type == PUGL_KEY_PRESS, | |||
event->key.character); | |||
} | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
#endif |
@@ -187,12 +187,9 @@ puglDisplay(PuglView* view) | |||
printf("Is doubleBuffered? FALSE\n"); | |||
} | |||
if (self) { | |||
NSOpenGLContext* context = [self openGLContext]; | |||
[context makeCurrentContext]; | |||
if (self) { | |||
GLint swapInterval = 1; | |||
[context setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; | |||
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; | |||
[self reshape]; | |||
} | |||
@@ -216,26 +213,25 @@ puglDisplay(PuglView* view) | |||
int width = bounds.size.width; | |||
int height = bounds.size.height; | |||
puglEnterContext(puglview); | |||
if (puglview->reshapeFunc) { | |||
puglview->reshapeFunc(puglview, width, height); | |||
} else { | |||
puglDefaultReshape(puglview, width, height); | |||
} | |||
puglLeaveContext(puglview, false); | |||
puglview->width = width; | |||
puglview->height = height; | |||
} | |||
- (void) drawRect:(NSRect)r | |||
{ | |||
puglEnterContext(puglview); | |||
puglDisplay(puglview); | |||
if (doubleBuffered) { | |||
[[self openGLContext] flushBuffer]; | |||
} else { | |||
glFlush(); | |||
//glSwapAPPLE(); | |||
} | |||
puglLeaveContext(puglview, true); | |||
// unused | |||
return; (void)r; | |||
@@ -428,6 +424,31 @@ puglInitInternals() | |||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
} | |||
void | |||
puglEnterContext(PuglView* view) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
[[view->impl->glview openGLContext] makeCurrentContext]; | |||
} | |||
#endif | |||
} | |||
void | |||
puglLeaveContext(PuglView* view, bool flush) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL && flush) { | |||
if (view->impl->glview->doubleBuffered) { | |||
[[view->impl->glview openGLContext] flushBuffer]; | |||
} else { | |||
glFlush(); | |||
} | |||
//[NSOpenGLContext clearCurrentContext]; | |||
} | |||
#endif | |||
} | |||
int | |||
puglCreateWindow(PuglView* view, const char* title) | |||
{ | |||
@@ -544,3 +565,9 @@ puglGetNativeWindow(PuglView* view) | |||
{ | |||
return (PuglNativeWindow)view->impl->glview; | |||
} | |||
void* | |||
puglGetContext(PuglView* view) | |||
{ | |||
return NULL; | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -18,15 +18,16 @@ | |||
@file pugl_win.cpp Windows/WGL Pugl Implementation. | |||
*/ | |||
#include <winsock2.h> | |||
#include <windows.h> | |||
#include <windowsx.h> | |||
#include <GL/gl.h> | |||
#include <ctime> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <cstdio> | |||
#include <cstdlib> | |||
#include "pugl_internal.h" | |||
#include "pugl/pugl_internal.h" | |||
#ifndef WM_MOUSEWHEEL | |||
# define WM_MOUSEWHEEL 0x020A | |||
@@ -37,8 +38,11 @@ | |||
#ifndef WHEEL_DELTA | |||
# define WHEEL_DELTA 120 | |||
#endif | |||
#ifndef GWLP_USERDATA | |||
# define GWLP_USERDATA (-21) | |||
#endif | |||
const int LOCAL_CLOSE_MSG = WM_USER + 50; | |||
#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) | |||
HINSTANCE hInstance = NULL; | |||
@@ -69,6 +73,27 @@ puglInitInternals() | |||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
} | |||
void | |||
puglEnterContext(PuglView* view) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
} | |||
#endif | |||
} | |||
void | |||
puglLeaveContext(PuglView* view, bool flush) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL && flush) { | |||
glFlush(); | |||
SwapBuffers(view->impl->hdc); | |||
} | |||
#endif | |||
} | |||
int | |||
puglCreateWindow(PuglView* view, const char* title) | |||
{ | |||
@@ -104,8 +129,19 @@ puglCreateWindow(PuglView* view, const char* title) | |||
return 1; | |||
} | |||
// Adjust the overall window size to accomodate our requested client size | |||
const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (view->resizable ? WS_SIZEBOX : 0x0); | |||
int winFlags = WS_POPUPWINDOW | WS_CAPTION; | |||
if (view->resizable) { | |||
winFlags |= WS_SIZEBOX; | |||
if (view->min_width > 0 && view->min_height > 0) { | |||
// Adjust the minimum window size to accomodate requested view size | |||
RECT mr = { 0, 0, view->min_width, view->min_height }; | |||
AdjustWindowRectEx(&mr, view->parent ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); | |||
view->min_width = mr.right - mr.left; | |||
view->min_height = mr.bottom - mr.top; | |||
} | |||
} | |||
// Adjust the window size to accomodate requested view size | |||
RECT wr = { 0, 0, view->width, view->height }; | |||
AdjustWindowRectEx(&wr, view->parent ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); | |||
@@ -152,25 +188,19 @@ puglCreateWindow(PuglView* view, const char* title) | |||
return 1; | |||
} | |||
wglMakeCurrent(impl->hdc, impl->hglrc); | |||
return 0; | |||
return PUGL_SUCCESS; | |||
} | |||
void | |||
puglShowWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
ShowWindow(impl->hwnd, SW_SHOWNORMAL); | |||
ShowWindow(view->impl->hwnd, SW_SHOWNORMAL); | |||
} | |||
void | |||
puglHideWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
ShowWindow(impl->hwnd, SW_HIDE); | |||
ShowWindow(view->impl->hwnd, SW_HIDE); | |||
} | |||
void | |||
@@ -189,7 +219,7 @@ puglDestroy(PuglView* view) | |||
static void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
puglEnterContext(view); | |||
if (view->reshapeFunc) { | |||
view->reshapeFunc(view, width, height); | |||
@@ -204,15 +234,14 @@ puglReshape(PuglView* view, int width, int height) | |||
static void | |||
puglDisplay(PuglView* view) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
puglEnterContext(view); | |||
view->redisplay = false; | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
glFlush(); | |||
SwapBuffers(view->impl->hdc); | |||
puglLeaveContext(view, true); | |||
} | |||
static PuglKey | |||
@@ -282,18 +311,24 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
{ | |||
PAINTSTRUCT ps; | |||
PuglKey key; | |||
RECT rect; | |||
MINMAXINFO* mmi; | |||
setModifiers(view); | |||
switch (message) { | |||
case WM_CREATE: | |||
case WM_SHOWWINDOW: | |||
case WM_SIZE: | |||
RECT rect; | |||
GetClientRect(view->impl->hwnd, &rect); | |||
puglReshape(view, rect.right, rect.bottom); | |||
view->width = rect.right; | |||
view->height = rect.bottom; | |||
break; | |||
case WM_GETMINMAXINFO: | |||
mmi = (MINMAXINFO*)lParam; | |||
mmi->ptMinTrackSize.x = view->min_width; | |||
mmi->ptMinTrackSize.y = view->min_height; | |||
break; | |||
case WM_PAINT: | |||
BeginPaint(view->impl->hwnd, &ps); | |||
puglDisplay(view); | |||
@@ -301,6 +336,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
break; | |||
case WM_MOUSEMOVE: | |||
if (view->motionFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); | |||
} | |||
break; | |||
@@ -329,7 +365,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
ScreenToClient(view->impl->hwnd, &pt); | |||
view->scrollFunc( | |||
view, pt.x, pt.y, | |||
0, GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA); | |||
0.0f, GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA); | |||
} | |||
break; | |||
case WM_MOUSEHWHEEL: | |||
@@ -339,7 +375,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
ScreenToClient(view->impl->hwnd, &pt); | |||
view->scrollFunc( | |||
view, pt.x, pt.y, | |||
GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0); | |||
GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f); | |||
} | |||
break; | |||
case WM_KEYDOWN: | |||
@@ -364,9 +400,10 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
} | |||
break; | |||
case WM_QUIT: | |||
case LOCAL_CLOSE_MSG: | |||
case PUGL_LOCAL_CLOSE_MSG: | |||
if (view->closeFunc) { | |||
view->closeFunc(view); | |||
view->redisplay = false; | |||
} | |||
break; | |||
default: | |||
@@ -377,6 +414,12 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
return 0; | |||
} | |||
void | |||
puglGrabFocus(PuglView* view) | |||
{ | |||
// TODO | |||
} | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
@@ -402,7 +445,7 @@ wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||
PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); | |||
return 0; | |||
case WM_CLOSE: | |||
PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam); | |||
PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); | |||
return 0; | |||
case WM_DESTROY: | |||
return 0; | |||
@@ -426,3 +469,14 @@ puglGetNativeWindow(PuglView* view) | |||
{ | |||
return (PuglNativeWindow)view->impl->hwnd; | |||
} | |||
void* | |||
puglGetContext(PuglView* view) | |||
{ | |||
#ifdef PUGL_HAVE_CAIRO | |||
if (view->ctx_type == PUGL_CAIRO) { | |||
// TODO | |||
} | |||
#endif | |||
return NULL; | |||
} |
@@ -1,7 +1,7 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||
Copyright 2013 Robin Gareus <robin@gareus.org> | |||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -24,13 +24,22 @@ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <GL/gl.h> | |||
#include <GL/glx.h> | |||
#include <X11/Xatom.h> | |||
#include <X11/Xlib.h> | |||
#include <X11/Xutil.h> | |||
#include <X11/keysym.h> | |||
#include "pugl_internal.h" | |||
#ifdef PUGL_HAVE_GL | |||
#include <GL/gl.h> | |||
#include <GL/glx.h> | |||
#endif | |||
#ifdef PUGL_HAVE_CAIRO | |||
#include <cairo/cairo.h> | |||
#include <cairo/cairo-xlib.h> | |||
#endif | |||
#include "pugl/pugl_internal.h" | |||
#define SOFD_HAVE_X11 | |||
#include "../sofd/libsofd.h" | |||
@@ -40,53 +49,16 @@ struct PuglInternalsImpl { | |||
Display* display; | |||
int screen; | |||
Window win; | |||
XIM xim; | |||
XIC xic; | |||
#ifdef PUGL_HAVE_CAIRO | |||
cairo_t* cr; | |||
cairo_surface_t* surface; | |||
#endif | |||
#ifdef PUGL_HAVE_GL | |||
GLXContext ctx; | |||
Bool doubleBuffered; | |||
}; | |||
/** | |||
Attributes for single-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
static int attrListSgl[] = { | |||
GLX_RGBA, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
GLX_ARB_multisample, 1, | |||
None | |||
}; | |||
/** | |||
Attributes for double-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
static int attrListDbl[] = { | |||
GLX_RGBA, GLX_DOUBLEBUFFER, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
GLX_ARB_multisample, 1, | |||
None | |||
}; | |||
/** | |||
Attributes for double-buffered RGBA with multi-sampling | |||
(antialiasing) | |||
*/ | |||
static int attrListDblMS[] = { | |||
GLX_RGBA, | |||
GLX_DOUBLEBUFFER , True, | |||
GLX_RED_SIZE , 4, | |||
GLX_GREEN_SIZE , 4, | |||
GLX_BLUE_SIZE , 4, | |||
GLX_ALPHA_SIZE , 4, | |||
GLX_DEPTH_SIZE , 16, | |||
GLX_SAMPLE_BUFFERS , 1, | |||
GLX_SAMPLES , 4, | |||
None | |||
#endif | |||
}; | |||
PuglInternals* | |||
@@ -95,33 +67,186 @@ puglInitInternals(void) | |||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
} | |||
static XVisualInfo* | |||
getVisual(PuglView* view) | |||
{ | |||
PuglInternals* const impl = view->impl; | |||
XVisualInfo* vi = NULL; | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
/** | |||
Attributes for single-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
int attrListSgl[] = { | |||
GLX_RGBA, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
GLX_ARB_multisample, 1, | |||
None | |||
}; | |||
/** | |||
Attributes for double-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
int attrListDbl[] = { | |||
GLX_RGBA, | |||
GLX_DOUBLEBUFFER, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
GLX_ARB_multisample, 1, | |||
None | |||
}; | |||
/** | |||
Attributes for double-buffered RGBA with multi-sampling | |||
(antialiasing) | |||
*/ | |||
int attrListDblMS[] = { | |||
GLX_RGBA, | |||
GLX_DOUBLEBUFFER, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_ALPHA_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
GLX_SAMPLE_BUFFERS, 1, | |||
GLX_SAMPLES, 4, | |||
None | |||
}; | |||
impl->doubleBuffered = True; | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||
if (vi == NULL) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||
PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||
} | |||
if (vi == NULL) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
impl->doubleBuffered = False; | |||
PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||
} | |||
} | |||
#endif | |||
#ifdef PUGL_HAVE_CAIRO | |||
if (view->ctx_type == PUGL_CAIRO) { | |||
XVisualInfo pat; | |||
int n; | |||
pat.screen = impl->screen; | |||
vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); | |||
} | |||
#endif | |||
return vi; | |||
} | |||
static bool | |||
createContext(PuglView* view, XVisualInfo* vi) | |||
{ | |||
PuglInternals* const impl = view->impl; | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
return (impl->ctx != NULL); | |||
} | |||
#endif | |||
#ifdef PUGL_HAVE_CAIRO | |||
if (view->ctx_type == PUGL_CAIRO) { | |||
impl->surface = cairo_xlib_surface_create( | |||
impl->display, impl->win, vi->visual, view->width, view->height); | |||
if (impl->surface == NULL) { | |||
PUGL_LOG("failed to create cairo surface\n"); | |||
return false; | |||
} | |||
impl->cr = cairo_create(impl->surface); | |||
if (impl->cr == NULL) { | |||
cairo_surface_destroy(impl->surface); | |||
impl->surface = NULL; | |||
PUGL_LOG("failed to create cairo context\n"); | |||
return false; | |||
} | |||
return true; | |||
} | |||
#endif | |||
return false; | |||
} | |||
static void | |||
destroyContext(PuglView* view) | |||
{ | |||
PuglInternals* const impl = view->impl; | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
glXDestroyContext(impl->display, impl->ctx); | |||
impl->ctx = NULL; | |||
} | |||
#endif | |||
#ifdef PUGL_HAVE_CAIRO | |||
if (view->ctx_type == PUGL_CAIRO) { | |||
cairo_destroy(impl->cr); | |||
impl->cr = NULL; | |||
cairo_surface_destroy(impl->surface); | |||
impl->surface = NULL; | |||
} | |||
#endif | |||
} | |||
void | |||
puglEnterContext(PuglView* view) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL) { | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
} | |||
#endif | |||
} | |||
void | |||
puglLeaveContext(PuglView* view, bool flush) | |||
{ | |||
#ifdef PUGL_HAVE_GL | |||
if (view->ctx_type == PUGL_GL && flush) { | |||
glFlush(); | |||
if (view->impl->doubleBuffered) { | |||
glXSwapBuffers(view->impl->display, view->impl->win); | |||
} | |||
} | |||
#endif | |||
} | |||
int | |||
puglCreateWindow(PuglView* view, const char* title) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
PuglInternals* const impl = view->impl; | |||
impl->display = XOpenDisplay(NULL); | |||
impl->screen = DefaultScreen(impl->display); | |||
impl->doubleBuffered = True; | |||
XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||
if (!vi) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||
PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||
} | |||
XVisualInfo* const vi = getVisual(view); | |||
if (!vi) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
impl->doubleBuffered = False; | |||
PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||
XCloseDisplay(impl->display); | |||
impl->display = NULL; | |||
return 1; | |||
} | |||
#ifdef PUGL_HAVE_GL | |||
int glxMajor, glxMinor; | |||
glXQueryVersion(impl->display, &glxMajor, &glxMinor); | |||
PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
#endif | |||
Window xParent = view->parent | |||
? (Window)view->parent | |||
@@ -132,20 +257,29 @@ puglCreateWindow(PuglView* view, const char* title) | |||
XSetWindowAttributes attr; | |||
memset(&attr, 0, sizeof(XSetWindowAttributes)); | |||
attr.colormap = cmap; | |||
attr.border_pixel = 0; | |||
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | |||
| ButtonPressMask | ButtonReleaseMask | |||
#ifdef PUGL_GRAB_FOCUS | |||
| EnterWindowMask | |||
#endif | |||
| PointerMotionMask | StructureNotifyMask; | |||
attr.background_pixel = BlackPixel(impl->display, impl->screen); | |||
attr.border_pixel = BlackPixel(impl->display, impl->screen); | |||
attr.colormap = cmap; | |||
attr.event_mask = (ExposureMask | StructureNotifyMask | | |||
EnterWindowMask | LeaveWindowMask | | |||
KeyPressMask | KeyReleaseMask | | |||
ButtonPressMask | ButtonReleaseMask | | |||
PointerMotionMask | FocusChangeMask); | |||
impl->win = XCreateWindow( | |||
impl->display, xParent, | |||
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | |||
CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
if (!createContext(view, vi)) { | |||
XDestroyWindow(impl->display, impl->win); | |||
impl->win = 0; | |||
XCloseDisplay(impl->display); | |||
impl->display = NULL; | |||
return 1; | |||
} | |||
XSizeHints sizeHints; | |||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||
@@ -156,6 +290,11 @@ puglCreateWindow(PuglView* view, const char* title) | |||
sizeHints.max_width = view->width; | |||
sizeHints.max_height = view->height; | |||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||
} else if (view->min_width > 0 && view->min_height > 0) { | |||
sizeHints.flags = PMinSize; | |||
sizeHints.min_width = view->min_width; | |||
sizeHints.min_height = view->min_height; | |||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||
} | |||
if (title) { | |||
@@ -175,25 +314,19 @@ puglCreateWindow(PuglView* view, const char* title) | |||
XFree(vi); | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
return 0; | |||
return PUGL_SUCCESS; | |||
} | |||
void | |||
puglShowWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
XMapRaised(impl->display, impl->win); | |||
XMapRaised(view->impl->display, view->impl->win); | |||
} | |||
void | |||
puglHideWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
XUnmapWindow(impl->display, impl->win); | |||
XUnmapWindow(view->impl->display, view->impl->win); | |||
} | |||
void | |||
@@ -203,7 +336,9 @@ puglDestroy(PuglView* view) | |||
return; | |||
} | |||
glXDestroyContext(view->impl->display, view->impl->ctx); | |||
x_fib_close(view->impl->display); | |||
destroyContext(view); | |||
XDestroyWindow(view->impl->display, view->impl->win); | |||
XCloseDisplay(view->impl->display); | |||
free(view->impl); | |||
@@ -213,7 +348,7 @@ puglDestroy(PuglView* view) | |||
static void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
puglEnterContext(view); | |||
if (view->reshapeFunc) { | |||
view->reshapeFunc(view, width, height); | |||
@@ -221,6 +356,8 @@ puglReshape(PuglView* view, int width, int height) | |||
puglDefaultReshape(view, width, height); | |||
} | |||
puglLeaveContext(view, false); | |||
view->width = width; | |||
view->height = height; | |||
} | |||
@@ -228,7 +365,7 @@ puglReshape(PuglView* view, int width, int height) | |||
static void | |||
puglDisplay(PuglView* view) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
puglEnterContext(view); | |||
view->redisplay = false; | |||
@@ -236,11 +373,7 @@ puglDisplay(PuglView* view) | |||
view->displayFunc(view); | |||
} | |||
glFlush(); | |||
if (view->impl->doubleBuffered) { | |||
glXSwapBuffers(view->impl->display, view->impl->win); | |||
} | |||
puglLeaveContext(view, true); | |||
} | |||
static PuglKey | |||
@@ -346,6 +479,10 @@ puglProcessEvents(PuglView* view) | |||
break; | |||
} | |||
if (event.xany.window != view->impl->win) { | |||
continue; | |||
} | |||
switch (event.type) { | |||
case MapNotify: | |||
puglReshape(view, view->width, view->height); | |||
@@ -456,3 +593,17 @@ puglGetNativeWindow(PuglView* view) | |||
{ | |||
return view->impl->win; | |||
} | |||
void* | |||
puglGetContext(PuglView* view) | |||
{ | |||
#ifdef PUGL_HAVE_CAIRO | |||
if (view->ctx_type == PUGL_CAIRO) { | |||
return view->impl->cr; | |||
} | |||
#endif | |||
return NULL; | |||
// may be unused | |||
(void)view; | |||
} |
@@ -21,14 +21,14 @@ | |||
* THE SOFTWARE. | |||
*/ | |||
#ifdef SOFD_HAVE_X11 | |||
#ifndef LIBSOFD_H | |||
#define LIBSOFD_H | |||
#include <X11/Xlib.h> | |||
/////////////////////////////////////////////////////////////////////////////// | |||
/* public API */ | |||
typedef struct FibInternalsImpl FibInternals; | |||
/** open a file select dialog | |||
* @param dpy X Display connection | |||
* @param parent (optional) if not NULL, become transient for given window | |||
@@ -110,8 +110,6 @@ int x_fib_cfg_buttons (int k, int v); | |||
*/ | |||
int x_fib_cfg_filter_callback (int (*cb)(const char*)); | |||
#endif /* END X11 specific functions */ | |||
/* 'recently used' API. x-platform | |||
* NOTE: all functions use a static cache and are not reentrant. | |||
* It is expected that none of these functions are called in | |||
@@ -173,3 +171,5 @@ unsigned int x_fib_recent_count (); | |||
* @return pointer to static string | |||
*/ | |||
const char *x_fib_recent_at (unsigned int i); | |||
#endif // LIBSOFD_H |
@@ -0,0 +1,571 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifdef DOXYGEN | |||
#include "src/DistrhoDefines.h" | |||
START_NAMESPACE_DISTRHO | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Intro */ | |||
/** | |||
@mainpage DISTRHO %Plugin Framework | |||
DISTRHO %Plugin Framework (or @b DPF for short) | |||
is a plugin framework designed to make development of new plugins an easy and enjoyable task.@n | |||
It allows developers to create plugins with custom UIs using a simple C++ API.@n | |||
The framework facilitates exporting various different plugin formats from the same code-base. | |||
DPF can build for LADSPA, DSSI, LV2 and VST2 formats.@n | |||
A JACK/Standalone mode is also available, allowing you to quickly test plugins. | |||
@section Macros | |||
You start by creating a "DistrhoPluginInfo.h" file describing the plugin via macros, see @ref PluginMacros.@n | |||
This file is included in the main DPF code to select which features to activate for each plugin format. | |||
For example, a plugin (with %UI) that use states will require LV2 hosts to support Atom and Worker extensions for | |||
message passing from the %UI to the plugin.@n | |||
If your plugin does not make use of states, the Worker extension is not set as a required feature. | |||
@section Plugin | |||
The next step is to create your plugin code by subclassing DPF's Plugin class.@n | |||
You need to pass the number of parameters in the constructor and also the number of programs and states, if any. | |||
Here's an example of an audio plugin that simply mutes the host output: | |||
@code | |||
class MutePlugin : public Plugin | |||
{ | |||
public: | |||
/** | |||
Plugin class constructor. | |||
*/ | |||
MutePlugin() | |||
: Plugin(0, 0, 0) // 0 parameters, 0 programs and 0 states | |||
{ | |||
} | |||
protected: | |||
/* ---------------------------------------------------------------------------------------- | |||
* Information */ | |||
/** | |||
Get the plugin label. | |||
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. | |||
*/ | |||
const char* getLabel() const override | |||
{ | |||
return "Mute"; | |||
} | |||
/** | |||
Get the plugin author/maker. | |||
*/ | |||
const char* getMaker() const override | |||
{ | |||
return "DPF"; | |||
} | |||
/** | |||
Get the plugin license name (a single line of text). | |||
For commercial plugins this should return some short copyright information. | |||
*/ | |||
const char* getLicense() const override | |||
{ | |||
return "MIT"; | |||
} | |||
/** | |||
Get the plugin version, in hexadecimal. | |||
TODO format to be defined | |||
*/ | |||
uint32_t getVersion() const override | |||
{ | |||
return 0x1000; | |||
} | |||
/** | |||
Get the plugin unique Id. | |||
This value is used by LADSPA, DSSI and VST plugin formats. | |||
*/ | |||
int64_t getUniqueId() const override | |||
{ | |||
return cconst('M', 'u', 't', 'e'); | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* This example has no parameters, so skip parameter stuff */ | |||
void initParameter(uint32_t, Parameter&) override {} | |||
float getParameterValue(uint32_t) const override { return 0.0f; } | |||
void setParameterValue(uint32_t, float) override {} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Audio/MIDI Processing */ | |||
/** | |||
Run/process function for plugins without MIDI input. | |||
NOTE: Some parameters might be null if there are no audio inputs or outputs. | |||
*/ | |||
void run(const float**, float** outputs, uint32_t frames) override | |||
{ | |||
// get the left and right audio outputs | |||
float* const outL = outputs[0]; | |||
float* const outR = outputs[1]; | |||
// mute audio | |||
std::memset(outL, 0, sizeof(float)*frames); | |||
std::memset(outR, 0, sizeof(float)*frames); | |||
} | |||
}; | |||
@endcode | |||
See the Plugin class for more information and to understand what each function does. | |||
@section Parameters | |||
A plugin is nothing without parameters.@n | |||
In DPF parameters can be inputs or outputs.@n | |||
They have hints to describe how they behave plus a name and a symbol identifying them.@n | |||
Parameters also have 'ranges' – a minimum, maximum and default value. | |||
Input parameters are "read-only": the plugin can read them but not change them. | |||
(the exception being when changing programs, more on that below)@n | |||
It's the host responsibility to save, restore and set input parameters. | |||
Output parameters can be changed at anytime by the plugin.@n | |||
The host will simply read their values and not change them. | |||
Here's an example of an audio plugin that has 1 input parameter: | |||
@code | |||
class GainPlugin : public Plugin | |||
{ | |||
public: | |||
/** | |||
Plugin class constructor. | |||
You must set all parameter values to their defaults, matching ParameterRanges::def. | |||
*/ | |||
GainPlugin() | |||
: Plugin(1, 0, 0), // 1 parameter, 0 programs and 0 states | |||
fGain(1.0f) | |||
{ | |||
} | |||
protected: | |||
/* ---------------------------------------------------------------------------------------- | |||
* Information */ | |||
const char* getLabel() const override | |||
{ | |||
return "Gain"; | |||
} | |||
const char* getMaker() const override | |||
{ | |||
return "DPF"; | |||
} | |||
const char* getLicense() const override | |||
{ | |||
return "MIT"; | |||
} | |||
uint32_t getVersion() const override | |||
{ | |||
return 0x1000; | |||
} | |||
int64_t getUniqueId() const override | |||
{ | |||
return cconst('G', 'a', 'i', 'n'); | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Init */ | |||
/** | |||
Initialize a parameter. | |||
This function will be called once, shortly after the plugin is created. | |||
*/ | |||
void initParameter(uint32_t index, Parameter& parameter) override | |||
{ | |||
// we only have one parameter so we can skip checking the index | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.name = "Gain"; | |||
parameter.symbol = "gain"; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 2.0f; | |||
parameter.ranges.def = 1.0f; | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Internal data */ | |||
/** | |||
Get the current value of a parameter. | |||
*/ | |||
float getParameterValue(uint32_t index) const override | |||
{ | |||
// same as before, ignore index check | |||
return fGain; | |||
} | |||
/** | |||
Change a parameter value. | |||
*/ | |||
void setParameterValue(uint32_t index, float value) override | |||
{ | |||
// same as before, ignore index check | |||
fGain = value; | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Audio/MIDI Processing */ | |||
void run(const float**, float** outputs, uint32_t frames) override | |||
{ | |||
// get the mono input and output | |||
const float* const in = inputs[0]; | |||
/* */ float* const out = outputs[0]; | |||
// apply gain against all samples | |||
for (uint32_t i=0; i < frames; ++i) | |||
out[i] = in[i] * fGain; | |||
} | |||
private: | |||
float fGain; | |||
}; | |||
@endcode | |||
See the Parameter struct for more information about parameters. | |||
@section Programs | |||
Programs in DPF refer to plugin-side presets (usually called "factory presets"), | |||
an initial set of presets provided by plugin authors included in the actual plugin. | |||
To use programs you must first enable them by setting @ref DISTRHO_PLUGIN_WANT_PROGRAMS to 1 in your DistrhoPluginInfo.h file.@n | |||
When enabled you'll need to override 2 new function in your plugin code, | |||
Plugin::initProgramName(uint32_t, String&) and Plugin::loadProgram(uint32_t). | |||
Here's an example of a plugin with a "default" program: | |||
@code | |||
class PluginWithPresets : public Plugin | |||
{ | |||
public: | |||
PluginWithPresets() | |||
: Plugin(2, 1, 0), // 2 parameters, 1 program and 0 states | |||
fGainL(1.0f), | |||
fGainR(1.0f), | |||
{ | |||
} | |||
protected: | |||
/* ---------------------------------------------------------------------------------------- | |||
* Information */ | |||
const char* getLabel() const override | |||
{ | |||
return "Prog"; | |||
} | |||
const char* getMaker() const override | |||
{ | |||
return "DPF"; | |||
} | |||
const char* getLicense() const override | |||
{ | |||
return "MIT"; | |||
} | |||
uint32_t getVersion() const override | |||
{ | |||
return 0x1000; | |||
} | |||
int64_t getUniqueId() const override | |||
{ | |||
return cconst('P', 'r', 'o', 'g'); | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Init */ | |||
/** | |||
Initialize a parameter. | |||
This function will be called once, shortly after the plugin is created. | |||
*/ | |||
void initParameter(uint32_t index, Parameter& parameter) override | |||
{ | |||
parameter.hints = kParameterIsAutomable; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 2.0f; | |||
parameter.ranges.def = 1.0f; | |||
switch (index) | |||
{ | |||
case 0; | |||
parameter.name = "Gain Right"; | |||
parameter.symbol = "gainR"; | |||
break; | |||
case 1; | |||
parameter.name = "Gain Left"; | |||
parameter.symbol = "gainL"; | |||
break; | |||
} | |||
} | |||
/** | |||
Set the name of the program @a index. | |||
This function will be called once, shortly after the plugin is created. | |||
*/ | |||
void initProgramName(uint32_t index, String& programName) | |||
{ | |||
switch(index) | |||
{ | |||
case 0: | |||
programName = "Default"; | |||
break; | |||
} | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Internal data */ | |||
/** | |||
Get the current value of a parameter. | |||
*/ | |||
float getParameterValue(uint32_t index) const override | |||
{ | |||
switch (index) | |||
{ | |||
case 0; | |||
return fGainL; | |||
case 1; | |||
return fGainR; | |||
} | |||
} | |||
/** | |||
Change a parameter value. | |||
*/ | |||
void setParameterValue(uint32_t index, float value) override | |||
{ | |||
switch (index) | |||
{ | |||
case 0; | |||
fGainL = value; | |||
break; | |||
case 1; | |||
fGainR = value; | |||
break; | |||
} | |||
} | |||
/** | |||
Load a program. | |||
*/ | |||
void loadProgram(uint32_t index) | |||
{ | |||
switch(index) | |||
{ | |||
case 0: | |||
fGainL = 1.0f; | |||
fGainR = 1.0f; | |||
break; | |||
} | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Audio/MIDI Processing */ | |||
void run(const float**, float** outputs, uint32_t frames) override | |||
{ | |||
// get the left and right audio buffers | |||
const float* const inL = inputs[0]; | |||
const float* const inR = inputs[0]; | |||
/* */ float* const outL = outputs[0]; | |||
/* */ float* const outR = outputs[0]; | |||
// apply gain against all samples | |||
for (uint32_t i=0; i < frames; ++i) | |||
{ | |||
outL[i] = inL[i] * fGainL; | |||
outR[i] = inR[i] * fGainR; | |||
} | |||
} | |||
private: | |||
float fGainL, fGainR; | |||
}; | |||
@endcode | |||
@section States | |||
describe them | |||
@section MIDI | |||
describe them | |||
@section Latency | |||
describe it | |||
@section Time-Position | |||
describe it | |||
@section UI | |||
describe them | |||
*/ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Plugin Macros */ | |||
/** | |||
@defgroup PluginMacros Plugin Macros | |||
C Macros that describe your plugin. (defined in the "DistrhoPluginInfo.h" file) | |||
With these macros you can tell the host what features your plugin requires.@n | |||
Depending on which macros you enable, new functions will be available to call and/or override. | |||
All values are either integer or strings.@n | |||
For boolean-like values 1 means 'on' and 0 means 'off'. | |||
The values defined in this group are for documentation purposes only.@n | |||
All macros are disabled by default. | |||
Only 4 macros are required, they are: | |||
- @ref DISTRHO_PLUGIN_NAME | |||
- @ref DISTRHO_PLUGIN_NUM_INPUTS | |||
- @ref DISTRHO_PLUGIN_NUM_OUTPUTS | |||
- @ref DISTRHO_PLUGIN_URI | |||
@{ | |||
*/ | |||
/** | |||
The plugin name.@n | |||
This is used to identify your plugin before a Plugin instance can be created. | |||
@note This macro is required. | |||
*/ | |||
#define DISTRHO_PLUGIN_NAME "Plugin Name" | |||
/** | |||
Number of audio inputs the plugin has. | |||
@note This macro is required. | |||
*/ | |||
#define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
/** | |||
Number of audio outputs the plugin has. | |||
@note This macro is required. | |||
*/ | |||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
/** | |||
The plugin URI when exporting in LV2 format. | |||
@note This macro is required. | |||
*/ | |||
#define DISTRHO_PLUGIN_URI "urn:distrho:name" | |||
/** | |||
Wherever the plugin has a custom %UI. | |||
@see DISTRHO_UI_USE_NANOVG | |||
@see UI | |||
*/ | |||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||
/** | |||
Wherever the plugin processing is realtime-safe.@n | |||
TODO - list rtsafe requirements | |||
*/ | |||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1 | |||
/** | |||
Wherever the plugin is a synth.@n | |||
@ref DISTRHO_PLUGIN_WANT_MIDI_INPUT is automatically enabled when this is too. | |||
@see DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
*/ | |||
#define DISTRHO_PLUGIN_IS_SYNTH 1 | |||
/** | |||
Enable direct access between the %UI and plugin code. | |||
@see UI::getPluginInstancePointer() | |||
@note DO NOT USE THIS UNLESS STRICTLY NECESSARY!! | |||
Try to avoid it at all costs! | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||
/** | |||
Wherever the plugin introduces latency during audio or midi processing. | |||
@see Plugin::setLatency(uint32_t) | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
/** | |||
Wherever the plugin wants MIDI input.@n | |||
This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 | |||
/** | |||
Wherever the plugin wants MIDI output. | |||
@see Plugin::writeMidiEvent(const MidiEvent&) | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 | |||
/** | |||
Wherever the plugin provides its own internal programs. | |||
@see Plugin::initProgramName(uint32_t, String&) | |||
@see Plugin::loadProgram(uint32_t) | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 | |||
/** | |||
Wherever the plugin uses internal non-parameter data. | |||
@see Plugin::initState(uint32_t, String&, String&) | |||
@see Plugin::setState(const char*, const char*) | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_STATE 1 | |||
/** | |||
Wherever the plugin wants time position information from the host. | |||
@see Plugin::getTimePosition() | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
/** | |||
Wherever the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n | |||
When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget. | |||
*/ | |||
#define DISTRHO_UI_USE_NANOVG 1 | |||
/** | |||
The %UI URI when exporting in LV2 format.@n | |||
By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix. | |||
*/ | |||
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | |||
/** @} */ | |||
// ----------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
#endif // DOXYGEN |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,22 +17,34 @@ | |||
#ifndef DISTRHO_PLUGIN_HPP_INCLUDED | |||
#define DISTRHO_PLUGIN_HPP_INCLUDED | |||
#include "extra/d_string.hpp" | |||
#include "extra/String.hpp" | |||
#include "extra/LeakDetector.hpp" | |||
#include "src/DistrhoPluginChecks.h" | |||
#include <cmath> | |||
START_NAMESPACE_DISTRHO | |||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||
# include <cstdint> | |||
#else | |||
# include <stdint.h> | |||
#endif | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Audio Port Hints */ | |||
#ifndef M_PI | |||
# define M_PI 3.14159265358979323846 | |||
#endif | |||
/** | |||
@defgroup AudioPortHints Audio Port Hints | |||
START_NAMESPACE_DISTRHO | |||
Various audio port hints. | |||
@see AudioPort::hints | |||
@{ | |||
*/ | |||
/** | |||
Audio port can be used as control voltage (LV2 only). | |||
*/ | |||
static const uint32_t kAudioPortIsCV = 0x1; | |||
/** | |||
Audio port should be used as sidechan (LV2 only). | |||
*/ | |||
static const uint32_t kAudioPortIsSidechain = 0x2; | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Parameter Hints */ | |||
@@ -47,12 +59,12 @@ START_NAMESPACE_DISTRHO | |||
/** | |||
Parameter is automable (real-time safe). | |||
@see Plugin::d_setParameterValue() | |||
@see Plugin::setParameterValue(uint32_t, float) | |||
*/ | |||
static const uint32_t kParameterIsAutomable = 0x01; | |||
/** | |||
Parameter value is boolean. | |||
Parameter value is boolean.@n | |||
It's always at either minimum or maximum value. | |||
*/ | |||
static const uint32_t kParameterIsBoolean = 0x02; | |||
@@ -68,11 +80,11 @@ static const uint32_t kParameterIsInteger = 0x04; | |||
static const uint32_t kParameterIsLogarithmic = 0x08; | |||
/** | |||
Parameter is of output type. | |||
Parameter is of output type.@n | |||
When unset, parameter is assumed to be of input type. | |||
Parameter inputs are changed by the host and must not be changed by the plugin. | |||
The only exception being when changing programs, see Plugin::d_setProgram(). | |||
Parameter inputs are changed by the host and must not be changed by the plugin.@n | |||
The only exception being when changing programs, see Plugin::loadProgram().@n | |||
Outputs are changed by the plugin and never modified by the host. | |||
*/ | |||
static const uint32_t kParameterIsOutput = 0x10; | |||
@@ -80,13 +92,52 @@ static const uint32_t kParameterIsOutput = 0x10; | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* DPF Base structs */ | |||
* Base Plugin structs */ | |||
/** | |||
Parameter ranges. | |||
@defgroup BasePluginStructs Base Plugin Structs | |||
@{ | |||
*/ | |||
/** | |||
Audio Port. | |||
*/ | |||
struct AudioPort { | |||
/** | |||
Hints describing this audio port. | |||
@see AudioPortHints | |||
*/ | |||
uint32_t hints; | |||
/** | |||
The name of this audio port.@n | |||
An audio port name can contain any character, but hosts might have a hard time with non-ascii ones.@n | |||
The name doesn't have to be unique within a plugin instance, but it's recommended. | |||
*/ | |||
String name; | |||
/** | |||
The symbol of this audio port.@n | |||
An audio port symbol is a short restricted name used as a machine and human readable identifier.@n | |||
The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9. | |||
@note Audio port and parameter symbols MUST be unique within a plugin instance. | |||
*/ | |||
String symbol; | |||
/** | |||
Default constructor for a regular audio port. | |||
*/ | |||
AudioPort() noexcept | |||
: hints(0x0), | |||
name(), | |||
symbol() {} | |||
}; | |||
/** | |||
Parameter ranges.@n | |||
This is used to set the default, minimum and maximum values of a parameter. | |||
By default a parameter has 0.0 as minimum, 1.0 as maximum and 0.0 as default. | |||
By default a parameter has 0.0 as minimum, 1.0 as maximum and 0.0 as default.@n | |||
When changing this struct values you must ensure maximum > minimum and default is within range. | |||
*/ | |||
struct ParameterRanges { | |||
@@ -106,7 +157,7 @@ struct ParameterRanges { | |||
float max; | |||
/** | |||
Default constructor. | |||
Default constructor, using 0.0 as minimum, 1.0 as maximum and 0.0 as default. | |||
*/ | |||
ParameterRanges() noexcept | |||
: def(0.0f), | |||
@@ -116,7 +167,7 @@ struct ParameterRanges { | |||
/** | |||
Constructor using custom values. | |||
*/ | |||
ParameterRanges(const float df, const float mn, const float mx) noexcept | |||
ParameterRanges(float df, float mn, float mx) noexcept | |||
: def(df), | |||
min(mn), | |||
max(mx) {} | |||
@@ -211,29 +262,29 @@ struct Parameter { | |||
uint32_t hints; | |||
/** | |||
The name of this parameter. | |||
A parameter name can contain any character, but hosts might have a hard time with non-ascii ones. | |||
The name of this parameter.@n | |||
A parameter name can contain any character, but hosts might have a hard time with non-ascii ones.@n | |||
The name doesn't have to be unique within a plugin instance, but it's recommended. | |||
*/ | |||
d_string name; | |||
String name; | |||
/** | |||
The symbol of this parameter. | |||
A parameter symbol is a short restricted name used as a machine and human readable identifier. | |||
The symbol of this parameter.@n | |||
A parameter symbol is a short restricted name used as a machine and human readable identifier.@n | |||
The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9. | |||
@note: Parameter symbols MUST be unique within a plugin instance. | |||
@note Parameter symbols MUST be unique within a plugin instance. | |||
*/ | |||
d_string symbol; | |||
String symbol; | |||
/** | |||
The unit of this parameter. | |||
This means something like "dB", "kHz" and "ms". | |||
Can be left blank if units do not apply to this parameter. | |||
The unit of this parameter.@n | |||
This means something like "dB", "kHz" and "ms".@n | |||
Can be left blank if a unit does not apply to this parameter. | |||
*/ | |||
d_string unit; | |||
String unit; | |||
/** | |||
Ranges of this parameter. | |||
Ranges of this parameter.@n | |||
The ranges describe the default, minimum and maximum values. | |||
*/ | |||
ParameterRanges ranges; | |||
@@ -247,6 +298,16 @@ struct Parameter { | |||
symbol(), | |||
unit(), | |||
ranges() {} | |||
/** | |||
Constructor using custom values. | |||
*/ | |||
Parameter(uint32_t h, const char* n, const char* s, const char* u, float def, float min, float max) noexcept | |||
: hints(h), | |||
name(n), | |||
symbol(s), | |||
unit(u), | |||
ranges(def, min, max) {} | |||
}; | |||
/** | |||
@@ -269,7 +330,7 @@ struct MidiEvent { | |||
uint32_t size; | |||
/** | |||
MIDI data. | |||
MIDI data.@n | |||
If size > kDataSize, dataExt is used (otherwise null). | |||
*/ | |||
uint8_t data[kDataSize]; | |||
@@ -277,8 +338,8 @@ struct MidiEvent { | |||
}; | |||
/** | |||
Time position. | |||
The @a playing and @a frame values are always valid. | |||
Time position.@n | |||
The @a playing and @a frame values are always valid.@n | |||
BBT values are only valid when @a bbt.valid is true. | |||
This struct is inspired by the JACK Transport API. | |||
@@ -299,28 +360,28 @@ struct TimePosition { | |||
*/ | |||
struct BarBeatTick { | |||
/** | |||
Wherever the host transport is using BBT. | |||
Wherever the host transport is using BBT.@n | |||
If false you must not read from this struct. | |||
*/ | |||
bool valid; | |||
/** | |||
Current bar. | |||
Should always be > 0. | |||
Current bar.@n | |||
Should always be > 0.@n | |||
The first bar is bar '1'. | |||
*/ | |||
int32_t bar; | |||
/** | |||
Current beat within bar. | |||
Should always be > 0 and <= @a beatsPerBar. | |||
Current beat within bar.@n | |||
Should always be > 0 and <= @a beatsPerBar.@n | |||
The first beat is beat '1'. | |||
*/ | |||
int32_t beat; | |||
/** | |||
Current tick within beat. | |||
Should always be > 0 and <= @a ticksPerBeat. | |||
Current tick within beat.@n | |||
Should always be > 0 and <= @a ticksPerBeat.@n | |||
The first tick is tick '0'. | |||
*/ | |||
int32_t tick; | |||
@@ -341,7 +402,7 @@ struct TimePosition { | |||
float beatType; | |||
/** | |||
Number of ticks within a bar. | |||
Number of ticks within a bar.@n | |||
Usually a moderately large integer with many denominators, such as 1920.0. | |||
*/ | |||
double ticksPerBeat; | |||
@@ -375,44 +436,50 @@ struct TimePosition { | |||
bbt() {} | |||
}; | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* DPF Plugin */ | |||
/** | |||
@defgroup MainClasses Main Classes | |||
@{ | |||
*/ | |||
/** | |||
DPF Plugin class from where plugin instances are created. | |||
The public methods (Host state) are called from the plugin to get or set host information. | |||
They can be called from a plugin instance at anytime unless stated otherwise. | |||
The public methods (Host state) are called from the plugin to get or set host information.@n | |||
They can be called from a plugin instance at anytime unless stated otherwise.@n | |||
All other methods are to be implemented by the plugin and will be called by the host. | |||
Shortly after a plugin instance is created, the various d_init* functions will be called by the host. | |||
Host will call d_activate() before d_run(), and d_deactivate() before the plugin instance is destroyed. | |||
The host may call deactivate right after activate and vice-versa, but never activate/deactivate consecutively. | |||
There is no limit on how many times d_run() is called, only that activate/deactivate will be called in between. | |||
Shortly after a plugin instance is created, the various init* functions will be called by the host.@n | |||
Host will call activate() before run(), and deactivate() before the plugin instance is destroyed.@n | |||
The host may call deactivate right after activate and vice-versa, but never activate/deactivate consecutively.@n | |||
There is no limit on how many times run() is called, only that activate/deactivate will be called in between. | |||
The buffer size and sample rate values will remain constant between activate and deactivate. | |||
Buffer size is only a hint though, the host might call d_run() with a higher or lower number of frames. | |||
The buffer size and sample rate values will remain constant between activate and deactivate.@n | |||
Buffer size is only a hint though, the host might call run() with a higher or lower number of frames. | |||
Some of this class functions are only available according to some macros. | |||
DISTRHO_PLUGIN_WANT_PROGRAMS activates program related features. | |||
When enabled you need to implement d_initProgramName() and d_setProgram(). | |||
DISTRHO_PLUGIN_WANT_PROGRAMS activates program related features.@n | |||
When enabled you need to implement initProgramName() and loadProgram(). | |||
DISTRHO_PLUGIN_WANT_STATE activates internal state features. | |||
When enabled you need to implement d_initStateKey() and d_setState(). | |||
DISTRHO_PLUGIN_WANT_STATE activates internal state features.@n | |||
When enabled you need to implement initStateKey() and setState(). | |||
The process function d_run() changes wherever DISTRHO_PLUGIN_HAS_MIDI_INPUT is enabled or not. | |||
The process function run() changes wherever DISTRHO_PLUGIN_WANT_MIDI_INPUT is enabled or not.@n | |||
When enabled it provides midi input events. | |||
*/ | |||
class Plugin | |||
{ | |||
public: | |||
/** | |||
Plugin class constructor. | |||
Plugin class constructor.@n | |||
You must set all parameter values to their defaults, matching ParameterRanges::def. | |||
If you're using states you must also set them to their defaults by calling d_setState(). | |||
*/ | |||
Plugin(const uint32_t parameterCount, const uint32_t programCount, const uint32_t stateCount); | |||
Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount); | |||
/** | |||
Destructor. | |||
@@ -423,46 +490,47 @@ public: | |||
* Host state */ | |||
/** | |||
Get the current buffer size that will probably be used during processing, in frames. | |||
Get the current buffer size that will probably be used during processing, in frames.@n | |||
This value will remain constant between activate and deactivate. | |||
@note: This value is only a hint! | |||
Hosts might call d_run() with a higher or lower number of frames. | |||
@see d_bufferSizeChanged(uint32_t) | |||
@note This value is only a hint!@n | |||
Hosts might call run() with a higher or lower number of frames. | |||
@see bufferSizeChanged(uint32_t) | |||
*/ | |||
uint32_t d_getBufferSize() const noexcept; | |||
uint32_t getBufferSize() const noexcept; | |||
/** | |||
Get the current sample rate that will be used during processing. | |||
Get the current sample rate that will be used during processing.@n | |||
This value will remain constant between activate and deactivate. | |||
@see d_sampleRateChanged(double) | |||
@see sampleRateChanged(double) | |||
*/ | |||
double d_getSampleRate() const noexcept; | |||
double getSampleRate() const noexcept; | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
/** | |||
Get the current host transport time position. | |||
This function should only be called during d_run(). | |||
Get the current host transport time position.@n | |||
This function should only be called during run().@n | |||
You can call this during other times, but the returned position is not guaranteed to be in sync. | |||
@note: TimePos is not supported in LADSPA and DSSI plugin formats. | |||
@note TimePosition is not supported in LADSPA and DSSI plugin formats. | |||
*/ | |||
const TimePosition& d_getTimePosition() const noexcept; | |||
const TimePosition& getTimePosition() const noexcept; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
/** | |||
Change the plugin audio output latency to @a frames. | |||
This function should only be called in the constructor, d_activate() and d_run(). | |||
Change the plugin audio output latency to @a frames.@n | |||
This function should only be called in the constructor, activate() and run(). | |||
@note This function is only available if DISTRHO_PLUGIN_WANT_LATENCY is enabled. | |||
*/ | |||
void d_setLatency(const uint32_t frames) noexcept; | |||
void setLatency(uint32_t frames) noexcept; | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
/** | |||
Write a MIDI output event. | |||
This function must only be called during d_run(). | |||
Returns false when the host buffer is full, in which case do not call this again until the next d_run(). | |||
Write a MIDI output event.@n | |||
This function must only be called during run().@n | |||
Returns false when the host buffer is full, in which case do not call this again until the next run(). | |||
*/ | |||
bool d_writeMidiEvent(const MidiEvent& midiEvent) noexcept; | |||
bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; | |||
#endif | |||
protected: | |||
@@ -470,146 +538,153 @@ protected: | |||
* Information */ | |||
/** | |||
Get the plugin name. | |||
Get the plugin name.@n | |||
Returns DISTRHO_PLUGIN_NAME by default. | |||
*/ | |||
virtual const char* d_getName() const { return DISTRHO_PLUGIN_NAME; } | |||
virtual const char* getName() const { return DISTRHO_PLUGIN_NAME; } | |||
/** | |||
Get the plugin label. | |||
A plugin label follows the same rules as Parameter::symbol, with the exception that it can start with numbers. | |||
Get the plugin label.@n | |||
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. | |||
*/ | |||
virtual const char* d_getLabel() const = 0; | |||
virtual const char* getLabel() const = 0; | |||
/** | |||
Get the plugin author/maker. | |||
*/ | |||
virtual const char* d_getMaker() const = 0; | |||
virtual const char* getMaker() const = 0; | |||
/** | |||
Get the plugin license name (a single line of text). | |||
Get the plugin license name (a single line of text).@n | |||
For commercial plugins this should return some short copyright information. | |||
*/ | |||
virtual const char* d_getLicense() const = 0; | |||
virtual const char* getLicense() const = 0; | |||
/** | |||
Get the plugin version, in hexadecimal. | |||
Get the plugin version, in hexadecimal.@n | |||
TODO format to be defined | |||
*/ | |||
virtual uint32_t d_getVersion() const = 0; | |||
virtual uint32_t getVersion() const = 0; | |||
/** | |||
Get the plugin unique Id. | |||
Get the plugin unique Id.@n | |||
This value is used by LADSPA, DSSI and VST plugin formats. | |||
*/ | |||
virtual int64_t d_getUniqueId() const = 0; | |||
virtual int64_t getUniqueId() const = 0; | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* Init */ | |||
/** | |||
Initialize the parameter @a index. | |||
Initialize the audio port @a index.@n | |||
This function will be called once, shortly after the plugin is created. | |||
*/ | |||
virtual void d_initParameter(uint32_t index, Parameter& parameter) = 0; | |||
virtual void initAudioPort(bool input, uint32_t index, AudioPort& port); | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
/** | |||
Set the name of the program @a index. | |||
Initialize the parameter @a index.@n | |||
This function will be called once, shortly after the plugin is created. | |||
*/ | |||
virtual void initParameter(uint32_t index, Parameter& parameter) = 0; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
/** | |||
Set the name of the program @a index.@n | |||
This function will be called once, shortly after the plugin is created.@n | |||
Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_PROGRAMS is enabled. | |||
*/ | |||
virtual void d_initProgramName(uint32_t index, d_string& programName) = 0; | |||
virtual void initProgramName(uint32_t index, String& programName) = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
/** | |||
Set the state key and default value of @a index. | |||
This function will be called once, shortly after the plugin is created. | |||
Set the state key and default value of @a index.@n | |||
This function will be called once, shortly after the plugin is created.@n | |||
Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_STATE is enabled. | |||
*/ | |||
virtual void d_initState(uint32_t index, d_string& stateKey, d_string& defaultStateValue) = 0; | |||
virtual void initState(uint32_t index, String& stateKey, String& defaultStateValue) = 0; | |||
#endif | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* Internal data */ | |||
/** | |||
Get the current value of a parameter. | |||
Get the current value of a parameter.@n | |||
The host may call this function from any context, including realtime processing. | |||
*/ | |||
virtual float d_getParameterValue(uint32_t index) const = 0; | |||
virtual float getParameterValue(uint32_t index) const = 0; | |||
/** | |||
Change a parameter value. | |||
The host may call this function from any context, including realtime processing. | |||
When a parameter is marked as automable, you must ensure no non-realtime operations are called. | |||
Change a parameter value.@n | |||
The host may call this function from any context, including realtime processing.@n | |||
When a parameter is marked as automable, you must ensure no non-realtime operations are performed. | |||
@note This function will only be called for parameter inputs. | |||
*/ | |||
virtual void d_setParameterValue(uint32_t index, float value) = 0; | |||
virtual void setParameterValue(uint32_t index, float value) = 0; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
/** | |||
Change the currently used program to @a index. | |||
The host may call this function from any context, including realtime processing. | |||
Load a program.@n | |||
The host may call this function from any context, including realtime processing.@n | |||
Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_PROGRAMS is enabled. | |||
*/ | |||
virtual void d_setProgram(uint32_t index) = 0; | |||
virtual void loadProgram(uint32_t index) = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
/** | |||
Change an internal state @a key to @a value. | |||
Change an internal state @a key to @a value.@n | |||
Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_STATE is enabled. | |||
*/ | |||
virtual void d_setState(const char* key, const char* value) = 0; | |||
virtual void setState(const char* key, const char* value) = 0; | |||
#endif | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* Process */ | |||
* Audio/MIDI Processing */ | |||
/** | |||
Activate this plugin. | |||
*/ | |||
virtual void d_activate() {} | |||
virtual void activate() {} | |||
/** | |||
Deactivate this plugin. | |||
*/ | |||
virtual void d_deactivate() {} | |||
virtual void deactivate() {} | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
/** | |||
Run/process function for plugins with MIDI input. | |||
@note: Some parameters might be null if there are no audio inputs/outputs or MIDI events. | |||
@note Some parameters might be null if there are no audio inputs/outputs or MIDI events. | |||
*/ | |||
virtual void d_run(const float** inputs, float** outputs, uint32_t frames, | |||
const MidiEvent* midiEvents, uint32_t midiEventCount) = 0; | |||
virtual void run(const float** inputs, float** outputs, uint32_t frames, | |||
const MidiEvent* midiEvents, uint32_t midiEventCount) = 0; | |||
#else | |||
/** | |||
Run/process function for plugins without MIDI input. | |||
@note: Some parameters might be null if there are no audio inputs or outputs. | |||
@note Some parameters might be null if there are no audio inputs or outputs. | |||
*/ | |||
virtual void d_run(const float** inputs, float** outputs, uint32_t frames) = 0; | |||
virtual void run(const float** inputs, float** outputs, uint32_t frames) = 0; | |||
#endif | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* Callbacks (optional) */ | |||
/** | |||
Optional callback to inform the plugin about a buffer size change. | |||
Optional callback to inform the plugin about a buffer size change.@n | |||
This function will only be called when the plugin is deactivated. | |||
@note: This value is only a hint! | |||
Hosts might call d_run() with a higher or lower number of frames. | |||
@see d_getBufferSize() | |||
@note This value is only a hint!@n | |||
Hosts might call run() with a higher or lower number of frames. | |||
@see getBufferSize() | |||
*/ | |||
virtual void d_bufferSizeChanged(uint32_t newBufferSize); | |||
virtual void bufferSizeChanged(uint32_t newBufferSize); | |||
/** | |||
Optional callback to inform the plugin about a sample rate change. | |||
Optional callback to inform the plugin about a sample rate change.@n | |||
This function will only be called when the plugin is deactivated. | |||
@see d_getSampleRate() | |||
@see getSampleRate() | |||
*/ | |||
virtual void d_sampleRateChanged(double newSampleRate); | |||
virtual void sampleRateChanged(double newSampleRate); | |||
// ------------------------------------------------------------------------------------------------------- | |||
@@ -621,14 +696,23 @@ private: | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Plugin) | |||
}; | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Create plugin, entry point */ | |||
/** | |||
@defgroup EntryPoints Entry Points | |||
@{ | |||
*/ | |||
/** | |||
TODO. | |||
*/ | |||
extern Plugin* createPlugin(); | |||
/** @} */ | |||
// ----------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,7 +17,7 @@ | |||
#ifndef DISTRHO_UI_HPP_INCLUDED | |||
#define DISTRHO_UI_HPP_INCLUDED | |||
#include "extra/d_leakdetector.hpp" | |||
#include "extra/LeakDetector.hpp" | |||
#include "src/DistrhoPluginChecks.h" | |||
#if DISTRHO_UI_USE_NANOVG | |||
@@ -33,6 +33,11 @@ START_NAMESPACE_DISTRHO | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* DPF UI */ | |||
/** | |||
@addtogroup MainClasses | |||
@{ | |||
*/ | |||
/** | |||
DPF UI class from where UI instances are created. | |||
@@ -47,7 +52,7 @@ public: | |||
UI class constructor. | |||
The UI should be initialized to a default state that matches the plugin side. | |||
*/ | |||
UI(); | |||
UI(uint width = 0, uint height = 0); | |||
/** | |||
Destructor. | |||
@@ -59,32 +64,32 @@ public: | |||
/** | |||
Get the current sample rate used in plugin processing. | |||
@see d_sampleRateChanged(double) | |||
@see sampleRateChanged(double) | |||
*/ | |||
double d_getSampleRate() const noexcept; | |||
double getSampleRate() const noexcept; | |||
/** | |||
TODO: Document this. | |||
*/ | |||
void d_editParameter(const uint32_t index, const bool started); | |||
void editParameter(uint32_t index, bool started); | |||
/** | |||
TODO: Document this. | |||
*/ | |||
void d_setParameterValue(const uint32_t index, const float value); | |||
void setParameterValue(uint32_t index, float value); | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
/** | |||
TODO: Document this. | |||
*/ | |||
void d_setState(const char* const key, const char* const value); | |||
void setState(const char* key, const char* value); | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
/** | |||
TODO: Document this. | |||
*/ | |||
void d_sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity); | |||
void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
@@ -94,7 +99,7 @@ public: | |||
/** | |||
TODO: Document this. | |||
*/ | |||
void* d_getPluginInstancePointer() const noexcept; | |||
void* getPluginInstancePointer() const noexcept; | |||
#endif | |||
protected: | |||
@@ -102,25 +107,25 @@ protected: | |||
* DSP/Plugin Callbacks */ | |||
/** | |||
A parameter has changed on the plugin side. | |||
A parameter has changed on the plugin side.@n | |||
This is called by the host to inform the UI about parameter changes. | |||
*/ | |||
virtual void d_parameterChanged(uint32_t index, float value) = 0; | |||
virtual void parameterChanged(uint32_t index, float value) = 0; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
/** | |||
The current program has changed on the plugin side. | |||
A program has been loaded on the plugin side.@n | |||
This is called by the host to inform the UI about program changes. | |||
*/ | |||
virtual void d_programChanged(uint32_t index) = 0; | |||
virtual void programLoaded(uint32_t index) = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
/** | |||
A state has changed on the plugin side. | |||
A state has changed on the plugin side.@n | |||
This is called by the host to inform the UI about state changes. | |||
*/ | |||
virtual void d_stateChanged(const char* key, const char* value) = 0; | |||
virtual void stateChanged(const char* key, const char* value) = 0; | |||
#endif | |||
/* -------------------------------------------------------------------------------------------------------- | |||
@@ -128,9 +133,9 @@ protected: | |||
/** | |||
Optional callback to inform the UI about a sample rate change on the plugin side. | |||
@see d_getSampleRate() | |||
@see getSampleRate() | |||
*/ | |||
virtual void d_sampleRateChanged(double newSampleRate); | |||
virtual void sampleRateChanged(double newSampleRate); | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* UI Callbacks (optional) */ | |||
@@ -138,20 +143,20 @@ protected: | |||
/** | |||
TODO: Document this. | |||
*/ | |||
virtual void d_uiIdle() {} | |||
virtual void uiIdle() {} | |||
/** | |||
File browser selected function. | |||
@see Window::fileBrowserSelected(const char*) | |||
*/ | |||
virtual void d_uiFileBrowserSelected(const char* filename); | |||
virtual void uiFileBrowserSelected(const char* filename); | |||
/** | |||
OpenGL window reshape function, called when parent window is resized. | |||
You can reimplement this function for a custom OpenGL state. | |||
@see Window::onReshape(uint,uint) | |||
*/ | |||
virtual void d_uiReshape(uint width, uint height); | |||
virtual void uiReshape(uint width, uint height); | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* UI Resize Handling, internal */ | |||
@@ -176,19 +181,27 @@ private: | |||
void setAbsoluteY(int) const noexcept {} | |||
void setAbsolutePos(int, int) const noexcept {} | |||
void setAbsolutePos(const DGL::Point<int>&) const noexcept {} | |||
void setNeedsFullViewport(bool) const noexcept {} | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | |||
}; | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Create UI, entry point */ | |||
/** | |||
@addtogroup EntryPoints | |||
@{ | |||
*/ | |||
/** | |||
TODO. | |||
*/ | |||
extern UI* createUI(); | |||
/** @} */ | |||
// ----------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -46,6 +46,10 @@ inline float round(float __x) | |||
} | |||
#endif | |||
#ifndef M_PI | |||
# define M_PI 3.14159265358979323846 | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// misc functions | |||
@@ -197,6 +201,33 @@ bool d_isNotZero(const T& value) | |||
return std::abs(value) >= std::numeric_limits<T>::epsilon(); | |||
} | |||
/* | |||
* Get next power of 2. | |||
*/ | |||
static inline | |||
uint32_t d_nextPowerOf2(uint32_t size) noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(size > 0, 0); | |||
// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 | |||
--size; | |||
size |= size >> 1; | |||
size |= size >> 2; | |||
size |= size >> 4; | |||
size |= size >> 8; | |||
size |= size >> 16; | |||
return ++size; | |||
} | |||
// ----------------------------------------------------------------------- | |||
#ifndef DONT_SET_USING_DISTRHO_NAMESPACE | |||
// If your code uses a lot of DISTRHO classes, then this will obviously save you | |||
// a lot of typing, but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE. | |||
namespace DISTRHO_NAMESPACE {} | |||
using namespace DISTRHO_NAMESPACE; | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#endif // DISTRHO_UTILS_HPP_INCLUDED |
@@ -0,0 +1,127 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2015 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. | |||
*/ | |||
#ifndef DISTRHO_BASE64_HPP_INCLUDED | |||
#define DISTRHO_BASE64_HPP_INCLUDED | |||
#include "../DistrhoUtils.hpp" | |||
#include <cctype> | |||
#include <vector> | |||
// ----------------------------------------------------------------------- | |||
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html | |||
// Copyright (C) 2004-2008 René Nyffenegger | |||
// ----------------------------------------------------------------------- | |||
// Helpers | |||
#ifndef DOXYGEN | |||
namespace DistrhoBase64Helpers { | |||
static const char* const kBase64Chars = | |||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
"abcdefghijklmnopqrstuvwxyz" | |||
"0123456789+/"; | |||
static inline | |||
uint8_t findBase64CharIndex(const char c) | |||
{ | |||
static const uint8_t kBase64CharsLen(static_cast<uint8_t>(std::strlen(kBase64Chars))); | |||
for (uint8_t i=0; i<kBase64CharsLen; ++i) | |||
{ | |||
if (kBase64Chars[i] == c) | |||
return i; | |||
} | |||
d_stderr2("findBase64CharIndex('%c') - failed", c); | |||
return 0; | |||
} | |||
static inline | |||
bool isBase64Char(const char c) | |||
{ | |||
return (std::isalnum(c) || (c == '+') || (c == '/')); | |||
} | |||
} // namespace DistrhoBase64Helpers | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
static inline | |||
std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(base64string != nullptr, std::vector<uint8_t>()); | |||
uint i=0, j=0; | |||
uint charArray3[3], charArray4[4]; | |||
std::vector<uint8_t> ret; | |||
ret.reserve(std::strlen(base64string)*3/4 + 4); | |||
for (std::size_t l=0, len=std::strlen(base64string); l<len; ++l) | |||
{ | |||
const char c = base64string[l]; | |||
if (c == '\0' || c == '=') | |||
break; | |||
if (c == ' ' || c == '\n') | |||
continue; | |||
DISTRHO_SAFE_ASSERT_CONTINUE(CarlaBase64Helpers::isBase64Char(c)); | |||
charArray4[i++] = static_cast<uint>(c); | |||
if (i == 4) | |||
{ | |||
for (i=0; i<4; ++i) | |||
charArray4[i] = DistrhoBase64Helpers::findBase64CharIndex(static_cast<char>(charArray4[i])); | |||
charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); | |||
charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); | |||
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
for (i=0; i<3; ++i) | |||
ret.push_back(static_cast<uint8_t>(charArray3[i])); | |||
i = 0; | |||
} | |||
} | |||
if (i != 0) | |||
{ | |||
for (j=0; j<i && j<4; ++j) | |||
charArray4[j] = DistrhoBase64Helpers::findBase64CharIndex(static_cast<char>(charArray4[j])); | |||
for (j=i; j<4; ++j) | |||
charArray4[j] = 0; | |||
charArray3[0] = (charArray4[0] << 2) + ((charArray4[1] & 0x30) >> 4); | |||
charArray3[1] = ((charArray4[1] & 0xf) << 4) + ((charArray4[2] & 0x3c) >> 2); | |||
charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
for (j=0; i>0 && j<i-1; j++) | |||
ret.push_back(static_cast<uint8_t>(charArray3[j])); | |||
} | |||
return ret; | |||
} | |||
// ----------------------------------------------------------------------- | |||
#endif // DISTRHO_BASE64_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -32,6 +32,7 @@ START_NAMESPACE_DISTRHO | |||
#define DISTRHO_JOIN_MACRO_HELPER(a, b) a ## b | |||
#define DISTRHO_JOIN_MACRO(item1, item2) DISTRHO_JOIN_MACRO_HELPER(item1, item2) | |||
#ifdef DEBUG | |||
/** This macro lets you embed a leak-detecting object inside a class.\n | |||
To use it, simply declare a DISTRHO_LEAK_DETECTOR(YourClassName) inside a private section | |||
of the class declaration. E.g. | |||
@@ -47,14 +48,20 @@ START_NAMESPACE_DISTRHO | |||
}; | |||
\endcode | |||
*/ | |||
#define DISTRHO_LEAK_DETECTOR(ClassName) \ | |||
# define DISTRHO_LEAK_DETECTOR(ClassName) \ | |||
friend class DISTRHO_NAMESPACE::LeakedObjectDetector<ClassName>; \ | |||
static const char* getLeakedObjectClassName() noexcept { return #ClassName; } \ | |||
DISTRHO_NAMESPACE::LeakedObjectDetector<ClassName> DISTRHO_JOIN_MACRO(leakDetector_, ClassName); | |||
#define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ | |||
# define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ | |||
DISTRHO_LEAK_DETECTOR(ClassName) | |||
#else | |||
/** Don't use leak detection on release builds. */ | |||
# define DISTRHO_LEAK_DETECTOR(ClassName) | |||
# define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) | |||
#endif | |||
//============================================================================== | |||
/** |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -38,6 +38,7 @@ public: | |||
* Constructor. | |||
*/ | |||
Mutex() noexcept | |||
: fMutex() | |||
{ | |||
pthread_mutex_init(&fMutex, nullptr); | |||
} | |||
@@ -92,6 +93,11 @@ public: | |||
* Constructor. | |||
*/ | |||
RecursiveMutex() noexcept | |||
#ifdef DISTRHO_OS_WINDOWS | |||
: fSection() | |||
#else | |||
: fMutex() | |||
#endif | |||
{ | |||
#ifdef DISTRHO_OS_WINDOWS | |||
InitializeCriticalSection(&fSection); | |||
@@ -168,16 +174,16 @@ private: | |||
// Helper class to lock&unlock a mutex during a function scope. | |||
template <class Mutex> | |||
class ScopedLocker | |||
class ScopeLocker | |||
{ | |||
public: | |||
ScopedLocker(const Mutex& mutex) noexcept | |||
ScopeLocker(const Mutex& mutex) noexcept | |||
: fMutex(mutex) | |||
{ | |||
fMutex.lock(); | |||
} | |||
~ScopedLocker() noexcept | |||
~ScopeLocker() noexcept | |||
{ | |||
fMutex.unlock(); | |||
} | |||
@@ -186,23 +192,58 @@ private: | |||
const Mutex& fMutex; | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopedLocker) | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeLocker) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Helper class to try-lock&unlock a mutex during a function scope. | |||
template <class Mutex> | |||
class ScopeTryLocker | |||
{ | |||
public: | |||
ScopeTryLocker(const Mutex& mutex) noexcept | |||
: fMutex(mutex), | |||
fLocked(mutex.tryLock()) {} | |||
~ScopeTryLocker() noexcept | |||
{ | |||
if (fLocked) | |||
fMutex.unlock(); | |||
} | |||
bool wasLocked() const noexcept | |||
{ | |||
return fLocked; | |||
} | |||
bool wasNotLocked() const noexcept | |||
{ | |||
return !fLocked; | |||
} | |||
private: | |||
const Mutex& fMutex; | |||
const bool fLocked; | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeTryLocker) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Helper class to unlock&lock a mutex during a function scope. | |||
template <class Mutex> | |||
class ScopedUnlocker | |||
class ScopeUnlocker | |||
{ | |||
public: | |||
ScopedUnlocker(const Mutex& mutex) noexcept | |||
ScopeUnlocker(const Mutex& mutex) noexcept | |||
: fMutex(mutex) | |||
{ | |||
fMutex.unlock(); | |||
} | |||
~ScopedUnlocker() noexcept | |||
~ScopeUnlocker() noexcept | |||
{ | |||
fMutex.lock(); | |||
} | |||
@@ -211,17 +252,20 @@ private: | |||
const Mutex& fMutex; | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopedUnlocker) | |||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeUnlocker) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Define types | |||
typedef ScopedLocker<Mutex> MutexLocker; | |||
typedef ScopedLocker<RecursiveMutex> RecursiveMutexLocker; | |||
typedef ScopeLocker<Mutex> MutexLocker; | |||
typedef ScopeLocker<RecursiveMutex> RecursiveMutexLocker; | |||
typedef ScopeTryLocker<Mutex> MutexTryLocker; | |||
typedef ScopeTryLocker<RecursiveMutex> RecursiveMutexTryLocker; | |||
typedef ScopedUnlocker<Mutex> MutexUnlocker; | |||
typedef ScopedUnlocker<RecursiveMutex> RecursiveMutexUnlocker; | |||
typedef ScopeUnlocker<Mutex> MutexUnlocker; | |||
typedef ScopeUnlocker<RecursiveMutex> RecursiveMutexUnlocker; | |||
// ----------------------------------------------------------------------- | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -27,23 +27,6 @@ START_NAMESPACE_DISTRHO | |||
// The following code was based from juce-core ScopedPointer class | |||
// Copyright (C) 2013 Raw Material Software Ltd. | |||
/** | |||
Used by container classes as an indirect way to delete an object of a | |||
particular type. | |||
The generic implementation of this class simply calls 'delete', but you can | |||
create a specialised version of it for a particular class if you need to | |||
delete that type of object in a more appropriate way. | |||
*/ | |||
template<typename ObjectType> | |||
struct ContainerDeletePolicy | |||
{ | |||
static void destroy(ObjectType* const object) | |||
{ | |||
delete object; | |||
} | |||
}; | |||
//============================================================================== | |||
/** | |||
This class holds a pointer which is automatically deleted when this object goes | |||
@@ -107,7 +90,7 @@ public: | |||
*/ | |||
~ScopedPointer() | |||
{ | |||
ContainerDeletePolicy<ObjectType>::destroy(object); | |||
delete object; | |||
} | |||
/** Changes this ScopedPointer to point to a new object. | |||
@@ -130,7 +113,7 @@ public: | |||
ObjectType* const oldObject = object; | |||
object = objectToTransferFrom.object; | |||
objectToTransferFrom.object = nullptr; | |||
ContainerDeletePolicy<ObjectType>::destroy(oldObject); | |||
delete oldObject; | |||
} | |||
return *this; | |||
@@ -149,7 +132,7 @@ public: | |||
{ | |||
ObjectType* const oldObject = object; | |||
object = newObjectToTakePossessionOf; | |||
ContainerDeletePolicy<ObjectType>::destroy(oldObject); | |||
delete oldObject; | |||
} | |||
return *this; |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -29,6 +29,9 @@ | |||
// ----------------------------------------------------------------------- | |||
// d_*sleep | |||
/* | |||
* Sleep for 'secs' seconds. | |||
*/ | |||
static inline | |||
void d_sleep(const uint secs) noexcept | |||
{ | |||
@@ -43,6 +46,9 @@ void d_sleep(const uint secs) noexcept | |||
} DISTRHO_SAFE_EXCEPTION("d_sleep"); | |||
} | |||
/* | |||
* Sleep for 'msecs' milliseconds. | |||
*/ | |||
static inline | |||
void d_msleep(const uint msecs) noexcept | |||
{ |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,14 +17,14 @@ | |||
#ifndef DISTRHO_STRING_HPP_INCLUDED | |||
#define DISTRHO_STRING_HPP_INCLUDED | |||
#include "d_leakdetector.hpp" | |||
#include "../DistrhoUtils.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// d_string class | |||
// String class | |||
class d_string | |||
class String | |||
{ | |||
public: | |||
// ------------------------------------------------------------------- | |||
@@ -33,143 +33,153 @@ public: | |||
/* | |||
* Empty string. | |||
*/ | |||
explicit d_string() noexcept | |||
{ | |||
_init(); | |||
} | |||
explicit String() noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) {} | |||
/* | |||
* Simple character. | |||
*/ | |||
explicit d_string(const char c) noexcept | |||
explicit String(const char c) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char ch[2]; | |||
ch[0] = c; | |||
ch[1] = '\0'; | |||
_init(); | |||
_dup(ch); | |||
} | |||
/* | |||
* Simple char string. | |||
*/ | |||
explicit d_string(char* const strBuf) noexcept | |||
explicit String(char* const strBuf) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Simple const char string. | |||
*/ | |||
explicit d_string(const char* const strBuf) noexcept | |||
explicit String(const char* const strBuf) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Integer. | |||
*/ | |||
explicit d_string(const int value) noexcept | |||
explicit String(const int value) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, "%d", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Unsigned integer, possibly in hexadecimal. | |||
*/ | |||
explicit d_string(const unsigned int value, const bool hexadecimal = false) noexcept | |||
explicit String(const unsigned int value, const bool hexadecimal = false) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long integer. | |||
*/ | |||
explicit d_string(const long value) noexcept | |||
explicit String(const long value) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, "%ld", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long unsigned integer, possibly hexadecimal. | |||
*/ | |||
explicit d_string(const unsigned long value, const bool hexadecimal = false) noexcept | |||
explicit String(const unsigned long value, const bool hexadecimal = false) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long long integer. | |||
*/ | |||
explicit d_string(const long long value) noexcept | |||
explicit String(const long long value) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, "%lld", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Long long unsigned integer, possibly hexadecimal. | |||
*/ | |||
explicit d_string(const unsigned long long value, const bool hexadecimal = false) noexcept | |||
explicit String(const unsigned long long value, const bool hexadecimal = false) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Single-precision floating point number. | |||
*/ | |||
explicit d_string(const float value) noexcept | |||
explicit String(const float value) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, "%f", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
/* | |||
* Double-precision floating point number. | |||
*/ | |||
explicit d_string(const double value) noexcept | |||
explicit String(const double value) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
char strBuf[0xff+1]; | |||
std::snprintf(strBuf, 0xff, "%g", value); | |||
strBuf[0xff] = '\0'; | |||
_init(); | |||
_dup(strBuf); | |||
} | |||
@@ -179,9 +189,10 @@ public: | |||
/* | |||
* Create string from another string. | |||
*/ | |||
d_string(const d_string& str) noexcept | |||
String(const String& str) noexcept | |||
: fBuffer(_null()), | |||
fBufferLen(0) | |||
{ | |||
_init(); | |||
_dup(str.fBuffer); | |||
} | |||
@@ -191,7 +202,7 @@ public: | |||
/* | |||
* Destructor. | |||
*/ | |||
~d_string() noexcept | |||
~String() noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fBuffer != nullptr,); | |||
@@ -210,7 +221,7 @@ public: | |||
/* | |||
* Get length of the string. | |||
*/ | |||
size_t length() const noexcept | |||
std::size_t length() const noexcept | |||
{ | |||
return fBufferLen; | |||
} | |||
@@ -243,7 +254,7 @@ public: | |||
#ifdef __USE_GNU | |||
return (strcasestr(fBuffer, strBuf) != nullptr); | |||
#else | |||
d_string tmp1(fBuffer), tmp2(strBuf); | |||
String tmp1(fBuffer), tmp2(strBuf); | |||
// memory allocation failed or empty string(s) | |||
if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null()) | |||
@@ -261,7 +272,7 @@ public: | |||
/* | |||
* Check if character at 'pos' is a digit. | |||
*/ | |||
bool isDigit(const size_t pos) const noexcept | |||
bool isDigit(const std::size_t pos) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen, false); | |||
@@ -285,7 +296,7 @@ public: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(prefix != nullptr, false); | |||
const size_t prefixLen(std::strlen(prefix)); | |||
const std::size_t prefixLen(std::strlen(prefix)); | |||
if (fBufferLen < prefixLen) | |||
return false; | |||
@@ -310,7 +321,7 @@ public: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(suffix != nullptr, false); | |||
const size_t suffixLen(std::strlen(suffix)); | |||
const std::size_t suffixLen(std::strlen(suffix)); | |||
if (fBufferLen < suffixLen) | |||
return false; | |||
@@ -322,7 +333,7 @@ public: | |||
* Find the first occurrence of character 'c' in the string. | |||
* Returns "length()" if the character is not found. | |||
*/ | |||
size_t find(const char c, bool* const found = nullptr) const noexcept | |||
std::size_t find(const char c, bool* const found = nullptr) const noexcept | |||
{ | |||
if (fBufferLen == 0 || c == '\0') | |||
{ | |||
@@ -331,7 +342,7 @@ public: | |||
return fBufferLen; | |||
} | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] == c) | |||
{ | |||
@@ -350,7 +361,7 @@ public: | |||
* Find the first occurrence of string 'strBuf' in the string. | |||
* Returns "length()" if the string is not found. | |||
*/ | |||
size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
{ | |||
if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0') | |||
{ | |||
@@ -375,7 +386,7 @@ public: | |||
if (found != nullptr) | |||
*found = true; | |||
return static_cast<size_t>(ret); | |||
return static_cast<std::size_t>(ret); | |||
} | |||
if (found != nullptr) | |||
@@ -387,7 +398,7 @@ public: | |||
* Find the last occurrence of character 'c' in the string. | |||
* Returns "length()" if the character is not found. | |||
*/ | |||
size_t rfind(const char c, bool* const found = nullptr) const noexcept | |||
std::size_t rfind(const char c, bool* const found = nullptr) const noexcept | |||
{ | |||
if (fBufferLen == 0 || c == '\0') | |||
{ | |||
@@ -396,7 +407,7 @@ public: | |||
return fBufferLen; | |||
} | |||
for (size_t i=fBufferLen; i > 0; --i) | |||
for (std::size_t i=fBufferLen; i > 0; --i) | |||
{ | |||
if (fBuffer[i-1] == c) | |||
{ | |||
@@ -415,7 +426,7 @@ public: | |||
* Find the last occurrence of string 'strBuf' in the string. | |||
* Returns "length()" if the string is not found. | |||
*/ | |||
size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
{ | |||
if (found != nullptr) | |||
*found = false; | |||
@@ -423,12 +434,12 @@ public: | |||
if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0') | |||
return fBufferLen; | |||
const size_t strBufLen(std::strlen(strBuf)); | |||
const std::size_t strBufLen(std::strlen(strBuf)); | |||
size_t ret = fBufferLen; | |||
std::size_t ret = fBufferLen; | |||
const char* tmpBuf = fBuffer; | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0) | |||
{ | |||
@@ -455,37 +466,41 @@ public: | |||
/* | |||
* Replace all occurrences of character 'before' with character 'after'. | |||
*/ | |||
void replace(const char before, const char after) noexcept | |||
String& replace(const char before, const char after) noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',); | |||
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this); | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] == before) | |||
fBuffer[i] = after; | |||
} | |||
return *this; | |||
} | |||
/* | |||
* Truncate the string to size 'n'. | |||
*/ | |||
void truncate(const size_t n) noexcept | |||
String& truncate(const std::size_t n) noexcept | |||
{ | |||
if (n >= fBufferLen) | |||
return; | |||
return *this; | |||
for (size_t i=n; i < fBufferLen; ++i) | |||
for (std::size_t i=n; i < fBufferLen; ++i) | |||
fBuffer[i] = '\0'; | |||
fBufferLen = n; | |||
return *this; | |||
} | |||
/* | |||
* Convert all non-basic characters to '_'. | |||
*/ | |||
void toBasic() noexcept | |||
String& toBasic() noexcept | |||
{ | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] >= '0' && fBuffer[i] <= '9') | |||
continue; | |||
@@ -498,34 +513,40 @@ public: | |||
fBuffer[i] = '_'; | |||
} | |||
return *this; | |||
} | |||
/* | |||
* Convert to all ascii characters to lowercase. | |||
*/ | |||
void toLower() noexcept | |||
String& toLower() noexcept | |||
{ | |||
static const char kCharDiff('a' - 'A'); | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z') | |||
fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff); | |||
} | |||
return *this; | |||
} | |||
/* | |||
* Convert to all ascii characters to uppercase. | |||
*/ | |||
void toUpper() noexcept | |||
String& toUpper() noexcept | |||
{ | |||
static const char kCharDiff('a' - 'A'); | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z') | |||
fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff); | |||
} | |||
return *this; | |||
} | |||
/* | |||
@@ -536,6 +557,81 @@ public: | |||
return fBuffer; | |||
} | |||
// ------------------------------------------------------------------- | |||
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html | |||
// Copyright (C) 2004-2008 René Nyffenegger | |||
static String asBase64(const void* const data, const std::size_t dataSize) | |||
{ | |||
static const char* const kBase64Chars = | |||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
"abcdefghijklmnopqrstuvwxyz" | |||
"0123456789+/"; | |||
const std::size_t kTmpBufSize = d_nextPowerOf2(dataSize/3); | |||
const uchar* bytesToEncode((const uchar*)data); | |||
uint i=0, j=0; | |||
uint charArray3[3], charArray4[4]; | |||
char strBuf[kTmpBufSize+1]; | |||
strBuf[kTmpBufSize] = '\0'; | |||
std::size_t strBufIndex = 0; | |||
String ret; | |||
for (std::size_t s=0; s<dataSize; ++s) | |||
{ | |||
charArray3[i++] = *(bytesToEncode++); | |||
if (i == 3) | |||
{ | |||
charArray4[0] = (charArray3[0] & 0xfc) >> 2; | |||
charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); | |||
charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); | |||
charArray4[3] = charArray3[2] & 0x3f; | |||
for (i=0; i<4; ++i) | |||
strBuf[strBufIndex++] = kBase64Chars[charArray4[i]]; | |||
if (strBufIndex >= kTmpBufSize-7) | |||
{ | |||
strBuf[strBufIndex] = '\0'; | |||
strBufIndex = 0; | |||
ret += strBuf; | |||
} | |||
i = 0; | |||
} | |||
} | |||
if (i != 0) | |||
{ | |||
for (j=i; j<3; ++j) | |||
charArray3[j] = '\0'; | |||
charArray4[0] = (charArray3[0] & 0xfc) >> 2; | |||
charArray4[1] = ((charArray3[0] & 0x03) << 4) + ((charArray3[1] & 0xf0) >> 4); | |||
charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); | |||
charArray4[3] = charArray3[2] & 0x3f; | |||
for (j=0; j<4 && i<3 && j<i+1; ++j) | |||
strBuf[strBufIndex++] = kBase64Chars[charArray4[j]]; | |||
for (; i++ < 3;) | |||
strBuf[strBufIndex++] = '='; | |||
} | |||
if (strBufIndex != 0) | |||
{ | |||
strBuf[strBufIndex] = '\0'; | |||
ret += strBuf; | |||
} | |||
return ret; | |||
} | |||
// ------------------------------------------------------------------- | |||
// public operators | |||
@@ -544,7 +640,7 @@ public: | |||
return fBuffer; | |||
} | |||
char operator[](const size_t pos) const noexcept | |||
char operator[](const std::size_t pos) const noexcept | |||
{ | |||
if (pos < fBufferLen) | |||
return fBuffer[pos]; | |||
@@ -556,7 +652,7 @@ public: | |||
return fallback; | |||
} | |||
char& operator[](const size_t pos) noexcept | |||
char& operator[](const std::size_t pos) noexcept | |||
{ | |||
if (pos < fBufferLen) | |||
return fBuffer[pos]; | |||
@@ -573,7 +669,7 @@ public: | |||
return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0); | |||
} | |||
bool operator==(const d_string& str) const noexcept | |||
bool operator==(const String& str) const noexcept | |||
{ | |||
return operator==(str.fBuffer); | |||
} | |||
@@ -583,32 +679,32 @@ public: | |||
return !operator==(strBuf); | |||
} | |||
bool operator!=(const d_string& str) const noexcept | |||
bool operator!=(const String& str) const noexcept | |||
{ | |||
return !operator==(str.fBuffer); | |||
} | |||
d_string& operator=(const char* const strBuf) noexcept | |||
String& operator=(const char* const strBuf) noexcept | |||
{ | |||
_dup(strBuf); | |||
return *this; | |||
} | |||
d_string& operator=(const d_string& str) noexcept | |||
String& operator=(const String& str) noexcept | |||
{ | |||
_dup(str.fBuffer); | |||
return *this; | |||
} | |||
d_string& operator+=(const char* const strBuf) noexcept | |||
String& operator+=(const char* const strBuf) noexcept | |||
{ | |||
if (strBuf == nullptr) | |||
return *this; | |||
const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1; | |||
char newBuf[newBufSize]; | |||
const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, fBuffer); | |||
std::strcat(newBuf, strBuf); | |||
@@ -618,25 +714,25 @@ public: | |||
return *this; | |||
} | |||
d_string& operator+=(const d_string& str) noexcept | |||
String& operator+=(const String& str) noexcept | |||
{ | |||
return operator+=(str.fBuffer); | |||
} | |||
d_string operator+(const char* const strBuf) noexcept | |||
String operator+(const char* const strBuf) noexcept | |||
{ | |||
const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, fBuffer); | |||
if (strBuf != nullptr) | |||
std::strcat(newBuf, strBuf); | |||
return d_string(newBuf); | |||
return String(newBuf); | |||
} | |||
d_string operator+(const d_string& str) noexcept | |||
String operator+(const String& str) noexcept | |||
{ | |||
return operator+(str.fBuffer); | |||
} | |||
@@ -644,8 +740,8 @@ public: | |||
// ------------------------------------------------------------------- | |||
private: | |||
char* fBuffer; // the actual string buffer | |||
size_t fBufferLen; // string length | |||
char* fBuffer; // the actual string buffer | |||
std::size_t fBufferLen; // string length | |||
/* | |||
* Static null string. | |||
@@ -657,16 +753,6 @@ private: | |||
return &sNull; | |||
} | |||
/* | |||
* Shared init function. | |||
* Called on all constructors. | |||
*/ | |||
void _init() noexcept | |||
{ | |||
fBuffer = _null(); | |||
fBufferLen = 0; | |||
} | |||
/* | |||
* Helper function. | |||
* Called whenever the string needs to be allocated. | |||
@@ -675,7 +761,7 @@ private: | |||
* - Allocates string only if 'strBuf' is not null and new string contents are different | |||
* - If 'strBuf' is null, 'size' must be 0 | |||
*/ | |||
void _dup(const char* const strBuf, const size_t size = 0) noexcept | |||
void _dup(const char* const strBuf, const std::size_t size = 0) noexcept | |||
{ | |||
if (strBuf != nullptr) | |||
{ | |||
@@ -690,7 +776,11 @@ private: | |||
fBuffer = (char*)std::malloc(fBufferLen+1); | |||
if (fBuffer == nullptr) | |||
return _init(); | |||
{ | |||
fBuffer = _null(); | |||
fBufferLen = 0; | |||
return; | |||
} | |||
std::strcpy(fBuffer, strBuf); | |||
@@ -707,40 +797,40 @@ private: | |||
DISTRHO_SAFE_ASSERT(fBuffer != nullptr); | |||
std::free(fBuffer); | |||
_init(); | |||
fBuffer = _null(); | |||
fBufferLen = 0; | |||
} | |||
} | |||
DISTRHO_LEAK_DETECTOR(d_string) | |||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||
}; | |||
// ----------------------------------------------------------------------- | |||
static inline | |||
d_string operator+(const d_string& strBefore, const char* const strBufAfter) noexcept | |||
String operator+(const String& strBefore, const char* const strBufAfter) noexcept | |||
{ | |||
const char* const strBufBefore = strBefore.buffer(); | |||
const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1; | |||
const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, strBufBefore); | |||
std::strcat(newBuf, strBufAfter); | |||
return d_string(newBuf); | |||
return String(newBuf); | |||
} | |||
static inline | |||
d_string operator+(const char* const strBufBefore, const d_string& strAfter) noexcept | |||
String operator+(const char* const strBufBefore, const String& strAfter) noexcept | |||
{ | |||
const char* const strBufAfter = strAfter.buffer(); | |||
const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1; | |||
const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1; | |||
char newBuf[newBufSize]; | |||
std::strcpy(newBuf, strBufBefore); | |||
std::strcat(newBuf, strBufAfter); | |||
return d_string(newBuf); | |||
return String(newBuf); | |||
} | |||
// ----------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -17,13 +17,11 @@ | |||
#ifndef DISTRHO_THREAD_HPP_INCLUDED | |||
#define DISTRHO_THREAD_HPP_INCLUDED | |||
#include "d_mutex.hpp" | |||
#include "d_sleep.hpp" | |||
#include "d_string.hpp" | |||
#include "Mutex.hpp" | |||
#include "Sleep.hpp" | |||
#include "String.hpp" | |||
#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 | |||
// has pthread_setname_np | |||
#elif defined(DISTRHO_OS_LINUX) | |||
#ifdef DISTRHO_OS_LINUX | |||
# include <sys/prctl.h> | |||
#endif | |||
@@ -156,7 +154,7 @@ public: | |||
if (isThreadRunning()) | |||
{ | |||
// should never happen! | |||
d_stderr2("Carla assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__); | |||
d_stderr2("assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__); | |||
// copy thread id so we can clear our one | |||
pthread_t threadId; | |||
@@ -188,7 +186,7 @@ public: | |||
* Returns the name of the thread. | |||
* This is the name that gets set in the constructor. | |||
*/ | |||
const d_string& getThreadName() const noexcept | |||
const String& getThreadName() const noexcept | |||
{ | |||
return fName; | |||
} | |||
@@ -200,10 +198,11 @@ public: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | |||
#ifdef DISTRHO_OS_LINUX | |||
prctl(PR_SET_NAME, name, 0, 0, 0); | |||
#endif | |||
#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 | |||
pthread_setname_np(pthread_self(), name); | |||
#elif defined(DISTRHO_OS_LINUX) | |||
prctl(PR_SET_NAME, name, 0, 0, 0); | |||
#endif | |||
} | |||
@@ -211,7 +210,7 @@ public: | |||
private: | |||
Mutex fLock; // Thread lock | |||
const d_string fName; // Thread name | |||
const String fName; // Thread name | |||
volatile pthread_t fHandle; // Handle for this thread | |||
volatile bool fShouldExit; // true if thread should exit | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -27,15 +27,20 @@ double d_lastSampleRate = 0.0; | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Static fallback data, see DistrhoPluginInternal.hpp */ | |||
const d_string PluginExporter::sFallbackString; | |||
const String PluginExporter::sFallbackString; | |||
const AudioPort PluginExporter::sFallbackAudioPort; | |||
const ParameterRanges PluginExporter::sFallbackRanges; | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Plugin */ | |||
Plugin::Plugin(const uint32_t parameterCount, const uint32_t programCount, const uint32_t stateCount) | |||
Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount) | |||
: pData(new PrivateData()) | |||
{ | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
pData->audioPorts = new AudioPort[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
#endif | |||
if (parameterCount > 0) | |||
{ | |||
pData->parameterCount = parameterCount; | |||
@@ -46,7 +51,7 @@ Plugin::Plugin(const uint32_t parameterCount, const uint32_t programCount, const | |||
if (programCount > 0) | |||
{ | |||
pData->programCount = programCount; | |||
pData->programNames = new d_string[programCount]; | |||
pData->programNames = new String[programCount]; | |||
} | |||
#else | |||
DISTRHO_SAFE_ASSERT(programCount == 0); | |||
@@ -56,8 +61,8 @@ Plugin::Plugin(const uint32_t parameterCount, const uint32_t programCount, const | |||
if (stateCount > 0) | |||
{ | |||
pData->stateCount = stateCount; | |||
pData->stateKeys = new d_string[stateCount]; | |||
pData->stateDefValues = new d_string[stateCount]; | |||
pData->stateKeys = new String[stateCount]; | |||
pData->stateDefValues = new String[stateCount]; | |||
} | |||
#else | |||
DISTRHO_SAFE_ASSERT(stateCount == 0); | |||
@@ -72,43 +77,64 @@ Plugin::~Plugin() | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Host state */ | |||
uint32_t Plugin::d_getBufferSize() const noexcept | |||
uint32_t Plugin::getBufferSize() const noexcept | |||
{ | |||
return pData->bufferSize; | |||
} | |||
double Plugin::d_getSampleRate() const noexcept | |||
double Plugin::getSampleRate() const noexcept | |||
{ | |||
return pData->sampleRate; | |||
} | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
const TimePosition& Plugin::d_getTimePosition() const noexcept | |||
const TimePosition& Plugin::getTimePosition() const noexcept | |||
{ | |||
return pData->timePosition; | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
void Plugin::d_setLatency(const uint32_t frames) noexcept | |||
void Plugin::setLatency(uint32_t frames) noexcept | |||
{ | |||
pData->latency = frames; | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
bool Plugin::d_writeMidiEvent(const MidiEvent& /*midiEvent*/) noexcept | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
bool Plugin::writeMidiEvent(const MidiEvent& /*midiEvent*/) noexcept | |||
{ | |||
// TODO | |||
return false; | |||
} | |||
#endif | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Init */ | |||
void Plugin::initAudioPort(bool input, uint32_t index, AudioPort& port) | |||
{ | |||
if (port.hints & kAudioPortIsCV) | |||
{ | |||
port.name = input ? "CV Input " : "CV Output "; | |||
port.name += String(index+1); | |||
port.symbol = input ? "cv_in_" : "cv_out_"; | |||
port.symbol += String(index+1); | |||
} | |||
else | |||
{ | |||
port.name = input ? "Audio Input " : "Audio Output "; | |||
port.name += String(index+1); | |||
port.symbol = input ? "audio_in_" : "audio_out_"; | |||
port.symbol += String(index+1); | |||
} | |||
} | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Callbacks (optional) */ | |||
void Plugin::d_bufferSizeChanged(uint32_t) {} | |||
void Plugin::d_sampleRateChanged(double) {} | |||
void Plugin::bufferSizeChanged(uint32_t) {} | |||
void Plugin::sampleRateChanged(double) {} | |||
// ----------------------------------------------------------------------------------------------------------- | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
@@ -76,7 +76,7 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void carla_setMidiProgram(const uint32_t realProgram) | |||
{ | |||
fUI.programChanged(realProgram); | |||
fUI.programLoaded(realProgram); | |||
} | |||
#endif | |||
@@ -292,7 +292,7 @@ protected: | |||
CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),); | |||
fPlugin.setProgram(realProgram); | |||
fPlugin.loadProgram(realProgram); | |||
} | |||
#endif | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -26,14 +26,6 @@ | |||
# error DISTRHO_PLUGIN_NAME undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_HAS_UI | |||
# error DISTRHO_PLUGIN_HAS_UI undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_IS_SYNTH | |||
# error DISTRHO_PLUGIN_IS_SYNTH undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_NUM_INPUTS | |||
# error DISTRHO_PLUGIN_NUM_INPUTS undefined! | |||
#endif | |||
@@ -42,51 +34,47 @@ | |||
# error DISTRHO_PLUGIN_NUM_OUTPUTS undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_LATENCY | |||
# error DISTRHO_PLUGIN_WANT_LATENCY undefined! | |||
#ifndef DISTRHO_PLUGIN_URI | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS | |||
# error DISTRHO_PLUGIN_WANT_PROGRAMS undefined! | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Define optional macros if not done yet | |||
#ifndef DISTRHO_PLUGIN_WANT_STATE | |||
# error DISTRHO_PLUGIN_WANT_STATE undefined! | |||
#ifndef DISTRHO_PLUGIN_HAS_UI | |||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_TIMEPOS | |||
# error DISTRHO_PLUGIN_WANT_TIMEPOS undefined! | |||
#ifndef DISTRHO_PLUGIN_IS_RT_SAFE | |||
# define DISTRHO_PLUGIN_IS_RT_SAFE 0 | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Test if synth has audio outputs | |||
#if DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | |||
# error Synths need audio output to work! | |||
#ifndef DISTRHO_PLUGIN_IS_SYNTH | |||
# define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Enable MIDI input if synth, test if midi-input disabled when synth | |||
#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
# define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# define DISTRHO_PLUGIN_HAS_MIDI_INPUT DISTRHO_PLUGIN_IS_SYNTH | |||
#elif DISTRHO_PLUGIN_IS_SYNTH && ! DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# error Synths need MIDI input to work! | |||
#ifndef DISTRHO_PLUGIN_WANT_LATENCY | |||
# define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Define optional macros if not done yet | |||
#ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
# define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
# define DISTRHO_PLUGIN_HAS_MIDI_OUTPUT 0 | |||
#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS | |||
# define DISTRHO_PLUGIN_WANT_PROGRAMS 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_IS_RT_SAFE | |||
# define DISTRHO_PLUGIN_IS_RT_SAFE 0 | |||
#ifndef DISTRHO_PLUGIN_WANT_STATE | |||
# define DISTRHO_PLUGIN_WANT_STATE 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
# define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||
#ifndef DISTRHO_PLUGIN_WANT_TIMEPOS | |||
# define DISTRHO_PLUGIN_WANT_TIMEPOS 0 | |||
#endif | |||
#ifndef DISTRHO_UI_USE_NANOVG | |||
@@ -100,6 +88,22 @@ | |||
# define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Test if synth has audio outputs | |||
#if DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | |||
# error Synths need audio output to work! | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Enable MIDI input if synth, test if midi-input disabled when synth | |||
#ifndef DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
# define DISTRHO_PLUGIN_WANT_MIDI_INPUT DISTRHO_PLUGIN_IS_SYNTH | |||
#elif DISTRHO_PLUGIN_IS_SYNTH && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
# error Synths need MIDI input to work! | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -38,18 +38,22 @@ extern double d_lastSampleRate; | |||
struct Plugin::PrivateData { | |||
bool isProcessing; | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
AudioPort* audioPorts; | |||
#endif | |||
uint32_t parameterCount; | |||
Parameter* parameters; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
uint32_t programCount; | |||
d_string* programNames; | |||
uint32_t programCount; | |||
String* programNames; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
uint32_t stateCount; | |||
d_string* stateKeys; | |||
d_string* stateDefValues; | |||
uint32_t stateCount; | |||
String* stateKeys; | |||
String* stateDefValues; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
@@ -65,6 +69,9 @@ struct Plugin::PrivateData { | |||
PrivateData() noexcept | |||
: isProcessing(false), | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
audioPorts(nullptr), | |||
#endif | |||
parameterCount(0), | |||
parameters(nullptr), | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
@@ -88,6 +95,14 @@ struct Plugin::PrivateData { | |||
~PrivateData() noexcept | |||
{ | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
if (audioPorts != nullptr) | |||
{ | |||
delete[] audioPorts; | |||
audioPorts = nullptr; | |||
} | |||
#endif | |||
if (parameters != nullptr) | |||
{ | |||
delete[] parameters; | |||
@@ -132,17 +147,31 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
{ | |||
uint32_t j=0; | |||
# if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j) | |||
fPlugin->initAudioPort(true, i, fData->audioPorts[j]); | |||
# endif | |||
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j) | |||
fPlugin->initAudioPort(false, i, fData->audioPorts[j]); | |||
# endif | |||
} | |||
#endif | |||
for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
fPlugin->d_initParameter(i, fData->parameters[i]); | |||
fPlugin->initParameter(i, fData->parameters[i]); | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
for (uint32_t i=0, count=fData->programCount; i < count; ++i) | |||
fPlugin->d_initProgramName(i, fData->programNames[i]); | |||
fPlugin->initProgramName(i, fData->programNames[i]); | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
for (uint32_t i=0, count=fData->stateCount; i < count; ++i) | |||
fPlugin->d_initState(i, fData->stateKeys[i], fData->stateDefValues[i]); | |||
fPlugin->initState(i, fData->stateKeys[i], fData->stateDefValues[i]); | |||
#endif | |||
} | |||
@@ -157,42 +186,42 @@ public: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); | |||
return fPlugin->d_getName(); | |||
return fPlugin->getName(); | |||
} | |||
const char* getLabel() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); | |||
return fPlugin->d_getLabel(); | |||
return fPlugin->getLabel(); | |||
} | |||
const char* getMaker() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); | |||
return fPlugin->d_getMaker(); | |||
return fPlugin->getMaker(); | |||
} | |||
const char* getLicense() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, ""); | |||
return fPlugin->d_getLicense(); | |||
return fPlugin->getLicense(); | |||
} | |||
uint32_t getVersion() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0); | |||
return fPlugin->d_getVersion(); | |||
return fPlugin->getVersion(); | |||
} | |||
long getUniqueId() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0); | |||
return fPlugin->d_getUniqueId(); | |||
return fPlugin->getUniqueId(); | |||
} | |||
void* getInstancePointer() const noexcept | |||
@@ -211,6 +240,28 @@ public: | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); | |||
if (input) | |||
{ | |||
# if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS, sFallbackAudioPort); | |||
# endif | |||
} | |||
else | |||
{ | |||
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort); | |||
# endif | |||
} | |||
return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; | |||
} | |||
#endif | |||
uint32_t getParameterCount() const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | |||
@@ -230,21 +281,21 @@ public: | |||
return (getParameterHints(index) & kParameterIsOutput); | |||
} | |||
const d_string& getParameterName(const uint32_t index) const noexcept | |||
const String& getParameterName(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); | |||
return fData->parameters[index].name; | |||
} | |||
const d_string& getParameterSymbol(const uint32_t index) const noexcept | |||
const String& getParameterSymbol(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); | |||
return fData->parameters[index].symbol; | |||
} | |||
const d_string& getParameterUnit(const uint32_t index) const noexcept | |||
const String& getParameterUnit(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString); | |||
@@ -263,7 +314,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f); | |||
return fPlugin->d_getParameterValue(index); | |||
return fPlugin->getParameterValue(index); | |||
} | |||
void setParameterValue(const uint32_t index, const float value) | |||
@@ -271,7 +322,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount,); | |||
fPlugin->d_setParameterValue(index, value); | |||
fPlugin->setParameterValue(index, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
@@ -282,19 +333,19 @@ public: | |||
return fData->programCount; | |||
} | |||
const d_string& getProgramName(const uint32_t index) const noexcept | |||
const String& getProgramName(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount, sFallbackString); | |||
return fData->programNames[index]; | |||
} | |||
void setProgram(const uint32_t index) | |||
void loadProgram(const uint32_t index) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->programCount,); | |||
fPlugin->d_setProgram(index); | |||
fPlugin->loadProgram(index); | |||
} | |||
#endif | |||
@@ -306,14 +357,14 @@ public: | |||
return fData->stateCount; | |||
} | |||
const d_string& getStateKey(const uint32_t index) const noexcept | |||
const String& getStateKey(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); | |||
return fData->stateKeys[index]; | |||
} | |||
const d_string& getStateDefaultValue(const uint32_t index) const noexcept | |||
const String& getStateDefaultValue(const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->stateCount, sFallbackString); | |||
@@ -326,7 +377,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | |||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); | |||
fPlugin->d_setState(key, value); | |||
fPlugin->setState(key, value); | |||
} | |||
bool wantStateKey(const char* const key) const noexcept | |||
@@ -355,20 +406,38 @@ public: | |||
// ------------------------------------------------------------------- | |||
bool isActive() const noexcept | |||
{ | |||
return fIsActive; | |||
} | |||
void activate() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(! fIsActive,); | |||
fIsActive = true; | |||
fPlugin->d_activate(); | |||
fPlugin->activate(); | |||
} | |||
void deactivate() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fIsActive,); | |||
fIsActive = false; | |||
fPlugin->d_deactivate(); | |||
fPlugin->deactivate(); | |||
} | |||
void deactivateIfNeeded() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
if (fIsActive) | |||
{ | |||
fIsActive = false; | |||
fPlugin->deactivate(); | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
@@ -378,8 +447,14 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
if (! fIsActive) | |||
{ | |||
fIsActive = true; | |||
fPlugin->activate(); | |||
} | |||
fData->isProcessing = true; | |||
fPlugin->d_run(inputs, outputs, frames, midiEvents, midiEventCount); | |||
fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount); | |||
fData->isProcessing = false; | |||
} | |||
#else | |||
@@ -388,8 +463,14 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
if (! fIsActive) | |||
{ | |||
fIsActive = true; | |||
fPlugin->activate(); | |||
} | |||
fData->isProcessing = true; | |||
fPlugin->d_run(inputs, outputs, frames); | |||
fPlugin->run(inputs, outputs, frames); | |||
fData->isProcessing = false; | |||
} | |||
#endif | |||
@@ -421,9 +502,9 @@ public: | |||
if (doCallback) | |||
{ | |||
if (fIsActive) fPlugin->d_deactivate(); | |||
fPlugin->d_bufferSizeChanged(bufferSize); | |||
if (fIsActive) fPlugin->d_activate(); | |||
if (fIsActive) fPlugin->deactivate(); | |||
fPlugin->bufferSizeChanged(bufferSize); | |||
if (fIsActive) fPlugin->activate(); | |||
} | |||
} | |||
@@ -440,9 +521,9 @@ public: | |||
if (doCallback) | |||
{ | |||
if (fIsActive) fPlugin->d_deactivate(); | |||
fPlugin->d_sampleRateChanged(sampleRate); | |||
if (fIsActive) fPlugin->d_activate(); | |||
if (fIsActive) fPlugin->deactivate(); | |||
fPlugin->sampleRateChanged(sampleRate); | |||
if (fIsActive) fPlugin->activate(); | |||
} | |||
} | |||
@@ -457,7 +538,8 @@ private: | |||
// ------------------------------------------------------------------- | |||
// Static fallback data, see DistrhoPlugin.cpp | |||
static const d_string sFallbackString; | |||
static const String sFallbackString; | |||
static const AudioPort sFallbackAudioPort; | |||
static const ParameterRanges sFallbackRanges; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
@@ -16,32 +16,91 @@ | |||
#include "DistrhoPluginInternal.hpp" | |||
#if ! DISTRHO_PLUGIN_HAS_UI | |||
# error JACK export requires an UI | |||
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) | |||
# undef DISTRHO_PLUGIN_HAS_UI | |||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||
#endif | |||
#include "DistrhoUIInternal.hpp" | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# include "DistrhoUIInternal.hpp" | |||
#else | |||
# include "../extra/Sleep.hpp" | |||
#endif | |||
#include "jack/jack.h" | |||
#include "jack/midiport.h" | |||
#include "jack/transport.h" | |||
#ifndef DISTRHO_OS_WINDOWS | |||
# include <signal.h> | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
START_NAMESPACE_DISTRHO | |||
#if ! DISTRHO_PLUGIN_WANT_STATE | |||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_STATE | |||
static const setStateFunc setStateCallback = nullptr; | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
static volatile bool gCloseSignalReceived = false; | |||
#ifdef DISTRHO_OS_WINDOWS | |||
static BOOL WINAPI winSignalHandler(DWORD dwCtrlType) noexcept | |||
{ | |||
if (dwCtrlType == CTRL_C_EVENT) | |||
{ | |||
gCloseSignalReceived = true; | |||
return TRUE; | |||
} | |||
return FALSE; | |||
} | |||
static void initSignalHandler() | |||
{ | |||
SetConsoleCtrlHandler(winSignalHandler, TRUE); | |||
} | |||
#else | |||
static void closeSignalHandler(int) noexcept | |||
{ | |||
gCloseSignalReceived = true; | |||
} | |||
static void initSignalHandler() | |||
{ | |||
struct sigaction sint; | |||
struct sigaction sterm; | |||
sint.sa_handler = closeSignalHandler; | |||
sint.sa_flags = SA_RESTART; | |||
sint.sa_restorer = nullptr; | |||
sigemptyset(&sint.sa_mask); | |||
sigaction(SIGINT, &sint, nullptr); | |||
sterm.sa_handler = closeSignalHandler; | |||
sterm.sa_flags = SA_RESTART; | |||
sterm.sa_restorer = nullptr; | |||
sigemptyset(&sterm.sa_mask); | |||
sigaction(SIGTERM, &sterm, nullptr); | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
class PluginJack : public IdleCallback | |||
#else | |||
class PluginJack | |||
#endif | |||
{ | |||
public: | |||
PluginJack(jack_client_t* const client) | |||
: fPlugin(), | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
fUI(this, 0, nullptr, setParameterValueCallback, setStateCallback, nullptr, setSizeCallback, fPlugin.getInstancePointer()), | |||
#endif | |||
fClient(client) | |||
{ | |||
char strBuf[0xff+1]; | |||
@@ -70,8 +129,10 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
if (fPlugin.getProgramCount() > 0) | |||
{ | |||
fPlugin.setProgram(0); | |||
fUI.programChanged(0); | |||
fPlugin.loadProgram(0); | |||
# if DISTRHO_PLUGIN_HAS_UI | |||
fUI.programLoaded(0); | |||
# endif | |||
} | |||
#endif | |||
@@ -88,7 +149,9 @@ public: | |||
else | |||
{ | |||
fLastOutputValues[i] = 0.0f; | |||
# if DISTRHO_PLUGIN_HAS_UI | |||
fUI.parameterChanged(i, fPlugin.getParameterValue(i)); | |||
# endif | |||
} | |||
} | |||
} | |||
@@ -102,14 +165,21 @@ public: | |||
jack_set_process_callback(fClient, jackProcessCallback, this); | |||
jack_on_shutdown(fClient, jackShutdownCallback, this); | |||
fPlugin.activate(); | |||
jack_activate(fClient); | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
if (const char* const name = jack_get_client_name(fClient)) | |||
fUI.setWindowTitle(name); | |||
else | |||
fUI.setWindowTitle(fPlugin.getName()); | |||
fUI.exec(this); | |||
#else | |||
while (! gCloseSignalReceived) | |||
d_sleep(1); | |||
#endif | |||
} | |||
~PluginJack() | |||
@@ -119,6 +189,8 @@ public: | |||
jack_deactivate(fClient); | |||
fPlugin.deactivate(); | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
jack_port_unregister(fClient, fPortMidiIn); | |||
fPortMidiIn = nullptr; | |||
@@ -146,8 +218,12 @@ public: | |||
// ------------------------------------------------------------------- | |||
protected: | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
void idleCallback() override | |||
{ | |||
if (gCloseSignalReceived) | |||
return fUI.quit(); | |||
float value; | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
@@ -166,6 +242,7 @@ protected: | |||
fUI.exec_idle(); | |||
} | |||
#endif | |||
void jackBufferSize(const jack_nframes_t nframes) | |||
{ | |||
@@ -273,7 +350,9 @@ protected: | |||
{ | |||
d_stderr("jack has shutdown, quitting now..."); | |||
fClient = nullptr; | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
fUI.quit(); | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -290,16 +369,20 @@ protected: | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
void setSize(const uint width, const uint height) | |||
{ | |||
fUI.setWindowSize(width, height); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
private: | |||
PluginExporter fPlugin; | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
UIExporter fUI; | |||
#endif | |||
jack_client_t* fClient; | |||
@@ -359,10 +442,12 @@ private: | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
static void setSizeCallback(void* ptr, uint width, uint height) | |||
{ | |||
uiPtr->setSize(width, height); | |||
} | |||
#endif | |||
#undef uiPtr | |||
}; | |||
@@ -380,7 +465,7 @@ int main() | |||
if (client == nullptr) | |||
{ | |||
d_string errorString; | |||
String errorString; | |||
if (status & JackFailure) | |||
errorString += "Overall operation failed;\n"; | |||
@@ -422,9 +507,13 @@ int main() | |||
USE_NAMESPACE_DISTRHO; | |||
initSignalHandler(); | |||
d_lastBufferSize = jack_get_buffer_size(client); | |||
d_lastSampleRate = jack_get_sample_rate(client); | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
d_lastUiSampleRate = d_lastSampleRate; | |||
#endif | |||
const PluginJack p(client); | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -16,7 +16,7 @@ | |||
#include "DistrhoPluginInternal.hpp" | |||
#if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
# error Cannot use MIDI Output with LADSPA or DSSI | |||
#endif | |||
@@ -24,7 +24,7 @@ | |||
# include "dssi/dssi.h" | |||
#else | |||
# include "ladspa/ladspa.h" | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
# error Cannot use MIDI with LADSPA | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
@@ -190,7 +190,7 @@ public: | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
// Get MIDI Events | |||
uint32_t midiEventCount = 0; | |||
MidiEvent midiEvents[eventCount]; | |||
@@ -271,7 +271,7 @@ public: | |||
updateParameterOutputs(); | |||
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
return; // unused | |||
(void)events; (void)eventCount; | |||
#endif | |||
@@ -314,7 +314,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(realProgram < fPlugin.getProgramCount(),); | |||
fPlugin.setProgram(realProgram); | |||
fPlugin.loadProgram(realProgram); | |||
// Update control inputs | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
@@ -435,7 +435,7 @@ static void dssi_select_program(LADSPA_Handle instance, ulong bank, ulong progra | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
static void dssi_run_synth(LADSPA_Handle instance, ulong sampleCount, snd_seq_event_t* events, ulong eventCount) | |||
{ | |||
instancePtr->dssi_run_synth(sampleCount, events, eventCount); | |||
@@ -490,7 +490,7 @@ static DSSI_Descriptor sDssiDescriptor = { | |||
/* select_program */ nullptr, | |||
# endif | |||
/* get_midi_controller_for_port */ nullptr, | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
dssi_run_synth, | |||
# else | |||
/* run_synth */ nullptr, | |||
@@ -530,10 +530,9 @@ public: | |||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++port) | |||
{ | |||
char portName[24] = { '\0' }; | |||
std::sprintf(portName, "Audio Input %lu", i+1); | |||
const AudioPort& aport(plugin.getAudioPort(true, i)); | |||
portNames[port] = strdup(portName); | |||
portNames[port] = strdup(aport.name); | |||
portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT; | |||
portRangeHints[port].HintDescriptor = 0x0; | |||
@@ -545,10 +544,9 @@ public: | |||
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++port) | |||
{ | |||
char portName[24] = { '\0' }; | |||
std::sprintf(portName, "Audio Output %lu", i+1); | |||
const AudioPort& aport(plugin.getAudioPort(false, i)); | |||
portNames[port] = strdup(portName); | |||
portNames[port] = strdup(aport.name); | |||
portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT; | |||
portRangeHints[port].HintDescriptor = 0x0; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -40,16 +40,12 @@ | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
# warning LV2 TimePos still TODO | |||
#endif | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_HAS_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_HAS_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
START_NAMESPACE_DISTRHO | |||
typedef std::map<const d_string,d_string> StringMap; | |||
typedef std::map<const String, String> StringMap; | |||
// ----------------------------------------------------------------------- | |||
@@ -61,9 +57,6 @@ public: | |||
fLastControlValues(nullptr), | |||
fSampleRate(sampleRate), | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
fLastTimeSpeed(0.0), | |||
# endif | |||
fURIDs(uridMap), | |||
#endif | |||
fUridMap(uridMap), | |||
@@ -119,8 +112,8 @@ public: | |||
{ | |||
fNeededUiSends[i] = false; | |||
const d_string& d_key(fPlugin.getStateKey(i)); | |||
fStateMap[d_key] = fPlugin.getStateDefaultValue(i); | |||
const String& dkey(fPlugin.getStateKey(i)); | |||
fStateMap[dkey] = fPlugin.getStateDefaultValue(i); | |||
} | |||
} | |||
else | |||
@@ -133,8 +126,7 @@ public: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
// hosts may not send all values, resulting on some invalid ones | |||
fTimePosition.bbt.valid = false; | |||
// hosts may not send all values, resulting on some invalid data | |||
fTimePosition.bbt.bar = 1; | |||
fTimePosition.bbt.beat = 1; | |||
fTimePosition.bbt.tick = 0; | |||
@@ -271,7 +263,7 @@ public: | |||
} | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
uint32_t midiEventCount = 0; | |||
# endif | |||
LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) | |||
@@ -279,7 +271,7 @@ public: | |||
if (event == nullptr) | |||
break; | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
if (event->body.type == fURIDs.midiEvent) | |||
{ | |||
if (midiEventCount >= kMaxMidiEvents) | |||
@@ -311,142 +303,178 @@ public: | |||
LV2_Atom* bar = nullptr; | |||
LV2_Atom* barBeat = nullptr; | |||
LV2_Atom* beat = nullptr; | |||
LV2_Atom* beatUnit = nullptr; | |||
LV2_Atom* beatsPerBar = nullptr; | |||
LV2_Atom* beatsPerMinute = nullptr; | |||
LV2_Atom* ticksPerBeat = nullptr; | |||
LV2_Atom* frame = nullptr; | |||
LV2_Atom* speed = nullptr; | |||
LV2_Atom* ticksPerBeat = nullptr; | |||
lv2_atom_object_get(obj, | |||
fURIDs.timeBar, &bar, | |||
fURIDs.timeBarBeat, &barBeat, | |||
fURIDs.timeBeat, &beat, | |||
fURIDs.timeBeatUnit, &beatUnit, | |||
fURIDs.timeBeatsPerBar, &beatsPerBar, | |||
fURIDs.timeBeatsPerMinute, &beatsPerMinute, | |||
fURIDs.timeTicksPerBeat, &ticksPerBeat, | |||
fURIDs.timeFrame, &frame, | |||
fURIDs.timeSpeed, &speed, | |||
fURIDs.timeTicksPerBeat, &ticksPerBeat, | |||
nullptr); | |||
// need to handle this first as other values depend on it | |||
if (ticksPerBeat != nullptr) | |||
{ | |||
/**/ if (ticksPerBeat->type == fURIDs.atomDouble) | |||
fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomFloat) | |||
fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomInt) | |||
fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomLong) | |||
fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; | |||
else | |||
d_stderr("Unknown lv2 ticksPerBeat value type"); | |||
if (fLastPositionData.ticksPerBeat > 0) | |||
fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; | |||
} | |||
// same | |||
if (speed != nullptr) | |||
{ | |||
/**/ if (speed->type == fURIDs.atomDouble) | |||
fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; | |||
else if (speed->type == fURIDs.atomFloat) | |||
fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; | |||
else if (speed->type == fURIDs.atomInt) | |||
fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; | |||
else if (speed->type == fURIDs.atomLong) | |||
fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; | |||
else | |||
d_stderr("Unknown lv2 speed value type"); | |||
fTimePosition.playing = d_isNotZero(fLastPositionData.speed); | |||
} | |||
if (bar != nullptr) | |||
{ | |||
/**/ if (bar->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.bar = ((LV2_Atom_Double*)bar)->body + 1.0; | |||
fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; | |||
else if (bar->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.bar = ((LV2_Atom_Float*)bar)->body + 1.0f; | |||
fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; | |||
else if (bar->type == fURIDs.atomInt) | |||
fTimePosition.bbt.bar = ((LV2_Atom_Int*)bar)->body + 1; | |||
fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; | |||
else if (bar->type == fURIDs.atomLong) | |||
fTimePosition.bbt.bar = ((LV2_Atom_Long*)bar)->body + 1; | |||
fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; | |||
else | |||
d_stderr("Unknown lv2 bar value type"); | |||
} | |||
if (ticksPerBeat != nullptr) | |||
{ | |||
/**/ if (ticksPerBeat->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomInt) | |||
fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; | |||
else if (ticksPerBeat->type == fURIDs.atomLong) | |||
fTimePosition.bbt.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; | |||
else | |||
d_stderr("Unknown lv2 ticksPerBeat value type"); | |||
if (fLastPositionData.bar >= 0) | |||
fTimePosition.bbt.bar = fLastPositionData.bar + 1; | |||
} | |||
if (barBeat != nullptr) | |||
{ | |||
double barBeatValue = 0.0; | |||
/**/ if (barBeat->type == fURIDs.atomDouble) | |||
barBeatValue = ((LV2_Atom_Double*)barBeat)->body; | |||
fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; | |||
else if (barBeat->type == fURIDs.atomFloat) | |||
barBeatValue = ((LV2_Atom_Float*)barBeat)->body; | |||
fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; | |||
else if (barBeat->type == fURIDs.atomInt) | |||
barBeatValue = ((LV2_Atom_Int*)barBeat)->body; | |||
fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; | |||
else if (barBeat->type == fURIDs.atomLong) | |||
barBeatValue = ((LV2_Atom_Long*)barBeat)->body; | |||
fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; | |||
else | |||
d_stderr("Unknown lv2 barBeat value type"); | |||
const double rest = std::fmod(barBeatValue, 1.0); | |||
fTimePosition.bbt.beat = barBeatValue-rest+1.0; | |||
fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; | |||
} | |||
// barBeat includes beat | |||
else if (beat != nullptr) | |||
{ | |||
/**/ if (beat->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.beat = ((LV2_Atom_Double*)beat)->body + 1.0; | |||
else if (beat->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.beat = ((LV2_Atom_Float*)beat)->body + 1.0f; | |||
else if (beat->type == fURIDs.atomInt) | |||
fTimePosition.bbt.beat = ((LV2_Atom_Int*)beat)->body + 1; | |||
else if (beat->type == fURIDs.atomLong) | |||
fTimePosition.bbt.beat = ((LV2_Atom_Long*)beat)->body + 1; | |||
else | |||
d_stderr("Unknown lv2 beat value type"); | |||
if (fLastPositionData.barBeat >= 0.0f) | |||
{ | |||
const double rest = std::fmod(fLastPositionData.barBeat, 1.0); | |||
fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; | |||
fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; | |||
} | |||
} | |||
if (beatUnit != nullptr) | |||
{ | |||
/**/ if (beatUnit->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.beatType = ((LV2_Atom_Double*)beatUnit)->body; | |||
fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; | |||
fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomInt) | |||
fTimePosition.bbt.beatType = ((LV2_Atom_Int*)beatUnit)->body; | |||
fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomLong) | |||
fTimePosition.bbt.beatType = ((LV2_Atom_Long*)beatUnit)->body; | |||
fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; | |||
else | |||
d_stderr("Unknown lv2 beatUnit value type"); | |||
if (fLastPositionData.beatUnit > 0) | |||
fTimePosition.bbt.beatType = fLastPositionData.beatUnit; | |||
} | |||
if (beatsPerBar != nullptr) | |||
{ | |||
/**/ if (beatsPerBar->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; | |||
fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; | |||
fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomInt) | |||
fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; | |||
fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomLong) | |||
fTimePosition.bbt.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; | |||
fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; | |||
else | |||
d_stderr("Unknown lv2 beatsPerBar value type"); | |||
if (fLastPositionData.beatsPerBar > 0.0f) | |||
fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar; | |||
} | |||
if (beatsPerMinute != nullptr) | |||
{ | |||
/**/ if (beatsPerMinute->type == fURIDs.atomDouble) | |||
fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; | |||
fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomFloat) | |||
fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; | |||
fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomInt) | |||
fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; | |||
fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomLong) | |||
fTimePosition.bbt.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; | |||
fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; | |||
else | |||
d_stderr("Unknown lv2 beatsPerMinute value type"); | |||
} | |||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); | |||
if (fLastPositionData.beatsPerMinute > 0.0f) | |||
{ | |||
fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; | |||
if (frame != nullptr && frame->type == fURIDs.atomLong) | |||
fTimePosition.frame = ((LV2_Atom_Long*)frame)->body; | |||
if (d_isNotZero(fLastPositionData.speed)) | |||
fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); | |||
} | |||
} | |||
if (speed != nullptr && speed->type == fURIDs.atomFloat) | |||
if (frame != nullptr) | |||
{ | |||
fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body; | |||
fTimePosition.playing = (fLastTimeSpeed == 1.0); | |||
/**/ if (frame->type == fURIDs.atomDouble) | |||
fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; | |||
else if (frame->type == fURIDs.atomFloat) | |||
fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; | |||
else if (frame->type == fURIDs.atomInt) | |||
fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; | |||
else if (frame->type == fURIDs.atomLong) | |||
fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; | |||
else | |||
d_stderr("Unknown lv2 frame value type"); | |||
if (fLastPositionData.frame >= 0) | |||
fTimePosition.frame = fLastPositionData.frame; | |||
} | |||
fTimePosition.bbt.valid = (beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr); | |||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* | |||
fTimePosition.bbt.beatsPerBar* | |||
(fTimePosition.bbt.bar-1); | |||
fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && | |||
fLastPositionData.beatUnit > 0 && | |||
fLastPositionData.beatsPerBar > 0.0f); | |||
continue; | |||
} | |||
# endif | |||
@@ -477,7 +505,7 @@ public: | |||
fPlugin.setTimePosition(fTimePosition); | |||
# endif | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); | |||
#else | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | |||
@@ -485,37 +513,56 @@ public: | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
// update timePos for next callback | |||
if (fLastTimeSpeed != 0.0) | |||
if (d_isNotZero(fLastPositionData.speed)) | |||
{ | |||
const double newFrames = fLastTimeSpeed*sampleCount; | |||
if (fLastPositionData.speed > 0.0) | |||
{ | |||
// playing forwards | |||
fLastPositionData.frame += sampleCount; | |||
} | |||
else | |||
{ | |||
// playing backwards | |||
fLastPositionData.frame -= sampleCount; | |||
fTimePosition.frame += newFrames; | |||
if (fLastPositionData.frame < 0) | |||
fLastPositionData.frame = 0; | |||
} | |||
fTimePosition.frame = fLastPositionData.frame; | |||
if (fTimePosition.bbt.valid) | |||
{ | |||
const double samplesPerBeat = 60.0 / fTimePosition.bbt.beatsPerMinute * fSampleRate; | |||
const double ticksPerSample = fTimePosition.bbt.ticksPerBeat / samplesPerBeat; | |||
const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; | |||
const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; | |||
const double addedBarBeats = double(sampleCount) / framesPerBeat; | |||
double newTickPos = double(fTimePosition.bbt.tick) + ticksPerSample*newFrames; | |||
double newBeatPos = double(fTimePosition.bbt.beat)-1.0; | |||
double newBarPos = double(fTimePosition.bbt.bar)-1.0; | |||
for (; newTickPos >= fTimePosition.bbt.ticksPerBeat;) | |||
if (fLastPositionData.barBeat >= 0.0f) | |||
{ | |||
++newBeatPos; | |||
newTickPos -= fTimePosition.bbt.ticksPerBeat; | |||
} | |||
fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, | |||
fLastPositionData.beatsPerBar); | |||
for (; newBeatPos >= fTimePosition.bbt.beatsPerBar;) | |||
{ | |||
++newBarPos; | |||
newBeatPos -= fTimePosition.bbt.beatsPerBar; | |||
const double rest = std::fmod(fLastPositionData.barBeat, 1.0); | |||
fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; | |||
fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; | |||
if (fLastPositionData.bar >= 0) | |||
{ | |||
fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ | |||
fLastPositionData.beatsPerBar); | |||
if (fLastPositionData.bar < 0) | |||
fLastPositionData.bar = 0; | |||
fTimePosition.bbt.bar = fLastPositionData.bar + 1; | |||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* | |||
fTimePosition.bbt.beatsPerBar* | |||
(fTimePosition.bbt.bar-1); | |||
} | |||
} | |||
fTimePosition.bbt.bar = newBarPos+1.0; | |||
fTimePosition.bbt.beat = newBeatPos+1.0; | |||
fTimePosition.bbt.tick = newTickPos; | |||
fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*fTimePosition.bbt.beatsPerBar*(fTimePosition.bbt.bar-1); | |||
fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); | |||
} | |||
} | |||
# endif | |||
@@ -529,7 +576,7 @@ public: | |||
uint32_t size, offset = 0; | |||
LV2_Atom_Event* aev; | |||
# if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
// TODO | |||
# endif | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
@@ -538,16 +585,16 @@ public: | |||
if (! fNeededUiSends[i]) | |||
continue; | |||
const d_string& key = fPlugin.getStateKey(i); | |||
const String& key = fPlugin.getStateKey(i); | |||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | |||
{ | |||
const d_string& curKey = cit->first; | |||
const String& curKey = cit->first; | |||
if (curKey != key) | |||
continue; | |||
const d_string& value = cit->second; | |||
const String& value = cit->second; | |||
// set msg size (key + value + separator + 2x null terminator) | |||
const size_t msgSize(key.length()+value.length()+3); | |||
@@ -661,7 +708,7 @@ public: | |||
if (realProgram >= fPlugin.getProgramCount()) | |||
return; | |||
fPlugin.setProgram(realProgram); | |||
fPlugin.loadProgram(realProgram); | |||
// Update control inputs | |||
for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) | |||
@@ -684,10 +731,10 @@ public: | |||
{ | |||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | |||
{ | |||
const d_string& key = cit->first; | |||
const d_string& value = cit->second; | |||
const String& key = cit->first; | |||
const String& value = cit->second; | |||
const d_string urnKey("urn:distrho:" + key); | |||
const String urnKey("urn:distrho:" + key); | |||
// some hosts need +1 for the null terminator, even though the type is string | |||
store(handle, fUridMap->map(fUridMap->handle, urnKey.buffer()), value.buffer(), value.length()+1, fURIDs.atomString, LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE); | |||
@@ -703,8 +750,8 @@ public: | |||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||
{ | |||
const d_string& key(fPlugin.getStateKey(i)); | |||
const d_string urnKey("urn:distrho:" + key); | |||
const String& key(fPlugin.getStateKey(i)); | |||
const String urnKey("urn:distrho:" + key); | |||
size = 0; | |||
type = 0; | |||
@@ -783,12 +830,33 @@ private: | |||
// Temporary data | |||
float* fLastControlValues; | |||
double fSampleRate; | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
TimePosition fTimePosition; | |||
double fLastTimeSpeed; | |||
struct Lv2PositionData { | |||
int64_t bar; | |||
float barBeat; | |||
uint32_t beatUnit; | |||
float beatsPerBar; | |||
float beatsPerMinute; | |||
int64_t frame; | |||
double speed; | |||
int64_t ticksPerBeat; | |||
Lv2PositionData() | |||
: bar(-1), | |||
barBeat(-1.0f), | |||
beatUnit(0), | |||
beatsPerBar(0.0f), | |||
beatsPerMinute(0.0f), | |||
frame(-1), | |||
speed(0.0), | |||
ticksPerBeat(-1) {} | |||
} fLastPositionData; | |||
#endif | |||
// LV2 URIDs | |||
@@ -807,7 +875,6 @@ private: | |||
LV2_URID timePosition; | |||
LV2_URID timeBar; | |||
LV2_URID timeBarBeat; | |||
LV2_URID timeBeat; | |||
LV2_URID timeBeatUnit; | |||
LV2_URID timeBeatsPerBar; | |||
LV2_URID timeBeatsPerMinute; | |||
@@ -829,7 +896,6 @@ private: | |||
timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)), | |||
timeBar(uridMap->map(uridMap->handle, LV2_TIME__bar)), | |||
timeBarBeat(uridMap->map(uridMap->handle, LV2_TIME__barBeat)), | |||
timeBeat(uridMap->map(uridMap->handle, LV2_TIME__beat)), | |||
timeBeatUnit(uridMap->map(uridMap->handle, LV2_TIME__beatUnit)), | |||
timeBeatsPerBar(uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar)), | |||
timeBeatsPerMinute(uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute)), | |||
@@ -858,9 +924,9 @@ private: | |||
// check if key already exists | |||
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||
{ | |||
const d_string& d_key(it->first); | |||
const String& dkey(it->first); | |||
if (d_key == key) | |||
if (dkey == key) | |||
{ | |||
it->second = newValue; | |||
return; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -23,6 +23,7 @@ | |||
#include "lv2/midi.h" | |||
#include "lv2/options.h" | |||
#include "lv2/port-props.h" | |||
#include "lv2/presets.h" | |||
#include "lv2/resize-port.h" | |||
#include "lv2/state.h" | |||
#include "lv2/time.h" | |||
@@ -49,8 +50,20 @@ | |||
# define DISTRHO_PLUGIN_HAS_UI 0 | |||
#endif | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_HAS_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_HAS_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# if DISTRHO_OS_HAIKU | |||
# define DISTRHO_LV2_UI_TYPE "BeUI" | |||
# elif DISTRHO_OS_MAC | |||
# define DISTRHO_LV2_UI_TYPE "CocoaUI" | |||
# elif DISTRHO_OS_WINDOWS | |||
# define DISTRHO_LV2_UI_TYPE "WindowsUI" | |||
# else | |||
# define DISTRHO_LV2_UI_TYPE "X11UI" | |||
# endif | |||
#endif | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
// ----------------------------------------------------------------------- | |||
@@ -66,8 +79,17 @@ void lv2_generate_ttl(const char* const basename) | |||
d_lastBufferSize = 0; | |||
d_lastSampleRate = 0.0; | |||
d_string pluginDLL(basename); | |||
d_string pluginTTL(pluginDLL + ".ttl"); | |||
String pluginDLL(basename); | |||
String pluginTTL(pluginDLL + ".ttl"); | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
String pluginUI(pluginDLL); | |||
# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
pluginUI.truncate(pluginDLL.rfind("_dsp")); | |||
pluginUI += "_ui"; | |||
const String uiTTL(pluginUI + ".ttl"); | |||
# endif | |||
#endif | |||
// --------------------------------------------- | |||
@@ -75,9 +97,12 @@ void lv2_generate_ttl(const char* const basename) | |||
std::cout << "Writing manifest.ttl..."; std::cout.flush(); | |||
std::fstream manifestFile("manifest.ttl", std::ios::out); | |||
d_string manifestString; | |||
String manifestString; | |||
manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
manifestString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
manifestString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||
#endif | |||
@@ -91,42 +116,49 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
manifestString += "<" DISTRHO_UI_URI ">\n"; | |||
# if DISTRHO_OS_HAIKU | |||
manifestString += " a ui:BeUI ;\n"; | |||
# elif DISTRHO_OS_MAC | |||
manifestString += " a ui:CocoaUI ;\n"; | |||
# elif DISTRHO_OS_WINDOWS | |||
manifestString += " a ui:WindowsUI ;\n"; | |||
# else | |||
manifestString += " a ui:X11UI ;\n"; | |||
# endif | |||
# if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
d_string pluginUI(pluginDLL); | |||
pluginUI.truncate(pluginDLL.rfind("_dsp")); | |||
pluginUI += "_ui"; | |||
manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n"; | |||
manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n"; | |||
# else | |||
manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n"; | |||
#endif | |||
# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
manifestString += "\n"; | |||
manifestString += " lv2:extensionData ui:idleInterface ,\n"; | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
manifestString += " ui:showInterface ,\n"; | |||
manifestString += " <" LV2_PROGRAMS__Interface "> ;\n"; | |||
# else | |||
# else | |||
manifestString += " ui:showInterface ;\n"; | |||
# endif | |||
# endif | |||
manifestString += "\n"; | |||
manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | |||
manifestString += " ui:resize ,\n"; | |||
manifestString += " ui:touch ;\n"; | |||
# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
manifestString += "\n"; | |||
manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n"; | |||
manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n"; | |||
manifestString += " <" LV2_OPTIONS__options "> ,\n"; | |||
manifestString += " <" LV2_URID__map "> .\n"; | |||
# else | |||
manifestString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n"; | |||
manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n"; | |||
# endif | |||
manifestString += " <" LV2_URID__map "> .\n"; | |||
manifestString += "\n"; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); | |||
char strBuf[0xff+1]; | |||
strBuf[0xff] = '\0'; | |||
// Presets | |||
for (uint32_t i = 0; i < plugin.getProgramCount(); ++i) | |||
{ | |||
std::snprintf(strBuf, 0xff, "%03i", i+1); | |||
manifestString += "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; | |||
manifestString += " a pset:Preset ;\n"; | |||
manifestString += " lv2:appliesTo <" DISTRHO_PLUGIN_URI "> ;\n"; | |||
manifestString += " rdfs:seeAlso <presets.ttl> .\n"; | |||
manifestString += "\n"; | |||
} | |||
#endif | |||
manifestFile << manifestString << std::endl; | |||
@@ -140,7 +172,7 @@ void lv2_generate_ttl(const char* const basename) | |||
std::cout << "Writing " << pluginTTL << "..."; std::cout.flush(); | |||
std::fstream pluginFile(pluginTTL, std::ios::out); | |||
d_string pluginString; | |||
String pluginString; | |||
// header | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
@@ -158,7 +190,9 @@ void lv2_generate_ttl(const char* const basename) | |||
// plugin | |||
pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
#ifdef DISTRHO_PLUGIN_LV2_CATEGORY | |||
pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin ;\n"; | |||
#elif DISTRHO_PLUGIN_IS_SYNTH | |||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n"; | |||
#else | |||
pluginString += " a lv2:Plugin ;\n"; | |||
@@ -205,18 +239,27 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | |||
{ | |||
const AudioPort& port(plugin.getAudioPort(true, i)); | |||
if (i == 0) | |||
pluginString += " lv2:port [\n"; | |||
else | |||
pluginString += " [\n"; | |||
pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:symbol \"lv2_audio_in_" + d_string(i+1) + "\" ;\n"; | |||
pluginString += " lv2:name \"Audio Input " + d_string(i+1) + "\" ;\n"; | |||
if (port.hints & kAudioPortIsCV) | |||
pluginString += " a lv2:InputPort, lv2:CVPort ;\n"; | |||
else | |||
pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:symbol \"" + port.symbol + "\" ;\n"; | |||
pluginString += " lv2:name \"" + port.name + "\" ;\n"; | |||
if (port.hints & kAudioPortIsSidechain) | |||
pluginString += " lv2:portProperty lv2:isSideChain;\n"; | |||
if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) | |||
pluginString += " ] ;\n\n"; | |||
pluginString += " ] ;\n"; | |||
else | |||
pluginString += " ] ,\n"; | |||
} | |||
@@ -226,18 +269,27 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | |||
{ | |||
const AudioPort& port(plugin.getAudioPort(false, i)); | |||
if (i == 0) | |||
pluginString += " lv2:port [\n"; | |||
else | |||
pluginString += " [\n"; | |||
pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:symbol \"lv2_audio_out_" + d_string(i+1) + "\" ;\n"; | |||
pluginString += " lv2:name \"Audio Output " + d_string(i+1) + "\" ;\n"; | |||
if (port.hints & kAudioPortIsCV) | |||
pluginString += " a lv2:OutputPort, lv2:CVPort ;\n"; | |||
else | |||
pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:symbol \"" + port.symbol + "\" ;\n"; | |||
pluginString += " lv2:name \"" + port.name + "\" ;\n"; | |||
if (port.hints & kAudioPortIsSidechain) | |||
pluginString += " lv2:portProperty lv2:isSideChain;\n"; | |||
if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) | |||
pluginString += " ] ;\n\n"; | |||
pluginString += " ] ;\n"; | |||
else | |||
pluginString += " ] ,\n"; | |||
} | |||
@@ -247,15 +299,15 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
pluginString += " lv2:port [\n"; | |||
pluginString += " a lv2:InputPort, atom:AtomPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Events Input\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_events_in\" ;\n"; | |||
pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
@@ -268,15 +320,15 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_LV2_USE_EVENTS_OUT | |||
pluginString += " lv2:port [\n"; | |||
pluginString += " a lv2:OutputPort, atom:AtomPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Events Output\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_events_out\" ;\n"; | |||
pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
# endif | |||
pluginString += " ] ;\n\n"; | |||
@@ -286,7 +338,7 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
pluginString += " lv2:port [\n"; | |||
pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Latency\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_latency\" ;\n"; | |||
pluginString += " lv2:designation lv2:latency ;\n"; | |||
@@ -307,15 +359,15 @@ void lv2_generate_ttl(const char* const basename) | |||
else | |||
pluginString += " a lv2:InputPort, lv2:ControlPort ;\n"; | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:index " + String(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; | |||
// symbol | |||
{ | |||
d_string symbol(plugin.getParameterSymbol(i)); | |||
String symbol(plugin.getParameterSymbol(i)); | |||
if (symbol.isEmpty()) | |||
symbol = "lv2_port_" + d_string(portIndex-1); | |||
symbol = "lv2_port_" + String(portIndex-1); | |||
pluginString += " lv2:symbol \"" + symbol + "\" ;\n"; | |||
} | |||
@@ -326,21 +378,21 @@ void lv2_generate_ttl(const char* const basename) | |||
if (plugin.getParameterHints(i) & kParameterIsInteger) | |||
{ | |||
pluginString += " lv2:default " + d_string(int(plugin.getParameterValue(i))) + " ;\n"; | |||
pluginString += " lv2:minimum " + d_string(int(ranges.min)) + " ;\n"; | |||
pluginString += " lv2:maximum " + d_string(int(ranges.max)) + " ;\n"; | |||
pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; | |||
pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; | |||
pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; | |||
} | |||
else | |||
{ | |||
pluginString += " lv2:default " + d_string(plugin.getParameterValue(i)) + " ;\n"; | |||
pluginString += " lv2:minimum " + d_string(ranges.min) + " ;\n"; | |||
pluginString += " lv2:maximum " + d_string(ranges.max) + " ;\n"; | |||
pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; | |||
pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; | |||
pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; | |||
} | |||
} | |||
// unit | |||
{ | |||
const d_string& unit(plugin.getParameterUnit(i)); | |||
const String& unit(plugin.getParameterUnit(i)); | |||
if (! unit.isEmpty()) | |||
{ | |||
@@ -400,11 +452,140 @@ void lv2_generate_ttl(const char* const basename) | |||
} | |||
} | |||
pluginString += " doap:name \"" + d_string(plugin.getName()) + "\" ;\n"; | |||
pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.getMaker()) + "\" ] .\n"; | |||
pluginString += " doap:name \"" + String(plugin.getName()) + "\" ;\n"; | |||
pluginString += " doap:maintainer [ foaf:name \"" + String(plugin.getMaker()) + "\" ] .\n"; | |||
pluginFile << pluginString << std::endl; | |||
pluginFile.close(); | |||
std::cout << " done!" << std::endl; | |||
} | |||
// --------------------------------------------- | |||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
{ | |||
std::cout << "Writing " << uiTTL << "..."; std::cout.flush(); | |||
std::fstream uiFile(uiTTL, std::ios::out); | |||
String uiString; | |||
uiString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
uiString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||
uiString += "\n"; | |||
uiString += "<" DISTRHO_UI_URI ">\n"; | |||
uiString += " lv2:extensionData ui:idleInterface ,\n"; | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
uiString += " ui:showInterface ,\n"; | |||
uiString += " <" LV2_PROGRAMS__Interface "> ;\n"; | |||
# else | |||
uiString += " ui:showInterface ;\n"; | |||
# endif | |||
uiString += "\n"; | |||
uiString += " lv2:optionalFeature ui:noUserResize ,\n"; | |||
uiString += " ui:resize ,\n"; | |||
uiString += " ui:touch ;\n"; | |||
uiString += "\n"; | |||
uiString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n"; | |||
uiString += " <" LV2_URID__map "> .\n"; | |||
uiFile << uiString << std::endl; | |||
uiFile.close(); | |||
std::cout << " done!" << std::endl; | |||
} | |||
#endif | |||
// --------------------------------------------- | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
{ | |||
std::cout << "Writing presets.ttl..."; std::cout.flush(); | |||
std::fstream presetsFile("presets.ttl", std::ios::out); | |||
String presetsString; | |||
presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; | |||
presetsString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n"; | |||
# endif | |||
presetsString += "\n"; | |||
const uint32_t numParameters = plugin.getParameterCount(); | |||
const uint32_t numPrograms = plugin.getProgramCount(); | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
const uint32_t numStates = plugin.getStateCount(); | |||
# endif | |||
const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); | |||
char strBuf[0xff+1]; | |||
strBuf[0xff] = '\0'; | |||
String presetString; | |||
for (uint32_t i=0; i<numPrograms; ++i) | |||
{ | |||
std::snprintf(strBuf, 0xff, "%03i", i+1); | |||
plugin.loadProgram(i); | |||
presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; | |||
presetString += " rdfs:label \"" + plugin.getProgramName(i) + "\" ;\n\n"; | |||
// TODO | |||
# if 0 // DISTRHO_PLUGIN_WANT_STATE | |||
for (uint32_t j=0; j<numStates; ++j) | |||
{ | |||
if (j == 0) | |||
presetString += " state:state [\n"; | |||
else | |||
presetString += " [\n"; | |||
presetString += " <urn:distrho:" + plugin.getStateKey(j) + ">\n"; | |||
presetString += "\"\"\"\n"; | |||
presetString += plugin.getState(j); | |||
presetString += "\"\"\"\n"; | |||
if (j+1 == numStates) | |||
{ | |||
if (numParameters > 0) | |||
presetString += " ] ;\n\n"; | |||
else | |||
presetString += " ] .\n\n"; | |||
} | |||
else | |||
{ | |||
presetString += " ] ,\n"; | |||
} | |||
} | |||
# endif | |||
for (uint32_t j=0; j <numParameters; ++j) | |||
{ | |||
if (j == 0) | |||
presetString += " lv2:port [\n"; | |||
else | |||
presetString += " [\n"; | |||
presetString += " lv2:symbol \"" + plugin.getParameterSymbol(j) + "\" ;\n"; | |||
if (plugin.getParameterHints(j) & kParameterIsInteger) | |||
presetString += " pset:value " + String(int(plugin.getParameterValue(j))) + " ;\n"; | |||
else | |||
presetString += " pset:value " + String(plugin.getParameterValue(j)) + " ;\n"; | |||
if (j+1 == numParameters) | |||
presetString += " ] .\n\n"; | |||
else | |||
presetString += " ] ,\n"; | |||
} | |||
presetsString += presetString; | |||
} | |||
presetsFile << presetsString << std::endl; | |||
presetsFile.close(); | |||
std::cout << " done!" << std::endl; | |||
} | |||
#endif | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -64,7 +64,7 @@ struct ERect { | |||
START_NAMESPACE_DISTRHO | |||
typedef std::map<const d_string,d_string> StringMap; | |||
typedef std::map<const String, String> StringMap; | |||
// ----------------------------------------------------------------------- | |||
@@ -107,9 +107,9 @@ public: | |||
bool* parameterChecks; | |||
float* parameterValues; | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0; | |||
#endif | |||
# endif | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -160,24 +160,28 @@ public: | |||
// ------------------------------------------------------------------- | |||
// functions called from the plugin side, may block | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
void setStateFromPlugin(const char* const key, const char* const value) | |||
{ | |||
fUI.stateChanged(key, value); | |||
} | |||
#endif | |||
# endif | |||
// ------------------------------------------------------------------- | |||
protected: | |||
intptr_t hostCallback(const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) | |||
intptr_t hostCallback(const int32_t opcode, | |||
const int32_t index = 0, | |||
const intptr_t value = 0, | |||
void* const ptr = nullptr, | |||
const float opt = 0.0f) | |||
{ | |||
return fAudioMaster(fEffect, opcode, index, value, ptr, opt); | |||
} | |||
void editParameter(const uint32_t index, const bool started) | |||
{ | |||
hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index, 0, nullptr, 0.0f); | |||
hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); | |||
} | |||
void setParameterValue(const uint32_t index, const float realValue) | |||
@@ -191,31 +195,31 @@ protected: | |||
void setState(const char* const key, const char* const value) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
fUiHelper->setStateFromUI(key, value); | |||
#else | |||
# else | |||
return; // unused | |||
(void)key; | |||
(void)value; | |||
#endif | |||
# endif | |||
} | |||
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||
{ | |||
#if 0 //DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if 0 //DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
// TODO | |||
#else | |||
# else | |||
return; // unused | |||
(void)channel; | |||
(void)note; | |||
(void)velocity; | |||
#endif | |||
# endif | |||
} | |||
void setSize(const uint width, const uint height) | |||
{ | |||
fUI.setWindowSize(width, height); | |||
hostCallback(audioMasterSizeWindow, width, height, nullptr, 0.0f); | |||
hostCallback(audioMasterSizeWindow, width, height); | |||
} | |||
private: | |||
@@ -278,7 +282,7 @@ public: | |||
std::memset(fProgramName, 0, sizeof(char)*(32+1)); | |||
std::strcpy(fProgramName, "Default"); | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
fMidiEventCount = 0; | |||
#endif | |||
@@ -315,8 +319,8 @@ public: | |||
for (uint32_t i=0, count=fPlugin.getStateCount(); i<count; ++i) | |||
{ | |||
const d_string& d_key(fPlugin.getStateKey(i)); | |||
fStateMap[d_key] = fPlugin.getStateDefaultValue(i); | |||
const String& dkey(fPlugin.getStateKey(i)); | |||
fStateMap[dkey] = fPlugin.getStateDefaultValue(i); | |||
} | |||
#endif | |||
} | |||
@@ -389,10 +393,27 @@ public: | |||
case effMainsChanged: | |||
if (value != 0) | |||
{ | |||
fPlugin.activate(); | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
fMidiEventCount = 0; | |||
// tell host we want MIDI events | |||
hostCallback(audioMasterWantMidi); | |||
#endif | |||
// deactivate for possible changes | |||
fPlugin.deactivateIfNeeded(); | |||
// check if something changed | |||
const uint32_t bufferSize = static_cast<uint32_t>(hostCallback(audioMasterGetBlockSize)); | |||
const double sampleRate = static_cast<double>(hostCallback(audioMasterGetSampleRate)); | |||
if (bufferSize != 0) | |||
fPlugin.setBufferSize(bufferSize, true); | |||
if (sampleRate != 0.0) | |||
fPlugin.setSampleRate(sampleRate, true); | |||
fPlugin.activate(); | |||
} | |||
else | |||
{ | |||
@@ -436,8 +457,8 @@ public: | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | |||
{ | |||
const d_string& key = cit->first; | |||
const d_string& value = cit->second; | |||
const String& key = cit->first; | |||
const String& value = cit->second; | |||
fVstUI->setStateFromPlugin(key, value); | |||
} | |||
@@ -485,15 +506,15 @@ public: | |||
} | |||
else | |||
{ | |||
d_string chunkStr; | |||
String chunkStr; | |||
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) | |||
{ | |||
const d_string& key = cit->first; | |||
const d_string& value = cit->second; | |||
const String& key = cit->first; | |||
const String& value = cit->second; | |||
// join key and value | |||
d_string tmpStr; | |||
String tmpStr; | |||
tmpStr = key; | |||
tmpStr += "\xff"; | |||
tmpStr += value; | |||
@@ -537,8 +558,10 @@ public: | |||
setStateFromUI(key, value); | |||
# if DISTRHO_PLUGIN_HAS_UI | |||
if (fVstUI != nullptr) | |||
fVstUI->setStateFromPlugin(key, value); | |||
# endif | |||
// get next key | |||
key = value+(std::strlen(value)+1); | |||
@@ -548,8 +571,14 @@ public: | |||
} | |||
#endif // DISTRHO_PLUGIN_WANT_STATE | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
case effProcessEvents: | |||
if (! fPlugin.isActive()) | |||
{ | |||
// host has not activated the plugin yet, nasty! | |||
vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); | |||
} | |||
if (const VstEvents* const events = (const VstEvents*)ptr) | |||
{ | |||
if (events->numEvents == 0) | |||
@@ -586,7 +615,7 @@ public: | |||
} | |||
break; | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT || DISTRHO_PLUGIN_HAS_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_OS_MAC | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_OS_MAC | |||
case effCanDo: | |||
if (const char* const canDo = (const char*)ptr) | |||
{ | |||
@@ -597,13 +626,13 @@ public: | |||
return 0xbeef0000; | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
if (std::strcmp(canDo, "receiveVstEvents") == 0) | |||
return 1; | |||
if (std::strcmp(canDo, "receiveVstMidiEvent") == 0) | |||
return 1; | |||
# endif | |||
# if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT | |||
# if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
if (std::strcmp(canDo, "sendVstEvents") == 0) | |||
return 1; | |||
if (std::strcmp(canDo, "sendVstMidiEvent") == 0) | |||
@@ -646,10 +675,19 @@ public: | |||
void vst_processReplacing(const float** const inputs, float** const outputs, const int32_t sampleFrames) | |||
{ | |||
if (sampleFrames <= 0) | |||
return; | |||
if (! fPlugin.isActive()) | |||
{ | |||
// host has not activated the plugin yet, nasty! | |||
vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid); | |||
if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)fAudioMaster(fEffect, audioMasterGetTime, 0, kWantVstTimeFlags, nullptr, 0.0f)) | |||
if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(audioMasterGetTime, 0, kWantVstTimeFlags)) | |||
{ | |||
fTimePosition.frame = vstTimeInfo->samplePos; | |||
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | |||
@@ -690,7 +728,7 @@ public: | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
fPlugin.run(inputs, outputs, sampleFrames, fMidiEvents, fMidiEventCount); | |||
fMidiEventCount = 0; | |||
#else | |||
@@ -724,7 +762,7 @@ private: | |||
// Temporary data | |||
char fProgramName[32+1]; | |||
#if DISTRHO_PLUGIN_HAS_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
uint32_t fMidiEventCount; | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
@@ -747,6 +785,18 @@ private: | |||
StringMap fStateMap; | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// host callback | |||
intptr_t hostCallback(const int32_t opcode, | |||
const int32_t index = 0, | |||
const intptr_t value = 0, | |||
void* const ptr = nullptr, | |||
const float opt = 0.0f) | |||
{ | |||
return fAudioMaster(fEffect, opcode, index, value, ptr, opt); | |||
} | |||
// ------------------------------------------------------------------- | |||
// functions called from the plugin side, RT no block | |||
@@ -762,7 +812,11 @@ private: | |||
// ------------------------------------------------------------------- | |||
// functions called from the UI side, may block | |||
# if DISTRHO_PLUGIN_HAS_UI | |||
void setStateFromUI(const char* const key, const char* const newValue) override | |||
# else | |||
void setStateFromUI(const char* const key, const char* const newValue) | |||
# endif | |||
{ | |||
fPlugin.setState(key, newValue); | |||
@@ -773,9 +827,9 @@ private: | |||
// check if key already exists | |||
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) | |||
{ | |||
const d_string& d_key(it->first); | |||
const String& dkey(it->first); | |||
if (d_key == key) | |||
if (dkey == key) | |||
{ | |||
it->second = newValue; | |||
return; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -15,6 +15,7 @@ | |||
*/ | |||
#include "DistrhoUIInternal.hpp" | |||
#include "src/WidgetPrivateData.hpp" | |||
START_NAMESPACE_DISTRHO | |||
@@ -28,11 +29,14 @@ Window* d_lastUiWindow = nullptr; | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* UI */ | |||
UI::UI() | |||
UI::UI(uint width, uint height) | |||
: UIWidget(*d_lastUiWindow), | |||
pData(new PrivateData()) | |||
{ | |||
UIWidget::setNeedsFullViewport(true); | |||
((UIWidget*)this)->pData->needsFullViewport = false; | |||
if (width > 0 && height > 0) | |||
setSize(width, height); | |||
} | |||
UI::~UI() | |||
@@ -43,30 +47,30 @@ UI::~UI() | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Host state */ | |||
double UI::d_getSampleRate() const noexcept | |||
double UI::getSampleRate() const noexcept | |||
{ | |||
return pData->sampleRate; | |||
} | |||
void UI::d_editParameter(const uint32_t index, const bool started) | |||
void UI::editParameter(uint32_t index, bool started) | |||
{ | |||
pData->editParamCallback(index + pData->parameterOffset, started); | |||
} | |||
void UI::d_setParameterValue(const uint32_t index, const float value) | |||
void UI::setParameterValue(uint32_t index, float value) | |||
{ | |||
pData->setParamCallback(index + pData->parameterOffset, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
void UI::d_setState(const char* const key, const char* const value) | |||
void UI::setState(const char* key, const char* value) | |||
{ | |||
pData->setStateCallback(key, value); | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void UI::d_sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||
void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
pData->sendNoteCallback(channel, note, velocity); | |||
} | |||
@@ -76,7 +80,7 @@ void UI::d_sendNote(const uint8_t channel, const uint8_t note, const uint8_t vel | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Direct DSP access */ | |||
void* UI::d_getPluginInstancePointer() const noexcept | |||
void* UI::getPluginInstancePointer() const noexcept | |||
{ | |||
return pData->dspPtr; | |||
} | |||
@@ -85,16 +89,16 @@ void* UI::d_getPluginInstancePointer() const noexcept | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* DSP/Plugin Callbacks (optional) */ | |||
void UI::d_sampleRateChanged(double) {} | |||
void UI::sampleRateChanged(double) {} | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* UI Callbacks (optional) */ | |||
void UI::d_uiFileBrowserSelected(const char*) | |||
void UI::uiFileBrowserSelected(const char*) | |||
{ | |||
} | |||
void UI::d_uiReshape(uint width, uint height) | |||
void UI::uiReshape(uint width, uint height) | |||
{ | |||
glEnable(GL_BLEND); | |||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -20,7 +20,7 @@ | |||
# error DSSI UIs do not support direct access! | |||
#endif | |||
#include "../extra/d_sleep.hpp" | |||
#include "../extra/Sleep.hpp" | |||
#include <lo/lo.h> | |||
@@ -136,7 +136,7 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void dssiui_program(ulong bank, ulong program) | |||
{ | |||
fUI.programChanged(bank * 128 + program); | |||
fUI.programLoaded(bank * 128 + program); | |||
} | |||
#endif | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -18,10 +18,10 @@ | |||
#define DISTRHO_UI_INTERNAL_HPP_INCLUDED | |||
#include "../DistrhoUI.hpp" | |||
#include "../../dgl/App.hpp" | |||
#include "../../dgl/Application.hpp" | |||
#include "../../dgl/Window.hpp" | |||
using DGL::App; | |||
using DGL::Application; | |||
using DGL::IdleCallback; | |||
using DGL::Window; | |||
@@ -142,7 +142,7 @@ UI* createUiWrapper(void* const dspPtr, Window* const window) | |||
class UIExporterWindow : public Window | |||
{ | |||
public: | |||
UIExporterWindow(App& app, const intptr_t winId, void* const dspPtr) | |||
UIExporterWindow(Application& app, const intptr_t winId, void* const dspPtr) | |||
: Window(app, winId), | |||
fUI(createUiWrapper(dspPtr, this)), | |||
fIsReady(false) | |||
@@ -175,7 +175,7 @@ protected: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
fUI->d_uiReshape(width, height); | |||
fUI->uiReshape(width, height); | |||
fIsReady = true; | |||
} | |||
@@ -184,7 +184,7 @@ protected: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
fUI->d_uiFileBrowserSelected(filename); | |||
fUI->uiFileBrowserSelected(filename); | |||
} | |||
private: | |||
@@ -257,15 +257,15 @@ public: | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
fUI->d_parameterChanged(index, value); | |||
fUI->parameterChanged(index, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void programChanged(const uint32_t index) | |||
void programLoaded(const uint32_t index) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
fUI->d_programChanged(index); | |||
fUI->programLoaded(index); | |||
} | |||
#endif | |||
@@ -276,7 +276,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | |||
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,); | |||
fUI->d_stateChanged(key, value); | |||
fUI->stateChanged(key, value); | |||
} | |||
#endif | |||
@@ -295,7 +295,7 @@ public: | |||
void exec_idle() | |||
{ | |||
if (glWindow.isReady()) | |||
fUI->d_uiIdle(); | |||
fUI->uiIdle(); | |||
} | |||
bool idle() | |||
@@ -305,7 +305,7 @@ public: | |||
glApp.idle(); | |||
if (glWindow.isReady()) | |||
fUI->d_uiIdle(); | |||
fUI->uiIdle(); | |||
return ! glApp.isQuiting(); | |||
} | |||
@@ -364,14 +364,14 @@ public: | |||
fData->sampleRate = sampleRate; | |||
if (doCallback) | |||
fUI->d_sampleRateChanged(sampleRate); | |||
fUI->sampleRateChanged(sampleRate); | |||
} | |||
private: | |||
// ------------------------------------------------------------------- | |||
// DGL Application and Window for this widget | |||
App glApp; | |||
Application glApp; | |||
UIExporterWindow glWindow; | |||
// prevent recursion | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2015 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 | |||
@@ -16,7 +16,7 @@ | |||
#include "DistrhoUIInternal.hpp" | |||
#include "../extra/d_string.hpp" | |||
#include "../extra/String.hpp" | |||
#include "lv2/atom.h" | |||
#include "lv2/atom-util.h" | |||
@@ -195,7 +195,7 @@ public: | |||
{ | |||
const uint32_t realProgram(bank * 128 + program); | |||
fUI.programChanged(realProgram); | |||
fUI.programLoaded(realProgram); | |||
} | |||
#endif | |||
@@ -222,7 +222,7 @@ protected: | |||
const uint32_t eventInPortIndex(DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS); | |||
// join key and value | |||
d_string tmpStr; | |||
String tmpStr; | |||
tmpStr += key; | |||
tmpStr += "\xff"; | |||
tmpStr += value; | |||
@@ -0,0 +1 @@ | |||
../../../includes/dssi/ |
@@ -0,0 +1 @@ | |||
../../../includes/ladspa/ |
@@ -0,0 +1 @@ | |||
../../../includes/lv2/ |
@@ -0,0 +1 @@ | |||
../../../includes/vestige/ |