/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include #include #include #include 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); } QPoint midPoint = targetRect.topLeft() + QPoint(targetRect.width() / 2, targetRect.height() / 2); QScreen* pointScreen = QApplication::screenAt(midPoint); QRect rect(targetRect); if (!pointScreen || pointScreen != screen) { if (midPoint.x() >= QCursor::pos().x()) { rect.setLeft(rect.left() - rect.width()); rect.setTop(rect.top() - rect.height()); m_paintMode = PaintMode::BOTTOMRIGHT; } else { rect.setRight(rect.right() + rect.width()); rect.setTop(rect.top() - rect.height()); m_paintMode = PaintMode::BOTTOMLEFT; } } else { m_paintMode = PaintMode::FULL; } setGeometry(rect); 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; } switch (m_paintMode) { case PaintMode::FULL: { painter.drawPixmap(QRect(0, yOffset, widgetSize.width(), aspectRatioHeight), m_pixmap); } break; case PaintMode::BOTTOMLEFT: { painter.drawPixmap(QRect(0, (widgetSize.height() + yOffset) / 2, widgetSize.width() / 2, aspectRatioHeight / 2), m_pixmap); } break; case PaintMode::BOTTOMRIGHT: { painter.drawPixmap(QRect(widgetSize.width() / 2, (widgetSize.height() + yOffset) / 2, widgetSize.width() / 2, aspectRatioHeight / 2), m_pixmap); } break; } if (m_clipToWidgets) { painter.restore(); } } else { // fill to blank, in case anything is cached painter.fillRect(rect(), QColor(0, 0, 0, 0)); } } }