forked from qt-creator/qt-creator
Add general UI introduction
Adds a Help > UI Introduction, which highlights basic aspects of the Qt Creator UI. The pages to show are defined in a format that can later move into a text based configuration file like JSON. It specifies an optional object name of a widget to highlight, a title, a brief description and a longer description (potentially with tables, lists and other simple HTML). Fixes: QTCREATORBUG-21585 Change-Id: Idb64c87e1d752bc24437588278093a96be0eeddb Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Tobias Hunger <tobias.hunger@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
@@ -277,7 +277,7 @@ QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButt
|
|||||||
return static_cast<QMessageBox::StandardButton>(int(db));
|
return static_cast<QMessageBox::StandardButton>(int(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool askAgain(QSettings *settings, const QString &settingsSubKey)
|
bool CheckableMessageBox::shouldAskAgain(QSettings *settings, const QString &settingsSubKey)
|
||||||
{
|
{
|
||||||
if (QTC_GUARD(settings)) {
|
if (QTC_GUARD(settings)) {
|
||||||
settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
|
settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
|
||||||
@@ -309,7 +309,7 @@ void initDoNotAskAgainMessageBox(CheckableMessageBox &messageBox, const QString
|
|||||||
messageBox.setDefaultButton(defaultButton);
|
messageBox.setDefaultButton(defaultButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doNotAskAgain(QSettings *settings, const QString &settingsSubKey)
|
void CheckableMessageBox::doNotAskAgain(QSettings *settings, const QString &settingsSubKey)
|
||||||
{
|
{
|
||||||
if (!settings)
|
if (!settings)
|
||||||
return;
|
return;
|
||||||
@@ -337,7 +337,7 @@ CheckableMessageBox::doNotAskAgainQuestion(QWidget *parent, const QString &title
|
|||||||
QDialogButtonBox::StandardButton acceptButton)
|
QDialogButtonBox::StandardButton acceptButton)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!askAgain(settings, settingsSubKey))
|
if (!shouldAskAgain(settings, settingsSubKey))
|
||||||
return acceptButton;
|
return acceptButton;
|
||||||
|
|
||||||
CheckableMessageBox messageBox(parent);
|
CheckableMessageBox messageBox(parent);
|
||||||
@@ -365,7 +365,7 @@ CheckableMessageBox::doNotShowAgainInformation(QWidget *parent, const QString &t
|
|||||||
QDialogButtonBox::StandardButton defaultButton)
|
QDialogButtonBox::StandardButton defaultButton)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!askAgain(settings, settingsSubKey))
|
if (!shouldAskAgain(settings, settingsSubKey))
|
||||||
return defaultButton;
|
return defaultButton;
|
||||||
|
|
||||||
CheckableMessageBox messageBox(parent);
|
CheckableMessageBox messageBox(parent);
|
||||||
|
@@ -117,6 +117,10 @@ public:
|
|||||||
QAbstractButton *clickedButton() const;
|
QAbstractButton *clickedButton() const;
|
||||||
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
QDialogButtonBox::StandardButton clickedStandardButton() const;
|
||||||
|
|
||||||
|
// check and set "ask again" status
|
||||||
|
static bool shouldAskAgain(QSettings *settings, const QString &settingsSubKey);
|
||||||
|
static void doNotAskAgain(QSettings *settings, const QString &settingsSubKey);
|
||||||
|
|
||||||
// Conversion convenience
|
// Conversion convenience
|
||||||
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
|
||||||
static void resetAllDoNotAskAgainQuestions(QSettings *settings);
|
static void resetAllDoNotAskAgainQuestions(QSettings *settings);
|
||||||
|
@@ -373,6 +373,8 @@ void FancyActionBar::addProjectSelector(QAction *action)
|
|||||||
void FancyActionBar::insertAction(int index, QAction *action)
|
void FancyActionBar::insertAction(int index, QAction *action)
|
||||||
{
|
{
|
||||||
auto *button = new FancyToolButton(action, this);
|
auto *button = new FancyToolButton(action, this);
|
||||||
|
if (!action->objectName().isEmpty())
|
||||||
|
button->setObjectName(action->objectName() + ".Button"); // used for UI introduction
|
||||||
button->setIconsOnly(m_iconsOnly);
|
button->setIconsOnly(m_iconsOnly);
|
||||||
m_actionsLayout->insertWidget(index, button);
|
m_actionsLayout->insertWidget(index, button);
|
||||||
}
|
}
|
||||||
|
@@ -458,6 +458,7 @@ FancyTabWidget::FancyTabWidget(QWidget *parent)
|
|||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
m_tabBar = new FancyTabBar(this);
|
m_tabBar = new FancyTabBar(this);
|
||||||
|
m_tabBar->setObjectName("ModeSelector"); // used for UI introduction
|
||||||
|
|
||||||
m_selectionWidget = new QWidget(this);
|
m_selectionWidget = new QWidget(this);
|
||||||
auto selectionLayout = new QVBoxLayout;
|
auto selectionLayout = new QVBoxLayout;
|
||||||
@@ -473,7 +474,8 @@ FancyTabWidget::FancyTabWidget(QWidget *parent)
|
|||||||
layout->addWidget(fancyButton);
|
layout->addWidget(fancyButton);
|
||||||
selectionLayout->addWidget(bar);
|
selectionLayout->addWidget(bar);
|
||||||
|
|
||||||
selectionLayout->addWidget(m_tabBar, 1);
|
selectionLayout->addWidget(m_tabBar);
|
||||||
|
selectionLayout->addStretch(1);
|
||||||
m_selectionWidget->setLayout(selectionLayout);
|
m_selectionWidget->setLayout(selectionLayout);
|
||||||
m_selectionWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
m_selectionWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
|
||||||
@@ -551,6 +553,7 @@ void FancyTabWidget::paintEvent(QPaintEvent *event)
|
|||||||
const QRectF boderRect = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5);
|
const QRectF boderRect = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5);
|
||||||
|
|
||||||
if (creatorTheme()->flag(Theme::FlatToolBars)) {
|
if (creatorTheme()->flag(Theme::FlatToolBars)) {
|
||||||
|
painter.fillRect(event->rect(), StyleHelper::baseColor());
|
||||||
painter.setPen(StyleHelper::toolBarBorderColor());
|
painter.setPen(StyleHelper::toolBarBorderColor());
|
||||||
painter.drawLine(boderRect.topRight(), boderRect.bottomRight());
|
painter.drawLine(boderRect.topRight(), boderRect.bottomRight());
|
||||||
} else {
|
} else {
|
||||||
|
@@ -123,6 +123,7 @@ void Locator::initialize()
|
|||||||
mtools->addAction(cmd);
|
mtools->addAction(cmd);
|
||||||
|
|
||||||
auto locatorWidget = LocatorManager::createLocatorInputWidget(ICore::mainWindow());
|
auto locatorWidget = LocatorManager::createLocatorInputWidget(ICore::mainWindow());
|
||||||
|
locatorWidget->setObjectName("LocatorInput"); // used for UI introduction
|
||||||
StatusBarManager::addStatusBarWidget(locatorWidget, StatusBarManager::First,
|
StatusBarManager::addStatusBarWidget(locatorWidget, StatusBarManager::First,
|
||||||
Context("LocatorWidget"));
|
Context("LocatorWidget"));
|
||||||
connect(ICore::instance(), &ICore::saveSettingsRequested, this, &Locator::saveSettings);
|
connect(ICore::instance(), &ICore::saveSettingsRequested, this, &Locator::saveSettings);
|
||||||
|
@@ -232,6 +232,7 @@ OutputPaneManager::OutputPaneManager(QWidget *parent) :
|
|||||||
setLayout(mainlayout);
|
setLayout(mainlayout);
|
||||||
|
|
||||||
m_buttonsWidget = new QWidget;
|
m_buttonsWidget = new QWidget;
|
||||||
|
m_buttonsWidget->setObjectName("OutputPaneButtons"); // used for UI introduction
|
||||||
m_buttonsWidget->setLayout(new QHBoxLayout);
|
m_buttonsWidget->setLayout(new QHBoxLayout);
|
||||||
m_buttonsWidget->layout()->setContentsMargins(5,0,0,0);
|
m_buttonsWidget->layout()->setContentsMargins(5,0,0,0);
|
||||||
m_buttonsWidget->layout()->setSpacing(
|
m_buttonsWidget->layout()->setSpacing(
|
||||||
|
@@ -300,6 +300,7 @@ void ProgressManagerPrivate::init()
|
|||||||
readSettings();
|
readSettings();
|
||||||
|
|
||||||
m_statusBarWidget = new QWidget;
|
m_statusBarWidget = new QWidget;
|
||||||
|
m_statusBarWidget->setObjectName("ProgressInfo"); // used for UI introduction
|
||||||
auto layout = new QHBoxLayout(m_statusBarWidget);
|
auto layout = new QHBoxLayout(m_statusBarWidget);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
|
@@ -1120,6 +1120,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
|
|||||||
m_visibleStartAction.setAttribute(ProxyAction::UpdateIcon);
|
m_visibleStartAction.setAttribute(ProxyAction::UpdateIcon);
|
||||||
m_visibleStartAction.setAction(&m_startAction);
|
m_visibleStartAction.setAction(&m_startAction);
|
||||||
|
|
||||||
|
m_visibleStartAction.setObjectName("Debug"); // used for UI introduction
|
||||||
ModeManager::addAction(&m_visibleStartAction, Constants::P_ACTION_DEBUG);
|
ModeManager::addAction(&m_visibleStartAction, Constants::P_ACTION_DEBUG);
|
||||||
|
|
||||||
m_undisturbableAction.setIcon(interruptIcon(false));
|
m_undisturbableAction.setIcon(interruptIcon(false));
|
||||||
|
@@ -984,6 +984,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
|||||||
|
|
||||||
// Add to mode bar
|
// Add to mode bar
|
||||||
dd->m_modeBarBuildAction = new Utils::ProxyAction(this);
|
dd->m_modeBarBuildAction = new Utils::ProxyAction(this);
|
||||||
|
dd->m_modeBarBuildAction->setObjectName("Build"); // used for UI introduction
|
||||||
dd->m_modeBarBuildAction->initialize(cmd->action());
|
dd->m_modeBarBuildAction->initialize(cmd->action());
|
||||||
dd->m_modeBarBuildAction->setAttribute(Utils::ProxyAction::UpdateText);
|
dd->m_modeBarBuildAction->setAttribute(Utils::ProxyAction::UpdateText);
|
||||||
dd->m_modeBarBuildAction->setAction(cmd->action());
|
dd->m_modeBarBuildAction->setAction(cmd->action());
|
||||||
@@ -1027,6 +1028,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
|||||||
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+R")));
|
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+R")));
|
||||||
mbuild->addAction(cmd, Constants::G_BUILD_RUN);
|
mbuild->addAction(cmd, Constants::G_BUILD_RUN);
|
||||||
|
|
||||||
|
cmd->action()->setObjectName("Run"); // used for UI introduction
|
||||||
ModeManager::addAction(cmd->action(), Constants::P_ACTION_RUN);
|
ModeManager::addAction(cmd->action(), Constants::P_ACTION_RUN);
|
||||||
|
|
||||||
// Run without deployment action
|
// Run without deployment action
|
||||||
@@ -1213,6 +1215,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
|
|||||||
|
|
||||||
// target selector
|
// target selector
|
||||||
dd->m_projectSelectorAction = new QAction(this);
|
dd->m_projectSelectorAction = new QAction(this);
|
||||||
|
dd->m_projectSelectorAction->setObjectName("KitSelector"); // used for UI introduction
|
||||||
dd->m_projectSelectorAction->setCheckable(true);
|
dd->m_projectSelectorAction->setCheckable(true);
|
||||||
dd->m_projectSelectorAction->setEnabled(false);
|
dd->m_projectSelectorAction->setEnabled(false);
|
||||||
QWidget *mainWindow = ICore::mainWindow();
|
QWidget *mainWindow = ICore::mainWindow();
|
||||||
|
BIN
src/plugins/welcome/images/border.png
Normal file
BIN
src/plugins/welcome/images/border.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 852 B |
399
src/plugins/welcome/introductionwidget.cpp
Normal file
399
src/plugins/welcome/introductionwidget.cpp
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "introductionwidget.h"
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/checkablemessagebox.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/stylehelper.h>
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
const char kTakeTourSetting[] = "TakeUITour";
|
||||||
|
|
||||||
|
namespace Welcome {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
void IntroductionWidget::askUserAboutIntroduction(QWidget *parent, QSettings *settings)
|
||||||
|
{
|
||||||
|
if (!CheckableMessageBox::shouldAskAgain(settings, kTakeTourSetting))
|
||||||
|
return;
|
||||||
|
auto messageBox = new CheckableMessageBox(parent);
|
||||||
|
messageBox->setWindowTitle(tr("Take a UI Tour"));
|
||||||
|
messageBox->setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
|
||||||
|
messageBox->setText(
|
||||||
|
tr("Do you want to take a quick UI tour? This shows where the most important user "
|
||||||
|
"interface elements are, and how they are used, and will only take a minute. You can "
|
||||||
|
"also take the tour later by selecting Help > UI Tour."));
|
||||||
|
messageBox->setCheckBoxVisible(true);
|
||||||
|
messageBox->setCheckBoxText(CheckableMessageBox::msgDoNotAskAgain());
|
||||||
|
messageBox->setChecked(true);
|
||||||
|
messageBox->setStandardButtons(QDialogButtonBox::Cancel);
|
||||||
|
QPushButton *tourButton = messageBox->addButton(tr("Take UI Tour"), QDialogButtonBox::AcceptRole);
|
||||||
|
connect(messageBox, &QDialog::finished, parent, [parent, settings, messageBox, tourButton]() {
|
||||||
|
if (messageBox->isChecked())
|
||||||
|
CheckableMessageBox::doNotAskAgain(settings, kTakeTourSetting);
|
||||||
|
if (messageBox->clickedButton() == tourButton) {
|
||||||
|
auto intro = new IntroductionWidget(parent);
|
||||||
|
intro->show();
|
||||||
|
}
|
||||||
|
messageBox->deleteLater();
|
||||||
|
});
|
||||||
|
messageBox->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
IntroductionWidget::IntroductionWidget(QWidget *parent)
|
||||||
|
: QWidget(parent),
|
||||||
|
m_borderImage(std::make_unique<QImage>(":/welcome/images/border.png"))
|
||||||
|
{
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setFocus();
|
||||||
|
parent->installEventFilter(this);
|
||||||
|
|
||||||
|
QPalette p = palette();
|
||||||
|
p.setColor(QPalette::Foreground, QColor(220, 220, 220));
|
||||||
|
setPalette(p);
|
||||||
|
|
||||||
|
m_textWidget = new QWidget(this);
|
||||||
|
auto layout = new QVBoxLayout;
|
||||||
|
m_textWidget->setLayout(layout);
|
||||||
|
|
||||||
|
m_stepText = new QLabel(this);
|
||||||
|
m_stepText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
m_stepText->setWordWrap(true);
|
||||||
|
m_stepText->setTextFormat(Qt::RichText);
|
||||||
|
// why is palette not inherited???
|
||||||
|
m_stepText->setPalette(palette());
|
||||||
|
m_stepText->setOpenExternalLinks(true);
|
||||||
|
m_stepText->installEventFilter(this);
|
||||||
|
layout->addWidget(m_stepText);
|
||||||
|
|
||||||
|
m_continueLabel = new QLabel(this);
|
||||||
|
m_continueLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_continueLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
m_continueLabel->setWordWrap(true);
|
||||||
|
auto fnt = font();
|
||||||
|
fnt.setPointSizeF(fnt.pointSizeF() * 1.5);
|
||||||
|
m_continueLabel->setFont(fnt);
|
||||||
|
m_continueLabel->setPalette(palette());
|
||||||
|
layout->addWidget(m_continueLabel);
|
||||||
|
m_bodyCss = "font-size: 16px;";
|
||||||
|
m_items = {
|
||||||
|
{"ModeSelector",
|
||||||
|
tr("Mode Selector"),
|
||||||
|
tr("Select different modes depending on the task at hand."),
|
||||||
|
tr("<p style=\"margin-top: 30px\"><table>"
|
||||||
|
"<tr><td style=\"padding-right: 20px\">Welcome:</td><td>Open examples, tutorials, and "
|
||||||
|
"recent sessions and projects.</td></tr>"
|
||||||
|
"<tr><td>Edit:</td><td>Work with code and navigate your project.</td></tr>"
|
||||||
|
"<tr><td>Design:</td><td>Work with UI designs for Qt Widgets or Qt Quick.</td></tr>"
|
||||||
|
"<tr><td>Debug:</td><td>Analyze your application with a debugger or other "
|
||||||
|
"analyzer.</td></tr>"
|
||||||
|
"<tr><td>Projects:</td><td>Manage project settings.</td></tr>"
|
||||||
|
"<tr><td>Help:</td><td>Browse the help database.</td></tr>"
|
||||||
|
"</table></p>")},
|
||||||
|
{"KitSelector.Button",
|
||||||
|
tr("Kit Selector"),
|
||||||
|
tr("Select the active project or project configuration."),
|
||||||
|
""},
|
||||||
|
{"Run.Button",
|
||||||
|
tr("Run Button"),
|
||||||
|
tr("Run the active project. By default this builds the project first."),
|
||||||
|
""},
|
||||||
|
{"Debug.Button", tr("Debug Button"), tr("Run the active project in a debugger."), ""},
|
||||||
|
{"Build.Button", tr("Build Button"), tr("Build the active project."), ""},
|
||||||
|
{"LocatorInput",
|
||||||
|
tr("Locator"),
|
||||||
|
tr("Type here to open a file from any open project."),
|
||||||
|
tr("Or:"
|
||||||
|
"<ul>"
|
||||||
|
"<li>type <code>c<space><pattern></code> to jump to a class definition</li>"
|
||||||
|
"<li>type <code>f<space><pattern></code> to open a file from the file "
|
||||||
|
"system</li>"
|
||||||
|
"<li>click on the magnifier icon for a complete list of possible options</li>"
|
||||||
|
"</ul>")},
|
||||||
|
{"OutputPaneButtons",
|
||||||
|
tr("Output Panes"),
|
||||||
|
tr("Find compile and application output here, "
|
||||||
|
"as well as a list of configuration and build issues, "
|
||||||
|
"and the panel for global searches."),
|
||||||
|
""},
|
||||||
|
{"ProgressInfo",
|
||||||
|
tr("Progress Indicator"),
|
||||||
|
tr("Progress information about running tasks is shown here."),
|
||||||
|
""},
|
||||||
|
{{},
|
||||||
|
tr("Escape to Editor"),
|
||||||
|
tr("Pressing the Escape key brings you back to the editor. Press it "
|
||||||
|
"multiple times to also hide output panes and context help, giving the editor more "
|
||||||
|
"space."),
|
||||||
|
""},
|
||||||
|
{{},
|
||||||
|
tr("The End"),
|
||||||
|
tr("You have now completed the UI tour. To learn more about the highlighted "
|
||||||
|
"controls, see <a style=\"color: #41CD52\" "
|
||||||
|
"href=\"qthelp://org.qt-project.qtcreator/doc/creator-quick-tour.html\">User "
|
||||||
|
"Interface</a>."),
|
||||||
|
""}};
|
||||||
|
setStep(0);
|
||||||
|
resizeToParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IntroductionWidget::event(QEvent *e)
|
||||||
|
{
|
||||||
|
if (e->type() == QEvent::ShortcutOverride) {
|
||||||
|
e->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QWidget::event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IntroductionWidget::eventFilter(QObject *obj, QEvent *ev)
|
||||||
|
{
|
||||||
|
if (obj == parent() && ev->type() == QEvent::Resize)
|
||||||
|
resizeToParent();
|
||||||
|
else if (obj == m_stepText && ev->type() == QEvent::MouseButtonRelease)
|
||||||
|
step();
|
||||||
|
return QWidget::eventFilter(obj, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int SPOTLIGHTMARGIN = 18;
|
||||||
|
const int POINTER_SIZE = 30;
|
||||||
|
const int POINTER_WIDTH = 3;
|
||||||
|
|
||||||
|
static int margin(const QRect &small, const QRect &big, Qt::Alignment side)
|
||||||
|
{
|
||||||
|
switch (side) {
|
||||||
|
case Qt::AlignRight:
|
||||||
|
return qMax(0, big.right() - small.right());
|
||||||
|
case Qt::AlignTop:
|
||||||
|
return qMax(0, small.top() - big.top());
|
||||||
|
case Qt::AlignBottom:
|
||||||
|
return qMax(0, big.bottom() - small.bottom());
|
||||||
|
case Qt::AlignLeft:
|
||||||
|
return qMax(0, small.x() - big.x());
|
||||||
|
default:
|
||||||
|
QTC_ASSERT(false, return 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oppositeMargin(const QRect &small, const QRect &big, Qt::Alignment side)
|
||||||
|
{
|
||||||
|
switch (side) {
|
||||||
|
case Qt::AlignRight:
|
||||||
|
return margin(small, big, Qt::AlignLeft);
|
||||||
|
case Qt::AlignTop:
|
||||||
|
return margin(small, big, Qt::AlignBottom);
|
||||||
|
case Qt::AlignBottom:
|
||||||
|
return margin(small, big, Qt::AlignTop);
|
||||||
|
case Qt::AlignLeft:
|
||||||
|
return margin(small, big, Qt::AlignRight);
|
||||||
|
default:
|
||||||
|
QTC_ASSERT(false, return 100000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QVector<QPolygonF> pointerPolygon(const QRect &anchorRect, const QRect &fullRect)
|
||||||
|
{
|
||||||
|
// Put the arrow opposite to the smallest margin,
|
||||||
|
// with priority right, top, bottom, left.
|
||||||
|
// Not very sophisticated but sufficient for current use cases.
|
||||||
|
QVector<Qt::Alignment> alignments{Qt::AlignRight, Qt::AlignTop, Qt::AlignBottom, Qt::AlignLeft};
|
||||||
|
Utils::sort(alignments, [anchorRect, fullRect](Qt::Alignment a, Qt::Alignment b) {
|
||||||
|
return oppositeMargin(anchorRect, fullRect, a) < oppositeMargin(anchorRect, fullRect, b);
|
||||||
|
});
|
||||||
|
const auto alignIt = std::find_if(alignments.cbegin(),
|
||||||
|
alignments.cend(),
|
||||||
|
[anchorRect, fullRect](Qt::Alignment align) {
|
||||||
|
return margin(anchorRect, fullRect, align) > POINTER_SIZE;
|
||||||
|
});
|
||||||
|
if (alignIt == alignments.cend())
|
||||||
|
return {{}}; // no side with sufficient space found
|
||||||
|
const qreal arrowHeadWidth = POINTER_SIZE/3.;
|
||||||
|
if (*alignIt == Qt::AlignRight) {
|
||||||
|
const qreal middleY = anchorRect.center().y();
|
||||||
|
const qreal startX = anchorRect.right() + POINTER_SIZE;
|
||||||
|
const qreal endX = anchorRect.right() + POINTER_WIDTH;
|
||||||
|
return {{QVector<QPointF>{{startX, middleY}, {endX, middleY}}},
|
||||||
|
QVector<QPointF>{{endX + arrowHeadWidth, middleY - arrowHeadWidth},
|
||||||
|
{endX, middleY},
|
||||||
|
{endX + arrowHeadWidth, middleY + arrowHeadWidth}}};
|
||||||
|
}
|
||||||
|
if (*alignIt == Qt::AlignTop) {
|
||||||
|
const qreal middleX = anchorRect.center().x();
|
||||||
|
const qreal startY = anchorRect.y() - POINTER_SIZE;
|
||||||
|
const qreal endY = anchorRect.y() - POINTER_WIDTH;
|
||||||
|
return {{QVector<QPointF>{{middleX, startY}, {middleX, endY}}},
|
||||||
|
QVector<QPointF>{{middleX - arrowHeadWidth, endY - arrowHeadWidth},
|
||||||
|
{middleX, endY},
|
||||||
|
{middleX + arrowHeadWidth, endY - arrowHeadWidth}}};
|
||||||
|
}
|
||||||
|
if (*alignIt == Qt::AlignBottom) {
|
||||||
|
const qreal middleX = anchorRect.center().x();
|
||||||
|
const qreal startY = anchorRect.y() + POINTER_WIDTH;
|
||||||
|
const qreal endY = anchorRect.y() + POINTER_SIZE;
|
||||||
|
return {{QVector<QPointF>{{middleX, startY}, {middleX, endY}}},
|
||||||
|
QVector<QPointF>{{middleX - arrowHeadWidth, endY + arrowHeadWidth},
|
||||||
|
{middleX, endY},
|
||||||
|
{middleX + arrowHeadWidth, endY + arrowHeadWidth}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt::AlignLeft
|
||||||
|
const qreal middleY = anchorRect.center().y();
|
||||||
|
const qreal startX = anchorRect.x() - POINTER_WIDTH;
|
||||||
|
const qreal endX = anchorRect.x() - POINTER_SIZE;
|
||||||
|
return {{QVector<QPointF>{{startX, middleY}, {endX, middleY}}},
|
||||||
|
QVector<QPointF>{{endX - arrowHeadWidth, middleY - arrowHeadWidth},
|
||||||
|
{endX, middleY},
|
||||||
|
{endX - arrowHeadWidth, middleY + arrowHeadWidth}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
QPainter p(this);
|
||||||
|
p.setOpacity(.87);
|
||||||
|
const QColor backgroundColor = Qt::black;
|
||||||
|
if (m_stepPointerAnchor) {
|
||||||
|
const QPoint anchorPos = m_stepPointerAnchor->mapTo(parentWidget(), {0, 0});
|
||||||
|
const QRect anchorRect(anchorPos, m_stepPointerAnchor->size());
|
||||||
|
const QRect spotlightRect = anchorRect.adjusted(-SPOTLIGHTMARGIN,
|
||||||
|
-SPOTLIGHTMARGIN,
|
||||||
|
SPOTLIGHTMARGIN,
|
||||||
|
SPOTLIGHTMARGIN);
|
||||||
|
|
||||||
|
// darken the background to create a spotlighted area
|
||||||
|
if (spotlightRect.left() > 0) {
|
||||||
|
p.fillRect(0, 0, spotlightRect.left(), height(), backgroundColor);
|
||||||
|
}
|
||||||
|
if (spotlightRect.top() > 0) {
|
||||||
|
p.fillRect(spotlightRect.left(),
|
||||||
|
0,
|
||||||
|
width() - spotlightRect.left(),
|
||||||
|
spotlightRect.top(),
|
||||||
|
backgroundColor);
|
||||||
|
}
|
||||||
|
if (spotlightRect.right() < width() - 1) {
|
||||||
|
p.fillRect(spotlightRect.right() + 1,
|
||||||
|
spotlightRect.top(),
|
||||||
|
width() - spotlightRect.right() - 1,
|
||||||
|
height() - spotlightRect.top(),
|
||||||
|
backgroundColor);
|
||||||
|
}
|
||||||
|
if (spotlightRect.bottom() < height() - 1) {
|
||||||
|
p.fillRect(spotlightRect.left(),
|
||||||
|
spotlightRect.bottom() + 1,
|
||||||
|
spotlightRect.width(),
|
||||||
|
height() - spotlightRect.bottom() - 1,
|
||||||
|
backgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// smooth borders of the spotlighted area by gradients
|
||||||
|
StyleHelper::drawCornerImage(*m_borderImage,
|
||||||
|
&p,
|
||||||
|
spotlightRect,
|
||||||
|
SPOTLIGHTMARGIN,
|
||||||
|
SPOTLIGHTMARGIN,
|
||||||
|
SPOTLIGHTMARGIN,
|
||||||
|
SPOTLIGHTMARGIN);
|
||||||
|
|
||||||
|
// draw pointer
|
||||||
|
const QColor qtGreen(65, 205, 82);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
p.setPen(QPen(QBrush(qtGreen),
|
||||||
|
POINTER_WIDTH,
|
||||||
|
Qt::SolidLine,
|
||||||
|
Qt::RoundCap,
|
||||||
|
Qt::MiterJoin));
|
||||||
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
|
for (const QPolygonF &poly : pointerPolygon(spotlightRect, rect()))
|
||||||
|
p.drawPolyline(poly);
|
||||||
|
} else {
|
||||||
|
p.fillRect(rect(), backgroundColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::keyPressEvent(QKeyEvent *ke)
|
||||||
|
{
|
||||||
|
if (ke->key() == Qt::Key_Escape)
|
||||||
|
finish();
|
||||||
|
else if (ke->modifiers() == Qt::NoModifier)
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::mouseReleaseEvent(QMouseEvent *me)
|
||||||
|
{
|
||||||
|
me->accept();
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::finish()
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::step()
|
||||||
|
{
|
||||||
|
if (m_step >= m_items.size() - 1)
|
||||||
|
finish();
|
||||||
|
else
|
||||||
|
setStep(m_step + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::setStep(uint index)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(index < m_items.size(), return);
|
||||||
|
m_step = index;
|
||||||
|
m_continueLabel->setText(tr("UI Introduction %1/%2 >").arg(m_step + 1).arg(m_items.size()));
|
||||||
|
const Item &item = m_items.at(m_step);
|
||||||
|
m_stepText->setText("<html><body style=\"" + m_bodyCss + "\">" + "<h1>" + item.title
|
||||||
|
+ "</h1><p>" + item.brief + "</p>" + item.description + "</body></html>");
|
||||||
|
const QString anchorObjectName = m_items.at(m_step).pointerAnchorObjectName;
|
||||||
|
if (!anchorObjectName.isEmpty()) {
|
||||||
|
m_stepPointerAnchor = parentWidget()->findChild<QWidget *>(anchorObjectName);
|
||||||
|
QTC_CHECK(m_stepPointerAnchor);
|
||||||
|
} else {
|
||||||
|
m_stepPointerAnchor.clear();
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntroductionWidget::resizeToParent()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(parentWidget(), return);
|
||||||
|
setGeometry(QRect(QPoint(0, 0), parentWidget()->size()));
|
||||||
|
m_textWidget->setGeometry(QRect(width()/4, height()/4, width()/2, height()/2));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Welcome
|
82
src/plugins/welcome/introductionwidget.h
Normal file
82
src/plugins/welcome/introductionwidget.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2018 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QLabel;
|
||||||
|
class QSettings;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Welcome {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
QString pointerAnchorObjectName;
|
||||||
|
QString title;
|
||||||
|
QString brief;
|
||||||
|
QString description;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IntroductionWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit IntroductionWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
static void askUserAboutIntroduction(QWidget *parent, QSettings *settings);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *e) override;
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||||
|
void paintEvent(QPaintEvent *ev) override;
|
||||||
|
void keyPressEvent(QKeyEvent *ke) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *me) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void finish();
|
||||||
|
void step();
|
||||||
|
void setStep(uint index);
|
||||||
|
void resizeToParent();
|
||||||
|
|
||||||
|
QWidget *m_textWidget;
|
||||||
|
QLabel *m_stepText;
|
||||||
|
QLabel *m_continueLabel;
|
||||||
|
std::unique_ptr<QImage> m_borderImage;
|
||||||
|
QString m_bodyCss;
|
||||||
|
std::vector<Item> m_items;
|
||||||
|
QPointer<QWidget> m_stepPointerAnchor;
|
||||||
|
uint m_step = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Welcome
|
@@ -1,8 +1,12 @@
|
|||||||
|
|
||||||
include(../../qtcreatorplugin.pri)
|
include(../../qtcreatorplugin.pri)
|
||||||
|
|
||||||
SOURCES += welcomeplugin.cpp
|
SOURCES += welcomeplugin.cpp \
|
||||||
|
introductionwidget.cpp
|
||||||
|
|
||||||
DEFINES += WELCOME_LIBRARY
|
DEFINES += WELCOME_LIBRARY
|
||||||
|
|
||||||
RESOURCES += welcome.qrc
|
RESOURCES += welcome.qrc
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
introductionwidget.h
|
||||||
|
@@ -22,5 +22,6 @@
|
|||||||
<file>images/new@2x.png</file>
|
<file>images/new@2x.png</file>
|
||||||
<file>images/expandarrow.png</file>
|
<file>images/expandarrow.png</file>
|
||||||
<file>images/expandarrow@2x.png</file>
|
<file>images/expandarrow@2x.png</file>
|
||||||
|
<file>images/border.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -23,11 +23,14 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "introductionwidget.h"
|
||||||
|
|
||||||
#include <extensionsystem/iplugin.h>
|
#include <extensionsystem/iplugin.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
#include <app/app_version.h>
|
#include <app/app_version.h>
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/actionmanager/command.h>
|
#include <coreplugin/actionmanager/command.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
@@ -139,6 +142,18 @@ public:
|
|||||||
{
|
{
|
||||||
m_welcomeMode->initPlugins();
|
m_welcomeMode->initPlugins();
|
||||||
ModeManager::activateMode(m_welcomeMode->id());
|
ModeManager::activateMode(m_welcomeMode->id());
|
||||||
|
auto introAction = new QAction(tr("UI Tour"), this);
|
||||||
|
connect(introAction, &QAction::triggered, this, []() {
|
||||||
|
auto intro = new IntroductionWidget(ICore::mainWindow());
|
||||||
|
intro->show();
|
||||||
|
});
|
||||||
|
Command *cmd = ActionManager::registerAction(introAction, "Welcome.UITour");
|
||||||
|
ActionContainer *mhelp = ActionManager::actionContainer(Core::Constants::M_HELP);
|
||||||
|
if (QTC_GUARD(mhelp))
|
||||||
|
mhelp->addAction(cmd, Core::Constants::G_HELP_HELP);
|
||||||
|
connect(ICore::instance(), &ICore::coreOpened, this, []() {
|
||||||
|
IntroductionWidget::askUserAboutIntroduction(ICore::mainWindow(), ICore::settings());
|
||||||
|
}, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
WelcomeMode *m_welcomeMode = nullptr;
|
WelcomeMode *m_welcomeMode = nullptr;
|
||||||
|
@@ -18,6 +18,22 @@
|
|||||||
sodipodi:docname="qtcreatoricons.svg">
|
sodipodi:docname="qtcreatoricons.svg">
|
||||||
<defs
|
<defs
|
||||||
id="defs4">
|
id="defs4">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient3970">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:0"
|
||||||
|
offset="0"
|
||||||
|
id="stop3966" />
|
||||||
|
<stop
|
||||||
|
id="stop3974"
|
||||||
|
offset="0.35135135"
|
||||||
|
style="stop-color:#000000;stop-opacity:0" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop3968" />
|
||||||
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
inkscape:collect="always"
|
inkscape:collect="always"
|
||||||
id="linearGradient9821">
|
id="linearGradient9821">
|
||||||
@@ -527,6 +543,16 @@
|
|||||||
y1="109.69"
|
y1="109.69"
|
||||||
x2="-191.87"
|
x2="-191.87"
|
||||||
y2="110.83" />
|
y2="110.83" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3970"
|
||||||
|
id="radialGradient3972"
|
||||||
|
cx="548.5"
|
||||||
|
cy="91.5"
|
||||||
|
fx="548.5"
|
||||||
|
fy="91.5"
|
||||||
|
r="18.5"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
</defs>
|
</defs>
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
id="base"
|
||||||
@@ -741,6 +767,13 @@
|
|||||||
d="m 108.63,21.74 h -2 V 9 h 2 v 7.36 l 1.11,-0.11 2.13,-3.51 h 2.19 l -2.59,4.26 2.74,4.78 H 112 l -2.2,-3.78 -1.17,0.12 z m -6.41,0 V 9 h 2 v 12.74 z m -2.57,-6.22 v 4.1 a 0.86,0.86 0 0 0 0.2,0.58 1,1 0 0 0 0.59,0.25 l -0.06,1.49 A 3.8,3.8 0 0 1 98,21.28 6.91,6.91 0 0 1 95.1,21.94 c -1.79,0 -2.68,-1 -2.68,-2.86 a 2.44,2.44 0 0 1 0.73,-2 4,4 0 0 1 2.24,-0.74 l 2.32,-0.2 V 15.5 a 1.33,1.33 0 0 0 -0.31,-1 1.35,1.35 0 0 0 -0.93,-0.29 c -0.77,0 -1.73,0 -2.88,0.14 H 93.01 L 92.93,13 a 15.72,15.72 0 0 1 3.61,-0.46 3.31,3.31 0 0 1 2.38,0.71 3.05,3.05 0 0 1 0.73,2.27 z m -4,2.23 a 1.21,1.21 0 0 0 -1.24,1.35 c 0,0.83 0.37,1.24 1.1,1.24 a 7,7 0 0 0 1.91,-0.29 l 0.32,-0.11 V 17.55 Z M 84,11.2 V 9.41 h 9 v 1.79 h -3.49 v 10.54 h -2 V 11.2 Z m -4.62,3.22 h -2.49 v 4 a 4.12,4.12 0 0 0 0.17,1.46 c 0.1,0.24 0.38,0.36 0.82,0.36 l 1.48,-0.06 0.09,1.57 A 11,11 0 0 1 77.61,21.98 2.55,2.55 0 0 1 75.52,21.28 4.41,4.41 0 0 1 75,18.59 V 14.42 H 73.8 V 12.74 H 75 v -2.61 h 1.94 v 2.61 h 2.49 z m -11.94,7.52 c -1.87,0 -3.17,-0.5 -3.91,-1.51 a 8.16,8.16 0 0 1 -1.11,-4.78 8.43,8.43 0 0 1 1.13,-4.85 c 0.75,-1.06 2,-1.58 3.89,-1.58 1.89,0 3.15,0.52 3.89,1.57 a 8.41,8.41 0 0 1 1.12,4.85 11.08,11.08 0 0 1 -0.45,3.49 4,4 0 0 1 -1.5,2 l 1.5,2.47 -1.86,0.86 -1.6,-2.63 a 3.68,3.68 0 0 1 -1.1,0.11 z m -2.34,-2.8 a 3.13,3.13 0 0 0 4.68,0 7.43,7.43 0 0 0 0.6,-3.5 7.78,7.78 0 0 0 -0.62,-3.58 3,3 0 0 0 -4.64,0 7.56,7.56 0 0 0 -0.63,3.56 7.47,7.47 0 0 0 0.61,3.52 z"
|
d="m 108.63,21.74 h -2 V 9 h 2 v 7.36 l 1.11,-0.11 2.13,-3.51 h 2.19 l -2.59,4.26 2.74,4.78 H 112 l -2.2,-3.78 -1.17,0.12 z m -6.41,0 V 9 h 2 v 12.74 z m -2.57,-6.22 v 4.1 a 0.86,0.86 0 0 0 0.2,0.58 1,1 0 0 0 0.59,0.25 l -0.06,1.49 A 3.8,3.8 0 0 1 98,21.28 6.91,6.91 0 0 1 95.1,21.94 c -1.79,0 -2.68,-1 -2.68,-2.86 a 2.44,2.44 0 0 1 0.73,-2 4,4 0 0 1 2.24,-0.74 l 2.32,-0.2 V 15.5 a 1.33,1.33 0 0 0 -0.31,-1 1.35,1.35 0 0 0 -0.93,-0.29 c -0.77,0 -1.73,0 -2.88,0.14 H 93.01 L 92.93,13 a 15.72,15.72 0 0 1 3.61,-0.46 3.31,3.31 0 0 1 2.38,0.71 3.05,3.05 0 0 1 0.73,2.27 z m -4,2.23 a 1.21,1.21 0 0 0 -1.24,1.35 c 0,0.83 0.37,1.24 1.1,1.24 a 7,7 0 0 0 1.91,-0.29 l 0.32,-0.11 V 17.55 Z M 84,11.2 V 9.41 h 9 v 1.79 h -3.49 v 10.54 h -2 V 11.2 Z m -4.62,3.22 h -2.49 v 4 a 4.12,4.12 0 0 0 0.17,1.46 c 0.1,0.24 0.38,0.36 0.82,0.36 l 1.48,-0.06 0.09,1.57 A 11,11 0 0 1 77.61,21.98 2.55,2.55 0 0 1 75.52,21.28 4.41,4.41 0 0 1 75,18.59 V 14.42 H 73.8 V 12.74 H 75 v -2.61 h 1.94 v 2.61 h 2.49 z m -11.94,7.52 c -1.87,0 -3.17,-0.5 -3.91,-1.51 a 8.16,8.16 0 0 1 -1.11,-4.78 8.43,8.43 0 0 1 1.13,-4.85 c 0.75,-1.06 2,-1.58 3.89,-1.58 1.89,0 3.15,0.52 3.89,1.57 a 8.41,8.41 0 0 1 1.12,4.85 11.08,11.08 0 0 1 -0.45,3.49 4,4 0 0 1 -1.5,2 l 1.5,2.47 -1.86,0.86 -1.6,-2.63 a 3.68,3.68 0 0 1 -1.1,0.11 z m -2.34,-2.8 a 3.13,3.13 0 0 0 4.68,0 7.43,7.43 0 0 0 0.6,-3.5 7.78,7.78 0 0 0 -0.62,-3.58 3,3 0 0 0 -4.64,0 7.56,7.56 0 0 0 -0.63,3.56 7.47,7.47 0 0 0 0.61,3.52 z"
|
||||||
inkscape:connector-curvature="0" />
|
inkscape:connector-curvature="0" />
|
||||||
</g>
|
</g>
|
||||||
|
<rect
|
||||||
|
style="fill:url(#radialGradient3972)"
|
||||||
|
id="src/plugins/welcome/images/border"
|
||||||
|
width="37"
|
||||||
|
height="37"
|
||||||
|
x="530"
|
||||||
|
y="73" />
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 354 KiB |
Reference in New Issue
Block a user