|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- /*
- * Common Carla code
- * Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or 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 General Public License for more details.
- *
- * For a full copy of the GNU General Public License see the doc/GPL.txt file.
- */
-
- #include "carla_shared.hpp"
-
- //---------------------------------------------------------------------------------------------------------------------
- // Imports (Global)
-
- #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wconversion"
- # pragma GCC diagnostic ignored "-Weffc++"
- # pragma GCC diagnostic ignored "-Wsign-conversion"
- #endif
-
- #include <QtGui/QFontMetrics>
-
- #include <QtWidgets/QFileDialog>
- #include <QtWidgets/QGridLayout>
- #include <QtWidgets/QLineEdit>
-
- #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
- # pragma GCC diagnostic pop
- #endif
-
- //---------------------------------------------------------------------------------------------------------------------
-
- #ifdef CARLA_OS_UNIX
- # include <signal.h>
- #endif
-
- //---------------------------------------------------------------------------------------------------------------------
- // Imports (Custom)
-
- #include "carla_host.hpp"
-
- #include "CarlaUtils.h"
- #include "CarlaMathUtils.hpp"
-
- //---------------------------------------------------------------------------------------------------------------------
- // Global Carla object
-
- CarlaObject::CarlaObject() noexcept
- : host(nullptr),
- gui(nullptr),
- nogui(false),
- term(false) {}
-
- CarlaObject gCarla;
-
- //---------------------------------------------------------------------------------------------------------------------
- // Get Icon from user theme, using our own as backup (Oxygen)
-
- QIcon getIcon(const QString icon, const int size)
- {
- return QIcon::fromTheme(icon, QIcon(QString(":/%1x%1/%2.png").arg(size).arg(icon)));
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Handle some basic command-line arguments shared between all carla variants
-
- QString handleInitialCommandLineArguments(const int argc, char* argv[])
- {
- static const QStringList listArgsNoGUI = { "-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui" };
- static const QStringList listArgsHelp = { "-h", "--h", "-help", "--help" };
- static const QStringList listArgsVersion = { "-v", "--v", "-version", "--version" };
-
- QString initName(argv[0]); // = os.path.basename(file) if (file is not None and os.path.dirname(file) in PATH) else sys.argv[0]
- // libPrefix = None
-
- for (int i=1; i<argc; ++i)
- {
- const QString arg(argv[i]);
-
- if (arg.startsWith("--with-appname="))
- {
- // initName = os.path.basename(arg.replace("--with-appname=", ""));
- }
- else if (arg.startsWith("--with-libprefix=") || arg == "--gdb")
- {
- pass();
- }
- else if (listArgsNoGUI.contains(arg))
- {
- gCarla.nogui = true;
- }
- else if (listArgsHelp.contains(arg))
- {
- carla_stdout("Usage: %s [OPTION]... [FILE|URL]", initName);
- carla_stdout("");
- carla_stdout(" where FILE can be a Carla project or preset file to be loaded, or URL if using Carla-Control");
- carla_stdout("");
- carla_stdout(" and OPTION can be one or more of the following:");
- carla_stdout("");
- carla_stdout(" --gdb \t Run Carla inside gdb.");
- carla_stdout(" -n,--no-gui \t Run Carla headless, don't show UI.");
- carla_stdout("");
- carla_stdout(" -h,--help \t Print this help text and exit.");
- carla_stdout(" -v,--version\t Print version information and exit.");
- carla_stdout("");
-
- std::exit(0);
- }
- else if (listArgsVersion.contains(arg))
- {
- /*
- QString pathBinaries, pathResources = getPaths();
- */
-
- carla_stdout("Using Carla version %s", CARLA_VERSION_STRING);
- /*
- carla_stdout(" Qt version: %s", QT_VERSION_STR);
- carla_stdout(" Binary dir: %s", pathBinaries.toUtf8());
- carla_stdout(" Resources dir: %s", pathResources.toUtf8());
- */
-
- std::exit(0);
- }
- }
-
- return initName;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Get initial project file (as passed in the command-line parameters)
-
- QString getInitialProjectFile(bool)
- {
- // TODO
- return "";
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Get paths (binaries, resources)
-
- bool getPaths(QString& pathBinaries, QString& pathResources)
- {
- const QString libFolder(carla_get_library_folder());
-
- QDir dir(libFolder);
-
- // FIXME need to completely rework this in C++ mode, so check if all cases are valid
-
- if (libFolder.endsWith("bin"))
- {
- CARLA_SAFE_ASSERT_RETURN(dir.cd("resources"), false);
- pathBinaries = libFolder;
- pathResources = dir.absolutePath();
- return true;
- }
- else if (libFolder.endsWith("carla"))
- {
- for (int i=2; --i>=0;)
- {
- CARLA_SAFE_ASSERT_INT_RETURN(dir.cdUp(), i, false);
- CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("share"), i, false);
-
- if (dir.exists())
- {
- CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("carla"), i, false);
- CARLA_SAFE_ASSERT_INT_RETURN(dir.cd("resources"), i, false);
- pathBinaries = libFolder;
- pathResources = dir.absolutePath();
- return true;
- }
- }
- }
-
- return false;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Signal handler
-
- static void signalHandler(const int sig)
- {
- switch (sig)
- {
- case SIGINT:
- case SIGTERM:
- gCarla.term = true;
- if (gCarla.host != nullptr)
- emit gCarla.host->SignalTerminate();
- break;
- case SIGUSR1:
- if (gCarla.host != nullptr)
- emit gCarla.host->SignalSave();
- break;
- }
- }
-
- #ifdef CARLA_OS_WIN
- static BOOL WINAPI winSignalHandler(DWORD dwCtrlType) noexcept
- {
- if (dwCtrlType == CTRL_C_EVENT)
- {
- signalHandler(SIGINT);
- return TRUE;
- }
- return FALSE;
- }
- #endif
-
- void setUpSignals()
- {
- #if defined(CARLA_OS_UNIX)
- struct sigaction sig;
- carla_zeroStruct(sig);
- sig.sa_handler = signalHandler;
- sig.sa_flags = SA_RESTART;
- sigemptyset(&sig.sa_mask);
- sigaction(SIGTERM, &sig, nullptr);
- sigaction(SIGINT, &sig, nullptr);
- sigaction(SIGUSR1, &sig, nullptr);
- #elif defined(CARLA_OS_WIN)
- SetConsoleCtrlHandler(winSignalHandler, TRUE);
- #endif
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // QLineEdit and QPushButton combo
-
- QString getAndSetPath(QWidget* const parent, QLineEdit* const lineEdit)
- {
- const QCarlaString newPath = QFileDialog::getExistingDirectory(parent, parent->tr("Set Path"), lineEdit->text(), QFileDialog::ShowDirsOnly);
- if (newPath.isNotEmpty())
- lineEdit->setText(newPath);
- return newPath;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // fill up a qlists from a C arrays
-
- void fillQStringListFromStringArray(QStringList& list, const char* const* const stringArray)
- {
- int count = 0;
-
- // count number of strings first
- for (; stringArray[count] != nullptr; ++count) {}
-
- // allocate list
- list.reserve(count);
-
- // fill in strings
- for (count = 0; stringArray[count] != nullptr; ++count)
- list.append(stringArray[count]);
- }
-
- void fillQDoubleListFromDoubleArray(QList<double>& list, const double* const doubleArray)
- {
- int count = 0;
-
- // count number of strings first
- for (; carla_isNotZero(doubleArray[count]); ++count) {}
-
- // allocate list
- list.reserve(count);
-
- // fill in strings
- for (count = 0; carla_isNotZero(doubleArray[count]); ++count)
- list.append(doubleArray[count]);
- }
-
- void fillQUIntListFromUIntArray(QList<uint>& list, const uint* const uintArray)
- {
- int count = 0;
-
- // count number of strings first
- for (; uintArray[count] != 0; ++count) {}
-
- // allocate list
- list.reserve(count);
-
- // fill in strings
- for (count = 0; uintArray[count] != 0; ++count)
- list.append(uintArray[count]);
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Backwards-compatible horizontalAdvance/width call, depending on Qt version
-
- int fontMetricsHorizontalAdvance(const QFontMetrics& fm, const QString& s)
- {
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
- return fm.horizontalAdvance(s);
- #else
- return fm.width(s);
- #endif
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Check if a string array contains a string
-
- bool stringArrayContainsString(const char* const* const stringArray, const char* const string) noexcept
- {
- for (uint i=0; stringArray[i] != nullptr; ++i)
- {
- if (std::strcmp(stringArray[i], string) == 0)
- return true;
- }
-
- return false;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Get index of a QList<double> value
-
- int getIndexOfQDoubleListValue(const QList<double>& list, const double value)
- {
- if (list.size() > 0)
- {
- for (QList<double>::const_iterator n = list.cbegin(), e = list.cend(); n != e; ++n)
- if (carla_isEqual(*n, value))
- return int(n - list.cbegin());
- }
-
- return -1;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Check if two QList<double> instances match
-
- bool isQDoubleListEqual(const QList<double>& list1, const QList<double>& list2)
- {
- if (list1.size() != list2.size())
- return false;
- if (list1.isEmpty())
- return true;
-
- for (QList<double>::const_iterator l1n = list1.cbegin(), l2n = list2.cbegin(), l1e = list1.cend(); l1n != l1e; ++l1n, ++l2n)
- if (carla_isNotEqual(*l1n, *l2n))
- return false;
-
- return true;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Custom QMessageBox which resizes itself to fit text
-
- void QMessageBoxWithBetterWidth::showEvent(QShowEvent* const event)
- {
- const QFontMetrics metrics(fontMetrics());
- const QStringList lines(text().trimmed().split("\n") + informativeText().trimmed().split("\n"));
-
- if (lines.size() > 0)
- {
- int width = 0;
-
- for (const QString& line : lines)
- width = std::max(fontMetricsHorizontalAdvance(metrics, line), width);
-
- if (QGridLayout* const layout_ = dynamic_cast<QGridLayout*>(layout()))
- layout_->setColumnMinimumWidth(2, width + 12);
- }
-
- QMessageBox::showEvent(event);
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Safer QSettings class, which does not throw if type mismatches
-
- bool QSafeSettings::valueBool(const QString key, const bool defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Bool), defaultValue);
-
- return var.isValid() ? var.toBool() : defaultValue;
- }
-
- Qt::CheckState QSafeSettings::valueCheckState(const QString key, const Qt::CheckState defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue);
-
- if (! var.isValid())
- return defaultValue;
-
- const uint value = var.toUInt();
-
- switch (value)
- {
- case Qt::Unchecked:
- case Qt::PartiallyChecked:
- case Qt::Checked:
- return static_cast<Qt::CheckState>(value);
- default:
- return defaultValue;
- }
- }
-
- int QSafeSettings::valueIntPositive(const QString key, const int defaultValue) const
- {
- CARLA_SAFE_ASSERT_INT(defaultValue >= 0, defaultValue);
-
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Int), defaultValue);
- CARLA_SAFE_ASSERT_RETURN(var.isValid(), defaultValue);
-
- const int value = var.toInt();
- CARLA_SAFE_ASSERT_RETURN(value >= 0, defaultValue);
-
- return value;
- }
-
- uint QSafeSettings::valueUInt(const QString key, const uint defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue);
-
- return var.isValid() ? var.toUInt() : defaultValue;
- }
-
- double QSafeSettings::valueDouble(const QString key, const double defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Double), defaultValue);
-
- return var.isValid() ? var.toDouble() : defaultValue;
- }
-
- QString QSafeSettings::valueString(const QString key, const QString defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::String), defaultValue);
-
- return var.isValid() ? var.toString() : defaultValue;
- }
-
- QByteArray QSafeSettings::valueByteArray(const QString key, const QByteArray defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::ByteArray), defaultValue);
-
- return var.isValid() ? var.toByteArray() : defaultValue;
- }
-
- QStringList QSafeSettings::valueStringList(const QString key, const QStringList defaultValue) const
- {
- QVariant var(value(key, defaultValue));
-
- if (var.isNull())
- return defaultValue;
-
- CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::StringList), defaultValue);
-
- return var.isValid() ? var.toStringList() : defaultValue;
- }
-
- //---------------------------------------------------------------------------------------------------------------------
- // Custom MessageBox
-
- int CustomMessageBox(QWidget* const parent,
- const QMessageBox::Icon icon,
- const QString title,
- const QString text,
- const QString extraText,
- const QMessageBox::StandardButtons buttons,
- const QMessageBox::StandardButton defButton)
- {
- QMessageBoxWithBetterWidth msgBox(parent);
- msgBox.setIcon(icon);
- msgBox.setWindowTitle(title);
- msgBox.setText(text);
- msgBox.setInformativeText(extraText);
- msgBox.setStandardButtons(buttons);
- msgBox.setDefaultButton(defButton);
- return msgBox.exec();
- }
-
- //---------------------------------------------------------------------------------------------------------------------
|