diff --git a/examples/Info/InfoExampleUI.cpp b/examples/Info/InfoExampleUI.cpp index 09110e04..e8afc2a5 100644 --- a/examples/Info/InfoExampleUI.cpp +++ b/examples/Info/InfoExampleUI.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2021 Filipe Coelho * * Permission to use, copy, modify, and/or distribute this software for any purpose with * or without fee is hereby granted, provided that the above copyright notice and this @@ -14,11 +14,9 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "DistrhoPluginInfo.h" - #include "DistrhoUI.hpp" -#include "Window.hpp" +#include "ResizeHandle.hpp" START_NAMESPACE_DISTRHO @@ -33,7 +31,9 @@ public: InfoExampleUI() : UI(kInitialWidth, kInitialHeight), fSampleRate(getSampleRate()), - fScale(1.0f) + fResizable(isResizable()), + fScale(1.0f), + fResizeHandle(this) { std::memset(fParameters, 0, sizeof(float)*kParameterCount); std::memset(fStrBuf, 0, sizeof(char)*(0xff+1)); @@ -45,6 +45,10 @@ public: #endif setGeometryConstraints(kInitialWidth, kInitialHeight, true); + + // no need to show resize handle if window is user-resizable + if (fResizable) + fResizeHandle.hide(); } protected: @@ -123,6 +127,11 @@ protected: drawRight(x, y, (fParameters[kParameterCanRequestParameterValueChanges] > 0.5f) ? "Yes" : "No", 40); y+=lineHeight; + // resizable + drawLeft(x, y, "UI resizable:", 20); + drawRight(x, y, fResizable ? "Yes" : "No", 40); + y+=lineHeight; + // BBT x = 200.0f * fScale; y = 15.0f * fScale; @@ -184,7 +193,9 @@ private: double fSampleRate; // UI stuff + bool fResizable; float fScale; + ResizeHandle fResizeHandle; // temp buf for text char fStrBuf[0xff+1]; diff --git a/examples/Info/ResizeHandle.hpp b/examples/Info/ResizeHandle.hpp new file mode 100644 index 00000000..ac66d69a --- /dev/null +++ b/examples/Info/ResizeHandle.hpp @@ -0,0 +1,176 @@ +/* + * Resize handle for DPF + * Copyright (C) 2021 Filipe Coelho + * + * 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. + */ + +#pragma once + +#include "TopLevelWidget.hpp" +#include "Color.hpp" + +START_NAMESPACE_DGL + +/** Resize handle for DPF windows, will sit on bottom-right. */ +class ResizeHandle : public TopLevelWidget +{ +public: + /** Constructor for placing this handle on top of a window. */ + explicit ResizeHandle(Window& window) + : TopLevelWidget(window), + handleSize(16), + resizing(false) + { + resetArea(); + } + + /** Overloaded constructor, will fetch the window from an existing top-level widget. */ + explicit ResizeHandle(TopLevelWidget* const tlw) + : TopLevelWidget(tlw->getWindow()), + handleSize(16), + resizing(false) + { + resetArea(); + } + + /** Set the handle size, minimum 16. */ + void setHandleSize(const uint size) + { + handleSize = std::max(16u, size); + resetArea(); + } + +protected: + void onDisplay() override + { + const GraphicsContext& context(getGraphicsContext()); + const double lineWidth = 1.0 * getScaleFactor(); + + // draw white lines, 1px wide + Color(1.0f, 1.0f, 1.0f).setFor(context); + l1.draw(context, lineWidth); + l2.draw(context, lineWidth); + l3.draw(context, lineWidth); + + // draw black lines, offset by 1px and 1px wide + Color(0.0f, 0.0f, 0.0f).setFor(context); + Line l1b(l1), l2b(l2), l3b(l3); + l1b.moveBy(lineWidth, lineWidth); + l2b.moveBy(lineWidth, lineWidth); + l3b.moveBy(lineWidth, lineWidth); + l1b.draw(context, lineWidth); + l2b.draw(context, lineWidth); + l3b.draw(context, lineWidth); + } + + bool onMouse(const MouseEvent& ev) override + { + if (ev.button != 1) + return false; + + if (ev.press && area.contains(ev.pos)) + { + resizing = true; + resizingSize = Size(getWidth(), getHeight()); + lastResizePoint = ev.pos; + return true; + } + + if (resizing && ! ev.press) + { + resizing = false; + return true; + } + + return false; + } + + bool onMotion(const MotionEvent& ev) override + { + if (! resizing) + return false; + + const Size offset(ev.pos.getX() - lastResizePoint.getX(), + ev.pos.getY() - lastResizePoint.getY()); + + resizingSize += offset; + lastResizePoint = ev.pos; + + // TODO min width, min height + const uint minWidth = 16; + const uint minHeight = 16; + + if (resizingSize.getWidth() < minWidth) + resizingSize.setWidth(minWidth); + if (resizingSize.getHeight() < minHeight) + resizingSize.setHeight(minHeight); + + setSize(resizingSize.getWidth(), resizingSize.getHeight()); + return true; + } + + void onResize(const ResizeEvent& ev) override + { + TopLevelWidget::onResize(ev); + resetArea(); + } + +private: + Rectangle area; + Line l1, l2, l3; + uint handleSize; + + // event handling state + bool resizing; + Point lastResizePoint; + Size resizingSize; + + void resetArea() + { + const double scaleFactor = getScaleFactor(); + const uint margin = 0.0 * scaleFactor; + const uint size = handleSize * scaleFactor; + + area = Rectangle(getWidth() - size - margin, + getHeight() - size - margin, + size, size); + + recreateLines(area.getX(), area.getY(), size); + } + + void recreateLines(const uint x, const uint y, const uint size) + { + uint linesize = size; + uint offset = 0; + + // 1st line, full diagonal size + l1.setStartPos(x + size, y); + l1.setEndPos(x, y + size); + + // 2nd line, bit more to the right and down, cropped + offset += size / 3; + linesize -= size / 3; + l2.setStartPos(x + linesize + offset, y + offset); + l2.setEndPos(x + offset, y + linesize + offset); + + // 3rd line, even more right and down + offset += size / 3; + linesize -= size / 3; + l3.setStartPos(x + linesize + offset, y + offset); + l3.setEndPos(x + offset, y + linesize + offset); + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ResizeHandle) +}; + +END_NAMESPACE_DGL