Files
o3de/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDockingGhostWidget.cpp
T
2021-06-23 10:55:22 -07:00

151 lines
4.5 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzQtComponents/Components/FancyDockingGhostWidget.h>
#include <QDebug>
#include <QCloseEvent>
#include <QScreen>
#include <QWindow>
#include <QMainWindow>
#include <QRect>
#include <QPainter>
#include <AzQtComponents/Utilities/QtWindowUtilities.h>
namespace AzQtComponents
{
FancyDockingGhostWidget::FancyDockingGhostWidget(QMainWindow* mainWindow, QWidget* parent) :
QWidget(parent, Qt::WindowFlags(Qt::ToolTip | Qt::BypassWindowManagerHint | Qt::FramelessWindowHint)),
m_mainWindow(mainWindow)
{
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_NoSystemBackground);
setAutoFillBackground(false);
}
FancyDockingGhostWidget::~FancyDockingGhostWidget()
{
}
void FancyDockingGhostWidget::setPixmapVisible(bool visible)
{
if (m_visible != visible)
{
m_visible = visible;
if (visible)
{
update();
}
}
}
void FancyDockingGhostWidget::setPixmap(const QPixmap& pixmap, const QRect& targetRect, QScreen* screen)
{
const bool needsRepaint = m_pixmap.cacheKey() != pixmap.cacheKey() || m_clipToWidgets;
m_pixmap = pixmap;
if (pixmap.isNull() || targetRect.isNull() || !screen)
{
setPixmapVisible(false);
return;
}
QWindow *window = windowHandle();
if (!window)
{
// So we don't crash when setting a pixmap before having a window
create();
window = windowHandle();
}
if (window->screen() != screen)
{
// Qt usually handles screens with different scale factors correctly, however
// when the geometry's origin is in a gap between monitors it won't map to native
// coordinates correctly, we have to set the screen before setting geometry, so that
// Qt uses the correct scale factor when mapping to native coordinates.
// (By gap we mean that monitors are not consecutive, they might be consecutive
// in native coordinates, but due to using scale factors there will be gaps that don't
// belong to any screen.
window->setScreen(screen);
}
setGeometry(targetRect);
setPixmapVisible(true);
if (needsRepaint)
{
update();
}
}
// The equivalent of lowering the pixmap under the parent's dock widgets
void FancyDockingGhostWidget::EnableClippingToDockWidgets()
{
if (!m_clipToWidgets)
{
m_clipToWidgets = true;
update();
}
}
// The equivalent of raising above all of the parent's dock widgets
void FancyDockingGhostWidget::DisableClippingToDockWidgets()
{
if (m_clipToWidgets)
{
m_clipToWidgets = false;
update();
}
}
void FancyDockingGhostWidget::closeEvent(QCloseEvent* ev)
{
ev->ignore(); // Don't close the window.
}
void FancyDockingGhostWidget::paintEvent(QPaintEvent* /* ev */)
{
QPainter painter(this);
if (m_visible && !m_pixmap.isNull())
{
if (m_clipToWidgets)
{
painter.save();
AzQtComponents::SetClipRegionForDockingWidgets(this, painter, m_mainWindow);
}
// Our rendered pixmaps might be smaller than the widget size
// We put them at the bottom of the widget.
// It's specifically because we use this widget to render
// floating dock widgets, and they often render without the titlebar
// but the geometry of the widget will take the title bar into account.
QSize widgetSize = rect().size();
int aspectRatioHeight = (m_pixmap.height() * widgetSize.width()) / m_pixmap.width();
int yOffset = 0;
if (aspectRatioHeight < widgetSize.height())
{
yOffset = widgetSize.height() - aspectRatioHeight;
}
painter.drawPixmap(QRect(0, yOffset, widgetSize.width(), aspectRatioHeight), m_pixmap);
if (m_clipToWidgets)
{
painter.restore();
}
}
else
{
// fill to blank, in case anything is cached
painter.fillRect(rect(), QColor(0, 0, 0, 0));
}
}
}