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/Sandbox/Plugins/EditorCommon/QParentWndWidget.cpp

310 lines
7.5 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "QParentWndWidget.h"
#include <QEvent>
#include <QGuiApplication>
#include <QApplication>
#include <QFocusEvent>
#include "QParentWndWidget.h"
#include <qt_windows.h>
#if QT_VERSION >= 0x050000
#include <QWindow>
#endif
static HWND FindTopmostWindow(HWND child, bool considerWsChild)
{
if (child == GetDesktopWindow())
{
return 0;
}
HWND current = child;
while (GetParent(current) != 0)
{
if (considerWsChild && (GetWindowLongW(current, GWL_STYLE) & WS_CHILD) == 0)
{
break;
}
current = GetParent(current);
}
return current;
}
QParentWndWidget::QParentWndWidget(HWND parent)
: m_parent(parent)
, m_previousFocus(0)
, m_modalityRoot(0)
, m_parentToCenterOn(0)
{
if (m_parent)
{
SetWindowLongA((HWND)winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP);
#if QT_VERSION >= 0x50000
QWindow* window = windowHandle();
window->setProperty("_q_embedded_native_parent_handle", (WId)m_parent);
SetParent((HWND)winId(), m_parent);
window->setFlags(Qt::FramelessWindowHint);
#else
SetParent((HWND)winId(), m_parent);
#endif
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(this, &e);
}
m_parentToCenterOn = FindTopmostWindow(m_parent, true);
m_modalityRoot = FindTopmostWindow(m_parent, false);
}
void QParentWndWidget::childEvent(QChildEvent* ev)
{
QObject* child = ev->child();
if (child->isWidgetType())
{
if (ev->added())
{
if (child->isWidgetType())
{
child->installEventFilter(this);
}
}
else if (ev->removed() && m_parentWasDisabled)
{
m_parentWasDisabled = false;
EnableWindow(m_modalityRoot, true);
child->removeEventFilter(this);
}
}
QWidget::childEvent(ev);
}
void QParentWndWidget::show()
{
if (!m_previousFocus)
{
m_previousFocus = ::GetFocus();
}
if (!m_previousFocus)
{
m_previousFocus = parentWindow();
}
QWidget::show();
}
void QParentWndWidget::hide()
{
QWidget::hide();
}
void QParentWndWidget::center()
{
const QWidget* child = findChild<QWidget*>();
RECT rect;
GetWindowRect(m_parentToCenterOn, &rect);
setGeometry((rect.right - rect.left) / 2 + rect.left,
(rect.bottom - rect.top) / 2 + rect.top, 0, 0);
}
#if QT_VERSION >= 0x50000
bool QParentWndWidget::nativeEvent(const QByteArray&, void* message, long* result)
#else
bool QParentWndWidget::winEvent(MSG* msg, long* result)
#endif
{
#if QT_VERSION >= 0x50000
MSG* msg = (MSG*)message;
#endif
if (msg->message == WM_SETFOCUS)
{
Qt::FocusReason reason;
if (::GetKeyState(VK_LBUTTON) < 0 ||
::GetKeyState(VK_RBUTTON) < 0)
{
reason = Qt::MouseFocusReason;
}
else if (::GetKeyState(VK_SHIFT) < 0)
{
reason = Qt::BacktabFocusReason;
}
else
{
reason = Qt::TabFocusReason;
}
QFocusEvent ev(QEvent::FocusIn, reason);
QApplication::sendEvent(this, &ev);
}
if (msg->message == WM_GETDLGCODE)
{
*result = DLGC_WANTARROWS | DLGC_WANTTAB;
return(true);
}
return false;
}
bool QParentWndWidget::eventFilter(QObject* obj, QEvent* ev)
{
QWidget* widget = (QWidget*)obj;
switch (ev->type())
{
case QEvent::WindowDeactivate:
{
if (widget->isModal() && isHidden())
{
BringWindowToTop(m_parent);
}
break;
}
case QEvent::Show:
{
if (widget->isWindow())
{
if (!m_previousFocus)
{
m_previousFocus = ::GetFocus();
}
if (!m_previousFocus)
{
m_previousFocus = parentWindow();
}
hide();
if (widget->isModal() && !m_parentWasDisabled)
{
EnableWindow(m_modalityRoot, false);
m_parentWasDisabled = true;
}
}
break;
}
case QEvent::Hide:
{
if (m_parentWasDisabled)
{
EnableWindow(m_modalityRoot, true);
m_parentWasDisabled = false;
}
if (m_previousFocus)
{
::SetFocus(m_previousFocus);
}
else
{
::SetFocus(parentWindow());
}
if (widget->testAttribute(Qt::WA_DeleteOnClose) && widget->isWindow())
{
deleteLater();
}
break;
}
case QEvent::Close:
{
::SetActiveWindow(m_parent);
if (widget->testAttribute(Qt::WA_DeleteOnClose))
{
deleteLater();
}
break;
}
default:
break;
}
;
return QWidget::eventFilter(obj, ev);
}
void QParentWndWidget::focusInEvent(QFocusEvent* ev)
{
QWidget* candidate = this;
if (ev->reason() == Qt::TabFocusReason || ev->reason() == Qt::BacktabFocusReason)
{
while (candidate && (candidate->focusPolicy() & Qt::TabFocus) == 0)
{
candidate = candidate->nextInFocusChain();
if (candidate == this)
{
candidate = 0;
}
}
if (candidate)
{
candidate->setFocus(ev->reason());
candidate->setAttribute(Qt::WA_KeyboardFocusChange);
candidate->window()->setAttribute(Qt::WA_KeyboardFocusChange);
if (ev->reason() == Qt::BacktabFocusReason)
{
QWidget::focusNextPrevChild(false);
}
}
}
}
bool QParentWndWidget::focusNextPrevChild(bool next)
{
QWidget* current = focusWidget();
if (next)
{
QWidget* nextFocus = current;
while (true)
{
nextFocus = nextFocus->nextInFocusChain();
if (nextFocus->isWindow())
{
break;
}
if (nextFocus->focusPolicy() & Qt::TabFocus)
{
return QWidget::focusNextPrevChild(true);
}
}
}
else
{
if (!current->isWindow())
{
QWidget* nextFocus = current->nextInFocusChain();
QWidget* prevFocus = 0;
QWidget* topLevel = 0;
while (nextFocus != current)
{
if ((nextFocus->focusPolicy() & Qt::TabFocus) != 0)
{
prevFocus = nextFocus;
topLevel = 0;
}
else if (nextFocus->isWindow())
{
topLevel = nextFocus;
}
nextFocus = nextFocus->nextInFocusChain();
}
if (!topLevel)
{
return QWidget::focusNextPrevChild(false);
}
}
}
::SetFocus(m_parent);
return true;
}
#include <moc_QParentWndWidget.cpp>