QmlDesigner: Add indicator button as an item of the 3d toolbar

Task-number: QDS-12953
Change-Id: I00fd84000d2d61b296c91c52f47c140711dd0219
Reviewed-by: Shrief Gabr <shrief.gabr@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2024-06-05 14:33:34 +03:00
parent 1e3f8afdce
commit 08dcd7d47c
7 changed files with 353 additions and 13 deletions

View File

@@ -663,6 +663,7 @@ extend_qtc_plugin(QmlDesigner
edit3dtoolbarmenu.cpp edit3dtoolbarmenu.h
backgroundcolorselection.cpp backgroundcolorselection.h
bakelights.cpp bakelights.h
indicatoractionwidget.cpp indicatoractionwidget.h
snapconfiguration.cpp snapconfiguration.h
cameraspeedconfiguration.cpp cameraspeedconfiguration.h
bakelightsdatamodel.cpp bakelightsdatamodel.h

View File

@@ -3,9 +3,8 @@
#include "edit3dactions.h"
#include "bakelights.h"
#include "edit3dview.h"
#include "nodemetainfo.h"
#include "indicatoractionwidget.h"
#include "qmldesignerconstants.h"
#include "seekerslider.h"
@@ -34,10 +33,25 @@ void Edit3DActionTemplate::actionTriggered(bool b)
m_action(m_selectionContext);
}
Edit3DWidgetActionTemplate::Edit3DWidgetActionTemplate(QWidgetAction *widget)
Edit3DWidgetActionTemplate::Edit3DWidgetActionTemplate(QWidgetAction *widget,
SelectionContextOperation action)
: PureActionInterface(widget)
, m_action(action)
{
QObject::connect(widget, &QAction::triggered, widget, [this](bool value) {
actionTriggered(value);
});
}
void Edit3DWidgetActionTemplate::setSelectionContext(const SelectionContext &selectionContext)
{
m_selectionContext = selectionContext;
}
void Edit3DWidgetActionTemplate::actionTriggered([[maybe_unused]] bool b)
{
if (m_action)
m_action(m_selectionContext);
}
Edit3DAction::Edit3DAction(const QByteArray &menuId,
@@ -154,4 +168,34 @@ bool Edit3DBakeLightsAction::isEnabled(const SelectionContext &) const
&& !Utils3D::activeView3dId(m_view).isEmpty();
}
Edit3DIndicatorButtonAction::Edit3DIndicatorButtonAction(const QByteArray &menuId,
View3DActionType type,
const QString &description,
const QIcon &icon,
SelectionContextOperation customAction,
Edit3DView *view)
: Edit3DAction(menuId,
type,
view,
new Edit3DWidgetActionTemplate(new IndicatorButtonAction(description, icon),
customAction))
{
m_buttonAction = qobject_cast<IndicatorButtonAction *>(action());
}
void Edit3DIndicatorButtonAction::setIndicator(bool indicator)
{
m_buttonAction->setIndicator(indicator);
}
bool Edit3DIndicatorButtonAction::isVisible(const SelectionContext &) const
{
return m_buttonAction->isVisible();
}
bool Edit3DIndicatorButtonAction::isEnabled(const SelectionContext &) const
{
return m_buttonAction->isEnabled();
}
} // namespace QmlDesigner

View File

