/* * 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.getWidth() > 16384) resizingSize.setWidth(16384); if (resizingSize.getHeight() < minHeight) resizingSize.setHeight(minHeight); if (resizingSize.getHeight() > 16384) resizingSize.setHeight(16384); 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