[ktuberling] /: Add initial Android version
Albert Astals Cid
null at kde.org
Mon Oct 9 11:25:27 UTC 2017
Git commit 7d4fde1f5a039d1a700d6806a4c000046c845465 by Albert Astals Cid.
Committed on 09/10/2017 at 11:25.
Pushed by aacid into branch 'master'.
Add initial Android version
Includes a few other tweaks for the desktop version too but very minor
M +97 -68 CMakeLists.txt
A +37 -0 android_data/AndroidManifest.xml
A +- -- android_data/audio-volume-high.png
A +13 -0 android_data/audio-volume-high.svg
A +- -- android_data/audio-volume-muted.png
A +21 -0 android_data/audio-volume-muted.svg
A +- -- android_data/games-config-theme.png
A +13 -0 android_data/games-config-theme.svg
A +- -- android_data/res/drawable/ktuberling.png
A +7 -0 android_data/resources.qrc
M +0 -6 doc/index.docbook
A +42 -0 filefactory.cpp [License: GPL (v2+)]
A +23 -0 filefactory.h [License: GPL (v2+)]
A +137 -0 main_mobile.cpp [License: GPL (v2+)]
M +- -- pics/robot_workshop.svgz
M +40 -29 playground.cpp
M +18 -6 playground.h
M +16 -22 soundfactory.cpp
M +11 -8 soundfactory.h
M +5 -5 toplevel.cpp
M +8 -6 toplevel.h
https://commits.kde.org/ktuberling/7d4fde1f5a039d1a700d6806a4c000046c845465
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42f415f..ca6240e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,26 +7,27 @@ set (KF5_MIN_VERSION "5.15.0")
find_package(ECM 1.7.0 REQUIRED CONFIG)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
-find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS PrintSupport Svg Widgets Xml)
-find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
- Completion
- Config
- ConfigWidgets
- CoreAddons
- Crash
- DBusAddons
- KIO
- DocTools
- I18n
- KDELibs4Support #TODO eventually remove kdelibs4support
- WidgetsAddons
- XmlGui
-)
-
-find_package(KF5KDEGames 4.9.0 REQUIRED)
-find_package(Phonon4Qt5 CONFIG REQUIRED)
+find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS PrintSupport Svg Widgets Xml Multimedia)
+find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Config)
+
+if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Android")
+ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
+ Completion
+ ConfigWidgets
+ CoreAddons
+ Crash
+ DBusAddons
+ KIO
+ DocTools
+ I18n
+ KDELibs4Support #TODO eventually remove kdelibs4support
+ WidgetsAddons
+ XmlGui
+ )
+
+ find_package(KF5KDEGames 4.9.0 REQUIRED)
+endif()
-include_directories(BEFORE ${PHONON_INCLUDES})
include(FeatureSummary)
include(ECMAddAppIcon)
@@ -40,59 +41,87 @@ add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
add_subdirectory(sounds)
add_subdirectory(pics)
-add_subdirectory(doc)
+if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Android")
+ add_subdirectory(doc)
+endif()
########### next target ###############
-set(ktuberling_SRCS
- action.cpp
- main.cpp
- toplevel.cpp
- playground.cpp
- todraw.cpp
- soundfactory.cpp
- playgrounddelegate.cpp
+set(ktuberling_common_SRCS
+ action.cpp
+ playground.cpp
+ todraw.cpp
+ soundfactory.cpp
+ filefactory.cpp
)
-file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*-apps-ktuberling.png")
-ecm_add_app_icon(ktuberling_SRCS ICONS ${ICONS_SRCS})
-add_executable(ktuberling ${ktuberling_SRCS})
-
-target_link_libraries(ktuberling
- Qt5::PrintSupport
- Qt5::Svg
- KF5::Completion
- KF5::Crash
- KF5::DBusAddons
- KF5::KIOCore
- KF5::KDELibs4Support
- KF5::XmlGui
- Phonon::phonon4qt5
- KF5KDEGames
-)
-
-install(TARGETS ktuberling ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
-
-
-########### install files ###############
-
-install(PROGRAMS org.kde.ktuberling.desktop DESTINATION ${KDE_INSTALL_APPDIR})
-install(FILES ktuberlingui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/ktuberling)
-
-ecm_install_icons(ICONS
- 128-apps-ktuberling.png
- 16-apps-ktuberling.png
- 22-apps-ktuberling.png
- 32-apps-ktuberling.png
- 48-apps-ktuberling.png
- 64-apps-ktuberling.png
- 128-mimetypes-application-x-tuberling.png
- 16-mimetypes-application-x-tuberling.png
- 22-mimetypes-application-x-tuberling.png
- 32-mimetypes-application-x-tuberling.png
- 48-mimetypes-application-x-tuberling.png
- 64-mimetypes-application-x-tuberling.png
- DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor
-)
+if(${CMAKE_SYSTEM_NAME} MATCHES "Android")
+ set(ktuberling_mobile_SRCS
+ ${ktuberling_common_SRCS}
+ main_mobile.cpp
+ )
+
+ qt5_add_resources(ktuberling_mobile_SRCS android_data/resources.qrc)
+
+ add_executable(ktuberling_mobile ${ktuberling_mobile_SRCS})
+
+ target_link_libraries(ktuberling_mobile
+ Qt5::Gui
+ Qt5::Svg
+ Qt5::Multimedia
+ Qt5::Xml
+ Qt5::Widgets
+ KF5::ConfigCore )
+
+ install(TARGETS ktuberling_mobile RUNTIME DESTINATION bin)
+
+else()
+
+ set(ktuberling_SRCS
+ ${ktuberling_common_SRCS}
+ main.cpp
+ toplevel.cpp
+ playgrounddelegate.cpp
+ )
+
+ file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*-apps-ktuberling.png")
+ ecm_add_app_icon(ktuberling_SRCS ICONS ${ICONS_SRCS})
+
+ add_executable(ktuberling ${ktuberling_SRCS})
+
+ target_link_libraries(ktuberling
+ Qt5::PrintSupport
+ Qt5::Svg
+ Qt5::Multimedia
+ KF5::Completion
+ KF5::Crash
+ KF5::DBusAddons
+ KF5::KIOCore
+ KF5::KDELibs4Support
+ KF5::XmlGui
+ KF5KDEGames
+ )
+
+ install(TARGETS ktuberling ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
+
+ install(PROGRAMS org.kde.ktuberling.desktop DESTINATION ${KDE_INSTALL_APPDIR})
+ install(FILES ktuberlingui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/ktuberling)
+
+ ecm_install_icons(ICONS
+ 128-apps-ktuberling.png
+ 16-apps-ktuberling.png
+ 22-apps-ktuberling.png
+ 32-apps-ktuberling.png
+ 48-apps-ktuberling.png
+ 64-apps-ktuberling.png
+ 128-mimetypes-application-x-tuberling.png
+ 16-mimetypes-application-x-tuberling.png
+ 22-mimetypes-application-x-tuberling.png
+ 32-mimetypes-application-x-tuberling.png
+ 48-mimetypes-application-x-tuberling.png
+ 64-mimetypes-application-x-tuberling.png
+ DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor
+ )
+endif()
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/android_data/AndroidManifest.xml b/android_data/AndroidManifest.xml
new file mode 100644
index 0000000..f57c1f0
--- /dev/null
+++ b/android_data/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.0.3" package="org.kde.ktuberling" android:installLocation="auto" android:versionCode="7">
+ <application android:name="org.qtproject.qt5.android.bindings.QtApplication"
+ android:label="KTuberling"
+ android:icon="@drawable/ktuberling">
+ <activity android:name="org.qtproject.qt5.android.bindings.QtActivity"
+ android:label="KTuberling"
+ android:screenOrientation="landscape"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
+ <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
+ <meta-data android:name="android.app.repository" android:value="default"/>
+ <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
+ <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
+ <!-- Deploy Qt libs as part of package -->
+ <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
+ <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
+ <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
+ <!-- Run with local libs -->
+ <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
+ <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
+ <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
+ <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
+ <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
+ <!-- Messages maps -->
+ <meta-data android:name="android.app.ministro_not_found_msg" android:value="@string/ministro_not_found_msg"/>
+ <meta-data android:name="android.app.ministro_needed_msg" android:value="@string/ministro_needed_msg"/>
+ <meta-data android:name="android.app.fatal_error_msg" android:value="@string/fatal_error_msg"/>
+ </activity>
+ </application>
+ <supports-screens android:anyDensity="true" android:normalScreens="true" android:smallScreens="true" android:largeScreens="true"/>
+ <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="19"/>
+</manifest>
diff --git a/android_data/audio-volume-high.png b/android_data/audio-volume-high.png
new file mode 100644
index 0000000..1df64b9
Binary files /dev/null and b/android_data/audio-volume-high.png differ
diff --git a/android_data/audio-volume-high.svg b/android_data/audio-volume-high.svg
new file mode 100644
index 0000000..a5dca4c
--- /dev/null
+++ b/android_data/audio-volume-high.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 10.988281 3 L 6 7.9902344 L 6 8 L 6 9 L 6 13 L 6 14 L 6 14.009766 L 10.988281 19 L 12 19 L 12 18.597656 L 12 3.4023438 L 12 3 L 10.988281 3 z M 13.865234 3.5371094 L 13.621094 4.5136719 A 7 7 0 0 1 18 11 A 7 7 0 0 1 13.619141 17.478516 L 13.863281 18.453125 A 8 8 0 0 0 19 11 A 8 8 0 0 0 13.865234 3.5371094 z M 14.324219 7.28125 L 13.785156 8.1425781 A 4 4 0 0 1 15 11 A 4 4 0 0 1 13.789062 13.861328 L 14.328125 14.724609 A 5 5 0 0 0 16 11 A 5 5 0 0 0 14.324219 7.28125 z M 3 8 L 3 9 L 3 13 L 3 14 L 5 14 L 5 13 L 5 9 L 5 8 L 3 8 z "
+ class="ColorScheme-Text"/>
+</svg>
diff --git a/android_data/audio-volume-muted.png b/android_data/audio-volume-muted.png
new file mode 100644
index 0000000..29508f7
Binary files /dev/null and b/android_data/audio-volume-muted.png differ
diff --git a/android_data/audio-volume-muted.svg b/android_data/audio-volume-muted.svg
new file mode 100644
index 0000000..1a9f68b
--- /dev/null
+++ b/android_data/audio-volume-muted.svg
@@ -0,0 +1,21 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ .ColorScheme-NegativeText {
+ color:#da4453;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 10.988281 3 L 6 7.9902344 L 6 8 L 6 9 L 6 13 L 6 14 L 6 14.009766 L 10.988281 19 L 12 19 L 12 18.597656 L 12 3.4023438 L 12 3 L 10.988281 3 z M 3 8 L 3 9 L 3 13 L 3 14 L 5 14 L 5 13 L 5 9 L 5 8 L 3 8 z "
+ class="ColorScheme-Text"/>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 13 10 L 13 12 L 19 12 L 19 10 L 13 10 z "
+ class="ColorScheme-NegativeText"
+ />
+</svg>
diff --git a/android_data/games-config-theme.png b/android_data/games-config-theme.png
new file mode 100644
index 0000000..29a358a
Binary files /dev/null and b/android_data/games-config-theme.png differ
diff --git a/android_data/games-config-theme.svg b/android_data/games-config-theme.svg
new file mode 100644
index 0000000..c74afd0
--- /dev/null
+++ b/android_data/games-config-theme.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 19.513672 4.0078125 A 2 9 45 0 0 12.068359 9.1054688 A 2 9 45 0 0 8.5253906 13.21875 C 9.6014506 13.56139 10.440563 14.400494 10.783203 15.476562 A 2 9 45 0 0 14.896484 11.933594 A 2 9 45 0 0 19.845703 4.15625 A 2 9 45 0 0 19.513672 4.0078125 z M 8 14.664062 C 3.99999 15.735864 7 18.26795 4 20 C 8.00339 20 10 17.99918 10 16.664062 C 10 15.999182 10.0676 14.774622 8 14.664062 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/android_data/res/drawable/ktuberling.png b/android_data/res/drawable/ktuberling.png
new file mode 100644
index 0000000..6d5bbbf
Binary files /dev/null and b/android_data/res/drawable/ktuberling.png differ
diff --git a/android_data/resources.qrc b/android_data/resources.qrc
new file mode 100644
index 0000000..8a596b4
--- /dev/null
+++ b/android_data/resources.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file>games-config-theme.png</file>
+ <file>audio-volume-high.png</file>
+ <file>audio-volume-muted.png</file>
+ </qresource>
+</RCC>
diff --git a/doc/index.docbook b/doc/index.docbook
index 91cbdef..83bcd64 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -508,12 +508,6 @@ It will contain the playgrounds installed in your system.
<sect2>
<title>The Speech Menu</title>
-<!--FIXME
-<para>
-Please note that you need to have <command>&phonon;</command> installed
-and properly configured to be able to hear sounds.
-</para>-->
-
<variablelist>
<varlistentry>
diff --git a/filefactory.cpp b/filefactory.cpp
new file mode 100644
index 0000000..ef3d39c
--- /dev/null
+++ b/filefactory.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Albert Astals Cid <aacid at kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "filefactory.h"
+
+#include <QFileInfo>
+#include <QStandardPaths>
+
+bool FileFactory::folderExists(const QString &relativePath)
+{
+#if defined(Q_OS_ANDROID)
+ QFileInfo fi("/data/data/org.kde.ktuberling/qt-reserved-files/share/ktuberling/" + relativePath);
+ return fi.isDir();
+#else
+ return !(QStandardPaths::locate(QStandardPaths::AppDataLocation, relativePath, QStandardPaths::LocateDirectory).isEmpty());
+#endif
+}
+
+QString FileFactory::locate(const QString &relativePath)
+{
+#if defined(Q_OS_ANDROID)
+ return "/data/data/org.kde.ktuberling/qt-reserved-files/share/ktuberling/" + relativePath;
+#else
+ return QStandardPaths::locate(QStandardPaths::AppDataLocation, relativePath);
+#endif
+}
+
+QStringList FileFactory::locateAll(const QString &relativePath)
+{
+#if defined(Q_OS_ANDROID)
+ return { "/data/data/org.kde.ktuberling/qt-reserved-files/share/ktuberling/" + relativePath };
+#else
+ return QStandardPaths::locateAll(QStandardPaths::AppDataLocation, relativePath, QStandardPaths::LocateDirectory);
+#endif
+}
+
diff --git a/filefactory.h b/filefactory.h
new file mode 100644
index 0000000..f7954b8
--- /dev/null
+++ b/filefactory.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Albert Astals Cid <aacid at kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef FILEFACTORY_H
+#define FILEFACTORY_H
+
+class QString;
+class QStringList;
+
+namespace FileFactory
+{
+ bool folderExists(const QString &relativePath);
+ QString locate(const QString &relativePath);
+ QStringList locateAll(const QString &relativePath);
+};
+
+#endif
diff --git a/main_mobile.cpp b/main_mobile.cpp
new file mode 100644
index 0000000..429323f
--- /dev/null
+++ b/main_mobile.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * Copyright (C) 1999-2006 by Éric Bischoff <ebischoff at nerim.net> *
+ * Copyright (C) 2007 by Albert Astals Cid <aacid at kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include <QApplication>
+#include <QDebug>
+#include <QDesktopWidget>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+
+#include "filefactory.h"
+#include "soundfactory.h"
+#include "playground.h"
+
+static const char version[] = "1.0.0";
+
+class KTuberlingMobile : public PlayGroundCallbacks, public SoundFactoryCallbacks
+{
+public:
+ KTuberlingMobile()
+ : m_soundEnabled(true)
+ {
+ m_soundFactory = new SoundFactory(this);
+ m_soundFactory->registerLanguages();
+ m_soundFactory->loadLanguage(FileFactory::locate("sounds/en.soundtheme"));
+
+ QWidget *mainWidget = new QWidget();
+ QHBoxLayout *lay = new QHBoxLayout(mainWidget);
+
+ m_themesWidget = new QWidget();
+ m_gameboardLayout = new QGridLayout(m_themesWidget);
+
+ m_playground = new PlayGround(this, mainWidget);
+ m_playground->registerPlayGrounds();
+ m_playground->lockAspectRatio(true);
+ m_playground->setAllowOnlyDrag(true);
+ m_playground->loadPlayGround(FileFactory::locate("pics/default_theme.theme"));
+
+ QVBoxLayout *sideLayout = new QVBoxLayout();
+
+ // Not sure this is the best way but it works for now
+ const int screenWidth = QDesktopWidget().screenGeometry().width();
+ const int iconWidth = screenWidth / 15;
+
+ QPushButton *themesButton = new QPushButton(mainWidget);
+ themesButton->setIcon(QPixmap(":/games-config-theme.png"));
+ themesButton->setIconSize(QSize(iconWidth, iconWidth));
+ themesButton->setFocusPolicy(Qt::NoFocus);
+ QObject::connect(themesButton, &QPushButton::clicked, [this, mainWidget] {
+ m_themesWidget->showFullScreen();
+ });
+
+ QPushButton *soundsButton = new QPushButton(mainWidget);
+ soundsButton->setIcon(QPixmap(":/audio-volume-high.png"));
+ soundsButton->setIconSize(QSize(iconWidth, iconWidth));
+ soundsButton->setFocusPolicy(Qt::NoFocus);
+ QObject::connect(soundsButton, &QPushButton::clicked, [this, soundsButton] {
+ m_soundEnabled = !m_soundEnabled;
+ soundsButton->setIcon(QPixmap(m_soundEnabled ? ":/audio-volume-high.png" : ":/audio-volume-muted.png"));
+ });
+
+ sideLayout->addWidget(themesButton);
+ sideLayout->addWidget(soundsButton);
+ sideLayout->addStretch(1);
+
+ lay->setContentsMargins(0, 0, 0, 0);
+ lay->setSpacing(0);
+ lay->addWidget(m_playground);
+ lay->addLayout(sideLayout);
+
+ mainWidget->showFullScreen();
+ }
+
+ ~KTuberlingMobile()
+ {
+ delete m_soundFactory;
+ }
+
+ void playSound(const QString &ref) override
+ {
+ m_soundFactory->playSound(ref);
+ }
+
+ void changeGameboard(const QString &/*gameboard*/) override
+ {
+ // Only needed when loading a file so not needed for now
+ }
+
+ void registerGameboard(const QString& menuText, const QString& boardFile, const QPixmap &/*pixmap*/) override
+ {
+ // TODO this should be scrollable
+ // TODO use the pixmap
+ QPushButton *pb = new QPushButton(menuText);
+ QObject::connect(pb, &QPushButton::clicked, [this, boardFile] {
+ m_playground->loadPlayGround(boardFile);
+ m_themesWidget->hide();
+ });
+
+ m_gameboardLayout->addWidget(pb, m_gameboardLayout->count() / 2, m_gameboardLayout->count() % 2);
+ }
+
+ bool isSoundEnabled() const override
+ {
+ return m_soundEnabled;
+ }
+
+ void registerLanguage(const QString &/*code*/, const QString &/*soundFile*/, bool /*enabled*/)
+ {
+ // TODO
+ }
+
+private:
+ SoundFactory *m_soundFactory;
+ PlayGround *m_playground;
+ QWidget *m_themesWidget;
+ QGridLayout *m_gameboardLayout;
+ bool m_soundEnabled;
+};
+
+// Main function
+Q_DECL_EXPORT int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QLocale::system().name(); // needed to workaround QTBUG-41385
+ app.setApplicationName("ktuberling");
+
+ KTuberlingMobile tuberling;
+
+ return app.exec();
+}
diff --git a/pics/robot_workshop.svgz b/pics/robot_workshop.svgz
index 57a61cf..2e0717f 100644
Binary files a/pics/robot_workshop.svgz and b/pics/robot_workshop.svgz differ
diff --git a/playground.cpp b/playground.cpp
index afe70c2..58d8d1f 100644
--- a/playground.cpp
+++ b/playground.cpp
@@ -12,12 +12,12 @@
#include "playground.h"
-#include <KLocalizedString>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <qdebug.h>
#include <QAction>
+#include <QApplication>
#include <QCursor>
#include <QDataStream>
#include <QDir>
@@ -27,15 +27,10 @@
#include <QGraphicsSvgItem>
#include <QMouseEvent>
#include <QPainter>
-#include <QPrinter>
-#include <QStandardPaths>
-
-#include <kstandardaction.h>
-#include <kactioncollection.h>
-#include <kstandardshortcut.h>
+#include <QPagedPaintDevice>
#include "action.h"
-#include "toplevel.h"
+#include "filefactory.h"
#include "todraw.h"
static const char *saveGameTextScaleTextMode = "KTuberlingSaveGameV2";
@@ -43,10 +38,9 @@ static const char *saveGameTextTextMode = "KTuberlingSaveGameV3";
static const char *saveGameText = "KTuberlingSaveGameV4";
// Constructor
-PlayGround::PlayGround(TopLevel *parent)
- : QGraphicsView(parent), m_newItem(0), m_dragItem(0), m_nextZValue(1), m_lockAspect(false)
+PlayGround::PlayGround(PlayGroundCallbacks *callbacks, QWidget *parent)
+ : QGraphicsView(parent), m_callbacks(callbacks), m_newItem(0), m_dragItem(0), m_nextZValue(1), m_lockAspect(false), m_allowOnlyDrag(false)
{
- m_topLevel = parent;
setFrameStyle(QFrame::NoFrame);
setOptimizationFlag(QGraphicsView::DontSavePainterState, true); // all items here save the painter state
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -99,7 +93,7 @@ bool PlayGround::saveAs(const QString & name)
}
// Print gameboard's picture
-bool PlayGround::printPicture(QPrinter &printer)
+bool PlayGround::printPicture(QPagedPaintDevice &printer)
{
QPainter artist;
QPixmap picture(getPicture());
@@ -139,6 +133,8 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
if (event->button() != Qt::LeftButton) return;
+ m_mousePressPos = event->pos();
+
if (m_dragItem) placeDraggedItem(event->pos());
else if (m_newItem) placeNewItem(event->pos());
else
@@ -163,7 +159,7 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
QPointF itemPos = mapToScene(event->pos());
itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
- m_topLevel->playSound(m_objectsNameSound.value(foundElem));
+ m_callbacks->playSound(m_objectsNameSound.value(foundElem));
m_newItem = new ToDraw;
m_newItem->setBeingDragged(true);
@@ -186,7 +182,7 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
{
QString elem = m_dragItem->elementId();
- m_topLevel->playSound(m_objectsNameSound.value(elem));
+ m_callbacks->playSound(m_objectsNameSound.value(elem));
setCursor(Qt::BlankCursor);
m_dragItem->setBeingDragged(true);
m_itemDraggedPos = m_dragItem->pos();
@@ -202,18 +198,22 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
void PlayGround::mouseMoveEvent(QMouseEvent *event)
{
- if (m_newItem) {
+ ToDraw *movingItem = m_newItem ? m_newItem : m_dragItem;
+ if (movingItem) {
QPointF itemPos = mapToScene(event->pos());
- const QSizeF elementSize = m_newItem->transform().mapRect(m_newItem->unclippedRect()).size();
+ const QSizeF elementSize = movingItem->transform().mapRect(movingItem->unclippedRect()).size();
itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
- m_newItem->setPos(clipPos(itemPos, m_newItem));
- } else if (m_dragItem) {
- QPointF itemPos = mapToScene(event->pos());
- const QSizeF elementSize = m_dragItem->transform().mapRect(m_dragItem->unclippedRect()).size();
- itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
+ movingItem->setPos(clipPos(itemPos, movingItem));
+ }
+}
- m_dragItem->setPos(clipPos(itemPos, m_dragItem));
+void PlayGround::mouseReleaseEvent(QMouseEvent *event)
+{
+ QPoint point = event->pos() - m_mousePressPos;
+ if (m_allowOnlyDrag || point.manhattanLength() > qApp->startDragDistance()) {
+ if (m_dragItem) placeDraggedItem(event->pos());
+ else if (m_newItem) placeNewItem(event->pos());
}
}
@@ -317,7 +317,7 @@ bool PlayGround::isAspectRatioLocked() const
void PlayGround::registerPlayGrounds()
{
QSet<QString> list;
- const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("pics"), QStandardPaths::LocateDirectory);
+ const QStringList dirs = FileFactory::locateAll(QStringLiteral("pics"));
Q_FOREACH (const QString &dir, dirs)
{
const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.theme"));
@@ -327,6 +327,8 @@ void PlayGround::registerPlayGrounds()
}
}
+ QMap<QString, QPair<QString, QPixmap>> sortedByName;
+
foreach(const QString &theme, list)
{
QFile layoutFile(theme);
@@ -336,21 +338,26 @@ void PlayGround::registerPlayGrounds()
if (layoutDocument.setContent(&layoutFile))
{
QString desktop = layoutDocument.documentElement().attribute(QStringLiteral( "desktop" ));
- KConfig c( QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "pics/" ) + desktop ) );
+ KConfig c( FileFactory::locate( QLatin1String( "pics/" ) + desktop ) );
KConfigGroup cg = c.group("KTuberlingTheme");
QString gameboard = layoutDocument.documentElement().attribute(QStringLiteral( "gameboard" ));
QPixmap pixmap(200,100);
pixmap.fill(Qt::transparent);
playGroundPixmap(gameboard,pixmap);
- m_topLevel->registerGameboard(cg.readEntry("Name"), theme, pixmap);
+ sortedByName.insertMulti(cg.readEntry("Name"), QPair<QString, QPixmap>(theme, pixmap));
}
}
}
+
+ for(auto it = sortedByName.begin(); it != sortedByName.end(); ++it) {
+ m_callbacks->registerGameboard(it.key(), it.value().first, it.value().second);
+ }
+
}
void PlayGround::playGroundPixmap(const QString &playgroundName, QPixmap &pixmap)
{
- m_SvgRenderer.load(QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "pics/" ) + playgroundName ));
+ m_SvgRenderer.load(FileFactory::locate(QLatin1String( "pics/" ) + playgroundName ));
QPainter painter(&pixmap);
m_SvgRenderer.render(&painter,QStringLiteral( "background" ));
}
@@ -370,7 +377,6 @@ bool PlayGround::loadPlayGround(const QString &gameboardFile)
QFile layoutFile(gameboardFile);
if (!layoutFile.open(QIODevice::ReadOnly)) return false;
-
QDomDocument layoutDocument;
if (!layoutDocument.setContent(&layoutFile)) return false;
@@ -382,7 +388,7 @@ bool PlayGround::loadPlayGround(const QString &gameboardFile)
if (!bgColor.isValid())
bgColor = Qt::white;
- if (!m_SvgRenderer.load(QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "pics/" ) + gameboardName )))
+ if (!m_SvgRenderer.load(FileFactory::locate( QLatin1String( "pics/" ) + gameboardName )))
return false;
objectsList = playGroundElement.elementsByTagName(QStringLiteral( "object" ));
@@ -434,6 +440,11 @@ bool PlayGround::loadPlayGround(const QString &gameboardFile)
return true;
}
+void PlayGround::setAllowOnlyDrag(bool allowOnlyDrag)
+{
+ m_allowOnlyDrag = allowOnlyDrag;
+}
+
QString PlayGround::currentGameboard() const
{
return m_gameboardFile;
@@ -481,7 +492,7 @@ PlayGround::LoadError PlayGround::loadFrom(const QString &name)
qreal xFactor = 1.0;
qreal yFactor = 1.0;
- m_topLevel->changeGameboard(board);
+ m_callbacks->changeGameboard(board);
reset();
diff --git a/playground.h b/playground.h
index 39072d3..a671e8b 100644
--- a/playground.h
+++ b/playground.h
@@ -23,16 +23,24 @@ class KActionCollection;
class Action;
class ToDraw;
-class TopLevel;
-class QPrinter;
+class QPagedPaintDevice;
class QGraphicsSvgItem;
+class PlayGroundCallbacks
+{
+public:
+ virtual ~PlayGroundCallbacks() {}
+ virtual void playSound(const QString &ref) = 0;
+ virtual void changeGameboard(const QString &gameboard) = 0;
+ virtual void registerGameboard(const QString& menuText, const QString& boardFile, const QPixmap& pixmap) = 0;
+};
+
class PlayGround : public QGraphicsView
{
Q_OBJECT
public:
- explicit PlayGround(TopLevel *parent);
+ explicit PlayGround(PlayGroundCallbacks *callbacks, QWidget *parent = nullptr);
~PlayGround();
enum LoadError { NoError, OldFileVersionError, OtherError };
@@ -40,7 +48,7 @@ public:
void reset();
LoadError loadFrom(const QString &name);
bool saveAs(const QString &name);
- bool printPicture(QPrinter &printer);
+ bool printPicture(QPagedPaintDevice &printer);
QPixmap getPicture();
void connectRedoAction(QAction *action);
@@ -49,6 +57,8 @@ public:
void registerPlayGrounds();
bool loadPlayGround(const QString &gameboardFile);
+ void setAllowOnlyDrag(bool allowOnlyDrag);
+
QString currentGameboard() const;
bool isAspectRatioLocked() const;
@@ -60,6 +70,7 @@ protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private:
@@ -75,12 +86,12 @@ private:
QGraphicsScene *scene() const;
QUndoStack *undoStack() const;
+ PlayGroundCallbacks *m_callbacks;
QString m_gameboardFile; // the file the board
QMap<QString, QString> m_objectsNameSound; // map between element name and sound
QMap<QString, double> m_objectsNameRatio; // map between element name and scaling ratio
- TopLevel *m_topLevel; // Top-level window
-
+ QPoint m_mousePressPos;
QPointF m_itemDraggedPos;
ToDraw *m_newItem; // the new item we are moving
ToDraw *m_dragItem; // the existing item we are dragging
@@ -88,6 +99,7 @@ private:
int m_nextZValue; // the next Z value to use
bool m_lockAspect; // whether we are locking aspect ratio
+ bool m_allowOnlyDrag;
QUndoGroup m_undoGroup;
class SceneData
diff --git a/soundfactory.cpp b/soundfactory.cpp
index db207df..1a5e197 100644
--- a/soundfactory.cpp
+++ b/soundfactory.cpp
@@ -14,48 +14,42 @@
#include <stdlib.h>
-#include <kmessagebox.h>
-#include <KLocalizedString>
-
-#include <phonon/MediaObject>
-
#include <QDir>
#include <QDomDocument>
#include <QFile>
-#include <QStandardPaths>
+#include <QMediaPlayer>
+#include <QSet>
+#include <QUrl>
-#include "toplevel.h"
+#include "filefactory.h"
// Constructor
-SoundFactory::SoundFactory(TopLevel *parent)
+SoundFactory::SoundFactory(SoundFactoryCallbacks *callbacks)
+ : m_callbacks(callbacks)
{
- topLevel = parent;
- player = Phonon::createPlayer(Phonon::GameCategory);
- player->setParent(parent);
+ player = new QMediaPlayer();
}
// Destructor
SoundFactory::~SoundFactory()
{
+ delete player;
}
// Play some sound
void SoundFactory::playSound(const QString &soundRef) const
{
- int sound;
- QString soundFile;
-
- if (!topLevel->isSoundEnabled()) return;
+ if (!m_callbacks->isSoundEnabled()) return;
+ int sound;
for (sound = 0; sound < sounds; sound++)
if (!namesList[sound].compare(soundRef)) break;
if (sound == sounds) return;
- soundFile = QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "sounds/" ) + filesList[sound]);
+ const QString soundFile = FileFactory::locate(QLatin1String( "sounds/" ) + filesList[sound]);
if (soundFile.isEmpty()) return;
-//printf("%s\n", (const char *) soundFile);
- player->setCurrentSource(QUrl::fromLocalFile(soundFile));
+ player->setMedia(QUrl::fromLocalFile(soundFile));
player->play();
}
@@ -63,7 +57,7 @@ void SoundFactory::playSound(const QString &soundRef) const
void SoundFactory::registerLanguages()
{
QSet<QString> list;
- const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("sounds"), QStandardPaths::LocateDirectory);
+ const QStringList dirs = FileFactory::locateAll(QStringLiteral("sounds"));
Q_FOREACH (const QString &dir, dirs)
{
const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.soundtheme"));
@@ -81,9 +75,9 @@ void SoundFactory::registerLanguages()
QDomDocument document;
if (document.setContent(&file))
{
- QString code = document.documentElement().attribute(QStringLiteral( "code" ));
- bool enabled = !(QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "sounds/" ) + code + QLatin1Char( '/' ), QStandardPaths::LocateDirectory).isEmpty());
- topLevel->registerLanguage(code, soundTheme, enabled);
+ const QString code = document.documentElement().attribute(QStringLiteral( "code" ));
+ const bool enabled = FileFactory::folderExists(QLatin1String( "sounds/" ) + code + QLatin1Char( '/' ));
+ m_callbacks->registerLanguage(code, soundTheme, enabled);
}
}
}
diff --git a/soundfactory.h b/soundfactory.h
index a8d81e1..34b38b6 100644
--- a/soundfactory.h
+++ b/soundfactory.h
@@ -15,18 +15,20 @@
#include <QStringList>
-class TopLevel;
+class QMediaPlayer;
-namespace Phonon
+class SoundFactoryCallbacks
{
- class MediaObject;
-}
+public:
+ virtual ~SoundFactoryCallbacks() {};
+ virtual bool isSoundEnabled() const = 0;
+ virtual void registerLanguage(const QString &code, const QString &soundFile, bool enabled) = 0;
+};
class SoundFactory
{
public:
-
- explicit SoundFactory(TopLevel *parent);
+ explicit SoundFactory(SoundFactoryCallbacks *callbacks);
~SoundFactory();
bool loadLanguage(const QString &selectedLanguageFile);
@@ -37,14 +39,15 @@ public:
void registerLanguages();
private:
+ SoundFactoryCallbacks *m_callbacks;
+
QString currentSndFile; // The current language
int sounds; // Number of sounds
QStringList namesList, // List of sound names
filesList; // List of sound files associated with each sound name
- TopLevel *topLevel; // Top-level window
- Phonon::MediaObject *player; // Sound player
+ QMediaPlayer *player;
};
#endif
diff --git a/toplevel.cpp b/toplevel.cpp
index 414a78a..6df33b9 100644
--- a/toplevel.cpp
+++ b/toplevel.cpp
@@ -33,10 +33,10 @@
#include <QMimeDatabase>
#include <QPrintDialog>
#include <QPrinter>
-#include <QStandardPaths>
#include <QTemporaryFile>
#include <QWidgetAction>
+#include "filefactory.h"
#include "playground.h"
#include "soundfactory.h"
#include "playgrounddelegate.h"
@@ -52,7 +52,7 @@ TopLevel::TopLevel()
{
QString board, language;
- playGround = new PlayGround(this);
+ playGround = new PlayGround(this, this);
playGround->setObjectName( QStringLiteral( "playGround" ) );
soundFactory = new SoundFactory(this);
@@ -146,7 +146,7 @@ void TopLevel::changeGameboard(const QString &newGameBoard)
QFileInfo fi(newGameBoard);
if (fi.isRelative())
{
- fileToLoad = QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "pics/" ) + newGameBoard);
+ fileToLoad = FileFactory::locate(QLatin1String( "pics/" ) + newGameBoard);
}
else
{
@@ -193,7 +193,7 @@ void TopLevel::changeLanguage(const QString &soundFile)
QFileInfo fi(soundFile);
if (fi.isRelative())
{
- fileToLoad = QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String( "sounds/" ) + soundFile);
+ fileToLoad = FileFactory::locate(QLatin1String( "sounds/" ) + soundFile);
}
else
{
@@ -217,7 +217,7 @@ void TopLevel::changeLanguage(const QString &soundFile)
}
// Play a sound
-void TopLevel::playSound(const QString &ref) const
+void TopLevel::playSound(const QString &ref)
{
soundFactory->playSound(ref);
}
diff --git a/toplevel.h b/toplevel.h
index d8b3d96..662baea 100644
--- a/toplevel.h
+++ b/toplevel.h
@@ -14,11 +14,13 @@
#include <kxmlguiwindow.h>
#include <kcombobox.h>
+#include "soundfactory.h"
+#include "playground.h"
+
class QActionGroup;
class PlayGround;
-class SoundFactory;
-class TopLevel : public KXmlGuiWindow
+class TopLevel : public KXmlGuiWindow, public SoundFactoryCallbacks, public PlayGroundCallbacks
{
Q_OBJECT
@@ -28,12 +30,12 @@ public:
~TopLevel();
void open(const QUrl &url);
- void registerGameboard(const QString& menuText, const QString& boardFile, const QPixmap& pixmap);
- void registerLanguage(const QString &code, const QString &soundFile, bool enabled);
+ void registerGameboard(const QString& menuText, const QString& boardFile, const QPixmap& pixmap) override;
+ void registerLanguage(const QString &code, const QString &soundFile, bool enabled) override;
void changeLanguage(const QString &langCode);
- void playSound(const QString &ref) const;
+ void playSound(const QString &ref) override;
- bool isSoundEnabled() const;
+ bool isSoundEnabled() const override;
void changeGameboard(const QString &gameboard);
More information about the kde-doc-english
mailing list