You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Framework/AzQtComponents/AzQtComponents/Utilities/QtWindowUtilities.cpp

182 lines
5.7 KiB
C++

/*
* 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 <AzCore/PlatformIncl.h>
#include <AzQtComponents/Utilities/QtWindowUtilities.h>
#include <AzQtComponents/Utilities/ScreenUtilities.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QMainWindow>
#include <QPainter>
#include <QDockWidget>
#include <QCursor>
#include <QScreen>
#include <QTimer>
#include <QWindow>
namespace AzQtComponents
{
QRect GetTotalScreenGeometry()
{
QRect totalScreenRect;
int numScreens = QApplication::screens().count();
for (int i = 0; i < numScreens; ++i)
{
totalScreenRect = totalScreenRect.united(QApplication::screens().at(i)->geometry());
}
return totalScreenRect;
}
void EnsureGeometryWithinScreenTop(QRect& geometry)
{
QScreen* screen = Utilities::ScreenAtPoint(geometry.center());
if (screen)
{
QRect screenRect = screen->geometry();
if (!screenRect.isNull() && geometry.top() < screenRect.top())
{
geometry.moveTop(screenRect.top());
}
}
}
void EnsureWindowWithinScreenGeometry(QWidget* widget)
{
// manipulate the window, not the input widget. Might be the same thing
widget = widget->window();
// get the edges of the screens
QRect screenGeometry = GetTotalScreenGeometry();
// check if we cross over any edges
QRect geometry = widget->geometry();
const bool mustBeEntirelyInside = true;
if (screenGeometry.contains(geometry, mustBeEntirelyInside))
{
return;
}
if ((geometry.x() + geometry.width()) > screenGeometry.right())
{
geometry.moveTo(screenGeometry.right() - geometry.width(), geometry.top());
}
if (geometry.x() < screenGeometry.left())
{
geometry.moveTo(screenGeometry.left(), geometry.top());
}
if ((geometry.y() + geometry.height()) > screenGeometry.bottom())
{
geometry.moveTo(geometry.x(), screenGeometry.bottom() - geometry.height());
}
if (geometry.y() < screenGeometry.top())
{
geometry.moveTo(geometry.x(), screenGeometry.top());
}
widget->setGeometry(geometry);
}
void SetClipRegionForDockingWidgets(QWidget* widget, QPainter& painter, QMainWindow* mainWindow)
{
QRegion clipRegion(widget->rect());
for (QDockWidget* childDockWidget : mainWindow->findChildren<QDockWidget*>(QString(), Qt::FindDirectChildrenOnly))
{
if (childDockWidget->isFloating() && childDockWidget->isVisible() && !childDockWidget->isMinimized())
{
QRect globalDockRect = childDockWidget->geometry();
QRect localDockRect(widget->mapFromGlobal(globalDockRect.topLeft()), globalDockRect.size());
clipRegion = clipRegion.subtracted(QRegion(localDockRect));
}
}
painter.setClipRegion(clipRegion);
painter.setClipping(true);
}
void SetCursorPos(const QPoint& point)
{
const QList<QScreen*> screens = QGuiApplication::screens();
bool finished = false;
for (int screenIndex = 0; !finished && screenIndex < screens.size(); ++screenIndex)
{
QScreen* screen = screens[screenIndex];
if (screen->geometry().contains(point))
{
QCursor::setPos(screen, point);
finished = true;
}
}
}
void SetCursorPos(int x, int y)
{
SetCursorPos(QPoint(x, y));
}
void bringWindowToTop(QWidget* widget)
{
auto window = widget->window();
bool wasMaximized = window->isMaximized();
// this will un-maximize a window that's previously been maximized...
window->setWindowState(Qt::WindowActive);
if (wasMaximized)
{
// re-maximize it now
window->showMaximized();
}
else if (WindowDecorationWrapper* wrapper = qobject_cast<WindowDecorationWrapper*>(window))
{
// otherwise, restore this from any saved settings if we can
wrapper->showFromSettings();
}
else
{
window->show();
}
window->raise();
// activateWindow only works if the window is shown, so let's include
// a slight delay to make sure the events for showing the window
// have been processed.
QTimer::singleShot(0, widget, [widget] {
widget->activateWindow();
if (QWindow* window = widget->window()->windowHandle())
{
window->requestActivate();
}
// The Windows OS has all kinds of issues with bringing a window to the front
// from another application.
// For the moment, we assume that any other application calling this
// has called AllowSetForegroundWindow(), otherwise, the code below
// won't work.
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(widget->winId());
SetForegroundWindow(hwnd);
// Hack to get this to show up for sure
::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#endif // Q_OS_WIN
});
}
} // namespace AzQtComponents