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/Components/Widgets/Menu.cpp

214 lines
6.9 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 <AzQtComponents/Components/Widgets/Menu.h>
#include <AzQtComponents/Components/Style.h>
#include <AzQtComponents/Components/ConfigHelpers.h>
#include <QApplication>
#include <QMenu>
#include <QPainter>
#include <QSettings>
#include <QStyleOption>
#include <QWindow>
#include <QSurfaceFormat>
#include <QTimer>
#include <QWindow>
#include <qdrawutil.h>
#include <limits>
namespace AzQtComponents
{
static void ReadMargins(QSettings& settings, const QString& name, Menu::Margins& margins)
{
ConfigHelpers::GroupGuard guard(&settings, name);
ConfigHelpers::read<int>(settings, QStringLiteral("Top"), margins.top);
ConfigHelpers::read<int>(settings, QStringLiteral("Right"), margins.right);
ConfigHelpers::read<int>(settings, QStringLiteral("Bottom"), margins.bottom);
ConfigHelpers::read<int>(settings, QStringLiteral("Left"), margins.left);
}
Menu::Config Menu::loadConfig(QSettings& settings)
{
Config config = defaultConfig();
ConfigHelpers::read<QPixmap>(settings, QStringLiteral("PixmapPath"), config.shadowPixmap);
ReadMargins(settings, QStringLiteral("PixmapMargins"), config.shadowMargins);
ConfigHelpers::read<QColor>(settings, QStringLiteral("BackgroundColor"), config.backgroundColor);
ConfigHelpers::read<int>(settings, QStringLiteral("Radius"), config.radius);
ConfigHelpers::read<int>(settings, QStringLiteral("HorizontalMargin"), config.horizontalMargin);
ConfigHelpers::read<int>(settings, QStringLiteral("VerticalMargin"), config.verticalMargin);
ConfigHelpers::read<int>(settings, QStringLiteral("HorizontalPadding"), config.horizontalPadding);
ConfigHelpers::read<int>(settings, QStringLiteral("VerticalPadding"), config.verticalPadding);
ConfigHelpers::read<int>(settings, QStringLiteral("SubMenuOverlap"), config.subMenuOverlap);
return config;
}
Menu::Config Menu::defaultConfig()
{
Config config;
config.shadowPixmap = QPixmap(QStringLiteral(":/stylesheet/img/UI20/shadows/menu-shadow.png"));
// 5px margin + 2px radius = 7px
config.shadowMargins.top = 7;
config.shadowMargins.right = 7;
config.shadowMargins.bottom = 7;
config.shadowMargins.left = 7;
config.backgroundColor = QStringLiteral("#222222");
config.radius = 2;
config.horizontalMargin = 5;
config.verticalMargin = 5;
config.horizontalPadding = 0;
config.verticalPadding = 4;
config.subMenuOverlap = 0;
return config;
}
bool Menu::polish(Style* style, QWidget* widget, const Config& config)
{
Q_UNUSED(config);
auto menu = qobject_cast<QMenu*>(widget);
if (!menu)
{
return false;
}
style->repolishOnSettingsChange(widget);
// QMenu::popup results in the QWindow being created before polish is called. If the QWindow
// is created with the wrong flags, window tranparency does not work. Check if the window
// surface format supports an alpha. If not, destroy it.
if (QWindow* window = menu->windowHandle())
{
if (!window->format().hasAlpha())
{
window->destroy();
}
}
// Set the widget attributes we need to enable window transparency. Do this before calling
// QWidget::setWindowFlags as the QWindow is created there if it does not exist.
menu->setAttribute(Qt::WA_TranslucentBackground, true);
menu->setAttribute(Qt::WA_OpaquePaintEvent, true);
menu->setWindowFlags(menu->windowFlags() | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
return true;
}
bool Menu::unpolish(Style* style, QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(config);
auto menu = qobject_cast<QMenu*>(widget);
if (!menu)
{
return false;
}
menu->setWindowFlags(menu->windowFlags());
menu->setAttribute(Qt::WA_TranslucentBackground, false);
menu->setAttribute(Qt::WA_OpaquePaintEvent, false);
return true;
}
int Menu::horizontalMargin(const Style* style, const QStyleOption* option, const QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(option);
if (qobject_cast<const QMenu*>(widget))
{
return config.horizontalMargin + config.horizontalPadding;
}
return -1;
}
int Menu::verticalMargin(const Style* style, const QStyleOption* option, const QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(option);
if (qobject_cast<const QMenu*>(widget))
{
return config.verticalMargin + config.verticalPadding;
}
return -1;
}
int Menu::subMenuOverlap(const Style* style, const QStyleOption* option, const QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(option);
if (qobject_cast<const QMenu*>(widget))
{
return config.subMenuOverlap;
}
return std::numeric_limits<int>::lowest();
}
int Menu::verticalShadowMargin(const Style* style, const QStyleOption* option, const QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(option);
if (qobject_cast<const QMenu*>(widget))
{
return -config.verticalMargin;
}
return std::numeric_limits<int>::lowest();
}
int Menu::horizontalShadowMargin(const Style* style, const QStyleOption* option, const QWidget* widget, const Config& config)
{
Q_UNUSED(style);
Q_UNUSED(option);
if (qobject_cast<const QMenu*>(widget))
{
return -config.horizontalMargin;
}
return std::numeric_limits<int>::lowest();
}
bool Menu::drawFrame(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Menu::Config& config)
{
Q_UNUSED(style);
auto menu = qobject_cast<const QMenu*>(widget);
if (!menu)
{
return false;
}
const auto& m = config.shadowMargins;
const QMargins shadowMargins(m.left, m.top, m.right, m.bottom);
qDrawBorderPixmap(painter, option->rect, shadowMargins, config.shadowPixmap);
painter->setPen(Qt::NoPen);
painter->setBrush(config.backgroundColor);
const auto hMargin = config.horizontalMargin;
const auto vMargin = config.verticalMargin;
painter->drawRoundedRect(option->rect.adjusted(hMargin, vMargin, -hMargin, -vMargin), config.radius, config.radius);
return true;
}
} // namespace AzQtComponents