@@ -17,6 +17,7 @@ namespace QmlDesigner {
using SelectionContextOperation = std::function<void(const SelectionContext &)>;
class Edit3DView;
class SeekerSliderAction;
class IndicatorButtonAction;
class Edit3DActionTemplate : public DefaultAction
{
@@ -40,8 +41,13 @@ class Edit3DWidgetActionTemplate : public PureActionInterface
Q_DISABLE_COPY(Edit3DWidgetActionTemplate)
public:
explicit Edit3DWidgetActionTemplate(QWidgetAction *widget);
virtual void setSelectionContext(const SelectionContext &) {}
explicit Edit3DWidgetActionTemplate(QWidgetAction *widget, SelectionContextOperation action = {});
void setSelectionContext(const SelectionContext &selectionContext) override;
virtual void actionTriggered(bool b);
SelectionContextOperation m_action;
SelectionContext m_selectionContext;
};
class Edit3DAction : public AbstractAction
@@ -108,6 +114,27 @@ private:
SeekerSliderAction *m_seeker = nullptr;
};
class Edit3DIndicatorButtonAction : public Edit3DAction
{
public:
Edit3DIndicatorButtonAction(const QByteArray &menuId,
View3DActionType type,
const QString &description,
const QIcon &icon,
SelectionContextOperation customAction,
Edit3DView *view);
IndicatorButtonAction *buttonAction();
void setIndicator(bool indicator);
protected:
bool isVisible(const SelectionContext &) const override;
bool isEnabled(const SelectionContext &) const override;
private:
IndicatorButtonAction *m_buttonAction = nullptr;
};
class Edit3DBakeLightsAction : public Edit3DAction
{
public:

View File

@@ -57,6 +57,19 @@ inline static QIcon toolbarIcon(const DesignerIcons::IconId &iconId)
return DesignerActionManager::instance().toolbarIcon(iconId);
};
#ifdef Q_OS_MACOS
extern "C" bool AXIsProcessTrusted();
#endif
static bool isAXITrusted()
{
#ifdef Q_OS_MACOS
return AXIsProcessTrusted();
#else
return true;
#endif
}
Edit3DView::Edit3DView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
{
@@ -1315,17 +1328,16 @@ void Edit3DView::createEdit3DActions()
m_cameraSpeedConfiguration->showConfigDialog(resolveToolbarPopupPos(m_cameraSpeedConfigAction.get()));
};
m_cameraSpeedConfigAction = std::make_unique<Edit3DAction>(
m_cameraSpeedConfigAction = std::make_unique<Edit3DIndicatorButtonAction>(
QmlDesigner::Constants::EDIT3D_CAMERA_SPEED_CONFIG,
View3DActionType::Empty,
QCoreApplication::translate("CameraSpeedConfigAction", "Open camera speed configuration dialog"),
QKeySequence(),
false,
false,
QCoreApplication::translate("CameraSpeedConfigAction",
"Open camera speed configuration dialog"),
toolbarIcon(DesignerIcons::CameraSpeedConfigIcon),
this,
cameraSpeedConfigTrigger);
cameraSpeedConfigTrigger,
this);
m_cameraSpeedConfigAction->setIndicator(!isAXITrusted());
m_leftActions << m_selectionModeAction.get();
m_leftActions << nullptr; // Null indicates separator

View File

@@ -180,7 +180,7 @@ private:
std::unique_ptr<Edit3DAction> m_backgroundColorMenuAction;
std::unique_ptr<Edit3DAction> m_snapToggleAction;
std::unique_ptr<Edit3DAction> m_snapConfigAction;
std::unique_ptr<Edit3DAction> m_cameraSpeedConfigAction;
std::unique_ptr<Edit3DIndicatorButtonAction> m_cameraSpeedConfigAction;
std::unique_ptr<Edit3DBakeLightsAction> m_bakeLightsAction;
int particlemode;

View File

