SaControlsDialog.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * SaControlsDialog.cpp - definition of SaControlsDialog class.
  3. *
  4. * Copyright (c) 2019 Martin Pavelek <he29/dot/HS/at/gmail/dot/com>
  5. *
  6. * This file is part of LMMS - https://lmms.io
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public
  19. * License along with this program (see COPYING); if not, write to the
  20. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301 USA.
  22. *
  23. */
  24. #include "SaControlsDialog.h"
  25. #include <QGridLayout>
  26. #include <QLabel>
  27. #include <QSizePolicy>
  28. #include <QSplitter>
  29. #include <QWidget>
  30. #include "ComboBox.h"
  31. #include "ComboBoxModel.h"
  32. #include "embed.h"
  33. #include "Engine.h"
  34. #include "LedCheckbox.h"
  35. #include "PixmapButton.h"
  36. #include "SaControls.h"
  37. #include "SaProcessor.h"
  38. // The entire GUI layout is built here.
  39. SaControlsDialog::SaControlsDialog(SaControls *controls, SaProcessor *processor) :
  40. EffectControlDialog(controls),
  41. m_controls(controls),
  42. m_processor(processor)
  43. {
  44. // Top level placement of sections is handled by QSplitter widget.
  45. QHBoxLayout *master_layout = new QHBoxLayout;
  46. QSplitter *display_splitter = new QSplitter(Qt::Vertical);
  47. master_layout->addWidget(display_splitter);
  48. master_layout->setContentsMargins(2, 6, 2, 8);
  49. setLayout(master_layout);
  50. // QSplitter top: configuration section
  51. QWidget *config_widget = new QWidget;
  52. QGridLayout *config_layout = new QGridLayout;
  53. config_widget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  54. config_widget->setMaximumHeight(m_configHeight);
  55. config_widget->setLayout(config_layout);
  56. display_splitter->addWidget(config_widget);
  57. // Pre-compute target pixmap size based on monitor DPI.
  58. // Using setDevicePixelRatio() on pixmap allows the SVG image to be razor
  59. // sharp on High-DPI screens, but the desired size must be manually
  60. // enlarged. No idea how to make Qt do it in a more reasonable way.
  61. QSize iconSize = QSize(22.0 * devicePixelRatio(), 22.0 * devicePixelRatio());
  62. QSize buttonSize = 1.2 * iconSize;
  63. // pause and freeze buttons
  64. PixmapButton *pauseButton = new PixmapButton(this, tr("Pause"));
  65. pauseButton->setToolTip(tr("Pause data acquisition"));
  66. QPixmap *pauseOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("play").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  67. QPixmap *pauseOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("pause").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  68. pauseOnPixmap->setDevicePixelRatio(devicePixelRatio());
  69. pauseOffPixmap->setDevicePixelRatio(devicePixelRatio());
  70. pauseButton->setActiveGraphic(*pauseOnPixmap);
  71. pauseButton->setInactiveGraphic(*pauseOffPixmap);
  72. pauseButton->setCheckable(true);
  73. pauseButton->setModel(&controls->m_pauseModel);
  74. config_layout->addWidget(pauseButton, 0, 0, 2, 1);
  75. PixmapButton *refFreezeButton = new PixmapButton(this, tr("Reference freeze"));
  76. refFreezeButton->setToolTip(tr("Freeze current input as a reference / disable falloff in peak-hold mode."));
  77. QPixmap *freezeOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  78. QPixmap *freezeOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("freeze_off").scaled(buttonSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  79. freezeOnPixmap->setDevicePixelRatio(devicePixelRatio());
  80. freezeOffPixmap->setDevicePixelRatio(devicePixelRatio());
  81. refFreezeButton->setActiveGraphic(*freezeOnPixmap);
  82. refFreezeButton->setInactiveGraphic(*freezeOffPixmap);
  83. refFreezeButton->setCheckable(true);
  84. refFreezeButton->setModel(&controls->m_refFreezeModel);
  85. config_layout->addWidget(refFreezeButton, 2, 0, 2, 1);
  86. // misc configuration switches
  87. LedCheckBox *waterfallButton = new LedCheckBox(tr("Waterfall"), this);
  88. waterfallButton->setToolTip(tr("Display real-time spectrogram"));
  89. waterfallButton->setCheckable(true);
  90. waterfallButton->setMinimumSize(70, 12);
  91. waterfallButton->setModel(&controls->m_waterfallModel);
  92. config_layout->addWidget(waterfallButton, 0, 1);
  93. LedCheckBox *smoothButton = new LedCheckBox(tr("Averaging"), this);
  94. smoothButton->setToolTip(tr("Enable exponential moving average"));
  95. smoothButton->setCheckable(true);
  96. smoothButton->setMinimumSize(70, 12);
  97. smoothButton->setModel(&controls->m_smoothModel);
  98. config_layout->addWidget(smoothButton, 1, 1);
  99. LedCheckBox *stereoButton = new LedCheckBox(tr("Stereo"), this);
  100. stereoButton->setToolTip(tr("Display stereo channels separately"));
  101. stereoButton->setCheckable(true);
  102. stereoButton->setMinimumSize(70, 12);
  103. stereoButton->setModel(&controls->m_stereoModel);
  104. config_layout->addWidget(stereoButton, 2, 1);
  105. LedCheckBox *peakHoldButton = new LedCheckBox(tr("Peak hold"), this);
  106. peakHoldButton->setToolTip(tr("Display envelope of peak values"));
  107. peakHoldButton->setCheckable(true);
  108. peakHoldButton->setMinimumSize(70, 12);
  109. peakHoldButton->setModel(&controls->m_peakHoldModel);
  110. config_layout->addWidget(peakHoldButton, 3, 1);
  111. // frequency: linear / log. switch and range selector
  112. PixmapButton *logXButton = new PixmapButton(this, tr("Logarithmic frequency"));
  113. logXButton->setToolTip(tr("Switch between logarithmic and linear frequency scale"));
  114. QPixmap *logXOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  115. QPixmap *logXOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("x_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  116. logXOnPixmap->setDevicePixelRatio(devicePixelRatio());
  117. logXOffPixmap->setDevicePixelRatio(devicePixelRatio());
  118. logXButton->setActiveGraphic(*logXOnPixmap);
  119. logXButton->setInactiveGraphic(*logXOffPixmap);
  120. logXButton->setCheckable(true);
  121. logXButton->setModel(&controls->m_logXModel);
  122. config_layout->addWidget(logXButton, 0, 2, 2, 1, Qt::AlignRight);
  123. ComboBox *freqRangeCombo = new ComboBox(this, tr("Frequency range"));
  124. freqRangeCombo->setToolTip(tr("Frequency range"));
  125. freqRangeCombo->setMinimumSize(100, 22);
  126. freqRangeCombo->setMaximumSize(200, 22);
  127. freqRangeCombo->setModel(&controls->m_freqRangeModel);
  128. config_layout->addWidget(freqRangeCombo, 0, 3, 2, 1);
  129. // amplitude: linear / log switch and range selector
  130. PixmapButton *logYButton = new PixmapButton(this, tr("Logarithmic amplitude"));
  131. logYButton->setToolTip(tr("Switch between logarithmic and linear amplitude scale"));
  132. QPixmap *logYOnPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_log").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  133. QPixmap *logYOffPixmap = new QPixmap(PLUGIN_NAME::getIconPixmap("y_linear").scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  134. logYOnPixmap->setDevicePixelRatio(devicePixelRatio());
  135. logYOffPixmap->setDevicePixelRatio(devicePixelRatio());
  136. logYButton->setActiveGraphic(*logYOnPixmap);
  137. logYButton->setInactiveGraphic(*logYOffPixmap);
  138. logYButton->setCheckable(true);
  139. logYButton->setModel(&controls->m_logYModel);
  140. config_layout->addWidget(logYButton, 2, 2, 2, 1, Qt::AlignRight);
  141. ComboBox *ampRangeCombo = new ComboBox(this, tr("Amplitude range"));
  142. ampRangeCombo->setToolTip(tr("Amplitude range"));
  143. ampRangeCombo->setMinimumSize(100, 22);
  144. ampRangeCombo->setMaximumSize(200, 22);
  145. ampRangeCombo->setModel(&controls->m_ampRangeModel);
  146. config_layout->addWidget(ampRangeCombo, 2, 3, 2, 1);
  147. // FFT: block size: icon and selector
  148. QLabel *blockSizeLabel = new QLabel("", this);
  149. QPixmap *blockSizeIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("block_size"));
  150. blockSizeIcon->setDevicePixelRatio(devicePixelRatio());
  151. blockSizeLabel->setPixmap(blockSizeIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  152. config_layout->addWidget(blockSizeLabel, 0, 4, 2, 1, Qt::AlignRight);
  153. ComboBox *blockSizeCombo = new ComboBox(this, tr("FFT block bize"));
  154. blockSizeCombo->setToolTip(tr("FFT block size"));
  155. blockSizeCombo->setMinimumSize(100, 22);
  156. blockSizeCombo->setMaximumSize(200, 22);
  157. blockSizeCombo->setModel(&controls->m_blockSizeModel);
  158. config_layout->addWidget(blockSizeCombo, 0, 5, 2, 1);
  159. processor->reallocateBuffers();
  160. connect(&controls->m_blockSizeModel, &ComboBoxModel::dataChanged, [=] {processor->reallocateBuffers();});
  161. // FFT: window type: icon and selector
  162. QLabel *windowLabel = new QLabel("", this);
  163. QPixmap *windowIcon = new QPixmap(PLUGIN_NAME::getIconPixmap("window"));
  164. windowIcon->setDevicePixelRatio(devicePixelRatio());
  165. windowLabel->setPixmap(windowIcon->scaled(iconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
  166. config_layout->addWidget(windowLabel, 2, 4, 2, 1, Qt::AlignRight);
  167. ComboBox *windowCombo = new ComboBox(this, tr("FFT window type"));
  168. windowCombo->setToolTip(tr("FFT window type"));
  169. windowCombo->setMinimumSize(100, 22);
  170. windowCombo->setMaximumSize(200, 22);
  171. windowCombo->setModel(&controls->m_windowModel);
  172. config_layout->addWidget(windowCombo, 2, 5, 2, 1);
  173. processor->rebuildWindow();
  174. connect(&controls->m_windowModel, &ComboBoxModel::dataChanged, [=] {processor->rebuildWindow();});
  175. // QSplitter middle and bottom: spectrum display widgets
  176. m_spectrum = new SaSpectrumView(controls, processor, this);
  177. display_splitter->addWidget(m_spectrum);
  178. m_waterfall = new SaWaterfallView(controls, processor, this);
  179. display_splitter->addWidget(m_waterfall);
  180. m_waterfall->setVisible(m_controls->m_waterfallModel.value());
  181. connect(&controls->m_waterfallModel, &BoolModel::dataChanged, [=] {m_waterfall->updateVisibility();});
  182. }
  183. // Suggest the best current widget size.
  184. QSize SaControlsDialog::sizeHint() const
  185. {
  186. // Best width is determined by spectrum display sizeHint.
  187. // Best height depends on whether waterfall is visible and
  188. // consists of heights of the config section, spectrum, waterfall
  189. // and some reserve for margins.
  190. if (m_waterfall->isVisible())
  191. {
  192. return QSize(m_spectrum->sizeHint().width(),
  193. m_configHeight + m_spectrum->sizeHint().height() + m_waterfall->sizeHint().height() + 50);
  194. }
  195. else
  196. {
  197. return QSize(m_spectrum->sizeHint().width(),
  198. m_configHeight + m_spectrum->sizeHint().height() + 50);
  199. }
  200. }