Skip to content

Commit a6fa69a

Browse files
committed
Add UiEngine class
1 parent bf496a7 commit a6fa69a

File tree

9 files changed

+221
-0
lines changed

9 files changed

+221
-0
lines changed

src/app/app.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "app.h"
1010
#include "globalmodule.h"
1111
#include "modularity/ioc.h"
12+
#include "ui/internal/uiengine.h"
1213

1314
using namespace scratchcpp;
1415
using namespace scratchcpp::modularity;
@@ -77,6 +78,8 @@ int App::run(int argc, char **argv)
7778
Qt::QueuedConnection);
7879
engine.load(url);
7980

81+
ui::UiEngine::instance()->setQmlEngine(&engine);
82+
8083
// Run the event loop
8184
int exitCode = app.exec();
8285

src/ui/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ set(MODULE_URI Ui)
33
set(MODULE_SRC
44
uimodule.cpp
55
uimodule.h
6+
iuiengine.h
7+
internal/uiengine.cpp
8+
internal/uiengine.h
69
)
710

811
include(${PROJECT_SOURCE_DIR}/build/module.cmake)
12+
13+
add_subdirectory(test)

src/ui/internal/uiengine.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#include <QCoreApplication>
4+
#include <QPushButton>
5+
6+
#include "uiengine.h"
7+
8+
using namespace scratchcpp::ui;
9+
10+
std::shared_ptr<UiEngine> UiEngine::m_instance = std::make_shared<UiEngine>();
11+
12+
UiEngine::UiEngine(QObject *parent) :
13+
QObject(parent)
14+
{
15+
}
16+
17+
UiEngine::~UiEngine()
18+
{
19+
if (m_dialogButtonBox)
20+
m_dialogButtonBox->deleteLater();
21+
}
22+
23+
std::shared_ptr<UiEngine> UiEngine::instance()
24+
{
25+
return m_instance;
26+
}
27+
28+
QQmlEngine *UiEngine::qmlEngine() const
29+
{
30+
return m_qmlEngine;
31+
}
32+
33+
void UiEngine::setQmlEngine(QQmlEngine *engine)
34+
{
35+
m_qmlEngine = engine;
36+
}
37+
38+
QString UiEngine::standardButtonText(QDialogButtonBox::StandardButton button) const
39+
{
40+
if (!m_dialogButtonBox)
41+
m_dialogButtonBox = new QDialogButtonBox; // construct on first use because widgets need QApplication
42+
43+
QPushButton *btn = m_dialogButtonBox->button(button);
44+
45+
if (!btn) {
46+
m_dialogButtonBox->addButton(button);
47+
btn = m_dialogButtonBox->button(button);
48+
}
49+
50+
if (btn)
51+
return btn->text();
52+
else
53+
return QString();
54+
}
55+
56+
QQuickItem *UiEngine::activeFocusItem() const
57+
{
58+
return m_activeFocusItem;
59+
}
60+
61+
void UiEngine::setActiveFocusItem(QQuickItem *newActiveFocusItem)
62+
{
63+
if (m_activeFocusItem == newActiveFocusItem)
64+
return;
65+
66+
m_activeFocusItem = newActiveFocusItem;
67+
emit activeFocusItemChanged();
68+
}

src/ui/internal/uiengine.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <QObject>
6+
7+
#include "ui/iuiengine.h"
8+
9+
Q_MOC_INCLUDE(<QQuickItem>)
10+
11+
class QQuickItem;
12+
13+
namespace scratchcpp::ui
14+
{
15+
16+
class UiEngine
17+
: public QObject
18+
, public IUiEngine
19+
{
20+
Q_OBJECT
21+
Q_PROPERTY(QQuickItem *activeFocusItem READ activeFocusItem WRITE setActiveFocusItem NOTIFY activeFocusItemChanged)
22+
23+
public:
24+
explicit UiEngine(QObject *parent = nullptr);
25+
~UiEngine();
26+
27+
static std::shared_ptr<UiEngine> instance();
28+
29+
QQmlEngine *qmlEngine() const override;
30+
void setQmlEngine(QQmlEngine *engine);
31+
32+
Q_INVOKABLE QString standardButtonText(QDialogButtonBox::StandardButton button) const override;
33+
34+
QQuickItem *activeFocusItem() const;
35+
void setActiveFocusItem(QQuickItem *newActiveFocusItem);
36+
37+
signals:
38+
void activeFocusItemChanged();
39+
40+
private:
41+
static std::shared_ptr<UiEngine> m_instance;
42+
QQmlEngine *m_qmlEngine = nullptr;
43+
QQuickItem *m_activeFocusItem = nullptr;
44+
mutable QDialogButtonBox *m_dialogButtonBox = nullptr;
45+
};
46+
47+
} // namespace scratchcpp::ui