@@ -0,0 +1,193 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "indicatoractionwidget.h"
#include <theme.h>
#include <utils/icon.h>
#include <utils/stylehelper.h>
#include <QActionGroup>
#include <QMenu>
#include <QMouseEvent>
#include <QStyleOption>
#include <QStylePainter>
#include <QToolBar>
namespace QmlDesigner {
static void drawIndicator(QPainter *painter, const QPoint &point, int dimension)
{
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(Theme::getColor(Theme::DSamberLight));
painter->drawEllipse(point, dimension, dimension);
painter->restore();
}
IndicatorButton::IndicatorButton(QWidget *parent)
: QToolButton(parent)
{
Utils::StyleHelper::setPanelWidget(this);
Utils::StyleHelper::setPanelWidgetSingleRow(this);
}
bool IndicatorButton::indicator() const
{
return m_indicator;
}
void IndicatorButton::setIndicator(bool newIndicator)
{
if (m_indicator != newIndicator) {
m_indicator = newIndicator;
emit indicatorChanged(m_indicator);
update();
}
}
QSize IndicatorButton::sizeHint() const
{
if (QMenu *menu = qobject_cast<QMenu *>(parent())) {
ensurePolished();
QStyleOptionMenuItem opt;
initMenuStyleOption(menu, &opt, defaultAction());
QSize sz = style()
->itemTextRect(fontMetrics(), QRect(), Qt::TextShowMnemonic, false, text())
.size();
if (!opt.icon.isNull())
sz = QSize(sz.width() + opt.maxIconWidth + 4, qMax(sz.height(), opt.maxIconWidth));
QSize size = style()->sizeFromContents(QStyle::CT_MenuItem, &opt, sz, this);
return size;
}
return Super::sizeHint();
}
void IndicatorButton::paintEvent([[maybe_unused]] QPaintEvent *event)
{
QStylePainter p(this);
if (QMenu *menu = qobject_cast<QMenu *>(parent())) {
this->setFixedWidth(menu->width());
QStyleOptionMenuItem opt;
initMenuStyleOption(menu, &opt, defaultAction());
p.drawControl(QStyle::CE_MenuItem, opt);
if (indicator() && opt.maxIconWidth && !opt.icon.isNull()) {
const int indicatorDim = opt.rect.height() / 8;
const int indicatorOffset = indicatorDim * 5 / 4;
drawIndicator(&p,
opt.rect.topLeft()
+ QPoint{opt.rect.height() - indicatorOffset, indicatorOffset},
indicatorDim);
}
} else {
QStyleOptionToolButton option;
initStyleOption(&option);
p.drawComplexControl(QStyle::CC_ToolButton, option);
if (indicator() && option.iconSize.isValid() && !option.icon.isNull()) {
const int indicatorDim = std::min(option.rect.width(), option.rect.height()) / 8;
const int indicatorOffset = indicatorDim * 5 / 4;
drawIndicator(&p,
option.rect.topRight() + QPoint{-indicatorOffset, indicatorOffset},
indicatorDim);
}
}
}
void IndicatorButton::initMenuStyleOption(QMenu *menu,
QStyleOptionMenuItem *option,
const QAction *action) const
{
if (!option || !action)
return;
option->initFrom(menu);
option->palette = palette();
option->state = QStyle::State_None;
if (window()->isActiveWindow())
option->state |= QStyle::State_Active;
if (isEnabled() && action->isEnabled() && (!action->menu() || action->menu()->isEnabled()))
option->state |= QStyle::State_Enabled;
else
option->palette.setCurrentColorGroup(QPalette::Disabled);
option->font = action->font().resolve(font());
option->fontMetrics = QFontMetrics(option->font);
if (menu->activeAction() && menu->activeAction() == action)
option->state |= QStyle::State_Selected;
option->menuHasCheckableItems = false;
if (!action->isCheckable()) {
option->checkType = QStyleOptionMenuItem::NotCheckable;
} else {
option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive())
? QStyleOptionMenuItem::Exclusive
: QStyleOptionMenuItem::NonExclusive;
option->checked = action->isChecked();
}
if (action->menu())
option->menuItemType = QStyleOptionMenuItem::SubMenu;
else if (action->isSeparator())
option->menuItemType = QStyleOptionMenuItem::Separator;
else
option->menuItemType = QStyleOptionMenuItem::Normal;
if (action->isIconVisibleInMenu())
option->icon = action->icon();
option->text = action->text();
option->maxIconWidth = 20;
option->rect = rect();
}
IndicatorButtonAction::IndicatorButtonAction(const QString &description,
const QIcon &icon,
QObject *parent)
: QWidgetAction(parent)
{
setText(description);
setToolTip(description);
setIcon(icon);
}
IndicatorButtonAction::~IndicatorButtonAction() = default;
void IndicatorButtonAction::setIndicator(bool indicator)
{
if (m_indicator != indicator) {
m_indicator = indicator;
emit indicatorChanged(m_indicator, QPrivateSignal{});
}
}
QWidget *IndicatorButtonAction::createWidget(QWidget *parent)
{
if (QMenu *menu = qobject_cast<QMenu *>(parent))
return nullptr;
IndicatorButton *button = new IndicatorButton(parent);
connect(this, &IndicatorButtonAction::indicatorChanged, button, &IndicatorButton::setIndicator);
connect(button, &IndicatorButton::indicatorChanged, this, &IndicatorButtonAction::setIndicator);
connect(button, &QToolButton::clicked, this, &QAction::trigger);
button->setIndicator(m_indicator);
button->setDefaultAction(this);
if (QToolBar *tb = qobject_cast<QToolBar *>(parent)) {
button->setAutoRaise(true);
button->setFocusPolicy(Qt::NoFocus);
button->setIconSize(tb->iconSize());
button->setToolButtonStyle(tb->toolButtonStyle());
connect(tb, &QToolBar::iconSizeChanged, button, &IndicatorButton::setIconSize);
connect(tb, &QToolBar::toolButtonStyleChanged, button, &IndicatorButton::setToolButtonStyle);
connect(button, &IndicatorButton::triggered, tb, &QToolBar::actionTriggered);
}
return button;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <QToolButton>
#include <QWidgetAction>
QT_BEGIN_NAMESPACE
class QStyleOptionToolButton;
class QPaintEvent;
class QStyleOptionMenuItem;
QT_END_NAMESPACE
namespace QmlDesigner {
class IndicatorButton : public QToolButton
{
Q_OBJECT
Q_PROPERTY(bool indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
public:
explicit IndicatorButton(QWidget *parent = nullptr);
bool indicator() const;
void setIndicator(bool newIndicator);
protected:
QSize sizeHint() const override;
void paintEvent(QPaintEvent *event) override;
void initMenuStyleOption(QMenu *menu, QStyleOptionMenuItem *option, const QAction *action) const;
signals:
void indicatorChanged(bool);
private:
bool m_indicator = false;
using Super = QToolButton;
};
class IndicatorButtonAction : public QWidgetAction
{
Q_OBJECT
public:
explicit IndicatorButtonAction(const QString &description,
const QIcon &icon,
QObject *parent = nullptr);
virtual ~IndicatorButtonAction();
public slots:
void setIndicator(bool indicator);
protected:
virtual QWidget *createWidget(QWidget *parent) override;
private:
bool m_indicator;
signals:
void indicatorChanged(bool, QPrivateSignal);
};
} // namespace QmlDesigner