Resize wasm windows using a div outline

Introducing a div outline which handles the resize events by itself.
Manual computations in wasm compositor are no longer needed.

The outline reacts to setting css variables (border-width,
resize-outline-width), it sets the correct cursors using css and
always keeps the correct size.

Fixes: QTBUG-107498
Change-Id: I6b0564632af5e17e464fe93a3dfa20820c624292
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Mikolaj Boc 2022-10-13 10:55:37 +02:00
parent f546f3700b
commit e50bc60e87
9 changed files with 311 additions and 221 deletions

View File

@ -149,11 +149,6 @@ void QWasmCompositor::initEventHandlers()
emscripten::val(quintptr(reinterpret_cast<void *>(screen()))));
}
void QWasmCompositor::startResize(Qt::Edges edges)
{
m_windowManipulation.startResize(edges);
}
void QWasmCompositor::addWindow(QWasmWindow *window)
{
m_windowStack.pushWindow(window);
@ -317,33 +312,6 @@ void QWasmCompositor::frame(bool all, const QList<QWasmWindow *> &windows)
}
}
void QWasmCompositor::WindowManipulation::resizeWindow(const QPoint& amount)
{
const auto& minShrink = std::get<ResizeState>(m_state->operationSpecific).m_minShrink;
const auto& maxGrow = std::get<ResizeState>(m_state->operationSpecific).m_maxGrow;
const auto &resizeEdges = std::get<ResizeState>(m_state->operationSpecific).m_resizeEdges;
const QPoint cappedGrowVector(
std::min(maxGrow.x(),
std::max(minShrink.x(),
(resizeEdges & Qt::Edge::LeftEdge) ? -amount.x()
: (resizeEdges & Qt::Edge::RightEdge) ? amount.x()
: 0)),
std::min(maxGrow.y(),
std::max(minShrink.y(),
(resizeEdges & Qt::Edge::TopEdge) ? -amount.y()
: (resizeEdges & Qt::Edge::BottomEdge) ? amount.y()
: 0)));
const auto& initialBounds =
std::get<ResizeState>(m_state->operationSpecific).m_initialWindowBounds;
m_state->window->setGeometry(initialBounds.adjusted(
(resizeEdges & Qt::Edge::LeftEdge) ? -cappedGrowVector.x() : 0,
(resizeEdges & Qt::Edge::TopEdge) ? -cappedGrowVector.y() : 0,
(resizeEdges & Qt::Edge::RightEdge) ? cappedGrowVector.x() : 0,
(resizeEdges & Qt::Edge::BottomEdge) ? cappedGrowVector.y() : 0));
}
void QWasmCompositor::onTopWindowChanged()
{
constexpr int zOrderForElementInFrontOfScreen = 3;
@ -413,7 +381,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
const QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(event.point);
const bool pointerIsWithinTargetWindowBounds = targetWindow->geometry().contains(event.point);
const bool isTargetWindowBlocked = QGuiApplicationPrivate::instance()->isWindowBlocked(targetWindow);
if (m_mouseInScreen && m_windowUnderMouse != targetWindow
&& pointerIsWithinTargetWindowBounds) {
@ -422,10 +389,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
m_windowUnderMouse = targetWindow;
}
QWasmWindow *wasmTargetWindow = asWasmWindow(targetWindow);
Qt::WindowStates windowState = targetWindow->windowState();
const bool isTargetWindowResizable = !windowState.testFlag(Qt::WindowMaximized) && !windowState.testFlag(Qt::WindowFullScreen);
switch (event.type) {
case EventType::PointerDown:
{
@ -444,25 +407,7 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
m_windowManipulation.onPointerUp(event);
break;
}
case EventType::PointerMove:
{
if (wasmTargetWindow && event.mouseButtons.testFlag(Qt::NoButton)) {
const bool isOnResizeRegion = wasmTargetWindow->isPointOnResizeRegion(event.point);
if (isTargetWindowResizable && isOnResizeRegion && !isTargetWindowBlocked) {
const QCursor resizingCursor = QWasmEventTranslator::cursorForEdges(
wasmTargetWindow->resizeEdgesAtPoint(event.point));
if (resizingCursor != targetWindow->cursor()) {
m_isResizeCursorDisplayed = true;
QWasmCursor::setOverrideWasmCursor(resizingCursor, targetWindow->screen());
}
} else if (m_isResizeCursorDisplayed) { // off resizing area
m_isResizeCursorDisplayed = false;
QWasmCursor::clearOverrideWasmCursor(targetWindow->screen());
}
}
case EventType::PointerMove: {
m_windowManipulation.onPointerMove(event);
if (m_windowManipulation.operation() != WindowManipulation::Operation::None)
requestUpdate();
@ -538,9 +483,7 @@ QWasmCompositor::WindowManipulation::Operation QWasmCompositor::WindowManipulati
{
if (!m_state)
return Operation::None;
return std::holds_alternative<MoveState>(m_state->operationSpecific)
? Operation::Move : Operation::Resize;
return Operation::Move;
}
void QWasmCompositor::WindowManipulation::onPointerDown(
@ -564,61 +507,30 @@ void QWasmCompositor::WindowManipulation::onPointerDown(
if (isTargetWindowBlocked)
return;
std::unique_ptr<std::variant<ResizeState, MoveState>> operationSpecific;
if (asWasmWindow(windowAtPoint)->isPointOnTitle(event.point)) {
operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(
MoveState{ .m_lastPointInScreenCoords = event.point });
} else if (asWasmWindow(windowAtPoint)->isPointOnResizeRegion(event.point)) {
operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(ResizeState{
.m_resizeEdges = asWasmWindow(windowAtPoint)->resizeEdgesAtPoint(event.point),
.m_originInScreenCoords = event.point,
.m_initialWindowBounds = windowAtPoint->geometry(),
.m_minShrink =
QPoint(windowAtPoint->minimumWidth() - windowAtPoint->geometry().width(),
windowAtPoint->minimumHeight() - windowAtPoint->geometry().height()),
.m_maxGrow =
QPoint(windowAtPoint->maximumWidth() - windowAtPoint->geometry().width(),
windowAtPoint->maximumHeight() - windowAtPoint->geometry().height()),
});
} else {
if (!asWasmWindow(windowAtPoint)->isPointOnTitle(event.point))
return;
}
m_state.reset(new OperationState{
.pointerId = event.pointerId,
.window = windowAtPoint,
.operationSpecific = std::move(*operationSpecific),
});
m_state.reset(new OperationState{ .pointerId = event.pointerId,
.window = windowAtPoint,
.lastPointInScreenCoords = event.point });
}
void QWasmCompositor::WindowManipulation::onPointerMove(
const PointerEvent& event)
{
m_systemDragInitData = {
.lastMouseMovePoint = m_screen->clipPoint(event.point),
.lastMousePointerId = event.pointerId,
};
if (operation() == Operation::None || event.pointerId != m_state->pointerId)
return;
switch (operation()) {
case Operation::Move: {
const QPoint targetPointClippedToScreen = m_screen->clipPoint(event.point);
const QPoint difference = targetPointClippedToScreen -
std::get<MoveState>(m_state->operationSpecific).m_lastPointInScreenCoords;
const QPoint difference = targetPointClippedToScreen - m_state->lastPointInScreenCoords;
std::get<MoveState>(m_state->operationSpecific).m_lastPointInScreenCoords = targetPointClippedToScreen;
m_state->lastPointInScreenCoords = targetPointClippedToScreen;
m_state->window->setPosition(m_state->window->position() + difference);
break;
}
case Operation::Resize: {
const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
resizeWindow(pointInScreenCoords -
std::get<ResizeState>(m_state->operationSpecific).m_originInScreenCoords);
break;
}
case Operation::None:
Q_ASSERT(0);
break;
@ -633,34 +545,6 @@ void QWasmCompositor::WindowManipulation::onPointerUp(const PointerEvent& event)
m_state.reset();
}
void QWasmCompositor::WindowManipulation::startResize(Qt::Edges edges)
{
Q_ASSERT_X(operation() == Operation::None, Q_FUNC_INFO,
"Resize must not start anew when one is in progress");
auto *window = m_screen->compositor()->windowAt(m_systemDragInitData.lastMouseMovePoint);
if (Q_UNLIKELY(!window))
return;
m_state.reset(new OperationState{
.pointerId = m_systemDragInitData.lastMousePointerId,
.window = window,
.operationSpecific =
ResizeState{
.m_resizeEdges = edges,
.m_originInScreenCoords = m_systemDragInitData.lastMouseMovePoint,
.m_initialWindowBounds = window->geometry(),
.m_minShrink =
QPoint(window->minimumWidth() - window->geometry().width(),
window->minimumHeight() - window->geometry().height()),
.m_maxGrow =
QPoint(window->maximumWidth() - window->geometry().width(),
window->maximumHeight() - window->geometry().height()),
},
});
m_screen->element().call<void>("setPointerCapture", m_systemDragInitData.lastMousePointerId);
}
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent)
{
constexpr bool ProceedToNativeEvent = false;

View File

@ -43,8 +43,6 @@ public:
QPalette palette;
};
void startResize(Qt::Edges edges);
void addWindow(QWasmWindow *window);
void removeWindow(QWasmWindow *window);
@ -72,47 +70,26 @@ private:
enum class Operation {
None,
Move,
Resize,
};
WindowManipulation(QWasmScreen* screen);
void onPointerDown(const PointerEvent& event, QWindow* windowAtPoint);
void onPointerMove(const PointerEvent& event);
void onPointerUp(const PointerEvent& event);
void startResize(Qt::Edges edges);
void onPointerUp(const PointerEvent &event);
Operation operation() const;
private:
struct ResizeState {
Qt::Edges m_resizeEdges;
QPoint m_originInScreenCoords;
QRect m_initialWindowBounds;
const QPoint m_minShrink;
const QPoint m_maxGrow;
};
struct MoveState {
QPoint m_lastPointInScreenCoords;
};
struct OperationState
{
int pointerId;
QPointer<QWindow> window;
std::variant<ResizeState, MoveState> operationSpecific;
QPoint lastPointInScreenCoords;
};
struct SystemDragInitData
{
QPoint lastMouseMovePoint;
int lastMousePointerId = -1;
};
void resizeWindow(const QPoint& amount);
ResizeState makeResizeState(Qt::Edges edges, const QPoint &startPoint, QWindow *window);
QWasmScreen *m_screen;
SystemDragInitData m_systemDragInitData;
std::unique_ptr<OperationState> m_state;
};

View File

@ -12,6 +12,8 @@ namespace {
const char *Style = R"css(
.qt-screen {
--border-width: 4px;
--resize-outline-width: 8px;
--resize-outline-half-width: var(--resize-outline-width) / 2;
position: relative;
border: none;
@ -35,6 +37,80 @@ const char *Style = R"css(
caret-color: transparent;
}
.resize-outline {
position: absolute;
pointer-events: all;
display: none;
}
.qt-window.has-title-bar:not(.maximized) .resize-outline {
display: block;
}
.resize-outline.nw {
left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
width: var(--resize-outline-width);
height: var(--resize-outline-width);
cursor: nwse-resize;
}
.resize-outline.n {
left: var(--resize-outline-half-width);
top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
height: var(--resize-outline-width);
width: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
cursor: ns-resize;
}
.resize-outline.ne {
left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
top: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
width: var(--resize-outline-width);
height: var(--resize-outline-width);
cursor: nesw-resize;
}
.resize-outline.w {
left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
top: 0;
height: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
width: var(--resize-outline-width);
cursor: ew-resize;
}
.resize-outline.e {
left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
top: 0;
height: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
width: var(--resize-outline-width);
cursor: ew-resize;
}
.resize-outline.sw {
left: calc(-1 * var(--resize-outline-half-width) - var(--border-width));
top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
width: var(--resize-outline-width);
height: var(--resize-outline-width);
cursor: nesw-resize;
}
.resize-outline.s {
left: var(--resize-outline-half-width);
top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
height: var(--resize-outline-width);
width: calc(100% + 2 * var(--border-width) - var(--resize-outline-width));
cursor: ns-resize;
}
.resize-outline.se {
left: calc(100% + var(--border-width) - var(--resize-outline-half-width));
top: calc(100% + var(--border-width) - var(--resize-outline-half-width));
width: var(--resize-outline-width);
height: var(--resize-outline-width);
cursor: nwse-resize;
}
.title-bar {
display: none;
align-items: center;

View File

@ -44,6 +44,7 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
ret.mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>());
ret.point = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>());
ret.pointInViewport = QPoint(event["x"].as<int>(), event["y"].as<int>());
ret.pointerId = event["pointerId"].as<int>();
ret.modifiers = KeyboardModifier::getForEvent(event);

View File

@ -115,6 +115,7 @@ struct Q_CORE_EXPORT Event
struct Q_CORE_EXPORT MouseEvent : public Event
{
QPoint point;
QPoint pointInViewport;
Qt::MouseButton mouseButton;
Qt::MouseButtons mouseButtons;
QFlags<Qt::KeyboardModifier> modifiers;

View File

@ -283,29 +283,6 @@ QWasmEventTranslator::QWasmEventTranslator() = default;
QWasmEventTranslator::~QWasmEventTranslator() = default;
QCursor QWasmEventTranslator::cursorForEdges(Qt::Edges edges)
{
switch (edges) {
case Qt::Edge::LeftEdge | Qt::Edge::TopEdge:
case Qt::Edge::RightEdge | Qt::Edge::BottomEdge:
return Qt::SizeFDiagCursor;
case Qt::Edge::LeftEdge | Qt::Edge::BottomEdge:
case Qt::Edge::RightEdge | Qt::Edge::TopEdge:
return Qt::SizeBDiagCursor;
case Qt::Edge::TopEdge:
case Qt::Edge::BottomEdge:
return Qt::SizeVerCursor;
case Qt::Edge::LeftEdge:
case Qt::Edge::RightEdge:
return Qt::SizeHorCursor;
case Qt::Edge(0):
return Qt::ArrowCursor;
default:
Q_ASSERT(false); // Bad edges
}
return Qt::ArrowCursor;
}
QWasmEventTranslator::TranslatedEvent
QWasmEventTranslator::translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent)
{

View File

@ -33,8 +33,6 @@ public:
explicit QWasmEventTranslator();
~QWasmEventTranslator();
static QCursor cursorForEdges(Qt::Edges edges);
TranslatedEvent translateKeyEvent(int emEventType, const EmscriptenKeyboardEvent *keyEvent);
private:

View File

@ -45,8 +45,222 @@ void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool fl
element["classList"].call<void>("remove", emscripten::val(std::move(cssClassName)));
}
} // namespace
class QWasmWindow::Resizer
{
public:
class ResizerElement
{
public:
static constexpr const char *cssClassNameForEdges(Qt::Edges edges)
{
switch (edges) {
case Qt::TopEdge | Qt::LeftEdge:;
return "nw";
case Qt::TopEdge:
return "n";
case Qt::TopEdge | Qt::RightEdge:
return "ne";
case Qt::LeftEdge:
return "w";
case Qt::RightEdge:
return "e";
case Qt::BottomEdge | Qt::LeftEdge:
return "sw";
case Qt::BottomEdge:
return "s";
case Qt::BottomEdge | Qt::RightEdge:
return "se";
default:
Q_ASSERT(false); // notreached
return "";
}
}
ResizerElement(emscripten::val parentElement, Qt::Edges edges, Resizer *resizer)
: m_element(emscripten::val::global("document")
.call<emscripten::val>("createElement", emscripten::val("div"))),
m_edges(edges),
m_resizer(resizer)
{
Q_ASSERT_X(m_resizer, Q_FUNC_INFO, "Resizer cannot be null");
m_element["classList"].call<void>("add", emscripten::val("resize-outline"));
m_element["classList"].call<void>("add", emscripten::val(cssClassNameForEdges(edges)));
parentElement.call<void>("appendChild", m_element);
m_mouseDownEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointerdown", [this](emscripten::val event) {
if (!onPointerDown(*PointerEvent::fromWeb(event)))
return;
m_resizer->onInteraction();
event.call<void>("preventDefault");
event.call<void>("stopPropagation");
});
m_mouseDragEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointermove", [this](emscripten::val event) {
if (onPointerMove(*PointerEvent::fromWeb(event))) {
event.call<void>("preventDefault");
event.call<void>("stopPropagation");
}
});
m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointerup", [this](emscripten::val event) {
if (onPointerUp(*PointerEvent::fromWeb(event))) {
event.call<void>("preventDefault");
event.call<void>("stopPropagation");
}
});
}
~ResizerElement()
{
m_element["parentElement"].call<emscripten::val>("removeChild", m_element);
}
ResizerElement(const ResizerElement &other) = delete;
ResizerElement(ResizerElement &&other) = default;
ResizerElement &operator=(const ResizerElement &other) = delete;
ResizerElement &operator=(ResizerElement &&other) = delete;
bool onPointerDown(const PointerEvent &event)
{
if (event.pointerType != PointerType::Mouse)
return false;
m_element.call<void>("setPointerCapture", event.pointerId);
m_capturedPointerId = event.pointerId;
m_resizer->startResize(m_edges, event.pointInViewport);
return true;
}
bool onPointerMove(const PointerEvent &event)
{
if (m_capturedPointerId != event.pointerId)
return false;
m_resizer->continueResize(event.pointInViewport);
return true;
}
bool onPointerUp(const PointerEvent &event)
{
if (m_capturedPointerId != event.pointerId)
return false;
m_resizer->finishResize();
m_element.call<void>("releasePointerCapture", event.pointerId);
m_capturedPointerId = -1;
return true;
}
private:
emscripten::val m_element;
int m_capturedPointerId = -1;
const Qt::Edges m_edges;
Resizer *m_resizer;
std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseDragEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent;
};
using ClickCallback = std::function<void()>;
Resizer(QWasmWindow *window, emscripten::val parentElement) : m_window(window)
{
Q_ASSERT_X(m_window, Q_FUNC_INFO, "Window must not be null");
constexpr std::array<int, 8> ResizeEdges = { Qt::TopEdge | Qt::LeftEdge,
Qt::TopEdge,
Qt::TopEdge | Qt::RightEdge,
Qt::LeftEdge,
Qt::RightEdge,
Qt::BottomEdge | Qt::LeftEdge,
Qt::BottomEdge,
Qt::BottomEdge | Qt::RightEdge };
std::transform(std::begin(ResizeEdges), std::end(ResizeEdges),
std::back_inserter(m_elements), [parentElement, this](int edges) {
return std::make_unique<ResizerElement>(parentElement,
Qt::Edges::fromInt(edges), this);
});
}
~Resizer() = default;
private:
void onInteraction() { m_window->onInteraction(); }
void startResize(Qt::Edges resizeEdges, const QPoint &origin)
{
Q_ASSERT_X(!m_currentResizeData, Q_FUNC_INFO, "Another resize in progress");
const QWindow *window = m_window->window();
// TODO(mikolajboc): Implement system resize
// .m_originInScreenCoords = m_systemDragInitData.lastMouseMovePoint,
m_currentResizeData.reset(new ResizeData{
.edges = resizeEdges,
.originInScreenCoords = origin,
.initialWindowBounds = window->geometry(),
.minShrink = QPoint(window->minimumWidth() - window->geometry().width(),
window->minimumHeight() - window->geometry().height()),
.maxGrow = QPoint(window->maximumWidth() - window->geometry().width(),
window->maximumHeight() - window->geometry().height()) });
}
void continueResize(const QPoint &point)
{
const auto amount = point - m_currentResizeData->originInScreenCoords;
const QPoint cappedGrowVector(
std::min(m_currentResizeData->maxGrow.x(),
std::max(m_currentResizeData->minShrink.x(),
(m_currentResizeData->edges & Qt::Edge::LeftEdge) ? -amount.x()
: (m_currentResizeData->edges & Qt::Edge::RightEdge)
? amount.x()
: 0)),
std::min(m_currentResizeData->maxGrow.y(),
std::max(m_currentResizeData->minShrink.y(),
(m_currentResizeData->edges & Qt::Edge::TopEdge) ? -amount.y()
: (m_currentResizeData->edges & Qt::Edge::BottomEdge)
? amount.y()
: 0)));
auto bounds = m_currentResizeData->initialWindowBounds.adjusted(
(m_currentResizeData->edges & Qt::Edge::LeftEdge) ? -cappedGrowVector.x() : 0,
(m_currentResizeData->edges & Qt::Edge::TopEdge) ? -cappedGrowVector.y() : 0,
(m_currentResizeData->edges & Qt::Edge::RightEdge) ? cappedGrowVector.x() : 0,
(m_currentResizeData->edges & Qt::Edge::BottomEdge) ? cappedGrowVector.y() : 0);
bounds.setY(std::max(m_window->screen()->geometry().y() + m_window->frameMargins().top(),
bounds.y()));
m_window->setGeometry(std::move(bounds));
}
void finishResize()
{
Q_ASSERT_X(m_currentResizeData, Q_FUNC_INFO, "No resize in progress");
m_currentResizeData.reset();
}
struct ResizeData
{
Qt::Edges edges = Qt::Edges::fromInt(0);
QPoint originInScreenCoords;
QRect initialWindowBounds;
QPoint minShrink;
QPoint maxGrow;
};
std::unique_ptr<ResizeData> m_currentResizeData;
QWasmWindow *m_window;
std::vector<std::unique_ptr<ResizerElement>> m_elements;
};
class QWasmWindow::WebImageButton
{
public:
@ -181,6 +395,8 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
m_qtWindow.call<void>("appendChild", m_windowContents);
m_resizer = std::make_unique<Resizer>(this, m_qtWindow);
m_icon = std::make_unique<WebImageButton>();
m_icon->setImage(IconType::QtLogo);
@ -411,11 +627,10 @@ void QWasmWindow::propagateSizeHints()
}
}
bool QWasmWindow::startSystemResize(Qt::Edges edges)
bool QWasmWindow::startSystemResize(Qt::Edges)
{
m_compositor->startResize(edges);
return true;
// TODO(mikolajboc): This can only be implemented if per-window events are up and running
return false;
}
void QWasmWindow::onRestoreClicked()
@ -450,51 +665,12 @@ QMarginsF QWasmWindow::borderMargins() const
frameRect.bottom() - canvasRect.bottom());
}
QRegion QWasmWindow::resizeRegion() const
{
QMargins margins = borderMargins().toMargins();
QRegion result(window()->frameGeometry().marginsAdded(margins));
result -= window()->frameGeometry().marginsRemoved(margins);
return result;
}
bool QWasmWindow::isPointOnTitle(QPoint globalPoint) const
{
return QRectF::fromDOMRect(m_titleBar.call<emscripten::val>("getBoundingClientRect"))
.contains(globalPoint);
}
bool QWasmWindow::isPointOnResizeRegion(QPoint point) const
{
// Certain windows, like undocked dock widgets, are both popups and dialogs. Those should be
// resizable.
if (windowIsPopupType(window()->flags()))
return false;
return (window()->maximumSize().isEmpty() || window()->minimumSize() != window()->maximumSize())
&& resizeRegion().contains(point);
}
Qt::Edges QWasmWindow::resizeEdgesAtPoint(QPoint point) const
{
const QPoint topLeft = window()->frameGeometry().topLeft() - QPoint(5, 5);
const QPoint bottomRight = window()->frameGeometry().bottomRight() + QPoint(5, 5);
const int gripAreaWidth = std::min(20, (bottomRight.y() - topLeft.y()) / 2);
const QRect top(topLeft, QPoint(bottomRight.x(), topLeft.y() + gripAreaWidth));
const QRect bottom(QPoint(topLeft.x(), bottomRight.y() - gripAreaWidth), bottomRight);
const QRect left(topLeft, QPoint(topLeft.x() + gripAreaWidth, bottomRight.y()));
const QRect right(QPoint(bottomRight.x() - gripAreaWidth, topLeft.y()), bottomRight);
Q_ASSERT(!top.intersects(bottom));
Q_ASSERT(!left.intersects(right));
Qt::Edges edges(top.contains(point) ? Qt::Edge::TopEdge : Qt::Edge(0));
edges |= bottom.contains(point) ? Qt::Edge::BottomEdge : Qt::Edge(0);
edges |= left.contains(point) ? Qt::Edge::LeftEdge : Qt::Edge(0);
return edges | (right.contains(point) ? Qt::Edge::RightEdge : Qt::Edge(0));
}
void QWasmWindow::invalidate()
{
m_compositor->requestUpdateWindow(this);
@ -565,6 +741,7 @@ void QWasmWindow::applyWindowState()
newGeom = normalGeometry();
syncCSSClassWith(m_qtWindow, "has-title-bar", hasTitleBar());
syncCSSClassWith(m_qtWindow, "maximized", isMaximized);
m_restore->setVisible(isMaximized);
m_maximize->setVisible(!isMaximized);

View File

@ -55,9 +55,6 @@ public:
bool startSystemResize(Qt::Edges edges) final;
bool isPointOnTitle(QPoint point) const;
bool isPointOnResizeRegion(QPoint point) const;
Qt::Edges resizeEdgesAtPoint(QPoint point) const;
void setWindowFlags(Qt::WindowFlags flags) override;
void setWindowState(Qt::WindowStates state) override;
@ -74,10 +71,10 @@ public:
private:
friend class QWasmScreen;
class Resizer;
class WebImageButton;
QMarginsF borderMargins() const;
QRegion resizeRegion() const;
void onRestoreClicked();
void onMaximizeClicked();
@ -101,6 +98,8 @@ private:
emscripten::val m_canvas;
emscripten::val m_context2d = emscripten::val::undefined();
std::unique_ptr<Resizer> m_resizer;
std::unique_ptr<WebImageButton> m_close;
std::unique_ptr<WebImageButton> m_maximize;
std::unique_ptr<WebImageButton> m_restore;