diff options
author | falkTX <falktx@gmail.com> | 2015-02-16 15:35:53 +0000 |
---|---|---|
committer | falkTX <falktx@gmail.com> | 2015-02-16 15:35:53 +0000 |
commit | ddfcc4af8f2bbb6e2546894d3ded991122461a8c (patch) | |
tree | 9babf74313503cad5a92eca8cedaa016a091bef8 | |
parent | 9baf523196128b5c847a578d93b4e71cabdacaa6 (diff) |
Update dgl libs
Remove NTK specific code, now a separate project
Start of file-browser code
Cross-platform fixes (win & osx should be working nicely now)
Misc cleanup, fixes and documentation
31 files changed, 1216 insertions, 1405 deletions
diff --git a/libs/dgl/App.hpp b/libs/dgl/App.hpp index b6fce01..4babf1f 100644 --- a/libs/dgl/App.hpp +++ b/libs/dgl/App.hpp @@ -21,6 +21,9 @@ START_NAMESPACE_DGL +// ----------------------------------------------------------------------- +// Forward class names + class Window; // ----------------------------------------------------------------------- @@ -50,7 +53,7 @@ public: /** Idle function. - This calls all this app Windows' idle functions and idle callbacks. + This runs the application event-loop once. */ void idle(); @@ -69,7 +72,7 @@ public: /** Check if the application is about to quit. - Returning true means there's no event-loop running at the moment. + Returning true means there's no event-loop running at the moment (or it's just about to stop). */ bool isQuiting() const noexcept; diff --git a/libs/dgl/Base.hpp b/libs/dgl/Base.hpp index 0d62d72..edefbcf 100644 --- a/libs/dgl/Base.hpp +++ b/libs/dgl/Base.hpp @@ -127,6 +127,16 @@ enum Char { }; /** + 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 */ +}; + +/** Special (non-Unicode) keyboard keys. */ enum Key { @@ -157,16 +167,6 @@ enum Key { KEY_SUPER }; -/** - 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 */ -}; - // ----------------------------------------------------------------------- // Base DGL classes diff --git a/libs/dgl/CairoWidget.hpp b/libs/dgl/CairoWidget.hpp deleted file mode 100644 index 9ebfe8f..0000000 --- a/libs/dgl/CairoWidget.hpp +++ /dev/null @@ -1,208 +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. - */ - -#ifndef DGL_CAIRO_WIDGET_HPP_INCLUDED -#define DGL_CAIRO_WIDGET_HPP_INCLUDED - -#include "Widget.hpp" - -#include <cairo.h> - -#include <cstdio> - -START_NAMESPACE_DGL - -// ----------------------------------------------------------------------- - -class CairoWidget : public Widget -{ -public: - CairoWidget(Window& parent) - : Widget(parent), - fContext(nullptr), - fSurface(nullptr), - fTextureId(0) - { - } - - virtual void setWidth(int width) override - { - if (fArea.getWidth() == width) - return; - - Widget::setWidth(width); - _recreateSurface(); - } - - virtual void setHeight(int height) override - { - if (fArea.getHeight() == height) - return; - - Widget::setHeight(height); - _recreateSurface(); - } - - virtual void setSize(const Size<int>& size) override - { - if (fArea.getSize() == size) - return; - - Widget::setSize(size); - _recreateSurface(); - } - - void setSize(int width, int height) - { - setSize(Size<int>(width, height)); - } - -protected: - virtual void cairoDisplay(cairo_t* const context) = 0; - -private: - void onDisplay() override - { - // wait for sizing - if (fSurface == nullptr || fContext == nullptr) - { - printf("invalid surface\n"); - return; - } - - if (fTextureId == 0) - glGenTextures(1, &fTextureId); - if (fTextureId == 0) - { - // TODO: invalidate widget - printf("invalid texture\n"); - return; - } - -#if 1 - const int x = getX(); - const int y = getY(); - const int width = getWidth(); - const int height = getHeight(); - - // draw cairo stuff - cairoDisplay(fContext); - - // get cairo surface data (RGB24) - uchar* const surfaceData = cairo_image_surface_get_data(fSurface); - - // enable GL texture - glEnable(GL_TEXTURE_RECTANGLE_ARB); - - // set texture params - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - // bind texture to surface data - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fTextureId); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceData); - - // draw the texture - -// glBegin(GL_QUADS); -// glTexCoord2f(0.0f, 0.0f); -// glVertex2i(x, y); -// -// glTexCoord2f(1.0f, 0.0f); -// glVertex2i(x+width, y); -// -// glTexCoord2f(1.0f, 1.0f); -// glVertex2i(x+width, y+height); -// -// glTexCoord2f(0.0f, 1.0f); -// glVertex2i(x, y+height); -// glEnd(); - - glBegin(GL_QUADS); - //glTexCoord2i(x, y); - glTexCoord2i(0, 0); - glVertex2i(x, y); - - //glTexCoord2i(x+width, y); - glTexCoord2i(width, 0); - glVertex2i(x+width, y); - - //glTexCoord2i(x+width, y+height); - glTexCoord2i(width, height); - glVertex2i(x+width, y+height); - - //glTexCoord2i(x, y+height); - glTexCoord2i(0, height); - glVertex2i(x, y+height); - glEnd(); - - // cleanup - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - glDisable(GL_TEXTURE_RECTANGLE_ARB); -#endif - } - - void onClose() override - { - if (fContext != nullptr) - { - cairo_destroy(fContext); - fContext = nullptr; - } - - if (fSurface != nullptr) - { - cairo_surface_destroy(fSurface); - fSurface = nullptr; - } - - if (fTextureId != 0) - { - glDeleteTextures(1, &fTextureId); - fTextureId = 0; - } - } - - void _recreateSurface() - { - if (fContext != nullptr) - cairo_destroy(fContext); - - if (fSurface != nullptr) - cairo_surface_destroy(fSurface); - - fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, fArea.getWidth(), fArea.getHeight()); - - if (fSurface != nullptr) - fContext = cairo_create(fSurface); - else - fContext = nullptr; - } - -private: - cairo_t* fContext; - cairo_surface_t* fSurface; - GLuint fTextureId; - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CairoWidget) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#endif // DGL_CAIRO_WIDGET_HPP_INCLUDED diff --git a/libs/dgl/Color.hpp b/libs/dgl/Color.hpp index dbe2cd1..d47f354 100644 --- a/libs/dgl/Color.hpp +++ b/libs/dgl/Color.hpp @@ -28,7 +28,7 @@ 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. + A color made from red, green, blue and alpha floating-point values in [0..1] range. */ struct Color { /** @@ -48,13 +48,13 @@ struct Color { Create a color from red, green, blue and alpha numeric values. Values must be in [0..255] range. */ - Color(const int red, const int green, const int blue, const int alpha = 255) noexcept; + Color(int red, int green, int blue, int alpha = 255) noexcept; /** Create a color from red, green, blue and alpha floating-point values. Values must in [0..1] range. */ - Color(const float red, const float green, const float blue, const float alpha = 1.0f) noexcept; + Color(float red, float green, float blue, float alpha = 1.0f) noexcept; /** Create a color by copying another color. @@ -65,26 +65,39 @@ struct Color { /** Create a color by linearly interpolating two other colors. */ - Color(const Color& color1, const Color& color2, const float u) noexcept; + Color(const Color& color1, const Color& color2, float u) noexcept; /** - Create a color specified by hue, saturation, lightness and alpha. - HSL values are all in [0..1] range, alpha in [0..255] range. + Create a color specified by hue, saturation and lightness. + Values must in [0..1] range. + */ + static Color fromHSL(float hue, float saturation, float lightness, float alpha = 1.0f); + + /** + Create a color from a HTML string like "#333" or "#112233". */ - static Color HSL(const float hue, const float saturation, const float lightness, const int alpha = 255); + static Color fromHTML(const char* rgb, float alpha = 1.0f); /** Linearly interpolate this color against another. */ - void interpolate(const Color& other, const float u) noexcept; + void interpolate(const Color& other, float u) noexcept; /** Check if this color matches another. + @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; bool operator==(const Color& color) noexcept; bool operator!=(const Color& color) noexcept; /** + Fix color bounds if needed. + */ + void fixBounds() noexcept; + + /** @internal Needed for NanoVG compatibility. */ diff --git a/libs/dgl/Geometry.hpp b/libs/dgl/Geometry.hpp index 117c0a9..725a15e 100644 --- a/libs/dgl/Geometry.hpp +++ b/libs/dgl/Geometry.hpp @@ -30,8 +30,12 @@ template<typename> class Triangle; template<typename> class Rectangle; // ----------------------------------------------------------------------- -// Point +/** + DGL Point class. + + This class describes a single point in space, defined by an X and Y value. + */ template<typename T> class Point { @@ -62,17 +66,17 @@ public: const T& getY() const noexcept; /** - Set X value as @a x. + Set X value to @a x. */ void setX(const T& x) noexcept; /** - Set Y value as @a y. + Set Y value to @a y. */ void setY(const T& y) noexcept; /** - Set X and Y values as @a x and @a y respectively. + Set X and Y values to @a x and @a y respectively. */ void setPos(const T& x, const T& y) noexcept; @@ -96,6 +100,11 @@ public: */ bool isZero() const noexcept; + /** + Return true if point is not (0, 0). + */ + bool isNotZero() const noexcept; + Point<T> operator+(const Point<T>& pos) noexcept; Point<T> operator-(const Point<T>& pos) noexcept; Point<T>& operator=(const Point<T>& pos) noexcept; @@ -113,8 +122,12 @@ private: }; // ----------------------------------------------------------------------- -// Size +/** + DGL Size class. + + This class describes a size, defined by a width and height value. + */ template<typename T> class Size { @@ -155,7 +168,7 @@ public: void setHeight(const T& height) noexcept; /** - Set size using @a width and @a height. + Set size to @a width and @a height. */ void setSize(const T& width, const T& height) noexcept; @@ -167,30 +180,43 @@ public: /** Grow size by @a multiplier. */ - void growBy(const T& multiplier) noexcept; + void growBy(double multiplier) noexcept; /** Shrink size by @a divider. */ - void shrinkBy(const T& divider) noexcept; + void shrinkBy(double divider) noexcept; /** Return true if size is null (0x0). + An null size is also invalid. */ bool isNull() const noexcept; /** Return true if size is not null (0x0). + A non-null size is still invalid if its width or height is negative. */ bool isNotNull() const noexcept; + /** + Return true if size is valid (width and height are higher than zero). + */ + bool isValid() const noexcept; + + /** + Return true if size is invalid (width or height are lower or equal to zero). + An invalid size might not be null under some circumstances. + */ + bool isInvalid() const noexcept; + Size<T> operator+(const Size<T>& size) noexcept; Size<T> operator-(const Size<T>& size) noexcept; Size<T>& operator=(const Size<T>& size) noexcept; Size<T>& operator+=(const Size<T>& size) noexcept; Size<T>& operator-=(const Size<T>& size) noexcept; - Size<T>& operator*=(const T& m) noexcept; - Size<T>& operator/=(const T& d) noexcept; + Size<T>& operator*=(double m) noexcept; + Size<T>& operator/=(double d) noexcept; bool operator==(const Size<T>& size) const noexcept; bool operator!=(const Size<T>& size) const noexcept; @@ -200,14 +226,18 @@ private: }; // ----------------------------------------------------------------------- -// Line +/** + DGL Line class. + + This class describes a line, defined by two points. + */ template<typename T> class Line { public: /** - Constructor for a null line ([0, 0] to [0, 0]). + Constructor for a null line ([0,0] to [0,0]). */ Line() noexcept; @@ -217,7 +247,7 @@ public: Line(const T& startX, const T& startY, const T& endX, const T& endY) noexcept; /** - Constructor using custom start X, start Y, end pos values. + Constructor using custom start X, start Y and end pos values. */ Line(const T& startX, const T& startY, const Point<T>& endPos) noexcept; @@ -267,17 +297,17 @@ public: const Point<T>& getEndPos() const noexcept; /** - Set start X value as @a x. + Set start X value to @a x. */ void setStartX(const T& x) noexcept; /** - Set start Y value as @a y. + Set start Y value to @a y. */ void setStartY(const T& y) noexcept; /** - Set start X and Y values as @a x and @a y respectively. + Set start X and Y values to @a x and @a y respectively. */ void setStartPos(const T& x, const T& y) noexcept; @@ -287,17 +317,17 @@ public: void setStartPos(const Point<T>& pos) noexcept; /** - Set end X value as @a x. + Set end X value to @a x. */ void setEndX(const T& x) noexcept; /** - Set end Y value as @a y. + Set end Y value to @a y. */ void setEndY(const T& y) noexcept; /** - Set end X and Y values as @a x and @a y respectively. + Set end X and Y values to @a x and @a y respectively. */ void setEndPos(const T& x, const T& y) noexcept; @@ -321,6 +351,16 @@ public: */ void draw(); + /** + Return true if line is null (start and end pos are equal). + */ + bool isNull() const noexcept; + + /** + Return true if line is not null (start and end pos are different). + */ + bool isNotNull() const noexcept; + Line<T>& operator=(const Line<T>& line) noexcept; bool operator==(const Line<T>& line) const noexcept; bool operator!=(const Line<T>& line) const noexcept; @@ -330,8 +370,15 @@ private: }; // ----------------------------------------------------------------------- -// Circle +/** + DGL Circle class. + + This class describes a circle, defined by position, size and a minimum of 3 segments. + + TODO: report if circle starts at top-left, bottom-right or center. + and size grows from which point? + */ template<typename T> class Circle { @@ -372,17 +419,17 @@ public: const Point<T>& getPos() const noexcept; /** - Set X value as @a x. + Set X value to @a x. */ void setX(const T& x) noexcept; /** - Set Y value as @a y. + Set Y value to @a y. */ void setY(const T& y) noexcept; /** - Set X and Y values as @a x and @a y respectively. + Set X and Y values to @a x and @a y respectively. */ void setPos(const T& x, const T& y) noexcept; @@ -435,12 +482,16 @@ private: // cached values float fTheta, fCos, fSin; - void _draw(const bool isOutline); + void _draw(const bool outline); }; // ----------------------------------------------------------------------- -// Triangle +/** + DGL Triangle class. + + This class describes a triangle, defined by 3 points. + */ template<typename T> class Triangle { @@ -475,6 +526,29 @@ public: */ void drawOutline(); + /** + Return true if triangle is null (all its points are equal). + An null triangle is also invalid. + */ + bool isNull() const noexcept; + + /** + Return true if triangle is not null (one its points is different from the others). + A non-null triangle is still invalid if two of its points are equal. + */ + bool isNotNull() const noexcept; + + /** + Return true if triangle is valid (all its points are different). + */ + bool isValid() const noexcept; + + /** + Return true if triangle is invalid (one or two of its points are equal). + An invalid triangle might not be null under some circumstances. + */ + bool isInvalid() const noexcept; + Triangle<T>& operator=(const Triangle<T>& tri) noexcept; bool operator==(const Triangle<T>& tri) const noexcept; bool operator!=(const Triangle<T>& tri) const noexcept; @@ -482,12 +556,16 @@ public: private: Point<T> fPos1, fPos2, fPos3; - void _draw(const bool isOutline); + void _draw(const bool outline); }; // ----------------------------------------------------------------------- -// Rectangle +/** + DGL Rectangle class. + + This class describes a rectangle, defined by a starting point and a size. + */ template<typename T> class Rectangle { @@ -605,12 +683,12 @@ public: /** Grow size by @a multiplier. */ - void growBy(const T& multiplier) noexcept; + void growBy(double multiplier) noexcept; /** Shrink size by @a divider. */ - void shrinkBy(const T& divider) noexcept; + void shrinkBy(double divider) noexcept; /** Set rectangle using @a pos and @a size. @@ -653,8 +731,8 @@ public: void drawOutline(); Rectangle<T>& operator=(const Rectangle<T>& rect) noexcept; - Rectangle<T>& operator*=(const T& m) noexcept; - Rectangle<T>& operator/=(const T& d) noexcept; + Rectangle<T>& operator*=(double m) noexcept; + Rectangle<T>& operator/=(double d) noexcept; bool operator==(const Rectangle<T>& size) const noexcept; bool operator!=(const Rectangle<T>& size) const noexcept; @@ -662,7 +740,7 @@ private: Point<T> fPos; Size<T> fSize; - void _draw(const bool isOutline); + void _draw(const bool outline); }; // ----------------------------------------------------------------------- diff --git a/libs/dgl/ImageAboutWindow.hpp b/libs/dgl/ImageAboutWindow.hpp index 5a72ea2..2ffc0de 100644 --- a/libs/dgl/ImageAboutWindow.hpp +++ b/libs/dgl/ImageAboutWindow.hpp @@ -43,7 +43,8 @@ protected: private: Image fImgBackground; - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow) + DISTRHO_DECLARE_NON_COPY_CLASS(ImageAboutWindow) + //DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow) }; // ----------------------------------------------------------------------- diff --git a/libs/dgl/ImageKnob.hpp b/libs/dgl/ImageKnob.hpp index 3563824..2dd2669 100644 --- a/libs/dgl/ImageKnob.hpp +++ b/libs/dgl/ImageKnob.hpp @@ -41,15 +41,12 @@ public: virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; }; - explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical, int id = 0) noexcept; - explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical, int id = 0) noexcept; + 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; - int getId() const noexcept; - void setId(int id) noexcept; - float getValue() const noexcept; void setDefault(float def) noexcept; @@ -70,7 +67,6 @@ protected: private: Image fImage; - int fId; float fMinimum; float fMaximum; float fStep; @@ -89,11 +85,10 @@ private: Callback* fCallback; bool fIsImgVertical; - int fImgLayerSize; - int fImgLayerCount; - Rectangle<int> fKnobArea; - GLuint fTextureId; + uint fImgLayerSize; + uint fImgLayerCount; bool fIsReady; + GLuint fTextureId; float _logscale(float value) const; float _invlogscale(float value) const; diff --git a/libs/dgl/ImageSlider.hpp b/libs/dgl/ImageSlider.hpp index 613b25c..e6f2716 100644 --- a/libs/dgl/ImageSlider.hpp +++ b/libs/dgl/ImageSlider.hpp @@ -36,14 +36,11 @@ public: virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; }; - explicit ImageSlider(Window& parent, const Image& image, int id = 0) noexcept; - explicit ImageSlider(Widget* widget, const Image& image, int id = 0) noexcept; + 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; - int getId() const noexcept; - void setId(int id) noexcept; - float getValue() const noexcept; void setStartPos(const Point<int>& startPos) noexcept; @@ -65,7 +62,6 @@ protected: private: Image fImage; - int fId; float fMinimum; float fMaximum; float fStep; diff --git a/libs/dgl/ImageSwitch.hpp b/libs/dgl/ImageSwitch.hpp index bb963ac..172d61c 100644 --- a/libs/dgl/ImageSwitch.hpp +++ b/libs/dgl/ImageSwitch.hpp @@ -34,14 +34,11 @@ public: virtual void imageSwitchClicked(ImageSwitch* imageButton, bool down) = 0; }; - explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown, int id = 0) noexcept; - explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown, int id = 0) noexcept; + 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; - int getId() const noexcept; - void setId(int id) noexcept; - bool isDown() const noexcept; void setDown(bool down) noexcept; @@ -55,7 +52,6 @@ private: Image fImageNormal; Image fImageDown; bool fIsDown; - int fId; Callback* fCallback; diff --git a/libs/dgl/NanoVG.hpp b/libs/dgl/NanoVG.hpp index 32d467d..1135f55 100644 --- a/libs/dgl/NanoVG.hpp +++ b/libs/dgl/NanoVG.hpp @@ -258,7 +258,7 @@ public: /** Destructor. */ - ~NanoVG(); + virtual ~NanoVG(); /** Get the NanoVG context. @@ -641,7 +641,7 @@ public: Creates font by loading it from the specified memory chunk. Returns handle to the font. */ - FontId createFontMem(const char* name, uchar* data, int ndata, bool freeData); + FontId createFontMem(const char* name, const uchar* data, int ndata, bool freeData); /** Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. @@ -761,7 +761,8 @@ public: */ NanoWidget(Window& parent) : Widget(parent), - NanoVG() + NanoVG(), + leakDetector_NanoWidget() { setNeedsScaling(true); } diff --git a/libs/dgl/Widget.hpp b/libs/dgl/Widget.hpp index 86c42d4..faed6b5 100644 --- a/libs/dgl/Widget.hpp +++ b/libs/dgl/Widget.hpp @@ -26,6 +26,7 @@ START_NAMESPACE_DGL class App; class Window; +class StandaloneWindow; // ----------------------------------------------------------------------- @@ -52,12 +53,17 @@ class Widget public: /** Base event data. - @a mod The currently active modifiers. - @a time The timestamp (if any) of the currently-processing event. + @a mod The currently active keyboard modifiers, @see Modifier. + @a time The timestamp (if any). */ struct BaseEvent { - Modifier mod; + uint mod; uint32_t time; + + /** Constuctor */ + BaseEvent() noexcept : mod(0x0), time(0) {} + /** Destuctor */ + virtual ~BaseEvent() noexcept {} }; /** @@ -69,6 +75,12 @@ public: struct KeyboardEvent : BaseEvent { bool press; uint key; + + /** Constuctor */ + KeyboardEvent() noexcept + : BaseEvent(), + press(false), + key(0) {} }; /** @@ -79,7 +91,13 @@ public: */ struct SpecialEvent : BaseEvent { bool press; - Key key; + Key key; + + /** Constuctor */ + SpecialEvent() noexcept + : BaseEvent(), + press(false), + key(Key(0)) {} }; /** @@ -90,9 +108,16 @@ public: @see onMouse */ struct MouseEvent : BaseEvent { - int button; + int button; bool press; Point<int> pos; + + /** Constuctor */ + MouseEvent() noexcept + : BaseEvent(), + button(0), + press(false), + pos(0, 0) {} }; /** @@ -102,6 +127,11 @@ public: */ struct MotionEvent : BaseEvent { Point<int> pos; + + /** Constuctor */ + MotionEvent() noexcept + : BaseEvent(), + pos(0, 0) {} }; /** @@ -113,6 +143,12 @@ public: struct ScrollEvent : BaseEvent { Point<int> pos; Point<float> delta; + + /** Constuctor */ + ScrollEvent() noexcept + : BaseEvent(), + pos(0, 0), + delta(0.0f, 0.0f) {} }; /** @@ -124,6 +160,11 @@ public: struct ResizeEvent { Size<uint> size; Size<uint> oldSize; + + /** Constuctor */ + ResizeEvent() noexcept + : size(0, 0), + oldSize(0, 0) {} }; /** @@ -177,22 +218,22 @@ public: /** Set width. */ - virtual void setWidth(uint width) noexcept; + void setWidth(uint width) noexcept; /** Set height. */ - virtual void setHeight(uint height) noexcept; + void setHeight(uint height) noexcept; /** Set size using @a width and @a height values. */ - virtual void setSize(uint width, uint height) noexcept; + void setSize(uint width, uint height) noexcept; /** Set size. */ - virtual void setSize(const Size<uint>& size) noexcept; + void setSize(const Size<uint>& size) noexcept; /** Get absolute X. @@ -255,6 +296,18 @@ public: */ void repaint() noexcept; + /** + Get the Id associated with this widget. + @see setId + */ + uint getId() const noexcept; + + /** + Set an Id to be associated with this widget. + @see getId + */ + void setId(uint id) noexcept; + protected: /** A function called to draw the view contents with OpenGL. @@ -317,10 +370,10 @@ private: bool fNeedsFullViewport; bool fNeedsScaling; bool fVisible; + uint fId; Point<int> fAbsolutePos; Size<uint> fSize; - friend class CairoWidget; friend class Window; friend class StandaloneWindow; diff --git a/libs/dgl/Window.hpp b/libs/dgl/Window.hpp index 89e91de..37ae278 100644 --- a/libs/dgl/Window.hpp +++ b/libs/dgl/Window.hpp @@ -25,10 +25,48 @@ START_NAMESPACE_DGL class App; class Widget; +class StandaloneWindow; class Window { public: + /** + File browser options. + */ + struct FileBrowserOptions { + const char* startDir; + const char* title; + uint width; + uint height; + + /** + File browser buttons. + + 0 means hidden. + 1 means visible and unchecked. + 2 means visible and checked. + */ + struct Buttons { + uint listAllFiles; + uint showHidden; + uint showPlaces; + + /** Constuctor for default values */ + Buttons() + : listAllFiles(2), + showHidden(1), + showPlaces(1) {} + } buttons; + + /** Constuctor for default values */ + FileBrowserOptions() + : startDir(nullptr), + title(nullptr), + width(0), + height(0), + buttons() {} + }; + explicit Window(App& app); explicit Window(App& app, Window& parent); explicit Window(App& app, intptr_t parentId); @@ -42,6 +80,8 @@ public: void focus(); void repaint() noexcept; + bool openFileBrowser(const FileBrowserOptions& options); + bool isVisible() const noexcept; void setVisible(bool yesNo); @@ -54,9 +94,10 @@ public: void setSize(uint width, uint height); void setSize(Size<uint> size); + const char* getTitle() const noexcept; void setTitle(const char* title); - void setTransientWinId(intptr_t winId); + void setTransientWinId(uintptr_t winId); App& getApp() const noexcept; intptr_t getWindowId() const noexcept; @@ -70,6 +111,8 @@ protected: virtual void onReshape(uint width, uint height); virtual void onClose(); + virtual void fileBrowserSelected(const char* filename); + private: struct PrivateData; PrivateData* const pData; diff --git a/libs/dgl/ntk/NtkApp.hpp b/libs/dgl/ntk/NtkApp.hpp deleted file mode 100644 index 2c32d56..0000000 --- a/libs/dgl/ntk/NtkApp.hpp +++ /dev/null @@ -1,291 +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. - */ - -#ifndef DGL_NTK_APP_HPP_INCLUDED -#define DGL_NTK_APP_HPP_INCLUDED - -#include "../Base.hpp" -#include "../../distrho/DistrhoUI.hpp" -#include "../../distrho/extra/d_thread.hpp" - -#ifdef override -# define override_defined -# undef override -#endif - -#include <list> -#include <FL/Fl.H> -#include <FL/Fl_Double_Window.H> -#include <FL/Fl_Shared_Image.H> -#include <FL/x.H> - -#ifdef override_defined -# define override -# undef override_defined -#endif - -struct ScopedDisplayLock { - ScopedDisplayLock() - { -#ifdef DISTRHO_OS_LINUX - XLockDisplay(fl_display); -#endif - } - - ~ScopedDisplayLock() - { -#ifdef DISTRHO_OS_LINUX - XUnlockDisplay(fl_display); -#endif - } -}; - -// ----------------------------------------------------------------------- - -namespace DISTRHO_NAMESPACE { - class UI; -} - -START_NAMESPACE_DGL - -class NtkWindow; - -typedef DISTRHO_NAMESPACE::Mutex d_Mutex; -typedef DISTRHO_NAMESPACE::MutexLocker d_MutexLocker; -typedef DISTRHO_NAMESPACE::Thread d_Thread; -typedef DISTRHO_NAMESPACE::UI d_UI; - -// ----------------------------------------------------------------------- - -/** - DGL compatible App class that uses NTK instead of OpenGL. - @see App - */ -class NtkApp : d_Thread -{ -public: - /** - Constructor. - */ - NtkApp() - : d_Thread("NtkApp"), - fWindows(), - fWindowMutex(), - fNextUI(), - fDoNextUI(false), - fInitialized(false) - { -#ifdef DISTRHO_OS_LINUX - //XInitThreads(); -#endif - - startThread(); - - for (; ! fInitialized;) - d_msleep(10); - } - - /** - Destructor. - */ - ~NtkApp() - { - stopThread(-1); - fWindows.clear(); - } - - /** - Idle function. - This calls does nothing. - */ - void idle() {} - - /** - Run the application event-loop until all Windows are closed. - @note: This function is meant for standalones only, *never* call this from plugins. - */ - void exec() - { - while (isThreadRunning() && ! shouldThreadExit()) - d_sleep(1); - } - - /** - Quit the application. - This stops the event-loop and closes all Windows. - */ - void quit() - { - signalThreadShouldExit(); - } - - /** - Check if the application is about to quit. - Returning true means there's no event-loop running at the moment. - */ - bool isQuiting() const noexcept - { - if (isThreadRunning() && ! shouldThreadExit()) - return false; - return true; - } - - // ------------------------------------------------------------------- - - /** - Create UI on our separate thread. - Blocks until the UI is created and returns it. - */ - d_UI* createUI(void* const func) - { - DISTRHO_SAFE_ASSERT_RETURN(isThreadRunning(), nullptr); - DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI, nullptr); - - fNextUI.create = true; - fNextUI.func = (NextUI::UiFunc)func; - fDoNextUI = true; - - for (; fDoNextUI;) - d_msleep(10); - - return fNextUI.ui; - } - - /** - Delete UI on our separate thread. - Blocks until the UI is deleted. - */ - void deleteUI(d_UI* const ui) - { - DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI,); - - fNextUI.create = false; - fNextUI.ui = ui; - fDoNextUI = true; - - if (isThreadRunning()) - { - for (; fDoNextUI;) - d_msleep(10); - } - else - { - fNextUI.run(); - fDoNextUI = false; - } - } - - // ------------------------------------------------------------------- - -private: - struct NextUI { - typedef d_UI* (*UiFunc)(); - - bool create; - - union { - UiFunc func; - d_UI* ui; - }; - - NextUI() - : create(false), - func(nullptr) {} - - void run(); - }; - - std::list<Fl_Double_Window*> fWindows; - d_Mutex fWindowMutex; - NextUI fNextUI; - volatile bool fDoNextUI; - volatile bool fInitialized; - - /** @internal used by NtkWindow. */ - void addWindow(Fl_Double_Window* const window) - { - DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); - - if (fWindows.size() == 0 && ! isThreadRunning()) - startThread(); - - const d_MutexLocker sl(fWindowMutex); - fWindows.push_back(window); - } - - /** @internal used by NtkWindow. */ - void removeWindow(Fl_Double_Window* const window) - { - DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); - - const d_MutexLocker sl(fWindowMutex); - fWindows.remove(window); - - if (fWindows.size() == 0) - signalThreadShouldExit(); - } - - /** @internal */ - void run() override - { - static bool initialized = false; - - if (! initialized) - { - initialized = true; - fl_register_images(); -#ifdef DISTRHO_OS_LINUX - fl_open_display(); -#endif - } - - fInitialized = true; - - for (; ! shouldThreadExit();) - { - if (fDoNextUI) - { - const ScopedDisplayLock csdl; - fNextUI.run(); - fDoNextUI = false; - } - - const ScopedDisplayLock csdl; - Fl::check(); - Fl::flush(); - - d_msleep(20); - } - - const d_MutexLocker sl(fWindowMutex); - const ScopedDisplayLock csdl; - - for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit) - { - Fl_Double_Window* const window(*rit); - window->hide(); - } - } - - friend class NtkWindow; - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp) -}; -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#endif // DGL_NTK_APP_HPP_INCLUDED diff --git a/libs/dgl/ntk/NtkWidget.hpp b/libs/dgl/ntk/NtkWidget.hpp deleted file mode 100644 index 2247be3..0000000 --- a/libs/dgl/ntk/NtkWidget.hpp +++ /dev/null @@ -1,202 +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. - */ - -#ifndef DGL_NTK_WIDGET_HPP_INCLUDED -#define DGL_NTK_WIDGET_HPP_INCLUDED - -#include "NtkWindow.hpp" - -START_NAMESPACE_DGL - -// ----------------------------------------------------------------------- - -/** - DGL compatible Widget class that uses NTK instead of OpenGL. - @see Widget - */ -class NtkWidget : public Fl_Double_Window -{ -public: - /** - Constructor. - */ - explicit NtkWidget(NtkWindow& parent) - : Fl_Double_Window(100, 100), - fParent(parent) - { - fParent.add(this); - show(); - } - - /** - Destructor. - */ - ~NtkWidget() override - { - hide(); - fParent.remove(this); - } - - /** - Check if this widget is visible within its parent window. - Invisible widgets do not receive events except resize. - */ - bool isVisible() const - { - return visible(); - } - - /** - Set widget visible (or not) according to @a yesNo. - */ - void setVisible(bool yesNo) - { - if (yesNo) - show(); - else - hide(); - } - - /** - Get width. - */ - int getWidth() const - { - return w(); - } - - /** - Get height. - */ - int getHeight() const - { - return h(); - } - - /** - Set width. - */ - void setWidth(int width) - { - resize(x(), y(), width, h()); - } - - /** - Set height. - */ - void setHeight(int height) - { - resize(x(), y(), w(), height); - } - - /** - Set size using @a width and @a height values. - */ - void setSize(int width, int height) - { - resize(x(), y(), width, height); - } - - /** - Get absolute X. - */ - int getAbsoluteX() const - { - return x(); - } - - /** - Get absolute Y. - */ - int getAbsoluteY() const - { - return y(); - } - - /** - Set absolute X. - */ - void setAbsoluteX(int x) - { - resize(x, y(), w(), h()); - } - - /** - Set absolute Y. - */ - void setAbsoluteY(int y) - { - resize(x(), y, w(), h()); - } - - /** - Set absolute position using @a x and @a y values. - */ - void setAbsolutePos(int x, int y) - { - resize(x, y, w(), h()); - } - - /** - Get this widget's window application. - Same as calling getParentWindow().getApp(). - */ - NtkApp& getParentApp() const noexcept - { - return fParent.getApp(); - } - - /** - Get parent window, as passed in the constructor. - */ - NtkWindow& getParentWindow() const noexcept - { - return fParent; - } - - /** - Check if this widget contains the point defined by @a x and @a y. - */ - bool contains(int x, int y) const - { - return (x >= 0 && y >= 0 && x < w() && y < h()); - } - - /** - Tell this widget's window to repaint itself. - */ - void repaint() - { - redraw(); - } - -protected: - /** @internal used for DGL compatibility. */ - void setNeedsFullViewport(bool) noexcept {} - /** @internal used for DGL compatibility. */ - void setNeedsScaling(bool) noexcept {} - -private: - NtkWindow& fParent; - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkWidget) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#endif // DGL_NTK_WIDGET_HPP_INCLUDED diff --git a/libs/dgl/ntk/NtkWindow.hpp b/libs/dgl/ntk/NtkWindow.hpp deleted file mode 100644 index 47e9f10..0000000 --- a/libs/dgl/ntk/NtkWindow.hpp +++ /dev/null @@ -1,215 +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. - */ - -#ifndef DGL_NTK_WINDOW_HPP_INCLUDED -#define DGL_NTK_WINDOW_HPP_INCLUDED - -#include "NtkApp.hpp" - -START_NAMESPACE_DGL - -class NtkWidget; - -// ----------------------------------------------------------------------- - -class NtkWindow : public Fl_Double_Window -{ -public: - explicit NtkWindow(NtkApp& app) - : Fl_Double_Window(100, 100), - fApp(app), - fIsVisible(false), - fUsingEmbed(false), - fParent(nullptr) {} - - explicit NtkWindow(NtkApp& app, NtkWindow& parent) - : Fl_Double_Window(100, 100), - fApp(app), - fIsVisible(false), - fUsingEmbed(false), - fParent(&parent) {} - - explicit NtkWindow(NtkApp& app, intptr_t parentId) - : Fl_Double_Window(100, 100), - fApp(app), - fIsVisible(parentId != 0), - fUsingEmbed(parentId != 0), - fParent(nullptr) - { - if (fUsingEmbed) - { - fl_embed(this, (Window)parentId); - Fl_Double_Window::show(); - fApp.addWindow(this); - } - } - - ~NtkWindow() override - { - if (fUsingEmbed) - { - fApp.removeWindow(this); - Fl_Double_Window::hide(); - } - } - - void show() override - { - if (fUsingEmbed || fIsVisible) - return; - - Fl_Double_Window::show(); - fApp.addWindow(this); - fIsVisible = true; - - if (fParent != nullptr) - setTransientWinId((intptr_t)fl_xid(fParent)); - } - - void hide() override - { - if (fUsingEmbed || ! fIsVisible) - return; - - fIsVisible = false; - fApp.removeWindow(this); - Fl_Double_Window::hide(); - } - - void close() - { - hide(); - } - - bool isVisible() const - { - return visible(); - } - - void setVisible(bool yesNo) - { - if (yesNo) - show(); - else - hide(); - } - - bool isResizable() const - { - // TODO - return false; - } - - void setResizable(bool /*yesNo*/) - { - // TODO - } - - int getWidth() const noexcept - { - return w(); - } - - int getHeight() const noexcept - { - return h(); - } - - void setSize(uint width, uint height) - { - resize(x(), y(), width, height); - } - - void setTitle(const char* title) - { - label(title); - } - - void setTransientWinId(intptr_t winId) - { - DISTRHO_SAFE_ASSERT_RETURN(winId != 0,); - -#ifdef DISTRHO_OS_LINUX - DISTRHO_SAFE_ASSERT_RETURN(fl_display != nullptr,); - - const ::Window ourWindow(fl_xid(this)); - DISTRHO_SAFE_ASSERT_RETURN(ourWindow != 0,); - - XSetTransientForHint(fl_display, ourWindow, winId); -#endif - } - - NtkApp& getApp() const noexcept - { - return fApp; - } - - intptr_t getWindowId() const - { - return (intptr_t)fl_xid(this); - } - - void addIdleCallback(IdleCallback* const callback) - { - DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,); - - if (fIdleCallbacks.size() == 0) - Fl::add_idle(_idleHandler, this); - - fIdleCallbacks.push_back(callback); - } - - void removeIdleCallback(IdleCallback* const callback) - { - DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,); - - fIdleCallbacks.remove(callback); - - if (fIdleCallbacks.size() == 0) - Fl::remove_idle(_idleHandler, this); - } - -private: - NtkApp& fApp; - bool fIsVisible; - bool fUsingEmbed; - - // transient parent, may be null - NtkWindow* const fParent; - - std::list<IdleCallback*> fIdleCallbacks; - - friend class NtkWidget; - - static void _idleHandler(void* data) - { - NtkWindow* const self((NtkWindow*)data); - - for (std::list<IdleCallback*>::iterator it=self->fIdleCallbacks.begin(), ite=self->fIdleCallbacks.end(); it != ite; ++it) - { - IdleCallback* const idleCallback(*it); - idleCallback->idleCallback(); - } - } - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkWindow) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#endif // DGL_NTK_WINDOW_HPP_INCLUDED diff --git a/libs/dgl/src/Color.cpp b/libs/dgl/src/Color.cpp index 46b7ad3..57b8c07 100644 --- a/libs/dgl/src/Color.cpp +++ b/libs/dgl/src/Color.cpp @@ -22,51 +22,66 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -Color::Color() noexcept - : red(1.0f), green(1.0f), blue(1.0f), alpha(1.0f) {} - -Color::Color(const int r, const int g, const int b, const int a) noexcept - : red(static_cast<float>(r)/255.0f), green(static_cast<float>(g)/255.0f), blue(static_cast<float>(b)/255.0f), alpha(static_cast<float>(a)/255.0f) {} - -Color::Color(const float r, const float g, const float b, const float a) noexcept - : red(r), green(g), blue(b), alpha(a) {} - -Color::Color(const Color& color) noexcept - : red(color.red), green(color.green), blue(color.blue), alpha(color.alpha) {} - -Color::Color(const Color& color1, const Color& color2, const float u) noexcept - : red(color1.red), green(color1.green), blue(color1.blue), alpha(color1.alpha) +static void fixRange(float& value) { - interpolate(color2, u); + /**/ if (value < 0.0f) + value = 0.0f; + else if (value > 1.0f) + value = 1.0f; } -void Color::interpolate(const Color& other, const float u) noexcept +static float getFixedRange(const float& value) { - const float u2 = (u < 0.0f) ? 0.0f : ((u > 1.0f) ? 1.0f : u); - const float oneMinusU = 1.0f - u; + if (value <= 0.0f) + return 0.0f; + if (value >= 1.0f) + return 1.0f; + return value; +} - red = red * oneMinusU + other.red * u2; - green = green * oneMinusU + other.green * u2; - blue = blue * oneMinusU + other.blue * u2; - alpha = alpha * oneMinusU + other.alpha * u2; +static uchar getFixedRange2(const float& value) +{ + const float value2(getFixedRange(value)*255.0f); + if (value2 <= 0.0f) + return 0; + if (value2 >= 255.0f) + return 255; + return static_cast<uchar>(value2); } -Color Color::HSL(const float hue, const float saturation, const float lightness, const int alpha) +// ----------------------------------------------------------------------- + +Color::Color() noexcept + : red(1.0f), + green(1.0f), + blue(1.0f), + alpha(1.0f) {} + +Color::Color(int r, int g, int b, int a) noexcept + : red(static_cast<float>(r)/255.0f), + green(static_cast<float>(g)/255.0f), + blue(static_cast<float>(b)/255.0f), + alpha(static_cast<float>(a)/255.0f) { - return nvgHSLA(hue, saturation, lightness, alpha); + fixBounds(); } -Color::Color(const NVGcolor& c) noexcept - : red(c.r), green(c.g), blue(c.b), alpha(c.a) {} +Color::Color(float r, float g, float b, float a) noexcept + : red(r), + green(g), + blue(b), + alpha(a) +{ + fixBounds(); +} -Color::operator NVGcolor() const noexcept +Color::Color(const Color& color) noexcept + : red(color.red), + green(color.green), + blue(color.blue), + alpha(color.alpha) { - NVGcolor nc; - nc.r = red; - nc.g = green; - nc.b = blue; - nc.a = alpha; - return nc; + fixBounds(); } Color& Color::operator=(const Color& color) noexcept @@ -75,17 +90,154 @@ Color& Color::operator=(const Color& color) noexcept green = color.green; blue = color.blue; alpha = color.alpha; + fixBounds(); return *this; } +Color::Color(const Color& color1, const Color& color2, float u) noexcept + : red(color1.red), + green(color1.green), + blue(color1.blue), + alpha(color1.alpha) +{ + interpolate(color2, u); +} + +Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) +{ + return nvgHSLA(hue, saturation, lightness, static_cast<uchar>(getFixedRange(alpha)*255.0f)); +} + +Color Color::fromHTML(const char* rgb, float alpha) +{ + Color fallback; + DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback); + + if (rgb[0] == '#') ++rgb; + DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback); + + std::size_t rgblen(std::strlen(rgb)); + DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback); + + char rgbtmp[3] = { '\0', '\0', '\0' }; + int r, g, b; + + if (rgblen == 3) + { + rgbtmp[0] = rgb[0]; + r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + + rgbtmp[0] = rgb[1]; + g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + + rgbtmp[0] = rgb[2]; + b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + } + else + { + rgbtmp[0] = rgb[0]; + rgbtmp[1] = rgb[1]; + r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + + rgbtmp[0] = rgb[2]; + rgbtmp[1] = rgb[3]; + g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + + rgbtmp[0] = rgb[4]; + rgbtmp[1] = rgb[5]; + b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); + } + + return Color(r, g, b, static_cast<int>(getFixedRange(alpha)*255.0f)); +} + +void Color::interpolate(const Color& other, float u) noexcept +{ + fixRange(u); + const float oneMinusU(1.0f - u); + + red = red * oneMinusU + other.red * u; + green = green * oneMinusU + other.green * u; + blue = blue * oneMinusU + other.blue * u; + alpha = alpha * oneMinusU + other.alpha * u; + + fixBounds(); +} + +// ----------------------------------------------------------------------- + +bool Color::isEqual(const Color& color, bool withAlpha) noexcept +{ + const uchar r1 = getFixedRange2(rgba[0]); + const uchar g1 = getFixedRange2(rgba[1]); + const uchar b1 = getFixedRange2(rgba[2]); + const uchar a1 = getFixedRange2(rgba[3]); + + const uchar r2 = getFixedRange2(color.rgba[0]); + const uchar g2 = getFixedRange2(color.rgba[1]); + const uchar b2 = getFixedRange2(color.rgba[2]); + const uchar a2 = getFixedRange2(color.rgba[3]); + + if (withAlpha) + return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2); + else + return (r1 == r2 && g1 == g2 && b1 == b2); +} + +bool Color::isNotEqual(const Color& color, bool withAlpha) noexcept +{ + const uchar r1 = getFixedRange2(rgba[0]); + const uchar g1 = getFixedRange2(rgba[1]); + const uchar b1 = getFixedRange2(rgba[2]); + const uchar a1 = getFixedRange2(rgba[3]); + + const uchar r2 = getFixedRange2(color.rgba[0]); + const uchar g2 = getFixedRange2(color.rgba[1]); + const uchar b2 = getFixedRange2(color.rgba[2]); + const uchar a2 = getFixedRange2(color.rgba[3]); + + if (withAlpha) + return (r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2); + else + return (r1 != r2 || g1 != g2 || b1 != b2); +} + bool Color::operator==(const Color& color) noexcept { - return (red == color.red && green == color.green && blue == color.blue && alpha == color.alpha); + return isEqual(color, true); } bool Color::operator!=(const Color& color) noexcept { - return (red != color.red || green != color.green || blue != color.blue || alpha != color.alpha); + return isNotEqual(color, true); +} + +// ----------------------------------------------------------------------- + +void Color::fixBounds() noexcept +{ + fixRange(red); + fixRange(green); + fixRange(blue); + fixRange(alpha); +} + +// ----------------------------------------------------------------------- + +Color::Color(const NVGcolor& c) noexcept + : red(c.r), green(c.g), blue(c.b), alpha(c.a) +{ + fixBounds(); +} + +Color::operator NVGcolor() const noexcept +{ + NVGcolor nc; + nc.r = red; + nc.g = green; + nc.b = blue; + nc.a = alpha; + return nc; } // ----------------------------------------------------------------------- diff --git a/libs/dgl/src/Geometry.cpp b/libs/dgl/src/Geometry.cpp index a7565fa..6964816 100644 --- a/libs/dgl/src/Geometry.cpp +++ b/libs/dgl/src/Geometry.cpp @@ -99,6 +99,12 @@ bool Point<T>::isZero() const noexcept } template<typename T> +bool Point<T>::isNotZero() const noexcept +{ + return fX != 0 || fY != 0; +} + +template<typename T> Point<T> Point<T>::operator+(const Point<T>& pos) noexcept { return Point<T>(fX+pos.fX, fY+pos.fY); @@ -203,17 +209,17 @@ void Size<T>::setSize(const Size<T>& size) noexcept } template<typename T> -void Size<T>::growBy(const T& multiplier) noexcept +void Size<T>::growBy(double multiplier) noexcept { - fWidth = static_cast<T>(fWidth*multiplier); - fHeight = static_cast<T>(fHeight*multiplier); + fWidth = static_cast<T>(static_cast<double>(fWidth)*multiplier); + fHeight = static_cast<T>(static_cast<double>(fHeight)*multiplier); } template<typename T> -void Size<T>::shrinkBy(const T& divider) noexcept +void Size<T>::shrinkBy(double divider) noexcept { - fWidth = static_cast<T>(fWidth/divider); - fHeight = static_cast<T>(fHeight/divider); + fWidth = static_cast<T>(static_cast<double>(fWidth)/divider); + fHeight = static_cast<T>(static_cast<double>(fHeight)/divider); } template<typename T> @@ -228,6 +234,17 @@ bool Size<T>::isNotNull() const noexcept return fWidth != 0 || fHeight != 0; } +template<typename T> +bool Size<T>::isValid() const noexcept +{ + return fWidth > 1 && fHeight > 1; +} + +template<typename T> +bool Size<T>::isInvalid() const noexcept +{ + return fWidth <= 0 || fHeight <= 0; +} template<typename T> Size<T> Size<T>::operator+(const Size<T>& size) noexcept @@ -266,18 +283,18 @@ Size<T>& Size<T>::operator-=(const Size<T>& size) noexcept } template<typename T> -Size<T>& Size<T>::operator*=(const T& m) noexcept +Size<T>& Size<T>::operator*=(double m) noexcept { - fWidth = static_cast<T>(fWidth*m); - fHeight = static_cast<T>(fHeight*m); + fWidth = static_cast<T>(static_cast<double>(fWidth)*m); + fHeight = static_cast<T>(static_cast<double>(fHeight)*m); return *this; } template<typename T> -Size<T>& Size<T>::operator/=(const T& d) noexcept +Size<T>& Size<T>::operator/=(double d) noexcept { - fWidth = static_cast<T>(fWidth/d); - fHeight = static_cast<T>(fHeight/d); + fWidth = static_cast<T>(static_cast<double>(fWidth)/d); + fHeight = static_cast<T>(static_cast<double>(fHeight)/d); return *this; } @@ -427,17 +444,31 @@ void Line<T>::moveBy(const Point<T>& pos) noexcept template<typename T> void Line<T>::draw() { + DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); + glBegin(GL_LINES); { - glVertex2i(fPosStart.fX, fPosStart.fY); - glVertex2i(fPosEnd.fX, fPosEnd.fY); + glVertex2d(fPosStart.fX, fPosStart.fY); + glVertex2d(fPosEnd.fX, fPosEnd.fY); } glEnd(); } template<typename T> +bool Line<T>::isNull() const noexcept +{ + return fPosStart == fPosEnd; +} + +template<typename T> +bool Line<T>::isNotNull() const noexcept +{ + return fPosStart != fPosEnd; +} + +template<typename T> Line<T>& Line<T>::operator=(const Line<T>& line) noexcept { fPosStart = line.fPosStart; @@ -610,24 +641,23 @@ Circle<T>& Circle<T>::operator=(const Circle<T>& cir) noexcept template<typename T> bool Circle<T>::operator==(const Circle<T>& cir) const noexcept { - return (fPos == cir.fPos && fSize == cir.fSize && fNumSegments == cir.fNumSegments); + return (fPos == cir.fPos && d_isEqual(fSize, cir.fSize) && fNumSegments == cir.fNumSegments); } template<typename T> bool Circle<T>::operator!=(const Circle<T>& cir) const noexcept { - return (fPos != cir.fPos || fSize != cir.fSize || fNumSegments != cir.fNumSegments); + return (fPos != cir.fPos || d_isNotEqual(fSize, cir.fSize) || fNumSegments != cir.fNumSegments); } template<typename T> -void Circle<T>::_draw(const bool isOutline) +void Circle<T>::_draw(const bool outline) { - if (fNumSegments < 3 || fSize <= 0.0f) - return; + DISTRHO_SAFE_ASSERT_RETURN(fNumSegments >= 3 && fSize > 0.0f,); - float t, x = fSize, y = 0; + float t, x = fSize, y = 0.0f; - glBegin(isOutline ? GL_LINE_LOOP : GL_POLYGON); + glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); for (uint i=0; i<fNumSegments; ++i) { @@ -681,6 +711,30 @@ void Triangle<T>::drawOutline() } template<typename T> +bool Triangle<T>::isNull() const noexcept +{ + return fPos1 == fPos2 && fPos1 == fPos3; +} + +template<typename T> +bool Triangle<T>::isNotNull() const noexcept +{ + return fPos1 != fPos2 || fPos1 != fPos3; +} + +template<typename T> +bool Triangle<T>::isValid() const noexcept +{ + return fPos1 != fPos2 && fPos1 != fPos3; +} + +template<typename T> +bool Triangle<T>::isInvalid() const noexcept +{ + return fPos1 == fPos2 || fPos1 == fPos3; +} + +template<typename T> Triangle<T>& Triangle<T>::operator=(const Triangle<T>& tri) noexcept { fPos1 = tri.fPos1; @@ -702,14 +756,16 @@ bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept } template<typename T> -void Triangle<T>::_draw(const bool isOutline) +void Triangle<T>::_draw(const bool outline) { - glBegin(isOutline ? GL_LINE_LOOP : GL_TRIANGLES); + DISTRHO_SAFE_ASSERT_RETURN(fPos1 != fPos2 && fPos1 != fPos3,); + + glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); { - glVertex2i(fPos1.fX, fPos1.fY); - glVertex2i(fPos2.fX, fPos2.fY); - glVertex2i(fPos3.fX, fPos3.fY); + glVertex2d(fPos1.fX, fPos1.fY); + glVertex2d(fPos2.fX, fPos2.fY); + glVertex2d(fPos3.fX, fPos3.fY); } glEnd(); @@ -847,13 +903,13 @@ void Rectangle<T>::setSize(const Size<T>& size) noexcept } template<typename T> -void Rectangle<T>::growBy(const T& multiplier) noexcept +void Rectangle<T>::growBy(double multiplier) noexcept { fSize.growBy(multiplier); } template<typename T> -void Rectangle<T>::shrinkBy(const T& divider) noexcept +void Rectangle<T>::shrinkBy(double divider) noexcept { fSize.shrinkBy(divider); } @@ -917,14 +973,14 @@ Rectangle<T>& Rectangle<T>::operator=(const Rectangle<T>& rect) noexcept } template<typename T> -Rectangle<T>& Rectangle<T>::operator*=(const T& m) noexcept +Rectangle<T>& Rectangle<T>::operator*=(double m) noexcept { fSize *= m; return *this; } template<typename T> -Rectangle<T>& Rectangle<T>::operator/=(const T& d) noexcept +Rectangle<T>& Rectangle<T>::operator/=(double d) noexcept { fSize /= d; return *this; @@ -943,22 +999,24 @@ bool Rectangle<T>::operator!=(const Rectangle<T>& rect) const noexcept } template<typename T> -void Rectangle<T>::_draw(const bool isOutline) +void Rectangle<T>::_draw(const bool outline) { - glBegin(isOutline ? GL_LINE_LOOP : GL_QUADS); + DISTRHO_SAFE_ASSERT_RETURN(fSize.isValid(),); + + glBegin(outline ? GL_LINE_LOOP : GL_QUADS); { glTexCoord2f(0.0f, 0.0f); - glVertex2i(fPos.fX, fPos.fY); + glVertex2d(fPos.fX, fPos.fY); glTexCoord2f(1.0f, 0.0f); - glVertex2i(fPos.fX+fSize.fWidth, fPos.fY); + glVertex2d(fPos.fX+fSize.fWidth, fPos.fY); glTexCoord2f(1.0f, 1.0f); - glVertex2i(fPos.fX+fSize.fWidth, fPos.fY+fSize.fHeight); + glVertex2d(fPos.fX+fSize.fWidth, fPos.fY+fSize.fHeight); glTexCoord2f(0.0f, 1.0f); - glVertex2i(fPos.fX, fPos.fY+fSize.fHeight); + glVertex2d(fPos.fX, fPos.fY+fSize.fHeight); } glEnd(); diff --git a/libs/dgl/src/Image.cpp b/libs/dgl/src/Image.cpp index 55ee0af..74dceed 100644 --- a/libs/dgl/src/Image.cpp +++ b/libs/dgl/src/Image.cpp @@ -152,12 +152,14 @@ void Image::drawAt(const Point<int>& pos) glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fSize.getWidth(), fSize.getHeight(), 0, fFormat, fType, fRawData); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + static_cast<GLsizei>(fSize.getWidth()), static_cast<GLsizei>(fSize.getHeight()), 0, + fFormat, fType, fRawData); fIsReady = true; } - Rectangle<int>(pos, fSize.getWidth(), fSize.getHeight()).draw(); + Rectangle<int>(pos, static_cast<int>(fSize.getWidth()), static_cast<int>(fSize.getHeight())).draw(); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); diff --git a/libs/dgl/src/ImageAboutWindow.cpp b/libs/dgl/src/ImageAboutWindow.cpp index a12aa57..9e90f29 100644 --- a/libs/dgl/src/ImageAboutWindow.cpp +++ b/libs/dgl/src/ImageAboutWindow.cpp @@ -23,8 +23,8 @@ START_NAMESPACE_DGL ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image) : Window(parent.getApp(), parent), Widget((Window&)*this), - fImgBackground(image), - leakDetector_ImageAboutWindow() + fImgBackground(image)/*, + leakDetector_ImageAboutWindow()*/ { Window::setResizable(false); Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight())); @@ -34,8 +34,8 @@ ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image) ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image) : Window(widget->getParentApp(), widget->getParentWindow()), Widget((Window&)*this), - fImgBackground(image), - leakDetector_ImageAboutWindow() + fImgBackground(image)/*, + leakDetector_ImageAboutWindow()*/ { Window::setResizable(false); Window::setSize(static_cast<uint>(image.getWidth()), static_cast<uint>(image.getHeight())); diff --git a/libs/dgl/src/ImageKnob.cpp b/libs/dgl/src/ImageKnob.cpp index 0fc8c69..57dae6a 100644 --- a/libs/dgl/src/ImageKnob.cpp +++ b/libs/dgl/src/ImageKnob.cpp @@ -22,10 +22,9 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation, int id) noexcept +ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation) noexcept : Widget(parent), fImage(image), - fId(id), fMinimum(0.0f), fMaximum(1.0f), fStep(0.0f), @@ -43,19 +42,17 @@ ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation fIsImgVertical(image.getHeight() > image.getWidth()), fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), - fKnobArea(0, 0, fImgLayerSize, fImgLayerSize), - fTextureId(0), fIsReady(false), + fTextureId(0), leakDetector_ImageKnob() { glGenTextures(1, &fTextureId); setSize(fImgLayerSize, fImgLayerSize); } -ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation, int id) noexcept +ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation) noexcept : Widget(widget->getParentWindow()), fImage(image), - fId(id), fMinimum(0.0f), fMaximum(1.0f), fStep(0.0f), @@ -73,9 +70,8 @@ ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation fIsImgVertical(image.getHeight() > image.getWidth()), fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), - fKnobArea(0, 0, fImgLayerSize, fImgLayerSize), - fTextureId(0), fIsReady(false), + fTextureId(0), leakDetector_ImageKnob() { glGenTextures(1, &fTextureId); @@ -85,7 +81,6 @@ ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation ImageKnob::ImageKnob(const ImageKnob& imageKnob) : Widget(imageKnob.getParentWindow()), fImage(imageKnob.fImage), - fId(imageKnob.fId), fMinimum(imageKnob.fMinimum), fMaximum(imageKnob.fMaximum), fStep(imageKnob.fStep), @@ -103,9 +98,8 @@ ImageKnob::ImageKnob(const ImageKnob& imageKnob) fIsImgVertical(imageKnob.fIsImgVertical), fImgLayerSize(imageKnob.fImgLayerSize), fImgLayerCount(imageKnob.fImgLayerCount), - fKnobArea(imageKnob.fKnobArea), - fTextureId(0), fIsReady(false), + fTextureId(0), leakDetector_ImageKnob() { glGenTextures(1, &fTextureId); @@ -115,7 +109,6 @@ ImageKnob::ImageKnob(const ImageKnob& imageKnob) ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) { fImage = imageKnob.fImage; - fId = imageKnob.fId; fMinimum = imageKnob.fMinimum; fMaximum = imageKnob.fMaximum; fStep = imageKnob.fStep; @@ -133,7 +126,6 @@ ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) fIsImgVertical = imageKnob.fIsImgVertical; fImgLayerSize = imageKnob.fImgLayerSize; fImgLayerCount = imageKnob.fImgLayerCount; - fKnobArea = imageKnob.fKnobArea; fIsReady = false; if (fTextureId != 0) @@ -157,16 +149,6 @@ ImageKnob::~ImageKnob() } } -int ImageKnob::getId() const noexcept -{ - return fId; -} - -void ImageKnob::setId(int id) noexcept -{ - fId = id; -} - float ImageKnob::getValue() const noexcept { return fValue; @@ -220,12 +202,12 @@ void ImageKnob::setStep(float step) noexcept // NOTE: value is assumed to be scaled if using log void ImageKnob::setValue(float value, bool sendCallback) noexcept { - if (fValue == value) + if (d_isEqual(fValue, value)) return; fValue = value; - if (fStep == 0.0f) + if (d_isZero(fStep)) fValueTmp = value; if (fRotationAngle == 0) @@ -288,36 +270,44 @@ void ImageKnob::onDisplay() glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - int imageDataOffset = 0; + uint imageDataOffset = 0; if (fRotationAngle == 0) { - int layerDataSize = fImgLayerSize * fImgLayerSize * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3); - imageDataOffset = layerDataSize * int(normValue * float(fImgLayerCount-1)); + 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, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset); + 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 GLint w2 = getWidth()/2; - const GLint h2 = getHeight()/2; + 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, getWidth(), getHeight()).draw(); + Rectangle<int>(-w2, -h2, w, h).draw(); glPopMatrix(); } else { - Rectangle<int>(0, 0, getWidth(), getHeight()).draw(); + Rectangle<int>(0, 0, w, h).draw(); } glBindTexture(GL_TEXTURE_2D, 0); @@ -403,7 +393,7 @@ bool ImageKnob::onMotion(const MotionEvent& ev) { fValueTmp = value = fMaximum; } - else if (fStep != 0.0f) + else if (d_isNotZero(fStep)) { fValueTmp = value; const float rest = std::fmod(value, fStep); @@ -437,7 +427,7 @@ bool ImageKnob::onScroll(const ScrollEvent& ev) { fValueTmp = value = fMaximum; } - else if (fStep != 0.0f) + else if (d_isNotZero(fStep)) { fValueTmp = value; const float rest = std::fmod(value, fStep); diff --git a/libs/dgl/src/ImageSlider.cpp b/libs/dgl/src/ImageSlider.cpp index b9ae84e..12f7b37 100644 --- a/libs/dgl/src/ImageSlider.cpp +++ b/libs/dgl/src/ImageSlider.cpp @@ -22,10 +22,9 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -ImageSlider::ImageSlider(Window& parent, const Image& image, int id) noexcept +ImageSlider::ImageSlider(Window& parent, const Image& image) noexcept : Widget(parent), fImage(image), - fId(id), fMinimum(0.0f), fMaximum(1.0f), fStep(0.0f), @@ -44,10 +43,9 @@ ImageSlider::ImageSlider(Window& parent, const Image& image, int id) noexcept Widget::setNeedsFullViewport(true); } -ImageSlider::ImageSlider(Widget* widget, const Image& image, int id) noexcept +ImageSlider::ImageSlider(Widget* widget, const Image& image) noexcept : Widget(widget->getParentWindow()), fImage(image), - fId(id), fMinimum(0.0f), fMaximum(1.0f), fStep(0.0f), @@ -69,7 +67,6 @@ ImageSlider::ImageSlider(Widget* widget, const Image& image, int id) noexcept ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept : Widget(imageSlider.getParentWindow()), fImage(imageSlider.fImage), - fId(imageSlider.fId), fMinimum(imageSlider.fMinimum), fMaximum(imageSlider.fMaximum), fStep(imageSlider.fStep), @@ -91,7 +88,6 @@ ImageSlider::ImageSlider(const ImageSlider& imageSlider) noexcept ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept { fImage = imageSlider.fImage; - fId = imageSlider.fId; fMinimum = imageSlider.fMinimum; fMaximum = imageSlider.fMaximum; fStep = imageSlider.fStep; @@ -109,16 +105,6 @@ ImageSlider& ImageSlider::operator=(const ImageSlider& imageSlider) noexcept return *this; } -int ImageSlider::getId() const noexcept -{ - return fId; -} - -void ImageSlider::setId(int id) noexcept -{ - fId = id; -} - float ImageSlider::getValue() const noexcept { return fValue; @@ -193,12 +179,12 @@ void ImageSlider::setStep(float step) noexcept void ImageSlider::setValue(float value, bool sendCallback) noexcept { - if (fValue == value) + if (d_isEqual(fValue, value)) return; fValue = value; - if (fStep == 0.0f) + if (d_isZero(fStep)) fValueTmp = value; repaint(); @@ -224,7 +210,7 @@ void ImageSlider::onDisplay() glColor4f(1.0f, 1.0f, 1.0f, 1.0f); #endif - float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); + const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); int x, y; @@ -292,7 +278,7 @@ bool ImageSlider::onMouse(const MouseEvent& ev) { fValueTmp = value = fMaximum; } - else if (fStep != 0.0f) + else if (d_isNotZero(fStep)) { fValueTmp = value; const float rest = std::fmod(value, fStep); @@ -361,7 +347,7 @@ bool ImageSlider::onMotion(const MotionEvent& ev) { fValueTmp = value = fMaximum; } - else if (fStep != 0.0f) + else if (d_isNotZero(fStep)) { fValueTmp = value; const float rest = std::fmod(value, fStep); @@ -395,16 +381,16 @@ void ImageSlider::_recheckArea() noexcept // horizontal fSliderArea = Rectangle<int>(fStartPos.getX(), fStartPos.getY(), - fEndPos.getX() + fImage.getWidth() - fStartPos.getX(), - fImage.getHeight()); + fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(), + static_cast<int>(fImage.getHeight())); } else { // vertical fSliderArea = Rectangle<int>(fStartPos.getX(), fStartPos.getY(), - fImage.getWidth(), - fEndPos.getY() + fImage.getHeight() - fStartPos.getY()); + static_cast<int>(fImage.getWidth()), + fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY()); } } diff --git a/libs/dgl/src/ImageSwitch.cpp b/libs/dgl/src/ImageSwitch.cpp index bd99786..37b3e56 100644 --- a/libs/dgl/src/ImageSwitch.cpp +++ b/libs/dgl/src/ImageSwitch.cpp @@ -20,12 +20,11 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- -ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown, int id) noexcept +ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept : Widget(parent), fImageNormal(imageNormal), fImageDown(imageDown), fIsDown(false), - fId(id), fCallback(nullptr), leakDetector_ImageSwitch() { @@ -34,12 +33,11 @@ ImageSwitch::ImageSwitch(Window& parent, const Image& imageNormal, const Image& setSize(fImageNormal.getSize()); } -ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown, int id) noexcept +ImageSwitch::ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept : Widget(widget->getParentWindow()), fImageNormal(imageNormal), fImageDown(imageDown), fIsDown(false), - fId(id), fCallback(nullptr), leakDetector_ImageSwitch() { @@ -53,7 +51,6 @@ ImageSwitch::ImageSwitch(const ImageSwitch& imageSwitch) noexcept fImageNormal(imageSwitch.fImageNormal), fImageDown(imageSwitch.fImageDown), fIsDown(imageSwitch.fIsDown), - fId(imageSwitch.fId), fCallback(imageSwitch.fCallback), leakDetector_ImageSwitch() { @@ -67,7 +64,6 @@ ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept fImageNormal = imageSwitch.fImageNormal; fImageDown = imageSwitch.fImageDown; fIsDown = imageSwitch.fIsDown; - fId = imageSwitch.fId; fCallback = imageSwitch.fCallback; DISTRHO_SAFE_ASSERT(fImageNormal.getSize() == fImageDown.getSize()); @@ -77,16 +73,6 @@ ImageSwitch& ImageSwitch::operator=(const ImageSwitch& imageSwitch) noexcept return *this; } -int ImageSwitch::getId() const noexcept -{ - return fId; -} - -void ImageSwitch::setId(int id) noexcept -{ - fId = id;; -} - bool ImageSwitch::isDown() const noexcept { return fIsDown; diff --git a/libs/dgl/src/NanoVG.cpp b/libs/dgl/src/NanoVG.cpp index bb7b9f1..a4c357b 100644 --- a/libs/dgl/src/NanoVG.cpp +++ b/libs/dgl/src/NanoVG.cpp @@ -18,8 +18,32 @@ #include "../Window.hpp" // ----------------------------------------------------------------------- +// Ignore some warnings if debugging + +#if 0 //def DEBUG +# define NANOVG_GL3 0 +# define NANOVG_GLES2 0 +# define NANOVG_GLES3 0 +# define NANOVG_GL_USE_UNIFORMBUFFER 0 +# if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Weverything" +# elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wall" +# pragma GCC diagnostic ignored "-Wextra" +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Weffc++" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wundef" +# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +# endif +#endif + +// ----------------------------------------------------------------------- +// Include NanoVG OpenGL implementation -#define NANOVG_GL2_IMPLEMENTATION +#define NANOVG_GL2_IMPLEMENTATION 1 #include "nanovg/nanovg_gl.h" #if defined(NANOVG_GL2) @@ -36,6 +60,19 @@ # define nvgDeleteGL nvgDeleteGLES3 #endif +// ----------------------------------------------------------------------- +// Restore normal state if debugging + +#if 0//def DEBUG +# if defined(__clang__) +# pragma clang diagnostic pop +# elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic pop +# endif +#endif + +// ----------------------------------------------------------------------- + START_NAMESPACE_DGL // ----------------------------------------------------------------------- @@ -75,7 +112,8 @@ NanoVG::Paint::operator NVGpaint() const noexcept NanoImage::NanoImage(NVGcontext* const context, const int imageId) noexcept : fContext(context), fImageId(imageId), - fSize() + fSize(), + leakDetector_NanoImage() { _updateSize(); } @@ -114,7 +152,7 @@ void NanoImage::_updateSize() if (h < 0) h = 0; } - fSize.setSize(w, h); + fSize.setSize(static_cast<uint>(w), static_cast<uint>(h)); } // ----------------------------------------------------------------------- @@ -122,14 +160,16 @@ void NanoImage::_updateSize() NanoVG::NanoVG() : fContext(nvgCreateGL(512, 512, NVG_ANTIALIAS)), - fInFrame(false) + fInFrame(false), + leakDetector_NanoVG() { DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,); } NanoVG::NanoVG(const int textAtlasWidth, const int textAtlasHeight) : fContext(nvgCreateGL(textAtlasWidth, textAtlasHeight, NVG_ANTIALIAS)), - fInFrame(false) + fInFrame(false), + leakDetector_NanoVG() { DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr,); } @@ -151,7 +191,7 @@ void NanoVG::beginFrame(const uint width, const uint height, const float scaleFa DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); fInFrame = true; - nvgBeginFrame(fContext, width, height, scaleFactor, static_cast<NVGalpha>(alpha)); + nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor, static_cast<NVGalpha>(alpha)); } void NanoVG::beginFrame(Widget* const widget) @@ -163,7 +203,7 @@ void NanoVG::beginFrame(Widget* const widget) Window& window(widget->getParentWindow()); fInFrame = true; - nvgBeginFrame(fContext, window.getWidth(), window.getHeight(), 1.0f, NVG_PREMULTIPLIED_ALPHA); + nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f, NVG_PREMULTIPLIED_ALPHA); } void NanoVG::endFrame() @@ -209,7 +249,17 @@ void NanoVG::strokeColor(const Color& color) void NanoVG::strokeColor(const int red, const int green, const int blue, const int alpha) { if (fContext != nullptr) - nvgStrokeColor(fContext, nvgRGBA(red, green, blue, alpha)); + { + DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,); + + nvgStrokeColor(fContext, nvgRGBA(static_cast<uchar>(red), + static_cast<uchar>(green), + static_cast<uchar>(blue), + static_cast<uchar>(alpha))); + } } void NanoVG::strokeColor(const float red, const float green, const float blue, const float alpha) @@ -233,7 +283,17 @@ void NanoVG::fillColor(const Color& color) void NanoVG::fillColor(const int red, const int green, const int blue, const int alpha) { if (fContext != nullptr) - nvgFillColor(fContext, nvgRGBA(red, green, blue, alpha)); + { + DISTRHO_SAFE_ASSERT_RETURN(red >= 0 && red <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(green >= 0 && green <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(blue >= 0 && blue <= 255,); + DISTRHO_SAFE_ASSERT_RETURN(alpha >= 0 && alpha <= 255,); + + nvgFillColor(fContext, nvgRGBA(static_cast<uchar>(red), + static_cast<uchar>(green), + static_cast<uchar>(blue), + static_cast<uchar>(alpha))); + } } void NanoVG::fillColor(const float red, const float green, const float blue, const float alpha) @@ -427,7 +487,7 @@ NanoImage* NanoVG::createImageRGBA(uint w, uint h, const uchar* data) if (fContext == nullptr) return nullptr; DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr); - if (const int imageId = nvgCreateImageRGBA(fContext, w, h, data)) + if (const int imageId = nvgCreateImageRGBA(fContext, static_cast<int>(w), static_cast<int>(h), data)) return new NanoImage(fContext, imageId); return nullptr; @@ -576,13 +636,13 @@ NanoVG::FontId NanoVG::createFont(const char* name, const char* filename) return nvgCreateFont(fContext, name, filename); } -NanoVG::FontId NanoVG::createFontMem(const char* name, uchar* data, int ndata, bool freeData) +NanoVG::FontId NanoVG::createFontMem(const char* name, const uchar* data, int ndata, 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, data, ndata, freeData); + return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), ndata, freeData); } NanoVG::FontId NanoVG::findFont(const char* name) diff --git a/libs/dgl/src/Widget.cpp b/libs/dgl/src/Widget.cpp index 6013ea2..d2898b3 100644 --- a/libs/dgl/src/Widget.cpp +++ b/libs/dgl/src/Widget.cpp @@ -27,6 +27,7 @@ Widget::Widget(Window& parent) fNeedsFullViewport(false), fNeedsScaling(false), fVisible(true), + fId(0), fAbsolutePos(0, 0), fSize(0, 0), leakDetector_Widget() @@ -200,6 +201,16 @@ void Widget::repaint() noexcept fParent.repaint(); } +uint Widget::getId() const noexcept +{ + return fId; +} + +void Widget::setId(uint id) noexcept +{ + fId = id; +} + bool Widget::onKeyboard(const KeyboardEvent&) { return false; diff --git a/libs/dgl/src/Window.cpp b/libs/dgl/src/Window.cpp index e31b75c..c901ff2 100644 --- a/libs/dgl/src/Window.cpp +++ b/libs/dgl/src/Window.cpp @@ -15,11 +15,12 @@ */ // we need this for now -#define PUGL_GRAB_FOCUS 1 +//#define PUGL_GRAB_FOCUS 1 #include "AppPrivateData.hpp" #include "../Widget.hpp" #include "../Window.hpp" +#include "../../distrho/extra/d_string.hpp" #include "pugl/pugl.h" @@ -62,13 +63,15 @@ struct Window::PrivateData { PrivateData(App& app, Window* const self) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(false), fResizable(true), fUsingEmbed(false), fWidth(1), fHeight(1), + fTitle(nullptr), + fWidgets(), fModal(), #if defined(DISTRHO_OS_WINDOWS) hwnd(0), @@ -89,13 +92,15 @@ struct Window::PrivateData { PrivateData(App& app, Window* const self, Window& parent) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(false), fResizable(true), fUsingEmbed(false), fWidth(1), fHeight(1), + fTitle(nullptr), + fWidgets(), fModal(parent.pData), #if defined(DISTRHO_OS_WINDOWS) hwnd(0), @@ -112,23 +117,29 @@ struct Window::PrivateData { DBG("Creating window with parent..."); DBGF; init(); -#ifdef DISTRHO_OS_LINUX const PuglInternals* const parentImpl(parent.pData->fView->impl); - +#if defined(DISTRHO_OS_LINUX) XSetTransientForHint(xDisplay, xWindow, parentImpl->win); +//#elif defined(DISTRHO_OS_MAC) +// [parentImpl->window orderWindow:NSWindowBelow relativeTo:[[mView window] windowNumber]]; +#else + // unused + return; (void)parentImpl; #endif } PrivateData(App& app, Window* const self, const intptr_t parentId) : fApp(app), fSelf(self), - fView(puglInit(nullptr, nullptr)), + fView(puglInit()), fFirstInit(true), fVisible(parentId != 0), fResizable(parentId == 0), fUsingEmbed(parentId != 0), fWidth(1), fHeight(1), + fTitle(nullptr), + fWidgets(), fModal(), #if defined(DISTRHO_OS_WINDOWS) hwnd(0), @@ -136,7 +147,7 @@ struct Window::PrivateData { xDisplay(nullptr), xWindow(0), #elif defined(DISTRHO_OS_MAC) - fNeedsIdle(false), + fNeedsIdle(parentId == 0), mView(nullptr), mWindow(nullptr), #endif @@ -172,7 +183,7 @@ struct Window::PrivateData { } puglInitResizable(fView, fResizable); - puglInitWindowSize(fView, fWidth, fHeight); + puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); puglSetHandle(fView, this); puglSetDisplayFunc(fView, onDisplayCallback); @@ -183,6 +194,7 @@ struct Window::PrivateData { puglSetSpecialFunc(fView, onSpecialCallback); puglSetReshapeFunc(fView, onReshapeCallback); puglSetCloseFunc(fView, onCloseCallback); + puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); puglCreateWindow(fView, nullptr); @@ -221,7 +233,12 @@ struct Window::PrivateData { { DBG("Destroying window..."); DBGF; - //fOnModal = false; + if (fModal.enabled) + { + exec_fini(); + close(); + } + fWidgets.clear(); if (fUsingEmbed) @@ -444,7 +461,11 @@ struct Window::PrivateData { fResizable = yesNo; -#ifdef CARLA_OS_MAC +#if defined(DISTRHO_OS_WINDOWS) + const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX + : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX; + SetWindowLong(hwnd, GWL_STYLE, winFlags); +#elif defined(DISTRHO_OS_MAC) // FIXME? const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0); [mView setAutoresizingMask:flags]; @@ -457,7 +478,7 @@ struct Window::PrivateData { void setSize(uint width, uint height, const bool forced = false) { - if (width == 0 || height == 0) + if (width <= 1 || height <= 1) { DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height); return; @@ -472,18 +493,15 @@ struct Window::PrivateData { fWidth = width; fHeight = height; - DBGp("Window setSize called %s, size %i %i\n", forced ? "(forced)" : "(not forced)", width, height); + DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false"); #if defined(DISTRHO_OS_WINDOWS) - int winFlags = WS_POPUPWINDOW | WS_CAPTION; - - if (fResizable) - winFlags |= WS_SIZEBOX; - + const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0); RECT wr = { 0, 0, static_cast<long>(width), static_cast<long>(height) }; - AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); + AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); - SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); + SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, + SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); if (! forced) UpdateWindow(hwnd); @@ -522,10 +540,22 @@ struct Window::PrivateData { // ------------------------------------------------------------------- + const char* getTitle() const noexcept + { + static const char* const kFallback = ""; + + return fTitle != nullptr ? fTitle : kFallback; + } + void setTitle(const char* const title) { DBGp("Window setTitle \"%s\"\n", title); + if (fTitle != nullptr) + std::free(fTitle); + + fTitle = strdup(title); + #if defined(DISTRHO_OS_WINDOWS) SetWindowTextA(hwnd, title); #elif defined(DISTRHO_OS_MAC) @@ -543,7 +573,7 @@ struct Window::PrivateData { #endif } - void setTransientWinId(const intptr_t winId) + void setTransientWinId(const uintptr_t winId) { #if defined(DISTRHO_OS_LINUX) XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId)); @@ -600,7 +630,7 @@ struct Window::PrivateData { // ------------------------------------------------------------------- - void onDisplay() + void onPuglDisplay() { fSelf->onDisplayBefore(); @@ -618,22 +648,35 @@ struct Window::PrivateData { if (widget->fNeedsFullViewport || (widget->fAbsolutePos.isZero() && widget->fSize == Size<uint>(fWidth, fHeight))) { // full viewport size - glViewport(0, 0, fWidth, fHeight); + glViewport(0, + 0, + static_cast<GLsizei>(fWidth), + static_cast<GLsizei>(fHeight)); } else if (! widget->fNeedsScaling) { // only set viewport pos - glViewport(widget->getAbsoluteX(), /*fView->height - widget->getHeight()*/ - widget->getAbsoluteY(), fWidth, fHeight); + 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 - widget->getHeight() - widget->getAbsoluteY(), widget->getWidth(), widget->getHeight()); + 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 - widget->getHeight() - widget->getAbsoluteY(), widget->getWidth(), widget->getHeight()); + glViewport(widget->getAbsoluteX(), + fView->height - static_cast<int>(widget->getHeight()) - widget->getAbsoluteY(), + static_cast<GLsizei>(widget->getWidth()), + static_cast<GLsizei>(widget->getHeight())); } // display widget @@ -650,7 +693,7 @@ struct Window::PrivateData { fSelf->onDisplayAfter(); } - void onKeyboard(const bool press, const uint key) + void onPuglKeyboard(const bool press, const uint key) { DBGp("PUGL: onKeyboard : %i %i\n", press, key); @@ -672,7 +715,7 @@ struct Window::PrivateData { } } - void onSpecial(const bool press, const Key key) + void onPuglSpecial(const bool press, const Key key) { DBGp("PUGL: onSpecial : %i %i\n", press, key); @@ -681,9 +724,9 @@ struct Window::PrivateData { Widget::SpecialEvent ev; ev.press = press; - ev.key = key; - ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); + ev.key = key; + ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); + ev.time = puglGetEventTimestamp(fView); FOR_EACH_WIDGET_INV(rit) { @@ -694,18 +737,21 @@ struct Window::PrivateData { } } - void onMouse(const int button, const bool press, const int x, const int y) + void onPuglMouse(const int button, const bool press, const int x, const int y) { DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y); + // FIXME - pugl sends 2 of these for each window on init, don't ask me why. we'll ignore it + if (press && button == 0 && x == 0 && y == 0) return; + if (fModal.childFocus != nullptr) return fModal.childFocus->focus(); Widget::MouseEvent ev; ev.button = button; - ev.press = press; - ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); - ev.time = puglGetEventTimestamp(fView); + ev.press = press; + ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); + ev.time = puglGetEventTimestamp(fView); FOR_EACH_WIDGET_INV(rit) { @@ -718,7 +764,7 @@ struct Window::PrivateData { } } - void onMotion(const int x, const int y) + void onPuglMotion(const int x, const int y) { DBGp("PUGL: onMotion : %i %i\n", x, y); @@ -740,7 +786,7 @@ struct Window::PrivateData { } } - void onScroll(const int x, const int y, const float dx, const float dy) + void onPuglScroll(const int x, const int y, const float dx, const float dy) { DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy); @@ -763,38 +809,38 @@ struct Window::PrivateData { } } - void onReshape(const int width, const int height) + void onPuglReshape(const int width, const int height) { DBGp("PUGL: onReshape : %i %i\n", width, height); - if (width == 1 && height == 1) + if (width <= 1 && height <= 1) return; - fWidth = width; - fHeight = height; + fWidth = static_cast<uint>(width); + fHeight = static_cast<uint>(height); - fSelf->onReshape(width, height); + fSelf->onReshape(fWidth, fHeight); FOR_EACH_WIDGET(it) { Widget* const widget(*it); if (widget->fNeedsFullViewport) - widget->setSize(width, height); + widget->setSize(fWidth, fHeight); } } - void onClose() + void onPuglClose() { DBG("PUGL: onClose\n"); - if (fModal.enabled && fModal.parent != nullptr) + if (fModal.enabled) exec_fini(); fSelf->onClose(); if (fModal.childFocus != nullptr) - fModal.childFocus->onClose(); + fModal.childFocus->fSelf->onClose(); close(); } @@ -811,6 +857,7 @@ struct Window::PrivateData { bool fUsingEmbed; uint fWidth; uint fHeight; + char* fTitle; std::list<Widget*> fWidgets; struct Modal { @@ -833,6 +880,8 @@ struct Window::PrivateData { DISTRHO_SAFE_ASSERT(! enabled); DISTRHO_SAFE_ASSERT(childFocus == nullptr); } + + DISTRHO_DECLARE_NON_COPY_STRUCT(Modal) } fModal; #if defined(DISTRHO_OS_WINDOWS) @@ -853,42 +902,47 @@ struct Window::PrivateData { static void onDisplayCallback(PuglView* view) { - handlePtr->onDisplay(); + handlePtr->onPuglDisplay(); } static void onKeyboardCallback(PuglView* view, bool press, uint32_t key) { - handlePtr->onKeyboard(press, key); + handlePtr->onPuglKeyboard(press, key); } static void onSpecialCallback(PuglView* view, bool press, PuglKey key) { - handlePtr->onSpecial(press, static_cast<Key>(key)); + handlePtr->onPuglSpecial(press, static_cast<Key>(key)); } static void onMouseCallback(PuglView* view, int button, bool press, int x, int y) { - handlePtr->onMouse(button, press, x, y); + handlePtr->onPuglMouse(button, press, x, y); } static void onMotionCallback(PuglView* view, int x, int y) { - handlePtr->onMotion(x, y); + handlePtr->onPuglMotion(x, y); } static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy) { - handlePtr->onScroll(x, y, dx, dy); + handlePtr->onPuglScroll(x, y, dx, dy); } static void onReshapeCallback(PuglView* view, int width, int height) { - handlePtr->onReshape(width, height); + handlePtr->onPuglReshape(width, height); } static void onCloseCallback(PuglView* view) { - handlePtr->onClose(); + handlePtr->onPuglClose(); + } + + static void fileBrowserSelectedCallback(PuglView* view, const char* filename) + { + handlePtr->fSelf->fileBrowserSelected(filename); } #undef handlePtr @@ -900,13 +954,16 @@ struct Window::PrivateData { // Window Window::Window(App& app) - : pData(new PrivateData(app, this)) {} + : pData(new PrivateData(app, this)), + leakDetector_Window() {} Window::Window(App& app, Window& parent) - : pData(new PrivateData(app, this, parent)) {} + : pData(new PrivateData(app, this, parent)), + leakDetector_Window() {} Window::Window(App& app, intptr_t parentId) - : pData(new PrivateData(app, this, parentId)) {} + : pData(new PrivateData(app, this, parentId)), + leakDetector_Window() {} Window::~Window() { @@ -943,6 +1000,73 @@ void Window::repaint() noexcept puglPostRedisplay(pData->fView); } +// static int fib_filter_filename_filter(const char* const name) +// { +// return 1; +// (void)name; +// } + +bool Window::openFileBrowser(const FileBrowserOptions& options) +{ + using DISTRHO_NAMESPACE::d_string; + + // -------------------------------------------------------------------------- + // configure start dir + + // TODO: get abspath if needed + // TODO: cross-platform + + d_string startDir(options.startDir); + + if (startDir.isEmpty()) + { + if (char* const dir_name = get_current_dir_name()) + { + startDir = dir_name; + std::free(dir_name); + } + } + + DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); + + if (! startDir.endsWith('/')) + startDir += "/"; + + DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); + + // -------------------------------------------------------------------------- + // configure title + + d_string title(options.title); + + if (title.isEmpty()) + { + title = pData->getTitle(); + + if (title.isEmpty()) + title = "FileBrowser"; + } + + DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); + + // -------------------------------------------------------------------------- + // configure filters + + x_fib_cfg_filter_callback(nullptr); //fib_filter_filename_filter); + + // -------------------------------------------------------------------------- + // configure buttons + + x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); + x_fib_cfg_buttons(1, options.buttons.showHidden-1); + x_fib_cfg_buttons(2, options.buttons.showPlaces-1); + + // -------------------------------------------------------------------------- + // show + + return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0); +} + bool Window::isVisible() const noexcept { return pData->fVisible; @@ -988,12 +1112,17 @@ void Window::setSize(Size<uint> size) pData->setSize(size.getWidth(), size.getHeight()); } +const char* Window::getTitle() const noexcept +{ + return pData->getTitle(); +} + void Window::setTitle(const char* title) { pData->setTitle(title); } -void Window::setTransientWinId(intptr_t winId) +void Window::setTransientWinId(uintptr_t winId) { pData->setTransientWinId(winId); } @@ -1057,8 +1186,8 @@ void Window::onReshape(uint width, uint height) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, width, height, 0, 0.0f, 1.0f); - glViewport(0, 0, width, height); + glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0); + glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } @@ -1067,6 +1196,10 @@ void Window::onClose() { } +void Window::fileBrowserSelected(const char*) +{ +} + // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/libs/dgl/src/nanovg/fontstash.h b/libs/dgl/src/nanovg/fontstash.h index 7fb8955..a97ce53 100644 --- a/libs/dgl/src/nanovg/fontstash.h +++ b/libs/dgl/src/nanovg/fontstash.h @@ -41,7 +41,7 @@ enum FONSalign { enum FONSerrorCode { // Font atlas is full. FONS_ATLAS_FULL = 1, - // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE. + // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE. FONS_SCRATCH_FULL = 2, // Calls to fonsPushState has craeted too large stack, if you need deep state stack bump up FONS_MAX_STATES. FONS_STATES_OVERFLOW = 3, @@ -85,7 +85,7 @@ void fonsDeleteInternal(struct FONScontext* s); void fonsSetErrorCallback(struct FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr); // Returns current atlas size. void fonsGetAtlasSize(struct FONScontext* s, int* width, int* height); -// Expands the atlas size. +// Expands the atlas size. int fonsExpandAtlas(struct FONScontext* s, int width, int height); // Reseta the whole stash. int fonsResetAtlas(struct FONScontext* stash, int width, int height); @@ -1388,7 +1388,7 @@ void fonsDrawDebug(struct FONScontext* stash, float x, float y) } float fonsTextBounds(struct FONScontext* stash, - float x, float y, + float x, float y, const char* str, const char* end, float* bounds) { @@ -1576,7 +1576,7 @@ int fonsExpandAtlas(struct FONScontext* stash, int width, int height) height = fons__maxi(height, stash->params.height); if (width == stash->params.width && height == stash->params.height) - return 1; + return 1; // Flush pending glyphs. fons__flush(stash); diff --git a/libs/dgl/src/pugl/pugl.h b/libs/dgl/src/pugl/pugl.h index 360f8e8..7cd8b84 100644 --- a/libs/dgl/src/pugl/pugl.h +++ b/libs/dgl/src/pugl/pugl.h @@ -51,7 +51,11 @@ # define PUGL_API PUGL_LIB_IMPORT # endif #else -# define PUGL_API +# ifdef _WIN32 +# define PUGL_API +# else +# define PUGL_API __attribute__((visibility("hidden"))) +# endif #endif #ifdef __cplusplus @@ -196,19 +200,18 @@ typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); so programs should handle any value gracefully. @param view The view being scrolled. + @param x The window-relative x coordinate of the pointer. + @param y The window-relative y coordinate of the pointer. @param dx The scroll x distance. @param dx The scroll y distance. */ -typedef void (*PuglScrollFunc)(PuglView* view, - int x, - int y, - float dx, - float dy); +typedef void (*PuglScrollFunc)(PuglView* view, int x, int y, float dx, float dy); /** A function called when a special key is pressed or released. This callback allows the use of keys that do not have unicode points. + Note that some are non-printable keys. @param view The view the event occured in. @param press True if the key was pressed, false if released. @@ -217,16 +220,21 @@ typedef void (*PuglScrollFunc)(PuglView* view, typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); /** + A function called when a filename is selected via file-browser. + + @param view The view the event occured in. + @param filename The selected file name or NULL if the dialog was canceled. +*/ +typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); + +/** Create a Pugl context. To create a window, call the various puglInit* functions as necessary, then call puglCreateWindow(). - - @param pargc Pointer to argument count (unused, for GLUT compatibility). - @param argv Arguments (unused, for GLUT compatibility). */ PUGL_API PuglView* -puglInit(int* pargc, char** argv); +puglInit(void); /** Set the parent window before creating a window (for embedding). @@ -244,7 +252,7 @@ puglInitWindowSize(PuglView* view, int width, int height); Enable or disable resizing before creating a window. */ PUGL_API void -puglInitResizable(PuglView* view, bool resizable); +puglInitUserResizable(PuglView* view, bool resizable); /** Create a window with the settings given by the various puglInit functions. @@ -353,6 +361,12 @@ PUGL_API void puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); /** + Set the function to call on file-browser selections. +*/ +PUGL_API void +puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); + +/** Return the native window handle. */ PUGL_API PuglNativeWindow diff --git a/libs/dgl/src/pugl/pugl_internal.h b/libs/dgl/src/pugl/pugl_internal.h index 1f75830..7301091 100644 --- a/libs/dgl/src/pugl/pugl_internal.h +++ b/libs/dgl/src/pugl/pugl_internal.h @@ -51,9 +51,9 @@ struct PuglViewImpl { PuglReshapeFunc reshapeFunc; PuglScrollFunc scrollFunc; PuglSpecialFunc specialFunc; + PuglFileSelectedFunc fileSelectedFunc; PuglInternals* impl; - PuglNativeWindow parent; int width; @@ -66,12 +66,10 @@ struct PuglViewImpl { uint32_t event_timestamp_ms; }; -PuglInternals* puglInitInternals(); - -void puglDefaultReshape(PuglView* view, int width, int height); +PuglInternals* puglInitInternals(void); PuglView* -puglInit(int* pargc, char** argv) +puglInit(void) { PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); if (!view) { @@ -80,6 +78,7 @@ puglInit(int* pargc, char** argv) PuglInternals* impl = puglInitInternals(); if (!impl) { + free(view); return NULL; } @@ -88,9 +87,6 @@ puglInit(int* pargc, char** argv) view->height = 480; return view; - - // unused - (void)pargc; (void)argv; } void @@ -136,7 +132,7 @@ puglGetModifiers(PuglView* view) return view->mods; } -void +static void puglDefaultReshape(PuglView* view, int width, int height) { glMatrixMode(GL_PROJECTION); @@ -205,3 +201,9 @@ puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) { view->specialFunc = specialFunc; } + +void +puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc) +{ + view->fileSelectedFunc = fileSelectedFunc; +} diff --git a/libs/dgl/src/pugl/pugl_osx.m b/libs/dgl/src/pugl/pugl_osx.m index 96aa57a..a99d8d0 100644 --- a/libs/dgl/src/pugl/pugl_osx.m +++ b/libs/dgl/src/pugl/pugl_osx.m @@ -35,6 +35,7 @@ backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; - (void) setPuglview:(PuglView*)view; +- (BOOL) canBecomeKeyWindow; - (BOOL) windowShouldClose:(id)sender; @end @@ -54,7 +55,7 @@ [result setAcceptsMouseMovedEvents:YES]; [result setLevel: CGShieldingWindowLevel() + 1]; - return result; + return (PuglWindow*)result; // unused (void)aStyle; (void)bufferingType; (void)flag; @@ -66,6 +67,11 @@ [self setContentSize:NSMakeSize(view->width, view->height)]; } +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + - (BOOL)windowShouldClose:(id)sender { if (puglview->closeFunc) @@ -81,6 +87,7 @@ static void puglDisplay(PuglView* view) { + view->redisplay = false; if (view->displayFunc) { view->displayFunc(view); } @@ -88,28 +95,33 @@ puglDisplay(PuglView* view) @interface PuglOpenGLView : NSOpenGLView { - int colorBits; - int depthBits; @public PuglView* puglview; - NSTrackingArea* trackingArea; + bool doubleBuffered; } -- (id) initWithFrame:(NSRect)frame - colorBits:(int)numColorBits - depthBits:(int)numDepthBits; +- (BOOL) acceptsFirstMouse:(NSEvent*)e; +- (BOOL) acceptsFirstResponder; +- (BOOL) isFlipped; +- (BOOL) isOpaque; +- (BOOL) preservesContentInLiveResize; +- (id) initWithFrame:(NSRect)frame; - (void) reshape; -- (void) drawRect:(NSRect)rect; -- (void) mouseEntered:(NSEvent*)event; -- (void) mouseExited:(NSEvent*)event; +- (void) drawRect:(NSRect)r; +- (void) cursorUpdate:(NSEvent*)e; +- (void) updateTrackingAreas; +- (void) viewWillMoveToWindow:(NSWindow*)newWindow; - (void) mouseMoved:(NSEvent*)event; - (void) mouseDragged:(NSEvent*)event; - (void) rightMouseDragged:(NSEvent*)event; +- (void) otherMouseDragged:(NSEvent*)event; - (void) mouseDown:(NSEvent*)event; -- (void) mouseUp:(NSEvent*)event; - (void) rightMouseDown:(NSEvent*)event; +- (void) otherMouseDown:(NSEvent*)event; +- (void) mouseUp:(NSEvent*)event; - (void) rightMouseUp:(NSEvent*)event; +- (void) otherMouseUp:(NSEvent*)event; - (void) scrollWheel:(NSEvent*)event; - (void) keyDown:(NSEvent*)event; - (void) keyUp:(NSEvent*)event; @@ -119,22 +131,46 @@ puglDisplay(PuglView* view) @implementation PuglOpenGLView +- (BOOL) acceptsFirstMouse:(NSEvent*)e +{ + return YES; + + // unused + (void)e; +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (BOOL) isFlipped +{ + return YES; +} + +- (BOOL) isOpaque +{ + return YES; +} + +- (BOOL) preservesContentInLiveResize +{ + return NO; +} + - (id) initWithFrame:(NSRect)frame - colorBits:(int)numColorBits - depthBits:(int)numDepthBits { - colorBits = numColorBits; - depthBits = numDepthBits; - puglview = nil; - trackingArea = nil; + puglview = nil; + trackingArea = nil; + doubleBuffered = true; - NSOpenGLPixelFormatAttribute pixelAttribs[16] = { + NSOpenGLPixelFormatAttribute pixelAttribs[] = { + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 16, NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, - NSOpenGLPFAColorSize, - colorBits, - NSOpenGLPFADepthSize, - depthBits, 0 }; @@ -144,12 +180,21 @@ puglDisplay(PuglView* view) if (pixelFormat) { self = [super initWithFrame:frame pixelFormat:pixelFormat]; [pixelFormat release]; - if (self) { - [[self openGLContext] makeCurrentContext]; - [self reshape]; - } + printf("Is doubleBuffered? TRUE\n"); } else { - self = nil; + self = [super initWithFrame:frame]; + doubleBuffered = false; + printf("Is doubleBuffered? FALSE\n"); + } + + if (self) { + NSOpenGLContext* context = [self openGLContext]; + [context makeCurrentContext]; + + GLint swapInterval = 1; + [context setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; + + [self reshape]; } return self; @@ -159,156 +204,180 @@ puglDisplay(PuglView* view) { [[self openGLContext] update]; - NSRect bounds = [self bounds]; - int width = bounds.size.width; - int height = bounds.size.height; - - if (puglview) { + if (!puglview) { /* NOTE: Apparently reshape gets called when the GC gets around to deleting the view (?), so we must have reset puglview to NULL when this comes around. */ - if (puglview->reshapeFunc) { - puglview->reshapeFunc(puglview, width, height); - } else { - puglDefaultReshape(puglview, width, height); - } + return; + } + + NSRect bounds = [self bounds]; + int width = bounds.size.width; + int height = bounds.size.height; - puglview->width = width; - puglview->height = height; + if (puglview->reshapeFunc) { + puglview->reshapeFunc(puglview, width, height); + } else { + puglDefaultReshape(puglview, width, height); } + + puglview->width = width; + puglview->height = height; } -- (void) drawRect:(NSRect)rect +- (void) drawRect:(NSRect)r { puglDisplay(puglview); - glFlush(); - glSwapAPPLE(); + + if (doubleBuffered) { + [[self openGLContext] flushBuffer]; + } else { + glFlush(); + //glSwapAPPLE(); + } // unused - return; (void)rect; + return; (void)r; } -static unsigned -getModifiers(PuglView* view, NSEvent* ev) +- (void) cursorUpdate:(NSEvent*)e { - const unsigned modifierFlags = [ev modifierFlags]; + [[NSCursor arrowCursor] set]; - view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); - - unsigned mods = 0; - mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; - mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; - mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; - mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; - return mods; + // unused + return; (void)e; } --(void)updateTrackingAreas +- (void) updateTrackingAreas { + static const int opts = NSTrackingMouseEnteredAndExited + | NSTrackingMouseMoved + | NSTrackingEnabledDuringMouseDrag + | NSTrackingInVisibleRect + | NSTrackingActiveAlways + | NSTrackingCursorUpdate; + if (trackingArea != nil) { [self removeTrackingArea:trackingArea]; [trackingArea release]; } - const int opts = (NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved | - NSTrackingActiveAlways); - trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; } -- (void)mouseEntered:(NSEvent*)theEvent +- (void) viewWillMoveToWindow:(NSWindow*)newWindow { - [self updateTrackingAreas]; + if (newWindow != nil) { + [newWindow setAcceptsMouseMovedEvents:YES]; + [newWindow makeFirstResponder:self]; + } - // unused - return; (void)theEvent; + [super viewWillMoveToWindow:newWindow]; } -- (void)mouseExited:(NSEvent*)theEvent +static unsigned +getModifiers(PuglView* view, NSEvent* ev) { - // unused - return; (void)theEvent; + const unsigned modifierFlags = [ev modifierFlags]; + + view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); + + unsigned mods = 0; + mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; + mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; + mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; + mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; + return mods; +} + +static int +getFixedAppKitButton(NSInteger button) +{ + switch (button) { + case 0: return 1; + case 1: return 3; + case 2: return 2; + default: return button; + } } - (void) mouseMoved:(NSEvent*)event { if (puglview->motionFunc) { - NSPoint loc = [event locationInWindow]; + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; puglview->mods = getModifiers(puglview, event); - puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); + puglview->motionFunc(puglview, loc.x, loc.y); } } - (void) mouseDragged:(NSEvent*)event { - if (puglview->motionFunc) { - NSPoint loc = [event locationInWindow]; - puglview->mods = getModifiers(puglview, event); - puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); - } + [self mouseMoved:event]; } - (void) rightMouseDragged:(NSEvent*)event { - if (puglview->motionFunc) { - NSPoint loc = [event locationInWindow]; - puglview->mods = getModifiers(puglview, event); - puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); - } + [self mouseDragged:event]; } -- (void) mouseDown:(NSEvent*)event +- (void) otherMouseDragged:(NSEvent*)event { - if (puglview->mouseFunc) { - NSPoint loc = [event locationInWindow]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, 1, true, loc.x, puglview->height - loc.y); - } + [self mouseDragged:event]; } -- (void) mouseUp:(NSEvent*)event +- (void) mouseDown:(NSEvent*)event { if (puglview->mouseFunc) { - NSPoint loc = [event locationInWindow]; + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, 1, false, loc.x, puglview->height - loc.y); + puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), true, loc.x, loc.y); } - [self updateTrackingAreas]; } - (void) rightMouseDown:(NSEvent*)event { + [self mouseDown:event]; +} + +- (void) otherMouseDown:(NSEvent*)event +{ + [self mouseDown:event]; +} + +- (void) mouseUp:(NSEvent*)event +{ if (puglview->mouseFunc) { - NSPoint loc = [event locationInWindow]; + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, 3, true, loc.x, puglview->height - loc.y); + puglview->mouseFunc(puglview, getFixedAppKitButton([event buttonNumber]), false, loc.x, loc.y); } } - (void) rightMouseUp:(NSEvent*)event { - if (puglview->mouseFunc) { - NSPoint loc = [event locationInWindow]; - puglview->mods = getModifiers(puglview, event); - puglview->mouseFunc(puglview, 3, false, loc.x, puglview->height - loc.y); - } + [self mouseUp:event]; +} + +- (void) otherMouseUp:(NSEvent*)event +{ + [self mouseUp:event]; } - (void) scrollWheel:(NSEvent*)event { if (puglview->scrollFunc) { - NSPoint loc = [event locationInWindow]; + NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; puglview->mods = getModifiers(puglview, event); puglview->scrollFunc(puglview, - loc.x, puglview->height - loc.y, + loc.x, loc.y, [event deltaX], [event deltaY]); } - [self updateTrackingAreas]; } - (void) keyDown:(NSEvent*)event @@ -368,6 +437,11 @@ puglCreateWindow(PuglView* view, const char* title) [NSApplication sharedApplication]; impl->glview = [PuglOpenGLView new]; + + if (!impl->glview) { + return 1; + } + impl->glview->puglview = view; if (view->resizable) { @@ -375,6 +449,7 @@ puglCreateWindow(PuglView* view, const char* title) } if (view->parent) { + [impl->glview retain]; NSView* pview = (NSView*)view->parent; [pview addSubview:impl->glview]; return 0; @@ -451,15 +526,17 @@ puglDestroy(PuglView* view) PuglStatus puglProcessEvents(PuglView* view) { - [view->impl->glview setNeedsDisplay: YES]; - return PUGL_SUCCESS; + + // unused + (void)view; } void puglPostRedisplay(PuglView* view) { view->redisplay = true; + [view->impl->glview setNeedsDisplay:YES]; } PuglNativeWindow diff --git a/libs/dgl/src/pugl/pugl_win.cpp b/libs/dgl/src/pugl/pugl_win.cpp index 9837671..0837ac1 100644 --- a/libs/dgl/src/pugl/pugl_win.cpp +++ b/libs/dgl/src/pugl/pugl_win.cpp @@ -22,6 +22,7 @@ #include <windowsx.h> #include <GL/gl.h> +#include <ctime> #include <stdio.h> #include <stdlib.h> @@ -37,7 +38,7 @@ # define WHEEL_DELTA 120 #endif -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) +const int LOCAL_CLOSE_MSG = WM_USER + 50; HINSTANCE hInstance = NULL; @@ -51,6 +52,7 @@ struct PuglInternalsImpl { LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +#if 0 extern "C" { BOOL WINAPI DllMain(HINSTANCE hInst, DWORD, LPVOID) @@ -59,6 +61,7 @@ DllMain(HINSTANCE hInst, DWORD, LPVOID) return 1; } } // extern "C" +#endif PuglInternals* puglInitInternals() @@ -79,7 +82,9 @@ puglCreateWindow(PuglView* view, const char* title) // Should class be a parameter? Does this make sense on other platforms? static int wc_count = 0; char classNameBuf[256]; - _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++); + std::srand((std::time(NULL))); + _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d-%d", title, std::rand(), ++wc_count); + classNameBuf[sizeof(classNameBuf)-1] = '\0'; impl->wc.style = CS_OWNDC; impl->wc.lpfnWndProc = wndProc; @@ -90,36 +95,36 @@ puglCreateWindow(PuglView* view, const char* title) impl->wc.hCursor = LoadCursor(hInstance, IDC_ARROW); impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); impl->wc.lpszMenuName = NULL; - impl->wc.lpszClassName = classNameBuf; - RegisterClass(&impl->wc); + impl->wc.lpszClassName = strdup(classNameBuf); - int winFlags = WS_POPUPWINDOW | WS_CAPTION; - if (view->resizable) { - winFlags |= WS_SIZEBOX; + if (!RegisterClass(&impl->wc)) { + free((void*)impl->wc.lpszClassName); + free(impl); + free(view); + 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); RECT wr = { 0, 0, view->width, view->height }; - AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); + AdjustWindowRectEx(&wr, view->parent ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); impl->hwnd = CreateWindowEx( WS_EX_TOPMOST, classNameBuf, title, - view->parent ? WS_CHILD : winFlags, + view->parent ? (WS_CHILD | WS_VISIBLE) : winFlags, CW_USEDEFAULT, CW_USEDEFAULT, wr.right-wr.left, wr.bottom-wr.top, (HWND)view->parent, NULL, hInstance, NULL); if (!impl->hwnd) { + UnregisterClass(impl->wc.lpszClassName, NULL); + free((void*)impl->wc.lpszClassName); free(impl); free(view); return 1; } -#ifdef _WIN64 SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); -#else - SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view); -#endif impl->hdc = GetDC(impl->hwnd); @@ -137,6 +142,16 @@ puglCreateWindow(PuglView* view, const char* title) SetPixelFormat(impl->hdc, format, &pfd); impl->hglrc = wglCreateContext(impl->hdc); + if (!impl->hglrc) { + ReleaseDC (impl->hwnd, impl->hdc); + DestroyWindow (impl->hwnd); + UnregisterClass (impl->wc.lpszClassName, NULL); + free((void*)impl->wc.lpszClassName); + free(impl); + free(view); + return 1; + } + wglMakeCurrent(impl->hdc, impl->hglrc); return 0; @@ -166,6 +181,7 @@ puglDestroy(PuglView* view) ReleaseDC(view->impl->hwnd, view->impl->hdc); DestroyWindow(view->impl->hwnd); UnregisterClass(view->impl->wc.lpszClassName, NULL); + free((void*)view->impl->wc.lpszClassName); free(view->impl); free(view); } @@ -190,13 +206,13 @@ puglDisplay(PuglView* view) { wglMakeCurrent(view->impl->hdc, view->impl->hglrc); + view->redisplay = false; if (view->displayFunc) { view->displayFunc(view); } glFlush(); SwapBuffers(view->impl->hdc); - view->redisplay = false; } static PuglKey @@ -309,17 +325,21 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) case WM_MOUSEWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ScreenToClient(view->impl->hwnd, &pt); view->scrollFunc( - view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), - 0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); + view, pt.x, pt.y, + 0, GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA); } break; case WM_MOUSEHWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); + POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; + ScreenToClient(view->impl->hwnd, &pt); view->scrollFunc( - view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), - (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); + view, pt.x, pt.y, + GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0); } break; case WM_KEYDOWN: @@ -333,11 +353,18 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) view->specialFunc(view, message == WM_KEYDOWN, key); } } else if (view->keyboardFunc) { - view->keyboardFunc(view, message == WM_KEYDOWN, wParam); + static BYTE kbs[256]; + if (GetKeyboardState(kbs) != FALSE) { + char lb[2]; + UINT scanCode = (lParam >> 8) & 0xFFFFFF00; + if ( 1 == ToAscii(wParam, scanCode, kbs, (LPWORD)lb, 0)) { + view->keyboardFunc(view, message == WM_KEYDOWN, (char)lb[0]); + } + } } break; case WM_QUIT: - case PUGL_LOCAL_CLOSE_MSG: + case LOCAL_CLOSE_MSG: if (view->closeFunc) { view->closeFunc(view); } @@ -358,7 +385,6 @@ puglProcessEvents(PuglView* view) handleMessage(view, msg.message, msg.wParam, msg.lParam); } - if (view->redisplay) { InvalidateRect(view->impl->hwnd, NULL, FALSE); } @@ -369,23 +395,19 @@ puglProcessEvents(PuglView* view) LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { -#ifdef _WIN64 PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); -#else - PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA); -#endif switch (message) { case WM_CREATE: PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); return 0; case WM_CLOSE: - PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); + PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam); return 0; case WM_DESTROY: return 0; default: - if (view) { + if (view && hwnd == view->impl->hwnd) { return handleMessage(view, message, wParam, lParam); } else { return DefWindowProc(hwnd, message, wParam, lParam); diff --git a/libs/dgl/src/pugl/pugl_x11.c b/libs/dgl/src/pugl/pugl_x11.c index fdba1b6..eac570c 100644 --- a/libs/dgl/src/pugl/pugl_x11.c +++ b/libs/dgl/src/pugl/pugl_x11.c @@ -1,6 +1,7 @@ /* Copyright 2012-2014 David Robillard <http://drobilla.net> Copyright 2011-2012 Ben Loftis, Harrison Consoles + Copyright 2013 Robin Gareus <robin@gareus.org> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -31,6 +32,10 @@ #include "pugl_internal.h" +#define SOFD_HAVE_X11 +#include "../sofd/libsofd.h" +#include "../sofd/libsofd.c" + struct PuglInternalsImpl { Display* display; int screen; @@ -49,6 +54,7 @@ static int attrListSgl[] = { GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, + GLX_ARB_multisample, 1, None }; @@ -62,11 +68,29 @@ static int attrListDbl[] = { 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 }; PuglInternals* -puglInitInternals() +puglInitInternals(void) { return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } @@ -76,17 +100,21 @@ puglCreateWindow(PuglView* view, const char* title) { PuglInternals* impl = view->impl; - impl->display = XOpenDisplay(0); + 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* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); if (!vi) { vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); impl->doubleBuffered = False; - PUGL_LOG("No double buffering available\n"); - } else { - impl->doubleBuffered = True; - PUGL_LOG("Double buffered rendering enabled\n"); + PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); } int glxMajor, glxMinor; @@ -202,16 +230,17 @@ puglDisplay(PuglView* view) { glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); + view->redisplay = false; + if (view->displayFunc) { view->displayFunc(view); } glFlush(); + if (view->impl->doubleBuffered) { glXSwapBuffers(view->impl->display, view->impl->win); } - - view->redisplay = false; } static PuglKey @@ -269,9 +298,16 @@ dispatchKey(PuglView* view, XEvent* event, bool press) KeySym sym; char str[5]; const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); + + if (sym == XK_Escape && view->closeFunc && !press && !view->parent) { + view->closeFunc(view); + view->redisplay = false; + return; + } if (n == 0) { return; - } else if (n > 1) { + } + if (n > 1) { fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); return; } @@ -290,6 +326,26 @@ puglProcessEvents(PuglView* view) XEvent event; while (XPending(view->impl->display) > 0) { XNextEvent(view->impl->display, &event); + + if (x_fib_handle_events(view->impl->display, &event)) { + const int status = x_fib_status(); + + if (status > 0) { + char* const filename = x_fib_filename(); + x_fib_close(view->impl->display); + if (view->fileSelectedFunc) { + view->fileSelectedFunc(view, filename); + } + free(filename); + } else if (status < 0) { + x_fib_close(view->impl->display); + if (view->fileSelectedFunc) { + view->fileSelectedFunc(view, NULL); + } + } + break; + } + switch (event.type) { case MapNotify: puglReshape(view, view->width, view->height); @@ -325,9 +381,7 @@ puglProcessEvents(PuglView* view) case 6: dx = -1.0f; break; case 7: dx = 1.0f; break; } - view->scrollFunc(view, - event.xbutton.x, event.xbutton.y, - dx, dy); + view->scrollFunc(view, event.xbutton.x, event.xbutton.y, dx, dy); } break; } @@ -345,8 +399,9 @@ puglProcessEvents(PuglView* view) setModifiers(view, event.xkey.state, event.xkey.time); dispatchKey(view, &event, true); break; - case KeyRelease: + case KeyRelease: { setModifiers(view, event.xkey.state, event.xkey.time); + bool repeated = false; if (view->ignoreKeyRepeat && XEventsQueued(view->impl->display, QueuedAfterReading)) { XEvent next; @@ -355,27 +410,27 @@ puglProcessEvents(PuglView* view) next.xkey.time == event.xkey.time && next.xkey.keycode == event.xkey.keycode) { XNextEvent(view->impl->display, &event); - break; + repeated = true; } } - dispatchKey(view, &event, false); - break; + if (!repeated) { + dispatchKey(view, &event, false); + } + } break; case ClientMessage: { char* type = XGetAtomName(view->impl->display, event.xclient.message_type); if (!strcmp(type, "WM_PROTOCOLS")) { if (view->closeFunc) { view->closeFunc(view); + view->redisplay = false; } } XFree(type); - } break; + } break; #ifdef PUGL_GRAB_FOCUS case EnterNotify: - XSetInputFocus(view->impl->display, - view->impl->win, - RevertToPointerRoot, - CurrentTime); + XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); break; #endif default: |