Skip to content

Commit

Permalink
Import ResizeHandle widget for tests, set Demo min size
Browse files Browse the repository at this point in the history
Signed-off-by: falkTX <[email protected]>
  • Loading branch information
falkTX committed May 26, 2022
1 parent 4f906d2 commit d76a112
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 150 deletions.
153 changes: 3 additions & 150 deletions tests/Demo.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <[email protected]>
* Copyright (C) 2012-2022 Filipe Coelho <[email protected]>
*
* 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
Expand All @@ -23,6 +23,7 @@
#ifdef DGL_OPENGL
#include "widgets/ExampleTextWidget.hpp"
#endif
#include "widgets/ResizeHandle.hpp"

#include "demo_res/DemoArtwork.cpp"
#include "images_res/CatPics.cpp"
Expand Down Expand Up @@ -250,155 +251,6 @@ class LeftSideWidget : public SubWidget
#endif
};

// --------------------------------------------------------------------------------------------------------------------
// Resize handle widget

class ResizeHandle : public TopLevelWidget
{
Rectangle<uint> area;
Line<double> l1, l2, l3;
uint baseSize;

// event handling state
bool resizing;
Point<double> lastResizePoint;
Size<double> resizingSize;

public:
explicit ResizeHandle(TopLevelWidget* const tlw)
: TopLevelWidget(tlw->getWindow()),
baseSize(16),
resizing(false)
{
resetArea();
}

explicit ResizeHandle(Window& window)
: TopLevelWidget(window),
baseSize(16),
resizing(false)
{
resetArea();
}

void setBaseSize(const uint size)
{
baseSize = std::max(16u, size);
resetArea();
}

protected:
void onDisplay() override
{
const GraphicsContext& context(getGraphicsContext());
const double offset = getScaleFactor();

// draw white lines, 1px wide
Color(1.0f, 1.0f, 1.0f).setFor(context);
l1.draw(context, 1);
l2.draw(context, 1);
l3.draw(context, 1);

// draw black lines, offset by 1px and 2px wide
Color(0.0f, 0.0f, 0.0f).setFor(context);
Line<double> l1b(l1), l2b(l2), l3b(l3);
l1b.moveBy(offset, offset);
l2b.moveBy(offset, offset);
l3b.moveBy(offset, offset);
l1b.draw(context, 1);
l2b.draw(context, 1);
l3b.draw(context, 1);
}

bool onMouse(const MouseEvent& ev) override
{
if (ev.button != 1)
return false;

if (ev.press && area.contains(ev.pos))
{
resizing = true;
resizingSize = Size<double>(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<double> 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:
void resetArea()
{
const double scaleFactor = getScaleFactor();
const uint margin = 0.0 * scaleFactor;
const uint size = baseSize * scaleFactor;

area = Rectangle<uint>(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);
}
};

// --------------------------------------------------------------------------------------------------------------------
// Main Demo Window, having a left-side tab-like widget and main area for current widget

Expand Down Expand Up @@ -535,6 +387,7 @@ void createAndShowExampleWidgetStandaloneWindow(Application& app)
{
ExampleWidgetStandaloneWindow swin(app);
const double scaleFactor = swin.getScaleFactor();
swin.setGeometryConstraints(128 * scaleFactor, 128 * scaleFactor);
swin.setResizable(true);
swin.setSize(600 * scaleFactor, 500 * scaleFactor);
swin.setTitle(ExampleWidgetStandaloneWindow::kExampleWidgetName);
Expand Down
207 changes: 207 additions & 0 deletions tests/widgets/ResizeHandle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Resize handle for DPF
* Copyright (C) 2021-2022 Filipe Coelho <[email protected]>
*
* 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 "../../dgl/Color.hpp"
#include "../../dgl/TopLevelWidget.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),
hasCursor(false),
isResizing(false)
{
resetArea();
}

/** Overloaded constructor, will fetch the window from an existing top-level widget. */
explicit ResizeHandle(TopLevelWidget* const tlw)
: TopLevelWidget(tlw->getWindow()),
handleSize(16),
hasCursor(false),
isResizing(false)
{
resetArea();
}

/** Set the handle size, minimum 16.
* Scale factor is automatically applied on top of this size as needed */
void setHandleSize(const uint size)
{
handleSize = std::max(16u, size);
resetArea();
}

protected:
void onDisplay() override
{
// TODO implement gl3 stuff in DPF
#ifndef DGL_USE_OPENGL3
const GraphicsContext& context(getGraphicsContext());
const double lineWidth = 1.0 * getScaleFactor();

#if defined(DGL_OPENGL) && !defined(DGL_USE_OPENGL3)
glMatrixMode(GL_MODELVIEW);
#endif

// 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<double> 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);
#endif
}

bool onMouse(const MouseEvent& ev) override
{
if (ev.button != 1)
return false;

if (ev.press && area.contains(ev.pos))
{
isResizing = true;
resizingSize = Size<double>(getWidth(), getHeight());
lastResizePoint = ev.pos;
return true;
}

if (isResizing && ! ev.press)
{
isResizing = false;
recheckCursor(ev.pos);
return true;
}

return false;
}

bool onMotion(const MotionEvent& ev) override
{
if (! isResizing)
{
recheckCursor(ev.pos);
return false;
}

const Size<double> offset(ev.pos.getX() - lastResizePoint.getX(),
ev.pos.getY() - lastResizePoint.getY());

resizingSize += offset;
lastResizePoint = ev.pos;

// TODO keepAspectRatio
bool keepAspectRatio;
const Size<uint> minSize(getWindow().getGeometryConstraints(keepAspectRatio));
const uint minWidth = minSize.getWidth();
const uint minHeight = minSize.getHeight();

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<uint> area;
Line<double> l1, l2, l3;
uint handleSize;

// event handling state
bool hasCursor, isResizing;
Point<double> lastResizePoint;
Size<double> resizingSize;

void recheckCursor(const Point<double>& pos)
{
const bool shouldHaveCursor = area.contains(pos);

if (shouldHaveCursor == hasCursor)
return;

hasCursor = shouldHaveCursor;
setCursor(shouldHaveCursor ? kMouseCursorDiagonal : kMouseCursorArrow);
}

void resetArea()
{
const double scaleFactor = getScaleFactor();
const uint margin = 0.0 * scaleFactor;
const uint size = handleSize * scaleFactor;

area = Rectangle<uint>(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

0 comments on commit d76a112

Please sign in to comment.