treeland/waylib/examples/tinywl/surfaceproxy.cpp

238 lines
6.7 KiB
C++

// Copyright (C) 2024 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "surfaceproxy.h"
#include "surfacewrapper.h"
#include "qmlengine.h"
SurfaceProxy::SurfaceProxy(QQuickItem *parent)
: QQuickItem(parent)
{
}
SurfaceWrapper *SurfaceProxy::surface() const
{
return m_sourceSurface;
}
void SurfaceProxy::setSurface(SurfaceWrapper *newSurface)
{
if (m_sourceSurface == newSurface)
return;
m_sourceSurface = newSurface;
if (m_proxySurface) {
m_proxySurface->deleteLater();
m_proxySurface = nullptr;
}
if (m_sourceSurface) {
m_proxySurface = new SurfaceWrapper(m_sourceSurface->m_engine,
m_sourceSurface->m_shellSurface,
m_sourceSurface->type(), this);
m_proxySurface->setTransformOrigin(QQuickItem::TransformOrigin::TopLeft);
if (!m_fullProxy) {
Q_ASSERT(!m_shadow);
m_shadow = m_sourceSurface->m_engine->createShadow(this);
m_shadow->setProperty("radius", radius());
m_shadow->stackBefore(m_proxySurface);
}
auto item = m_proxySurface->surfaceItem();
if (m_live) {
item->setFlags(WSurfaceItem::RejectEvent);
} else {
item->setFlags(WSurfaceItem::RejectEvent | WSurfaceItem::NonLive);
}
item->setDelegate(m_sourceSurface->surfaceItem()->delegate());
connect(m_sourceSurface, &SurfaceWrapper::destroyed, this, [this] {
Q_ASSERT(m_proxySurface);
setSurface(nullptr);
});
connect(m_sourceSurface->surfaceItem(), &WSurfaceItem::delegateChanged,
this, [this] {
Q_ASSERT(m_proxySurface);
auto sender = m_sourceSurface->surfaceItem();
m_proxySurface->surfaceItem()->setDelegate(sender->delegate());
});
connect(m_sourceSurface, &SurfaceWrapper::noTitleBarChanged,
this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration);
connect(m_sourceSurface, &SurfaceWrapper::radiusChanged, this, &SurfaceProxy::onSourceRadiusChanged);
connect(m_sourceSurface, &SurfaceWrapper::noDecorationChanged,
this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration);
connect(m_sourceSurface, &SurfaceWrapper::noCornerRadiusChanged,
this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration);
connect(m_proxySurface, &SurfaceWrapper::widthChanged, this, &SurfaceProxy::updateImplicitSize);
connect(m_proxySurface, &SurfaceWrapper::heightChanged, this, &SurfaceProxy::updateImplicitSize);
updateImplicitSize();
updateProxySurfaceScale();
updateProxySurfaceTitleBarAndDecoration();
} else {
m_shadow->deleteLater();
m_shadow = nullptr;
}
emit surfaceChanged();
}
void SurfaceProxy::geometryChange(const QRectF &newGeo, const QRectF &oldGeo)
{
QQuickItem::geometryChange(newGeo, oldGeo);
if (m_proxySurface) {
updateProxySurfaceScale();
if (m_shadow)
m_shadow->setSize(newGeo.size());
}
}
void SurfaceProxy::updateProxySurfaceScale()
{
if (size().isEmpty())
return;
QSizeF surfaceSize = m_proxySurface->size();
surfaceSize.scale(size(), Qt::KeepAspectRatio);
if (surfaceSize.width() < m_proxySurface->width()) {
m_proxySurface->setScale(surfaceSize.width() / m_proxySurface->width());
m_proxySurface->setRadius(radius() / m_proxySurface->scale());
} else {
m_proxySurface->setScale(1.0);
m_proxySurface->setRadius(radius());
}
}
void SurfaceProxy::updateProxySurfaceTitleBarAndDecoration()
{
if (m_fullProxy) {
m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar());
m_proxySurface->setNoDecoration(m_sourceSurface->noDecoration());
m_proxySurface->setNoCornerRadius(m_sourceSurface->noCornerRadius());
} else {
m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar());
m_proxySurface->setNoDecoration(true);
m_proxySurface->setNoCornerRadius(false);
}
}
void SurfaceProxy::updateImplicitSize()
{
if (!m_proxySurface) {
return;
}
const auto size = m_proxySurface->size();
if (size.isEmpty()) {
return;
}
const auto scaledSize = size.scaled(m_maxSize, Qt::KeepAspectRatio);
const auto scale = scaledSize.width() / size.width();
setImplicitSize(size.width() * scale, size.height() * scale);
}
void SurfaceProxy::onSourceRadiusChanged()
{
m_proxySurface->setRadius(radius() / m_proxySurface->scale());
if (m_shadow)
m_shadow->setProperty("radius", radius());
if (m_radius < 0)
emit radiusChanged();
}
qreal SurfaceProxy::radius() const
{
if (m_radius >= 0)
return m_radius;
return m_sourceSurface ? m_sourceSurface->radius() : 0;
}
void SurfaceProxy::setRadius(qreal newRadius)
{
if (qFuzzyCompare(m_radius, newRadius))
return;
m_radius = newRadius;
if (m_proxySurface) {
m_proxySurface->setRadius(radius() / m_proxySurface->scale());
if (m_shadow)
m_shadow->setProperty("radius", radius());
}
emit radiusChanged();
}
void SurfaceProxy::resetRadius()
{
setRadius(-1);
}
bool SurfaceProxy::live() const
{
return m_live;
}
void SurfaceProxy::setLive(bool newLive)
{
if (m_live == newLive)
return;
m_live = newLive;
if (m_proxySurface) {
auto item = m_proxySurface->surfaceItem();
if (m_live) {
item->setFlags(item->flags() & ~WSurfaceItem::NonLive);
} else {
item->setFlags(item->flags() | WSurfaceItem::NonLive);
}
}
emit liveChanged();
}
QSizeF SurfaceProxy::maxSize() const
{
return m_maxSize;
}
void SurfaceProxy::setMaxSize(const QSizeF &newMaxSize)
{
if (m_maxSize == newMaxSize)
return;
m_maxSize = newMaxSize;
updateImplicitSize();
emit maxSizeChanged();
}
bool SurfaceProxy::fullProxy() const
{
return m_fullProxy;
}
void SurfaceProxy::setFullProxy(bool newFullProxy)
{
if (m_fullProxy == newFullProxy)
return;
m_fullProxy = newFullProxy;
if (m_proxySurface) {
if (m_fullProxy) {
if (m_shadow) {
m_shadow->deleteLater();
m_shadow = nullptr;
}
} else if (!m_shadow) {
m_shadow = m_sourceSurface->m_engine->createShadow(this);
m_shadow->setProperty("radius", radius());
m_shadow->stackBefore(m_proxySurface);
}
updateProxySurfaceTitleBarAndDecoration();
}
emit fullProxyChanged();
}