src/ui/iuiengine.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <QDialogButtonBox>
6+
7+
#include "modularity/ioc.h"
8+
9+
class QQmlEngine;
10+
11+
namespace scratchcpp::ui
12+
{
13+
14+
class IUiEngine : MODULE_EXPORT_INTERFACE
15+
{
16+
public:
17+
virtual ~IUiEngine() { }
18+
19+
virtual QQmlEngine *qmlEngine() const = 0;
20+
21+
virtual QString standardButtonText(QDialogButtonBox::StandardButton button) const = 0;
22+
};
23+
24+
} // namespace scratchcpp::ui

src/ui/test/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
set(MODULE_TEST_SRC
2+
uiengine.cpp
3+
)
4+
5+
include(${PROJECT_SOURCE_DIR}/build/module_test.cmake)

src/ui/test/uiengine.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <gtest/gtest.h>
2+
#include <QQmlEngine>
3+
#include <QPushButton>
4+
#include <QQuickItem>
5+
#include <QSignalSpy>
6+
7+
#include "internal/uiengine.h"
8+
9+
using namespace scratchcpp::ui;
10+
11+
TEST(UiEngineTest, Instance)
12+
{
13+
ASSERT_TRUE(UiEngine::instance());
14+
}
15+
16+
TEST(UiEngineTest, QmlEngine)
17+
{
18+
UiEngine engine;
19+
ASSERT_EQ(engine.qmlEngine(), nullptr);
20+
21+
QQmlEngine qmlEngine;
22+
engine.setQmlEngine(&qmlEngine);
23+
ASSERT_EQ(engine.qmlEngine(), &qmlEngine);
24+
}
25+
26+
TEST(UiEngineTest, StandardButtonText)
27+
{
28+
static const std::vector<QDialogButtonBox::StandardButton> buttons = {
29+
QDialogButtonBox::Ok, QDialogButtonBox::Open, QDialogButtonBox::Save,
30+
QDialogButtonBox::Cancel, QDialogButtonBox::Close, QDialogButtonBox::Discard,
31+
QDialogButtonBox::Apply, QDialogButtonBox::Reset, QDialogButtonBox::RestoreDefaults,
32+
QDialogButtonBox::Help, QDialogButtonBox::SaveAll, QDialogButtonBox::Yes,
33+
QDialogButtonBox::YesToAll, QDialogButtonBox::No, QDialogButtonBox::NoToAll,
34+
QDialogButtonBox::Abort, QDialogButtonBox::Retry, QDialogButtonBox::Ignore
35+
};
36+
37+
UiEngine engine;
38+
QDialogButtonBox dialogButtonBox;
39+
40+
for (QDialogButtonBox::StandardButton button : buttons) {
41+
dialogButtonBox.addButton(button);
42+
ASSERT_EQ(engine.standardButtonText(button), dialogButtonBox.button(button)->text());
43+
ASSERT_FALSE(engine.standardButtonText(button).isEmpty());
44+
}
45+
}
46+
47+
TEST(UiEngineTest, ActiveFocusItem)
48+
{
49+
UiEngine engine;
50+
QSignalSpy spy(&engine, &UiEngine::activeFocusItemChanged);
51+
ASSERT_EQ(engine.activeFocusItem(), nullptr);
52+
53+
QQuickItem item;
54+
engine.setActiveFocusItem(&item);
55+
ASSERT_EQ(engine.activeFocusItem(), &item);
56+
ASSERT_EQ(spy.count(), 1);
57+
}

src/ui/uimodule.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// SPDX-License-Identifier: GPL-3.0-or-later
22

3+
#include <QQmlEngine>
4+
35
#include "uimodule.h"
6+
#include "internal/uiengine.h"
47

58
using namespace scratchcpp::ui;
69

@@ -12,3 +15,10 @@ std::string UiModule::moduleName() const
1215
{
1316
return "ui";
1417
}
18+
19+
void scratchcpp::ui::UiModule::registerExports()
20+
{
21+
QQmlEngine::setObjectOwnership(UiEngine::instance().get(), QQmlEngine::CppOwnership);
22+
qmlRegisterSingletonInstance<UiEngine>("ScratchCPP.Ui", 1, 0, "UiEngine", UiEngine::instance().get());
23+
modularity::ioc()->registerExport<IUiEngine>(UiEngine::instance());
24+
}

src/ui/uimodule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class UiModule : public modularity::IModuleSetup
1313
UiModule();
1414

1515
std::string moduleName() const override;
16+
17+
void registerExports() override;
1618
};
1719

1820
} // namespace scratchcpp::ui

0 commit comments

Comments
 (0)