Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
12KB

  1. /*
  2. * Common Carla code
  3. * Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "carla_shared.hpp"
  18. //---------------------------------------------------------------------------------------------------------------------
  19. // Imports (Global)
  20. #include <QtGui/QFontMetrics>
  21. #include <QtWidgets/QFileDialog>
  22. #include <QtWidgets/QGridLayout>
  23. #include <QtWidgets/QLineEdit>
  24. //---------------------------------------------------------------------------------------------------------------------
  25. // Imports (Custom)
  26. #include "CarlaMathUtils.hpp"
  27. //---------------------------------------------------------------------------------------------------------------------
  28. // Global Carla object
  29. CarlaObject::CarlaObject() noexcept
  30. : gui(nullptr),
  31. nogui(false),
  32. term(false) {}
  33. CarlaObject gCarla;
  34. //---------------------------------------------------------------------------------------------------------------------
  35. // Get Icon from user theme, using our own as backup (Oxygen)
  36. QIcon getIcon(const QString icon, const int size)
  37. {
  38. return QIcon::fromTheme(icon, QIcon(QString(":/%1x%1/%2.png").arg(size).arg(icon)));
  39. }
  40. //---------------------------------------------------------------------------------------------------------------------
  41. // Handle some basic command-line arguments shared between all carla variants
  42. QString handleInitialCommandLineArguments(const int argc, char* argv[])
  43. {
  44. static const QStringList listArgsNoGUI = { "-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui" };
  45. static const QStringList listArgsHelp = { "-h", "--h", "-help", "--help" };
  46. static const QStringList listArgsVersion = { "-v", "--v", "-version", "--version" };
  47. QString initName(argv[0]); // = os.path.basename(file) if (file is not None and os.path.dirname(file) in PATH) else sys.argv[0]
  48. // libPrefix = None
  49. for (int i=1; i<argc; ++i)
  50. {
  51. const QString arg(argv[i]);
  52. if (arg.startsWith("--with-appname="))
  53. {
  54. // initName = os.path.basename(arg.replace("--with-appname=", ""));
  55. }
  56. else if (arg.startsWith("--with-libprefix=") || arg == "--gdb")
  57. {
  58. pass();
  59. }
  60. else if (listArgsNoGUI.contains(arg))
  61. {
  62. gCarla.nogui = true;
  63. }
  64. else if (listArgsHelp.contains(arg))
  65. {
  66. carla_stdout("Usage: %s [OPTION]... [FILE|URL]", initName);
  67. carla_stdout("");
  68. carla_stdout(" where FILE can be a Carla project or preset file to be loaded, or URL if using Carla-Control");
  69. carla_stdout("");
  70. carla_stdout(" and OPTION can be one or more of the following:");
  71. carla_stdout("");
  72. carla_stdout(" --gdb \t Run Carla inside gdb.");
  73. carla_stdout(" -n,--no-gui \t Run Carla headless, don't show UI.");
  74. carla_stdout("");
  75. carla_stdout(" -h,--help \t Print this help text and exit.");
  76. carla_stdout(" -v,--version\t Print version information and exit.");
  77. carla_stdout("");
  78. std::exit(0);
  79. }
  80. else if (listArgsVersion.contains(arg))
  81. {
  82. /*
  83. QString pathBinaries, pathResources = getPaths();
  84. */
  85. carla_stdout("Using Carla version %s", CARLA_VERSION_STRING);
  86. /*
  87. carla_stdout(" Qt version: %s", QT_VERSION_STR);
  88. carla_stdout(" Binary dir: %s", pathBinaries.toUtf8());
  89. carla_stdout(" Resources dir: %s", pathResources.toUtf8());
  90. */
  91. std::exit(0);
  92. }
  93. }
  94. return initName;
  95. }
  96. //---------------------------------------------------------------------------------------------------------------------
  97. // Get initial project file (as passed in the command-line parameters)
  98. void getInitialProjectFile(void*, bool)
  99. {
  100. // TODO
  101. }
  102. //---------------------------------------------------------------------------------------------------------------------
  103. // Get paths (binaries, resources)
  104. void getPaths()
  105. {
  106. // TODO
  107. }
  108. //---------------------------------------------------------------------------------------------------------------------
  109. // Signal handler
  110. /*
  111. void signalHandler(const int sig)
  112. {
  113. if (sig == SIGINT || sig == SIGTERM)
  114. {
  115. gCarla.term = true;
  116. if (gCarla.gui != nullptr)
  117. gCarla.gui.SIGTERM.emit();
  118. }
  119. else if (sig == SIGUSR1)
  120. {
  121. if (gCarla.gui != nullptr)
  122. gCarla.gui.SIGUSR1.emit();
  123. }
  124. }
  125. */
  126. void setUpSignals()
  127. {
  128. /*
  129. signal(SIGINT, signalHandler);
  130. signal(SIGTERM, signalHandler);
  131. signal(SIGUSR1, signalHandler);
  132. */
  133. }
  134. //---------------------------------------------------------------------------------------------------------------------
  135. // QLineEdit and QPushButton combo
  136. QString getAndSetPath(QWidget* const parent, QLineEdit* const lineEdit)
  137. {
  138. const QCarlaString newPath = QFileDialog::getExistingDirectory(parent, parent->tr("Set Path"), lineEdit->text(), QFileDialog::ShowDirsOnly);
  139. if (newPath.isNotEmpty())
  140. lineEdit->setText(newPath);
  141. return newPath;
  142. }
  143. //---------------------------------------------------------------------------------------------------------------------
  144. // fill up a qlists from a C arrays
  145. void fillQStringListFromStringArray(QStringList& list, const char* const* const stringArray)
  146. {
  147. uint count = 0;
  148. // count number of strings first
  149. for (; stringArray[count] != nullptr; ++count) {}
  150. // allocate list
  151. list.reserve(count);
  152. // fill in strings
  153. for (count = 0; stringArray[count] != nullptr; ++count)
  154. list.append(stringArray[count]);
  155. }
  156. void fillQDoubleListFromDoubleArray(QList<double>& list, const double* const doubleArray)
  157. {
  158. uint count = 0;
  159. // count number of strings first
  160. for (; carla_isNotZero(doubleArray[count]); ++count) {}
  161. // allocate list
  162. list.reserve(count);
  163. // fill in strings
  164. for (count = 0; carla_isNotZero(doubleArray[count]); ++count)
  165. list.append(doubleArray[count]);
  166. }
  167. void fillQUIntListFromUIntArray(QList<uint>& list, const uint* const uintArray)
  168. {
  169. uint count = 0;
  170. // count number of strings first
  171. for (; uintArray[count] != 0; ++count) {}
  172. // allocate list
  173. list.reserve(count);
  174. // fill in strings
  175. for (count = 0; uintArray[count] != 0; ++count)
  176. list.append(uintArray[count]);
  177. }
  178. //---------------------------------------------------------------------------------------------------------------------
  179. // Backwards-compatible horizontalAdvance/width call, depending on qt version
  180. int fontMetricsHorizontalAdvance(const QFontMetrics& fm, const QString& s)
  181. {
  182. #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
  183. return fm.horizontalAdvance(s);
  184. #else
  185. return fm.width(s);
  186. #endif
  187. }
  188. //---------------------------------------------------------------------------------------------------------------------
  189. // Check if a string array contains a string
  190. bool stringArrayContainsString(const char* const* const stringArray, const char* const string) noexcept
  191. {
  192. for (uint i=0; stringArray[i] != nullptr; ++i)
  193. {
  194. if (std::strcmp(stringArray[i], string) == 0)
  195. return true;
  196. }
  197. return false;
  198. }
  199. //---------------------------------------------------------------------------------------------------------------------
  200. // Custom QMessageBox which resizes itself to fit text
  201. void QMessageBoxWithBetterWidth::showEvent(QShowEvent* const event)
  202. {
  203. const QFontMetrics metrics(fontMetrics());
  204. const QStringList lines(text().trimmed().split("\n") + informativeText().trimmed().split("\n"));
  205. if (lines.size() > 0)
  206. {
  207. int width = 0;
  208. for (const QString& line : lines)
  209. width = std::max(fontMetricsHorizontalAdvance(metrics, line), width);
  210. if (QGridLayout* const layout_ = dynamic_cast<QGridLayout*>(layout()))
  211. layout_->setColumnMinimumWidth(2, width + 12);
  212. }
  213. QMessageBox::showEvent(event);
  214. }
  215. //---------------------------------------------------------------------------------------------------------------------
  216. // Safer QSettings class, which does not throw if type mismatches
  217. bool QSafeSettings::valueBool(const QString key, const bool defaultValue) const
  218. {
  219. QVariant var(value(key, defaultValue));
  220. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Bool), defaultValue);
  221. return var.isValid() ? var.toBool() : defaultValue;
  222. }
  223. Qt::CheckState QSafeSettings::valueCheckState(const QString key, const Qt::CheckState defaultValue) const
  224. {
  225. QVariant var(value(key, defaultValue));
  226. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue);
  227. if (! var.isValid())
  228. return defaultValue;
  229. const uint value = var.toUInt();
  230. switch (value)
  231. {
  232. case Qt::Unchecked:
  233. case Qt::PartiallyChecked:
  234. case Qt::Checked:
  235. return static_cast<Qt::CheckState>(value);
  236. default:
  237. return defaultValue;
  238. }
  239. }
  240. uint QSafeSettings::valueUInt(const QString key, const uint defaultValue) const
  241. {
  242. QVariant var(value(key, defaultValue));
  243. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::UInt), defaultValue);
  244. return var.isValid() ? var.toUInt() : defaultValue;
  245. }
  246. double QSafeSettings::valueDouble(const QString key, const double defaultValue) const
  247. {
  248. QVariant var(value(key, defaultValue));
  249. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::Double), defaultValue);
  250. return var.isValid() ? var.toDouble() : defaultValue;
  251. }
  252. QString QSafeSettings::valueString(const QString key, const QString defaultValue) const
  253. {
  254. QVariant var(value(key, defaultValue));
  255. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::String), defaultValue);
  256. return var.isValid() ? var.toString() : defaultValue;
  257. }
  258. QByteArray QSafeSettings::valueByteArray(const QString key, const QByteArray defaultValue) const
  259. {
  260. QVariant var(value(key, defaultValue));
  261. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::ByteArray), defaultValue);
  262. return var.isValid() ? var.toByteArray() : defaultValue;
  263. }
  264. QStringList QSafeSettings::valueStringList(const QString key, const QStringList defaultValue) const
  265. {
  266. QVariant var(value(key, defaultValue));
  267. CARLA_SAFE_ASSERT_RETURN(var.convert(QVariant::StringList), defaultValue);
  268. return var.isValid() ? var.toStringList() : defaultValue;
  269. }
  270. //---------------------------------------------------------------------------------------------------------------------
  271. // Custom MessageBox
  272. int CustomMessageBox(QWidget* const parent,
  273. const QMessageBox::Icon icon,
  274. const QString title,
  275. const QString text,
  276. const QString extraText,
  277. const QMessageBox::StandardButtons buttons,
  278. const QMessageBox::StandardButton defButton)
  279. {
  280. QMessageBoxWithBetterWidth msgBox(parent);
  281. msgBox.setIcon(icon);
  282. msgBox.setWindowTitle(title);
  283. msgBox.setText(text);
  284. msgBox.setInformativeText(extraText);
  285. msgBox.setStandardButtons(buttons);
  286. msgBox.setDefaultButton(defButton);
  287. return msgBox.exec();
  288. }
  289. //---------------------------------------------------------------------------------------------------------------------