From 76f4aa6c73725cdb6dd8b7c2aa3ea25d08c48b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 18 Feb 2014 11:12:28 +0200 Subject: [PATCH 01/60] Fixed|libdeng2: Missing return value in AutoRef --- doomsday/libdeng2/include/de/data/counted.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/libdeng2/include/de/data/counted.h b/doomsday/libdeng2/include/de/data/counted.h index 9fca89ffa8..4563cbe7c8 100644 --- a/doomsday/libdeng2/include/de/data/counted.h +++ b/doomsday/libdeng2/include/de/data/counted.h @@ -262,7 +262,7 @@ class AutoRef operator CountedType const * () const { return _ref; } operator CountedType * () { return _ref; } operator CountedType const & () const { return *_ref; } - operator CountedType & () { *_ref; } + operator CountedType & () { return *_ref; } private: CountedType *_ref; }; From 53ec5f6e5af4fbd49cd097941e37f57f00b6fff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 18 Feb 2014 15:09:30 +0200 Subject: [PATCH 02/60] libdeng2|libgui|Client|Server: Defining application metadata de::App now defines a method for setting all the application metadata in one call without having to access Qt methods. Also, the Unix-style home folder name can be defined from the application and is no longer hardcoded to ".doomsday". --- doomsday/client/src/clientapp.cpp | 6 ++-- doomsday/client/src/unix/dd_uinit.cpp | 4 ++- doomsday/libdeng2/include/de/core/app.h | 25 +++++++++++++++++ doomsday/libdeng2/include/de/core/textapp.h | 3 ++ doomsday/libdeng2/src/core/app.cpp | 31 +++++++++++++++++++-- doomsday/libdeng2/src/core/textapp.cpp | 11 +++++++- doomsday/libdeng2/src/core/unixinfo.cpp | 5 ++-- doomsday/libgui/include/de/gui/guiapp.h | 3 ++ doomsday/libgui/src/guiapp.cpp | 9 ++++++ doomsday/server/src/serverapp.cpp | 6 ++-- 10 files changed, 88 insertions(+), 15 deletions(-) diff --git a/doomsday/client/src/clientapp.cpp b/doomsday/client/src/clientapp.cpp index 5a75049b8c..76b08c09e0 100644 --- a/doomsday/client/src/clientapp.cpp +++ b/doomsday/client/src/clientapp.cpp @@ -326,10 +326,8 @@ ClientApp::ClientApp(int &argc, char **argv) QNetworkProxyFactory::setUseSystemConfiguration(true); // Metadata. - setOrganizationDomain ("dengine.net"); - setOrganizationName ("Deng Team"); - setApplicationName ("Doomsday Engine"); - setApplicationVersion (DOOMSDAY_VERSION_BASE); + setMetadata("Deng Team", "dengine.net", "Doomsday Engine", DOOMSDAY_VERSION_BASE); + setUnixHomeFolderName(".doomsday"); setTerminateFunc(handleLegacyCoreTerminate); diff --git a/doomsday/client/src/unix/dd_uinit.cpp b/doomsday/client/src/unix/dd_uinit.cpp index 26131cbbc6..5dd1a381db 100644 --- a/doomsday/client/src/unix/dd_uinit.cpp +++ b/doomsday/client/src/unix/dd_uinit.cpp @@ -25,6 +25,7 @@ #include #include +#include #ifdef UNIX # include "library.h" @@ -63,7 +64,8 @@ static void determineGlobalPaths(application_t* app) { filename_t homePath; directory_t* temp; - dd_snprintf(homePath, FILENAME_T_MAXLEN, "%s/.doomsday/runtime/", getenv("HOME")); + dd_snprintf(homePath, FILENAME_T_MAXLEN, "%s/%s/runtime/", getenv("HOME"), + DENG2_APP->unixHomeFolderName().toLatin1().constData()); temp = Dir_New(homePath); Dir_mkpath(Dir_Path(temp)); app->usingHomeDir = Dir_SetCurrent(Dir_Path(temp)); diff --git a/doomsday/libdeng2/include/de/core/app.h b/doomsday/libdeng2/include/de/core/app.h index 604bfa65b9..1d32e342a7 100644 --- a/doomsday/libdeng2/include/de/core/app.h +++ b/doomsday/libdeng2/include/de/core/app.h @@ -95,6 +95,31 @@ class DENG2_PUBLIC App : DENG2_OBSERVES(Clock, TimeChange) virtual ~App(); + /** + * Defines metadata about the application. + * + * @param appName Name of the application, as presented to humans. + * @param appVersion Version of the application. + * @param orgName Name of the author/organization. + * @param orgDomain Network domain of the author/organization. + */ + virtual void setMetadata(String const &orgName, String const &orgDomain, + String const &appName, String const &appVersion) = 0; + + /** + * Sets the Unix-style home folder name. For instance, ".doomsday" could be used. + * + * @param name Name of the (usually hidden) user-specific home data folder. + */ + void setUnixHomeFolderName(String const &name); + + String unixHomeFolderName() const; + + /** + * Returns the home folder name without the possible dot in the beginning. + */ + String unixEtcFolderName() const; + /** * Sets a callback to be called when an uncaught exception occurs. */ diff --git a/doomsday/libdeng2/include/de/core/textapp.h b/doomsday/libdeng2/include/de/core/textapp.h index c2e908badf..920971158f 100644 --- a/doomsday/libdeng2/include/de/core/textapp.h +++ b/doomsday/libdeng2/include/de/core/textapp.h @@ -46,6 +46,9 @@ class DENG2_PUBLIC TextApp : public QCoreApplication, public App, public: TextApp(int &argc, char **argv); + void setMetadata(String const &orgName, String const &orgDomain, + String const &appName, String const &appVersion); + bool notify(QObject *receiver, QEvent *event); int execLoop(); diff --git a/doomsday/libdeng2/src/core/app.cpp b/doomsday/libdeng2/src/core/app.cpp index bc6539611c..3893c4e86e 100644 --- a/doomsday/libdeng2/src/core/app.cpp +++ b/doomsday/libdeng2/src/core/app.cpp @@ -57,6 +57,7 @@ DENG2_PIMPL(App) /// Path of the application executable. NativePath appPath; + String unixHomeFolder; NativePath cachedBasePath; NativePath cachedPluginBinaryPath; @@ -103,8 +104,13 @@ DENG2_PIMPL(App) GameChangeScriptAudience scriptAudienceForGameChange; Instance(Public *a, QStringList args) - : Base(a), cmdLine(args), persistentData(0), config(0), - currentGame(0), terminateFunc(0) + : Base(a) + , cmdLine(args) + , unixHomeFolder(".doomsday") + , persistentData(0) + , config(0) + , currentGame(0) + , terminateFunc(0) { singletonApp = a; mainThread = QThread::currentThread(); @@ -263,6 +269,25 @@ App::~App() singletonApp = 0; } +void App::setUnixHomeFolderName(String const &name) +{ + d->unixHomeFolder = name; +} + +String App::unixHomeFolderName() const +{ + return d->unixHomeFolder; +} + +String App::unixEtcFolderName() const +{ + if(d->unixHomeFolder.startsWith(".")) + { + return d->unixHomeFolder.mid(1); + } + return d->unixHomeFolder; +} + void App::setTerminateFunc(void (*func)(char const *)) { d->terminateFunc = func; @@ -358,7 +383,7 @@ NativePath App::nativeHomePath() nativeHome = nativeHome / "runtime"; #else // UNIX NativePath nativeHome = QDir::homePath(); - nativeHome = nativeHome / ".doomsday/runtime"; + nativeHome = nativeHome / d->unixHomeFolder / "runtime"; #endif return (d->cachedHomePath = nativeHome); } diff --git a/doomsday/libdeng2/src/core/textapp.cpp b/doomsday/libdeng2/src/core/textapp.cpp index 094094f6b9..943ec7236a 100644 --- a/doomsday/libdeng2/src/core/textapp.cpp +++ b/doomsday/libdeng2/src/core/textapp.cpp @@ -42,6 +42,15 @@ TextApp::TextApp(int &argc, char **argv) d(new Instance(this)) {} +void TextApp::setMetadata(String const &orgName, String const &orgDomain, + String const &appName, String const &appVersion) +{ + setOrganizationName (orgName); + setOrganizationDomain(orgDomain); + setApplicationName (appName); + setApplicationVersion(appVersion); +} + bool TextApp::notify(QObject *receiver, QEvent *event) { try @@ -83,7 +92,7 @@ Loop &TextApp::loop() NativePath TextApp::appDataPath() const { - return NativePath(QDir::homePath()) / ".doomsday"; + return NativePath(QDir::homePath()) / unixHomeFolderName(); } void TextApp::loopIteration() diff --git a/doomsday/libdeng2/src/core/unixinfo.cpp b/doomsday/libdeng2/src/core/unixinfo.cpp index 18b1201959..28905632b1 100644 --- a/doomsday/libdeng2/src/core/unixinfo.cpp +++ b/doomsday/libdeng2/src/core/unixinfo.cpp @@ -21,6 +21,7 @@ #include "de/UnixInfo" #include "de/Info" +#include "de/App" #include namespace de { @@ -34,14 +35,14 @@ class Infos public: Infos(String fileName) : etcInfo(0), userInfo(0) { - String fn = "/etc/doomsday/" + fileName; + String fn = String("/etc") / App::app().unixEtcFolderName() / fileName; if(QFile::exists(fn)) { etcInfo = new Info; etcInfo->parseNativeFile(fn); } - fn = QDir::homePath() + "/.doomsday/" + fileName; + fn = String(QDir::homePath()) / App::app().unixHomeFolderName() / fileName; if(QFile::exists(fn)) { userInfo = new Info; diff --git a/doomsday/libgui/include/de/gui/guiapp.h b/doomsday/libgui/include/de/gui/guiapp.h index 74620eb5ad..8e7813010f 100644 --- a/doomsday/libgui/include/de/gui/guiapp.h +++ b/doomsday/libgui/include/de/gui/guiapp.h @@ -53,6 +53,9 @@ class LIBGUI_PUBLIC GuiApp : public QApplication, public App, public: GuiApp(int &argc, char **argv); + void setMetadata(String const &orgName, String const &orgDomain, + String const &appName, String const &appVersion); + bool notify(QObject *receiver, QEvent *event); /** diff --git a/doomsday/libgui/src/guiapp.cpp b/doomsday/libgui/src/guiapp.cpp index 79b897e68a..fe675efec0 100644 --- a/doomsday/libgui/src/guiapp.cpp +++ b/doomsday/libgui/src/guiapp.cpp @@ -44,6 +44,15 @@ GuiApp::GuiApp(int &argc, char **argv) d(new Instance(this)) {} +void GuiApp::setMetadata(String const &orgName, String const &orgDomain, + String const &appName, String const &appVersion) +{ + setOrganizationName (orgName); + setOrganizationDomain(orgDomain); + setApplicationName (appName); + setApplicationVersion(appVersion); +} + bool GuiApp::notify(QObject *receiver, QEvent *event) { try diff --git a/doomsday/server/src/serverapp.cpp b/doomsday/server/src/serverapp.cpp index 58f11ec8b5..c19b05bdc5 100644 --- a/doomsday/server/src/serverapp.cpp +++ b/doomsday/server/src/serverapp.cpp @@ -103,10 +103,8 @@ ServerApp::ServerApp(int &argc, char **argv) QNetworkProxyFactory::setUseSystemConfiguration(true); // Metadata. - setOrganizationDomain ("dengine.net"); - setOrganizationName ("Deng Team"); - setApplicationName ("Doomsday Server"); - setApplicationVersion (DOOMSDAY_VERSION_BASE); + setMetadata("Deng Team", "dengine.net", "Doomsday Server", DOOMSDAY_VERSION_BASE); + setUnixHomeFolderName(".doomsday"); setTerminateFunc(handleAppTerminate); From aec179aad6e0391d1095cdd7ae167989703abc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 24 Feb 2014 12:46:40 +0200 Subject: [PATCH 03/60] Refactor|Client|libappfw: Calculate projection matrix in VRConfig The function for calculating a projection matrix suitable for the current VR configuration was moved to libappfw. It was also broken down to calculate vertical FOV and view aspect as separate methods. --- doomsday/client/src/gl/gl_main.cpp | 8 +++ doomsday/libappfw/include/de/vr/vrconfig.h | 28 +++++++++++ doomsday/libappfw/src/vr/vrconfig.cpp | 58 ++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/doomsday/client/src/gl/gl_main.cpp b/doomsday/client/src/gl/gl_main.cpp index e7b5b795d1..020fb978ac 100644 --- a/doomsday/client/src/gl/gl_main.cpp +++ b/doomsday/client/src/gl/gl_main.cpp @@ -556,6 +556,13 @@ void GL_Restore2DState(int step, viewport_t const *port, viewdata_t const *viewD Matrix4f GL_GetProjectionMatrix() { + float const fov = Rend_FieldOfView(); + Vector2f const size(viewpw, viewph); + yfov = vrCfg().verticalFieldOfView(fov, size); + return vrCfg().projectionMatrix(Rend_FieldOfView(), size, glNearClip, glFarClip); +} + +#if 0 // We're assuming pixels are squares. float aspect = viewpw / (float) viewph; @@ -594,6 +601,7 @@ Matrix4f GL_GetProjectionMatrix() Matrix4f::translate(Vector3f(-vrCfg().eyeShift(), 0, 0)) * Matrix4f::scale(Vector3f(1, 1, -1)); } +#endif void GL_ProjectionMatrix() { diff --git a/doomsday/libappfw/include/de/vr/vrconfig.h b/doomsday/libappfw/include/de/vr/vrconfig.h index 2b5a513a37..2585c324a9 100644 --- a/doomsday/libappfw/include/de/vr/vrconfig.h +++ b/doomsday/libappfw/include/de/vr/vrconfig.h @@ -21,6 +21,7 @@ #define LIBAPPFW_VRCONFIG_H #include +#include namespace de { @@ -172,6 +173,33 @@ class LIBAPPFW_PUBLIC VRConfig /// Multisampling used in unwarped Rift framebuffer. int riftFramebufferSampleCount() const; + float viewAspect(Vector2f const &viewPortSize) const; + + /** + * Calculates a vertical field of view angle based on a horizontal FOV angle, + * view port size, and the current VR configuration. + * + * @param horizFovDegrees Field of view horizontally, in degrees. + * @param viewPortSize Size of the viewport in pixels. + * + * @return Vertical field of view, in degrees. + */ + float verticalFieldOfView(float horizFovDegrees, Vector2f const &viewPortSize) const; + + /** + * Produces a projection matrix suitable for the current VR configuration. + * + * @param fovDegrees Horizontal field of view angle. + * @param viewPortSize Size of the viewport in pixels. + * @param nearClip Distance of the near clipping plane. + * @param farClip Distance of the far clipping plane. + * + * @return Projection matrix. + */ + Matrix4f projectionMatrix(float fovDegrees, + Vector2f const &viewPortSize, + float nearClip, float farClip) const; + de::OculusRift &oculusRift(); de::OculusRift const &oculusRift() const; diff --git a/doomsday/libappfw/src/vr/vrconfig.cpp b/doomsday/libappfw/src/vr/vrconfig.cpp index 3388d6f69e..4f53b9124f 100644 --- a/doomsday/libappfw/src/vr/vrconfig.cpp +++ b/doomsday/libappfw/src/vr/vrconfig.cpp @@ -18,6 +18,7 @@ */ #include "de/VRConfig" +#include "de/math.h" namespace de { @@ -174,6 +175,63 @@ int VRConfig::riftFramebufferSampleCount() const return d->riftFramebufferSamples; } +float VRConfig::viewAspect(Vector2f const &viewPortSize) const +{ + if(mode() == OculusRift) + { + // Override with the Oculus Rift's aspect ratio. + return oculusRift().aspect(); + } + + // We're assuming pixels are squares. + return viewPortSize.x / viewPortSize.y; +} + +float VRConfig::verticalFieldOfView(float horizFovDegrees, Vector2f const &viewPortSize) const +{ + // We're assuming pixels are squares. + float const aspect = viewAspect(viewPortSize); + + if(mode() == OculusRift) + { + // A little trigonometry to apply aspect ratio to angles + float x = std::tan(.5f * degreeToRadian(horizFovDegrees)); + return radianToDegree(2.f * std::atan2(x / aspect, 1.f)); + } + + return horizFovDegrees / aspect; +} + +Matrix4f VRConfig::projectionMatrix(float fovDegrees, + Vector2f const &viewPortSize, + float nearClip, float farClip) const +{ + float const yfov = verticalFieldOfView(fovDegrees, viewPortSize); + float const fH = std::tan(.5f * degreeToRadian(yfov)) * nearClip; + float const fW = fH * viewAspect(viewPortSize); + + /* + * Asymmetric frustum shift is computed to realign screen-depth items after view point has shifted. + * Asymmetric frustum shift method is probably superior to competing toe-in stereo 3D method: + * - AFS preserves identical near and far clipping planes in both views + * - AFS shows items at/near infinity better + * - AFS conforms to what stereo 3D photographers call "ortho stereo" + * Asymmetric frustum shift is used for all stereo 3D modes except Oculus Rift mode, which only + * applies the viewpoint shift. + */ + float shift = 0; + if(frustumShift()) + { + shift = eyeShift() * nearClip / screenDistance(); + } + + return Matrix4f::frustum(-fW - shift, fW - shift, + -fH, fH, + nearClip, farClip) * + Matrix4f::translate(Vector3f(-eyeShift(), 0, 0)) * + Matrix4f::scale(Vector3f(1, 1, -1)); +} + OculusRift &VRConfig::oculusRift() { return d->ovr; From 5e4351787f8b4d86a58b21addcd395d7e625f51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 14:14:56 +0200 Subject: [PATCH 04/60] Fixed|Unix: Crash when launching application (UnixInfo) UnixInfo needed to know the application's /etc path, but the application had not been fully constructed at the time. --- doomsday/libdeng2/src/core/app.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doomsday/libdeng2/src/core/app.cpp b/doomsday/libdeng2/src/core/app.cpp index 65ba957e3d..de1a3a9b0b 100644 --- a/doomsday/libdeng2/src/core/app.cpp +++ b/doomsday/libdeng2/src/core/app.cpp @@ -77,7 +77,7 @@ DENG2_PIMPL(App) /// The archive is owned by the file system. Archive *persistentData; - UnixInfo unixInfo; + QScopedPointer unixInfo; /// The configuration. Config *config; @@ -232,6 +232,8 @@ DENG2_PIMPL(App) App::App(NativePath const &appFilePath, QStringList args) : d(new Instance(this, args)) { + d->unixInfo.reset(new UnixInfo); + // Global time source for animations. Animation::setClock(&d->clock); @@ -359,7 +361,7 @@ NativePath App::nativePluginBinaryPath() path = DENG_LIBRARY_DIR; # endif // Also check the system config files. - d->unixInfo.path("libdir", path); + d->unixInfo->path("libdir", path); #endif return (d->cachedPluginBinaryPath = path); } @@ -426,7 +428,7 @@ NativePath App::nativeBasePath() path = DENG_BASE_DIR; # endif // Also check the system config files. - d->unixInfo.path("basedir", path); + d->unixInfo->path("basedir", path); #endif return (d->cachedBasePath = path); } @@ -543,6 +545,7 @@ bool App::appExists() App &App::app() { + DENG2_ASSERT(appExists()); return *singletonApp; } @@ -596,7 +599,7 @@ Config &App::config() UnixInfo &App::unixInfo() { - return DENG2_APP->d->unixInfo; + return *DENG2_APP->d->unixInfo; } } // namespace de From ea8ef79f5f86b4a3125a93baed416ca1a0975ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 14:15:34 +0200 Subject: [PATCH 05/60] UI|Client: Added "24-bit" color depth to Video Settings --- doomsday/client/src/ui/dialogs/videosettingsdialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp b/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp index 8379c72205..da370bef0c 100644 --- a/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp +++ b/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp @@ -180,6 +180,7 @@ VideoSettingsDialog::VideoSettingsDialog(String const &name) d->depths->items() << new ChoiceItem(tr("32-bit"), 32) + << new ChoiceItem(tr("24-bit"), 24) << new ChoiceItem(tr("16-bit"), 16); #endif From 925bbd08c928223d1ed993702517f4374976156b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 14:33:49 +0200 Subject: [PATCH 06/60] Client|Stereo 3D: Cleanup --- doomsday/client/src/gl/gl_main.cpp | 41 ----------- doomsday/client/src/render/rend_main.cpp | 94 +++--------------------- 2 files changed, 11 insertions(+), 124 deletions(-) diff --git a/doomsday/client/src/gl/gl_main.cpp b/doomsday/client/src/gl/gl_main.cpp index 020fb978ac..73d07503df 100644 --- a/doomsday/client/src/gl/gl_main.cpp +++ b/doomsday/client/src/gl/gl_main.cpp @@ -562,47 +562,6 @@ Matrix4f GL_GetProjectionMatrix() return vrCfg().projectionMatrix(Rend_FieldOfView(), size, glNearClip, glFarClip); } -#if 0 - // We're assuming pixels are squares. - float aspect = viewpw / (float) viewph; - - if (vrCfg().mode() == VRConfig::OculusRift) - { - aspect = vrCfg().oculusRift().aspect(); - // A little trigonometry to apply aspect ratio to angles - float x = tan(0.5 * de::degreeToRadian(Rend_FieldOfView())); - yfov = de::radianToDegree(2.0 * atan2(x/aspect, 1.0f)); - } - else - { - yfov = Rend_FieldOfView() / aspect; - } - - float fH = tan(0.5 * de::degreeToRadian(yfov)) * glNearClip; - float fW = fH*aspect; - /* - * Asymmetric frustum shift is computed to realign screen-depth items after view point has shifted. - * Asymmetric frustum shift method is probably superior to competing toe-in stereo 3D method: - * - AFS preserves identical near and far clipping planes in both views - * - AFS shows items at/near infinity better - * - AFS conforms to what stereo 3D photographers call "ortho stereo" - * Asymmetric frustum shift is used for all stereo 3D modes except Oculus Rift mode, which only - * applies the viewpoint shift. - */ - float frustumShift = 0; - if (vrCfg().frustumShift()) - { - frustumShift = vrCfg().eyeShift() * glNearClip / vrCfg().screenDistance(); - } - - return Matrix4f::frustum(-fW - frustumShift, fW - frustumShift, - -fH, fH, - glNearClip, glFarClip) * - Matrix4f::translate(Vector3f(-vrCfg().eyeShift(), 0, 0)) * - Matrix4f::scale(Vector3f(1, 1, -1)); -} -#endif - void GL_ProjectionMatrix() { DENG_ASSERT_IN_MAIN_THREAD(); diff --git a/doomsday/client/src/render/rend_main.cpp b/doomsday/client/src/render/rend_main.cpp index cd7e2fd7e9..ef0a701557 100644 --- a/doomsday/client/src/render/rend_main.cpp +++ b/doomsday/client/src/render/rend_main.cpp @@ -512,103 +512,31 @@ Matrix4f Rend_GetModelViewMatrix(int consoleNum, bool useAngles) if(useAngles) { - //bool scheduledLate = false; - float yaw = vang; float pitch = vpitch; float roll = 0; - /* - static float storedPitch, storedRoll, storedYaw; - */ + /// @todo Elevate roll angle use into viewer_t, and maybe all the way up into player + /// model. /* - if(VR::viewPositionHeld()) + * Pitch and yaw can be taken directly from the head tracker, as the game is aware of + * these values and is syncing with them independently (however, game has more + * latency). + */ + if((vrCfg().mode() == VRConfig::OculusRift) && vrCfg().oculusRift().isReady()) { - roll = storedRoll; - pitch = storedPitch; - yaw = storedYaw; - } - else*/ + Vector3f const pry = vrCfg().oculusRift().headOrientation(); - { - /// @todo Elevate roll angle use into viewer_t, and maybe all the way up into player - /// model. + // Use angles directly from the Rift for best response. + roll = -radianToDegree(pry[1]); + pitch = radianToDegree(pry[0]); - /* - * Pitch and yaw can be taken directly from the head tracker, as the game is aware of - * these values and is syncing with them independently (however, game has more - * latency). - */ - if((vrCfg().mode() == VRConfig::OculusRift) && vrCfg().oculusRift().isReady()) - { - Vector3f const pry = vrCfg().oculusRift().headOrientation(); - - // Use angles directly from the Rift for best response. - roll = -radianToDegree(pry[1]); - pitch = radianToDegree(pry[0]); - -#if 0 - - static float previousRiftYaw = 0; - static float previousVang2 = 0; - - // Desired view angle without interpolation? - float vang2 = viewData->latest.angle / (float) ANGLE_MAX *360 - 90; - - // Late-scheduled update - scheduledLate = true; - roll = -radianToDegree(pry[1]); - pitch = radianToDegree(pry[0]); - - // Yaw might have a contribution from mouse/keyboard. - // So only late schedule if it seems to be head tracking only. - yaw = vang2; // default no late schedule - float currentRiftYaw = radianToDegree(pry[2]); - float dRiftYaw = currentRiftYaw - previousRiftYaw; - while (dRiftYaw > 180) dRiftYaw -= 360; - while (dRiftYaw < -180) dRiftYaw += 360; - float dVang = vang2 - previousVang2; - while (dVang > 180) dVang -= 360; - while (dVang < -180) dVang += 360; - if (abs(dVang) < 2.0 * abs(dRiftYaw)) // Mostly head motion - { - yaw = storedYaw + dRiftYaw; - float dy = vang2 - yaw; - while (dy > 180) dy -= 360; - while (dy < -180) dy += 360; - yaw += 0.05 * dy; // ease slowly toward target angle - } - else - { - yaw = vang2; // No interpolation if not from head tracker - } - - previousRiftYaw = currentRiftYaw; - previousVang2 = vang2; -#endif - } - - /* - if(!scheduledLate) - { - // Vanilla angle update - roll = 0; - pitch = vpitch; - yaw = vang; - }*/ } modelView = Matrix4f::rotate(roll, Vector3f(0, 0, 1)) * Matrix4f::rotate(pitch, Vector3f(1, 0, 0)) * Matrix4f::rotate(yaw, Vector3f(0, 1, 0)); - - /* - // Keep these for possible use in later frames. - storedRoll = roll; - storedPitch = pitch; - storedYaw = yaw; - */ } return (modelView * From 38632e365e5a4ab11673b382d9b13b043ad89c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 14:34:53 +0200 Subject: [PATCH 07/60] libappfw|Oculus Rift: Modelview matrix according to head tracking Added a utility for putting together a modelview matrix for the tracked head position/orientation, however this is not used by the Doomsday client at the moment. --- doomsday/libappfw/include/de/vr/oculusrift.h | 13 +++++++++++-- doomsday/libappfw/src/vr/oculusrift.cpp | 10 +++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/doomsday/libappfw/include/de/vr/oculusrift.h b/doomsday/libappfw/include/de/vr/oculusrift.h index 278cc86e64..c472fe542a 100644 --- a/doomsday/libappfw/include/de/vr/oculusrift.h +++ b/doomsday/libappfw/include/de/vr/oculusrift.h @@ -22,6 +22,7 @@ #include "../libappfw.h" #include +#include namespace de { @@ -49,10 +50,18 @@ class LIBAPPFW_PUBLIC OculusRift void update(); - // Returns current pitch, roll, yaw angles, in radians. If no head tracking is available, - // the returned values are not valid. + /** + * Returns the current head orientation as a vector containing the pitch, roll and + * yaw angles, in radians. If no head tracking is available, the returned values are + * not valid. + */ Vector3f headOrientation() const; + /** + * Returns a model-view matrix that applies the head's orientation. + */ + Matrix4f headModelViewMatrix() const; + float predictionLatency() const; /** diff --git a/doomsday/libappfw/src/vr/oculusrift.cpp b/doomsday/libappfw/src/vr/oculusrift.cpp index 8b8bf7f784..2ad871dfed 100644 --- a/doomsday/libappfw/src/vr/oculusrift.cpp +++ b/doomsday/libappfw/src/vr/oculusrift.cpp @@ -319,7 +319,7 @@ void OculusRift::update() Vector3f OculusRift::headOrientation() const { - de::Vector3f result; + Vector3f result; #ifdef DENG_HAVE_OCULUS_API DENG2_GUARD(d); if(isReady()) @@ -332,6 +332,14 @@ Vector3f OculusRift::headOrientation() const return result; } +Matrix4f OculusRift::headModelViewMatrix() const +{ + Vector3f const pry = headOrientation(); + return Matrix4f::rotate(pry[1], Vector3f(0, 0, 1)) * + Matrix4f::rotate(pry[0], Vector3f(1, 0, 0)) * + Matrix4f::rotate(pry[2], Vector3f(0, 1, 0)); +} + float OculusRift::distortionScale() const { float lensShift = d->screenSize.x * 0.25f - lensSeparationDistance() * 0.5f; From ac35b95b0a571c3f1850a91e3c8ce5ca2b991d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 14:35:42 +0200 Subject: [PATCH 08/60] UI|Client: Cleanup in 3D & VR Settings Moved the Oculus Rift specific multisampling setting below the Oculus Rift subtitle. --- .../src/ui/dialogs/vrsettingsdialog.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/doomsday/client/src/ui/dialogs/vrsettingsdialog.cpp b/doomsday/client/src/ui/dialogs/vrsettingsdialog.cpp index cc8c8ff398..39ce5ebd27 100644 --- a/doomsday/client/src/ui/dialogs/vrsettingsdialog.cpp +++ b/doomsday/client/src/ui/dialogs/vrsettingsdialog.cpp @@ -106,8 +106,6 @@ VRSettingsDialog::VRSettingsDialog(String const &name) LabelWidget *heightLabel = LabelWidget::newWithText(tr("Height (m):"), &area()); LabelWidget *ipdLabel = LabelWidget::newWithText(tr("IPD (mm):"), &area()); LabelWidget *dominantLabel = LabelWidget::newWithText(tr("Dominant Eye:"), &area()); - LabelWidget *sampleLabel = LabelWidget::newWithText(tr("Oculus Rift\nMultisampling:"), &area()); - sampleLabel->setTextLineAlignment(ui::AlignRight); // Layout. GridLayout layout(area().contentRule().left(), area().contentRule().top()); @@ -118,20 +116,21 @@ VRSettingsDialog::VRSettingsDialog(String const &name) << *heightLabel << *d->humanHeight << *ipdLabel << *d->ipd << *dominantLabel << *d->dominantEye - << Const(0) << *d->swapEyes - << *sampleLabel << *d->riftSamples; + << Const(0) << *d->swapEyes; + + LabelWidget *ovrLabel = LabelWidget::newWithText(_E(1)_E(D) + tr("Oculus Rift"), &area()); + LabelWidget *sampleLabel = LabelWidget::newWithText(tr("Multisampling:"), &area()); + ovrLabel->margins().setTop("gap"); + sampleLabel->setTextLineAlignment(ui::AlignRight); + + layout.setCellAlignment(Vector2i(0, 5), ui::AlignLeft); + layout.append(*ovrLabel, 2) << *sampleLabel << *d->riftSamples; if(vrCfg().oculusRift().isReady()) { - LabelWidget *ovrLabel = LabelWidget::newWithText(_E(1)_E(D) + tr("Oculus Rift"), &area()); LabelWidget *latencyLabel = LabelWidget::newWithText(tr("Prediction Latency:"), &area()); LabelWidget *utilLabel = LabelWidget::newWithText(tr("Utilities:"), &area()); - ovrLabel->margins().setTop("gap"); - - layout.setCellAlignment(Vector2i(0, 6), ui::AlignLeft); - - layout.append(*ovrLabel, 2); layout << *latencyLabel << *d->riftPredictionLatency << *utilLabel << *d->riftSetup << Const(0) << *d->desktopSetup; From 98ea79b5170719ec98a5ee382de76a7e6e3be5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 17:17:18 +0200 Subject: [PATCH 09/60] Cleanup --- doomsday/libgui/src/nativefont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/libgui/src/nativefont.cpp b/doomsday/libgui/src/nativefont.cpp index f06df24396..6a846f03ab 100644 --- a/doomsday/libgui/src/nativefont.cpp +++ b/doomsday/libgui/src/nativefont.cpp @@ -70,7 +70,7 @@ NativeFont::NativeFont(String const &family) : d(new Instance(this)) setFamily(family); } -NativeFont::NativeFont(NativeFont const &other) : d(new Instance(this)) +NativeFont::NativeFont(NativeFont const &other) : Asset(other), d(new Instance(this)) { *this = other; } From 9ba60bf2fed04273a810cbc1a38c991492785361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 17:19:13 +0200 Subject: [PATCH 10/60] qmake|SDK: Added sdk.pro, install rules for headers Public headers are now specified using a macro that automatically adds an install rule for them when doing an SDK build. --- doomsday/build/build.pro | 4 ++-- doomsday/config.pri | 10 +++++++++ doomsday/libappfw/libappfw.pro | 35 +++++++++++++++++++++++-------- doomsday/libdeng2/concurrency.pri | 10 +++++---- doomsday/libdeng2/data.pri | 10 +++++---- doomsday/libdeng2/filesys.pri | 10 +++++---- doomsday/libdeng2/game.pri | 10 ++++----- doomsday/libdeng2/libdeng2.pro | 14 +++++++------ doomsday/libdeng2/network.pri | 13 ++++++------ doomsday/libdeng2/scriptsys.pri | 10 +++++---- doomsday/libdeng2/widgets.pri | 10 +++++---- doomsday/libgui/libgui.pro | 9 +++++--- doomsday/libshell/libshell.pro | 5 +++-- doomsday/macros.pri | 17 +++++++++++++++ doomsday/sdk.pro | 28 +++++++++++++++++++++++++ 15 files changed, 141 insertions(+), 54 deletions(-) create mode 100644 doomsday/sdk.pro diff --git a/doomsday/build/build.pro b/doomsday/build/build.pro index 8468b1b070..7519caa11d 100644 --- a/doomsday/build/build.pro +++ b/doomsday/build/build.pro @@ -20,12 +20,12 @@ include(../config.pri) QMAKE_STRIP = true # Update the PK3 files. -!deng_nopackres { +!deng_sdk:!deng_nopackres { runPython2InDir($$PWD/scripts/, packres.py --quiet \"$$OUT_PWD/..\") } # Install the launcher. -deng_snowberry { +!deng_sdk:deng_snowberry { SB_ROOT = ../../snowberry SB_DIR = $$DENG_BASE_DIR/snowberry diff --git a/doomsday/config.pri b/doomsday/config.pri index bc8ea7bc88..3662d6a044 100644 --- a/doomsday/config.pri +++ b/doomsday/config.pri @@ -74,6 +74,12 @@ CONFIG(debug, debug|release) { DEFINES += NDEBUG } +# SDK build. +deng_sdk { + DEFINES += DENG_SDK_BUILD + echo("SDK build.") +} + # Debugging options. deng_fakememoryzone: DEFINES += LIBDENG_FAKE_MEMORY_ZONE @@ -100,6 +106,10 @@ else:macx: include(config_macx.pri) # Apply deng_* Configuration ------------------------------------------------- + !isEmpty(SDK_PREFIX): DENG_SDK_HEADER_DIR = $$SDK_PREFIX/include/doomsday/de +else:!isEmpty(PREFIX): DENG_SDK_HEADER_DIR = $$PREFIX/include/doomsday/de + else: DENG_SDK_HEADER_DIR = $$OUT_PWD/include/de + unix:deng_ccache { # ccache can be used to speed up recompilation. *-clang* { diff --git a/doomsday/libappfw/libappfw.pro b/doomsday/libappfw/libappfw.pro index 28ea1c51ce..0bd5c1fa4e 100644 --- a/doomsday/libappfw/libappfw.pro +++ b/doomsday/libappfw/libappfw.pro @@ -28,7 +28,7 @@ win32 { } # Public headers. -HEADERS += \ +publicHeaders(root, \ include/de/AtlasProceduralImage \ include/de/BaseGuiApp \ include/de/BaseWindow \ @@ -76,6 +76,14 @@ HEADERS += \ include/de/VRWindowTransform \ include/de/WindowSystem \ include/de/WindowTransform \ + include/de/VariableChoiceWidget \ + include/de/VariableToggleWidget \ + include/de/VRConfig \ + \ + include/de/libappfw.h \ +) + +publicHeaders(ui, \ include/de/ui/ActionItem \ include/de/ui/Data \ include/de/ui/ImageItem \ @@ -86,12 +94,11 @@ HEADERS += \ include/de/ui/SubmenuItem \ include/de/ui/SubwidgetItem \ include/de/ui/VariableToggleItem \ - include/de/VariableChoiceWidget \ - include/de/VariableToggleWidget \ - include/de/VRConfig \ \ - include/de/dialogs/inputdialog.h \ - include/de/dialogs/messagedialog.h \ + include/de/ui/defs.h \ +) + +publicHeaders(framework, \ include/de/framework/actionitem.h \ include/de/framework/atlasproceduralimage.h \ include/de/framework/baseguiapp.h \ @@ -123,10 +130,14 @@ HEADERS += \ include/de/framework/vrwindowtransform.h \ include/de/framework/windowsystem.h \ include/de/framework/windowtransform.h \ - include/de/libappfw.h \ - include/de/ui/defs.h \ +) + +publicHeaders(vr, \ include/de/vr/oculusrift.h \ include/de/vr/vrconfig.h \ +) + +publicHeaders(widgets, \ include/de/widgets/blurwidget.h \ include/de/widgets/buttonwidget.h \ include/de/widgets/choicewidget.h \ @@ -152,7 +163,13 @@ HEADERS += \ include/de/widgets/tabwidget.h \ include/de/widgets/togglewidget.h \ include/de/widgets/variablechoicewidget.h \ - include/de/widgets/variabletogglewidget.h + include/de/widgets/variabletogglewidget.h \ +) + +publicHeaders(dialogs, \ + include/de/dialogs/inputdialog.h \ + include/de/dialogs/messagedialog.h \ +) # Sources and private headers. SOURCES += \ diff --git a/doomsday/libdeng2/concurrency.pri b/doomsday/libdeng2/concurrency.pri index 217f2875bc..6f242088b3 100644 --- a/doomsday/libdeng2/concurrency.pri +++ b/doomsday/libdeng2/concurrency.pri @@ -1,18 +1,20 @@ -HEADERS += \ +publicHeaders(root, \ include/de/Guard \ include/de/Lockable \ include/de/ReadWriteLockable \ include/de/Task \ include/de/TaskPool \ - include/de/Waitable + include/de/Waitable \ +) -HEADERS += \ +publicHeaders(concurrency, \ include/de/concurrency/guard.h \ include/de/concurrency/lockable.h \ include/de/concurrency/readwritelockable.h \ include/de/concurrency/task.h \ include/de/concurrency/taskpool.h \ - include/de/concurrency/waitable.h + include/de/concurrency/waitable.h \ +) SOURCES += \ src/concurrency/guard.cpp \ diff --git a/doomsday/libdeng2/data.pri b/doomsday/libdeng2/data.pri index 7253bfb4b0..7fcc666a7d 100644 --- a/doomsday/libdeng2/data.pri +++ b/doomsday/libdeng2/data.pri @@ -1,4 +1,4 @@ -HEADERS += \ +publicHeaders(root, \ include/de/AccessorValue \ include/de/Archive \ include/de/ArrayValue \ @@ -51,9 +51,10 @@ HEADERS += \ include/de/WaitableFIFO \ include/de/Writer \ include/de/Zeroed \ - include/de/ZipArchive + include/de/ZipArchive \ +) -HEADERS += \ +publicHeaders(data, \ include/de/data/accessorvalue.h \ include/de/data/archive.h \ include/de/data/arrayvalue.h \ @@ -105,7 +106,8 @@ HEADERS += \ include/de/data/waitablefifo.h \ include/de/data/writer.h \ include/de/data/zeroed.h \ - include/de/data/ziparchive.h + include/de/data/ziparchive.h \ +) SOURCES += \ src/data/accessorvalue.cpp \ diff --git a/doomsday/libdeng2/filesys.pri b/doomsday/libdeng2/filesys.pri index 04d779853b..e8b1fe7d03 100644 --- a/doomsday/libdeng2/filesys.pri +++ b/doomsday/libdeng2/filesys.pri @@ -1,4 +1,4 @@ -HEADERS += \ +publicHeaders(root, \ include/de/ArchiveFeed \ include/de/ArchiveEntryFile \ include/de/ByteArrayFile \ @@ -11,9 +11,10 @@ HEADERS += \ include/de/LibraryFile \ include/de/NativeFile \ include/de/NativePath \ - include/de/PackageFolder + include/de/PackageFolder \ +) -HEADERS += \ +publicHeaders(filesys, \ include/de/filesys/archivefeed.h \ include/de/filesys/archiveentryfile.h \ include/de/filesys/bytearrayfile.h \ @@ -25,7 +26,8 @@ HEADERS += \ include/de/filesys/libraryfile.h \ include/de/filesys/nativefile.h \ include/de/filesys/nativepath.h \ - include/de/filesys/packagefolder.h + include/de/filesys/packagefolder.h \ +) SOURCES += \ src/filesys/archivefeed.cpp \ diff --git a/doomsday/libdeng2/game.pri b/doomsday/libdeng2/game.pri index 53f05316c3..9adbf5971b 100644 --- a/doomsday/libdeng2/game.pri +++ b/doomsday/libdeng2/game.pri @@ -1,8 +1,8 @@ -HEADERS += \ - include/de/game/Game - -HEADERS += \ - include/de/game/game.h +publicHeaders(game, \ + include/de/game/Game \ + \ + include/de/game/game.h \ +) SOURCES += \ src/game/game.cpp diff --git a/doomsday/libdeng2/libdeng2.pro b/doomsday/libdeng2/libdeng2.pro index 5a52309817..824ff0a0ed 100644 --- a/doomsday/libdeng2/libdeng2.pro +++ b/doomsday/libdeng2/libdeng2.pro @@ -68,8 +68,7 @@ include(network.pri) include(scriptsys.pri) include(widgets.pri) -# Convenience headers. -HEADERS += \ +publicHeaders(root, \ include/de/App \ include/de/Asset \ include/de/Clock \ @@ -98,14 +97,16 @@ HEADERS += \ include/de/TextStreamLogSink \ include/de/UnixInfo \ include/de/Vector \ - include/de/Version - -HEADERS += \ + include/de/Version \ + \ include/de/c_wrapper.h \ include/de/charsymbols.h \ include/de/error.h \ include/de/libdeng2.h \ include/de/math.h \ +) + +publicHeaders(core, \ include/de/core/app.h \ include/de/core/asset.h \ include/de/core/clock.h \ @@ -133,7 +134,8 @@ HEADERS += \ include/de/core/textstreamlogsink.h \ include/de/core/unixinfo.h \ include/de/core/vector.h \ - include/de/core/version.h + include/de/core/version.h \ +) # Private headers. HEADERS += \ diff --git a/doomsday/libdeng2/network.pri b/doomsday/libdeng2/network.pri index 1d8a875f6c..8e6e8e14f1 100644 --- a/doomsday/libdeng2/network.pri +++ b/doomsday/libdeng2/network.pri @@ -1,4 +1,4 @@ -HEADERS += \ +publicHeaders(root, \ include/de/Address \ include/de/Beacon \ include/de/BlockPacket \ @@ -9,9 +9,10 @@ HEADERS += \ include/de/Protocol \ include/de/RecordPacket \ include/de/Socket \ - include/de/Transmitter + include/de/Transmitter \ +) -HEADERS += \ +publicHeaders(net, \ include/de/net/address.h \ include/de/net/beacon.h \ include/de/net/blockpacket.h \ @@ -22,10 +23,8 @@ HEADERS += \ include/de/net/protocol.h \ include/de/net/recordpacket.h \ include/de/net/socket.h \ - include/de/net/transmitter.h - -# Private headers. -HEADERS += + include/de/net/transmitter.h \ +) SOURCES += \ src/net/address.cpp \ diff --git a/doomsday/libdeng2/scriptsys.pri b/doomsday/libdeng2/scriptsys.pri index 2a617c5bb9..f155d556b2 100644 --- a/doomsday/libdeng2/scriptsys.pri +++ b/doomsday/libdeng2/scriptsys.pri @@ -1,4 +1,4 @@ -HEADERS += \ +publicHeaders(root, \ include/de/ArrayExpression \ include/de/AssignStatement \ include/de/BuiltInExpression \ @@ -34,9 +34,10 @@ HEADERS += \ include/de/TokenBuffer \ include/de/TokenRange \ include/de/TryStatement \ - include/de/WhileStatement + include/de/WhileStatement \ +) -HEADERS += \ +publicHeaders(scriptsys, \ include/de/scriptsys/arrayexpression.h \ include/de/scriptsys/assignstatement.h \ include/de/scriptsys/builtinexpression.h \ @@ -72,7 +73,8 @@ HEADERS += \ include/de/scriptsys/tokenbuffer.h \ include/de/scriptsys/tokenrange.h \ include/de/scriptsys/trystatement.h \ - include/de/scriptsys/whilestatement.h + include/de/scriptsys/whilestatement.h \ +) SOURCES += \ src/scriptsys/arrayexpression.cpp \ diff --git a/doomsday/libdeng2/widgets.pri b/doomsday/libdeng2/widgets.pri index 25eca5b3f3..41b7c2a134 100644 --- a/doomsday/libdeng2/widgets.pri +++ b/doomsday/libdeng2/widgets.pri @@ -1,4 +1,4 @@ -HEADERS += \ +publicHeaders(root, \ include/de/Action \ include/de/Animation \ include/de/AnimationVector \ @@ -9,9 +9,10 @@ HEADERS += \ include/de/RuleRectangle \ include/de/RootWidget \ include/de/ScalarRule \ - include/de/Widget + include/de/Widget \ +) -HEADERS += \ +publicHeaders(widgets, \ include/de/widgets/action.h \ include/de/widgets/animation.h \ include/de/widgets/animationvector.h \ @@ -24,7 +25,8 @@ HEADERS += \ include/de/widgets/rulebank.h \ include/de/widgets/rules.h \ include/de/widgets/scalarrule.h \ - include/de/widgets/widget.h + include/de/widgets/widget.h \ +) SOURCES += \ src/widgets/action.cpp \ diff --git a/doomsday/libgui/libgui.pro b/doomsday/libgui/libgui.pro index ce28e677fc..a8d4689fe6 100644 --- a/doomsday/libgui/libgui.pro +++ b/doomsday/libgui/libgui.pro @@ -45,7 +45,7 @@ else:unix { } # Public headers. -HEADERS += \ +publicHeaders(root, \ include/de/Atlas \ include/de/AtlasTexture \ include/de/Canvas \ @@ -78,7 +78,9 @@ HEADERS += \ include/de/PersistentCanvasWindow \ include/de/RowAtlasAllocator \ include/de/VertexBuilder \ - \ +) + +publicHeaders(gui, \ include/de/gui/atlas.h \ include/de/gui/atlastexture.h \ include/de/gui/canvas.h \ @@ -115,7 +117,8 @@ HEADERS += \ include/de/gui/opengl.h \ include/de/gui/persistentcanvaswindow.h \ include/de/gui/rowatlasallocator.h \ - include/de/gui/vertexbuilder.h + include/de/gui/vertexbuilder.h \ +) # Sources and private headers. SOURCES += \ diff --git a/doomsday/libshell/libshell.pro b/doomsday/libshell/libshell.pro index 0c487494bc..8d95ba5966 100644 --- a/doomsday/libshell/libshell.pro +++ b/doomsday/libshell/libshell.pro @@ -23,7 +23,7 @@ DEFINES += __LIBSHELL__ INCLUDEPATH += include # Public headers. -HEADERS += \ +publicHeaders(shell, \ include/de/shell/AbstractLineEditor \ include/de/shell/AbstractLink \ include/de/shell/Action \ @@ -73,7 +73,8 @@ HEADERS += \ include/de/shell/serverfinder.h \ include/de/shell/textcanvas.h \ include/de/shell/textrootwidget.h \ - include/de/shell/textwidget.h + include/de/shell/textwidget.h \ +) # Sources and private headers. SOURCES += \ diff --git a/doomsday/macros.pri b/doomsday/macros.pri index 97f0078b3e..744d740387 100644 --- a/doomsday/macros.pri +++ b/doomsday/macros.pri @@ -64,3 +64,20 @@ macx { doPostLink("install_name_tool -id @executable_path/../DengPlugins/$${1}.bundle/Versions/$$2/$$1 $${1}.bundle/Versions/$$2/$$1") } } + +defineTest(publicHeaders) { + # 1: id ("root" for the main include dir) + # 2: header files + deng_sdk { + dir = $$1 + contains(1, root): dir = . + eval(sdk_headers_$${1}.files += $$2) + eval(sdk_headers_$${1}.path = $$DENG_SDK_HEADER_DIR/$$dir) + INSTALLS *= sdk_headers_$$1 + export(INSTALLS) + export(sdk_headers_$${1}.files) + export(sdk_headers_$${1}.path) + } + HEADERS += $$2 + export(HEADERS) +} diff --git a/doomsday/sdk.pro b/doomsday/sdk.pro new file mode 100644 index 0000000000..1bc33c0cde --- /dev/null +++ b/doomsday/sdk.pro @@ -0,0 +1,28 @@ +# The Doomsday Engine Project +# Copyright (c) 2014 Jaakko Keränen + +greaterThan(QT_MAJOR_VERSION, 4): cache() + +!deng_sdk: error(\"deng_sdk'" must be defined in CONFIG!) + +include(config.pri) + +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = \ + build \ + libdeng2 \ + libdeng1 \ + libshell + +!deng_noclient|macx { + SUBDIRS += \ + libgui \ + libappfw +} + +SUBDIRS += \ + tests + +#SUBDIRS += postbuild + From 8ea3d4545f7e2a37318016d14006ab3a67324852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 18:43:41 +0200 Subject: [PATCH 11/60] Fixed|qmake: Typo --- doomsday/sdk.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/sdk.pro b/doomsday/sdk.pro index 1bc33c0cde..48e16f98da 100644 --- a/doomsday/sdk.pro +++ b/doomsday/sdk.pro @@ -3,7 +3,7 @@ greaterThan(QT_MAJOR_VERSION, 4): cache() -!deng_sdk: error(\"deng_sdk'" must be defined in CONFIG!) +!deng_sdk: error(\"deng_sdk\" must be defined in CONFIG!) include(config.pri) From 65fd3acde0aae7bc6e4f8d5ca5572ea73bac8369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Feb 2014 19:51:55 +0200 Subject: [PATCH 12/60] SDK|qmake: Install libraries to the SDK directory --- doomsday/config.pri | 46 ++++++++++++++++++++++------------ doomsday/libappfw/libappfw.pro | 5 ++++ doomsday/libdeng2/libdeng2.pro | 5 ++++ doomsday/libgui/libgui.pro | 5 ++++ doomsday/libshell/libshell.pro | 5 ++++ 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/doomsday/config.pri b/doomsday/config.pri index 3662d6a044..2ef90869bd 100644 --- a/doomsday/config.pri +++ b/doomsday/config.pri @@ -106,9 +106,36 @@ else:macx: include(config_macx.pri) # Apply deng_* Configuration ------------------------------------------------- - !isEmpty(SDK_PREFIX): DENG_SDK_HEADER_DIR = $$SDK_PREFIX/include/doomsday/de -else:!isEmpty(PREFIX): DENG_SDK_HEADER_DIR = $$PREFIX/include/doomsday/de - else: DENG_SDK_HEADER_DIR = $$OUT_PWD/include/de +deng_nofixedasm { + DEFINES += DENG_NO_FIXED_ASM +} +!deng_rangecheck { + DEFINES += DENG_NO_RANGECHECKING +} +deng_nosdlmixer|deng_nosdl { + DEFINES += DENG_DISABLE_SDLMIXER +} +deng_nosdl { + DEFINES += DENG_NO_SDL +} + +deng_sdk { + # SDK install location. + !isEmpty(SDK_PREFIX) { + DENG_SDK_HEADER_DIR = $$SDK_PREFIX/include/doomsday/de + DENG_SDK_LIB_DIR = $$SDK_PREFIX/lib + } + else:!isEmpty(PREFIX) { + DENG_SDK_HEADER_DIR = $$PREFIX/include/doomsday/de + DENG_SDK_LIB_DIR = $$PREFIX/lib + } + else { + DENG_SDK_HEADER_DIR = $$OUT_PWD/../include/de + DENG_SDK_LIB_DIR = $$OUT_PWD/../lib + } + echo(SDK header directory: $$DENG_SDK_HEADER_DIR) + echo(SDK library directory: $$DENG_SDK_LIB_DIR) +} unix:deng_ccache { # ccache can be used to speed up recompilation. @@ -122,16 +149,3 @@ unix:deng_ccache { QMAKE_CXX = ccache $$QMAKE_CXX } } - -deng_nofixedasm { - DEFINES += DENG_NO_FIXED_ASM -} -!deng_rangecheck { - DEFINES += DENG_NO_RANGECHECKING -} -deng_nosdlmixer|deng_nosdl { - DEFINES += DENG_DISABLE_SDLMIXER -} -deng_nosdl { - DEFINES += DENG_NO_SDL -} diff --git a/doomsday/libappfw/libappfw.pro b/doomsday/libappfw/libappfw.pro index 0bd5c1fa4e..56f16763ea 100644 --- a/doomsday/libappfw/libappfw.pro +++ b/doomsday/libappfw/libappfw.pro @@ -241,3 +241,8 @@ else { INSTALLS += target target.path = $$DENG_LIB_DIR } + +deng_sdk { + INSTALLS *= target + target.path = $$DENG_SDK_LIB_DIR +} diff --git a/doomsday/libdeng2/libdeng2.pro b/doomsday/libdeng2/libdeng2.pro index 824ff0a0ed..bcdd5dcda0 100644 --- a/doomsday/libdeng2/libdeng2.pro +++ b/doomsday/libdeng2/libdeng2.pro @@ -197,3 +197,8 @@ macx { INSTALLS += target target.path = $$DENG_LIB_DIR } + +deng_sdk { + INSTALLS *= target + target.path = $$DENG_SDK_LIB_DIR +} diff --git a/doomsday/libgui/libgui.pro b/doomsday/libgui/libgui.pro index a8d4689fe6..97c7589b25 100644 --- a/doomsday/libgui/libgui.pro +++ b/doomsday/libgui/libgui.pro @@ -188,3 +188,8 @@ else { INSTALLS += target target.path = $$DENG_LIB_DIR } + +deng_sdk { + INSTALLS *= target + target.path = $$DENG_SDK_LIB_DIR +} diff --git a/doomsday/libshell/libshell.pro b/doomsday/libshell/libshell.pro index 8d95ba5966..ce71194bf7 100644 --- a/doomsday/libshell/libshell.pro +++ b/doomsday/libshell/libshell.pro @@ -117,3 +117,8 @@ else { INSTALLS += target target.path = $$DENG_LIB_DIR } + +deng_sdk { + INSTALLS *= target + target.path = $$DENG_SDK_LIB_DIR +} From 816768d282f5c49fa8a1647aeda7996734bbb1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 13:12:45 +0200 Subject: [PATCH 13/60] libgui|Cleanup: Removed ARB_debug_output This extension wasn't in use and seems to be subtly differently defined on different platforms. --- .../libgui/include/de/gui/glentrypoints.h | 5 ---- doomsday/libgui/include/de/gui/glinfo.h | 1 - doomsday/libgui/src/glentrypoints.cpp | 10 ------- doomsday/libgui/src/glinfo.cpp | 28 ------------------- 4 files changed, 44 deletions(-) diff --git a/doomsday/libgui/include/de/gui/glentrypoints.h b/doomsday/libgui/include/de/gui/glentrypoints.h index 0f174089f2..19bc82a01d 100644 --- a/doomsday/libgui/include/de/gui/glentrypoints.h +++ b/doomsday/libgui/include/de/gui/glentrypoints.h @@ -122,11 +122,6 @@ LIBGUI_EXTERN_C PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; // Extensions: -#ifdef GL_ARB_debug_output -LIBGUI_EXTERN_C PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; -LIBGUI_EXTERN_C PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; -#endif - LIBGUI_EXTERN_C PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; LIBGUI_EXTERN_C PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; diff --git a/doomsday/libgui/include/de/gui/glinfo.h b/doomsday/libgui/include/de/gui/glinfo.h index 224ee3f10a..b13e87d68c 100644 --- a/doomsday/libgui/include/de/gui/glinfo.h +++ b/doomsday/libgui/include/de/gui/glinfo.h @@ -31,7 +31,6 @@ class LIBGUI_PUBLIC GLInfo /// Extension availability bits. struct Extensions { - duint32 ARB_debug_output : 1; duint32 ARB_framebuffer_object : 1; duint32 ARB_texture_env_combine : 1; duint32 ARB_texture_non_power_of_two : 1; diff --git a/doomsday/libgui/src/glentrypoints.cpp b/doomsday/libgui/src/glentrypoints.cpp index 9a33bdb6c8..4e4c703a85 100644 --- a/doomsday/libgui/src/glentrypoints.cpp +++ b/doomsday/libgui/src/glentrypoints.cpp @@ -99,11 +99,6 @@ PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; // Extensions: -#ifdef GL_ARB_debug_output -PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; -PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; -#endif - PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; @@ -198,11 +193,6 @@ void getAllOpenGLEntryPoints() // Extensions: -#ifdef GL_ARB_debug_output - GET_PROC_EXT(glDebugMessageControlARB); - GET_PROC_EXT(glDebugMessageCallbackARB); -#endif - GET_PROC_EXT(glBlitFramebufferEXT); GET_PROC_EXT(glRenderbufferStorageMultisampleEXT); diff --git a/doomsday/libgui/src/glinfo.cpp b/doomsday/libgui/src/glinfo.cpp index 917b2bc6cc..e571b8951a 100644 --- a/doomsday/libgui/src/glinfo.cpp +++ b/doomsday/libgui/src/glinfo.cpp @@ -30,25 +30,6 @@ namespace de { static GLInfo info; -#ifdef WIN32 -# define GL_CALL APIENTRY -#else -# define GL_CALL -#endif - -#ifdef GL_ARB_debug_output -static void GL_CALL glDebugOut(GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, GLchar const *message, GLvoid *userParam) -{ - DENG2_UNUSED(source); - DENG2_UNUSED(type); - DENG2_UNUSED(id); - DENG2_UNUSED(severity); - DENG2_UNUSED(userParam); - qWarning() << "[GL]" << String(message, length); -} -#endif - DENG2_PIMPL_NOREF(GLInfo) { bool inited; @@ -127,7 +108,6 @@ DENG2_PIMPL_NOREF(GLInfo) if(inited) return; // Extensions. - ext.ARB_debug_output = query("GL_ARB_debug_output"); ext.ARB_framebuffer_object = query("GL_ARB_framebuffer_object"); ext.ARB_texture_env_combine = query("GL_ARB_texture_env_combine") || query("GL_EXT_texture_env_combine"); ext.ARB_texture_non_power_of_two = query("GL_ARB_texture_non_power_of_two"); @@ -172,14 +152,6 @@ DENG2_PIMPL_NOREF(GLInfo) LOG_GL_NOTE("Using requested maximum texture size of %i x %i") << lim.maxTexSize << lim.maxTexSize; } - if(CommandLine_Exists("-gldebug")) - { -#ifdef GL_ARB_debug_output - /// @todo The GL context is not created with the debug output bit. -jk - glDebugMessageCallbackARB(glDebugOut, NULL); -#endif - } - inited = true; } }; From ec9cf0166b9fddb6eb4e774ce32b049a14a9943f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 13:13:41 +0200 Subject: [PATCH 14/60] Cleanup|qmake|64-bit: Preprocessor symbol for 64-bit builds Conforming to naming conventions. --- doomsday/config.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/config.pri b/doomsday/config.pri index 2ef90869bd..fea41631f0 100644 --- a/doomsday/config.pri +++ b/doomsday/config.pri @@ -91,7 +91,7 @@ greaterThan(QT_MAJOR_VERSION, 4) { # Check for a 64-bit compiler. contains(QMAKE_HOST.arch, x86_64) { echo(64-bit architecture detected.) - DEFINES += HOST_IS_64BIT + DEFINES += DENG_64BIT_HOST win32: CONFIG += win64 } From 5543f69972da8a8fceeb58e7a792a38b10666444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 16:43:52 +0200 Subject: [PATCH 15/60] qmake|libgui|Scripting: Moved gui.de to libgui gui.de directly relates to functionality in libgui, so it should be located in libgui's modules. Project files updates accordingly. client.pro still handles the installation of all Doomsday Script modules for the Doomsday client. --- doomsday/client/client.pro | 4 +- doomsday/client/modules/appconfig.de | 51 ++---------------- doomsday/config.pri | 15 +++--- doomsday/libdeng2/libdeng2.pro | 10 ++-- doomsday/libgui/libgui.pro | 9 +++- doomsday/{libdeng2 => libgui}/modules/gui.de | 54 +++++++++++++++++++- 6 files changed, 82 insertions(+), 61 deletions(-) rename doomsday/{libdeng2 => libgui}/modules/gui.de (52%) diff --git a/doomsday/client/client.pro b/doomsday/client/client.pro index 1df0e68461..4cab403c53 100644 --- a/doomsday/client/client.pro +++ b/doomsday/client/client.pro @@ -815,9 +815,9 @@ data.files = $$OUT_PWD/../doomsday.pk3 mod.files = \ $$DOOMSDAY_SCRIPTS \ $$DENG_MODULES_DIR/Config.de \ - $$DENG_MODULES_DIR/gui.de \ $$DENG_MODULES_DIR/Log.de \ - $$DENG_MODULES_DIR/recutil.de + $$DENG_MODULES_DIR/recutil.de \ + $$DENG_MODULES_DIR/../../libgui/modules/gui.de # These fonts may be needed during the initial startup busy mode. startupfonts.files = \ diff --git a/doomsday/client/modules/appconfig.de b/doomsday/client/modules/appconfig.de index bba0ec0c6d..d9ed41c62e 100644 --- a/doomsday/client/modules/appconfig.de +++ b/doomsday/client/modules/appconfig.de @@ -23,6 +23,7 @@ # # TODO: make sure the server doesn't run this +import gui import Version import Updater import Log @@ -30,6 +31,8 @@ import Log def setDefaults(d) # Applies the client's defaults. # - d: Record where to set the values. + + gui.setDefaults(d) # Additional Log defaults. d.log.filterBySubsystem = False @@ -47,52 +50,6 @@ def setDefaults(d) record d.input record d.input.mouse d.input.mouse.syncSensitivity = True - - try - import DisplayMode - - # The default audio and video subsystems. - d.video = 'opengl' - d.audio = 'fmod' - - # Window manager defaults. - record d.window - d.window.fsaa = True # Remove this (should be window-specific). - - # Configure the main window. - record d.window.main - d.window.main.showFps = False - d.window.main.center = True - d.window.main.fsaa = True - d.window.main.vsync = True - - # The default window parameters depend on the original display mode. - mode = DisplayMode.originalMode() - - # By default the fullscreen resolution is the desktop resolution. - d.window.main.fullSize = [mode['width'], mode['height']] - - # In windowed mode mode, leave some space on the sides so that - # the first switch to windowed mode does not place the window in an - # inconvenient location. The reduction is done proportionally. - offx = mode['width'] * 0.15 - offy = mode['height'] * 0.15 - d.window.main.rect = [offx, offy, - mode['width'] - 2*offx, - mode['height'] - 2*offy] - d.window.main.colorDepth = mode['depth'] - - if Version.OS == 'windows' or Version.OS == 'macx' - d.window.main.fullscreen = True - d.window.main.maximize = False - else - d.window.main.fullscreen = False - d.window.main.maximize = True - end - - catch NotFoundError - # DisplayMode isn't available on the server. - end # Defaults for the automatic updater. record d.updater @@ -114,5 +71,5 @@ def setDefaults(d) record d.console d.console.snap = True d.console.script = False +end - diff --git a/doomsday/config.pri b/doomsday/config.pri index fea41631f0..6fe2b9fe23 100644 --- a/doomsday/config.pri +++ b/doomsday/config.pri @@ -122,16 +122,19 @@ deng_nosdl { deng_sdk { # SDK install location. !isEmpty(SDK_PREFIX) { - DENG_SDK_HEADER_DIR = $$SDK_PREFIX/include/doomsday/de - DENG_SDK_LIB_DIR = $$SDK_PREFIX/lib + DENG_SDK_DIR = $$SDK_PREFIX + DENG_SDK_HEADER_DIR = $$DENG_SDK_DIR/include/doomsday/de + DENG_SDK_LIB_DIR = $$DENG_SDK_DIR/lib } else:!isEmpty(PREFIX) { - DENG_SDK_HEADER_DIR = $$PREFIX/include/doomsday/de - DENG_SDK_LIB_DIR = $$PREFIX/lib + DENG_SDK_DIR = $$PREFIX + DENG_SDK_HEADER_DIR = $$DENG_SDK_DIR/include/doomsday/de + DENG_SDK_LIB_DIR = $$DENG_SDK_DIR/lib } else { - DENG_SDK_HEADER_DIR = $$OUT_PWD/../include/de - DENG_SDK_LIB_DIR = $$OUT_PWD/../lib + DENG_SDK_DIR = $$OUT_PWD/.. + DENG_SDK_HEADER_DIR = $$DENG_SDK_DIR/include/de + DENG_SDK_LIB_DIR = $$DENG_SDK_DIR/lib } echo(SDK header directory: $$DENG_SDK_HEADER_DIR) echo(SDK library directory: $$DENG_SDK_LIB_DIR) diff --git a/doomsday/libdeng2/libdeng2.pro b/doomsday/libdeng2/libdeng2.pro index bcdd5dcda0..25bf2662d8 100644 --- a/doomsday/libdeng2/libdeng2.pro +++ b/doomsday/libdeng2/libdeng2.pro @@ -171,11 +171,14 @@ SOURCES += \ src/core/textstreamlogsink.cpp \ src/core/unixinfo.cpp -OTHER_FILES += \ +scripts.files = \ modules/Config.de \ - modules/gui.de \ + modules/Log.de \ modules/recutil.de +OTHER_FILES += \ + $$scripts.files + # Installation --------------------------------------------------------------- macx { @@ -199,6 +202,7 @@ macx { } deng_sdk { - INSTALLS *= target + INSTALLS *= target scripts target.path = $$DENG_SDK_LIB_DIR + scripts.path = $$DENG_SDK_DIR/modules } diff --git a/doomsday/libgui/libgui.pro b/doomsday/libgui/libgui.pro index 97c7589b25..0b37defaf3 100644 --- a/doomsday/libgui/libgui.pro +++ b/doomsday/libgui/libgui.pro @@ -173,6 +173,12 @@ else { unix:!macx: SOURCES += src/imKStoUCS_x11.c +scripts.files = \ + modules/gui.de + +OTHER_FILES += \ + $$scripts.files + # Installation --------------------------------------------------------------- macx { @@ -190,6 +196,7 @@ else { } deng_sdk { - INSTALLS *= target + INSTALLS *= target scripts target.path = $$DENG_SDK_LIB_DIR + scripts.path = $$DENG_SDK_DIR/modules } diff --git a/doomsday/libdeng2/modules/gui.de b/doomsday/libgui/modules/gui.de similarity index 52% rename from doomsday/libdeng2/modules/gui.de rename to doomsday/libgui/modules/gui.de index dc6c5b4d6b..d20e02ba0e 100644 --- a/doomsday/libdeng2/modules/gui.de +++ b/doomsday/libgui/modules/gui.de @@ -1,6 +1,6 @@ -# The Doomsday Engine Project -- libdeng2 +# The Doomsday Engine Project # -# Copyright (c) 2013 Jaakko Keränen +# Copyright (c) 2013-2014 Jaakko Keränen # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by @@ -18,6 +18,56 @@ #---------------------------------------------------------------------------- # Graphical user interface +def setDefaults(d) + # Applies the default configuration settings. + # - d: Record where to set the values. + try + import DisplayMode + + # The default audio and video subsystems. + d.video = 'opengl' + d.audio = 'fmod' + + # Window manager defaults. + record d.window + d.window.fsaa = True # Remove this (should be window-specific). + + # Configure the main window. + record d.window.main + d.window.main.showFps = False + d.window.main.center = True + d.window.main.fsaa = True + d.window.main.vsync = True + + # The default window parameters depend on the original display mode. + mode = DisplayMode.originalMode() + + # By default the fullscreen resolution is the desktop resolution. + d.window.main.fullSize = [mode['width'], mode['height']] + + # In windowed mode mode, leave some space on the sides so that + # the first switch to windowed mode does not place the window in an + # inconvenient location. The reduction is done proportionally. + offx = mode['width'] * 0.15 + offy = mode['height'] * 0.15 + d.window.main.rect = [offx, offy, + mode['width'] - 2*offx, + mode['height'] - 2*offy] + d.window.main.colorDepth = mode['depth'] + + if Version.OS == 'windows' or Version.OS == 'macx' + d.window.main.fullscreen = True + d.window.main.maximize = False + else + d.window.main.fullscreen = False + d.window.main.maximize = True + end + + catch NotFoundError + # DisplayMode isn't available on the server. + end +end + def scale(value, factor) # Scales a value by 'factor'. If 'value' is a text string, the # suffixes "pt" and "px" (point, pixel) are retained in the result. From 80726a27a6b44b82145dd49be51c7027a0336a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 16:45:58 +0200 Subject: [PATCH 16/60] SDK: Added a .pri files for apps using the SDK doomsday_sdk.pri is installed to the SDK directory. --- doomsday/doomsday_sdk.pri | 55 +++++++++++++++++++++++++++++++++++++++ doomsday/sdk.pro | 6 +++++ 2 files changed, 61 insertions(+) create mode 100644 doomsday/doomsday_sdk.pri diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri new file mode 100644 index 0000000000..f20301e366 --- /dev/null +++ b/doomsday/doomsday_sdk.pri @@ -0,0 +1,55 @@ +# The Doomsday Engine Project +# Copyright (c) 2014 Jaakko Keränen +# +# qmake .pri file for projects using the Doomsday SDK. +# +# The Doomsday SDK is distributed under the GNU Lesser General Public +# License version 3 (or, at your option, any later version). Please +# visit http://www.gnu.org/licenses/lgpl.html for details. +# +# Variables: +# - DENG_CONFIG Names of supporting libraries to use (gui, appfw, shell) + +DENG_SDK_DIR = $$PWD + +exists($$DENG_SDK_DIR/include/doomsday) { + INCLUDEPATH += $$DENG_SDK_DIR/include/doomsday +} +else { + INCLUDEPATH += $$DENG_SDK_DIR/include +} + +LIBS += -L$$DENG_SDK_DIR/lib + +# The core library is always required. +LIBS += -ldeng2 + +# Supporting libraries are optional. +contains(DENG_CONFIG, gui): LIBS += -ldeng_gui +contains(DENG_CONFIG, appfw): LIBS += -ldeng_appfw +contains(DENG_CONFIG, shell): LIBS += -ldeng_shell + +# Instruct the dynamic linker to load the libs from the SDK lib dir. +*-g++*|*-gcc*|*-clang* { + QMAKE_LFLAGS += -Wl,-rpath,$$DENG_SDK_DIR/lib +} + +defineTest(dengClear) { + # 1: file to remove + win32: system(del /q \"$$1\") + else: system(rm -f \"$$1\") +} + +defineTest(dengPack) { + # 1: path of a .pack file + # 2: actual root directory + # 3: files to include, relative to the root + system(cd \"$$2\" && zip -r \"$$1\" $$3) +} + +DENG_MODULES = $$DENG_SDK_DIR/modules/*.de + +defineTest(dengPackModules) { + # 1: path of a .pack file + dengPack($$1, $$DENG_SDK_DIR, modules/*.de) +} diff --git a/doomsday/sdk.pro b/doomsday/sdk.pro index 48e16f98da..e45315ce23 100644 --- a/doomsday/sdk.pro +++ b/doomsday/sdk.pro @@ -26,3 +26,9 @@ SUBDIRS += \ #SUBDIRS += postbuild +OTHER_FILES += doomsday_sdk.pri + +# Install the main .pri file of the SDK. +INSTALLS += sdk_pri +sdk_pri.files = doomsday_sdk.pri +sdk_pri.path = $$DENG_SDK_DIR From 7253c8eef8289f439ba330d1fd61475b406d4488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 16:46:23 +0200 Subject: [PATCH 17/60] Fixed|libdeng2|SDK|qmake: Missing public header --- doomsday/libdeng2/data.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/doomsday/libdeng2/data.pri b/doomsday/libdeng2/data.pri index 7fcc666a7d..993d225502 100644 --- a/doomsday/libdeng2/data.pri +++ b/doomsday/libdeng2/data.pri @@ -32,6 +32,7 @@ publicHeaders(root, \ include/de/LittleEndianByteOrder \ include/de/NoneValue \ include/de/NumberValue \ + include/de/Observers \ include/de/Path \ include/de/PathTree \ include/de/Property \ From 52ee22cf561341252a4671d00564736ec905afd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 16:47:25 +0200 Subject: [PATCH 18/60] libdeng2|Unix: Expand paths specified in UnixInfo config Any symbols like "~" found in the paths of UnixInfo config files are automatically expanded. --- doomsday/libdeng2/include/de/core/unixinfo.h | 3 ++- doomsday/libdeng2/src/core/unixinfo.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doomsday/libdeng2/include/de/core/unixinfo.h b/doomsday/libdeng2/include/de/core/unixinfo.h index d4b21b0407..183e074760 100644 --- a/doomsday/libdeng2/include/de/core/unixinfo.h +++ b/doomsday/libdeng2/include/de/core/unixinfo.h @@ -53,7 +53,8 @@ class UnixInfo UnixInfo(); /** - * Returns a path preference. + * Returns a path preference. Any symbols in the path (e.g., ~) are expanded + * before the value is returned. * * @param key Path identifier. * @param value The value is returned here. diff --git a/doomsday/libdeng2/src/core/unixinfo.cpp b/doomsday/libdeng2/src/core/unixinfo.cpp index 28905632b1..8866d86202 100644 --- a/doomsday/libdeng2/src/core/unixinfo.cpp +++ b/doomsday/libdeng2/src/core/unixinfo.cpp @@ -110,7 +110,7 @@ bool UnixInfo::path(String const &key, NativePath &value) const String s; if(d->paths->find(key, s)) { - value = s; + value = NativePath(s).expand(); return true; } } From f63db80379af831f249693f20a9f6ecabf496823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 17:11:21 +0200 Subject: [PATCH 19/60] libdeng2|App: Using a .pack as basedir; configurable config path This commit adds flexibility to App. It is now possible to point the application's basedir to a pack file, so that the contents of the pack are used to feed the App's root folder. In this case, the usual /data and /modules are expected to be found inside the pack. Also, one can now specify a different path where Config reads its script from (defaults to "/modules/Config.de" as before). --- doomsday/libdeng2/include/de/core/app.h | 12 ++++ .../libdeng2/include/de/data/ziparchive.h | 13 +++- doomsday/libdeng2/src/core/app.cpp | 63 ++++++++++++++----- doomsday/libdeng2/src/data/ziparchive.cpp | 15 ++++- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/doomsday/libdeng2/include/de/core/app.h b/doomsday/libdeng2/include/de/core/app.h index 2db4bd8f1c..23afcb6f7a 100644 --- a/doomsday/libdeng2/include/de/core/app.h +++ b/doomsday/libdeng2/include/de/core/app.h @@ -106,6 +106,18 @@ class DENG2_PUBLIC App : DENG2_OBSERVES(Clock, TimeChange) virtual void setMetadata(String const &orgName, String const &orgDomain, String const &appName, String const &appVersion) = 0; + /** + * Sets the path of the configuration script that will be automatically run if needed + * during application launch. The script governs the contents of the special + * persistent Config module. @see Config + * + * This method must be called before initSubsystems(). + * + * @param path Location of the @em Config.de script file. The default path of the + * script is "/modules/Config.de". + */ + void setConfigScript(Path const &path); + /** * Sets the Unix-style home folder name. For instance, ".doomsday" could be used. * diff --git a/doomsday/libdeng2/include/de/data/ziparchive.h b/doomsday/libdeng2/include/de/data/ziparchive.h index 784dee14c6..8afc98e132 100644 --- a/doomsday/libdeng2/include/de/data/ziparchive.h +++ b/doomsday/libdeng2/include/de/data/ziparchive.h @@ -21,6 +21,7 @@ #define LIBDENG2_ZIPARCHIVE_H #include "../Archive" +#include "../NativePath" namespace de { @@ -80,8 +81,7 @@ class DENG2_PUBLIC ZipArchive : public Archive public: /** - * Determines whether a File looks like it could be accessed using - * ZipArchive. + * Determines whether a File looks like it could be accessed using ZipArchive. * * @param file File to check. * @@ -89,6 +89,15 @@ class DENG2_PUBLIC ZipArchive : public Archive */ static bool recognize(File const &file); + /** + * Determines whether a native file looks like it could be in ZIP format. + * + * @param path Native path of the file to check. + * + * @return @c true, if the file looks like an archive. + */ + static bool recognize(NativePath const &path); + protected: void readFromSource(Entry const &entry, Path const &path, IBlock &uncompressedData) const; diff --git a/doomsday/libdeng2/src/core/app.cpp b/doomsday/libdeng2/src/core/app.cpp index de1a3a9b0b..9dd1146b7d 100644 --- a/doomsday/libdeng2/src/core/app.cpp +++ b/doomsday/libdeng2/src/core/app.cpp @@ -28,6 +28,7 @@ #include "de/LogBuffer" #include "de/LogFilter" #include "de/Module" +#include "de/NativeFile" #include "de/NumberValue" #include "de/PackageFolder" #include "de/Record" @@ -70,6 +71,7 @@ DENG2_PIMPL(App) QList systems; FileSystem fs; + QScopedPointer basePackFile; ScriptSystem scriptSys; Record appModule; @@ -80,6 +82,7 @@ DENG2_PIMPL(App) QScopedPointer unixInfo; /// The configuration. + Path configPath; Config *config; game::Game *currentGame; @@ -108,6 +111,7 @@ DENG2_PIMPL(App) , cmdLine(args) , unixHomeFolder(".doomsday") , persistentData(0) + , configPath("/modules/Config.de") , config(0) , currentGame(0) , terminateFunc(0) @@ -135,12 +139,16 @@ DENG2_PIMPL(App) { clock.audienceForTimeChange -= self; - // Update the log filter in the persistent configuration. - Record *filter = new Record; - logFilter.write(*filter); - config->names().add("log.filter", filter); + if(config) + { + // Update the log filter in the persistent configuration. + Record *filter = new Record; + logFilter.write(*filter); + config->names().add("log.filter", filter); + + delete config; + } - delete config; Clock::setAppClock(0); } @@ -151,21 +159,34 @@ DENG2_PIMPL(App) // Initialize the built-in folders. This hooks up the default native // directories into the appropriate places in the file system. // All of these are in read-only mode. + + if(ZipArchive::recognize(self.nativeBasePath())) + { + // As a special case, if the base path points to a resource pack, + // use the contents of the pack as the root of the file system. + // The pack itself does not appear in the file system. + basePackFile.reset(new NativeFile(self.nativeBasePath().fileName(), self.nativeBasePath())); + basePackFile->setStatus(DirectoryFeed::fileStatus(self.nativeBasePath())); + fs.root().attach(new ArchiveFeed(*basePackFile)); + } + else + { #ifdef MACOSX - NativePath appDir = appPath.fileNamePath(); - binFolder.attach(new DirectoryFeed(appDir)); - fs.makeFolder("/data").attach(new DirectoryFeed(self.nativeBasePath())); - fs.makeFolder("/modules").attach(new DirectoryFeed(self.nativeBasePath() / "modules")); + NativePath appDir = appPath.fileNamePath(); + binFolder.attach(new DirectoryFeed(appDir)); + fs.makeFolder("/data").attach(new DirectoryFeed(self.nativeBasePath())); + fs.makeFolder("/modules").attach(new DirectoryFeed(self.nativeBasePath() / "modules")); #elif WIN32 - NativePath appDir = appPath.fileNamePath(); - fs.makeFolder("/data").attach(new DirectoryFeed(appDir / "..\\data")); - fs.makeFolder("/modules").attach(new DirectoryFeed(appDir / "..\\modules")); + NativePath appDir = appPath.fileNamePath(); + fs.makeFolder("/data").attach(new DirectoryFeed(appDir / "..\\data")); + fs.makeFolder("/modules").attach(new DirectoryFeed(appDir / "..\\modules")); #else // UNIX - fs.makeFolder("/data").attach(new DirectoryFeed(self.nativeBasePath() / "data")); - fs.makeFolder("/modules").attach(new DirectoryFeed(self.nativeBasePath() / "modules")); + fs.makeFolder("/data").attach(new DirectoryFeed(self.nativeBasePath() / "data")); + fs.makeFolder("/modules").attach(new DirectoryFeed(self.nativeBasePath() / "modules")); #endif + } if(allowPlugins) { @@ -173,8 +194,8 @@ DENG2_PIMPL(App) } // User's home folder. - fs.makeFolder("/home").attach(new DirectoryFeed(self.nativeHomePath(), - DirectoryFeed::AllowWrite | DirectoryFeed::CreateIfMissing)); + fs.makeFolder("/home", FS::DontInheritFeeds).attach(new DirectoryFeed(self.nativeHomePath(), + DirectoryFeed::AllowWrite | DirectoryFeed::CreateIfMissing)); // Populate the file system. fs.refresh(); @@ -271,9 +292,17 @@ App::~App() singletonApp = 0; } +void App::setConfigScript(Path const &path) +{ + d->configPath = path; +} + void App::setUnixHomeFolderName(String const &name) { d->unixHomeFolder = name; + + // Reload Unix config files. + d->unixInfo.reset(new UnixInfo); } String App::unixHomeFolderName() const @@ -452,7 +481,7 @@ void App::initSubsystems(SubsystemInitFlags flags) d->persistentData = &homeFolder().locate("persist.pack").archive(); // The configuration. - d->config = new Config("/modules/Config.de"); + d->config = new Config(d->configPath); d->scriptSys.addNativeModule("Config", d->config->names()); d->config->read(); diff --git a/doomsday/libdeng2/src/data/ziparchive.cpp b/doomsday/libdeng2/src/data/ziparchive.cpp index 270bca8d9f..0af8b4e531 100644 --- a/doomsday/libdeng2/src/data/ziparchive.cpp +++ b/doomsday/libdeng2/src/data/ziparchive.cpp @@ -606,14 +606,23 @@ void ZipArchive::operator >> (Writer &to) const to.seek(writer.offset()); } -bool ZipArchive::recognize(File const &file) +static bool recognizeZipExtension(String const &ext) { - // For now, just check the name. - String ext = file.name().fileNameExtension().lower(); return (ext == ".pack" || ext == ".demo" || ext == ".save" || ext == ".addon" || ext == ".box" || ext == ".pk3" || ext == ".zip"); } +bool ZipArchive::recognize(File const &file) +{ + // For now, just check the name. + return recognizeZipExtension(file.name().fileNameExtension().lower()); +} + +bool ZipArchive::recognize(NativePath const &path) +{ + return recognizeZipExtension(path.toString().fileNameExtension().lower()); +} + void ZipArchive::ZipEntry::update() { if(data) From 7bf20d39b67ea9fe5f45301e7ad3f62277b180a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Wed, 26 Feb 2014 17:11:48 +0200 Subject: [PATCH 20/60] libdeng2|Cleanup: More information in error messages --- doomsday/libdeng2/src/core/config.cpp | 7 ++++++- doomsday/libdeng2/src/data/block.cpp | 3 ++- doomsday/libdeng2/src/filesys/nativefile.cpp | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doomsday/libdeng2/src/core/config.cpp b/doomsday/libdeng2/src/core/config.cpp index bc1e4f1422..a6e0b20d4e 100644 --- a/doomsday/libdeng2/src/core/config.cpp +++ b/doomsday/libdeng2/src/core/config.cpp @@ -112,7 +112,7 @@ void Config::read() // If script is newer, it should be rerun. if(scriptFile.status().modifiedAt > d->refuge.lastWrittenAt()) { - LOG_MSG("%s is newer than %s, rerunning the script.") + LOG_MSG("%s is newer than %s, rerunning the script") << d->configPath << d->refuge.path(); shouldRunScript = true; } @@ -122,6 +122,11 @@ void Config::read() // It is missing from persist.pack if the config hasn't been written yet. shouldRunScript = true; } + catch(IByteArray::OffsetError const &) + { + // Empty or missing serialization? + shouldRunScript = true; + } catch(Error const &error) { LOG_WARNING(error.what()); diff --git a/doomsday/libdeng2/src/data/block.cpp b/doomsday/libdeng2/src/data/block.cpp index 8bfe8145b5..39c667b423 100644 --- a/doomsday/libdeng2/src/data/block.cpp +++ b/doomsday/libdeng2/src/data/block.cpp @@ -75,7 +75,8 @@ void Block::get(Offset atPos, Byte *values, Size count) const if(atPos + count > size()) { /// @throw OffsetError The accessed region of the block was out of range. - throw OffsetError("Block::get", "Out of range"); + throw OffsetError("Block::get", "Out of range " + + String("(%1[+%2] > %3)").arg(atPos).arg(count).arg(size())); } for(Offset i = atPos; count > 0; ++i, --count) diff --git a/doomsday/libdeng2/src/filesys/nativefile.cpp b/doomsday/libdeng2/src/filesys/nativefile.cpp index de5baa25a6..7567cbdadd 100644 --- a/doomsday/libdeng2/src/filesys/nativefile.cpp +++ b/doomsday/libdeng2/src/filesys/nativefile.cpp @@ -98,7 +98,8 @@ void NativeFile::get(Offset at, Byte *values, Size count) const { /// @throw IByteArray::OffsetError The region specified for reading extends /// beyond the bounds of the file. - throw OffsetError("NativeFile::get", "Cannot read past end of file"); + throw OffsetError("NativeFile::get", description() + ": cannot read past end of file " + + String("(%1[+%2] > %3)").arg(at).arg(count).arg(size())); } in.seek(at); in.read(reinterpret_cast(values), count); From a55a478d1c1621e97a2e3b83cb5ddf24b5ed9821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:01:34 +0200 Subject: [PATCH 21/60] qmake|SDK: Determining install location of libraries Added a macro for figuring out what is the appropriate Unix library directory. --- doomsday/config.pri | 38 +++++++++++++++++++------------------- doomsday/config_unix.pri | 16 +++------------- doomsday/macros.pri | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/doomsday/config.pri b/doomsday/config.pri index 6fe2b9fe23..3dfb07510a 100644 --- a/doomsday/config.pri +++ b/doomsday/config.pri @@ -100,25 +100,6 @@ isStableRelease(): DEFINES += DENG_STABLE # Options defined by the user (may not exist). exists(config_user.pri): include(config_user.pri) - win32: include(config_win32.pri) -else:macx: include(config_macx.pri) - else: include(config_unix.pri) - -# Apply deng_* Configuration ------------------------------------------------- - -deng_nofixedasm { - DEFINES += DENG_NO_FIXED_ASM -} -!deng_rangecheck { - DEFINES += DENG_NO_RANGECHECKING -} -deng_nosdlmixer|deng_nosdl { - DEFINES += DENG_DISABLE_SDLMIXER -} -deng_nosdl { - DEFINES += DENG_NO_SDL -} - deng_sdk { # SDK install location. !isEmpty(SDK_PREFIX) { @@ -140,6 +121,25 @@ deng_sdk { echo(SDK library directory: $$DENG_SDK_LIB_DIR) } + win32: include(config_win32.pri) +else:macx: include(config_macx.pri) + else: include(config_unix.pri) + +# Apply deng_* Configuration ------------------------------------------------- + +deng_nofixedasm { + DEFINES += DENG_NO_FIXED_ASM +} +!deng_rangecheck { + DEFINES += DENG_NO_RANGECHECKING +} +deng_nosdlmixer|deng_nosdl { + DEFINES += DENG_DISABLE_SDLMIXER +} +deng_nosdl { + DEFINES += DENG_NO_SDL +} + unix:deng_ccache { # ccache can be used to speed up recompilation. *-clang* { diff --git a/doomsday/config_unix.pri b/doomsday/config_unix.pri index 3ba5eb2c1c..485c01a52d 100644 --- a/doomsday/config_unix.pri +++ b/doomsday/config_unix.pri @@ -30,16 +30,8 @@ DENG_BIN_DIR = $$PREFIX/bin # Library location. isEmpty(DENG_LIB_DIR) { - DENG_LIB_DIR = $$PREFIX/lib - - contains(QMAKE_HOST.arch, x86_64) { - exists($$PREFIX/lib64) { - DENG_LIB_DIR = $$PREFIX/lib64 - } - exists($$PREFIX/lib/x86_64-linux-gnu) { - DENG_LIB_DIR = $$PREFIX/lib/x86_64-linux-gnu - } - } + deng_sdk: DENG_LIB_DIR = $$findLibDir($$DENG_SDK_DIR) + else: DENG_LIB_DIR = $$findLibDir($$PREFIX) } # Target location for plugin libraries. @@ -47,9 +39,7 @@ DENG_PLUGIN_LIB_DIR = $$DENG_LIB_DIR/doomsday # When installing libraries to a non-standard location, instruct # the linker where to find them. -!contains(DENG_LIB_DIR, ^/usr/.*) { - QMAKE_LFLAGS += -Wl,-rpath,$$DENG_LIB_DIR -} +!contains(DENG_LIB_DIR, ^/usr/.*): QMAKE_LFLAGS += -Wl,-rpath,$$DENG_LIB_DIR DENG_BASE_DIR = $$PREFIX/share/doomsday DENG_DATA_DIR = $$DENG_BASE_DIR/data diff --git a/doomsday/macros.pri b/doomsday/macros.pri index 744d740387..00cb8301a2 100644 --- a/doomsday/macros.pri +++ b/doomsday/macros.pri @@ -24,6 +24,21 @@ defineTest(echo) { } } +defineReplace(findLibDir) { + # Determines the appropriate library directory given prefix $$1 + prefix = $$1 + dir = $$prefix/lib + contains(QMAKE_HOST.arch, x86_64) { + exists($$prefix/lib64) { + dir = $$prefix/lib64 + } + exists($$prefix/lib/x86_64-linux-gnu) { + dir = $$prefix/lib/x86_64-linux-gnu + } + } + return($$dir) +} + defineTest(useLibDir) { btype = "" win32 { From 33b1cf24e4b43aa1e6263ca9a9873f8f56f22e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:01:51 +0200 Subject: [PATCH 22/60] Fixed|qmake|SDK: libdeng1 is not part of the SDK --- doomsday/sdk.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/doomsday/sdk.pro b/doomsday/sdk.pro index e45315ce23..b6e723a5a1 100644 --- a/doomsday/sdk.pro +++ b/doomsday/sdk.pro @@ -12,7 +12,6 @@ CONFIG += ordered SUBDIRS = \ build \ libdeng2 \ - libdeng1 \ libshell !deng_noclient|macx { From 0cf331243b623c7951729dc9ce1091ee7d8e7a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:02:31 +0200 Subject: [PATCH 23/60] SDK|qmake: Added an app deployment macro dengDeploy() can be used to easily deploy an application using the SDK. --- doomsday/doomsday_sdk.pri | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index f20301e366..6e2635d7af 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -53,3 +53,57 @@ defineTest(dengPackModules) { # 1: path of a .pack file dengPack($$1, $$DENG_SDK_DIR, modules/*.de) } + +defineReplace(dengFindLibDir) { + # Determines the appropriate library directory given prefix $$1 + prefix = $$1 + dir = $$prefix/lib + contains(QMAKE_HOST.arch, x86_64) { + exists($$prefix/lib64) { + dir = $$prefix/lib64 + } + exists($$prefix/lib/x86_64-linux-gnu) { + dir = $$prefix/lib/x86_64-linux-gnu + } + } + return($$dir) +} + +defineTest(dengDeploy) { + # 1: app name + # 2: install prefix + # 3: base pack file + prefix = $$2 + INSTALLS += target basepack + basepack.files = $$3 + contains(DENG_CONFIG, gui): INSTALLS += libgui + contains(DENG_CONFIG, appfw): INSTALLS += libappfw + contains(DENG_CONFIG, shell): INSTALLS += libshell + win32 { + } + else:macx { + } + else { + target.path = $$prefix/bin + basepack.path = $$prefix/share/$${1} + + libgui.files = $$DENG_SDK_DIR/lib/libdeng_gui.so + libappfw.files = $$DENG_SDK_DIR/lib/libdeng_appfw.so + libshell.files = $$DENG_SDK_DIR/lib/libdeng_shell.so + + libDir = $$dengFindLibDir($$prefix) + libgui.path = $$libDir + libappfw.path = $$libDir + libshell.path = $$libDir + } + export(INSTALLS) + export(target.path) + export(basepack.files) + export(basepack.path) + export(libgui.files) + export(libgui.path) + export(libappfw.files) + export(libappfw.path) + export(libshell.files) + export(libshell.path) +} From aa0424182499b6bbff3c7659d51a41daf2d79992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:43:54 +0200 Subject: [PATCH 24/60] SDK|Cleanup: Deploying SDK libraries --- doomsday/doomsday_sdk.pri | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index 6e2635d7af..4b0872cc01 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -24,6 +24,8 @@ LIBS += -L$$DENG_SDK_DIR/lib # The core library is always required. LIBS += -ldeng2 +contains(DENG_CONFIG, appfw): DENG_CONFIG *= gui shell + # Supporting libraries are optional. contains(DENG_CONFIG, gui): LIBS += -ldeng_gui contains(DENG_CONFIG, appfw): LIBS += -ldeng_appfw @@ -69,41 +71,46 @@ defineReplace(dengFindLibDir) { return($$dir) } +defineReplace(findSdkLib) { + # 1: name of library + win32: fn = $$DENG_SDK_DIR/lib/$${1}.dll + else:macx: fn = $$DENG_SDK_DIR/lib/lib$${1}.dylib + else { + fn = $$DENG_SDK_DIR/lib/lib$${1}.so + # Apply the latest major version. + exists($${fn}.2): fn = $${fn}.2 + else:exists($${fn}.1): fn = $${fn}.1 + else:exists($${fn}.0): fn = $${fn}.0 + } + return($$fn) +} + defineTest(dengDeploy) { # 1: app name # 2: install prefix # 3: base pack file prefix = $$2 - INSTALLS += target basepack + INSTALLS += target basepack denglibs basepack.files = $$3 - contains(DENG_CONFIG, gui): INSTALLS += libgui - contains(DENG_CONFIG, appfw): INSTALLS += libappfw - contains(DENG_CONFIG, shell): INSTALLS += libshell + + denglibs.files = $$findSdkLib(deng2) + contains(DENG_CONFIG, gui): denglibs.files += $$findSdkLib(deng_gui) + contains(DENG_CONFIG, appfw): denglibs.files += $$findSdkLib(deng_appfw) + contains(DENG_CONFIG, shell): denglibs.files += $$findSdkLib(deng_shell) + win32 { } else:macx { } else { - target.path = $$prefix/bin + target.path = $$prefix/bin basepack.path = $$prefix/share/$${1} - - libgui.files = $$DENG_SDK_DIR/lib/libdeng_gui.so - libappfw.files = $$DENG_SDK_DIR/lib/libdeng_appfw.so - libshell.files = $$DENG_SDK_DIR/lib/libdeng_shell.so - - libDir = $$dengFindLibDir($$prefix) - libgui.path = $$libDir - libappfw.path = $$libDir - libshell.path = $$libDir + denglibs.path = $$dengFindLibDir($$prefix) } export(INSTALLS) export(target.path) export(basepack.files) export(basepack.path) - export(libgui.files) - export(libgui.path) - export(libappfw.files) - export(libappfw.path) - export(libshell.files) - export(libshell.path) + export(denglibs.files) + export(denglibs.path) } From c48300aed092395cf573bf7e5864866e1428547d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:46:36 +0200 Subject: [PATCH 25/60] Cleanup --- doomsday/doomsday_sdk.pri | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index 4b0872cc01..6898a78e80 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -71,7 +71,7 @@ defineReplace(dengFindLibDir) { return($$dir) } -defineReplace(findSdkLib) { +defineReplace(dengSdkLib) { # 1: name of library win32: fn = $$DENG_SDK_DIR/lib/$${1}.dll else:macx: fn = $$DENG_SDK_DIR/lib/lib$${1}.dylib @@ -93,10 +93,10 @@ defineTest(dengDeploy) { INSTALLS += target basepack denglibs basepack.files = $$3 - denglibs.files = $$findSdkLib(deng2) - contains(DENG_CONFIG, gui): denglibs.files += $$findSdkLib(deng_gui) - contains(DENG_CONFIG, appfw): denglibs.files += $$findSdkLib(deng_appfw) - contains(DENG_CONFIG, shell): denglibs.files += $$findSdkLib(deng_shell) + denglibs.files = $$dengSdkLib(deng2) + contains(DENG_CONFIG, gui): denglibs.files += $$dengSdkLib(deng_gui) + contains(DENG_CONFIG, appfw): denglibs.files += $$dengSdkLib(deng_appfw) + contains(DENG_CONFIG, shell): denglibs.files += $$dengSdkLib(deng_shell) win32 { } From 355e5782e51dc134c9a3b1da5522d8c54fcaacfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 16:53:46 +0200 Subject: [PATCH 26/60] libdeng2|Refuge: Adjust log output level --- doomsday/libdeng2/src/data/refuge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doomsday/libdeng2/src/data/refuge.cpp b/doomsday/libdeng2/src/data/refuge.cpp index 94ff7a1ab4..5098724dc4 100644 --- a/doomsday/libdeng2/src/data/refuge.cpp +++ b/doomsday/libdeng2/src/data/refuge.cpp @@ -41,7 +41,7 @@ Refuge::Refuge(String const &persistentPath) : d(new Instance) catch(Error const &er) { LOG_AS("Refuge"); - LOG_RES_VERBOSE("\"%s\" could not be read: %s") << persistentPath << er.asText(); + LOGDEV_RES_MSG("\"%s\" could not be read: %s") << persistentPath << er.asText(); } } From a4abd020d242edf10a1f0e49de67adaa208f7cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 18:10:59 +0200 Subject: [PATCH 27/60] Fixed|libgui: Missing import in gui module --- doomsday/libgui/modules/gui.de | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doomsday/libgui/modules/gui.de b/doomsday/libgui/modules/gui.de index d20e02ba0e..b53792227d 100644 --- a/doomsday/libgui/modules/gui.de +++ b/doomsday/libgui/modules/gui.de @@ -18,6 +18,8 @@ #---------------------------------------------------------------------------- # Graphical user interface +import Version + def setDefaults(d) # Applies the default configuration settings. # - d: Record where to set the values. @@ -62,7 +64,7 @@ def setDefaults(d) d.window.main.fullscreen = False d.window.main.maximize = True end - + catch NotFoundError # DisplayMode isn't available on the server. end From 51526df48e292082c8f77294708d66e1f1a0b9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 18:11:20 +0200 Subject: [PATCH 28/60] Fixed|SDK: Missing public header files --- doomsday/libappfw/libappfw.pro | 1 + doomsday/libdeng2/widgets.pri | 1 + 2 files changed, 2 insertions(+) diff --git a/doomsday/libappfw/libappfw.pro b/doomsday/libappfw/libappfw.pro index 56f16763ea..cc528540c6 100644 --- a/doomsday/libappfw/libappfw.pro +++ b/doomsday/libappfw/libappfw.pro @@ -70,6 +70,7 @@ publicHeaders(root, \ include/de/SequentialLayout \ include/de/SignalAction \ include/de/SliderWidget \ + include/de/Style \ include/de/TabWidget \ include/de/TextDrawable \ include/de/ToggleWidget \ diff --git a/doomsday/libdeng2/widgets.pri b/doomsday/libdeng2/widgets.pri index 41b7c2a134..03cba00184 100644 --- a/doomsday/libdeng2/widgets.pri +++ b/doomsday/libdeng2/widgets.pri @@ -5,6 +5,7 @@ publicHeaders(root, \ include/de/ConstantRule \ include/de/IndirectRule \ include/de/OperatorRule \ + include/de/Rule \ include/de/RuleBank \ include/de/RuleRectangle \ include/de/RootWidget \ From ca26424cfdfb4ae234a74b1c843b4a3ffe980c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Thu, 27 Feb 2014 18:12:56 +0200 Subject: [PATCH 29/60] libdeng2|FS: ArchiveFeed observes source file for deletion If the source file is deleted, any changes to the archive are first saved. --- doomsday/libdeng2/src/filesys/archivefeed.cpp | 78 +++++++++++++------ 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/doomsday/libdeng2/src/filesys/archivefeed.cpp b/doomsday/libdeng2/src/filesys/archivefeed.cpp index 5757ae626a..ded3d3e066 100644 --- a/doomsday/libdeng2/src/filesys/archivefeed.cpp +++ b/doomsday/libdeng2/src/filesys/archivefeed.cpp @@ -29,9 +29,10 @@ namespace de { DENG2_PIMPL(ArchiveFeed) +, DENG2_OBSERVES(File, Deletion) { /// File where the archive is stored (in a serialized format). - File &file; + File *file; /// The archive can be physically stored here, as Archive doesn't make a /// copy of the buffer. @@ -45,9 +46,9 @@ DENG2_PIMPL(ArchiveFeed) /// The feed whose archive this feed is using. ArchiveFeed *parentFeed; - Instance(Public *feed, File &f) : Base(feed), file(f), arch(0), parentFeed(0) + Instance(Public *feed, File &f) : Base(feed), file(&f), arch(0), parentFeed(0) { - /// @todo Observe the file for deletion. + file->audienceForDeletion += this; // If the file happens to be a byte array file, we can use it // directly to store the Archive. @@ -73,29 +74,53 @@ DENG2_PIMPL(ArchiveFeed) Instance(Public *feed, ArchiveFeed &parentFeed, String const &path) : Base(feed), file(parentFeed.d->file), arch(0), basePath(path), parentFeed(&parentFeed) - {} + { + file->audienceForDeletion += this; + } ~Instance() { + if(file) + { + file->audienceForDeletion -= this; + } + if(arch) { - // If modified, the archive is written back to the file. - if(arch->modified()) - { - LOG_RES_MSG("Updating archive in ") << file.description(); + writeIfModified(); + delete arch; + } + } - // Make sure we have either a compressed or uncompressed version of - // each entry in memory before destroying the source file. - arch->cache(); + void writeIfModified() + { + if(!file || !arch) return; - file.clear(); - Writer(file) << *arch; - } - else - { - LOG_RES_VERBOSE("Not updating archive in %s (not changed)") << file.description(); - } - delete arch; + // If modified, the archive is written back to the file. + if(arch->modified()) + { + LOG_RES_MSG("Updating archive in ") << file->description(); + + // Make sure we have either a compressed or uncompressed version of + // each entry in memory before destroying the source file. + arch->cache(); + + file->clear(); + Writer(*file) << *arch; + } + else + { + LOG_RES_VERBOSE("Not updating archive in %s (not changed)") << file->description(); + } + } + + void fileBeingDeleted(File const &deleted) + { + if(file == &deleted) + { + // Ensure that changes are saved and detach from the file. + writeIfModified(); + file = 0; } } @@ -125,18 +150,19 @@ DENG2_PIMPL(ArchiveFeed) String entry = basePath / *i; std::auto_ptr archFile(new ArchiveEntryFile(*i, archive(), entry)); + // Use the status of the entry within the archive. archFile->setStatus(archive().entryStatus(entry)); // Create a new file that accesses this feed's archive and interpret the contents. - File *file = folder.fileSystem().interpret(archFile.release()); - folder.add(file); + File *f = folder.fileSystem().interpret(archFile.release()); + folder.add(f); // We will decide on pruning this. - file->setOriginFeed(&self); + f->setOriginFeed(&self); // Include the file in the main index. - folder.fileSystem().index(*file); + folder.fileSystem().index(*f); } // Also populate subfolders. @@ -165,7 +191,11 @@ ArchiveFeed::~ArchiveFeed() String ArchiveFeed::description() const { - return "archive in " + d->file.description(); + if(d->file) + { + return "archive in " + d->file->description(); + } + return "archive in (no file)"; } void ArchiveFeed::populate(Folder &folder) From 29ed7230f301e51e9088184139d20e95ec52ace6 Mon Sep 17 00:00:00 2001 From: danij Date: Fri, 28 Feb 2014 06:39:20 +0000 Subject: [PATCH 30/60] Fixed|libcommon: Compiler warnings (unused arg/expression result) --- doomsday/plugins/common/src/d_netcl.cpp | 2 +- doomsday/plugins/common/src/hu_automap.cpp | 25 +++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/doomsday/plugins/common/src/d_netcl.cpp b/doomsday/plugins/common/src/d_netcl.cpp index 5bab8476d0..2e6f6fb53e 100644 --- a/doomsday/plugins/common/src/d_netcl.cpp +++ b/doomsday/plugins/common/src/d_netcl.cpp @@ -62,7 +62,7 @@ void NetCl_UpdateGameState(Reader *msg) gsRules.respawnMonsters = (configFlags & 0x8? true : false); #endif /// @todo Not applied?? - /*byte gsJumping =*/ (configFlags & 0x10? true : false); + //byte gsJumping = (configFlags & 0x10? true : false); gsRules.skill = skillmode_t(Reader_ReadByte(msg)); // Interpret skill modes outside the normal range as "spawn no things". diff --git a/doomsday/plugins/common/src/hu_automap.cpp b/doomsday/plugins/common/src/hu_automap.cpp index e08181cae7..f51518c226 100644 --- a/doomsday/plugins/common/src/hu_automap.cpp +++ b/doomsday/plugins/common/src/hu_automap.cpp @@ -221,18 +221,20 @@ void UIAutomap_Reset(uiwidget_t* obj) /** * Draws the given line including any optional extras. */ -static void rendLine2(uiwidget_t* obj, float x1, float y1, float x2, float y2, - const float color[4], glowtype_t glowType, float glowStrength, float glowSize, +static void rendLine2(uiwidget_t *ob, float x1, float y1, float x2, float y2, + float const color[4], glowtype_t glowType, float glowStrength, float glowSize, dd_bool glowOnly, dd_bool scaleGlowWithView, dd_bool caps, blendmode_t blend, dd_bool drawNormal, dd_bool addToLists) { + DENG2_ASSERT(ob->type == GUI_AUTOMAP); + DENG2_UNUSED(ob); + //guidata_automap_t* am = (guidata_automap_t*)obj->typedata; - const float alpha = uiRendState->pageAlpha; + float const alpha = uiRendState->pageAlpha; //automapcfg_t* mcfg = am->mcfg; float a[2], b[2]; float length, dx, dy; float normal[2], unit[2]; - assert(obj->type == GUI_AUTOMAP); // Scale into map, screen space units. a[VX] = x1; @@ -1311,21 +1313,20 @@ static void setupGLStateForMap(uiwidget_t *obj) /** * Restores the previous GL draw state */ -static void restoreGLStateFromMap(uiwidget_t* obj) +static void restoreGLStateFromMap(uiwidget_t * /*ob*/) { - DENG_UNUSED(obj); - // Restore the previous GL state. DGL_PopState(); } -static void renderVertexes(uiwidget_t* obj) +static void renderVertexes(uiwidget_t *ob) { + DENG2_ASSERT(ob->type == GUI_AUTOMAP); + DENG2_UNUSED(ob); + //guidata_automap_t* am = (guidata_automap_t*)obj->typedata; - const float alpha = uiRendState->pageAlpha; + float const alpha = uiRendState->pageAlpha; float v[2], oldPointSize; - int i; - assert(obj->type == GUI_AUTOMAP); DGL_Color4f(.2f, .5f, 1, alpha); @@ -1334,7 +1335,7 @@ static void renderVertexes(uiwidget_t* obj) DGL_SetFloat(DGL_POINT_SIZE, 4 * aspectScale); DGL_Begin(DGL_POINTS); - for(i = 0; i < numvertexes; ++i) + for(int i = 0; i < numvertexes; ++i) { P_GetFloatv(DMU_VERTEX, i, DMU_XY, v); DGL_TexCoord2f(0, v[VX], v[VY]); From 427ab1e0da1d8b125b2aa2b04d83014f0a05ae72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 15:56:16 +0200 Subject: [PATCH 31/60] libdeng2|App: Do not hard-code app name to "Doomsday Engine" --- doomsday/libdeng2/include/de/core/app.h | 8 ++++++++ doomsday/libdeng2/src/core/app.cpp | 13 +++++++++++-- doomsday/libdeng2/src/core/textapp.cpp | 3 +++ doomsday/libgui/src/guiapp.cpp | 3 +++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/doomsday/libdeng2/include/de/core/app.h b/doomsday/libdeng2/include/de/core/app.h index 23afcb6f7a..8ed456c5c7 100644 --- a/doomsday/libdeng2/include/de/core/app.h +++ b/doomsday/libdeng2/include/de/core/app.h @@ -118,6 +118,14 @@ class DENG2_PUBLIC App : DENG2_OBSERVES(Clock, TimeChange) */ void setConfigScript(Path const &path); + /** + * Sets the name of the application. Derived classes should call this from their + * implementation of setMetadata(). + * + * @param appName Application name. Defaults to "Doomsday Engine". + */ + void setName(String const &appName); + /** * Sets the Unix-style home folder name. For instance, ".doomsday" could be used. * diff --git a/doomsday/libdeng2/src/core/app.cpp b/doomsday/libdeng2/src/core/app.cpp index 9dd1146b7d..fc6ac798ce 100644 --- a/doomsday/libdeng2/src/core/app.cpp +++ b/doomsday/libdeng2/src/core/app.cpp @@ -51,6 +51,9 @@ DENG2_PIMPL(App) { QThread *mainThread; + /// Name of the application (metadata for humans). + String appName; + CommandLine cmdLine; LogFilter logFilter; @@ -108,6 +111,7 @@ DENG2_PIMPL(App) Instance(Public *a, QStringList args) : Base(a) + , appName("Doomsday Engine") , cmdLine(args) , unixHomeFolder(".doomsday") , persistentData(0) @@ -297,6 +301,11 @@ void App::setConfigScript(Path const &path) d->configPath = path; } +void App::setName(String const &appName) +{ + d->appName = appName; +} + void App::setUnixHomeFolderName(String const &name) { d->unixHomeFolder = name; @@ -408,7 +417,7 @@ NativePath App::nativeHomePath() #ifdef MACOSX NativePath nativeHome = QDir::homePath(); - nativeHome = nativeHome / "Library/Application Support/Doomsday Engine/runtime"; + nativeHome = nativeHome / "Library/Application Support" / d->appName / "runtime"; #elif WIN32 NativePath nativeHome = appDataPath(); nativeHome = nativeHome / "runtime"; @@ -472,7 +481,7 @@ void App::initSubsystems(SubsystemInitFlags flags) { // Recreate the persistent state data package. ZipArchive arch; - arch.add("Info", String("# Package for Doomsday's persistent state.\n").toUtf8()); + arch.add("Info", String(QString("# Package for %1's persistent state.\n").arg(d->appName)).toUtf8()); Writer(homeFolder().replaceFile("persist.pack")) << arch; homeFolder().populate(Folder::PopulateOnlyThisFolder); diff --git a/doomsday/libdeng2/src/core/textapp.cpp b/doomsday/libdeng2/src/core/textapp.cpp index 943ec7236a..f908bbbc82 100644 --- a/doomsday/libdeng2/src/core/textapp.cpp +++ b/doomsday/libdeng2/src/core/textapp.cpp @@ -45,6 +45,9 @@ TextApp::TextApp(int &argc, char **argv) void TextApp::setMetadata(String const &orgName, String const &orgDomain, String const &appName, String const &appVersion) { + setName(appName); + + // Qt metadata. setOrganizationName (orgName); setOrganizationDomain(orgDomain); setApplicationName (appName); diff --git a/doomsday/libgui/src/guiapp.cpp b/doomsday/libgui/src/guiapp.cpp index fe675efec0..d27bd6a7f9 100644 --- a/doomsday/libgui/src/guiapp.cpp +++ b/doomsday/libgui/src/guiapp.cpp @@ -47,6 +47,9 @@ GuiApp::GuiApp(int &argc, char **argv) void GuiApp::setMetadata(String const &orgName, String const &orgDomain, String const &appName, String const &appVersion) { + setName(appName); + + // Qt metadata. setOrganizationName (orgName); setOrganizationDomain(orgDomain); setApplicationName (appName); From 0629451d33cbe4f0ad05eed0bceabb8afa3f5da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 15:59:05 +0200 Subject: [PATCH 32/60] SDK|OS X|qmake: Added Mac deployment for apps On OS X, apps are bundled with the shared libraries and resources inside the application folder. Also, PREFIX is now optional when using doomsday_sdk.pri and will default to the build output directory. --- doomsday/doomsday_sdk.pri | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index 6898a78e80..e13e6f59d2 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -12,6 +12,8 @@ DENG_SDK_DIR = $$PWD +isEmpty(PREFIX): PREFIX = $$OUT_PWD + exists($$DENG_SDK_DIR/include/doomsday) { INCLUDEPATH += $$DENG_SDK_DIR/include/doomsday } @@ -36,6 +38,14 @@ contains(DENG_CONFIG, shell): LIBS += -ldeng_shell QMAKE_LFLAGS += -Wl,-rpath,$$DENG_SDK_DIR/lib } +macx { + QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 +} + +DENG_MODULES = $$DENG_SDK_DIR/modules/*.de + +# Macros --------------------------------------------------------------------- + defineTest(dengClear) { # 1: file to remove win32: system(del /q \"$$1\") @@ -49,8 +59,6 @@ defineTest(dengPack) { system(cd \"$$2\" && zip -r \"$$1\" $$3) } -DENG_MODULES = $$DENG_SDK_DIR/modules/*.de - defineTest(dengPackModules) { # 1: path of a .pack file dengPack($$1, $$DENG_SDK_DIR, modules/*.de) @@ -73,8 +81,14 @@ defineReplace(dengFindLibDir) { defineReplace(dengSdkLib) { # 1: name of library - win32: fn = $$DENG_SDK_DIR/lib/$${1}.dll - else:macx: fn = $$DENG_SDK_DIR/lib/lib$${1}.dylib + win32: fn = $$DENG_SDK_DIR/lib/$${1}.dll + else:macx { + versions = 2 1 0 + for(vers, versions) { + fn = $$DENG_SDK_DIR/lib/lib$${1}.$${vers}.dylib + exists($$fn): return($$fn) + } + } else { fn = $$DENG_SDK_DIR/lib/lib$${1}.so # Apply the latest major version. @@ -101,14 +115,20 @@ defineTest(dengDeploy) { win32 { } else:macx { + QMAKE_BUNDLE_DATA += basepack denglibs + basepack.path = Contents/Resources + denglibs.path = Contents/Frameworks } else { target.path = $$prefix/bin basepack.path = $$prefix/share/$${1} denglibs.path = $$dengFindLibDir($$prefix) } - export(INSTALLS) - export(target.path) + macx: export(QMAKE_BUNDLE_DATA) + else { + export(INSTALLS) + export(target.path) + } export(basepack.files) export(basepack.path) export(denglibs.files) From d9005fb69063685828c5dee77c6131b0e5bac88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 17:12:18 +0200 Subject: [PATCH 33/60] qmake|Unix: Link against built libraries rather than system Even if the Doomsday libraries are present on the system, we need to prioritize the ones being built to avoid version conflicts. --- doomsday/macros.pri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doomsday/macros.pri b/doomsday/macros.pri index 97f0078b3e..07c250c452 100644 --- a/doomsday/macros.pri +++ b/doomsday/macros.pri @@ -31,8 +31,10 @@ defineTest(useLibDir) { else: btype = "/Release" } exists($${1}$${btype}) { - LIBS += -L$${1}$${btype} - export(LIBS) + # Specify this library directory first to ensure it overrides the + # system library directory. + QMAKE_LFLAGS = -L$${1}$${btype} $$QMAKE_LFLAGS + export(QMAKE_LFLAGS) return(true) } return(false) From fae0e3bb11204d8f0d7734a034c8b11b95644ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 20:07:37 +0200 Subject: [PATCH 34/60] Fixed|qmake|Windows: Library directory option for MSVC --- doomsday/macros.pri | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doomsday/macros.pri b/doomsday/macros.pri index 07c250c452..35863b3970 100644 --- a/doomsday/macros.pri +++ b/doomsday/macros.pri @@ -31,10 +31,16 @@ defineTest(useLibDir) { else: btype = "/Release" } exists($${1}$${btype}) { - # Specify this library directory first to ensure it overrides the - # system library directory. - QMAKE_LFLAGS = -L$${1}$${btype} $$QMAKE_LFLAGS - export(QMAKE_LFLAGS) + win32 { + LIBS += -L$${1}$${btype} + export(LIBS) + } + else { + # Specify this library directory first to ensure it overrides the + # system library directory. + QMAKE_LFLAGS = -L$${1}$${btype} $$QMAKE_LFLAGS + export(QMAKE_LFLAGS) + } return(true) } return(false) From 0a4a162cf4f64bdb6ab76697cfe2197d7462b5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 21:03:56 +0200 Subject: [PATCH 35/60] libdeng2|RuleRectangle: Added midX/midY output rules --- .../libdeng2/include/de/widgets/rulerectangle.h | 2 ++ doomsday/libdeng2/src/widgets/rulerectangle.cpp | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/doomsday/libdeng2/include/de/widgets/rulerectangle.h b/doomsday/libdeng2/include/de/widgets/rulerectangle.h index 433248798c..fe4b683b79 100644 --- a/doomsday/libdeng2/include/de/widgets/rulerectangle.h +++ b/doomsday/libdeng2/include/de/widgets/rulerectangle.h @@ -54,6 +54,8 @@ class DENG2_PUBLIC RuleRectangle Rule const &bottom() const; Rule const &width() const; Rule const &height() const; + Rule const &midX() const; + Rule const &midY() const; /** * Sets one of the input rules of the rectangle. diff --git a/doomsday/libdeng2/src/widgets/rulerectangle.cpp b/doomsday/libdeng2/src/widgets/rulerectangle.cpp index 21379dc52f..859b7a8dfd 100644 --- a/doomsday/libdeng2/src/widgets/rulerectangle.cpp +++ b/doomsday/libdeng2/src/widgets/rulerectangle.cpp @@ -47,6 +47,8 @@ DENG2_PIMPL(RuleRectangle) // The output rules. IndirectRule *outputRules[MAX_OUTPUT_RULES]; + Rule *midX; + Rule *midY; Instance(Public *i) : Base(i) { @@ -61,11 +63,16 @@ DENG2_PIMPL(RuleRectangle) outputRules[i] = new IndirectRule; } + midX = holdRef(*outputRules[OutLeft] + *outputRules[OutWidth] / 2); + midY = holdRef(*outputRules[OutTop] + *outputRules[OutHeight] / 2); + debugName = QString("0x%1").arg(dintptr(thisPublic), 0, 16); } ~Instance() { + releaseRef(midX); + releaseRef(midY); releaseRef(normalizedAnchorX); releaseRef(normalizedAnchorY); @@ -241,6 +248,16 @@ Rule const &RuleRectangle::height() const return *d->outputRules[Instance::OutHeight]; } +Rule const &RuleRectangle::midX() const +{ + return *d->midX; +} + +Rule const &RuleRectangle::midY() const +{ + return *d->midY; +} + RuleRectangle &RuleRectangle::setInput(Rule::Semantic inputRule, Rule const &rule) { d->setInputRule(inputRule, rule); From a34fdda24270a547b26b58e5610fca90dde23831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 21:08:21 +0200 Subject: [PATCH 36/60] Fixed|UI|Updater|libappfw: Updater Settings dialog position while closing In the Update Available dialog, the anchor where the Updater Settings was attached (the Gear button) was deleted, which caused the Settings dialog to be incorrectly positioned while being closed. --- .../src/updater/updateavailabledialog.cpp | 18 ++++-------------- .../libappfw/include/de/widgets/popupwidget.h | 5 +++++ doomsday/libappfw/src/widgets/popupwidget.cpp | 7 +++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/doomsday/client/src/updater/updateavailabledialog.cpp b/doomsday/client/src/updater/updateavailabledialog.cpp index a2b42e3730..552631dbcb 100644 --- a/doomsday/client/src/updater/updateavailabledialog.cpp +++ b/doomsday/client/src/updater/updateavailabledialog.cpp @@ -90,19 +90,6 @@ DENG2_OBSERVES(ToggleWidget, Toggle) checking->rule().setRect(self.rule()); self.add(checking); - //settings = new ButtonWidget; - //self.add(settings); - - /// @todo The dialog buttons should support a opposite-aligned button. - /*settings->setSizePolicy(ui::Filled, ui::Filled); - settings->setImage(self.style().images().image("gear")); - settings->rule() - .setInput(Rule::Left, self.area().contentRule().left()) - .setInput(Rule::Bottom, self.buttons().contentRule().bottom()) - .setInput(Rule::Height, self.buttons().contentRule().height()) - .setInput(Rule::Width, settings->rule().height()); - settings->setAction()));*/ - autoCheck = new ToggleWidget; self.area().add(autoCheck); autoCheck->setAlignment(ui::AlignLeft); @@ -225,7 +212,10 @@ void UpdateAvailableDialog::editSettings() st->setAnchorAndOpeningDirection(buttonWidget(DialogWidget::Id1)->rule(), ui::Up); st->setDeleteAfterDismissed(true); if(st->exec(root())) - { + { + // The Gear button will soon be deleted, so we'll need to detach from it. + st->detachAnchor(); + d->autoCheck->setInactive(UpdaterSettings().onlyCheckManually()); d->showProgress(true, SHOW_ANIM_SPAN); emit checkAgain(); diff --git a/doomsday/libappfw/include/de/widgets/popupwidget.h b/doomsday/libappfw/include/de/widgets/popupwidget.h index f47c8bed70..48b9227ca7 100644 --- a/doomsday/libappfw/include/de/widgets/popupwidget.h +++ b/doomsday/libappfw/include/de/widgets/popupwidget.h @@ -57,6 +57,11 @@ class LIBAPPFW_PUBLIC PopupWidget : public PanelWidget Rule const &anchorX() const; Rule const &anchorY() const; + /** + * Replace the anchor with rules of matching constant value. + */ + void detachAnchor(); + /** * Tells the popup to delete itself after being dismissed. The default is that * the popup does not get deleted. diff --git a/doomsday/libappfw/src/widgets/popupwidget.cpp b/doomsday/libappfw/src/widgets/popupwidget.cpp index aec2c71794..cda3f2feba 100644 --- a/doomsday/libappfw/src/widgets/popupwidget.cpp +++ b/doomsday/libappfw/src/widgets/popupwidget.cpp @@ -244,6 +244,13 @@ Rule const &PopupWidget::anchorY() const return *d->anchorY; } +void PopupWidget::detachAnchor() +{ + setAnchorX(Constf(anchorX().value())); + setAnchorY(Constf(anchorY().value())); + d->updateLayout(); +} + void PopupWidget::setDeleteAfterDismissed(bool deleteAfterDismiss) { d->deleteAfterDismiss = deleteAfterDismiss; From 321552c626d2ad2700ab16b5089ebcc47f96e448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 21:09:08 +0200 Subject: [PATCH 37/60] Cleanup --- .../libappfw/include/de/widgets/foldpanelwidget.h | 13 ++++++------- doomsday/libappfw/src/widgets/labelwidget.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/doomsday/libappfw/include/de/widgets/foldpanelwidget.h b/doomsday/libappfw/include/de/widgets/foldpanelwidget.h index 553709b2e6..af6d401ea3 100644 --- a/doomsday/libappfw/include/de/widgets/foldpanelwidget.h +++ b/doomsday/libappfw/include/de/widgets/foldpanelwidget.h @@ -27,15 +27,14 @@ namespace de { /** * Folding panel. * - * You should first set the container of the folding panel with setContent(). - * This ensures that widgets added to the panel use the appropriate stylist. + * You should first set the container of the folding panel with setContent(). This + * ensures that widgets added to the panel use the appropriate stylist. * - * When dismissed, the panel contents are GL-deinitialized and removed from - * the widget tree entirely. + * When dismissed, the panel contents are GL-deinitialized and removed from the widget + * tree entirely. * - * FoldPanelWidget creates a title button for toggling the panel open and - * closed. It is the user's responsibility to lay out this button - * appropriately. + * If needed, FoldPanelWidget can create a title button for toggling the panel open and + * closed. It is the user's responsibility to lay out this button appropriately. */ class LIBAPPFW_PUBLIC FoldPanelWidget : public PanelWidget { diff --git a/doomsday/libappfw/src/widgets/labelwidget.cpp b/doomsday/libappfw/src/widgets/labelwidget.cpp index 7d8663a52f..344a0de46c 100644 --- a/doomsday/libappfw/src/widgets/labelwidget.cpp +++ b/doomsday/libappfw/src/widgets/labelwidget.cpp @@ -249,7 +249,7 @@ public Font::RichFormat::IStyle */ void contentPlacement(ContentLayout &layout) const { - Rectanglei const contentRect = contentArea(); //self.rule().recti().adjusted(margin.xy(), -margin.zw()); + Rectanglei const contentRect = contentArea(); Vector2f const imgSize = imageSize() * imageScale; From 7cede9438a992838ced29425b24f6e66d8332770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Fri, 28 Feb 2014 21:09:56 +0200 Subject: [PATCH 38/60] UI|Task Bar: Show the "Connect to Server" item in Ring Zero --- doomsday/client/src/ui/widgets/taskbarwidget.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doomsday/client/src/ui/widgets/taskbarwidget.cpp b/doomsday/client/src/ui/widgets/taskbarwidget.cpp index ea0307018a..7b1b66b363 100644 --- a/doomsday/client/src/ui/widgets/taskbarwidget.cpp +++ b/doomsday/client/src/ui/widgets/taskbarwidget.cpp @@ -265,8 +265,8 @@ DENG_GUI_PIMPL(TaskBarWidget) itemWidget(mainMenu, POS_GAMES) .show(!newGame.isNull()); itemWidget(mainMenu, POS_UNLOAD) .show(!newGame.isNull()); itemWidget(mainMenu, POS_GAMES_SEPARATOR) .show(!newGame.isNull()); - itemWidget(mainMenu, POS_CONNECT) .show(!newGame.isNull()); - itemWidget(mainMenu, POS_CONNECT_SEPARATOR).show(!newGame.isNull()); + //itemWidget(mainMenu, POS_CONNECT) .show(!newGame.isNull()); + //itemWidget(mainMenu, POS_CONNECT_SEPARATOR).show(!newGame.isNull()); itemWidget(configMenu, POS_RENDERER_SETTINGS).show(!newGame.isNull()); itemWidget(configMenu, POS_VR_SETTINGS) .show(!newGame.isNull()); @@ -425,8 +425,8 @@ TaskBarWidget::TaskBarWidget() : GuiWidget("taskbar"), d(new Instance(this)) d->itemWidget(d->mainMenu, POS_GAMES).hide(); d->itemWidget(d->mainMenu, POS_UNLOAD).hide(); d->itemWidget(d->mainMenu, POS_GAMES_SEPARATOR).hide(); - d->itemWidget(d->mainMenu, POS_CONNECT).hide(); - d->itemWidget(d->mainMenu, POS_CONNECT_SEPARATOR).hide(); + //d->itemWidget(d->mainMenu, POS_CONNECT).hide(); + //d->itemWidget(d->mainMenu, POS_CONNECT_SEPARATOR).hide(); d->itemWidget(d->configMenu, POS_RENDERER_SETTINGS).hide(); d->itemWidget(d->configMenu, POS_VR_SETTINGS).hide(); @@ -746,4 +746,7 @@ void TaskBarWidget::updateCommandLineLayout() cmdRule.setInput(Rule::Left, d->console->button().rule().right()) .setInput(Rule::Bottom, rule().bottom()) .setInput(Rule::Right, layout.widgets().last()->as().rule().left()); + + // Just use a plain background for this editor. + d->console->commandLine().set(Background(style().colors().colorf("background"))); } From 2c54ad1b591828cf3bf78f43d2cf4e6b8f24fc09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 13:38:58 +0200 Subject: [PATCH 39/60] Network: Querying a subset of found servers from ServerLink --- doomsday/client/include/network/serverlink.h | 36 +++++++++++-- doomsday/client/src/network/serverlink.cpp | 57 ++++++++++++-------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/doomsday/client/include/network/serverlink.h b/doomsday/client/include/network/serverlink.h index 0c99046a40..7e051f1b01 100644 --- a/doomsday/client/include/network/serverlink.h +++ b/doomsday/client/include/network/serverlink.h @@ -68,15 +68,39 @@ class ServerLink : public de::shell::AbstractLink bool isDiscovering() const; - int foundServerCount() const; + enum FoundMaskFlag + { + Direct = 0x1, + LocalNetwork = 0x2, + MasterServer = 0x4, - QList foundServers() const; + Any = Direct | LocalNetwork | MasterServer + }; + Q_DECLARE_FLAGS(FoundMask, FoundMaskFlag) - bool isFound(de::Address const &host) const; + /** + * @param mask Defines the sources that are enabled when querying for found servers. + */ + int foundServerCount(FoundMask mask = Any) const; - bool foundServerInfo(de::Address const &host, serverinfo_t *info) const; + /** + * @param mask Defines the sources that are enabled when querying for found servers. + */ + QList foundServers(FoundMask mask = Any) const; - bool foundServerInfo(int index, serverinfo_t *info) const; + bool isFound(de::Address const &host, FoundMask mask = Any) const; + + /** + * @param mask Defines the sources that are enabled when querying for found servers. + */ + bool foundServerInfo(de::Address const &host, serverinfo_t *info, + FoundMask mask = Any) const; + + /** + * @param mask Defines the sources that are enabled when querying for found servers. + */ + bool foundServerInfo(int index, serverinfo_t *info, + FoundMask mask = Any) const; signals: void serversDiscovered(); @@ -96,4 +120,6 @@ protected slots: DENG2_PRIVATE(d) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(ServerLink::FoundMask) + #endif // CLIENT_LINK_H diff --git a/doomsday/client/src/network/serverlink.cpp b/doomsday/client/src/network/serverlink.cpp index 0b1bcb7aae..10923dd9be 100644 --- a/doomsday/client/src/network/serverlink.cpp +++ b/doomsday/client/src/network/serverlink.cpp @@ -208,27 +208,38 @@ DENG2_PIMPL(ServerLink) } } - Servers allFound() const + Servers allFound(FoundMask const &mask) const { - Servers all = discovered; + Servers all; - // Append from master (if available). - DENG2_FOR_EACH_CONST(Servers, i, fromMaster) + if(mask.testFlag(Direct)) { - all.insert(i.key(), i.value()); + all = discovered; } - // Append the ones from the server finder. - foreach(Address const &sv, finder.foundServers()) + if(mask.testFlag(MasterServer)) { - serverinfo_t info; - ServerInfo_FromRecord(&info, finder.messageFromServer(sv)); + // Append from master (if available). + DENG2_FOR_EACH_CONST(Servers, i, fromMaster) + { + all.insert(i.key(), i.value()); + } + } + + if(mask.testFlag(LocalNetwork)) + { + // Append the ones from the server finder. + foreach(Address const &sv, finder.foundServers()) + { + serverinfo_t info; + ServerInfo_FromRecord(&info, finder.messageFromServer(sv)); - // Update the address in the info, which is missing because this - // information didn't come from the master. - strncpy(info.address, sv.host().toString().toLatin1(), sizeof(info.address) - 1); + // Update the address in the info, which is missing because this + // information didn't come from the master. + strncpy(info.address, sv.host().toString().toLatin1(), sizeof(info.address) - 1); - all.insert(sv, info); + all.insert(sv, info); + } } return all; @@ -330,33 +341,33 @@ bool ServerLink::isDiscovering() const d->fetching); } -int ServerLink::foundServerCount() const +int ServerLink::foundServerCount(FoundMask mask) const { - return d->allFound().size(); + return d->allFound(mask).size(); } -QList
ServerLink::foundServers() const +QList
ServerLink::foundServers(FoundMask mask) const { - return d->allFound().keys(); + return d->allFound(mask).keys(); } -bool ServerLink::isFound(Address const &host) const +bool ServerLink::isFound(Address const &host, FoundMask mask) const { - return d->allFound().contains(host); + return d->allFound(mask).contains(host); } -bool ServerLink::foundServerInfo(int index, serverinfo_t *info) const +bool ServerLink::foundServerInfo(int index, serverinfo_t *info, FoundMask mask) const { - Instance::Servers all = d->allFound(); + Instance::Servers all = d->allFound(mask); QList
listed = all.keys(); if(index < 0 || index >= listed.size()) return false; memcpy(info, &all[listed[index]], sizeof(*info)); return true; } -bool ServerLink::foundServerInfo(de::Address const &host, serverinfo_t *info) const +bool ServerLink::foundServerInfo(de::Address const &host, serverinfo_t *info, FoundMask mask) const { - Instance::Servers all = d->allFound(); + Instance::Servers all = d->allFound(mask); if(!all.contains(host)) return false; memcpy(info, &all[host], sizeof(*info)); return true; From c55e7b3f1c79bdb9bca6e0cdc5f72ce62b31105e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 13:39:26 +0200 Subject: [PATCH 40/60] Default Style: Mini version of progress wheel is also a gear --- .../graphics/progress-mini.png | Bin 1483 -> 5055 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doomsday/client/data/defaultstyle.pack/graphics/progress-mini.png b/doomsday/client/data/defaultstyle.pack/graphics/progress-mini.png index 002d762928ad1aeb3e51cf5f498516b3e720fa90..f9f98d0ea7d2948febfccf3dbaa32abbc5665c24 100644 GIT binary patch literal 5055 zcmZ`*2RNJU_YP9KXzf+1c9B@MW5h}qiZ-!>AP8y(RhufRR*g1QrByXsw6@x_QnjmA z?LBL!{?UG;|6boO*Yzgvd!PG$&biO~oLoDMY1|_pBg0{qNPLZ4&8M?`yaL-CepI}lm2{bb z22rpeebR_9L2u1d+DvCeZrU1sAkm5Bv(aLr2@SCxq}pWAZ>cxX)S4NMaiUr)klh+f zC$u8Qhv(i84%@E<3|0d4k3xVAo^X;NnM^p->QcSgS;o$$T~am%5;{1^he>hkckjtn0GKJwvTIH-(>Y2?i-~{a}BDeVI=YfzEvBP|jE1SZWPex-nG zWd$)X>#$!pJbv!3Awi|h@6dQda2fwpJ?1H5+<7@4RKo(;;Wv5AT~eED3@F8rtIbU2 z>#gwuHctUc$DVARi*U9`X!=GgL=(Nd?Ce33;UsZ!UhXg>#I>U?LSZ+pbM^41(o0s= z;0rKjX_VH?%bb^2G`qTJ=~D2vgk6T?sSgV1kL`_OPclBRZiLSp8_XwBg+)13g)0Zc zA4=F#hXwXe2C`ieqF}#^b7FGvvIGQ#E9jTQDB4_A0MH9${4T0~qybB&43gAswbc#< z@kJhSQhqE0Rp&FD-Jy-Mbr*Op#-24E=3GyD_92DmGisS&2{5Uc)oHFE zX*aSlUO-roE(6&kG6`K$v>NcOI%J5r1to__yh9z`0DZxJpMcjxF1eAL0dIXc?M6cz zq@zY1QGW$YG8T-c3|VJjey;xdAxk!Wn#KSFrwOGmR9#=5iL4nK^^hS!ZU2+tD>l*4 z*O^d#mF)|j9F>&jp$E?>KJm(s6G#HW&ZLs|B2Nzi-USU8D{)ckG;~gAVws;%uznbs zyj;!#p?lxJI?1^X5DT|#NTgJ2qa^FmhEsBGXlgu!^OKx8?-b9MO`5Bf{*W%4vm#bE z{`NE(d1NLsm5rr^eJT?Jz}>EQj47uNl6Uc!a)RlTV$ zop~H9-gMI{&dRhnoa#@LsuJr@^H!iok>xoRT2!7TZ{32nC`UF+|Bw;}&y~|u$8pGEWE?21es`)}++&KNpr4Rl(wGwBdSECtlIRK=SD4nvE zGSyy?m>2Jqyp-ZEpqDh5;*(-2ks)MxKJfC7mq+EK2K8$7hQV3IH#4;-OB+2 zlJ`YjMDHZ?CEF#FB*(qJYV6w2)Q@|Od9Bw6b`*3(Iu1J?_Dkf&;&bpmPw_ZQnd9lB z$i?EyD8KRp$M21cDvOC6=^V8j>>S1%DKagx?CCD)?ddb=b26=^4kk2ZK$97hxiSlI za@uN_k)1$Ev_fV<;YyBp4v~Byqj`dashs+Iv-gHR8hTeiaFAt@ z!CEH7Afq57yH2OhG_d2tC*Chs(dv)uUuE9UtV2FUW=+~$cpabDBbsHBrPLyC^X~Tj z4ak(KU~v=-wzh*epH)dp2i7&;|I?Xx=%H+vbwLUNYia_LR4?I(7RBpSI<@+DB4#MQB*udfL7akPN*9X{8oxB9JDJ-Av_?2i*_3p@9GxvI$Q2*= zu3HIEN;fYaWvRMeh2Npu;X4#Ol%!CJ#75T8?GAZ*3s;2&^q*OppDgd*h?$}g@)vs3 z3(FbDA-YAnPj_e0(6X+x_KCB(_uQT==W>siu$73h#JXkn8IL4SnJgW2T^o#@^KQa4 zjSi^{6Uq-S(qEyE*NJXT%1NB#z|&aVODVb)f2-(y!mjn2<5~_x5fTN7g)r87*X9L) z_K*Zpg7?Ab*5LZw!Qi1DP#&01HBX%l)CS(9fY3-$ojv6RY^*1#uL|J-eYWH`>ti9+ zID&eID^tnRnlm4Gut|u?@j-rYhaIw$E)k(XlL7SbVhGb(*#M zb*^doYo%yiNr8(YN~X1AOk#Lns<7~IGW+v;yXWqH9=#Gdwfv2GYE?qo>`}?`7x%K6 z+)jMqL(6)^ZP9a_Jlx|9$5D(8xieP_w=FAtW`KigL{|_#P-r$%aoxwfzH;(=?NS_u7o$78-l^Rg zi{c!2xj)ut@XVmN*2ctgss%P*m-g2GvQ6?^L2Egatoejjj$O0R5)Q?Fw?d9eDi(Pt>xOA zNYmR^^yoO-xKgQCZ)+|WIqLN1EM_kTbHt_3)-3wJU%`E89T}_}#{~A0#F8~rK+Z97 zRR^~1>N^#vW15j)C-WQeOV1Z8>+Az912tE4H{$U+;W{r`8{)kBmHGzdUdbh0YKTo} zc{6pp)s-;u9qP}Rx1cYbRj~(@Kd-Ryt#yxQ?J2GDuuKM`+&UVaBT6#%`{S|zCH}jLn3K>3kH#J(qH=?6hBNcCX zLMltAKjR9E3&%QxQ;IA$D%^8NY7UQ#Q}XN!70i_aZ~-+d5ro)*b5&0tSuWp2FO;oe zY8Ko|2#=-;9@L%+m^&~(1dZ)f2FyG-#&MEGlOL=~)cPM=d{tQp7$fvhGV^Vsj!s|qSyxUFg$;-Iwb68_<-QKkB)U%YPdU@P|2r^U!9yHGW}PZ%;2dBUaVt4%N{nRuE%1JH8vXbtt8XxJx`! zQn~3OJcx(QvnLlxS&*D30087e8^Jx{*RCqsxMC!bwyxGF2`t8q$OZtEv5Lf749XM9 zi^Vv*cqn33_!Ot#nVZJ4}MLb7wYPc;+2(1StCyz=AKyu$e?GtJ^hDeJo5{uFFIz-|ppytlQUVP6FBuAp z{vWcF$p4ht+Wh0n&CA{Srzcw*5Xu>aLAiK(5OtFOnU2`oe}w<9NG#IrSF)c?{N+vg zq;ka@C=XX>uag!SyP!QGlFB~~{R#iukzXpPE5^+o<>5h;L1h1u{Eq#}hyR-fBLBDG zckoYvo;#Z86nRqDKQ;Z1{mDoCSAyTc-vlSESJX#iQOP)GY#T@rTH!Jo6y!q(ZkEy5oP1~+uI_(v!8ok18EQX4ORyI zCtI1g6BMtx+M?}zHIbeuh!j{-MjR|H4wf{MlvV^wD=J7UgZ|+BR>4UG>W)Hsy1E;= zx;jICy1<+~@=8k(UH=*XOR5YynWEpO>etBrM2RyCp(ZN-o_`3n_r#Pr@!w(xrm1cO zr}~&`de7LHEl9;CEp4cCAA|0!cW!xP<3*MqX{w&{?L|QXE2hP} z9~Y#uu24-f?x~bjiW8BSV_l8JxN*IFW~!joSTtz>mnq4SAfChldi88iLZ$XYLh`Jx zKS~ENQec4=A)J+NPL))#tc`Yij3(`soIbQPOuiH$gh+2Mb#y%t7#xYj`s((pn&ye1gOcpB&}i z_8ZV)+|is59e~GN5S5+BdMN1rd!Q~ zAEJF7)GZ=#YM!9vEM z!GA}N3N;u)Bb*0w`vg`o9=_0uS{0@)M7aEz>Z%Bv)a@KBw4@ISW$e>c$czugMJ()( zZTc=ROq_QU-1=tAP2WKxs^n1@>T|DJK0(|U6}MT06e@ER>NzGYL(odkpLXWjd>cgq zub2xNm5hNTg7bOq+HrPo-83gDQrn~3f)l83fUY;#`G~IA6CU=VDD(zTMI*^^1Ljs7 zwn+w+JO_elgq~Mqha>cXnw1MW)fQA41Fak5n$mTj>qtCO%Of&`Yb+o%t-NC2@5#1B zVn1P5&kA!mq>3sVjDPs9u|De~J3Xat)Zc5hZLXSa7;z-Xx!*GBOKD*+=wi*22qC>f zLw=Te(U-)Z!GeNYHb1|cieQWN*rGR*cXa#*^r+Q&cPRoQi^BVe~$ z9ziR)QXYI1Z?6r(DHN_lvwjKq)*RXGV_;F%DRXkv)@tABm zl)GVWg$+IOIX={+8OAMnuRqs#B112XskIMF-sp4h<(af$lc-eb;|?{Sp;TC8c!IXJM&m$-n>1tt;AREKB2bECF?3N<346UZ4wT0mp&Cc#Z-i zKx;gXRzJ!=n|1+{fhEBCzy{)7>+>A;o1 zGGIAy4RB^etrkzVUn`y_Fa-PzYy`doz6SQElv;mPBAF^UR|l2?_W^eSmqc2-ItYFX z7zTa?J_ObRKctifJH}-W_^6ZB+tjt{es$D|SxY^nZctaLGm5^qs&iA-`_)g?VNb7( zsGHTN)w$XCj_G7UubRRtAJhVTPdZZDWwzqspp9_s&y%_I;yo^Lco6j zn}IKY4}cv&BZ{FG1#}Lu0=Nmd0_ZO&tOP6q9t$TwNhvi?D44d?_NmWBK@{1jx=DRO zy(n;68v{1I>U?#z`nh_%WZ$FeYwF@sJgR?P>aDR+v&6Y?)Cbj>MSv~?c^u>pb$wv9 z2*baqkE%Uon@m%mQ4f~@db9eFdUhxMyDgfxs~e+=+igf)qb|%xu@=A70(&5krdbpeo@z!u<5;6SI%K7W6R zl+sb)6X5$06zw)Q0(C~d)QJ!JLzT4K5#UQ;XG+OVTT@0GIr|-W7uZ!0#qOY{vw~6n zb#O{}U({ds0q=!u>R8Veqdj$y--Ma89NZG6gcV#KBf@-i|DKojO;N?!SWA z8wCz73=Xa3BiI{^-_B_xk&+QkgXMn?*8&ce>^n0LwOY>eNhLCAD1KH`92J9^>pbn& zlW&c+oFgM8da);NqjO>-^-nd0dwfYi?5+g3h;gW=$4!M^7LcdC;olIC3dssUF43rc^Q!nU9` z^9~*Z_LQ)DUr46eRfIu>==H^Xv$%jYMk7!I8Lib~VIxMvtp#cB1}+8eR;P{8A*u+5 z9^l$&sgny{KNuZmsJ%#8st&3+209omA8zDolqp;9}sBIB+W9+^^zkoRlTC zuHGAhv{fL78tVJ%Eg2q5Fjjx$Xt#Q)`l>omB3k#VPpZA88>{ow7fUo@rrADHAC7nH zr-)!J#O*!m8)GKWgqZ5upyFN{ewh}z%XNgwe^N4yd(l{JrLhBT>@d5Q^bwQTe zPAFlP`joo0WQLgN704d-C3R^#?mBUDW)#GyCDYh=tfBs(J{tp4>X`Tou0d{8Uyqaz zS4dsiea!Bt)|COHQ#yZF^?tAmm=`T?Mcfq3k8V&O;|jPL?Q>t;M0^Z<1Z=Nb5UG>v z-)L3+(GeB_7erTB5EN3&iP60=4gMGkWlOZv;s5lGI?~b=TsJEsIWzuFxu$;z_$@?8 z188O(_n+KRk8zov3b-;OVDnCmcPbpOD*j*A{SBu*ZY!5b*+~ol0000 Date: Sun, 2 Mar 2014 13:40:46 +0200 Subject: [PATCH 41/60] libappfw|ButtonWidget: Added a method for triggering a button --- .../include/de/widgets/buttonwidget.h | 6 +++++ .../libappfw/src/widgets/buttonwidget.cpp | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/doomsday/libappfw/include/de/widgets/buttonwidget.h b/doomsday/libappfw/include/de/widgets/buttonwidget.h index 65fa2d9d9a..912c2596e9 100644 --- a/doomsday/libappfw/include/de/widgets/buttonwidget.h +++ b/doomsday/libappfw/include/de/widgets/buttonwidget.h @@ -86,12 +86,18 @@ class LIBAPPFW_PUBLIC ButtonWidget : public LabelWidget Action const *action() const; + /** + * Triggers the action of the button. + */ + void trigger(); + State state() const; // Events. void update(); bool handleEvent(Event const &event); + protected: void updateModelViewProjection(GLUniform &uMvp); diff --git a/doomsday/libappfw/src/widgets/buttonwidget.cpp b/doomsday/libappfw/src/widgets/buttonwidget.cpp index f47bb0aad9..148961aed5 100644 --- a/doomsday/libappfw/src/widgets/buttonwidget.cpp +++ b/doomsday/libappfw/src/widgets/buttonwidget.cpp @@ -212,6 +212,20 @@ Action const *ButtonWidget::action() const return d->action; } +void ButtonWidget::trigger() +{ + // Hold an extra ref so the action isn't deleted by triggering. + AutoRef held = holdRef(d->action); + + // Notify. + DENG2_FOR_AUDIENCE(Press, i) i->buttonPressed(*this); + + if(held) + { + held->trigger(); + } +} + ButtonWidget::State ButtonWidget::state() const { return d->state; @@ -242,16 +256,7 @@ bool ButtonWidget::handleEvent(Event const &event) d->updateHover(mouse.pos()); if(hitTest(mouse.pos())) { - // Hold an extra ref so the action isn't deleted by triggering. - AutoRef held = holdRef(d->action); - - // Notify. - DENG2_FOR_AUDIENCE(Press, i) i->buttonPressed(*this); - - if(held) - { - held->trigger(); - } + trigger(); } return true; From f6dc21285041c6179517c49fd6c5da332df9a899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 13:41:43 +0200 Subject: [PATCH 42/60] libappfw|ProgressWidget: Color of the mini style can be changed --- .../include/de/widgets/progresswidget.h | 2 +- .../libappfw/src/widgets/progresswidget.cpp | 52 +++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/doomsday/libappfw/include/de/widgets/progresswidget.h b/doomsday/libappfw/include/de/widgets/progresswidget.h index d42b68d97c..7ec5249581 100644 --- a/doomsday/libappfw/include/de/widgets/progresswidget.h +++ b/doomsday/libappfw/include/de/widgets/progresswidget.h @@ -48,7 +48,7 @@ class LIBAPPFW_PUBLIC ProgressWidget : public LabelWidget public: ProgressWidget(String const &name = ""); - void useMiniStyle(); + void useMiniStyle(DotPath const &colorId = "text"); void setRotationSpeed(float anglesPerSecond); Mode mode() const; diff --git a/doomsday/libappfw/src/widgets/progresswidget.cpp b/doomsday/libappfw/src/widgets/progresswidget.cpp index ee39188096..84a2807cee 100644 --- a/doomsday/libappfw/src/widgets/progresswidget.cpp +++ b/doomsday/libappfw/src/widgets/progresswidget.cpp @@ -32,6 +32,7 @@ DENG_GUI_PIMPL(ProgressWidget), public Lockable Animation pos; float angle; float rotationSpeed; + bool mini; Id gearTex; DotPath colorId; DotPath shadowColorId; @@ -40,24 +41,32 @@ DENG_GUI_PIMPL(ProgressWidget), public Lockable int framesWhileAnimDone; ///< # of frames drawn while animation was already done. Instance(Public *i) - : Base(i), - mode(Indefinite), - visualRange(0, 1), - pos(0, Animation::Linear), - angle(0), - rotationSpeed(20), - colorId("progress.light.wheel"), - shadowColorId("progress.light.shadow"), - gearId("progress.gear"), - updateAt(Time::invalidTime()), - framesWhileAnimDone(0) + : Base(i) + , mode(Indefinite) + , visualRange(0, 1) + , pos(0, Animation::Linear) + , angle(0) + , rotationSpeed(20) + , mini(false) + , colorId("progress.light.wheel") + , shadowColorId("progress.light.shadow") + , gearId("progress.gear") + , updateAt(Time::invalidTime()) + , framesWhileAnimDone(0) { updateStyle(); } void updateStyle() { - self.setImageColor(style().colors().colorf(colorId) /* * Vector4f(1, 1, 1, .5f)*/); + if(mini) + { + self.setImageColor(Vector4f()); + } + else + { + self.setImageColor(style().colors().colorf(colorId)); + } } void glInit() @@ -88,18 +97,19 @@ ProgressWidget::ProgressWidget(String const &name) setTextLineAlignment(ui::AlignLeft); } -void ProgressWidget::useMiniStyle() +void ProgressWidget::useMiniStyle(DotPath const &colorId) { - // Don't use the normal wheel. - setImage(de::Image()); - + d->mini = true; + d->colorId = colorId; d->gearId = "progress.mini"; - d->colorId = "text"; + setTextColor(colorId); + setRotationSpeed(40); setImageScale(1); - setAlignment(ui::AlignCenter, LabelWidget::AlignByCombination); // Resize to the height of the default font. setOverrideImageSize(style().fonts().font("default").height().value()); + + d->updateStyle(); } void ProgressWidget::setRotationSpeed(float anglesPerSecond) @@ -131,7 +141,7 @@ void ProgressWidget::setColor(DotPath const &styleId) d->updateStyle(); } -void ProgressWidget::setShadowColor(const DotPath &styleId) +void ProgressWidget::setShadowColor(DotPath const &styleId) { d->shadowColorId = styleId; d->updateStyle(); @@ -206,7 +216,7 @@ void ProgressWidget::glMakeGeometry(DefaultVertexBuf::Builder &verts) // There is a shadow behind the wheel. float gradientThick = layout.image.width() * 2.f; - float solidThick = layout.image.width() * .53f; + float solidThick = layout.image.width() * .53f; Vector4f const shadowColor = style().colors().colorf(d->shadowColorId); verts.makeRing(layout.image.middle(), @@ -256,7 +266,7 @@ void ProgressWidget::glMakeGeometry(DefaultVertexBuf::Builder &verts) DefaultVertexBuf::Builder gear; DefaultVertexBuf::Type v; - v.rgba = style().colors().colorf(d->colorId) * Vector4f(1, 1, 1, 2); + v.rgba = style().colors().colorf(d->colorId) * Vector4f(1, 1, 1, d->mini? 1.f : 1.9f); for(int i = 0; i <= edgeCount; ++i) { From aef1275a58cab74441f623a87e60f5677fa7b090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 13:42:07 +0200 Subject: [PATCH 43/60] libappfw|LineEditWidget: Added a frame for text edit widgets --- .../libappfw/src/widgets/lineeditwidget.cpp | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/doomsday/libappfw/src/widgets/lineeditwidget.cpp b/doomsday/libappfw/src/widgets/lineeditwidget.cpp index 1edf43b2d9..c944bfb535 100644 --- a/doomsday/libappfw/src/widgets/lineeditwidget.cpp +++ b/doomsday/libappfw/src/widgets/lineeditwidget.cpp @@ -76,6 +76,8 @@ DENG_GUI_PIMPL(LineEditWidget) updateStyle(); uCursorColor = Vector4f(1, 1, 1, 1); + + self.set(Background(Vector4f(1, 1, 1, 1), Background::GradientFrame)); } ~Instance() @@ -113,15 +115,29 @@ DENG_GUI_PIMPL(LineEditWidget) void updateBackground() { - Background bg(style().colors().colorf("background")); - if(hovering > 0) + // If using a gradient frame, update parameters automatically. + if(self.background().type == Background::GradientFrame) { - bg.type = Background::GradientFrame; - bg.thickness = 6; - bg.color = Vector4f(1, 1, 1, .15f * hovering); - self.requestGeometry(); + Background bg; + if(!self.hasFocus()) + { + bg = Background(Background::GradientFrame, Vector4f(1, 1, 1, .15f + hovering * .2f), 6); + //style().colors().colorf("background")); + } + else + { + bg = Background(style().colors().colorf("background"), Background::GradientFrame, + Vector4f(1, 1, 1, .25f + hovering * .3f), 6); + /*if(hovering > 0) + { + bg.type = Background::GradientFrame; + bg.thickness = 6; + bg.color = Vector4f(1, 1, 1, .15f * hovering); + self.requestGeometry(); + }*/ + } + self.set(bg); } - self.set(bg); } void glInit() @@ -188,7 +204,7 @@ DENG_GUI_PIMPL(LineEditWidget) void updateHover(Vector2i const &pos) { - if(!self.hasFocus() && self.hitTest(pos)) + if(/*!self.hasFocus() && */ self.hitTest(pos)) { if(hovering.target() < 1) { From b5543402fd259c746f72d9153afbae00b98fa314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 13:42:46 +0200 Subject: [PATCH 44/60] libappfw: Minor improvements --- doomsday/libappfw/include/de/framework/data.h | 2 ++ doomsday/libappfw/include/de/widgets/dialogwidget.h | 2 +- doomsday/libappfw/src/widgets/dialogwidget.cpp | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doomsday/libappfw/include/de/framework/data.h b/doomsday/libappfw/include/de/framework/data.h index 3a766e700e..7384340ee7 100644 --- a/doomsday/libappfw/include/de/framework/data.h +++ b/doomsday/libappfw/include/de/framework/data.h @@ -127,6 +127,8 @@ class LIBAPPFW_PUBLIC Data virtual dsize size() const = 0; }; +typedef Data::Pos DataPos; + } // namespace ui } // namespace de diff --git a/doomsday/libappfw/include/de/widgets/dialogwidget.h b/doomsday/libappfw/include/de/widgets/dialogwidget.h index 1320ee725e..31fc6ed64d 100644 --- a/doomsday/libappfw/include/de/widgets/dialogwidget.h +++ b/doomsday/libappfw/include/de/widgets/dialogwidget.h @@ -141,7 +141,7 @@ class LIBAPPFW_PUBLIC DialogWidget : public PopupWidget ScrollAreaWidget &area(); - //MenuWidget &buttons(); + MenuWidget &buttonsMenu(); /** * Additional buttons of the dialog, laid out opposite to the normal dialog diff --git a/doomsday/libappfw/src/widgets/dialogwidget.cpp b/doomsday/libappfw/src/widgets/dialogwidget.cpp index 35598a47d8..b08699993d 100644 --- a/doomsday/libappfw/src/widgets/dialogwidget.cpp +++ b/doomsday/libappfw/src/widgets/dialogwidget.cpp @@ -414,6 +414,11 @@ ScrollAreaWidget &DialogWidget::area() return *d->area; } +MenuWidget &DialogWidget::buttonsMenu() +{ + return *d->buttons; +} + /* MenuWidget &DialogWidget::buttons() { From 84eb5148e5bacf97488c7ba1a232f90925201779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 14:55:29 +0200 Subject: [PATCH 45/60] libdeng2|Action: Added as/is methods for Action classes --- doomsday/libdeng2/include/de/widgets/action.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doomsday/libdeng2/include/de/widgets/action.h b/doomsday/libdeng2/include/de/widgets/action.h index ee4f566c14..e353e7a58b 100644 --- a/doomsday/libdeng2/include/de/widgets/action.h +++ b/doomsday/libdeng2/include/de/widgets/action.h @@ -48,6 +48,8 @@ class DENG2_PUBLIC Action : public Counted */ virtual void trigger(); + DENG2_AS_IS_METHODS() + protected: virtual ~Action(); // ref counted, hence not publicly deletable }; From 84876d6e9249ee5f3ab86b97de91f5c3f3febc03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 14:56:40 +0200 Subject: [PATCH 46/60] libappfw|DialogWidget: Added an action for dialog acceptance When a dialog is accepted (closed with a non-zero result), they may now be given an action to trigger when the dialog has closed. --- .../include/de/widgets/dialogwidget.h | 9 +++++ .../libappfw/src/widgets/dialogwidget.cpp | 36 +++++++++++++++---- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/doomsday/libappfw/include/de/widgets/dialogwidget.h b/doomsday/libappfw/include/de/widgets/dialogwidget.h index 31fc6ed64d..da68c00700 100644 --- a/doomsday/libappfw/include/de/widgets/dialogwidget.h +++ b/doomsday/libappfw/include/de/widgets/dialogwidget.h @@ -159,6 +159,15 @@ class LIBAPPFW_PUBLIC DialogWidget : public PopupWidget ButtonWidget *buttonWidget(int roleId) const; + /** + * Sets the action that will be triggered if the dialog is accepted. The action + * will be triggered after the dialog has started closing (called from + * DialogWidget::finish()). + * + * @param action Action to trigger after the dialog has been accepted. + */ + void setAcceptanceAction(RefArg action); + /** * Shows the dialog and blocks execution until the dialog is closed -- * another event loop is started for event processing. Call either accept() diff --git a/doomsday/libappfw/src/widgets/dialogwidget.cpp b/doomsday/libappfw/src/widgets/dialogwidget.cpp index b08699993d..9eb5b32de1 100644 --- a/doomsday/libappfw/src/widgets/dialogwidget.cpp +++ b/doomsday/libappfw/src/widgets/dialogwidget.cpp @@ -85,6 +85,7 @@ public ChildWidgetOrganizer::IFilter MenuWidget *extraButtons; ui::ListData buttonItems; QEventLoop subloop; + de::Action *acceptAction; Animation glow; bool needButtonUpdate; float normalGlow; @@ -92,12 +93,13 @@ public ChildWidgetOrganizer::IFilter DialogContentStylist stylist; Instance(Public *i, Flags const &dialogFlags) - : Base(i), - modality(Modal), - flags(dialogFlags), - heading(0), - needButtonUpdate(false), - animatingGlow(false) + : Base(i) + , modality(Modal) + , flags(dialogFlags) + , heading(0) + , acceptAction(0) + , needButtonUpdate(false) + , animatingGlow(false) { // Initialize the border glow. normalGlow = style().colors().colorf("glow").w; @@ -190,6 +192,11 @@ public ChildWidgetOrganizer::IFilter self.setContent(container); } + ~Instance() + { + releaseRef(acceptAction); + } + void updateContentHeight() { // Determine suitable maximum height. @@ -464,6 +471,11 @@ ButtonWidget *DialogWidget::buttonWidget(int roleId) const return 0; } +void DialogWidget::setAcceptanceAction(RefArg action) +{ + changeRef(d->acceptAction, action); +} + int DialogWidget::exec(GuiRootWidget &root) { d->modality = Modal; @@ -620,10 +632,20 @@ void DialogWidget::preparePanelForOpening() d->updateBackground(); } -void DialogWidget::finish(int) +void DialogWidget::finish(int result) { root().setFocus(0); close(); + + if(result > 0) + { + // Success! + if(d->acceptAction) + { + AutoRef held = *d->acceptAction; + held->trigger(); + } + } } DialogWidget::ButtonItem::ButtonItem(RoleFlags flags, String const &label) From af3daf1c9b977e3452afbda066428f0ca9796d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 14:57:33 +0200 Subject: [PATCH 47/60] UI|Updater: Allow updater mini progress to rotate --- doomsday/client/src/updater/updater.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/doomsday/client/src/updater/updater.cpp b/doomsday/client/src/updater/updater.cpp index 0e34942190..24508d0bc5 100644 --- a/doomsday/client/src/updater/updater.cpp +++ b/doomsday/client/src/updater/updater.cpp @@ -120,7 +120,6 @@ class UpdaterStatusWidget : public ProgressWidget useMiniStyle(); setColor("text"); setShadowColor(""); // no shadow, please - setRotationSpeed(0); setSizePolicy(ui::Expand, ui::Expand); // The notification has a hidden button that can be clicked. From fd39af2c701f4fb3458e8f04b5dff2a58c88bbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 14:59:41 +0200 Subject: [PATCH 48/60] UI|Multiplayer: Improved MPSelectionWidget The multiplayer game selection widget can now notify an audience when the selection has been made, and the click-to-join feature can be disabled. This allows the widget to function as a part of another dialog. Also, the discovery mode for the widget can be configured. --- .../include/ui/widgets/mpselectionwidget.h | 36 ++++- .../src/ui/widgets/gameselectionwidget.cpp | 2 +- .../src/ui/widgets/mpselectionwidget.cpp | 123 +++++++++++------- 3 files changed, 113 insertions(+), 48 deletions(-) diff --git a/doomsday/client/include/ui/widgets/mpselectionwidget.h b/doomsday/client/include/ui/widgets/mpselectionwidget.h index 0c0cf12c06..1fae02721f 100644 --- a/doomsday/client/include/ui/widgets/mpselectionwidget.h +++ b/doomsday/client/include/ui/widgets/mpselectionwidget.h @@ -20,6 +20,7 @@ #define DENG_CLIENT_MPSELECTIONWIDGET_H #include +#include "network/net_main.h" /** * Menu that populates itself with available multiplayer games. @@ -31,10 +32,43 @@ class MPSelectionWidget : public de::MenuWidget Q_OBJECT public: - MPSelectionWidget(); + DENG2_DEFINE_AUDIENCE(Selection, void gameSelected(serverinfo_t const &info)) + + enum DiscoveryMode { + NoDiscovery, + DiscoverUsingMaster, + DirectDiscoveryOnly + }; + + /** + * Action for joining a game on a multiplayer server. + */ + class JoinAction : public de::Action + { + public: + JoinAction(serverinfo_t const &sv); + void trigger(); + + private: + DENG2_PRIVATE(d) + }; + +public: + MPSelectionWidget(DiscoveryMode discovery = NoDiscovery); + + /** + * Enables or disables joining games by pressing the menu items in the widget. + * By default, this is enabled. If disabled, one will only get a notification + * about the selection. + * + * @param enableJoin @c true to allow automatic joining, @c false to disallow. + */ + void setJoinGameWhenSelected(bool enableJoin); void setColumns(int numberOfColumns); + serverinfo_t const &serverInfo(de::ui::DataPos pos) const; + signals: void availabilityChanged(); void gameSelected(); diff --git a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp index b88df2bbbb..3542a9b261 100644 --- a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp +++ b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp @@ -109,7 +109,7 @@ DENG_GUI_PIMPL(GameSelectionWidget) break; case MultiplayerGames: - menu = new MPSelectionWidget; + menu = new MPSelectionWidget(MPSelectionWidget::DiscoverUsingMaster); QObject::connect(menu, SIGNAL(gameSelected()), owner->thisPublic, SIGNAL(gameSessionSelected())); QObject::connect(menu, SIGNAL(availabilityChanged()), owner->thisPublic, SLOT(updateSubsetLayout())); break; diff --git a/doomsday/client/src/ui/widgets/mpselectionwidget.cpp b/doomsday/client/src/ui/widgets/mpselectionwidget.cpp index 8bc0c93010..708307a912 100644 --- a/doomsday/client/src/ui/widgets/mpselectionwidget.cpp +++ b/doomsday/client/src/ui/widgets/mpselectionwidget.cpp @@ -75,33 +75,6 @@ DENG_GUI_PIMPL(MPSelectionWidget) */ struct ServerWidget : public GameSessionWidget { - struct JoinAction : public Action - { - public: - JoinAction(serverinfo_t const &sv, ButtonWidget &owner) - : _owner(&owner) - { - _gameId = sv.gameIdentityKey; - _cmd = String("connect %1 %2").arg(sv.address).arg(sv.port); - } - - void trigger() - { - Action::trigger(); - - BusyMode_FreezeGameForBusyMode(); - ClientWindow::main().taskBar().close(); - - App_ChangeGame(App_Games().byIdentityKey(_gameId), false /*no reload*/); - Con_Execute(CMDS_DDAY, _cmd.toLatin1(), false, false); - } - - private: - ButtonWidget *_owner; - String _gameId; - String _cmd; - }; - ServerWidget() { loadButton().disable(); @@ -124,10 +97,10 @@ DENG_GUI_PIMPL(MPSelectionWidget) loadButton().enable(sv.canJoin); if(sv.canJoin) { - loadButton().setAction(new JoinAction(sv, loadButton())); + loadButton().setAction(new JoinAction(sv)); } - loadButton().setText(String(_E(1) "%1 " _E(.)_E(2) "(%5/%6)" _E(.) "\n%2" + loadButton().setText(String(_E(1) "%1 " _E(.)_E(2) "(%5/%6)" _E(.) " "DENG2_CHAR_MDASH" %2" _E(D)_E(l) "\n%7 %4") .arg(sv.name) .arg(svGame.title()) @@ -146,7 +119,13 @@ DENG_GUI_PIMPL(MPSelectionWidget) } }; - Instance(Public *i) : Base(i) + ServerLink::FoundMask mask; + bool joinWhenSelected; + + Instance(Public *i) + : Base(i) + , mask(ServerLink::Any) + , joinWhenSelected(true) { self.organizer().setWidgetFactory(*this); link().audienceForDiscoveryUpdate += this; @@ -171,11 +150,27 @@ DENG_GUI_PIMPL(MPSelectionWidget) void updateItemWidget(GuiWidget &widget, ui::Item const &item) { - widget.as().updateFromItem(item.as()); + ServerWidget &sv = widget.as(); + sv.updateFromItem(item.as()); + + if(!joinWhenSelected) + { + // Only send notification. + sv.loadButton().setAction(0); + } } - void buttonPressed(ButtonWidget &) + void buttonPressed(ButtonWidget &loadButton) { + if(ServerListItem const *it = self.organizer().findItemForWidget( + loadButton.parentWidget()->as())->maybeAs()) + { + DENG2_FOR_PUBLIC_AUDIENCE(Selection, i) + { + i->gameSelected(it->info()); + } + } + // A load button has been pressed. emit self.gameSelected(); } @@ -188,7 +183,7 @@ DENG_GUI_PIMPL(MPSelectionWidget) for(ui::Data::Pos idx = 0; idx < self.items().size(); ++idx) { String const id = self.items().at(idx).data().toString(); - if(!link.isFound(Address::parse(id))) + if(!link.isFound(Address::parse(id), mask)) { self.items().remove(idx--); changed = true; @@ -196,10 +191,10 @@ DENG_GUI_PIMPL(MPSelectionWidget) } // Add new entries and update existing ones. - foreach(de::Address const &host, link.foundServers()) + foreach(de::Address const &host, link.foundServers(mask)) { serverinfo_t info; - if(!link.foundServerInfo(host, &info)) continue; + if(!link.foundServerInfo(host, &info, mask)) continue; ui::Data::Pos found = self.items().findData(hostId(info)); if(found == ui::Data::InvalidPos) @@ -224,12 +219,30 @@ DENG_GUI_PIMPL(MPSelectionWidget) } }; -MPSelectionWidget::MPSelectionWidget() +MPSelectionWidget::MPSelectionWidget(DiscoveryMode discovery) : MenuWidget("mp-selection"), d(new Instance(this)) { setGridSize(3, ui::Filled, 0, ui::Expand); - d->link().discoverUsingMaster(); + switch(discovery) + { + case DiscoverUsingMaster: + d->link().discoverUsingMaster(); + break; + + case DirectDiscoveryOnly: + // Only show servers found via direct connection. + d->mask = ServerLink::Direct; + break; + + default: + break; + } +} + +void MPSelectionWidget::setJoinGameWhenSelected(bool enableJoin) +{ + d->joinWhenSelected = enableJoin; } void MPSelectionWidget::setColumns(int numberOfColumns) @@ -239,15 +252,33 @@ void MPSelectionWidget::setColumns(int numberOfColumns) setGridSize(numberOfColumns, ui::Filled, 0, ui::Expand); } } -/* -void MPSelectionWidget::update() + +serverinfo_t const &MPSelectionWidget::serverInfo(ui::DataPos pos) const { - MenuWidget::update(); + DENG2_ASSERT(pos < items().size()); + return items().at(pos).as().info(); +} - Rectanglei rect; - if(hasChangedPlace(rect)) - { - d->updateLayoutForWidth(rect.width()); - } +DENG2_PIMPL_NOREF(MPSelectionWidget::JoinAction) +{ + String gameId; + String cmd; +}; + +MPSelectionWidget::JoinAction::JoinAction(serverinfo_t const &sv) + : d(new Instance) +{ + d->gameId = sv.gameIdentityKey; + d->cmd = String("connect %1 %2").arg(sv.address).arg(sv.port); +} + +void MPSelectionWidget::JoinAction::trigger() +{ + Action::trigger(); + + BusyMode_FreezeGameForBusyMode(); + ClientWindow::main().taskBar().close(); + + App_ChangeGame(App_Games().byIdentityKey(d->gameId), false /*no reload*/); + Con_Execute(CMDS_DDAY, d->cmd.toLatin1(), false, false); } -*/ From 7dcf201f2aa1b7527eea4f5bef01db1de9115abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 15:02:18 +0200 Subject: [PATCH 49/60] UI|Multiplayer: Improved manual connection dialog The manual "Connect to Server" dialog is now substantially more sophisticated. Once an address has been entered, it starts a query using ServerLink and shows the results in an MPSelectionWidget. The game can then be joined by pressing Enter, clicking the dialog's Connect button, or clicking the MPSelectionWidget's join button. The dialog takes advantage of an acceptance action to execute the join. This also works around the issue of not being able to change games when joining with the "connect" console command. --- .../ui/dialogs/manualconnectiondialog.h | 2 + .../src/ui/dialogs/manualconnectiondialog.cpp | 150 +++++++++++++++++- .../client/src/ui/widgets/taskbarwidget.cpp | 6 +- 3 files changed, 145 insertions(+), 13 deletions(-) diff --git a/doomsday/client/include/ui/dialogs/manualconnectiondialog.h b/doomsday/client/include/ui/dialogs/manualconnectiondialog.h index f89fa63f2e..d39e49d657 100644 --- a/doomsday/client/include/ui/dialogs/manualconnectiondialog.h +++ b/doomsday/client/include/ui/dialogs/manualconnectiondialog.h @@ -40,6 +40,8 @@ class ManualConnectionDialog : public de::InputDialog, public de::IPersistent void operator << (de::PersistentState const &fromState); public slots: + void queryOrConnect(); + void contentChanged(); void validate(); protected: diff --git a/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp b/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp index 155b05e21b..f6a97be393 100644 --- a/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp +++ b/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp @@ -17,28 +17,123 @@ */ #include "ui/dialogs/manualconnectiondialog.h" +#include "ui/widgets/mpselectionwidget.h" +#include "clientapp.h" + +#include +#include #include using namespace de; -DENG2_PIMPL_NOREF(ManualConnectionDialog) +DENG2_PIMPL(ManualConnectionDialog) +, DENG2_OBSERVES(ServerLink, DiscoveryUpdate) +, DENG2_OBSERVES(MPSelectionWidget, Selection) { String usedAddress; + FoldPanelWidget *fold; + MPSelectionWidget *games; + ProgressWidget *progress; + bool querying; + bool joinWhenEnterPressed; + + Instance(Public *i) + : Base(i) + , querying(false) + , joinWhenEnterPressed(false) + { + ClientApp::serverLink().audienceForDiscoveryUpdate += this; + } + + ~Instance() + { + ClientApp::serverLink().audienceForDiscoveryUpdate -= this; + } + + void linkDiscoveryUpdate(ServerLink const &link) + { + if(querying) + { + // Time to show what we found. + querying = false; + progress->setRotationSpeed(0); + self.editor().enable(); + self.validate(); + + if(link.foundServerCount(ServerLink::Direct) > 0) + { + progress->hide(); + fold->open(); + + if(link.foundServerCount(ServerLink::Direct) == 1) + { + joinWhenEnterPressed = true; + } + } + else + { + fold->close(0); + progress->setRotationSpeed(0); + progress->setText(_E(l) + tr("No response")); + progress->setOpacity(0, 4, 2); + } + } + } + + void gameSelected(serverinfo_t const &info) + { + self.setAcceptanceAction(new MPSelectionWidget::JoinAction(info)); + self.accept(); + } + + ButtonWidget &connectButton() + { + return self.buttonWidget(tr("Connect")); + } }; ManualConnectionDialog::ManualConnectionDialog(String const &name) - : InputDialog(name), d(new Instance) + : InputDialog(name), d(new Instance(this)) { + add(d->progress = new ProgressWidget); + d->progress->useMiniStyle("altaccent"); + d->progress->setWidthPolicy(ui::Expand); + d->progress->setTextAlignment(ui::AlignLeft); + d->progress->hide(); + + // The found games are shown inside a fold panel. + d->fold = new FoldPanelWidget; + d->games = new MPSelectionWidget(MPSelectionWidget::DirectDiscoveryOnly); + d->games->setJoinGameWhenSelected(false); + d->games->audienceForSelection += d; + d->games->setColumns(1); + d->games->rule().setInput(Rule::Width, rule().width() - margins().width()); + d->fold->setContent(d->games); + area().add(d->fold); + title().setText(tr("Connect to Server")); - message().setText(tr("Enter the address of the multiplayer server you want to connect to. " - "The address can be a domain name or an IP address. " + message().setText(tr("Enter the IP address or domain name of the multiplayer server you want to connect to. " "Optionally, you may include a TCP port number, for example " _E(b) "10.0.1.1:13209" _E(.) ".")); - defaultActionItem()->setLabel(tr("Connect")); - buttonWidget(tr("Connect")).disable(); + buttons().clear() + << new DialogButtonItem(Default, tr("Connect"), + new SignalAction(this, SLOT(queryOrConnect()))) + << new DialogButtonItem(Reject); + + d->connectButton().disable(); + d->progress->rule() + .setInput(Rule::Top, buttonsMenu().rule().top()) + .setInput(Rule::Right, buttonsMenu().rule().left()) + .setInput(Rule::Height, buttonsMenu().rule().height() - margins().bottom()); + + disconnect(&editor(), SIGNAL(enterPressed(QString)), this, SLOT(accept())); + connect(&editor(), SIGNAL(enterPressed(QString)), this, SLOT(queryOrConnect())); connect(&editor(), SIGNAL(editorContentChanged()), this, SLOT(validate())); + connect(&editor(), SIGNAL(editorContentChanged()), this, SLOT(contentChanged())); + + updateLayout(); } void ManualConnectionDialog::operator >> (PersistentState &toState) const @@ -53,17 +148,57 @@ void ManualConnectionDialog::operator << (PersistentState const &fromState) validate(); } +void ManualConnectionDialog::queryOrConnect() +{ + if(d->connectButton().isDisabled()) + { + // Should not try now. + return; + } + + if(!d->querying) + { + // Automatically connect if there is a single choice. + if(d->joinWhenEnterPressed) + { + d->gameSelected(d->games->serverInfo(0)); + return; + } + + d->joinWhenEnterPressed = false; + d->querying = true; + d->progress->setText(_E(l) + tr("Looking for host...")); + d->progress->setRotationSpeed(40); + d->progress->show(); + d->progress->setOpacity(1); + editor().disable(); + validate(); + + ClientApp::serverLink().discover(editor().text()); + } +} + +void ManualConnectionDialog::contentChanged() +{ + d->joinWhenEnterPressed = false; +} + void ManualConnectionDialog::validate() { bool valid = true; + if(d->querying) + { + valid = false; + } + if(editor().text().isEmpty() || editor().text().contains(';') || editor().text().endsWith(":") || editor().text().startsWith(":")) { valid = false; } - buttonWidget(tr("Connect")).enable(valid); + d->connectButton().enable(valid); } void ManualConnectionDialog::finish(int result) @@ -76,4 +211,3 @@ void ManualConnectionDialog::finish(int result) InputDialog::finish(result); } - diff --git a/doomsday/client/src/ui/widgets/taskbarwidget.cpp b/doomsday/client/src/ui/widgets/taskbarwidget.cpp index 7b1b66b363..549c1cac8a 100644 --- a/doomsday/client/src/ui/widgets/taskbarwidget.cpp +++ b/doomsday/client/src/ui/widgets/taskbarwidget.cpp @@ -720,11 +720,7 @@ void TaskBarWidget::connectToServerManually() { ManualConnectionDialog *dlg = new ManualConnectionDialog; dlg->setDeleteAfterDismissed(true); - if(dlg->exec(root())) - { - // Connect to the provided address. - Con_Executef(CMDS_DDAY, false, "connect %s", dlg->editor().text().toLatin1().constData()); - } + dlg->exec(root()); } void TaskBarWidget::updateCommandLineLayout() From 90209edd1a681bca6492b5765f09c6e0bef3707d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 19:41:34 +0200 Subject: [PATCH 50/60] Refactor|libdeng2: Pimpl-friendly audiences Defined a new set of audience macros that can be used in a pimpl friendly manner, i.e., without public member variables. They require adding accessor methods for the audiences, though (using new macros). Applied the pimpl idiom to Asset, Clock, File, and Variable. --- doomsday/libdeng2/include/de/core/app.h | 6 +- doomsday/libdeng2/include/de/core/asset.h | 7 +- doomsday/libdeng2/include/de/core/clock.h | 5 +- doomsday/libdeng2/include/de/core/loop.h | 2 +- doomsday/libdeng2/include/de/data/bank.h | 4 +- .../libdeng2/include/de/data/escapeparser.h | 4 +- doomsday/libdeng2/include/de/data/observers.h | 72 +++++++++ doomsday/libdeng2/include/de/data/property.h | 4 +- doomsday/libdeng2/include/de/data/record.h | 2 +- doomsday/libdeng2/include/de/data/variable.h | 21 ++- doomsday/libdeng2/include/de/filesys/file.h | 36 +---- doomsday/libdeng2/include/de/widgets/action.h | 7 +- doomsday/libdeng2/include/de/widgets/widget.h | 8 +- doomsday/libdeng2/src/core/app.cpp | 14 +- doomsday/libdeng2/src/core/asset.cpp | 47 ++++-- doomsday/libdeng2/src/core/clock.cpp | 24 ++- doomsday/libdeng2/src/core/logbuffer.cpp | 4 +- doomsday/libdeng2/src/core/loop.cpp | 6 +- .../src/core/monospacelogsinkformatter.cpp | 4 +- doomsday/libdeng2/src/core/textapp.cpp | 2 +- doomsday/libdeng2/src/data/bank.cpp | 17 ++- doomsday/libdeng2/src/data/escapeparser.cpp | 12 +- doomsday/libdeng2/src/data/record.cpp | 16 +- doomsday/libdeng2/src/data/recordvalue.cpp | 8 +- doomsday/libdeng2/src/data/refvalue.cpp | 4 +- doomsday/libdeng2/src/data/variable.cpp | 124 ++++++++++----- .../libdeng2/src/filesys/archiveentryfile.cpp | 4 +- doomsday/libdeng2/src/filesys/archivefeed.cpp | 6 +- doomsday/libdeng2/src/filesys/file.cpp | 141 +++++++++++++----- doomsday/libdeng2/src/filesys/folder.cpp | 4 +- doomsday/libdeng2/src/filesys/libraryfile.cpp | 4 +- doomsday/libdeng2/src/filesys/nativefile.cpp | 4 +- .../libdeng2/src/filesys/packagefolder.cpp | 4 +- doomsday/libdeng2/src/scriptsys/function.cpp | 4 +- .../libdeng2/src/scriptsys/scriptsystem.cpp | 4 +- doomsday/libdeng2/src/widgets/action.cpp | 12 +- doomsday/libdeng2/src/widgets/widget.cpp | 22 ++- 37 files changed, 457 insertions(+), 212 deletions(-) diff --git a/doomsday/libdeng2/include/de/core/app.h b/doomsday/libdeng2/include/de/core/app.h index 8ed456c5c7..db3c5db033 100644 --- a/doomsday/libdeng2/include/de/core/app.h +++ b/doomsday/libdeng2/include/de/core/app.h @@ -69,17 +69,17 @@ class DENG2_PUBLIC App : DENG2_OBSERVES(Clock, TimeChange) /** * Notified when application startup has been fully completed. */ - DENG2_DEFINE_AUDIENCE(StartupComplete, void appStartupCompleted()) + DENG2_DEFINE_AUDIENCE2(StartupComplete, void appStartupCompleted()) /** * Notified before the current game is unloaded. */ - DENG2_DEFINE_AUDIENCE(GameUnload, void aboutToUnloadGame(game::Game const &gameBeingUnloaded)) + DENG2_DEFINE_AUDIENCE2(GameUnload, void aboutToUnloadGame(game::Game const &gameBeingUnloaded)) /** * Notified after the current game has been changed. */ - DENG2_DEFINE_AUDIENCE(GameChange, void currentGameChanged(game::Game const &newGame)) + DENG2_DEFINE_AUDIENCE2(GameChange, void currentGameChanged(game::Game const &newGame)) public: /** diff --git a/doomsday/libdeng2/include/de/core/asset.h b/doomsday/libdeng2/include/de/core/asset.h index eec86d9913..ec782f5dc8 100644 --- a/doomsday/libdeng2/include/de/core/asset.h +++ b/doomsday/libdeng2/include/de/core/asset.h @@ -51,15 +51,16 @@ class DENG2_PUBLIC Asset /** * Notified whenever the state of the asset changes. */ - DENG2_DEFINE_AUDIENCE(StateChange, void assetStateChanged(Asset &)) + DENG2_DEFINE_AUDIENCE2(StateChange, void assetStateChanged(Asset &)) /** * Notified when the asset is destroyed. */ - DENG2_DEFINE_AUDIENCE(Deletion, void assetDeleted(Asset &)) + DENG2_DEFINE_AUDIENCE2(Deletion, void assetDeleted(Asset &)) public: Asset(State initialState = NotReady); + Asset(Asset const &other); virtual ~Asset(); void setState(State s); @@ -72,7 +73,7 @@ class DENG2_PUBLIC Asset virtual bool isReady() const; private: - State _state; + DENG2_PRIVATE(d) }; /** diff --git a/doomsday/libdeng2/include/de/core/clock.h b/doomsday/libdeng2/include/de/core/clock.h index 57bf0bd3a1..87e06b24a6 100644 --- a/doomsday/libdeng2/include/de/core/clock.h +++ b/doomsday/libdeng2/include/de/core/clock.h @@ -36,7 +36,7 @@ class DENG2_PUBLIC Clock * Notified whenever the time of the clock changes. The audience members * will be notified in unspecified order. */ - DENG2_DEFINE_AUDIENCE(TimeChange, void timeChanged(Clock const &)) + DENG2_DEFINE_AUDIENCE2(TimeChange, void timeChanged(Clock const &)) /** * Notified whenever the time of the clock changes. The entire priority @@ -73,8 +73,7 @@ class DENG2_PUBLIC Clock static Time const &appTime(); private: - Time _startedAt; - Time _time; + DENG2_PRIVATE(d) static Clock *_appClock; }; diff --git a/doomsday/libdeng2/include/de/core/loop.h b/doomsday/libdeng2/include/de/core/loop.h index a4932244a5..27d9df7d0f 100644 --- a/doomsday/libdeng2/include/de/core/loop.h +++ b/doomsday/libdeng2/include/de/core/loop.h @@ -39,7 +39,7 @@ class DENG2_PUBLIC Loop : public QObject /** * Audience to be notified each time the loop iterates. */ - DENG2_DEFINE_AUDIENCE(Iteration, void loopIteration()) + DENG2_DEFINE_AUDIENCE2(Iteration, void loopIteration()) public: /** diff --git a/doomsday/libdeng2/include/de/data/bank.h b/doomsday/libdeng2/include/de/data/bank.h index 84529de04e..4b1d1df0a7 100644 --- a/doomsday/libdeng2/include/de/data/bank.h +++ b/doomsday/libdeng2/include/de/data/bank.h @@ -176,13 +176,13 @@ class DENG2_PUBLIC Bank * Notified when a data item has been loaded to memory (cache level * InMemory). May be called from the background thread, if one is running. */ - DENG2_DEFINE_AUDIENCE(Load, void bankLoaded(DotPath const &path)) + DENG2_DEFINE_AUDIENCE2(Load, void bankLoaded(DotPath const &path)) /** * Notified when a data item's cache level changes (in addition to the Load * notification). */ - DENG2_DEFINE_AUDIENCE(CacheLevel, void bankCacheLevelChanged(DotPath const &path, CacheLevel level)) + DENG2_DEFINE_AUDIENCE2(CacheLevel, void bankCacheLevelChanged(DotPath const &path, CacheLevel level)) public: /** diff --git a/doomsday/libdeng2/include/de/data/escapeparser.h b/doomsday/libdeng2/include/de/data/escapeparser.h index 4dcb0cd0c9..f606bba1c6 100644 --- a/doomsday/libdeng2/include/de/data/escapeparser.h +++ b/doomsday/libdeng2/include/de/data/escapeparser.h @@ -38,7 +38,7 @@ class DENG2_PUBLIC EscapeParser * * @param range Range in the original text. */ - DENG2_DEFINE_AUDIENCE(PlainText, void handlePlainText(Rangei const &range)) + DENG2_DEFINE_AUDIENCE2(PlainText, void handlePlainText(Rangei const &range)) /** * Called during parsing when an escape sequence has been parsed. @@ -46,7 +46,7 @@ class DENG2_PUBLIC EscapeParser * * @param range Range in the original text. */ - DENG2_DEFINE_AUDIENCE(EscapeSequence, void handleEscapeSequence(Rangei const &range)) + DENG2_DEFINE_AUDIENCE2(EscapeSequence, void handleEscapeSequence(Rangei const &range)) public: EscapeParser(); diff --git a/doomsday/libdeng2/include/de/data/observers.h b/doomsday/libdeng2/include/de/data/observers.h index dee0ea4ade..9c06c404da 100644 --- a/doomsday/libdeng2/include/de/data/observers.h +++ b/doomsday/libdeng2/include/de/data/observers.h @@ -61,6 +61,24 @@ typedef de::Observers Name##Audience; \ extern Name##Audience audienceFor##Name; +#define DENG2_DECLARE_AUDIENCE_METHOD(Name) \ + typedef de::Observers Name##Audience; \ + Name##Audience &audienceFor##Name(); \ + Name##Audience const &audienceFor##Name() const; + +#define DENG2_AUDIENCE_METHOD(ClassName, Name) \ + ClassName::Name##Audience &ClassName::audienceFor##Name() { return d->audienceFor##Name; } \ + ClassName::Name##Audience const &ClassName::audienceFor##Name() const { return d->audienceFor##Name; } + +#define DENG2_AUDIENCE_METHOD_INLINE(Name) \ + typedef de::Observers Name##Audience; \ + Name##Audience _audienceFor##Name; \ + Name##Audience &audienceFor##Name() { return _audienceFor##Name; } \ + Name##Audience const &audienceFor##Name() const { return _audienceFor##Name; } + +#define DENG2_PIMPL_AUDIENCE(Name) \ + Name##Audience audienceFor##Name; + /** * Macro for defining an observer interface containing a single method. * @@ -73,6 +91,14 @@ DENG2_DECLARE_AUDIENCE(Name, Method) \ DENG2_AUDIENCE(Name) +#define DENG2_DEFINE_AUDIENCE2(Name, Method) \ + DENG2_DECLARE_AUDIENCE(Name, Method) \ + DENG2_DECLARE_AUDIENCE_METHOD(Name) + +#define DENG2_DEFINE_AUDIENCE_INLINE(Name, Method) \ + DENG2_DECLARE_AUDIENCE(Name, Method) \ + DENG2_AUDIENCE_METHOD_INLINE(Name) + /** * Macro that can be used in class declarations to specify which audiences the class * can belong to. @@ -101,6 +127,9 @@ #define DENG2_FOR_AUDIENCE(Name, Var) \ DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name) +#define DENG2_FOR_AUDIENCE2(Name, Var) \ + DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name()) + /** * Macro for looping through the public audience members from inside a private * implementation. @@ -111,12 +140,55 @@ #define DENG2_FOR_PUBLIC_AUDIENCE(Name, Var) \ DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, self.audienceFor##Name) +#define DENG2_FOR_PUBLIC_AUDIENCE2(Name, Var) \ + DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name) + namespace de { /** * Template for observer sets. The template type should be an interface * implemented by all the observers. @ingroup data * + * @par How to use the non-pimpl audience macros + * + * These examples explain how to create an audience called "Deletion". In general, + * audience names should be nouns like this so they can be used in the form + * "audience for (something)". + * + * In a class declaration, define the audience in the @c public section of the class: + *
DENG2_DEFINE_AUDIENCE(Deletion, ...interface-function...)
+ * + * This will generate a public member variable called @c audienceForDeletion that + * can be directly manipulated by other objects. + * + * Note that because the audience is created as a public member variable, this can + * easily lead to ABI backwards compatibility issues down the road if there is + * need to make changes to the class. + * + * @par How to use the pimpl audience macros + * + * Another set of macros is provided for declaring and defining a pimpl-friendly + * audience. The caveat is that you'll need to separately declare accessor methods + * and define the audience inside the private implementation of the class. + * + * First, define the audience in the @c public section of the class: + *
DENG2_DEFINE_AUDIENCE2(Deletion, ...interface-function...)
+ * + * This works like DENG2_DEFINE_AUDIENCE, but without a public member variable. + * Instead, accessor methods are declared for accessing the audience. + * + * Then, inside the private implementation (@c Instance struct), define the audience: + *
DENG2_PIMPL_AUDIENCE(Deletion)
+ * + * Finally, define the accessor methods (for instance, just before the constructor + * of the class): + *
DENG2_AUDIENCE_METHOD(ClassName, Deletion)
+ * + * It is recommended to keep the DENG2_PIMPL_AUDIENCE and DENG2_AUDIENCE_METHOD + * macros close together in the source file for easier maintenance. The former + * could be at the end of the @c Instance struct while the latter is immediately + * following the struct. + * * @par Thread-safety * * Observers and Observers::Loop lock the observer set separately for reading diff --git a/doomsday/libdeng2/include/de/data/property.h b/doomsday/libdeng2/include/de/data/property.h index fc04d818e4..7204d4ab55 100644 --- a/doomsday/libdeng2/include/de/data/property.h +++ b/doomsday/libdeng2/include/de/data/property.h @@ -69,12 +69,12 @@ class BaseProperty void setValue(ValueType const &v) { \ if(_value == v) return; \ _value = v; \ - DENG2_FOR_AUDIENCE(Change, i) i->valueOf ## PropName ## Changed(); \ + DENG2_FOR_AUDIENCE2(Change, i) i->valueOf ## PropName ## Changed(); \ } \ PropName &operator = (ValueType const &v) { setValue(v); return *this; } \ PropName &operator += (ValueType const &v) { setValue(_value + v); return *this; } \ PropName &operator -= (ValueType const &v) { setValue(_value - v); return *this; } \ - DENG2_DEFINE_AUDIENCE(Change, void valueOf ## PropName ## Changed()) \ + DENG2_DEFINE_AUDIENCE_INLINE(Change, void valueOf ## PropName ## Changed()) \ }; #define DENG2_PROPERTY(PropName, ValueType) \ diff --git a/doomsday/libdeng2/include/de/data/record.h b/doomsday/libdeng2/include/de/data/record.h index 625733fcb4..232eae6ffd 100644 --- a/doomsday/libdeng2/include/de/data/record.h +++ b/doomsday/libdeng2/include/de/data/record.h @@ -63,7 +63,7 @@ class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base, typedef std::pair KeyValue; typedef QList List; - DENG2_DEFINE_AUDIENCE(Deletion, void recordBeingDeleted(Record &record)) + DENG2_DEFINE_AUDIENCE2(Deletion, void recordBeingDeleted(Record &record)) public: Record(); diff --git a/doomsday/libdeng2/include/de/data/variable.h b/doomsday/libdeng2/include/de/data/variable.h index 0fc5d6e962..212558cfbd 100644 --- a/doomsday/libdeng2/include/de/data/variable.h +++ b/doomsday/libdeng2/include/de/data/variable.h @@ -126,7 +126,7 @@ class DENG2_PUBLIC Variable : public ISerializable /** * Returns the name of the variable. */ - String const &name() const { return _name; } + String const &name() const; /** * Sets the value of the variable. @@ -159,12 +159,15 @@ class DENG2_PUBLIC Variable : public ISerializable */ Value &value(); + Value *valuePtr(); + Value const *valuePtr() const; + /** * Returns the value of the variable. */ template Type &value() { - Type *v = dynamic_cast(_value); + Type *v = dynamic_cast(valuePtr()); if(!v) { /// @throw TypeError Casting to Type failed. throw TypeError("Variable::value", @@ -193,7 +196,7 @@ class DENG2_PUBLIC Variable : public ISerializable */ template Type const &value() const { - Type const *v = dynamic_cast(_value); + Type const *v = dynamic_cast(valuePtr()); if(!v) { /// @throw TypeError Casting to Type failed. throw TypeError("Variable::value", @@ -265,7 +268,7 @@ class DENG2_PUBLIC Variable : public ISerializable * * @param variable Variable. */ - DENG2_DEFINE_AUDIENCE(Deletion, void variableBeingDeleted(Variable &variable)) + DENG2_DEFINE_AUDIENCE2(Deletion, void variableBeingDeleted(Variable &variable)) /** * The value of the variable has changed. @@ -273,16 +276,10 @@ class DENG2_PUBLIC Variable : public ISerializable * @param variable Variable. * @param newValue New value of the variable. */ - DENG2_DEFINE_AUDIENCE(Change, void variableValueChanged(Variable &variable, Value const &newValue)) + DENG2_DEFINE_AUDIENCE2(Change, void variableValueChanged(Variable &variable, Value const &newValue)) private: - String _name; - - /// Value of the variable. - Value *_value; - - /// Mode flags. - Flags _mode; + DENG2_PRIVATE(d) }; Q_DECLARE_OPERATORS_FOR_FLAGS(Variable::Flags) diff --git a/doomsday/libdeng2/include/de/filesys/file.h b/doomsday/libdeng2/include/de/filesys/file.h index 630ca84d55..7982b81d52 100644 --- a/doomsday/libdeng2/include/de/filesys/file.h +++ b/doomsday/libdeng2/include/de/filesys/file.h @@ -82,7 +82,7 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream * * @param file The file object being deleted. */ - DENG2_DEFINE_AUDIENCE(Deletion, void fileBeingDeleted(File const &file)) + DENG2_DEFINE_AUDIENCE2(Deletion, void fileBeingDeleted(File const &file)) /** * Stores the status of a file (size, time of last modification). @@ -187,7 +187,7 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream static FileSystem &fileSystem(); /// Returns the name of the file. - String const &name() const { return _name; } + String const &name() const; /** * Returns a textual description of the file, intended only for humans. @@ -210,12 +210,12 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream /** * Sets the parent folder of this file. */ - void setParent(Folder *parent) { _parent = parent; } + void setParent(Folder *parent); /** * Returns the parent folder. May be NULL. */ - Folder *parent() const { return _parent; } + Folder *parent() const; /** * Sets the origin Feed of the File. The origin feed is the feed that is able @@ -233,7 +233,7 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream * Returns the origin Feed of the File. * @see setOriginFeed() */ - Feed *originFeed() const { return _originFeed; } + Feed *originFeed() const; /** * Sets the source file of this file. The source is where this file is @@ -306,10 +306,10 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream virtual void setMode(Flags const &newMode); /// Returns the file information (const). - Record const &info() const { return _info; } + Record const &info() const; /// Returns the file information. - Record &info() { return _info; } + Record &info(); /** * Makes sure that the file has write access. @@ -333,27 +333,7 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream explicit File(String const &name = ""); private: - /// The parent folder. - Folder *_parent; - - /// The source file (NULL for non-interpreted files). - File *_source; - - /// Feed that generated the file. This feed is called upon when the file needs - /// to be pruned. May also be NULL. - Feed *_originFeed; - - /// Name of the file. - String _name; - - /// Status of the file. - Status _status; - - /// Mode flags. - Flags _mode; - - /// File information. - Record _info; + DENG2_PRIVATE(d) }; Q_DECLARE_OPERATORS_FOR_FLAGS(File::Flags) diff --git a/doomsday/libdeng2/include/de/widgets/action.h b/doomsday/libdeng2/include/de/widgets/action.h index e353e7a58b..287a09d3b3 100644 --- a/doomsday/libdeng2/include/de/widgets/action.h +++ b/doomsday/libdeng2/include/de/widgets/action.h @@ -39,7 +39,9 @@ class DENG2_PUBLIC Action : public Counted /** * Audience to be notified when the action is triggerd. */ - DENG2_DEFINE_AUDIENCE(Triggered, void actionTriggered(Action &)) + DENG2_DEFINE_AUDIENCE2(Triggered, void actionTriggered(Action &)) + + Action(); /** * Perform the action this instance represents. Derived classes must call @@ -52,6 +54,9 @@ class DENG2_PUBLIC Action : public Counted protected: virtual ~Action(); // ref counted, hence not publicly deletable + +private: + DENG2_PRIVATE(d) }; } // namespace de diff --git a/doomsday/libdeng2/include/de/widgets/widget.h b/doomsday/libdeng2/include/de/widgets/widget.h index eef4b5319b..ac532f5684 100644 --- a/doomsday/libdeng2/include/de/widgets/widget.h +++ b/doomsday/libdeng2/include/de/widgets/widget.h @@ -85,22 +85,22 @@ class DENG2_PUBLIC Widget /** * Notified when the widget is about to be deleted. */ - DENG2_DEFINE_AUDIENCE(Deletion, void widgetBeingDeleted(Widget &widget)) + DENG2_DEFINE_AUDIENCE2(Deletion, void widgetBeingDeleted(Widget &widget)) /** * Notified when the widget's parent changes. */ - DENG2_DEFINE_AUDIENCE(ParentChange, void widgetParentChanged(Widget &child, Widget *oldParent, Widget *newParent)) + DENG2_DEFINE_AUDIENCE2(ParentChange, void widgetParentChanged(Widget &child, Widget *oldParent, Widget *newParent)) /** * Notified when a child is added to the widget. */ - DENG2_DEFINE_AUDIENCE(ChildAddition, void widgetChildAdded(Widget &child)) + DENG2_DEFINE_AUDIENCE2(ChildAddition, void widgetChildAdded(Widget &child)) /** * Notified after a child has been removed from the widget. */ - DENG2_DEFINE_AUDIENCE(ChildRemoval, void widgetChildRemoved(Widget &child)) + DENG2_DEFINE_AUDIENCE2(ChildRemoval, void widgetChildRemoved(Widget &child)) public: Widget(String const &name = ""); diff --git a/doomsday/libdeng2/src/core/app.cpp b/doomsday/libdeng2/src/core/app.cpp index fc6ac798ce..f323b09762 100644 --- a/doomsday/libdeng2/src/core/app.cpp +++ b/doomsday/libdeng2/src/core/app.cpp @@ -136,12 +136,12 @@ DENG2_PIMPL(App) appModule.addArray("audienceForGameChange"); // game change observers scriptSys.addNativeModule("App", appModule); - self.audienceForGameChange += scriptAudienceForGameChange; + audienceForGameChange += scriptAudienceForGameChange; } ~Instance() { - clock.audienceForTimeChange -= self; + clock.audienceForTimeChange() -= self; if(config) { @@ -252,8 +252,16 @@ DENG2_PIMPL(App) logFilter.setAllowDev(LogEntry::AllDomains, false); } } + + DENG2_PIMPL_AUDIENCE(StartupComplete) + DENG2_PIMPL_AUDIENCE(GameUnload) + DENG2_PIMPL_AUDIENCE(GameChange) }; +DENG2_AUDIENCE_METHOD(App, StartupComplete) +DENG2_AUDIENCE_METHOD(App, GameUnload) +DENG2_AUDIENCE_METHOD(App, GameChange) + App::App(NativePath const &appFilePath, QStringList args) : d(new Instance(this, args)) { @@ -560,7 +568,7 @@ void App::initSubsystems(SubsystemInitFlags flags) d->clock.setTime(Time::currentHighPerformanceTime()); // Now we can start observing progress of time. - d->clock.audienceForTimeChange += this; + d->clock.audienceForTimeChange() += this; LOG_VERBOSE("libdeng2::App %s subsystems initialized.") << Version().asText(); } diff --git a/doomsday/libdeng2/src/core/asset.cpp b/doomsday/libdeng2/src/core/asset.cpp index 49164ed71f..b6312ebb07 100644 --- a/doomsday/libdeng2/src/core/asset.cpp +++ b/doomsday/libdeng2/src/core/asset.cpp @@ -20,21 +20,38 @@ namespace de { -Asset::Asset(State initialState) : _state(initialState) +DENG2_PIMPL_NOREF(Asset) +{ + State state; + + Instance(State s) : state(s) {} + Instance(Instance const &other) : state(other.state) {} + + DENG2_PIMPL_AUDIENCE(StateChange) + DENG2_PIMPL_AUDIENCE(Deletion) +}; + +DENG2_AUDIENCE_METHOD(Asset, StateChange) +DENG2_AUDIENCE_METHOD(Asset, Deletion) + +Asset::Asset(State initialState) : d(new Instance(initialState)) +{} + +Asset::Asset(Asset const &other) : d(new Instance(*other.d)) {} Asset::~Asset() { - DENG2_FOR_AUDIENCE(Deletion, i) i->assetDeleted(*this); + DENG2_FOR_AUDIENCE2(Deletion, i) i->assetDeleted(*this); } void Asset::setState(State s) { - State old = _state; - _state = s; - if(old != _state) + State old = d->state; + d->state = s; + if(old != d->state) { - DENG2_FOR_AUDIENCE(StateChange, i) i->assetStateChanged(*this); + DENG2_FOR_AUDIENCE2(StateChange, i) i->assetStateChanged(*this); } } @@ -45,12 +62,12 @@ void Asset::setState(bool assetReady) Asset::State Asset::state() const { - return _state; + return d->state; } bool Asset::isReady() const { - return _state == Ready; + return d->state == Ready; } //---------------------------------------------------------------------------- @@ -95,7 +112,7 @@ AssetGroup::AssetGroup() : d(new Instance) AssetGroup::~AssetGroup() { // We are about to be deleted. - audienceForStateChange.clear(); + audienceForStateChange().clear(); clear(); } @@ -109,8 +126,8 @@ void AssetGroup::clear() { DENG2_FOR_EACH(Members, i, d->deps) { - i->first->audienceForDeletion -= this; - i->first->audienceForStateChange -= this; + i->first->audienceForDeletion() -= this; + i->first->audienceForStateChange() -= this; } d->deps.clear(); @@ -120,15 +137,15 @@ void AssetGroup::clear() void AssetGroup::insert(Asset const &asset, Policy policy) { d->deps[&asset] = policy; - asset.audienceForDeletion += this; - asset.audienceForStateChange += this; + asset.audienceForDeletion() += this; + asset.audienceForStateChange() += this; d->update(*this); } void AssetGroup::remove(Asset const &asset) { - asset.audienceForDeletion -= this; - asset.audienceForStateChange -= this; + asset.audienceForDeletion() -= this; + asset.audienceForStateChange() -= this; d->deps.erase(&asset); d->update(*this); } diff --git a/doomsday/libdeng2/src/core/clock.cpp b/doomsday/libdeng2/src/core/clock.cpp index 381317c17a..0d9ac59e07 100644 --- a/doomsday/libdeng2/src/core/clock.cpp +++ b/doomsday/libdeng2/src/core/clock.cpp @@ -20,9 +20,19 @@ namespace de { +DENG2_PIMPL_NOREF(Clock) +{ + Time startedAt; + Time time; + + DENG2_PIMPL_AUDIENCE(TimeChange) +}; + +DENG2_AUDIENCE_METHOD(Clock, TimeChange) + Clock *Clock::_appClock = 0; -Clock::Clock() +Clock::Clock() : d(new Instance) {} Clock::~Clock() @@ -30,9 +40,9 @@ Clock::~Clock() void Clock::setTime(Time const ¤tTime) { - bool changed = (_time != currentTime); + bool changed = (d->time != currentTime); - _time = currentTime; + d->time = currentTime; if(changed) { @@ -40,23 +50,23 @@ void Clock::setTime(Time const ¤tTime) { i->timeChanged(*this); } - DENG2_FOR_AUDIENCE(TimeChange, i) i->timeChanged(*this); + DENG2_FOR_AUDIENCE2(TimeChange, i) i->timeChanged(*this); } } void Clock::advanceTime(TimeDelta const &span) { - setTime(_time + span); + setTime(d->time + span); } TimeDelta Clock::elapsed() const { - return _time - _startedAt; + return d->time - d->startedAt; } Time const &Clock::time() const { - return _time; + return d->time; } void Clock::setAppClock(Clock *c) diff --git a/doomsday/libdeng2/src/core/logbuffer.cpp b/doomsday/libdeng2/src/core/logbuffer.cpp index 2bd0e6cbbe..e77aade084 100644 --- a/doomsday/libdeng2/src/core/logbuffer.cpp +++ b/doomsday/libdeng2/src/core/logbuffer.cpp @@ -230,7 +230,7 @@ void LogBuffer::setOutputFile(String const &path) if(d->outputFile) { - d->outputFile->audienceForDeletion -= this; + d->outputFile->audienceForDeletion() -= this; d->outputFile = 0; } @@ -238,7 +238,7 @@ void LogBuffer::setOutputFile(String const &path) { d->outputFile = &App::rootFolder().replaceFile(path); d->outputFile->setMode(File::Write); - d->outputFile->audienceForDeletion += this; + d->outputFile->audienceForDeletion() += this; // Add a sink for the file. d->fileLogSink = new FileLogSink(*d->outputFile); diff --git a/doomsday/libdeng2/src/core/loop.cpp b/doomsday/libdeng2/src/core/loop.cpp index 5bac69d247..456186f34c 100644 --- a/doomsday/libdeng2/src/core/loop.cpp +++ b/doomsday/libdeng2/src/core/loop.cpp @@ -50,8 +50,12 @@ DENG2_PIMPL(Loop) { loopSingleton = 0; } + + DENG2_PIMPL_AUDIENCE(Iteration) }; +DENG2_AUDIENCE_METHOD(Loop, Iteration) + Loop::Loop() : d(new Instance(this)) {} @@ -102,7 +106,7 @@ void Loop::nextLoopIteration() { if(d->running) { - DENG2_FOR_AUDIENCE(Iteration, i) i->loopIteration(); + DENG2_FOR_AUDIENCE2(Iteration, i) i->loopIteration(); } } catch(Error const &er) diff --git a/doomsday/libdeng2/src/core/monospacelogsinkformatter.cpp b/doomsday/libdeng2/src/core/monospacelogsinkformatter.cpp index d11f5b7ac8..4df429fb24 100644 --- a/doomsday/libdeng2/src/core/monospacelogsinkformatter.cpp +++ b/doomsday/libdeng2/src/core/monospacelogsinkformatter.cpp @@ -40,8 +40,8 @@ struct TabFiller TabFiller(String const &text) : hasTabs(false) { - esc.audienceForPlainText += this; - esc.audienceForEscapeSequence += this; + esc.audienceForPlainText() += this; + esc.audienceForEscapeSequence() += this; // Break the entire message into lines, excluding all escape codes // except for tabs. diff --git a/doomsday/libdeng2/src/core/textapp.cpp b/doomsday/libdeng2/src/core/textapp.cpp index f908bbbc82..55b504a335 100644 --- a/doomsday/libdeng2/src/core/textapp.cpp +++ b/doomsday/libdeng2/src/core/textapp.cpp @@ -29,7 +29,7 @@ DENG2_PIMPL(TextApp) Instance(Public *i) : Base(i) { - loop.audienceForIteration += self; + loop.audienceForIteration() += self; // In text-based apps, we can limit the loop frequency. loop.setRate(35); diff --git a/doomsday/libdeng2/src/data/bank.cpp b/doomsday/libdeng2/src/data/bank.cpp index ceadea9b78..22bf2bfaa3 100644 --- a/doomsday/libdeng2/src/data/bank.cpp +++ b/doomsday/libdeng2/src/data/bank.cpp @@ -111,6 +111,7 @@ class Cache : public Lockable } // namespace internal + DENG2_PIMPL(Bank), DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via main Loop { @@ -545,7 +546,7 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai ~Instance() { - Loop::appLoop().audienceForIteration -= this; + Loop::appLoop().audienceForIteration() -= this; destroySerialCache(); } @@ -669,13 +670,13 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai notifications.put(new Notification(notif)); if(isThreaded()) { - Loop::appLoop().audienceForIteration += this; + Loop::appLoop().audienceForIteration() += this; } } void loopIteration() { - Loop::appLoop().audienceForIteration -= this; + Loop::appLoop().audienceForIteration() -= this; performNotifications(); } @@ -695,14 +696,14 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai switch(nt.kind) { case Notification::Loaded: - DENG2_FOR_PUBLIC_AUDIENCE(Load, i) + DENG2_FOR_PUBLIC_AUDIENCE2(Load, i) { i->bankLoaded(nt.path); } break; case Notification::CacheChanged: - DENG2_FOR_PUBLIC_AUDIENCE(CacheLevel, i) + DENG2_FOR_PUBLIC_AUDIENCE2(CacheLevel, i) { DENG2_ASSERT(nt.cache != 0); @@ -714,8 +715,14 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai break; } } + + DENG2_PIMPL_AUDIENCE(Load) + DENG2_PIMPL_AUDIENCE(CacheLevel) }; +DENG2_AUDIENCE_METHOD(Bank, Load) +DENG2_AUDIENCE_METHOD(Bank, CacheLevel) + Bank::Bank(Flags const &flags, String const &hotStorageLocation) : d(new Instance(this, flags)) { diff --git a/doomsday/libdeng2/src/data/escapeparser.cpp b/doomsday/libdeng2/src/data/escapeparser.cpp index 2305015a96..afd59709b9 100644 --- a/doomsday/libdeng2/src/data/escapeparser.cpp +++ b/doomsday/libdeng2/src/data/escapeparser.cpp @@ -24,8 +24,14 @@ DENG2_PIMPL_NOREF(EscapeParser) { String original; String plain; + + DENG2_PIMPL_AUDIENCE(PlainText) + DENG2_PIMPL_AUDIENCE(EscapeSequence) }; +DENG2_AUDIENCE_METHOD(EscapeParser, PlainText) +DENG2_AUDIENCE_METHOD(EscapeParser, EscapeSequence) + EscapeParser::EscapeParser() : d(new Instance) {} @@ -44,7 +50,7 @@ void EscapeParser::parse(String const &textWithEscapes) // Empty ranges are ignored. if(range.size() > 0) { - DENG2_FOR_AUDIENCE(PlainText, i) + DENG2_FOR_AUDIENCE2(PlainText, i) { i->handlePlainText(range); } @@ -75,7 +81,7 @@ void EscapeParser::parse(String const &textWithEscapes) break; } - DENG2_FOR_AUDIENCE(EscapeSequence, i) + DENG2_FOR_AUDIENCE2(EscapeSequence, i) { i->handleEscapeSequence(Rangei(range.end + 1, range.end + escLen)); } @@ -89,7 +95,7 @@ void EscapeParser::parse(String const &textWithEscapes) range.end = d->original.size(); if(range.size() > 0) { - DENG2_FOR_AUDIENCE(PlainText, i) + DENG2_FOR_AUDIENCE2(PlainText, i) { i->handlePlainText(range); } diff --git a/doomsday/libdeng2/src/data/record.cpp b/doomsday/libdeng2/src/data/record.cpp index 95d9bc4ab7..18211a6288 100644 --- a/doomsday/libdeng2/src/data/record.cpp +++ b/doomsday/libdeng2/src/data/record.cpp @@ -170,8 +170,12 @@ DENG2_PIMPL(Record) } } } + + DENG2_PIMPL_AUDIENCE(Deletion) }; +DENG2_AUDIENCE_METHOD(Record, Deletion) + Record::Record() : d(new Instance(*this)) {} @@ -184,7 +188,7 @@ Record::Record(Record const &other) Record::~Record() { - DENG2_FOR_AUDIENCE(Deletion, i) i->recordBeingDeleted(*this); + DENG2_FOR_AUDIENCE2(Deletion, i) i->recordBeingDeleted(*this); clear(); } @@ -194,7 +198,7 @@ void Record::clear() { DENG2_FOR_EACH(Members, i, d->members) { - i.value()->audienceForDeletion -= this; + i.value()->audienceForDeletion() -= this; delete i.value(); } d->members.clear(); @@ -209,7 +213,7 @@ void Record::copyMembersFrom(Record const &other, CopyBehavior behavior) i.key().startsWith("__")) continue; Variable *var = new Variable(*i.value()); - var->audienceForDeletion += this; + var->audienceForDeletion() += this; d->members[i.key()] = var; } } @@ -254,14 +258,14 @@ Variable &Record::add(Variable *variable) // Delete the previous variable with this name. delete d->members[variable->name()]; } - var->audienceForDeletion += this; + var->audienceForDeletion() += this; d->members[variable->name()] = var.release(); return *variable; } Variable *Record::remove(Variable &variable) { - variable.audienceForDeletion -= this; + variable.audienceForDeletion() -= this; d->members.remove(variable.name()); return &variable; } @@ -565,7 +569,7 @@ void Record::operator << (Reader &from) // Observe all members for deletion. DENG2_FOR_EACH(Members, i, d->members) { - i.value()->audienceForDeletion += this; + i.value()->audienceForDeletion() += this; } } diff --git a/doomsday/libdeng2/src/data/recordvalue.cpp b/doomsday/libdeng2/src/data/recordvalue.cpp index e92bed2f15..eb5856a675 100644 --- a/doomsday/libdeng2/src/data/recordvalue.cpp +++ b/doomsday/libdeng2/src/data/recordvalue.cpp @@ -36,7 +36,7 @@ RecordValue::RecordValue(Record *record, OwnershipFlags o) if(!_ownership.testFlag(OwnsRecord)) { // If we don't own it, someone may delete the record. - _record->audienceForDeletion += this; + _record->audienceForDeletion() += this; } } @@ -44,7 +44,7 @@ RecordValue::RecordValue(Record &record) : _record(&record), _ownership(0), _oldOwnership(0) { // Someone may delete the record. - _record->audienceForDeletion += this; + _record->audienceForDeletion() += this; } RecordValue::~RecordValue() @@ -72,7 +72,7 @@ void RecordValue::setRecord(Record *record) } else if(_record) { - _record->audienceForDeletion -= this; + _record->audienceForDeletion() -= this; } _record = record; @@ -81,7 +81,7 @@ void RecordValue::setRecord(Record *record) if(_record) { // Since we don't own it, someone may delete the record. - _record->audienceForDeletion += this; + _record->audienceForDeletion() += this; } } diff --git a/doomsday/libdeng2/src/data/refvalue.cpp b/doomsday/libdeng2/src/data/refvalue.cpp index ef1d8de1cb..5f2a431c02 100644 --- a/doomsday/libdeng2/src/data/refvalue.cpp +++ b/doomsday/libdeng2/src/data/refvalue.cpp @@ -27,7 +27,7 @@ RefValue::RefValue(Variable *variable) : _variable(variable) { if(_variable) { - _variable->audienceForDeletion.add(this); + _variable->audienceForDeletion() += this; } } @@ -35,7 +35,7 @@ RefValue::~RefValue() { if(_variable) { - _variable->audienceForDeletion.remove(this); + _variable->audienceForDeletion() -= this; } } diff --git a/doomsday/libdeng2/src/data/variable.cpp b/doomsday/libdeng2/src/data/variable.cpp index ef1dd483f8..92a979aebd 100644 --- a/doomsday/libdeng2/src/data/variable.cpp +++ b/doomsday/libdeng2/src/data/variable.cpp @@ -31,29 +31,67 @@ #include "de/Writer" #include "de/Log" -using namespace de; +namespace de { + +DENG2_PIMPL_NOREF(Variable) +{ + String name; + + /// Value of the variable. + Value *value; + + /// Mode flags. + Flags mode; + + Instance() : value(0) {} + + Instance(Instance const &other) + : name (other.name) + , value(other.value->duplicate()) + , mode (other.mode) + {} + + ~Instance() + { + delete value; + } + + DENG2_PIMPL_AUDIENCE(Deletion) + DENG2_PIMPL_AUDIENCE(Change) +}; + +DENG2_AUDIENCE_METHOD(Variable, Deletion) +DENG2_AUDIENCE_METHOD(Variable, Change) Variable::Variable(String const &name, Value *initial, Flags const &m) - : _name(name), _value(0), _mode(m) + : d(new Instance) { + d->name = name; + d->mode = m; + std::auto_ptr v(initial); if(!initial) { v.reset(new NoneValue); } - verifyName(_name); + verifyName(d->name); verifyValid(*v); - _value = v.release(); + d->value = v.release(); } Variable::Variable(Variable const &other) - : ISerializable(), _name(other._name), _value(other._value->duplicate()), _mode(other._mode) + : ISerializable() + , d(new Instance(*other.d)) {} Variable::~Variable() { - DENG2_FOR_AUDIENCE(Deletion, i) i->variableBeingDeleted(*this); - delete _value; + DENG2_FOR_AUDIENCE2(Deletion, i) i->variableBeingDeleted(*this); +} + +String const &Variable::name() const +{ + return d->name; } Variable &Variable::operator = (Value *v) @@ -72,11 +110,11 @@ Variable &Variable::set(Value *v) verifyWritable(*v); verifyValid(*v); - QScopedPointer oldValue(_value); // old value deleted afterwards - _value = val.take(); + QScopedPointer oldValue(d->value); // old value deleted afterwards + d->value = val.take(); // We'll only determine if actual change occurred if someone is interested. - if(!audienceForChange.isEmpty()) + if(!audienceForChange().isEmpty()) { bool notify = true; try @@ -91,7 +129,7 @@ Variable &Variable::set(Value *v) if(notify) { - DENG2_FOR_AUDIENCE(Change, i) i->variableValueChanged(*this, *_value); + DENG2_FOR_AUDIENCE2(Change, i) i->variableValueChanged(*this, *d->value); } } return *this; @@ -105,14 +143,24 @@ Variable &Variable::set(Value const &v) Value const &Variable::value() const { - DENG2_ASSERT(_value != 0); - return *_value; + DENG2_ASSERT(d->value != 0); + return *d->value; } Value &Variable::value() { - DENG2_ASSERT(_value != 0); - return *_value; + DENG2_ASSERT(d->value != 0); + return *d->value; +} + +Value *Variable::valuePtr() +{ + return d->value; +} + +Value const *Variable::valuePtr() const +{ + return d->value; } Record const &Variable::valueAsRecord() const @@ -142,30 +190,30 @@ Variable::operator ddouble () const Variable::Flags Variable::mode() const { - return _mode; + return d->mode; } void Variable::setMode(Flags const &flags, FlagOp operation) { - applyFlagOperation(_mode, flags, operation); + applyFlagOperation(d->mode, flags, operation); } Variable &Variable::setReadOnly() { - _mode |= ReadOnly; + d->mode |= ReadOnly; return *this; } bool Variable::isValid(Value const &v) const { /// @todo Make sure this actually works and add func, record, ref. - if((dynamic_cast(&v) && !_mode.testFlag(AllowNone)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowNumber)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowText)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowArray)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowDictionary)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowBlock)) || - (dynamic_cast(&v) && !_mode.testFlag(AllowTime))) + if((dynamic_cast(&v) && !d->mode.testFlag(AllowNone)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowNumber)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowText)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowArray)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowDictionary)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowBlock)) || + (dynamic_cast(&v) && !d->mode.testFlag(AllowTime))) { return false; } @@ -179,16 +227,16 @@ void Variable::verifyValid(Value const &v) const { /// @throw InvalidError Value @a v is not allowed by the variable. throw InvalidError("Variable::verifyValid", - "Value type is not allowed by the variable '" + _name + "'"); + "Value type is not allowed by the variable '" + d->name + "'"); } } void Variable::verifyWritable(Value const &attemptedNewValue) { - if(_mode & ReadOnly) + if(d->mode & ReadOnly) { - if(_value && typeid(*_value) == typeid(attemptedNewValue) && - !_value->compare(attemptedNewValue)) + if(d->value && typeid(*d->value) == typeid(attemptedNewValue) && + !d->value->compare(attemptedNewValue)) { // This is ok: the value doesn't change. return; @@ -196,7 +244,7 @@ void Variable::verifyWritable(Value const &attemptedNewValue) /// @throw ReadOnlyError The variable is in read-only mode. throw ReadOnlyError("Variable::verifyWritable", - "Variable '" + _name + "' is in read-only mode"); + "Variable '" + d->name + "' is in read-only mode"); } } @@ -211,26 +259,28 @@ void Variable::verifyName(String const &s) void Variable::operator >> (Writer &to) const { - if(!_mode.testFlag(NoSerialize)) + if(!d->mode.testFlag(NoSerialize)) { - to << _name << duint32(_mode) << *_value; + to << d->name << duint32(d->mode) << *d->value; } } void Variable::operator << (Reader &from) { duint32 modeFlags = 0; - from >> _name >> modeFlags; - _mode = Flags(modeFlags); - delete _value; + from >> d->name >> modeFlags; + d->mode = Flags(modeFlags); + delete d->value; try { - _value = Value::constructFrom(from); + d->value = Value::constructFrom(from); } catch(Error const &) { // Always need to have a value. - _value = new NoneValue(); + d->value = new NoneValue(); throw; } } + +} // namespace de diff --git a/doomsday/libdeng2/src/filesys/archiveentryfile.cpp b/doomsday/libdeng2/src/filesys/archiveentryfile.cpp index a348b8ab1f..e6ee375dd4 100644 --- a/doomsday/libdeng2/src/filesys/archiveentryfile.cpp +++ b/doomsday/libdeng2/src/filesys/archiveentryfile.cpp @@ -32,8 +32,8 @@ ArchiveEntryFile::~ArchiveEntryFile() { DENG2_GUARD(this); - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); - audienceForDeletion.clear(); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); + audienceForDeletion().clear(); deindex(); } diff --git a/doomsday/libdeng2/src/filesys/archivefeed.cpp b/doomsday/libdeng2/src/filesys/archivefeed.cpp index ded3d3e066..b6227402e8 100644 --- a/doomsday/libdeng2/src/filesys/archivefeed.cpp +++ b/doomsday/libdeng2/src/filesys/archivefeed.cpp @@ -48,7 +48,7 @@ DENG2_PIMPL(ArchiveFeed) Instance(Public *feed, File &f) : Base(feed), file(&f), arch(0), parentFeed(0) { - file->audienceForDeletion += this; + file->audienceForDeletion() += this; // If the file happens to be a byte array file, we can use it // directly to store the Archive. @@ -75,14 +75,14 @@ DENG2_PIMPL(ArchiveFeed) Instance(Public *feed, ArchiveFeed &parentFeed, String const &path) : Base(feed), file(parentFeed.d->file), arch(0), basePath(path), parentFeed(&parentFeed) { - file->audienceForDeletion += this; + file->audienceForDeletion() += this; } ~Instance() { if(file) { - file->audienceForDeletion -= this; + file->audienceForDeletion() -= this; } if(arch) diff --git a/doomsday/libdeng2/src/filesys/file.cpp b/doomsday/libdeng2/src/filesys/file.cpp index 79dda257b4..96564b2671 100644 --- a/doomsday/libdeng2/src/filesys/file.cpp +++ b/doomsday/libdeng2/src/filesys/file.cpp @@ -26,38 +26,71 @@ #include "de/NumberValue" #include "de/Guard" -using namespace de; +namespace de { -File::File(String const &fileName) - : _parent(0), _originFeed(0), _name(fileName) +DENG2_PIMPL_NOREF(File) { - _source = this; + /// The parent folder. + Folder *parent; + + /// The source file (NULL for non-interpreted files). + File *source; + + /// Feed that generated the file. This feed is called upon when the file needs + /// to be pruned. May also be NULL. + Feed *originFeed; + + /// Name of the file. + String name; + + /// Status of the file. + Status status; + + /// Mode flags. + Flags mode; + + /// File information. + Record info; + + Instance(String const &fileName) + : parent(0) + , originFeed(0) + , name(fileName) {} + + DENG2_PIMPL_AUDIENCE(Deletion) +}; + +DENG2_AUDIENCE_METHOD(File, Deletion) + +File::File(String const &fileName) : d(new Instance(fileName)) +{ + d->source = this; // Create the default set of info variables common to all files. - _info.add(new Variable("name", new Accessor(*this, Accessor::NAME), Accessor::VARIABLE_MODE)); - _info.add(new Variable("path", new Accessor(*this, Accessor::PATH), Accessor::VARIABLE_MODE)); - _info.add(new Variable("type", new Accessor(*this, Accessor::TYPE), Accessor::VARIABLE_MODE)); - _info.add(new Variable("size", new Accessor(*this, Accessor::SIZE), Accessor::VARIABLE_MODE)); - _info.add(new Variable("modifiedAt", new Accessor(*this, Accessor::MODIFIED_AT), Accessor::VARIABLE_MODE)); + d->info.add(new Variable("name", new Accessor(*this, Accessor::NAME), Accessor::VARIABLE_MODE)); + d->info.add(new Variable("path", new Accessor(*this, Accessor::PATH), Accessor::VARIABLE_MODE)); + d->info.add(new Variable("type", new Accessor(*this, Accessor::TYPE), Accessor::VARIABLE_MODE)); + d->info.add(new Variable("size", new Accessor(*this, Accessor::SIZE), Accessor::VARIABLE_MODE)); + d->info.add(new Variable("modifiedAt", new Accessor(*this, Accessor::MODIFIED_AT), Accessor::VARIABLE_MODE)); } File::~File() { DENG2_GUARD(this); - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); flush(); - if(_source != this) + if(d->source != this) { // If we own a source, get rid of it. - delete _source; - _source = 0; + delete d->source; + d->source = 0; } - if(_parent) + if(d->parent) { // Remove from parent folder. - _parent->remove(this); + d->parent->remove(this); } deindex(); } @@ -80,6 +113,11 @@ FileSystem &File::fileSystem() return DENG2_APP->fileSystem(); } +String const &File::name() const +{ + return d->name; +} + String File::description() const { DENG2_GUARD(this); @@ -109,11 +147,26 @@ String File::describe() const return "abstract File"; } +void File::setParent(Folder *parent) +{ + d->parent = parent; +} + +Folder *File::parent() const +{ + return d->parent; +} + void File::setOriginFeed(Feed *feed) { DENG2_GUARD(this); - _originFeed = feed; + d->originFeed = feed; +} + +Feed *File::originFeed() const +{ + return d->originFeed; } String const File::path() const @@ -121,7 +174,7 @@ String const File::path() const DENG2_GUARD(this); String thePath = name(); - for(Folder *i = _parent; i; i = i->_parent) + for(Folder *i = d->parent; i; i = i->d->parent) { thePath = i->name() / thePath; } @@ -132,34 +185,34 @@ void File::setSource(File *source) { DENG2_GUARD(this); - if(_source != this) + if(d->source != this) { // Delete the old source. - delete _source; + delete d->source; } - _source = source; + d->source = source; } File const *File::source() const { DENG2_GUARD(this); - if(_source != this) + if(d->source != this) { - return _source->source(); + return d->source->source(); } - return _source; + return d->source; } File *File::source() { DENG2_GUARD(this); - if(_source != this) + if(d->source != this) { - return _source->source(); + return d->source->source(); } - return _source; + return d->source; } void File::setStatus(Status const &status) @@ -167,13 +220,13 @@ void File::setStatus(Status const &status) DENG2_GUARD(this); // The source file status is the official one. - if(this != _source) + if(this != d->source) { - _source->setStatus(status); + d->source->setStatus(status); } else { - _status = status; + d->status = status; } } @@ -181,36 +234,46 @@ File::Status const &File::status() const { DENG2_GUARD(this); - if(this != _source) + if(this != d->source) { - return _source->status(); + return d->source->status(); } - return _status; + return d->status; } void File::setMode(Flags const &newMode) { DENG2_GUARD(this); - if(this != _source) + if(this != d->source) { - _source->setMode(newMode); + d->source->setMode(newMode); } else { - _mode = newMode; + d->mode = newMode; } } +Record const &File::info() const +{ + return d->info; +} + +Record &File::info() +{ + return d->info; +} + File::Flags const &File::mode() const { DENG2_GUARD(this); - if(this != _source) + if(this != d->source) { - return _source->mode(); + return d->source->mode(); } - return _mode; + return d->mode; } void File::verifyWriteAccess() @@ -289,3 +352,5 @@ Value *File::Accessor::duplicateContent() const } return new TextValue(*this); } + +} // namespace de diff --git a/doomsday/libdeng2/src/filesys/folder.cpp b/doomsday/libdeng2/src/filesys/folder.cpp index bfd4b25340..1475617a88 100644 --- a/doomsday/libdeng2/src/filesys/folder.cpp +++ b/doomsday/libdeng2/src/filesys/folder.cpp @@ -40,8 +40,8 @@ Folder::~Folder() { DENG2_GUARD(this); - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); - audienceForDeletion.clear(); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); + audienceForDeletion().clear(); deindex(); diff --git a/doomsday/libdeng2/src/filesys/libraryfile.cpp b/doomsday/libdeng2/src/filesys/libraryfile.cpp index c069b9533a..3595557a73 100644 --- a/doomsday/libdeng2/src/filesys/libraryfile.cpp +++ b/doomsday/libdeng2/src/filesys/libraryfile.cpp @@ -34,8 +34,8 @@ LibraryFile::LibraryFile(File *source) LibraryFile::~LibraryFile() { - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); - audienceForDeletion.clear(); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); + audienceForDeletion().clear(); deindex(); delete _library; diff --git a/doomsday/libdeng2/src/filesys/nativefile.cpp b/doomsday/libdeng2/src/filesys/nativefile.cpp index 7567cbdadd..5df855fdc9 100644 --- a/doomsday/libdeng2/src/filesys/nativefile.cpp +++ b/doomsday/libdeng2/src/filesys/nativefile.cpp @@ -31,8 +31,8 @@ NativeFile::~NativeFile() { DENG2_GUARD(this); - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); - audienceForDeletion.clear(); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); + audienceForDeletion().clear(); close(); deindex(); diff --git a/doomsday/libdeng2/src/filesys/packagefolder.cpp b/doomsday/libdeng2/src/filesys/packagefolder.cpp index f771fcbc6d..7595a92c7f 100644 --- a/doomsday/libdeng2/src/filesys/packagefolder.cpp +++ b/doomsday/libdeng2/src/filesys/packagefolder.cpp @@ -29,8 +29,8 @@ PackageFolder::PackageFolder(File &sourceArchiveFile, String const &name) : Fold PackageFolder::~PackageFolder() { - DENG2_FOR_AUDIENCE(Deletion, i) i->fileBeingDeleted(*this); - audienceForDeletion.clear(); + DENG2_FOR_AUDIENCE2(Deletion, i) i->fileBeingDeleted(*this); + audienceForDeletion().clear(); deindex(); } diff --git a/doomsday/libdeng2/src/scriptsys/function.cpp b/doomsday/libdeng2/src/scriptsys/function.cpp index 787cbadf5f..c59a78d21c 100644 --- a/doomsday/libdeng2/src/scriptsys/function.cpp +++ b/doomsday/libdeng2/src/scriptsys/function.cpp @@ -96,7 +96,7 @@ Function::~Function() if(d->globals) { // Stop observing the namespace. - d->globals->audienceForDeletion.remove(this); + d->globals->audienceForDeletion() -= this; } } @@ -230,7 +230,7 @@ void Function::setGlobals(Record *globals) if(!d->globals) { d->globals = globals; - d->globals->audienceForDeletion.add(this); + d->globals->audienceForDeletion() += this; } /* else if(d->globals != globals) diff --git a/doomsday/libdeng2/src/scriptsys/scriptsystem.cpp b/doomsday/libdeng2/src/scriptsys/scriptsystem.cpp index 482c7acc45..c11789a4c5 100644 --- a/doomsday/libdeng2/src/scriptsys/scriptsystem.cpp +++ b/doomsday/libdeng2/src/scriptsys/scriptsystem.cpp @@ -85,14 +85,14 @@ DENG2_PIMPL(ScriptSystem), DENG2_OBSERVES(Record, Deletion) DENG2_FOR_EACH(NativeModules, i, nativeModules) { - i.value()->audienceForDeletion -= this; + i.value()->audienceForDeletion() -= this; } } void addNativeModule(String const &name, Record &module) { nativeModules.insert(name, &module); // not owned - module.audienceForDeletion += this; + module.audienceForDeletion() += this; } void recordBeingDeleted(Record &record) diff --git a/doomsday/libdeng2/src/widgets/action.cpp b/doomsday/libdeng2/src/widgets/action.cpp index 57b0ba3d4c..c5da823433 100644 --- a/doomsday/libdeng2/src/widgets/action.cpp +++ b/doomsday/libdeng2/src/widgets/action.cpp @@ -20,12 +20,22 @@ namespace de { +DENG2_PIMPL_NOREF(Action) +{ + DENG2_PIMPL_AUDIENCE(Triggered) +}; + +DENG2_AUDIENCE_METHOD(Action, Triggered) + +Action::Action() : d(new Instance) +{} + Action::~Action() {} void Action::trigger() { - DENG2_FOR_AUDIENCE(Triggered, i) + DENG2_FOR_AUDIENCE2(Triggered, i) { i->actionTriggered(*this); } diff --git a/doomsday/libdeng2/src/widgets/widget.cpp b/doomsday/libdeng2/src/widgets/widget.cpp index 0e0c3998c3..3fa0d0099a 100644 --- a/doomsday/libdeng2/src/widgets/widget.cpp +++ b/doomsday/libdeng2/src/widgets/widget.cpp @@ -60,8 +60,18 @@ DENG2_PIMPL(Widget) } index.clear(); } + + DENG2_PIMPL_AUDIENCE(Deletion) + DENG2_PIMPL_AUDIENCE(ParentChange) + DENG2_PIMPL_AUDIENCE(ChildAddition) + DENG2_PIMPL_AUDIENCE(ChildRemoval) }; +DENG2_AUDIENCE_METHOD(Widget, Deletion) +DENG2_AUDIENCE_METHOD(Widget, ParentChange) +DENG2_AUDIENCE_METHOD(Widget, ChildAddition) +DENG2_AUDIENCE_METHOD(Widget, ChildRemoval) + Widget::Widget(String const &name) : d(new Instance(this, name)) {} @@ -72,7 +82,7 @@ Widget::~Widget() root().setFocus(0); } - audienceForParentChange.clear(); + audienceForParentChange().clear(); // Remove from parent automatically. if(d->parent) @@ -81,7 +91,7 @@ Widget::~Widget() } // Notify everyone else. - DENG2_FOR_AUDIENCE(Deletion, i) i->widgetBeingDeleted(*this); + DENG2_FOR_AUDIENCE2(Deletion, i) i->widgetBeingDeleted(*this); } Id Widget::id() const @@ -272,11 +282,11 @@ Widget &Widget::add(Widget *child) } // Notify. - DENG2_FOR_AUDIENCE(ChildAddition, i) + DENG2_FOR_AUDIENCE2(ChildAddition, i) { i->widgetChildAdded(*child); } - DENG2_FOR_EACH_OBSERVER(ParentChangeAudience, i, child->audienceForParentChange) + DENG2_FOR_EACH_OBSERVER(ParentChangeAudience, i, child->audienceForParentChange()) { i->widgetParentChanged(*child, 0, this); } @@ -309,11 +319,11 @@ Widget *Widget::remove(Widget &child) } // Notify. - DENG2_FOR_AUDIENCE(ChildRemoval, i) + DENG2_FOR_AUDIENCE2(ChildRemoval, i) { i->widgetChildRemoved(child); } - DENG2_FOR_EACH_OBSERVER(ParentChangeAudience, i, child.audienceForParentChange) + DENG2_FOR_EACH_OBSERVER(ParentChangeAudience, i, child.audienceForParentChange()) { i->widgetParentChanged(child, this, 0); } From b92c4b31649e13c62525b58e94541d10cb83d554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 19:42:44 +0200 Subject: [PATCH 51/60] Refactor: Use pimpl-friendly audiences for libdeng2 classes --- doomsday/client/src/alertmask.cpp | 2 +- doomsday/client/src/dd_main.cpp | 6 +++--- doomsday/client/src/network/serverlink.cpp | 6 +++--- doomsday/client/src/settingsregister.cpp | 8 ++++---- doomsday/client/src/ui/clientwindow.cpp | 8 ++++---- .../src/ui/editors/rendererappearanceeditor.cpp | 4 ++-- .../src/ui/widgets/consolecommandwidget.cpp | 8 ++++---- doomsday/client/src/ui/widgets/consolewidget.cpp | 4 ++-- .../client/src/ui/widgets/gameselectionwidget.cpp | 8 ++++---- .../client/src/ui/widgets/gamesessionwidget.cpp | 4 ++-- doomsday/client/src/ui/widgets/taskbarwidget.cpp | 4 ++-- doomsday/client/src/updater/updater.cpp | 2 +- doomsday/libappfw/src/childwidgetorganizer.cpp | 6 +++--- doomsday/libappfw/src/dialogcontentstylist.cpp | 6 +++--- doomsday/libappfw/src/guirootwidget.cpp | 2 +- doomsday/libappfw/src/guiwidget.cpp | 4 ++-- doomsday/libappfw/src/widgets/buttonwidget.cpp | 6 +++--- doomsday/libappfw/src/widgets/choicewidget.cpp | 15 ++++++++------- doomsday/libappfw/src/widgets/menuwidget.cpp | 12 ++++++------ .../libappfw/src/widgets/notificationwidget.cpp | 4 ++-- doomsday/libappfw/src/widgets/popupwidget.cpp | 6 +++--- .../libappfw/src/widgets/variablechoicewidget.cpp | 12 ++++++------ .../libappfw/src/widgets/variabletogglewidget.cpp | 12 ++++++------ doomsday/libgui/src/font_richformat.cpp | 4 ++-- doomsday/libgui/src/glframebuffer.cpp | 4 ++-- doomsday/libgui/src/glstate.cpp | 4 ++-- doomsday/libgui/src/gluniform.cpp | 6 +++--- doomsday/libgui/src/guiapp.cpp | 2 +- doomsday/tests/test_glsandbox/testwindow.cpp | 4 ++-- 29 files changed, 87 insertions(+), 86 deletions(-) diff --git a/doomsday/client/src/alertmask.cpp b/doomsday/client/src/alertmask.cpp index 3d1d75c7fb..e1af368366 100644 --- a/doomsday/client/src/alertmask.cpp +++ b/doomsday/client/src/alertmask.cpp @@ -67,7 +67,7 @@ void AlertMask::init() { foreach(Variable const *var, App::config().names().subrecord("alert").members()) { - var->audienceForChange += d; + var->audienceForChange() += d; } d->updateMask(); } diff --git a/doomsday/client/src/dd_main.cpp b/doomsday/client/src/dd_main.cpp index 7344ecae8c..cdf751e79a 100644 --- a/doomsday/client/src/dd_main.cpp +++ b/doomsday/client/src/dd_main.cpp @@ -1333,7 +1333,7 @@ bool App_ChangeGame(Game &game, bool allowReload) } // The current game will be gone very soon. - DENG2_FOR_EACH_OBSERVER(App::GameUnloadAudience, i, App::app().audienceForGameUnload) + DENG2_FOR_EACH_OBSERVER(App::GameUnloadAudience, i, App::app().audienceForGameUnload()) { i->aboutToUnloadGame(App::game()); } @@ -1589,7 +1589,7 @@ bool App_ChangeGame(Game &game, bool allowReload) #endif // Game change is complete. - DENG2_FOR_EACH_OBSERVER(App::GameChangeAudience, i, App::app().audienceForGameChange) + DENG2_FOR_EACH_OBSERVER(App::GameChangeAudience, i, App::app().audienceForGameChange()) { i->currentGameChanged(App::game()); } @@ -1703,7 +1703,7 @@ void DD_FinishInitializationAfterWindowReady() } /// @todo This notification should be done from the app. - DENG2_FOR_EACH_OBSERVER(App::StartupCompleteAudience, i, App::app().audienceForStartupComplete) + DENG2_FOR_EACH_OBSERVER(App::StartupCompleteAudience, i, App::app().audienceForStartupComplete()) { i->appStartupCompleted(); } diff --git a/doomsday/client/src/network/serverlink.cpp b/doomsday/client/src/network/serverlink.cpp index 10923dd9be..da8d85c274 100644 --- a/doomsday/client/src/network/serverlink.cpp +++ b/doomsday/client/src/network/serverlink.cpp @@ -66,7 +66,7 @@ DENG2_PIMPL(ServerLink) ~Instance() { - Loop::appLoop().audienceForIteration -= this; + Loop::appLoop().audienceForIteration() -= this; } void notifyDiscoveryUpdate() @@ -183,7 +183,7 @@ DENG2_PIMPL(ServerLink) fetching = true; N_MAPost(MAC_REQUEST); N_MAPost(MAC_WAIT); - Loop::appLoop().audienceForIteration += this; + Loop::appLoop().audienceForIteration() += this; } void loopIteration() @@ -193,7 +193,7 @@ DENG2_PIMPL(ServerLink) if(N_MADone()) { fetching = false; - Loop::appLoop().audienceForIteration -= this; + Loop::appLoop().audienceForIteration() -= this; fromMaster.clear(); int const count = N_MasterGet(0, 0); diff --git a/doomsday/client/src/settingsregister.cpp b/doomsday/client/src/settingsregister.cpp index 3d1751479f..92deb8ffe9 100644 --- a/doomsday/client/src/settingsregister.cpp +++ b/doomsday/client/src/settingsregister.cpp @@ -99,16 +99,16 @@ DENG2_OBSERVES(App, GameChange) Instance(Public *i) : Base(i), current(CUSTOM_PROFILE) { - App::app().audienceForGameUnload += this; - App::app().audienceForGameChange += this; + App::app().audienceForGameUnload() += this; + App::app().audienceForGameChange() += this; addProfile(current); } ~Instance() { - App::app().audienceForGameUnload -= this; - App::app().audienceForGameChange -= this; + App::app().audienceForGameUnload() -= this; + App::app().audienceForGameChange() -= this; clearProfiles(); } diff --git a/doomsday/client/src/ui/clientwindow.cpp b/doomsday/client/src/ui/clientwindow.cpp index 4bbe40e87c..5c859a4000 100644 --- a/doomsday/client/src/ui/clientwindow.cpp +++ b/doomsday/client/src/ui/clientwindow.cpp @@ -126,8 +126,8 @@ DENG2_PIMPL(ClientWindow) /// @todo The decision whether to receive input notifications from the /// canvas is really a concern for the input drivers. - App::app().audienceForGameChange += this; - App::app().audienceForStartupComplete += this; + App::app().audienceForGameChange() += this; + App::app().audienceForStartupComplete() += this; // Listen to input. self.canvas().audienceForMouseStateChange += this; @@ -135,8 +135,8 @@ DENG2_PIMPL(ClientWindow) ~Instance() { - App::app().audienceForGameChange -= this; - App::app().audienceForStartupComplete -= this; + App::app().audienceForGameChange() -= this; + App::app().audienceForStartupComplete() -= this; self.canvas().audienceForFocusChange -= this; self.canvas().audienceForMouseStateChange -= this; diff --git a/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp b/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp index 7109c95d4b..3a569db6e8 100644 --- a/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp +++ b/doomsday/client/src/ui/editors/rendererappearanceeditor.cpp @@ -265,7 +265,7 @@ DENG2_OBSERVES(App, GameChange) firstColumnWidth(new IndirectRule) { // The editor will close automatically when going to Ring Zero. - App::app().audienceForGameChange += this; + App::app().audienceForGameChange() += this; settings.audienceForProfileChange += this; @@ -570,7 +570,7 @@ DENG2_OBSERVES(App, GameChange) ~Instance() { - App::app().audienceForGameChange -= this; + App::app().audienceForGameChange() -= this; settings.audienceForProfileChange -= this; releaseRef(firstColumnWidth); } diff --git a/doomsday/client/src/ui/widgets/consolecommandwidget.cpp b/doomsday/client/src/ui/widgets/consolecommandwidget.cpp index 69ce394ee5..2d30bda1f2 100644 --- a/doomsday/client/src/ui/widgets/consolecommandwidget.cpp +++ b/doomsday/client/src/ui/widgets/consolecommandwidget.cpp @@ -32,14 +32,14 @@ DENG2_OBSERVES(App, GameChange) { Instance(Public *i) : Base(i) { - App::app().audienceForStartupComplete += this; - App::app().audienceForGameChange += this; + App::app().audienceForStartupComplete() += this; + App::app().audienceForGameChange() += this; } ~Instance() { - App::app().audienceForStartupComplete -= this; - App::app().audienceForGameChange -= this; + App::app().audienceForStartupComplete() -= this; + App::app().audienceForGameChange() -= this; } void appStartupCompleted() diff --git a/doomsday/client/src/ui/widgets/consolewidget.cpp b/doomsday/client/src/ui/widgets/consolewidget.cpp index b3227acb57..12673fa55e 100644 --- a/doomsday/client/src/ui/widgets/consolewidget.cpp +++ b/doomsday/client/src/ui/widgets/consolewidget.cpp @@ -88,12 +88,12 @@ DENG2_OBSERVES(Variable, Change) grabWidth = style().rules().rule("gap").valuei(); - App::config()["console.script"].audienceForChange += this; + App::config()["console.script"].audienceForChange() += this; } ~Instance() { - App::config()["console.script"].audienceForChange -= this; + App::config()["console.script"].audienceForChange() -= this; releaseRef(horizShift); releaseRef(width); diff --git a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp index 3542a9b261..f3f2042e9a 100644 --- a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp +++ b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp @@ -239,15 +239,15 @@ DENG_GUI_PIMPL(GameSelectionWidget) updateSubsetLayout(); App_Games().audienceForAddition += this; - App::app().audienceForStartupComplete += this; - App::app().audienceForGameChange += this; + App::app().audienceForStartupComplete() += this; + App::app().audienceForGameChange() += this; } ~Instance() { App_Games().audienceForAddition -= this; - App::app().audienceForStartupComplete -= this; - App::app().audienceForGameChange -= this; + App::app().audienceForStartupComplete() -= this; + App::app().audienceForGameChange() -= this; } void updateSubsetVisibility() diff --git a/doomsday/client/src/ui/widgets/gamesessionwidget.cpp b/doomsday/client/src/ui/widgets/gamesessionwidget.cpp index 5e74ed84f7..73791733fc 100644 --- a/doomsday/client/src/ui/widgets/gamesessionwidget.cpp +++ b/doomsday/client/src/ui/widgets/gamesessionwidget.cpp @@ -51,12 +51,12 @@ DENG2_PIMPL(GameSessionWidget) popup->document().setMaximumLineWidth(popup->style().rules().rule("document.popup.width").valuei()); info->audienceForPress += this; - App::app().audienceForGameUnload += this; + App::app().audienceForGameUnload() += this; } ~Instance() { - App::app().audienceForGameUnload -= this; + App::app().audienceForGameUnload() -= this; } void aboutToUnloadGame(game::Game const &) diff --git a/doomsday/client/src/ui/widgets/taskbarwidget.cpp b/doomsday/client/src/ui/widgets/taskbarwidget.cpp index 549c1cac8a..9ad66dbe8f 100644 --- a/doomsday/client/src/ui/widgets/taskbarwidget.cpp +++ b/doomsday/client/src/ui/widgets/taskbarwidget.cpp @@ -130,7 +130,7 @@ DENG_GUI_PIMPL(TaskBarWidget) vertShift = new ScalarRule(0); - App::app().audienceForGameChange += this; + App::app().audienceForGameChange() += this; ClientApp::serverLink().audienceForJoin += this; ClientApp::serverLink().audienceForLeave += this; @@ -139,7 +139,7 @@ DENG_GUI_PIMPL(TaskBarWidget) ~Instance() { - App::app().audienceForGameChange -= this; + App::app().audienceForGameChange() -= this; ClientApp::serverLink().audienceForJoin -= this; ClientApp::serverLink().audienceForLeave -= this; diff --git a/doomsday/client/src/updater/updater.cpp b/doomsday/client/src/updater/updater.cpp index 24508d0bc5..e57f8ad440 100644 --- a/doomsday/client/src/updater/updater.cpp +++ b/doomsday/client/src/updater/updater.cpp @@ -531,7 +531,7 @@ Updater::Updater() : d(new Instance(this)) connect(d->network, SIGNAL(finished(QNetworkReply *)), this, SLOT(gotReply(QNetworkReply *))); // Do a silent auto-update check when starting. - App::app().audienceForStartupComplete += d; + App::app().audienceForStartupComplete() += d; } void Updater::setupUI() diff --git a/doomsday/libappfw/src/childwidgetorganizer.cpp b/doomsday/libappfw/src/childwidgetorganizer.cpp index 9b21d3f4ed..2d0fc3ea01 100644 --- a/doomsday/libappfw/src/childwidgetorganizer.cpp +++ b/doomsday/libappfw/src/childwidgetorganizer.cpp @@ -55,7 +55,7 @@ DENG2_OBSERVES(ui::Item, Change ) { DENG2_FOR_EACH_CONST(Mapping, i, mapping) { - i.value()->audienceForDeletion -= this; + i.value()->audienceForDeletion() -= this; } } @@ -122,7 +122,7 @@ DENG2_OBSERVES(ui::Item, Change ) } // Observe. - w->audienceForDeletion += this; // in case it's manually deleted + w->audienceForDeletion() += this; // in case it's manually deleted item.audienceForChange += this; } @@ -139,7 +139,7 @@ DENG2_OBSERVES(ui::Item, Change ) void deleteWidget(GuiWidget *w) { - w->audienceForDeletion -= this; + w->audienceForDeletion() -= this; GuiWidget::destroy(w); } diff --git a/doomsday/libappfw/src/dialogcontentstylist.cpp b/doomsday/libappfw/src/dialogcontentstylist.cpp index 65ebaff526..3628731a14 100644 --- a/doomsday/libappfw/src/dialogcontentstylist.cpp +++ b/doomsday/libappfw/src/dialogcontentstylist.cpp @@ -41,7 +41,7 @@ DialogContentStylist::~DialogContentStylist() { if(_container) { - _container->audienceForChildAddition -= this; + _container->audienceForChildAddition() -= this; } } @@ -49,11 +49,11 @@ void DialogContentStylist::setContainer(GuiWidget &container) { if(_container) { - _container->audienceForChildAddition -= this; + _container->audienceForChildAddition() -= this; } _container = &container; - _container->audienceForChildAddition += this; + _container->audienceForChildAddition() += this; } void DialogContentStylist::widgetChildAdded(Widget &child) diff --git a/doomsday/libappfw/src/guirootwidget.cpp b/doomsday/libappfw/src/guirootwidget.cpp index 4a95eab8b2..78ce7c980d 100644 --- a/doomsday/libappfw/src/guirootwidget.cpp +++ b/doomsday/libappfw/src/guirootwidget.cpp @@ -55,7 +55,7 @@ DENG2_PIMPL(GuiRootWidget) , uTexAtlas("uTex", GLUniform::Sampler2D) , noFramesDrawnYet(true) { - self.audienceForChildAddition += this; + self.audienceForChildAddition() += this; } ~Instance() diff --git a/doomsday/libappfw/src/guiwidget.cpp b/doomsday/libappfw/src/guiwidget.cpp index 3b65c4832d..005961826e 100644 --- a/doomsday/libappfw/src/guiwidget.cpp +++ b/doomsday/libappfw/src/guiwidget.cpp @@ -86,11 +86,11 @@ DENG2_PIMPL(GuiWidget) , uBlurStep ("uBlurStep", GLUniform::Vec2) , uBlurWindow ("uWindow", GLUniform::Vec4) { - self.audienceForChildAddition += this; + self.audienceForChildAddition() += this; margins.audienceForChange += this; #ifdef DENG2_DEBUG - self.audienceForParentChange += this; + self.audienceForParentChange() += this; rule.setDebugName(self.path()); #endif diff --git a/doomsday/libappfw/src/widgets/buttonwidget.cpp b/doomsday/libappfw/src/widgets/buttonwidget.cpp index 148961aed5..05b24b04d0 100644 --- a/doomsday/libappfw/src/widgets/buttonwidget.cpp +++ b/doomsday/libappfw/src/widgets/buttonwidget.cpp @@ -52,7 +52,7 @@ DENG2_OBSERVES(Action, Triggered) ~Instance() { - if(action) action->audienceForTriggered -= this; + if(action) action->audienceForTriggered() -= this; releaseRef(action); } @@ -196,14 +196,14 @@ void ButtonWidget::setAction(RefArg action) { if(d->action) { - d->action->audienceForTriggered -= d; + d->action->audienceForTriggered() -= d; } changeRef(d->action, action); if(action) { - action->audienceForTriggered += d; + action->audienceForTriggered() += d; } } diff --git a/doomsday/libappfw/src/widgets/choicewidget.cpp b/doomsday/libappfw/src/widgets/choicewidget.cpp index 9989bb157e..5b805d78e9 100644 --- a/doomsday/libappfw/src/widgets/choicewidget.cpp +++ b/doomsday/libappfw/src/widgets/choicewidget.cpp @@ -37,20 +37,21 @@ DENG2_OBSERVES(ChildWidgetOrganizer, WidgetUpdate) */ struct SelectAction : public de::Action { - Instance *d; + ChoiceWidget::Instance *wd; ui::Item const &selItem; - SelectAction(Instance *inst, ui::Item const &item) : d(inst), selItem(item) {} + SelectAction(ChoiceWidget::Instance *inst, ui::Item const &item) + : wd(inst), selItem(item) {} void trigger() { Action::trigger(); - d->selected = d->items().find(selItem); - d->updateButtonWithSelection(); - d->updateItemHighlight(); - d->choices->dismiss(); + wd->selected = wd->items().find(selItem); + wd->updateButtonWithSelection(); + wd->updateItemHighlight(); + wd->choices->dismiss(); - emit d->self.selectionChangedByUser(d->selected); + emit wd->self.selectionChangedByUser(wd->selected); } }; diff --git a/doomsday/libappfw/src/widgets/menuwidget.cpp b/doomsday/libappfw/src/widgets/menuwidget.cpp index 21f5d03806..7860799da7 100644 --- a/doomsday/libappfw/src/widgets/menuwidget.cpp +++ b/doomsday/libappfw/src/widgets/menuwidget.cpp @@ -43,7 +43,7 @@ DENG2_PIMPL(MenuWidget) class SubAction : public de::Action, DENG2_OBSERVES(Widget, Deletion) { public: - SubAction(Instance *inst, ui::Item const &parentItem) + SubAction(MenuWidget::Instance *inst, ui::Item const &parentItem) : d(inst) , _parentItem(parentItem) , _dir(ui::Right) @@ -65,7 +65,7 @@ DENG2_PIMPL(MenuWidget) // Popups need a parent. d->self.add(_widget); - _widget->audienceForDeletion += this; + _widget->audienceForDeletion() += this; _dir = openingDirection; } @@ -95,7 +95,7 @@ DENG2_PIMPL(MenuWidget) } protected: - Instance *d; + MenuWidget::Instance *d; ui::Item const &_parentItem; ui::Direction _dir; PopupWidget *_widget; @@ -107,7 +107,7 @@ DENG2_PIMPL(MenuWidget) class SubmenuAction : public SubAction { public: - SubmenuAction(Instance *inst, ui::SubmenuItem const &parentItem) + SubmenuAction(MenuWidget::Instance *inst, ui::SubmenuItem const &parentItem) : SubAction(inst, parentItem) { PopupMenuWidget *sub = new PopupMenuWidget; @@ -124,7 +124,7 @@ DENG2_PIMPL(MenuWidget) class SubwidgetAction : public SubAction { public: - SubwidgetAction(Instance *inst, ui::SubwidgetItem const &parentItem) + SubwidgetAction(MenuWidget::Instance *inst, ui::SubwidgetItem const &parentItem) : SubAction(inst, parentItem) , _item(parentItem) {} @@ -325,7 +325,7 @@ DENG2_PIMPL(MenuWidget) openSubs.insert(w); w->audienceForClose += this; - w->audienceForDeletion += this; + w->audienceForDeletion() += this; } bool isVisibleItem(Widget const *child) const diff --git a/doomsday/libappfw/src/widgets/notificationwidget.cpp b/doomsday/libappfw/src/widgets/notificationwidget.cpp index 8bd124772d..959fa859ea 100644 --- a/doomsday/libappfw/src/widgets/notificationwidget.cpp +++ b/doomsday/libappfw/src/widgets/notificationwidget.cpp @@ -52,8 +52,8 @@ DENG2_OBSERVES(Widget, ChildRemoval) uMvpMatrix("uMvpMatrix", GLUniform::Mat4), uColor ("uColor", GLUniform::Vec4) { - self.audienceForChildAddition += this; - self.audienceForChildRemoval += this; + self.audienceForChildAddition() += this; + self.audienceForChildRemoval() += this; dismissTimer.setSingleShot(true); dismissTimer.setInterval(ANIM_SPAN.asMilliSeconds()); diff --git a/doomsday/libappfw/src/widgets/popupwidget.cpp b/doomsday/libappfw/src/widgets/popupwidget.cpp index cda3f2feba..7b820ceb5d 100644 --- a/doomsday/libappfw/src/widgets/popupwidget.cpp +++ b/doomsday/libappfw/src/widgets/popupwidget.cpp @@ -61,7 +61,7 @@ DENG_GUI_PIMPL(PopupWidget) ~Instance() { - if(realParent) realParent->audienceForDeletion -= this; + if(realParent) realParent->audienceForDeletion() -= this; releaseRef(anchorX); releaseRef(anchorY); @@ -414,7 +414,7 @@ void PopupWidget::preparePanelForOpening() // Reparent the popup into the root widget, on top of everything else. d->realParent = Widget::parent(); DENG2_ASSERT(d->realParent != 0); - d->realParent->audienceForDeletion += d; + d->realParent->audienceForDeletion() += d; d->realParent->remove(*this); d->realParent->root().as().addOnTop(this); @@ -428,7 +428,7 @@ void PopupWidget::panelDismissed() // Move back to the original parent widget. if(d->realParent) { - d->realParent->audienceForDeletion -= d; + d->realParent->audienceForDeletion() -= d; } else { diff --git a/doomsday/libappfw/src/widgets/variablechoicewidget.cpp b/doomsday/libappfw/src/widgets/variablechoicewidget.cpp index 486b3cd20a..b3c4f6b6e4 100644 --- a/doomsday/libappfw/src/widgets/variablechoicewidget.cpp +++ b/doomsday/libappfw/src/widgets/variablechoicewidget.cpp @@ -33,16 +33,16 @@ DENG2_OBSERVES(Variable, Change ) { updateFromVariable(); - var->audienceForDeletion += this; - var->audienceForChange += this; + var->audienceForDeletion() += this; + var->audienceForChange() += this; } ~Instance() { if(var) { - var->audienceForDeletion -= this; - var->audienceForChange -= this; + var->audienceForDeletion() -= this; + var->audienceForChange() -= this; } } @@ -57,9 +57,9 @@ DENG2_OBSERVES(Variable, Change ) { if(!var) return; - var->audienceForChange -= this; + var->audienceForChange() -= this; var->set(NumberValue(self.selectedItem().data().toInt())); - var->audienceForChange += this; + var->audienceForChange() += this; } void variableValueChanged(Variable &, Value const &) diff --git a/doomsday/libappfw/src/widgets/variabletogglewidget.cpp b/doomsday/libappfw/src/widgets/variabletogglewidget.cpp index 15f7f9f193..e4b98ed7f9 100644 --- a/doomsday/libappfw/src/widgets/variabletogglewidget.cpp +++ b/doomsday/libappfw/src/widgets/variabletogglewidget.cpp @@ -40,16 +40,16 @@ DENG2_OBSERVES(ToggleWidget, Toggle ) updateFromVariable(); self.audienceForToggle += this; - var->audienceForDeletion += this; - var->audienceForChange += this; + var->audienceForDeletion() += this; + var->audienceForChange() += this; } ~Instance() { if(var) { - var->audienceForDeletion -= this; - var->audienceForChange -= this; + var->audienceForDeletion() -= this; + var->audienceForChange() -= this; self.audienceForToggle -= this; } } @@ -66,9 +66,9 @@ DENG2_OBSERVES(ToggleWidget, Toggle ) { if(!var) return; - var->audienceForChange -= this; + var->audienceForChange() -= this; var->set(self.isActive()? activeValue : inactiveValue); - var->audienceForChange += this; + var->audienceForChange() += this; } void toggleStateChanged(ToggleWidget &) diff --git a/doomsday/libgui/src/font_richformat.cpp b/doomsday/libgui/src/font_richformat.cpp index 5eee7696b3..e36abe1218 100644 --- a/doomsday/libgui/src/font_richformat.cpp +++ b/doomsday/libgui/src/font_richformat.cpp @@ -254,8 +254,8 @@ String Font::RichFormat::initFromStyledText(String const &styledText) { clear(); - d->esc.audienceForEscapeSequence += d; - d->esc.audienceForPlainText += d; + d->esc.audienceForEscapeSequence() += d; + d->esc.audienceForPlainText() += d; d->esc.parse(styledText); diff --git a/doomsday/libgui/src/glframebuffer.cpp b/doomsday/libgui/src/glframebuffer.cpp index 9093049876..b74062f925 100644 --- a/doomsday/libgui/src/glframebuffer.cpp +++ b/doomsday/libgui/src/glframebuffer.cpp @@ -54,13 +54,13 @@ DENG2_PIMPL(GLFramebuffer) , uMvpMatrix("uMvpMatrix", GLUniform::Mat4) , uBufTex ("uTex", GLUniform::Sampler2D) { - pDefaultSampleCount.audienceForChange += this; + pDefaultSampleCount.audienceForChange() += this; //DENG2_GUI_APP->audienceForGLContextChange += this; } ~Instance() { - pDefaultSampleCount.audienceForChange -= this; + pDefaultSampleCount.audienceForChange() -= this; //DENG2_GUI_APP->audienceForGLContextChange -= this; } diff --git a/doomsday/libgui/src/glstate.cpp b/doomsday/libgui/src/glstate.cpp index 1f9e058711..22acf202f7 100644 --- a/doomsday/libgui/src/glstate.cpp +++ b/doomsday/libgui/src/glstate.cpp @@ -104,11 +104,11 @@ namespace internal } void set(GLTarget *trg) { if(_target) { - _target->audienceForDeletion -= this; + _target->audienceForDeletion() -= this; } _target = trg; if(_target) { - _target->audienceForDeletion += this; + _target->audienceForDeletion() += this; } } CurrentTarget &operator = (GLTarget *trg) { diff --git a/doomsday/libgui/src/gluniform.cpp b/doomsday/libgui/src/gluniform.cpp index e57eea7d1d..d14f62a297 100644 --- a/doomsday/libgui/src/gluniform.cpp +++ b/doomsday/libgui/src/gluniform.cpp @@ -90,7 +90,7 @@ DENG2_PIMPL(GLUniform) break; case Sampler2D: - if(value.tex) value.tex->audienceForDeletion -= this; + if(value.tex) value.tex->audienceForDeletion() -= this; break; default: @@ -280,12 +280,12 @@ GLUniform &GLUniform::operator = (GLTexture const *texture) if(d->value.tex != texture) { // We will observe the texture this uniform refers to. - if(d->value.tex) d->value.tex->audienceForDeletion -= d; + if(d->value.tex) d->value.tex->audienceForDeletion() -= d; d->value.tex = texture; d->markAsChanged(); - if(d->value.tex) d->value.tex->audienceForDeletion += d; + if(d->value.tex) d->value.tex->audienceForDeletion() += d; } return *this; } diff --git a/doomsday/libgui/src/guiapp.cpp b/doomsday/libgui/src/guiapp.cpp index d27bd6a7f9..160628a373 100644 --- a/doomsday/libgui/src/guiapp.cpp +++ b/doomsday/libgui/src/guiapp.cpp @@ -34,7 +34,7 @@ DENG2_PIMPL(GuiApp) Instance(Public *i) : Base(i) { - loop.audienceForIteration += self; + loop.audienceForIteration() += self; } }; diff --git a/doomsday/tests/test_glsandbox/testwindow.cpp b/doomsday/tests/test_glsandbox/testwindow.cpp index 049d5b3783..aa4c13b1fe 100644 --- a/doomsday/tests/test_glsandbox/testwindow.cpp +++ b/doomsday/tests/test_glsandbox/testwindow.cpp @@ -83,7 +83,7 @@ DENG2_OBSERVES(Bank, Load) self.canvas().audienceForGLInit += this; self.canvas().audienceForGLResize += this; - Clock::appClock().audienceForTimeChange += this; + Clock::appClock().audienceForTimeChange() += this; uColor = Vector4f(.5f, .75f, .5f, 1); atlas->setTotalSize(Vector2ui(256, 256)); @@ -91,7 +91,7 @@ DENG2_OBSERVES(Bank, Load) imageBank.add("rtt.cube", "/data/graphics/testpic.png"); //imageBank.loadAll(); - imageBank.audienceForLoad += this; + imageBank.audienceForLoad() += this; } void canvasGLInit(Canvas &cv) From c72e3422d7b43fc179ebc4dc2646d2b13eaf8248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Sun, 2 Mar 2014 20:39:15 +0200 Subject: [PATCH 52/60] Refactor|libgui: Use pimpl-friendly audiences for libgui classes All usage of libgui classes updated accordingly. --- doomsday/client/src/ui/clientwindow.cpp | 12 ++-- .../src/ui/dialogs/videosettingsdialog.cpp | 4 +- .../include/de/framework/guiwidgetprivate.h | 4 +- doomsday/libappfw/src/basewindow.cpp | 8 +-- .../libappfw/src/widgets/documentwidget.cpp | 4 +- doomsday/libappfw/src/widgets/logwidget.cpp | 4 +- doomsday/libdeng2/include/de/data/observers.h | 2 +- doomsday/libgui/include/de/gui/atlas.h | 4 +- doomsday/libgui/include/de/gui/canvas.h | 10 ++-- doomsday/libgui/include/de/gui/gluniform.h | 4 +- doomsday/libgui/include/de/gui/guiapp.h | 2 +- .../libgui/include/de/gui/keyeventsource.h | 6 +- .../libgui/include/de/gui/mouseeventsource.h | 9 ++- .../include/de/gui/persistentcanvaswindow.h | 2 +- doomsday/libgui/libgui.pro | 2 + doomsday/libgui/src/atlas.cpp | 10 +++- doomsday/libgui/src/canvas.cpp | 56 +++++++++++-------- doomsday/libgui/src/canvaswindow.cpp | 14 ++--- doomsday/libgui/src/glprogram.cpp | 12 ++-- doomsday/libgui/src/gluniform.cpp | 10 +++- doomsday/libgui/src/guiapp.cpp | 8 ++- doomsday/libgui/src/keyeventsource.cpp | 34 +++++++++++ doomsday/libgui/src/mouseeventsource.cpp | 35 ++++++++++++ .../libgui/src/persistentcanvaswindow.cpp | 8 ++- doomsday/tests/test_glsandbox/testwindow.cpp | 4 +- 25 files changed, 189 insertions(+), 79 deletions(-) create mode 100644 doomsday/libgui/src/keyeventsource.cpp create mode 100644 doomsday/libgui/src/mouseeventsource.cpp diff --git a/doomsday/client/src/ui/clientwindow.cpp b/doomsday/client/src/ui/clientwindow.cpp index 5c859a4000..3ce760b67e 100644 --- a/doomsday/client/src/ui/clientwindow.cpp +++ b/doomsday/client/src/ui/clientwindow.cpp @@ -130,7 +130,7 @@ DENG2_PIMPL(ClientWindow) App::app().audienceForStartupComplete() += this; // Listen to input. - self.canvas().audienceForMouseStateChange += this; + self.canvas().audienceForMouseStateChange() += this; } ~Instance() @@ -138,8 +138,8 @@ DENG2_PIMPL(ClientWindow) App::app().audienceForGameChange() -= this; App::app().audienceForStartupComplete() -= this; - self.canvas().audienceForFocusChange -= this; - self.canvas().audienceForMouseStateChange -= this; + self.canvas().audienceForFocusChange() -= this; + self.canvas().audienceForMouseStateChange() -= this; releaseRef(cursorX); releaseRef(cursorY); @@ -341,7 +341,7 @@ DENG2_PIMPL(ClientWindow) } */ - self.canvas().audienceForFocusChange += this; + self.canvas().audienceForFocusChange() += this; #ifdef WIN32 if(self.isFullScreen()) @@ -651,8 +651,8 @@ ClientWindow::ClientWindow(String const &id) : BaseWindow(id) , d(new Instance(this)) { - canvas().audienceForGLResize += this; - canvas().audienceForGLInit += this; + canvas().audienceForGLResize() += this; + canvas().audienceForGLInit() += this; #ifdef WIN32 // Set an icon for the window. diff --git a/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp b/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp index da370bef0c..d3ece3ddfe 100644 --- a/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp +++ b/doomsday/client/src/ui/dialogs/videosettingsdialog.cpp @@ -70,12 +70,12 @@ DENG2_OBSERVES(PersistentCanvasWindow, AttributeChange) #ifdef USE_COLOR_DEPTH_CHOICE area.add(depths = new ChoiceWidget); #endif - win.audienceForAttributeChange += this; + win.audienceForAttributeChange() += this; } ~Instance() { - win.audienceForAttributeChange -= this; + win.audienceForAttributeChange() -= this; } /** diff --git a/doomsday/libappfw/include/de/framework/guiwidgetprivate.h b/doomsday/libappfw/include/de/framework/guiwidgetprivate.h index 8ed31c717a..00ca9de28a 100644 --- a/doomsday/libappfw/include/de/framework/guiwidgetprivate.h +++ b/doomsday/libappfw/include/de/framework/guiwidgetprivate.h @@ -60,7 +60,7 @@ class GuiWidgetPrivate : public Private, { if(_observingAtlas) { - _observingAtlas->audienceForReposition -= this; + _observingAtlas->audienceForReposition() -= this; } /** @@ -80,7 +80,7 @@ class GuiWidgetPrivate : public Private, { // Automatically start observing the root atlas. _observingAtlas = &root().atlas(); - _observingAtlas->audienceForReposition += this; + _observingAtlas->audienceForReposition() += this; } } diff --git a/doomsday/libappfw/src/basewindow.cpp b/doomsday/libappfw/src/basewindow.cpp index 8831eae76f..d85f7554bb 100644 --- a/doomsday/libappfw/src/basewindow.cpp +++ b/doomsday/libappfw/src/basewindow.cpp @@ -37,14 +37,14 @@ DENG2_PIMPL(BaseWindow) , xf(&defaultXf) { // Listen to input. - self.canvas().audienceForKeyEvent += this; - self.canvas().audienceForMouseEvent += this; + self.canvas().audienceForKeyEvent() += this; + self.canvas().audienceForMouseEvent() += this; } ~Instance() { - self.canvas().audienceForKeyEvent -= this; - self.canvas().audienceForMouseEvent -= this; + self.canvas().audienceForKeyEvent() -= this; + self.canvas().audienceForMouseEvent() -= this; } void keyEvent(KeyEvent const &ev) diff --git a/doomsday/libappfw/src/widgets/documentwidget.cpp b/doomsday/libappfw/src/widgets/documentwidget.cpp index 1fb98813b3..df33af3204 100644 --- a/doomsday/libappfw/src/widgets/documentwidget.cpp +++ b/doomsday/libappfw/src/widgets/documentwidget.cpp @@ -125,7 +125,7 @@ public Font::RichFormat::IStyle void glInit() { - atlas().audienceForReposition += this; + atlas().audienceForReposition() += this; glText.init(atlas(), self.font(), this); @@ -145,7 +145,7 @@ public Font::RichFormat::IStyle void glDeinit() { - atlas().audienceForReposition -= this; + atlas().audienceForReposition() -= this; glText.deinit(); drawable.clear(); } diff --git a/doomsday/libappfw/src/widgets/logwidget.cpp b/doomsday/libappfw/src/widgets/logwidget.cpp index 11425e6998..49ea394bdc 100644 --- a/doomsday/libappfw/src/widgets/logwidget.cpp +++ b/doomsday/libappfw/src/widgets/logwidget.cpp @@ -463,8 +463,8 @@ public Font::RichFormat::IStyle Atlas::BackingStore | Atlas::AllowDefragment, GLTexture::maximumSize().min(Atlas::Size(4096, 2048))); - entryAtlas->audienceForReposition += this; - entryAtlas->audienceForOutOfSpace += this; + entryAtlas->audienceForReposition() += this; + entryAtlas->audienceForOutOfSpace() += this; // Simple texture for the scroll indicator. Image solidWhitePixel = Image::solidColor(Image::Color(255, 255, 255, 255), diff --git a/doomsday/libdeng2/include/de/data/observers.h b/doomsday/libdeng2/include/de/data/observers.h index 9c06c404da..a0a6bd294c 100644 --- a/doomsday/libdeng2/include/de/data/observers.h +++ b/doomsday/libdeng2/include/de/data/observers.h @@ -141,7 +141,7 @@ DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, self.audienceFor##Name) #define DENG2_FOR_PUBLIC_AUDIENCE2(Name, Var) \ - DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, audienceFor##Name) + DENG2_FOR_EACH_OBSERVER(Name##Audience, Var, self.audienceFor##Name()) namespace de { diff --git a/doomsday/libgui/include/de/gui/atlas.h b/doomsday/libgui/include/de/gui/atlas.h index 42705e9715..473a09138c 100644 --- a/doomsday/libgui/include/de/gui/atlas.h +++ b/doomsday/libgui/include/de/gui/atlas.h @@ -109,13 +109,13 @@ class LIBGUI_PUBLIC Atlas : public Lockable * repositioned for some reasons (e.g., defragmentation). Normally once * allocated, content will remain at its initial place. */ - DENG2_DEFINE_AUDIENCE(Reposition, void atlasContentRepositioned(Atlas &)) + DENG2_DEFINE_AUDIENCE2(Reposition, void atlasContentRepositioned(Atlas &)) /** * Audience that will be notified when an allocation fails due to the atlas * being so full that there is no room for the new image. */ - DENG2_DEFINE_AUDIENCE(OutOfSpace, void atlasOutOfSpace(Atlas &)) + DENG2_DEFINE_AUDIENCE2(OutOfSpace, void atlasOutOfSpace(Atlas &)) public: /** diff --git a/doomsday/libgui/include/de/gui/canvas.h b/doomsday/libgui/include/de/gui/canvas.h index df88bf08fc..480b8da46c 100644 --- a/doomsday/libgui/include/de/gui/canvas.h +++ b/doomsday/libgui/include/de/gui/canvas.h @@ -57,29 +57,29 @@ class LIBGUI_PUBLIC Canvas : public QGLWidget, public KeyEventSource, public Mou * screen. Note that the notification comes straight from the event loop * (timer signal) instead of during a paint event. */ - DENG2_DEFINE_AUDIENCE(GLReady, void canvasGLReady(Canvas &)) + DENG2_DEFINE_AUDIENCE2(GLReady, void canvasGLReady(Canvas &)) /** * Notified when the canvas's GL state needs to be initialized. This is * called immediately before drawing the contents of the canvas for the * first time (during a paint event). */ - DENG2_DEFINE_AUDIENCE(GLInit, void canvasGLInit(Canvas &)) + DENG2_DEFINE_AUDIENCE2(GLInit, void canvasGLInit(Canvas &)) /** * Notified when a canvas's size has changed. */ - DENG2_DEFINE_AUDIENCE(GLResize, void canvasGLResized(Canvas &)) + DENG2_DEFINE_AUDIENCE2(GLResize, void canvasGLResized(Canvas &)) /** * Notified when drawing of the canvas contents has been requested. */ - DENG2_DEFINE_AUDIENCE(GLDraw, void canvasGLDraw(Canvas &)) + DENG2_DEFINE_AUDIENCE2(GLDraw, void canvasGLDraw(Canvas &)) /** * Notified when the canvas gains or loses input focus. */ - DENG2_DEFINE_AUDIENCE(FocusChange, void canvasFocusChanged(Canvas &, bool hasFocus)) + DENG2_DEFINE_AUDIENCE2(FocusChange, void canvasFocusChanged(Canvas &, bool hasFocus)) public: explicit Canvas(CanvasWindow *parent, QGLWidget* shared = 0); diff --git a/doomsday/libgui/include/de/gui/gluniform.h b/doomsday/libgui/include/de/gui/gluniform.h index 066db6c79d..d126ec3a4c 100644 --- a/doomsday/libgui/include/de/gui/gluniform.h +++ b/doomsday/libgui/include/de/gui/gluniform.h @@ -67,12 +67,12 @@ class LIBGUI_PUBLIC GLUniform /** * Notified when the value of the uniform changes. */ - DENG2_DEFINE_AUDIENCE(ValueChange, void uniformValueChanged(GLUniform &)) + DENG2_DEFINE_AUDIENCE2(ValueChange, void uniformValueChanged(GLUniform &)) /** * Notified when the uniform instance is deleted. */ - DENG2_DEFINE_AUDIENCE(Deletion, void uniformDeleted(GLUniform &)) + DENG2_DEFINE_AUDIENCE2(Deletion, void uniformDeleted(GLUniform &)) public: GLUniform(char const *nameInShader, Type uniformType); diff --git a/doomsday/libgui/include/de/gui/guiapp.h b/doomsday/libgui/include/de/gui/guiapp.h index 8e7813010f..8e6ea2a15e 100644 --- a/doomsday/libgui/include/de/gui/guiapp.h +++ b/doomsday/libgui/include/de/gui/guiapp.h @@ -48,7 +48,7 @@ class LIBGUI_PUBLIC GuiApp : public QApplication, public App, /** * Notified when a Canvas is recreated. */ - DENG2_DEFINE_AUDIENCE(GLContextChange, void appGLContextChanged()) + DENG2_DEFINE_AUDIENCE2(GLContextChange, void appGLContextChanged()) public: GuiApp(int &argc, char **argv); diff --git a/doomsday/libgui/include/de/gui/keyeventsource.h b/doomsday/libgui/include/de/gui/keyeventsource.h index 49d5fc9671..eb0fa89bf3 100644 --- a/doomsday/libgui/include/de/gui/keyeventsource.h +++ b/doomsday/libgui/include/de/gui/keyeventsource.h @@ -32,10 +32,14 @@ namespace de { class LIBGUI_PUBLIC KeyEventSource { public: - DENG2_DEFINE_AUDIENCE(KeyEvent, void keyEvent(KeyEvent const &)) + DENG2_DEFINE_AUDIENCE2(KeyEvent, void keyEvent(KeyEvent const &)) public: + KeyEventSource(); virtual ~KeyEventSource() {} + +private: + DENG2_PRIVATE(d) }; } // namespace de diff --git a/doomsday/libgui/include/de/gui/mouseeventsource.h b/doomsday/libgui/include/de/gui/mouseeventsource.h index b6ea7e773a..f23d93a2ad 100644 --- a/doomsday/libgui/include/de/gui/mouseeventsource.h +++ b/doomsday/libgui/include/de/gui/mouseeventsource.h @@ -38,12 +38,15 @@ class LIBGUI_PUBLIC MouseEventSource Trapped }; - DENG2_DEFINE_AUDIENCE(MouseStateChange, void mouseStateChanged(State)) - - DENG2_DEFINE_AUDIENCE(MouseEvent, void mouseEvent(MouseEvent const &)) + DENG2_DEFINE_AUDIENCE2(MouseStateChange, void mouseStateChanged(State)) + DENG2_DEFINE_AUDIENCE2(MouseEvent, void mouseEvent(MouseEvent const &)) public: + MouseEventSource(); virtual ~MouseEventSource() {} + +private: + DENG2_PRIVATE(d) }; } // namespace de diff --git a/doomsday/libgui/include/de/gui/persistentcanvaswindow.h b/doomsday/libgui/include/de/gui/persistentcanvaswindow.h index a7c2e91dbd..717095b90d 100644 --- a/doomsday/libgui/include/de/gui/persistentcanvaswindow.h +++ b/doomsday/libgui/include/de/gui/persistentcanvaswindow.h @@ -78,7 +78,7 @@ class LIBGUI_PUBLIC PersistentCanvasWindow : public CanvasWindow * changes are queued, the notification is made only after all the changes * have been applied. */ - DENG2_DEFINE_AUDIENCE(AttributeChange, void windowAttributesChanged(PersistentCanvasWindow &)) + DENG2_DEFINE_AUDIENCE2(AttributeChange, void windowAttributesChanged(PersistentCanvasWindow &)) public: /** diff --git a/doomsday/libgui/libgui.pro b/doomsday/libgui/libgui.pro index 0b37defaf3..bc9bd3c494 100644 --- a/doomsday/libgui/libgui.pro +++ b/doomsday/libgui/libgui.pro @@ -150,7 +150,9 @@ SOURCES += \ src/imagebank.cpp \ src/kdtreeatlasallocator.cpp \ src/keyevent.cpp \ + src/keyeventsource.cpp \ src/mouseevent.cpp \ + src/mouseeventsource.cpp \ src/nativefont.cpp \ src/qtnativefont.h \ src/persistentcanvaswindow.cpp \ diff --git a/doomsday/libgui/src/atlas.cpp b/doomsday/libgui/src/atlas.cpp index fc53624cea..66ee4af311 100644 --- a/doomsday/libgui/src/atlas.cpp +++ b/doomsday/libgui/src/atlas.cpp @@ -139,13 +139,19 @@ DENG2_PIMPL(Atlas) markFullyChanged(); mayDefrag = false; - DENG2_FOR_PUBLIC_AUDIENCE(Reposition, i) + DENG2_FOR_PUBLIC_AUDIENCE2(Reposition, i) { i->atlasContentRepositioned(self); } } + + DENG2_PIMPL_AUDIENCE(Reposition) + DENG2_PIMPL_AUDIENCE(OutOfSpace) }; +DENG2_AUDIENCE_METHOD(Atlas, Reposition) +DENG2_AUDIENCE_METHOD(Atlas, OutOfSpace) + Atlas::Atlas(Flags const &flags, Size const &totalSize) : d(new Instance(this, flags, totalSize)) {} @@ -252,7 +258,7 @@ Id Atlas::alloc(Image const &image) { LOG_GL_XVERBOSE("Atlas is full with %.1f%% usage") << d->usedPercentage()*100; - DENG2_FOR_AUDIENCE(OutOfSpace, i) + DENG2_FOR_AUDIENCE2(OutOfSpace, i) { i->atlasOutOfSpace(*this); } diff --git a/doomsday/libgui/src/canvas.cpp b/doomsday/libgui/src/canvas.cpp index 662cf79795..16d3f4840c 100644 --- a/doomsday/libgui/src/canvas.cpp +++ b/doomsday/libgui/src/canvas.cpp @@ -101,7 +101,7 @@ DENG2_PIMPL(Canvas) mouseGrabbed = true; - DENG2_FOR_PUBLIC_AUDIENCE(MouseStateChange, i) + DENG2_FOR_PUBLIC_AUDIENCE2(MouseStateChange, i) { i->mouseStateChanged(Trapped); } @@ -119,7 +119,7 @@ DENG2_PIMPL(Canvas) // Tell the mouse driver that the mouse is untrapped. mouseGrabbed = false; - DENG2_FOR_PUBLIC_AUDIENCE(MouseStateChange, i) + DENG2_FOR_PUBLIC_AUDIENCE2(MouseStateChange, i) { i->mouseStateChanged(Untrapped); } @@ -171,7 +171,7 @@ DENG2_PIMPL(Canvas) } #endif - DENG2_FOR_PUBLIC_AUDIENCE(KeyEvent, i) + DENG2_FOR_PUBLIC_AUDIENCE2(KeyEvent, i) { i->keyEvent(KeyEvent(ev->isAutoRepeat()? KeyEvent::Repeat : ev->type() == QEvent::KeyPress? KeyEvent::Pressed : @@ -215,8 +215,20 @@ DENG2_PIMPL(Canvas) /// @todo Double buffering is not really needed in manual FB mode. framebuf.swapBuffers(self, mode); } + + DENG2_PIMPL_AUDIENCE(GLReady) + DENG2_PIMPL_AUDIENCE(GLInit) + DENG2_PIMPL_AUDIENCE(GLResize) + DENG2_PIMPL_AUDIENCE(GLDraw) + DENG2_PIMPL_AUDIENCE(FocusChange) }; +DENG2_AUDIENCE_METHOD(Canvas, GLReady) +DENG2_AUDIENCE_METHOD(Canvas, GLInit) +DENG2_AUDIENCE_METHOD(Canvas, GLResize) +DENG2_AUDIENCE_METHOD(Canvas, GLDraw) +DENG2_AUDIENCE_METHOD(Canvas, FocusChange) + Canvas::Canvas(CanvasWindow* parent, QGLWidget* shared) : QGLWidget(parent, shared), d(new Instance(this, parent)) { @@ -299,16 +311,16 @@ bool Canvas::isGLReady() const void Canvas::copyAudiencesFrom(Canvas const &other) { - audienceForGLReady = other.audienceForGLReady; - audienceForGLInit = other.audienceForGLInit; - audienceForGLResize = other.audienceForGLResize; - audienceForGLDraw = other.audienceForGLDraw; - audienceForFocusChange = other.audienceForFocusChange; + d->audienceForGLReady = other.d->audienceForGLReady; + d->audienceForGLInit = other.d->audienceForGLInit; + d->audienceForGLResize = other.d->audienceForGLResize; + d->audienceForGLDraw = other.d->audienceForGLDraw; + d->audienceForFocusChange = other.d->audienceForFocusChange; - audienceForKeyEvent = other.audienceForKeyEvent; + audienceForKeyEvent() = other.audienceForKeyEvent(); - audienceForMouseStateChange = other.audienceForMouseStateChange; - audienceForMouseEvent = other.audienceForMouseEvent; + audienceForMouseStateChange() = other.audienceForMouseStateChange(); + audienceForMouseEvent() = other.audienceForMouseEvent(); } GLTarget &Canvas::renderTarget() const @@ -336,7 +348,7 @@ void Canvas::initializeGL() #endif GLInfo::glInit(); - DENG2_FOR_AUDIENCE(GLInit, i) i->canvasGLInit(*this); + DENG2_FOR_AUDIENCE2(GLInit, i) i->canvasGLInit(*this); } void Canvas::resizeGL(int w, int h) @@ -372,7 +384,7 @@ void Canvas::updateSize() d->currentSize = d->pendingSize; d->reconfigureFramebuffer(); - DENG2_FOR_AUDIENCE(GLResize, i) i->canvasGLResized(*this); + DENG2_FOR_AUDIENCE2(GLResize, i) i->canvasGLResized(*this); } void Canvas::showEvent(QShowEvent* ev) @@ -424,7 +436,7 @@ void Canvas::notifyReady() LOG_GL_WARNING("OpenGL 2.0 is not supported!"); LOGDEV_GL_XVERBOSE("Notifying GL ready"); - DENG2_FOR_AUDIENCE(GLReady, i) i->canvasGLReady(*this); + DENG2_FOR_AUDIENCE2(GLReady, i) i->canvasGLReady(*this); // This Canvas instance might have been destroyed now. } @@ -446,7 +458,7 @@ void Canvas::paintGL() // Make sure any changes to the state stack become effective. GLState::current().apply(); - DENG2_FOR_AUDIENCE(GLDraw, i) i->canvasGLDraw(*this); + DENG2_FOR_AUDIENCE2(GLDraw, i) i->canvasGLDraw(*this); LIBGUI_ASSERT_GL_OK(); } @@ -456,7 +468,7 @@ void Canvas::focusInEvent(QFocusEvent*) LOG_AS("Canvas"); LOG_INPUT_VERBOSE("Gained focus"); - DENG2_FOR_AUDIENCE(FocusChange, i) i->canvasFocusChanged(*this, true); + DENG2_FOR_AUDIENCE2(FocusChange, i) i->canvasFocusChanged(*this, true); } void Canvas::focusOutEvent(QFocusEvent*) @@ -467,7 +479,7 @@ void Canvas::focusOutEvent(QFocusEvent*) // Automatically ungrab the mouse if focus is lost. d->ungrabMouse(); - DENG2_FOR_AUDIENCE(FocusChange, i) i->canvasFocusChanged(*this, false); + DENG2_FOR_AUDIENCE2(FocusChange, i) i->canvasFocusChanged(*this, false); } void Canvas::keyPressEvent(QKeyEvent *ev) @@ -507,7 +519,7 @@ void Canvas::mousePressEvent(QMouseEvent *ev) ev->accept(); - DENG2_FOR_AUDIENCE(MouseEvent, i) + DENG2_FOR_AUDIENCE2(MouseEvent, i) { i->mouseEvent(MouseEvent(translateButton(ev->button()), MouseEvent::Pressed, Vector2i(ev->pos().x(), ev->pos().y()))); @@ -524,7 +536,7 @@ void Canvas::mouseReleaseEvent(QMouseEvent* ev) ev->accept(); - DENG2_FOR_AUDIENCE(MouseEvent, i) + DENG2_FOR_AUDIENCE2(MouseEvent, i) { i->mouseEvent(MouseEvent(translateButton(ev->button()), MouseEvent::Released, Vector2i(ev->pos().x(), ev->pos().y()))); @@ -538,7 +550,7 @@ void Canvas::mouseMoveEvent(QMouseEvent *ev) // Absolute events are only emitted when the mouse is untrapped. if(!d->mouseGrabbed) { - DENG2_FOR_AUDIENCE(MouseEvent, i) + DENG2_FOR_AUDIENCE2(MouseEvent, i) { i->mouseEvent(MouseEvent(MouseEvent::Absolute, Vector2i(ev->pos().x(), ev->pos().y()))); @@ -559,7 +571,7 @@ void Canvas::wheelEvent(QWheelEvent *ev) int axis = (ev->orientation() == Qt::Horizontal? 0 : 1); int dir = (ev->delta() < 0? -1 : 1); - DENG2_FOR_AUDIENCE(MouseEvent, i) + DENG2_FOR_AUDIENCE2(MouseEvent, i) { i->mouseEvent(MouseEvent(MouseEvent::FineAngle, axis == 0? Vector2i(ev->delta(), 0) : @@ -571,7 +583,7 @@ void Canvas::wheelEvent(QWheelEvent *ev) { d->wheelDir[axis] = dir; - DENG2_FOR_AUDIENCE(MouseEvent, i) + DENG2_FOR_AUDIENCE2(MouseEvent, i) { i->mouseEvent(MouseEvent(MouseEvent::Step, axis == 0? Vector2i(dir, 0) : diff --git a/doomsday/libgui/src/canvaswindow.cpp b/doomsday/libgui/src/canvaswindow.cpp index c4a08f9a2e..1a8a498c03 100644 --- a/doomsday/libgui/src/canvaswindow.cpp +++ b/doomsday/libgui/src/canvaswindow.cpp @@ -105,7 +105,7 @@ DENG2_PIMPL(CanvasWindow) canvas->makeCurrent(); LIBGUI_ASSERT_GL_OK(); - DENG2_FOR_EACH_OBSERVER(Canvas::GLInitAudience, i, canvas->audienceForGLInit) + DENG2_FOR_EACH_OBSERVER(Canvas::GLInitAudience, i, canvas->audienceForGLInit()) { i->canvasGLInit(*canvas); } @@ -127,7 +127,7 @@ DENG2_PIMPL(CanvasWindow) } // Restore the old focus change audience. - canvas->audienceForFocusChange = canvasFocusAudience; + canvas->audienceForFocusChange() = canvasFocusAudience; LOGDEV_GL_MSG("Canvas replaced with %p") << de::dintptr(canvas); } @@ -139,8 +139,8 @@ CanvasWindow::CanvasWindow() // Create the drawing canvas for this window. setCentralWidget(d->canvas = new Canvas(this)); // takes ownership - d->canvas->audienceForGLReady += this; - d->canvas->audienceForGLDraw += this; + d->canvas->audienceForGLReady() += this; + d->canvas->audienceForGLDraw() += this; // All input goes to the canvas. d->canvas->setFocus(); @@ -166,8 +166,8 @@ void CanvasWindow::recreateCanvas() // Steal the focus change audience temporarily so no spurious focus // notifications are sent. - d->canvasFocusAudience = canvas().audienceForFocusChange; - canvas().audienceForFocusChange.clear(); + d->canvasFocusAudience = canvas().audienceForFocusChange(); + canvas().audienceForFocusChange().clear(); // We'll re-trap the mouse after the new canvas is ready. d->mouseWasTrapped = canvas().isMouseTrapped(); @@ -178,7 +178,7 @@ void CanvasWindow::recreateCanvas() // Create the replacement Canvas. Once it's created and visible, we'll // finish the switch-over. d->recreated = new Canvas(this, d->canvas); - d->recreated->audienceForGLReady += this; + d->recreated->audienceForGLReady() += this; //d->recreated->setGeometry(d->canvas->geometry()); d->recreated->show(); diff --git a/doomsday/libgui/src/glprogram.cpp b/doomsday/libgui/src/glprogram.cpp index b4d736a903..69b64f067e 100644 --- a/doomsday/libgui/src/glprogram.cpp +++ b/doomsday/libgui/src/glprogram.cpp @@ -140,8 +140,8 @@ DENG2_PIMPL(GLProgram) { foreach(GLUniform const *u, bound) { - u->audienceForValueChange -= this; - u->audienceForDeletion -= this; + u->audienceForValueChange() -= this; + u->audienceForDeletion() -= this; } texturesChanged = false; bound.clear(); @@ -351,8 +351,8 @@ GLProgram &GLProgram::bind(GLUniform const &uniform) d->bound.insert(&uniform); d->changed.insert(&uniform); - uniform.audienceForValueChange += d; - uniform.audienceForDeletion += d; + uniform.audienceForValueChange() += d; + uniform.audienceForDeletion() += d; if(uniform.type() == GLUniform::Sampler2D) { @@ -370,8 +370,8 @@ GLProgram &GLProgram::unbind(GLUniform const &uniform) d->bound.remove(&uniform); d->changed.remove(&uniform); - uniform.audienceForValueChange -= d.get(); - uniform.audienceForDeletion -= d.get(); + uniform.audienceForValueChange() -= d.get(); + uniform.audienceForDeletion() -= d.get(); if(uniform.type() == GLUniform::Sampler2D) { diff --git a/doomsday/libgui/src/gluniform.cpp b/doomsday/libgui/src/gluniform.cpp index d14f62a297..a0b90e437a 100644 --- a/doomsday/libgui/src/gluniform.cpp +++ b/doomsday/libgui/src/gluniform.cpp @@ -71,7 +71,7 @@ DENG2_PIMPL(GLUniform) ~Instance() { - DENG2_FOR_PUBLIC_AUDIENCE(Deletion, i) i->uniformDeleted(self); + DENG2_FOR_PUBLIC_AUDIENCE2(Deletion, i) i->uniformDeleted(self); switch(type) { @@ -141,7 +141,7 @@ DENG2_PIMPL(GLUniform) void markAsChanged() { - DENG2_FOR_PUBLIC_AUDIENCE(ValueChange, i) + DENG2_FOR_PUBLIC_AUDIENCE2(ValueChange, i) { i->uniformValueChanged(self); } @@ -158,8 +158,14 @@ DENG2_PIMPL(GLUniform) } } } + + DENG2_PIMPL_AUDIENCE(Deletion) + DENG2_PIMPL_AUDIENCE(ValueChange) }; +DENG2_AUDIENCE_METHOD(GLUniform, Deletion) +DENG2_AUDIENCE_METHOD(GLUniform, ValueChange) + GLUniform::GLUniform(char const *nameInShader, Type uniformType) : d(new Instance(this, QLatin1String(nameInShader), uniformType)) {} diff --git a/doomsday/libgui/src/guiapp.cpp b/doomsday/libgui/src/guiapp.cpp index 160628a373..6353c38b33 100644 --- a/doomsday/libgui/src/guiapp.cpp +++ b/doomsday/libgui/src/guiapp.cpp @@ -36,8 +36,12 @@ DENG2_PIMPL(GuiApp) { loop.audienceForIteration() += self; } + + DENG2_PIMPL_AUDIENCE(GLContextChange) }; +DENG2_AUDIENCE_METHOD(GuiApp, GLContextChange) + GuiApp::GuiApp(int &argc, char **argv) : QApplication(argc, argv), App(applicationFilePath(), arguments()), @@ -80,8 +84,8 @@ void GuiApp::notifyDisplayModeChanged() void GuiApp::notifyGLContextChanged() { - qDebug() << "notifying GL context change" << audienceForGLContextChange.size(); - DENG2_FOR_AUDIENCE(GLContextChange, i) i->appGLContextChanged(); + qDebug() << "notifying GL context change" << audienceForGLContextChange().size(); + DENG2_FOR_AUDIENCE2(GLContextChange, i) i->appGLContextChanged(); } int GuiApp::execLoop() diff --git a/doomsday/libgui/src/keyeventsource.cpp b/doomsday/libgui/src/keyeventsource.cpp new file mode 100644 index 0000000000..ab8dd6935e --- /dev/null +++ b/doomsday/libgui/src/keyeventsource.cpp @@ -0,0 +1,34 @@ +/** @file keyeventsource.cpp + * + * @authors Copyright (c) 2014 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#include "de/KeyEventSource" + +namespace de { + +DENG2_PIMPL_NOREF(KeyEventSource) +{ + DENG2_PIMPL_AUDIENCE(KeyEvent) +}; + +DENG2_AUDIENCE_METHOD(KeyEventSource, KeyEvent) + +KeyEventSource::KeyEventSource() : d(new Instance) +{} + +} // namespace de + diff --git a/doomsday/libgui/src/mouseeventsource.cpp b/doomsday/libgui/src/mouseeventsource.cpp new file mode 100644 index 0000000000..6484672746 --- /dev/null +++ b/doomsday/libgui/src/mouseeventsource.cpp @@ -0,0 +1,35 @@ +/** @file mouseeventsource.cpp + * + * @authors Copyright (c) 2014 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. This program is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#include "de/MouseEventSource" + +namespace de { + +DENG2_PIMPL_NOREF(MouseEventSource) +{ + DENG2_PIMPL_AUDIENCE(MouseStateChange) + DENG2_PIMPL_AUDIENCE(MouseEvent) +}; + +DENG2_AUDIENCE_METHOD(MouseEventSource, MouseStateChange) +DENG2_AUDIENCE_METHOD(MouseEventSource, MouseEvent) + +MouseEventSource::MouseEventSource() : d(new Instance) +{} + +} // namespace de diff --git a/doomsday/libgui/src/persistentcanvaswindow.cpp b/doomsday/libgui/src/persistentcanvaswindow.cpp index 241a7c3772..e820005a2e 100644 --- a/doomsday/libgui/src/persistentcanvaswindow.cpp +++ b/doomsday/libgui/src/persistentcanvaswindow.cpp @@ -737,7 +737,7 @@ DENG2_PIMPL(PersistentCanvasWindow) } // The queue is now empty; all modifications to state have been applied. - DENG2_FOR_PUBLIC_AUDIENCE(AttributeChange, i) + DENG2_FOR_PUBLIC_AUDIENCE2(AttributeChange, i) { i->windowAttributesChanged(self); } @@ -761,8 +761,12 @@ DENG2_PIMPL(PersistentCanvasWindow) return st; } + + DENG2_PIMPL_AUDIENCE(AttributeChange) }; +DENG2_AUDIENCE_METHOD(PersistentCanvasWindow, AttributeChange) + PersistentCanvasWindow::PersistentCanvasWindow(String const &id) : d(new Instance(this, id)) { @@ -896,7 +900,7 @@ void PersistentCanvasWindow::moveEvent(QMoveEvent *) d->state.setFlag(Instance::State::Centered, false); // Notify. - DENG2_FOR_AUDIENCE(AttributeChange, i) + DENG2_FOR_AUDIENCE2(AttributeChange, i) { i->windowAttributesChanged(*this); } diff --git a/doomsday/tests/test_glsandbox/testwindow.cpp b/doomsday/tests/test_glsandbox/testwindow.cpp index aa4c13b1fe..5a96be082e 100644 --- a/doomsday/tests/test_glsandbox/testwindow.cpp +++ b/doomsday/tests/test_glsandbox/testwindow.cpp @@ -81,8 +81,8 @@ DENG2_OBSERVES(Bank, Load) // Use this as the main window. setMain(i); - self.canvas().audienceForGLInit += this; - self.canvas().audienceForGLResize += this; + self.canvas().audienceForGLInit() += this; + self.canvas().audienceForGLResize() += this; Clock::appClock().audienceForTimeChange() += this; uColor = Vector4f(.5f, .75f, .5f, 1); From 8065a125b816be31bb0e75bb36b1d8a29f2f9428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 08:19:40 +0200 Subject: [PATCH 53/60] Refactor|LabelWidget: Rules for expansion Internally, the width and height rules may be either the grow animation rules or the constant rules describing the true size of the content. --- doomsday/libappfw/src/widgets/labelwidget.cpp | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/doomsday/libappfw/src/widgets/labelwidget.cpp b/doomsday/libappfw/src/widgets/labelwidget.cpp index 344a0de46c..86f98825b5 100644 --- a/doomsday/libappfw/src/widgets/labelwidget.cpp +++ b/doomsday/libappfw/src/widgets/labelwidget.cpp @@ -513,6 +513,38 @@ public Font::RichFormat::IStyle self.updateModelViewProjection(uMvpMatrix); drawable.draw(); } + + Rule const *widthRule() const + { + switch(appearType) + { + case AppearInstantly: + case AppearGrowVertically: + if(horizPolicy == Expand) return width; + break; + + case AppearGrowHorizontally: + if(horizPolicy == Expand) return appearSize; + break; + } + return 0; + } + + Rule const *heightRule() const + { + switch(appearType) + { + case AppearInstantly: + case AppearGrowHorizontally: + if(vertPolicy == Expand) return height; + break; + + case AppearGrowVertically: + if(vertPolicy == Expand) return appearSize; + break; + } + return 0; + } }; LabelWidget::LabelWidget(String const &name) : GuiWidget(name), d(new Instance(this)) @@ -715,7 +747,7 @@ void LabelWidget::setWidthPolicy(SizePolicy policy) d->horizPolicy = policy; if(policy == Expand) { - rule().setInput(Rule::Width, *d->width); + rule().setInput(Rule::Width, *d->widthRule()); } else { @@ -728,7 +760,7 @@ void LabelWidget::setHeightPolicy(SizePolicy policy) d->vertPolicy = policy; if(policy == Expand) { - rule().setInput(Rule::Height, *d->height); + rule().setInput(Rule::Height, *d->heightRule()); } else { @@ -741,22 +773,13 @@ void LabelWidget::setAppearanceAnimation(AppearanceAnimation method, TimeDelta c d->appearType = method; d->appearSpan = span; - switch(d->appearType) + if(Rule const *w = d->widthRule()) { - case AppearInstantly: - if(d->horizPolicy == Expand) rule().setInput(Rule::Width, *d->width); - if(d->vertPolicy == Expand) rule().setInput(Rule::Height, *d->height); - break; - - case AppearGrowHorizontally: - if(d->horizPolicy == Expand) rule().setInput(Rule::Width, *d->appearSize); - if(d->vertPolicy == Expand) rule().setInput(Rule::Height, *d->height); - break; - - case AppearGrowVertically: - if(d->horizPolicy == Expand) rule().setInput(Rule::Width, *d->width); - if(d->vertPolicy == Expand) rule().setInput(Rule::Height, *d->appearSize); - break; + rule().setInput(Rule::Width, *w); + } + if(Rule const *h = d->heightRule()) + { + rule().setInput(Rule::Height, *h); } } From 0ad59d1350dc9923075de944d4009b95444325f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 11:18:48 +0200 Subject: [PATCH 54/60] Refactor|libappfw: Use pimpl-friendly audiences for libappfw classes All use of libappfw classes updated accordingly. --- .../client/src/ui/dialogs/alertdialog.cpp | 4 +- .../src/ui/dialogs/logsettingsdialog.cpp | 2 +- .../src/ui/widgets/gameselectionwidget.cpp | 2 +- .../src/ui/widgets/gamesessionwidget.cpp | 2 +- .../src/ui/widgets/mpselectionwidget.cpp | 2 +- .../src/ui/widgets/profilepickerwidget.cpp | 4 +- .../src/updater/updateavailabledialog.cpp | 2 +- .../src/updater/updatersettingsdialog.cpp | 2 +- .../de/framework/childwidgetorganizer.h | 4 +- doomsday/libappfw/include/de/framework/data.h | 11 +++- doomsday/libappfw/include/de/framework/item.h | 22 +++---- .../libappfw/include/de/framework/margins.h | 2 +- .../include/de/widgets/buttonwidget.h | 6 +- .../libappfw/include/de/widgets/panelwidget.h | 2 +- .../include/de/widgets/togglewidget.h | 2 +- .../libappfw/src/childwidgetorganizer.cpp | 28 +++++---- doomsday/libappfw/src/data.cpp | 14 +++++ doomsday/libappfw/src/guiwidget.cpp | 2 +- doomsday/libappfw/src/item.cpp | 58 ++++++++++++++++--- doomsday/libappfw/src/listdata.cpp | 8 +-- doomsday/libappfw/src/margins.cpp | 6 +- .../libappfw/src/widgets/buttonwidget.cpp | 14 ++++- .../libappfw/src/widgets/choicewidget.cpp | 12 ++-- .../libappfw/src/widgets/dialogwidget.cpp | 16 ++--- doomsday/libappfw/src/widgets/menuwidget.cpp | 14 ++--- doomsday/libappfw/src/widgets/panelwidget.cpp | 6 +- .../libappfw/src/widgets/popupmenuwidget.cpp | 8 +-- doomsday/libappfw/src/widgets/tabwidget.cpp | 8 +-- .../libappfw/src/widgets/togglewidget.cpp | 10 +++- .../src/widgets/variabletogglewidget.cpp | 4 +- 30 files changed, 179 insertions(+), 98 deletions(-) diff --git a/doomsday/client/src/ui/dialogs/alertdialog.cpp b/doomsday/client/src/ui/dialogs/alertdialog.cpp index 17914fda44..cb0ed9fa93 100644 --- a/doomsday/client/src/ui/dialogs/alertdialog.cpp +++ b/doomsday/client/src/ui/dialogs/alertdialog.cpp @@ -106,8 +106,8 @@ DENG_GUI_PIMPL(AlertDialog) area.enableIndicatorDraw(true); - alerts->organizer().audienceForWidgetCreation += this; - alerts->organizer().audienceForWidgetUpdate += this; + alerts->organizer().audienceForWidgetCreation() += this; + alerts->organizer().audienceForWidgetUpdate() += this; } NotificationWidget ¬ifs() diff --git a/doomsday/client/src/ui/dialogs/logsettingsdialog.cpp b/doomsday/client/src/ui/dialogs/logsettingsdialog.cpp index 1ff2dbf3d5..7454c9a2d1 100644 --- a/doomsday/client/src/ui/dialogs/logsettingsdialog.cpp +++ b/doomsday/client/src/ui/dialogs/logsettingsdialog.cpp @@ -100,7 +100,7 @@ DENG2_PIMPL(LogSettingsDialog) // This'll keep the dialog's size fixed even though the choices change size. columnWidth->setSource(domWidgets[0].level->maximumWidth()); - separately->audienceForToggle += this; + separately->audienceForToggle() += this; } catch(Error const &er) { diff --git a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp index f3f2042e9a..7f91583ab8 100644 --- a/doomsday/client/src/ui/widgets/gameselectionwidget.cpp +++ b/doomsday/client/src/ui/widgets/gameselectionwidget.cpp @@ -115,7 +115,7 @@ DENG_GUI_PIMPL(GameSelectionWidget) break; } - menu->items().audienceForAddition += this; + menu->items().audienceForAddition() += this; setContent(menu); menu->enableScrolling(false); diff --git a/doomsday/client/src/ui/widgets/gamesessionwidget.cpp b/doomsday/client/src/ui/widgets/gamesessionwidget.cpp index 73791733fc..c15ccff701 100644 --- a/doomsday/client/src/ui/widgets/gamesessionwidget.cpp +++ b/doomsday/client/src/ui/widgets/gamesessionwidget.cpp @@ -49,7 +49,7 @@ DENG2_PIMPL(GameSessionWidget) self.add(popup = new DocumentPopupWidget); popup->setAnchorAndOpeningDirection(info->rule(), ui::Up); popup->document().setMaximumLineWidth(popup->style().rules().rule("document.popup.width").valuei()); - info->audienceForPress += this; + info->audienceForPress() += this; App::app().audienceForGameUnload() += this; } diff --git a/doomsday/client/src/ui/widgets/mpselectionwidget.cpp b/doomsday/client/src/ui/widgets/mpselectionwidget.cpp index 708307a912..8c1f6063e6 100644 --- a/doomsday/client/src/ui/widgets/mpselectionwidget.cpp +++ b/doomsday/client/src/ui/widgets/mpselectionwidget.cpp @@ -139,7 +139,7 @@ DENG_GUI_PIMPL(MPSelectionWidget) GuiWidget *makeItemWidget(ui::Item const &item, GuiWidget const *) { ServerWidget *w = new ServerWidget; - w->loadButton().audienceForPress += this; + w->loadButton().audienceForPress() += this; w->rule().setInput(Rule::Height, w->loadButton().rule().height()); // Automatically close the info popup if the dialog is closed. diff --git a/doomsday/client/src/ui/widgets/profilepickerwidget.cpp b/doomsday/client/src/ui/widgets/profilepickerwidget.cpp index d7fb8cf182..4200a4193d 100644 --- a/doomsday/client/src/ui/widgets/profilepickerwidget.cpp +++ b/doomsday/client/src/ui/widgets/profilepickerwidget.cpp @@ -51,7 +51,7 @@ DENG_GUI_PIMPL(ProfilePickerWidget) ~Instance() { - if(menu) menu->audienceForClose -= this; + if(menu) menu->audienceForClose() -= this; } void updateStyle() @@ -161,7 +161,7 @@ void ProfilePickerWidget::openMenu() d->menu->setDeleteAfterDismissed(true); d->menu->setAnchorAndOpeningDirection(d->button->rule(), ui::Down); - d->menu->audienceForClose += d; + d->menu->audienceForClose() += d; d->menu->open(); } diff --git a/doomsday/client/src/updater/updateavailabledialog.cpp b/doomsday/client/src/updater/updateavailabledialog.cpp index 552631dbcb..4166dffb01 100644 --- a/doomsday/client/src/updater/updateavailabledialog.cpp +++ b/doomsday/client/src/updater/updateavailabledialog.cpp @@ -94,7 +94,7 @@ DENG2_OBSERVES(ToggleWidget, Toggle) self.area().add(autoCheck); autoCheck->setAlignment(ui::AlignLeft); autoCheck->setText(tr("Check for updates automatically")); - autoCheck->audienceForToggle += this; + autoCheck->audienceForToggle() += this; // Include the toggle in the layout. self.updateLayout(); diff --git a/doomsday/client/src/updater/updatersettingsdialog.cpp b/doomsday/client/src/updater/updatersettingsdialog.cpp index 2a0b84430d..376477c043 100644 --- a/doomsday/client/src/updater/updatersettingsdialog.cpp +++ b/doomsday/client/src/updater/updatersettingsdialog.cpp @@ -112,7 +112,7 @@ DENG2_OBSERVES(ToggleWidget, Toggle) fetch(); - autoCheck->audienceForToggle += this; + autoCheck->audienceForToggle() += this; // Place the widgets into a grid. GridLayout layout(area.contentRule().left(), area.contentRule().top()); diff --git a/doomsday/libappfw/include/de/framework/childwidgetorganizer.h b/doomsday/libappfw/include/de/framework/childwidgetorganizer.h index 7c4dfe1b90..7b2dce319e 100644 --- a/doomsday/libappfw/include/de/framework/childwidgetorganizer.h +++ b/doomsday/libappfw/include/de/framework/childwidgetorganizer.h @@ -100,7 +100,7 @@ class LIBAPPFW_PUBLIC ChildWidgetOrganizer * Notified when the organizer creates a widget for a context item. Allows * third parties to customize the widget as needed. */ - DENG2_DEFINE_AUDIENCE(WidgetCreation, + DENG2_DEFINE_AUDIENCE2(WidgetCreation, void widgetCreatedForItem(GuiWidget &widget, ui::Item const &item)) @@ -108,7 +108,7 @@ class LIBAPPFW_PUBLIC ChildWidgetOrganizer * Notified when the organizer updates a widget for a changed context item. * Allows third parties to customize the widget as needed. */ - DENG2_DEFINE_AUDIENCE(WidgetUpdate, + DENG2_DEFINE_AUDIENCE2(WidgetUpdate, void widgetUpdatedForItem(GuiWidget &widget, ui::Item const &item)) diff --git a/doomsday/libappfw/include/de/framework/data.h b/doomsday/libappfw/include/de/framework/data.h index 7384340ee7..bae21bc774 100644 --- a/doomsday/libappfw/include/de/framework/data.h +++ b/doomsday/libappfw/include/de/framework/data.h @@ -50,18 +50,20 @@ class LIBAPPFW_PUBLIC Data /** * Notified when a new item is added to the data context. */ - DENG2_DEFINE_AUDIENCE(Addition, void dataItemAdded(Pos id, Item const &item)) + DENG2_DEFINE_AUDIENCE2(Addition, void dataItemAdded(Pos id, Item const &item)) /** * Notified when an item has been removed from the data context. When this * is called @a item is no longer in the context and can be modified at * will. */ - DENG2_DEFINE_AUDIENCE(Removal, void dataItemRemoved(Pos oldId, Item &item)) + DENG2_DEFINE_AUDIENCE2(Removal, void dataItemRemoved(Pos oldId, Item &item)) - DENG2_DEFINE_AUDIENCE(OrderChange, void dataItemOrderChanged()) + DENG2_DEFINE_AUDIENCE2(OrderChange, void dataItemOrderChanged()) public: + Data(); + virtual ~Data() {} virtual Data &clear() = 0; @@ -125,6 +127,9 @@ class LIBAPPFW_PUBLIC Data * Returns the total number of items in the data context. */ virtual dsize size() const = 0; + +private: + DENG2_PRIVATE(d) }; typedef Data::Pos DataPos; diff --git a/doomsday/libappfw/include/de/framework/item.h b/doomsday/libappfw/include/de/framework/item.h index dc5ed13df3..612830cab3 100644 --- a/doomsday/libappfw/include/de/framework/item.h +++ b/doomsday/libappfw/include/de/framework/item.h @@ -60,7 +60,7 @@ class LIBAPPFW_PUBLIC Item }; Q_DECLARE_FLAGS(Semantics, SemanticFlag) - DENG2_DEFINE_AUDIENCE(Change, void itemChanged(Item const &item)) + DENG2_DEFINE_AUDIENCE2(Change, void itemChanged(Item const &item)) public: Item(Semantics semantics = DefaultSemantics); @@ -75,14 +75,11 @@ class LIBAPPFW_PUBLIC Item String label() const; - void setDataContext(Data &context) { _context = &context; } + void setDataContext(Data &context); - bool hasDataContext() const { return _context != 0; } + bool hasDataContext() const; - Data &dataContext() const { - DENG2_ASSERT(hasDataContext()); - return *_context; - } + Data &dataContext() const; /** * Returns a text string that should be used for sorting the item inside a @@ -95,9 +92,9 @@ class LIBAPPFW_PUBLIC Item * * @param d Variant data to be associated with the item. */ - void setData(QVariant const &d) { _data = d; } + void setData(QVariant const &d); - QVariant const &data() const { return _data; } + QVariant const &data() const; DENG2_AS_IS_METHODS() @@ -108,12 +105,7 @@ class LIBAPPFW_PUBLIC Item void notifyChange(); private: - Semantics _semantics; - Data *_context; - String _label; - QVariant _data; - - friend class Data; + DENG2_PRIVATE(d) }; Q_DECLARE_OPERATORS_FOR_FLAGS(Item::Semantics) diff --git a/doomsday/libappfw/include/de/framework/margins.h b/doomsday/libappfw/include/de/framework/margins.h index 9a584beaaf..5e38bae768 100644 --- a/doomsday/libappfw/include/de/framework/margins.h +++ b/doomsday/libappfw/include/de/framework/margins.h @@ -34,7 +34,7 @@ namespace ui { class LIBAPPFW_PUBLIC Margins { public: - DENG2_DEFINE_AUDIENCE(Change, void marginsChanged()) + DENG2_DEFINE_AUDIENCE2(Change, void marginsChanged()) public: Margins(String const &defaultMargin = "gap"); diff --git a/doomsday/libappfw/include/de/widgets/buttonwidget.h b/doomsday/libappfw/include/de/widgets/buttonwidget.h index 912c2596e9..ce7322fc57 100644 --- a/doomsday/libappfw/include/de/widgets/buttonwidget.h +++ b/doomsday/libappfw/include/de/widgets/buttonwidget.h @@ -43,20 +43,20 @@ class LIBAPPFW_PUBLIC ButtonWidget : public LabelWidget /** * Notified when the state of the button changes. */ - DENG2_DEFINE_AUDIENCE(StateChange, void buttonStateChanged(ButtonWidget &button, State state)) + DENG2_DEFINE_AUDIENCE2(StateChange, void buttonStateChanged(ButtonWidget &button, State state)) /** * Notified immediately before the button's action is to be triggered. Will * occur regardless of whether an action has been set. */ - DENG2_DEFINE_AUDIENCE(Press, void buttonPressed(ButtonWidget &button)) + DENG2_DEFINE_AUDIENCE2(Press, void buttonPressed(ButtonWidget &button)) /** * Notified when the button's action is triggered (could be before or after * the action). Will not occur if no action has been defined for the * button. */ - DENG2_DEFINE_AUDIENCE(Triggered, void buttonActionTriggered(ButtonWidget &button)) + DENG2_DEFINE_AUDIENCE2(Triggered, void buttonActionTriggered(ButtonWidget &button)) public: ButtonWidget(String const &name = ""); diff --git a/doomsday/libappfw/include/de/widgets/panelwidget.h b/doomsday/libappfw/include/de/widgets/panelwidget.h index 547031ba1d..288dfee8e1 100644 --- a/doomsday/libappfw/include/de/widgets/panelwidget.h +++ b/doomsday/libappfw/include/de/widgets/panelwidget.h @@ -43,7 +43,7 @@ class LIBAPPFW_PUBLIC PanelWidget : public GuiWidget /** * Audience to be notified when the panel is closing. */ - DENG2_DEFINE_AUDIENCE(Close, void panelBeingClosed(PanelWidget &)) + DENG2_DEFINE_AUDIENCE2(Close, void panelBeingClosed(PanelWidget &)) public: PanelWidget(String const &name = ""); diff --git a/doomsday/libappfw/include/de/widgets/togglewidget.h b/doomsday/libappfw/include/de/widgets/togglewidget.h index 644077dd1d..9df8ff39ab 100644 --- a/doomsday/libappfw/include/de/widgets/togglewidget.h +++ b/doomsday/libappfw/include/de/widgets/togglewidget.h @@ -40,7 +40,7 @@ class LIBAPPFW_PUBLIC ToggleWidget : public ButtonWidget /** * Audience to be notified whenever the toggle is toggled. */ - DENG2_DEFINE_AUDIENCE(Toggle, void toggleStateChanged(ToggleWidget &toggle)) + DENG2_DEFINE_AUDIENCE2(Toggle, void toggleStateChanged(ToggleWidget &toggle)) public: ToggleWidget(String const &name = ""); diff --git a/doomsday/libappfw/src/childwidgetorganizer.cpp b/doomsday/libappfw/src/childwidgetorganizer.cpp index 2d0fc3ea01..fb937dee60 100644 --- a/doomsday/libappfw/src/childwidgetorganizer.cpp +++ b/doomsday/libappfw/src/childwidgetorganizer.cpp @@ -63,9 +63,9 @@ DENG2_OBSERVES(ui::Item, Change ) { if(context) { - context->audienceForAddition -= this; - context->audienceForRemoval -= this; - context->audienceForOrderChange -= this; + context->audienceForAddition() -= this; + context->audienceForRemoval() -= this; + context->audienceForOrderChange() -= this; clearWidgets(); context = 0; @@ -77,9 +77,9 @@ DENG2_OBSERVES(ui::Item, Change ) { makeWidgets(); - context->audienceForAddition += this; - context->audienceForRemoval += this; - context->audienceForOrderChange += this; + context->audienceForAddition() += this; + context->audienceForRemoval() += this; + context->audienceForOrderChange() += this; } } @@ -116,14 +116,14 @@ DENG2_OBSERVES(ui::Item, Change ) } // Others may alter the widget in some way. - DENG2_FOR_PUBLIC_AUDIENCE(WidgetCreation, i) + DENG2_FOR_PUBLIC_AUDIENCE2(WidgetCreation, i) { i->widgetCreatedForItem(*w, item); } // Observe. w->audienceForDeletion() += this; // in case it's manually deleted - item.audienceForChange += this; + item.audienceForChange() += this; } void makeWidgets() @@ -147,7 +147,7 @@ DENG2_OBSERVES(ui::Item, Change ) { DENG2_FOR_EACH_CONST(Mapping, i, mapping) { - i.key()->audienceForChange -= this; + i.key()->audienceForChange() -= this; deleteWidget(i.value()); } @@ -182,7 +182,7 @@ DENG2_OBSERVES(ui::Item, Change ) Mapping::const_iterator found = mapping.constFind(&item); if(found != mapping.constEnd()) { - found.key()->audienceForChange -= this; + found.key()->audienceForChange() -= this; deleteWidget(found.value()); mapping.remove(found.key()); } @@ -216,7 +216,7 @@ DENG2_OBSERVES(ui::Item, Change ) factory->updateItemWidget(w, item); // Notify. - DENG2_FOR_PUBLIC_AUDIENCE(WidgetUpdate, i) + DENG2_FOR_PUBLIC_AUDIENCE2(WidgetUpdate, i) { i->widgetUpdatedForItem(w, item); } @@ -252,8 +252,14 @@ DENG2_OBSERVES(ui::Item, Change ) } return 0; } + + DENG2_PIMPL_AUDIENCE(WidgetCreation) + DENG2_PIMPL_AUDIENCE(WidgetUpdate) }; +DENG2_AUDIENCE_METHOD(ChildWidgetOrganizer, WidgetCreation) +DENG2_AUDIENCE_METHOD(ChildWidgetOrganizer, WidgetUpdate) + ChildWidgetOrganizer::ChildWidgetOrganizer(GuiWidget &container) : d(new Instance(this, &container)) {} diff --git a/doomsday/libappfw/src/data.cpp b/doomsday/libappfw/src/data.cpp index 174125bfae..1984939347 100644 --- a/doomsday/libappfw/src/data.cpp +++ b/doomsday/libappfw/src/data.cpp @@ -38,6 +38,20 @@ static bool itemGreaterThan(Item const &a, Item const &b) return a.sortKey().compareWithoutCase(b.sortKey()) > 0; } +DENG2_PIMPL_NOREF(Data) +{ + DENG2_PIMPL_AUDIENCE(Addition) + DENG2_PIMPL_AUDIENCE(Removal) + DENG2_PIMPL_AUDIENCE(OrderChange) +}; + +DENG2_AUDIENCE_METHOD(Data, Addition) +DENG2_AUDIENCE_METHOD(Data, Removal) +DENG2_AUDIENCE_METHOD(Data, OrderChange) + +Data::Data() : d(new Instance) +{} + void Data::sort(SortMethod method) { switch(method) diff --git a/doomsday/libappfw/src/guiwidget.cpp b/doomsday/libappfw/src/guiwidget.cpp index 005961826e..3bac617fd8 100644 --- a/doomsday/libappfw/src/guiwidget.cpp +++ b/doomsday/libappfw/src/guiwidget.cpp @@ -87,7 +87,7 @@ DENG2_PIMPL(GuiWidget) , uBlurWindow ("uWindow", GLUniform::Vec4) { self.audienceForChildAddition() += this; - margins.audienceForChange += this; + margins.audienceForChange() += this; #ifdef DENG2_DEBUG self.audienceForParentChange() += this; diff --git a/doomsday/libappfw/src/item.cpp b/doomsday/libappfw/src/item.cpp index 350bd50f40..ead2563408 100644 --- a/doomsday/libappfw/src/item.cpp +++ b/doomsday/libappfw/src/item.cpp @@ -21,12 +21,30 @@ namespace de { namespace ui { +DENG2_PIMPL_NOREF(Item) +{ + Data *context; + Semantics semantics; + String label; + QVariant data; + + Instance(Semantics sem, String const &text = "", QVariant var = QVariant()) + : context(0) + , semantics(sem) + , label(text) + , data(var) {} + + DENG2_PIMPL_AUDIENCE(Change) +}; + +DENG2_AUDIENCE_METHOD(Item, Change) + Item::Item(Semantics semantics) - : _semantics(semantics), _context(0) + : d(new Instance(semantics)) {} Item::Item(Semantics semantics, String const &label) - : _semantics(semantics), _context(0), _label(label) + : d(new Instance(semantics, label)) {} Item::~Item() @@ -34,28 +52,54 @@ Item::~Item() Item::Semantics Item::semantics() const { - return _semantics; + return d->semantics; } void Item::setLabel(String const &label) { - _label = label; + d->label = label; notifyChange(); } String Item::label() const { - return _label; + return d->label; +} + +void Item::setDataContext(Data &context) +{ + d->context = &context; +} + +bool Item::hasDataContext() const +{ + return d->context != 0; +} + +Data &Item::dataContext() const +{ + DENG2_ASSERT(hasDataContext()); + return *d->context; } String Item::sortKey() const { - return _label; + return d->label; +} + +void Item::setData(QVariant const &v) +{ + d->data = v; +} + +QVariant const &Item::data() const +{ + return d->data; } void Item::notifyChange() { - DENG2_FOR_AUDIENCE(Change, i) + DENG2_FOR_AUDIENCE2(Change, i) { i->itemChanged(*this); } diff --git a/doomsday/libappfw/src/listdata.cpp b/doomsday/libappfw/src/listdata.cpp index 9abd60a795..576fd9c1f2 100644 --- a/doomsday/libappfw/src/listdata.cpp +++ b/doomsday/libappfw/src/listdata.cpp @@ -81,7 +81,7 @@ Data &ListData::insert(Pos pos, Item *item) item->setDataContext(*this); // Notify. - DENG2_FOR_AUDIENCE(Addition, i) + DENG2_FOR_AUDIENCE2(Addition, i) { i->dataItemAdded(pos, *item); } @@ -101,7 +101,7 @@ Item *ListData::take(Data::Pos pos) Item *taken = _items.takeAt(pos); // Notify. - DENG2_FOR_AUDIENCE(Removal, i) + DENG2_FOR_AUDIENCE2(Removal, i) { i->dataItemRemoved(pos, *taken); } @@ -123,7 +123,7 @@ void ListData::sort(LessThanFunc lessThan) qSort(_items.begin(), _items.end(), ListItemSorter(lessThan)); // Notify. - DENG2_FOR_AUDIENCE(OrderChange, i) + DENG2_FOR_AUDIENCE2(OrderChange, i) { i->dataItemOrderChanged(); } @@ -134,7 +134,7 @@ void ListData::stableSort(LessThanFunc lessThan) qStableSort(_items.begin(), _items.end(), ListItemSorter(lessThan)); // Notify. - DENG2_FOR_AUDIENCE(OrderChange, i) + DENG2_FOR_AUDIENCE2(OrderChange, i) { i->dataItemOrderChanged(); } diff --git a/doomsday/libappfw/src/margins.cpp b/doomsday/libappfw/src/margins.cpp index fdbea37d05..6e482f2829 100644 --- a/doomsday/libappfw/src/margins.cpp +++ b/doomsday/libappfw/src/margins.cpp @@ -81,7 +81,7 @@ DENG2_PIMPL(Margins) changeRef(inputs[side], rule); updateOutput(side); - DENG2_FOR_PUBLIC_AUDIENCE(Change, i) + DENG2_FOR_AUDIENCE(Change, i) { i->marginsChanged(); } @@ -120,8 +120,12 @@ DENG2_PIMPL(Margins) } return *outputs[side]; } + + DENG2_PIMPL_AUDIENCE(Change) }; +DENG2_AUDIENCE_METHOD(Margins, Change) + Margins::Margins(String const &defaultMargin) : d(new Instance(this, defaultMargin)) {} diff --git a/doomsday/libappfw/src/widgets/buttonwidget.cpp b/doomsday/libappfw/src/widgets/buttonwidget.cpp index 05b24b04d0..13c319ca67 100644 --- a/doomsday/libappfw/src/widgets/buttonwidget.cpp +++ b/doomsday/libappfw/src/widgets/buttonwidget.cpp @@ -113,7 +113,7 @@ DENG2_OBSERVES(Action, Triggered) break; } - DENG2_FOR_PUBLIC_AUDIENCE(StateChange, i) + DENG2_FOR_PUBLIC_AUDIENCE2(StateChange, i) { i->buttonStateChanged(self, state); } @@ -170,13 +170,21 @@ DENG2_OBSERVES(Action, Triggered) void actionTriggered(Action &) { - DENG2_FOR_PUBLIC_AUDIENCE(Triggered, i) + DENG2_FOR_PUBLIC_AUDIENCE2(Triggered, i) { i->buttonActionTriggered(self); } } + + DENG2_PIMPL_AUDIENCE(StateChange) + DENG2_PIMPL_AUDIENCE(Press) + DENG2_PIMPL_AUDIENCE(Triggered) }; +DENG2_AUDIENCE_METHOD(ButtonWidget, StateChange) +DENG2_AUDIENCE_METHOD(ButtonWidget, Press) +DENG2_AUDIENCE_METHOD(ButtonWidget, Triggered) + ButtonWidget::ButtonWidget(String const &name) : LabelWidget(name), d(new Instance(this)) {} @@ -218,7 +226,7 @@ void ButtonWidget::trigger() AutoRef held = holdRef(d->action); // Notify. - DENG2_FOR_AUDIENCE(Press, i) i->buttonPressed(*this); + DENG2_FOR_AUDIENCE2(Press, i) i->buttonPressed(*this); if(held) { diff --git a/doomsday/libappfw/src/widgets/choicewidget.cpp b/doomsday/libappfw/src/widgets/choicewidget.cpp index 5b805d78e9..124a458604 100644 --- a/doomsday/libappfw/src/widgets/choicewidget.cpp +++ b/doomsday/libappfw/src/widgets/choicewidget.cpp @@ -66,11 +66,11 @@ DENG2_OBSERVES(ChildWidgetOrganizer, WidgetUpdate) self.setFont("choice.selected"); choices = new PopupMenuWidget; - choices->items().audienceForAddition += this; - choices->items().audienceForRemoval += this; - choices->items().audienceForOrderChange += this; - choices->menu().organizer().audienceForWidgetCreation += this; - choices->menu().organizer().audienceForWidgetUpdate += this; + choices->items().audienceForAddition() += this; + choices->items().audienceForRemoval() += this; + choices->items().audienceForOrderChange() += this; + choices->menu().organizer().audienceForWidgetCreation() += this; + choices->menu().organizer().audienceForWidgetUpdate() += this; self.add(choices); self.setAction(new SignalAction(thisPublic, SLOT(openPopup()))); @@ -81,7 +81,7 @@ DENG2_OBSERVES(ChildWidgetOrganizer, WidgetUpdate) ~Instance() { - choices->items().audienceForRemoval -= this; + choices->items().audienceForRemoval() -= this; releaseRef(maxWidth); } diff --git a/doomsday/libappfw/src/widgets/dialogwidget.cpp b/doomsday/libappfw/src/widgets/dialogwidget.cpp index 9eb5b32de1..e0e534021e 100644 --- a/doomsday/libappfw/src/widgets/dialogwidget.cpp +++ b/doomsday/libappfw/src/widgets/dialogwidget.cpp @@ -114,19 +114,19 @@ public ChildWidgetOrganizer::IFilter buttons = new MenuWidget("buttons"); buttons->margins().setTop(""); buttons->setItems(buttonItems); - buttons->items().audienceForAddition += this; - buttons->items().audienceForRemoval += this; - buttons->organizer().audienceForWidgetCreation += this; - buttons->organizer().audienceForWidgetUpdate += this; + buttons->items().audienceForAddition() += this; + buttons->items().audienceForRemoval() += this; + buttons->organizer().audienceForWidgetCreation() += this; + buttons->organizer().audienceForWidgetUpdate() += this; buttons->organizer().setFilter(*this); extraButtons = new MenuWidget("extra"); extraButtons->margins().setTop(""); extraButtons->setItems(buttonItems); - extraButtons->items().audienceForAddition += this; - extraButtons->items().audienceForRemoval += this; - extraButtons->organizer().audienceForWidgetCreation += this; - extraButtons->organizer().audienceForWidgetUpdate += this; + extraButtons->items().audienceForAddition() += this; + extraButtons->items().audienceForRemoval() += this; + extraButtons->organizer().audienceForWidgetCreation() += this; + extraButtons->organizer().audienceForWidgetUpdate() += this; extraButtons->organizer().setFilter(*this); // The menu maintains its own width and height based on children. diff --git a/doomsday/libappfw/src/widgets/menuwidget.cpp b/doomsday/libappfw/src/widgets/menuwidget.cpp index 7860799da7..8721e16fa6 100644 --- a/doomsday/libappfw/src/widgets/menuwidget.cpp +++ b/doomsday/libappfw/src/widgets/menuwidget.cpp @@ -181,18 +181,18 @@ DENG2_PIMPL(MenuWidget) if(items) { // Get rid of the old context. - items->audienceForAddition -= this; - items->audienceForRemoval -= this; - items->audienceForOrderChange -= this; + items->audienceForAddition() -= this; + items->audienceForRemoval() -= this; + items->audienceForOrderChange() -= this; organizer.unsetContext(); } items = ctx; // Take new context into use. - items->audienceForAddition += this; - items->audienceForRemoval += this; - items->audienceForOrderChange += this; + items->audienceForAddition() += this; + items->audienceForRemoval() += this; + items->audienceForOrderChange() += this; organizer.setContext(*items); // recreates widgets } @@ -324,7 +324,7 @@ DENG2_PIMPL(MenuWidget) openSubs.insert(w); - w->audienceForClose += this; + w->audienceForClose() += this; w->audienceForDeletion() += this; } diff --git a/doomsday/libappfw/src/widgets/panelwidget.cpp b/doomsday/libappfw/src/widgets/panelwidget.cpp index ada96f8c15..2a7317806d 100644 --- a/doomsday/libappfw/src/widgets/panelwidget.cpp +++ b/doomsday/libappfw/src/widgets/panelwidget.cpp @@ -146,7 +146,7 @@ DENG_GUI_PIMPL(PanelWidget) self.panelClosing(); - DENG2_FOR_PUBLIC_AUDIENCE(Close, i) + DENG2_FOR_PUBLIC_AUDIENCE2(Close, i) { i->panelBeingClosed(self); } @@ -156,8 +156,12 @@ DENG_GUI_PIMPL(PanelWidget) dismissTimer.start(); dismissTimer.setInterval((CLOSING_ANIM_SPAN + delay).asMilliSeconds()); } + + DENG2_PIMPL_AUDIENCE(Close) }; +DENG2_AUDIENCE_METHOD(PanelWidget, Close) + PanelWidget::PanelWidget(String const &name) : GuiWidget(name), d(new Instance(this)) { setBehavior(ChildHitClipping); diff --git a/doomsday/libappfw/src/widgets/popupmenuwidget.cpp b/doomsday/libappfw/src/widgets/popupmenuwidget.cpp index 7e69133df5..3f0d99cf84 100644 --- a/doomsday/libappfw/src/widgets/popupmenuwidget.cpp +++ b/doomsday/libappfw/src/widgets/popupmenuwidget.cpp @@ -67,12 +67,12 @@ DENG_GUI_PIMPL(PopupMenuWidget) b->setOverrideImageSize(style().fonts().font("default").height().valuei()); } - b->audienceForStateChange += this; + b->audienceForStateChange() += this; // Triggered actions close the menu. if(item.semantics().testFlag(ui::Item::ActivationClosesPopup)) { - b->audienceForTriggered += this; + b->audienceForTriggered() += this; } } } @@ -191,8 +191,8 @@ PopupMenuWidget::PopupMenuWidget(String const &name) menu().setGridSize(1, ui::Expand, 0, ui::Expand); - menu().organizer().audienceForWidgetCreation += d; - menu().organizer().audienceForWidgetUpdate += d; + menu().organizer().audienceForWidgetCreation() += d; + menu().organizer().audienceForWidgetUpdate() += d; } MenuWidget &PopupMenuWidget::menu() const diff --git a/doomsday/libappfw/src/widgets/tabwidget.cpp b/doomsday/libappfw/src/widgets/tabwidget.cpp index 809d6c77ad..a793e920f2 100644 --- a/doomsday/libappfw/src/widgets/tabwidget.cpp +++ b/doomsday/libappfw/src/widgets/tabwidget.cpp @@ -44,9 +44,9 @@ DENG2_PIMPL(TabWidget) buttons->margins().set(""); buttons->setGridSize(0, ui::Expand, 1, ui::Expand, GridLayout::ColumnFirst); - buttons->organizer().audienceForWidgetCreation += this; - buttons->items().audienceForAddition += this; - buttons->items().audienceForOrderChange += this; + buttons->organizer().audienceForWidgetCreation() += this; + buttons->items().audienceForAddition() += this; + buttons->items().audienceForOrderChange() += this; // Center the buttons inside the widget. buttons->rule() @@ -63,7 +63,7 @@ DENG2_PIMPL(TabWidget) btn.setFont("tab.label"); btn.margins().set("dialog.gap"); - btn.audienceForPress += this; + btn.audienceForPress() += this; } void buttonPressed(ButtonWidget &button) diff --git a/doomsday/libappfw/src/widgets/togglewidget.cpp b/doomsday/libappfw/src/widgets/togglewidget.cpp index 287e7e1fb9..1b494ccdde 100644 --- a/doomsday/libappfw/src/widgets/togglewidget.cpp +++ b/doomsday/libappfw/src/widgets/togglewidget.cpp @@ -112,12 +112,12 @@ DENG2_OBSERVES(ButtonWidget, Press) { self.setImage(procImage); // base class owns it - self.audienceForPress += this; + self.audienceForPress() += this; } ~Instance() { - self.audienceForPress -= this; + self.audienceForPress() -= this; } void buttonPressed(ButtonWidget &) @@ -127,8 +127,12 @@ DENG2_OBSERVES(ButtonWidget, Press) emit self.stateChangedByUser(self.toggleState()); } + + DENG2_PIMPL_AUDIENCE(Toggle) }; +DENG2_AUDIENCE_METHOD(ToggleWidget, Toggle) + ToggleWidget::ToggleWidget(String const &name) : ButtonWidget(name), d(new Instance(this)) { setTextAlignment(ui::AlignRight); @@ -144,7 +148,7 @@ void ToggleWidget::setToggleState(ToggleState state, bool notify) if(notify) { - DENG2_FOR_AUDIENCE(Toggle, i) i->toggleStateChanged(*this); + DENG2_FOR_AUDIENCE2(Toggle, i) i->toggleStateChanged(*this); } emit stateChanged(state); } diff --git a/doomsday/libappfw/src/widgets/variabletogglewidget.cpp b/doomsday/libappfw/src/widgets/variabletogglewidget.cpp index e4b98ed7f9..3a387598c8 100644 --- a/doomsday/libappfw/src/widgets/variabletogglewidget.cpp +++ b/doomsday/libappfw/src/widgets/variabletogglewidget.cpp @@ -39,7 +39,7 @@ DENG2_OBSERVES(ToggleWidget, Toggle ) { updateFromVariable(); - self.audienceForToggle += this; + self.audienceForToggle() += this; var->audienceForDeletion() += this; var->audienceForChange() += this; } @@ -50,7 +50,7 @@ DENG2_OBSERVES(ToggleWidget, Toggle ) { var->audienceForDeletion() -= this; var->audienceForChange() -= this; - self.audienceForToggle -= this; + self.audienceForToggle() -= this; } } From 2a7448292e517f0fc7faed8b9488dd5462850727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 12:13:48 +0200 Subject: [PATCH 55/60] UI|Client: Handling a failed direct query for servers --- doomsday/client/include/ui/dialogs/manualconnectiondialog.h | 1 + doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/doomsday/client/include/ui/dialogs/manualconnectiondialog.h b/doomsday/client/include/ui/dialogs/manualconnectiondialog.h index d39e49d657..8d809c68a0 100644 --- a/doomsday/client/include/ui/dialogs/manualconnectiondialog.h +++ b/doomsday/client/include/ui/dialogs/manualconnectiondialog.h @@ -43,6 +43,7 @@ public slots: void queryOrConnect(); void contentChanged(); void validate(); + void disconnected(); protected: void finish(int result); diff --git a/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp b/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp index f6a97be393..3873c85aea 100644 --- a/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp +++ b/doomsday/client/src/ui/dialogs/manualconnectiondialog.cpp @@ -132,6 +132,7 @@ ManualConnectionDialog::ManualConnectionDialog(String const &name) connect(&editor(), SIGNAL(enterPressed(QString)), this, SLOT(queryOrConnect())); connect(&editor(), SIGNAL(editorContentChanged()), this, SLOT(validate())); connect(&editor(), SIGNAL(editorContentChanged()), this, SLOT(contentChanged())); + connect(&ClientApp::serverLink(), SIGNAL(disconnected()), this, SLOT(disconnected())); updateLayout(); } @@ -201,6 +202,11 @@ void ManualConnectionDialog::validate() d->connectButton().enable(valid); } +void ManualConnectionDialog::disconnected() +{ + d->linkDiscoveryUpdate(ClientApp::serverLink()); +} + void ManualConnectionDialog::finish(int result) { if(result) From 0fe76ef013c3dbb0ab301cfd4c8b3c350996eb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 20:45:49 +0200 Subject: [PATCH 56/60] Fixed|libgui: Unsigned math issue in window centering Trying to center a window larger than the desktop would produce invalid coordinates. --- doomsday/libgui/src/persistentcanvaswindow.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doomsday/libgui/src/persistentcanvaswindow.cpp b/doomsday/libgui/src/persistentcanvaswindow.cpp index e820005a2e..086f928529 100644 --- a/doomsday/libgui/src/persistentcanvaswindow.cpp +++ b/doomsday/libgui/src/persistentcanvaswindow.cpp @@ -50,15 +50,17 @@ static QRect desktopRect() static QRect centeredQRect(Vector2ui const &size) { - QSize screenSize = desktopRect().size(); + Vector2ui const screenSize(desktopRect().size().width(), + desktopRect().size().height()); + Vector2ui const clamped = size.min(screenSize); LOGDEV_GL_XVERBOSE("centeredGeometry: Current desktop rect %i x %i") - << screenSize.width() << screenSize.height(); + << screenSize.x << screenSize.y; return QRect(desktopRect().topLeft() + - QPoint((screenSize.width() - size.x) / 2, - (screenSize.height() - size.y) / 2), - QSize(size.x, size.y)); + QPoint((screenSize.x - clamped.x) / 2, + (screenSize.y - clamped.y) / 2), + QSize(clamped.x, clamped.y)); } static Rectanglei centeredRect(Vector2ui const &size) From 41f8a96ecd5fd2f0101bfa1119c50c1ea54803b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 20:47:21 +0200 Subject: [PATCH 57/60] SDK|Unix: Deploy SDK libs to built app using symlinks Todo: This should be an optional feature, though. --- doomsday/doomsday_sdk.pri | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index e13e6f59d2..588f4e29f0 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -46,6 +46,15 @@ DENG_MODULES = $$DENG_SDK_DIR/modules/*.de # Macros --------------------------------------------------------------------- +defineTest(dengPostLink) { + isEmpty(QMAKE_POST_LINK) { + QMAKE_POST_LINK = $$1 + } else { + QMAKE_POST_LINK = $$QMAKE_POST_LINK && $$1 + } + export(QMAKE_POST_LINK) +} + defineTest(dengClear) { # 1: file to remove win32: system(del /q \"$$1\") @@ -115,7 +124,8 @@ defineTest(dengDeploy) { win32 { } else:macx { - QMAKE_BUNDLE_DATA += basepack denglibs + QMAKE_BUNDLE_DATA += $$INSTALLS + QMAKE_BUNDLE_DATA -= target basepack.path = Contents/Resources denglibs.path = Contents/Frameworks } @@ -124,6 +134,22 @@ defineTest(dengDeploy) { basepack.path = $$prefix/share/$${1} denglibs.path = $$dengFindLibDir($$prefix) } + + unix { + # Symlink the libraries rather than copy. + macx { + QMAKE_BUNDLE_DATA -= denglibs + fwDir = $${TARGET}.app/$$denglibs.path + } + else { + INSTALLS -= denglibs + fwDir = $$denglibs.path + } + for(fn, denglibs.files) { + dengPostLink(mkdir -p \"$$fwDir\" && ln -sf \"$$fn\" \"$$fwDir\") + } + } + macx: export(QMAKE_BUNDLE_DATA) else { export(INSTALLS) From cdce85301b8cdc386fa55c991b91323361f73a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 20:49:04 +0200 Subject: [PATCH 58/60] Refactor|ClientApp: Moved font related script bindings to BaseGuiApp --- doomsday/client/src/clientapp.cpp | 64 +------------------------ doomsday/libappfw/src/baseguiapp.cpp | 71 +++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 63 deletions(-) diff --git a/doomsday/client/src/clientapp.cpp b/doomsday/client/src/clientapp.cpp index 76b08c09e0..b11e114cb0 100644 --- a/doomsday/client/src/clientapp.cpp +++ b/doomsday/client/src/clientapp.cpp @@ -91,61 +91,6 @@ static Value *Function_App_GamePlugin(Context &, Function::ArgumentValues const return new TextValue(name); } -static Value *Function_App_LoadFont(Context &, Function::ArgumentValues const &args) -{ - LOG_AS("ClientApp"); - try - { - // Try to load the specific font. - Block data(App::fileSystem().root().locate(args.at(0)->asText())); - int id; - id = QFontDatabase::addApplicationFontFromData(data); - if(id < 0) - { - LOG_RES_WARNING("Failed to load font:"); - } - else - { - LOG_RES_VERBOSE("Loaded font: %s") << args.at(0)->asText(); - //qDebug() << args.at(0)->asText(); - //qDebug() << "Families:" << QFontDatabase::applicationFontFamilies(id); - } - } - catch(Error const &er) - { - LOG_RES_WARNING("Failed to load font:\n") << er.asText(); - } - return 0; -} - -static Value *Function_App_AddFontMapping(Context &, Function::ArgumentValues const &args) -{ - // arg 0: family name - // arg 1: dictionary with [Text style, Number weight] => Text fontname - - // styles: regular, italic - // weight: 0-99 (25=light, 50=normal, 75=bold) - - NativeFont::StyleMapping mapping; - - DictionaryValue const &dict = args.at(1)->as(); - DENG2_FOR_EACH_CONST(DictionaryValue::Elements, i, dict.elements()) - { - NativeFont::Spec spec; - ArrayValue const &key = i->first.value->as(); - if(key.at(0).asText() == "italic") - { - spec.style = NativeFont::Italic; - } - spec.weight = roundi(key.at(1).asNumber()); - mapping.insert(spec, i->second->asText()); - } - - NativeFont::defineMapping(args.at(0)->asText(), mapping); - - return 0; -} - static Value *Function_App_Quit(Context &, Function::ArgumentValues const &) { Sys_Quit(); @@ -319,9 +264,6 @@ ClientApp::ClientApp(int &argc, char **argv) { novideo = false; - // Override the system locale (affects number/time formatting). - QLocale::setDefault(QLocale("en_US.UTF-8")); - // Use the host system's proxy configuration. QNetworkProxyFactory::setUseSystemConfiguration(true); @@ -335,10 +277,8 @@ ClientApp::ClientApp(int &argc, char **argv) setGame(d->games.nullGame()); d->binder.init(scriptSystem().nativeModule("App")) - << DENG2_FUNC_NOARG (App_GamePlugin, "gamePlugin") - << DENG2_FUNC (App_AddFontMapping, "addFontMapping", "family" << "mappings") - << DENG2_FUNC (App_LoadFont, "loadFont", "fileName") - << DENG2_FUNC_NOARG (App_Quit, "quit"); + << DENG2_FUNC_NOARG (App_GamePlugin, "gamePlugin") + << DENG2_FUNC_NOARG (App_Quit, "quit"); } void ClientApp::initialize() diff --git a/doomsday/libappfw/src/baseguiapp.cpp b/doomsday/libappfw/src/baseguiapp.cpp index 74438a48be..8cc6a99121 100644 --- a/doomsday/libappfw/src/baseguiapp.cpp +++ b/doomsday/libappfw/src/baseguiapp.cpp @@ -19,10 +19,72 @@ #include "de/BaseGuiApp" #include "de/VRConfig" +#include +#include +#include +#include +#include + namespace de { +static Value *Function_App_LoadFont(Context &, Function::ArgumentValues const &args) +{ + LOG_AS("ClientApp"); + try + { + // Try to load the specific font. + Block data(App::fileSystem().root().locate(args.at(0)->asText())); + int id; + id = QFontDatabase::addApplicationFontFromData(data); + if(id < 0) + { + LOG_RES_WARNING("Failed to load font:"); + } + else + { + LOG_RES_VERBOSE("Loaded font: %s") << args.at(0)->asText(); + //qDebug() << args.at(0)->asText(); + //qDebug() << "Families:" << QFontDatabase::applicationFontFamilies(id); + } + } + catch(Error const &er) + { + LOG_RES_WARNING("Failed to load font:\n") << er.asText(); + } + return 0; +} + +static Value *Function_App_AddFontMapping(Context &, Function::ArgumentValues const &args) +{ + // arg 0: family name + // arg 1: dictionary with [Text style, Number weight] => Text fontname + + // styles: regular, italic + // weight: 0-99 (25=light, 50=normal, 75=bold) + + NativeFont::StyleMapping mapping; + + DictionaryValue const &dict = args.at(1)->as(); + DENG2_FOR_EACH_CONST(DictionaryValue::Elements, i, dict.elements()) + { + NativeFont::Spec spec; + ArrayValue const &key = i->first.value->as(); + if(key.at(0).asText() == "italic") + { + spec.style = NativeFont::Italic; + } + spec.weight = roundi(key.at(1).asNumber()); + mapping.insert(spec, i->second->asText()); + } + + NativeFont::defineMapping(args.at(0)->asText(), mapping); + + return 0; +} + DENG2_PIMPL_NOREF(BaseGuiApp) { + Binder binder; QScopedPointer uiState; GLShaderBank shaders; VRConfig vr; @@ -30,7 +92,14 @@ DENG2_PIMPL_NOREF(BaseGuiApp) BaseGuiApp::BaseGuiApp(int &argc, char **argv) : GuiApp(argc, argv), d(new Instance) -{} +{ + // Override the system locale (affects number/time formatting). + QLocale::setDefault(QLocale("en_US.UTF-8")); + + d->binder.init(scriptSystem().nativeModule("App")) + << DENG2_FUNC (App_AddFontMapping, "addFontMapping", "family" << "mappings") + << DENG2_FUNC (App_LoadFont, "loadFont", "fileName"); +} void BaseGuiApp::initSubsystems(SubsystemInitFlags flags) { From 67296a70204c2e91137a0f63e6ed2832a2f271cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 3 Mar 2014 20:55:22 +0200 Subject: [PATCH 59/60] Cleanup --- doomsday/libappfw/src/baseguiapp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/doomsday/libappfw/src/baseguiapp.cpp b/doomsday/libappfw/src/baseguiapp.cpp index 8cc6a99121..a7353f5ac7 100644 --- a/doomsday/libappfw/src/baseguiapp.cpp +++ b/doomsday/libappfw/src/baseguiapp.cpp @@ -29,7 +29,6 @@ namespace de { static Value *Function_App_LoadFont(Context &, Function::ArgumentValues const &args) { - LOG_AS("ClientApp"); try { // Try to load the specific font. From 192aa621036bf03b3bfde4f8f85c744734433b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 4 Mar 2014 10:50:15 +0200 Subject: [PATCH 60/60] SDK|Unix: Prefer libs in SDK to system libs --- doomsday/doomsday_sdk.pri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doomsday/doomsday_sdk.pri b/doomsday/doomsday_sdk.pri index 588f4e29f0..a65575ca78 100644 --- a/doomsday/doomsday_sdk.pri +++ b/doomsday/doomsday_sdk.pri @@ -21,7 +21,8 @@ else { INCLUDEPATH += $$DENG_SDK_DIR/include } -LIBS += -L$$DENG_SDK_DIR/lib +win32: LIBS += -L$$DENG_SDK_DIR/lib + else: QMAKE_LFLAGS = -L$$DENG_SDK_DIR/lib $$QMAKE_LFLAGS # The core library is always required. LIBS += -ldeng2