1 #include <QCloseEvent>
2 #include <QSettings>
3 #include <QResizeEvent>
4 #include <QMessageBox>
5 #include <QPainter>
6 #include <QScrollArea>
7 #include <QVBoxLayout>
8 #include <QGroupBox>
9 #include <QFormLayout>
10 #include <QSpinBox>
11 #include <QDoubleSpinBox>
12 #include <QCheckBox>
13 #include <QComboBox>
14 #include <QPushButton>
15 #include <QToolButton>
16 #include <QMenu>
17 #include <QFileInfo>
18 #include <QFileDialog>
19 #include <QTimer>
20 #include <QMainWindow>
21 #include <QApplication>
22 #include <QLineEdit>
23 #include <QDialogButtonBox>
24 #include <QHBoxLayout>
25 #include <QColor>
26 #include <QColorDialog>
27 #include <QLabel>
28 #include <QBitmap>
29 #include <QStackedLayout>
30 #include <QScrollBar>
31
32 #include "coreoptionsdialog.h"
33 #include "viewoptionsdialog.h"
34 #include "coreinfodialog.h"
35 #include "playlistentrydialog.h"
36 #include "../ui_qt.h"
37
38 #ifndef CXX_BUILD
39 extern "C" {
40 #endif
41
42 #ifdef HAVE_CONFIG_H
43 #include "../../../config.h"
44 #endif
45
46 #include <math.h>
47 #include <string/stdstring.h>
48 #include <streams/file_stream.h>
49 #include <file/file_path.h>
50
51 #ifdef HAVE_MENU
52 #include "../../../menu/menu_driver.h"
53 #include "../../../menu/menu_entries.h"
54 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
55 #include "../../../menu/menu_shader.h"
56 #endif
57 #endif
58
59 #include "../../../command.h"
60 #include "../../../core_info.h"
61 #include "../../../core_option_manager.h"
62 #include "../../../configuration.h"
63 #include "../../../file_path_special.h"
64 #include "../../../msg_hash.h"
65 #include "../../../paths.h"
66 #include "../../../retroarch.h"
67
68 #ifndef CXX_BUILD
69 }
70 #endif
71
72 #if defined(HAVE_MENU)
73 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
74 #include "shaderparamsdialog.h"
75 #endif
76 #endif
77
78 #include "qt_options.h"
79
80 #if defined(_MSC_VER) && !defined(_XBOX) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
81 /* https://support.microsoft.com/en-us/kb/980263 */
82 #pragma execution_character_set("utf-8")
83 #pragma warning(disable:4566)
84 #endif
85
comp_string_lower(const QString & lhs,const QString & rhs)86 static inline bool comp_string_lower(const QString &lhs, const QString &rhs)
87 {
88 return lhs.toLower() < rhs.toLower();
89 }
90
comp_hash_ui_display_name_key_lower(const QHash<QString,QString> & lhs,const QHash<QString,QString> & rhs)91 static inline bool comp_hash_ui_display_name_key_lower(const QHash<QString, QString> &lhs, const QHash<QString, QString> &rhs)
92 {
93 return lhs.value("ui_display_name").toLower() < rhs.value("ui_display_name").toLower();
94 }
95
PlaylistEntryDialog(MainWindow * mainwindow,QWidget * parent)96 PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent) :
97 QDialog(parent)
98 ,m_mainwindow(mainwindow)
99 ,m_settings(mainwindow->settings())
100 ,m_nameLineEdit(new QLineEdit(this))
101 ,m_pathLineEdit(new QLineEdit(this))
102 ,m_extensionsLineEdit(new QLineEdit(this))
103 ,m_coreComboBox(new QComboBox(this))
104 ,m_databaseComboBox(new QComboBox(this))
105 ,m_extensionArchiveCheckBox(new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES), this))
106 {
107 QFormLayout *form = new QFormLayout();
108 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
109 QVBoxLayout *databaseVBoxLayout = new QVBoxLayout();
110 QHBoxLayout *pathHBoxLayout = new QHBoxLayout();
111 QHBoxLayout *extensionHBoxLayout = new QHBoxLayout();
112 QLabel *databaseLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS), this);
113 QToolButton *pathPushButton = new QToolButton(this);
114
115 pathPushButton->setText(QStringLiteral("..."));
116
117 pathHBoxLayout->addWidget(m_pathLineEdit);
118 pathHBoxLayout->addWidget(pathPushButton);
119
120 databaseVBoxLayout->addWidget(m_databaseComboBox);
121 databaseVBoxLayout->addWidget(databaseLabel);
122
123 extensionHBoxLayout->addWidget(m_extensionsLineEdit);
124 extensionHBoxLayout->addWidget(m_extensionArchiveCheckBox);
125
126 m_extensionsLineEdit->setPlaceholderText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER));
127
128 /* Ensure placeholder text is completely visible. */
129 m_extensionsLineEdit->setMinimumWidth(QFontMetrics(m_extensionsLineEdit->font()).boundingRect(m_extensionsLineEdit->placeholderText()).width() + m_extensionsLineEdit->frameSize().width());
130
131 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY));
132
133 form->setFormAlignment(Qt::AlignCenter);
134 form->setLabelAlignment(Qt::AlignCenter);
135
136 setLayout(new QVBoxLayout(this));
137
138 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
139 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
140
141 connect(this, SIGNAL(accepted()), this, SLOT(onAccepted()));
142 connect(this, SIGNAL(rejected()), this, SLOT(onRejected()));
143
144 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_NAME), m_nameLineEdit);
145 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH), pathHBoxLayout);
146 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE), m_coreComboBox);
147 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE), databaseVBoxLayout);
148 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS), extensionHBoxLayout);
149
150 qobject_cast<QVBoxLayout*>(layout())->addLayout(form);
151 layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
152 layout()->addWidget(buttonBox);
153
154 connect(pathPushButton, SIGNAL(clicked()), this, SLOT(onPathClicked()));
155 }
156
filterInArchive()157 bool PlaylistEntryDialog::filterInArchive()
158 {
159 return m_extensionArchiveCheckBox->isChecked();
160 }
161
onPathClicked()162 void PlaylistEntryDialog::onPathClicked()
163 {
164 QString filePath = QFileDialog::getOpenFileName(this);
165
166 if (filePath.isEmpty())
167 return;
168
169 m_pathLineEdit->setText(filePath);
170 }
171
loadPlaylistOptions()172 void PlaylistEntryDialog::loadPlaylistOptions()
173 {
174 unsigned i, j;
175 core_info_list_t *core_info_list = NULL;
176
177 m_nameLineEdit->clear();
178 m_pathLineEdit->clear();
179 m_coreComboBox->clear();
180 m_databaseComboBox->clear();
181
182 m_coreComboBox->addItem(
183 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_SELECTION_ASK));
184 m_databaseComboBox->addItem(
185 QString("<")
186 + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)
187 + ">",
188 QFileInfo(m_mainwindow->getCurrentPlaylistPath()).fileName().remove(".lpl"));
189
190 core_info_get_list(&core_info_list);
191
192 if (core_info_list && core_info_list->count > 0)
193 {
194 QVector<QHash<QString, QString> > allCores;
195 QStringList allDatabases;
196
197 for (i = 0; i < core_info_list->count; i++)
198 {
199 QString ui_display_name;
200 QHash<QString, QString> hash;
201 const core_info_t *core = &core_info_list->list[i];
202 QStringList databases = string_split_to_qt(QString(core->databases), '|');
203
204 hash["core_name"] = core->core_name;
205 hash["core_display_name"] = core->display_name;
206 hash["core_path"] = core->path;
207 hash["core_databases"] = core->databases;
208
209 ui_display_name = hash.value("core_name");
210
211 if (ui_display_name.isEmpty())
212 ui_display_name = hash.value("core_display_name");
213 if (ui_display_name.isEmpty())
214 ui_display_name = QFileInfo(
215 hash.value("core_path")).fileName();
216
217 if (ui_display_name.isEmpty())
218 continue;
219
220 hash["ui_display_name"] = ui_display_name;
221
222 for (j = 0; static_cast<int>(j) < databases.count(); j++)
223 {
224 QString database = databases.at(static_cast<int>(j));
225
226 if (database.isEmpty())
227 continue;
228
229 if (!allDatabases.contains(database))
230 allDatabases.append(database);
231 }
232
233 if (!allCores.contains(hash))
234 allCores.append(hash);
235 }
236
237 std::sort(allCores.begin(), allCores.end(), comp_hash_ui_display_name_key_lower);
238 std::sort(allDatabases.begin(), allDatabases.end(), comp_string_lower);
239
240 for (j = 0; static_cast<int>(j) < allCores.count(); j++)
241 {
242 const QHash<QString, QString> &hash = allCores.at(static_cast<int>(j));
243
244 m_coreComboBox->addItem(hash.value("ui_display_name"), QVariant::fromValue(hash));
245 }
246
247 for (j = 0; static_cast<int>(j) < allDatabases.count(); j++)
248 {
249 QString database = allDatabases.at(static_cast<int>(j));
250 m_databaseComboBox->addItem(database, database);
251 }
252 }
253 }
254
nameFieldEnabled()255 bool PlaylistEntryDialog::nameFieldEnabled()
256 {
257 return m_nameLineEdit->isEnabled();
258 }
259
setEntryValues(const QHash<QString,QString> & contentHash)260 void PlaylistEntryDialog::setEntryValues(
261 const QHash<QString, QString> &contentHash)
262 {
263 QString db;
264 QString coreName = contentHash.value("core_name");
265 int foundDB = 0;
266 int i = 0;
267
268 loadPlaylistOptions();
269
270 if (contentHash.isEmpty())
271 {
272 m_nameLineEdit->setText(
273 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE));
274 m_pathLineEdit->setText(
275 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FIELD_MULTIPLE));
276 m_nameLineEdit->setEnabled(false);
277 m_pathLineEdit->setEnabled(false);
278 }
279 else
280 {
281 m_nameLineEdit->setText(contentHash.value("label"));
282 m_pathLineEdit->setText(contentHash.value("path"));
283 m_nameLineEdit->setEnabled(true);
284 m_pathLineEdit->setEnabled(true);
285 }
286
287 for (i = 0; i < m_coreComboBox->count(); i++)
288 {
289 const QHash<QString, QString> hash = m_coreComboBox->itemData(i, Qt::UserRole).value<QHash<QString, QString> >();
290
291 if (hash.isEmpty() || coreName.isEmpty())
292 continue;
293
294 if (hash.value("core_name") == coreName)
295 {
296 m_coreComboBox->setCurrentIndex(i);
297 break;
298 }
299 }
300
301 db = contentHash.value("db_name");
302
303 if (!db.isEmpty())
304 {
305 foundDB = m_databaseComboBox->findText(db);
306
307 if (foundDB >= 0)
308 m_databaseComboBox->setCurrentIndex(foundDB);
309 }
310 }
311
getSelectedCore()312 const QHash<QString, QString> PlaylistEntryDialog::getSelectedCore()
313 {
314 return m_coreComboBox->currentData(Qt::UserRole).value<QHash<QString, QString> >();
315 }
316
getSelectedName()317 const QString PlaylistEntryDialog::getSelectedName()
318 {
319 return m_nameLineEdit->text();
320 }
321
getSelectedPath()322 const QString PlaylistEntryDialog::getSelectedPath()
323 {
324 return m_pathLineEdit->text();
325 }
326
getSelectedDatabase()327 const QString PlaylistEntryDialog::getSelectedDatabase()
328 {
329 return m_databaseComboBox->currentData(Qt::UserRole).toString();
330 }
331
getSelectedExtensions()332 const QStringList PlaylistEntryDialog::getSelectedExtensions()
333 {
334 QStringList list;
335 QString text = m_extensionsLineEdit->text();
336
337 /* Otherwise it would create a QStringList with a single blank entry... */
338 if (!text.isEmpty())
339 list = string_split_to_qt(text, ' ');
340 return list;
341 }
342
onAccepted()343 void PlaylistEntryDialog::onAccepted()
344 {
345 }
346
onRejected()347 void PlaylistEntryDialog::onRejected()
348 {
349 }
350
showDialog(const QHash<QString,QString> & hash)351 bool PlaylistEntryDialog::showDialog(const QHash<QString, QString> &hash)
352 {
353 loadPlaylistOptions();
354 setEntryValues(hash);
355
356 if (exec() == QDialog::Accepted)
357 return true;
358 return false;
359 }
360
hideDialog()361 void PlaylistEntryDialog::hideDialog()
362 {
363 reject();
364 }
365
CoreInfoDialog(MainWindow * mainwindow,QWidget * parent)366 CoreInfoDialog::CoreInfoDialog(MainWindow *mainwindow, QWidget *parent) :
367 QDialog(parent)
368 ,m_formLayout(new QFormLayout())
369 ,m_mainwindow(mainwindow)
370 {
371 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
372
373 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
374 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
375
376 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION));
377
378 m_formLayout->setFormAlignment(Qt::AlignCenter);
379 m_formLayout->setLabelAlignment(Qt::AlignCenter);
380
381 setLayout(new QVBoxLayout());
382
383 qobject_cast<QVBoxLayout*>(layout())->addLayout(m_formLayout);
384 layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
385 layout()->addWidget(buttonBox);
386 }
387
showCoreInfo()388 void CoreInfoDialog::showCoreInfo()
389 {
390 int row = 0;
391 int row_count = m_formLayout->rowCount();
392 int i = 0;
393 QVector<QHash<QString, QString> > info_list
394 = m_mainwindow->getCoreInfo();
395
396 if (row_count > 0)
397 {
398 for (row = 0; row < row_count; row++)
399 {
400 #if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
401 /* removeRow() and takeRow() was only added in 5.8! */
402 m_formLayout->removeRow(0);
403 #else
404 /* something is buggy here...
405 * sometimes items appear duplicated, and other times not */
406 QLayoutItem *item = m_formLayout->itemAt(0);
407 QWidget *w = NULL;
408
409 if (item)
410 {
411 w = item->widget();
412
413 if (w)
414 {
415 QWidget *label = m_formLayout->labelForField(w);
416
417 if (label)
418 delete label;
419
420 m_formLayout->removeWidget(w);
421
422 delete w;
423 }
424 }
425 #endif
426 }
427 }
428
429 if (info_list.count() == 0)
430 return;
431
432 for (i = 0; i < info_list.count(); i++)
433 {
434 const QHash<QString, QString> &line = info_list.at(i);
435 QLabel *label = new QLabel(line.value("key"));
436 CoreInfoLabel *value = new CoreInfoLabel(line.value("value"));
437 QString labelStyle = line.value("label_style");
438 QString valueStyle = line.value("value_style");
439
440 if (!labelStyle.isEmpty())
441 label->setStyleSheet(labelStyle);
442
443 if (!valueStyle.isEmpty())
444 value->setStyleSheet(valueStyle);
445
446 m_formLayout->addRow(label, value);
447 }
448
449 show();
450 }
451
452 #ifdef HAVE_MENU
getColorizedPixmap(const QPixmap & oldPixmap,const QColor & color)453 QPixmap getColorizedPixmap(const QPixmap& oldPixmap, const QColor& color)
454 {
455 QPixmap pixmap = oldPixmap;
456 QBitmap mask = pixmap.createMaskFromColor(Qt::transparent, Qt::MaskInColor);
457 pixmap.fill(color);
458 pixmap.setMask(mask);
459 return pixmap;
460 }
461
getLabelColor(const QString & objectName)462 QColor getLabelColor(const QString& objectName)
463 {
464 QLabel dummyColor;
465 dummyColor.setObjectName(objectName);
466 dummyColor.ensurePolished();
467 return dummyColor.palette().color(QPalette::Foreground);
468 }
469
470 /* stolen from Qt Creator */
471 class SmartScrollArea : public QScrollArea
472 {
473 public:
SmartScrollArea(QWidget * parent)474 explicit SmartScrollArea(QWidget *parent) :
475 QScrollArea(parent)
476 {
477 setFrameStyle(QFrame::NoFrame | QFrame::Plain);
478 viewport()->setAutoFillBackground(false);
479 setWidgetResizable(true);
480 }
481 private:
resizeEvent(QResizeEvent * event)482 void resizeEvent(QResizeEvent *event) final
483 {
484 QWidget *inner = widget();
485
486 if (inner)
487 {
488 int fw = frameWidth() * 2;
489 QSize innerSize = event->size() - QSize(fw, fw);
490 QSize innerSizeHint = inner->minimumSizeHint();
491
492 /* Widget wants to be bigger than available space */
493 if (innerSizeHint.height() > innerSize.height())
494 {
495 innerSize.setWidth(innerSize.width() - scrollBarWidth());
496 innerSize.setHeight(innerSizeHint.height());
497 }
498 inner->resize(innerSize);
499 }
500 QScrollArea::resizeEvent(event);
501 }
502
minimumSizeHint() const503 QSize minimumSizeHint() const final
504 {
505 static const int max_min_width = 250;
506 static const int max_min_height = 250;
507 QWidget *inner = widget();
508
509 if (inner)
510 {
511 int fw = frameWidth() * 2;
512 QSize minSize = inner->minimumSizeHint();
513
514 minSize += QSize(fw, fw);
515 minSize += QSize(scrollBarWidth(), 0);
516 minSize.setWidth(qMin(minSize.width(), max_min_width));
517 minSize.setHeight(qMin(minSize.height(), max_min_height));
518 return minSize;
519 }
520 return QSize(0, 0);
521 }
522
event(QEvent * event)523 bool event(QEvent *event) final
524 {
525 if (event->type() == QEvent::LayoutRequest)
526 updateGeometry();
527 return QScrollArea::event(event);
528 }
529
scrollBarWidth() const530 int scrollBarWidth() const
531 {
532 SmartScrollArea *that = const_cast<SmartScrollArea *>(this);
533 QWidgetList list = that->scrollBarWidgets(Qt::AlignRight);
534 if (list.isEmpty())
535 return 0;
536 return list.first()->sizeHint().width();
537 }
538 };
539
ViewOptionsDialog(MainWindow * mainwindow,QWidget * parent)540 ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) :
541 QDialog(mainwindow)
542 ,m_optionsList(new QListWidget(this))
543 ,m_optionsStack(new QStackedLayout)
544 {
545 int width;
546 QGridLayout *layout = new QGridLayout(this);
547 QLabel *m_headerLabel = new QLabel(this);
548 /* Header label with large font and a bit of spacing
549 * (align with group boxes) */
550 QFont headerLabelFont = m_headerLabel->font();
551 const int pointSize = headerLabelFont.pointSize();
552 QHBoxLayout *headerHLayout = new QHBoxLayout;
553 const int leftMargin = QApplication::style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
554
555 m_optionsStack->setMargin(0);
556
557 headerLabelFont.setBold(true);
558
559 /* Paranoia: Should a font be set in pixels... */
560 if (pointSize > 0)
561 headerLabelFont.setPointSize(pointSize + 2);
562
563 m_headerLabel->setFont(headerLabelFont);
564
565 headerHLayout->addSpacerItem(new QSpacerItem(leftMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
566 headerHLayout->addWidget(m_headerLabel);
567
568 addCategory(new DriversCategory(this));
569 addCategory(new VideoCategory(this));
570 addCategory(new AudioCategory(this));
571 addCategory(new InputCategory(this));
572 addCategory(new LatencyCategory(this));
573 addCategory(new CoreCategory(this));
574 addCategory(new ConfigurationCategory(this));
575 addCategory(new SavingCategory(this));
576 addCategory(new LoggingCategory(this));
577 addCategory(new FrameThrottleCategory(this));
578 addCategory(new RecordingCategory(this));
579 addCategory(new OnscreenDisplayCategory(this));
580 addCategory(new UserInterfaceCategory(mainwindow, this));
581 addCategory(new AIServiceCategory(this));
582 addCategory(new AchievementsCategory(this));
583 addCategory(new NetworkCategory(this));
584 addCategory(new PlaylistsCategory(this));
585 addCategory(new UserCategory(this));
586 addCategory(new DirectoryCategory(this));
587
588 width =
589 m_optionsList->sizeHintForColumn(0)
590 + m_optionsList->frameWidth() * 2
591 + 5;
592 width += m_optionsList->verticalScrollBar()->sizeHint().width();
593
594 m_optionsList->setMaximumWidth(width);
595 m_optionsList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
596
597 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE));
598
599 layout->addWidget(m_optionsList, 0, 0, 2, 1);
600 layout->addLayout(headerHLayout, 0, 1);
601 layout->addLayout(m_optionsStack, 1, 1);
602
603 connect(m_optionsList, SIGNAL(currentRowChanged(int)), m_optionsStack, SLOT(setCurrentIndex(int)));
604 connect(m_optionsList, SIGNAL(currentTextChanged(const QString&)), m_headerLabel, SLOT(setText(const QString&)));
605
606 connect(this, SIGNAL(rejected()), this, SLOT(onRejected()));
607 }
608
getIcon(OptionsCategory * category)609 QIcon getIcon(OptionsCategory *category)
610 {
611 settings_t *settings = config_get_ptr();
612 const char *path_dir_assets = settings->paths.directory_assets;
613 QPixmap pixmap = QPixmap(QString(path_dir_assets)
614 + "/xmb/monochrome/png/"
615 + category->categoryIconName()
616 + ".png");
617 return QIcon(getColorizedPixmap(pixmap, getLabelColor("iconColor")));
618 }
619
addCategory(OptionsCategory * category)620 void ViewOptionsDialog::addCategory(OptionsCategory *category)
621 {
622 QTabWidget *tabWidget = new QTabWidget();
623
624 m_categoryList.append(category);
625
626 for (OptionsPage* page : category->pages())
627 {
628 SmartScrollArea *scrollArea = new SmartScrollArea(this);
629 QWidget *widget = page->widget();
630
631 scrollArea->setWidget(widget);
632 widget->setAutoFillBackground(false);
633 tabWidget->addTab(scrollArea, page->displayName());
634 }
635
636 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
637 tabWidget->setTabBarAutoHide(true);
638 #else
639 /* TODO remove the tabBar's space */
640 if (tabWidget->count() < 2)
641 tabWidget->tabBar()->hide();
642 #endif
643 m_optionsList->addItem(
644 new QListWidgetItem(getIcon(category),
645 category->displayName()));
646 m_optionsStack->addWidget(tabWidget);
647 }
648
repaintIcons()649 void ViewOptionsDialog::repaintIcons()
650 {
651 unsigned i;
652 size_t list_size = (size_t)m_categoryList.size();
653
654 for (i = 0; i < list_size; i++)
655 m_optionsList->item(i)->setIcon(getIcon(m_categoryList.at(i)));
656 }
657 #else
ViewOptionsDialog(MainWindow * mainwindow,QWidget * parent)658 ViewOptionsDialog::ViewOptionsDialog(MainWindow *mainwindow, QWidget *parent) :
659 QDialog(mainwindow)
660 , m_viewOptionsWidget(new ViewOptionsWidget(mainwindow))
661 {
662 QVBoxLayout *layout = new QVBoxLayout;
663 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
664
665 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
666 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
667
668 connect(this, SIGNAL(accepted()), m_viewOptionsWidget, SLOT(onAccepted()));
669 connect(this, SIGNAL(rejected()), m_viewOptionsWidget, SLOT(onRejected()));
670
671 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_TITLE));
672
673 layout->setContentsMargins(0, 0, 0, 0);
674
675 layout->addWidget(m_viewOptionsWidget);
676 layout->addWidget(buttonBox);
677
678 setLayout(layout);
679 }
680 #endif
681
showDialog()682 void ViewOptionsDialog::showDialog()
683 {
684 #ifdef HAVE_MENU
685 unsigned i;
686 size_t list_size = (size_t)m_categoryList.size();
687 for (i = 0; i < list_size; i++)
688 m_categoryList.at(i)->load();
689 #else
690 m_viewOptionsWidget->loadViewOptions();
691 #endif
692 show();
693 activateWindow();
694 }
695
hideDialog()696 void ViewOptionsDialog::hideDialog()
697 {
698 reject();
699 }
700
onRejected()701 void ViewOptionsDialog::onRejected()
702 {
703 #ifdef HAVE_MENU
704 unsigned i;
705 size_t list_size = (size_t)m_categoryList.size();
706 for (i = 0; i < list_size; i++)
707 m_categoryList.at(i)->apply();
708 #endif
709 }
710
ViewOptionsWidget(MainWindow * mainwindow,QWidget * parent)711 ViewOptionsWidget::ViewOptionsWidget(MainWindow *mainwindow, QWidget *parent) :
712 QWidget(parent)
713 ,m_mainwindow(mainwindow)
714 ,m_settings(mainwindow->settings())
715 ,m_saveGeometryCheckBox(new QCheckBox(this))
716 ,m_saveDockPositionsCheckBox(new QCheckBox(this))
717 ,m_saveLastTabCheckBox(new QCheckBox(this))
718 ,m_showHiddenFilesCheckBox(new QCheckBox(this))
719 ,m_themeComboBox(new QComboBox(this))
720 ,m_thumbnailCacheSpinBox(new QSpinBox(this))
721 ,m_thumbnailDropSizeSpinBox(new QSpinBox(this))
722 ,m_startupPlaylistComboBox(new QComboBox(this))
723 ,m_highlightColorPushButton(new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CHOOSE), this))
724 ,m_highlightColor()
725 ,m_highlightColorLabel(new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR), this))
726 ,m_customThemePath()
727 ,m_suggestLoadedCoreFirstCheckBox(new QCheckBox(this))
728 /* ,m_allPlaylistsListMaxCountSpinBox(new QSpinBox(this)) */
729 /* ,m_allPlaylistsGridMaxCountSpinBox(new QSpinBox(this)) */
730 {
731 QVBoxLayout *layout = new QVBoxLayout;
732 QFormLayout *form = new QFormLayout;
733
734 m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_SYSTEM_DEFAULT), MainWindow::THEME_SYSTEM_DEFAULT);
735 m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_DARK), MainWindow::THEME_DARK);
736 m_themeComboBox->addItem(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME_CUSTOM), MainWindow::THEME_CUSTOM);
737
738 m_thumbnailCacheSpinBox->setSuffix(" MB");
739 m_thumbnailCacheSpinBox->setRange(0, 99999);
740
741 m_thumbnailDropSizeSpinBox->setSuffix(" px");
742 m_thumbnailDropSizeSpinBox->setRange(0, 99999);
743
744 /* m_allPlaylistsListMaxCountSpinBox->setRange(0, 99999); */
745 /* m_allPlaylistsGridMaxCountSpinBox->setRange(0, 99999); */
746
747 form->setFormAlignment(Qt::AlignCenter);
748 form->setLabelAlignment(Qt::AlignCenter);
749
750 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY), m_saveGeometryCheckBox);
751 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_DOCK_POSITIONS), m_saveDockPositionsCheckBox);
752 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB), m_saveLastTabCheckBox);
753 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES), m_showHiddenFilesCheckBox);
754 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST), m_suggestLoadedCoreFirstCheckBox);
755 #if 0
756 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT), m_allPlaylistsListMaxCountSpinBox);
757 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT), m_allPlaylistsGridMaxCountSpinBox);
758 #endif
759 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST), m_startupPlaylistComboBox);
760 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT), m_thumbnailCacheSpinBox);
761 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT), m_thumbnailDropSizeSpinBox);
762 form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME), m_themeComboBox);
763 form->addRow(m_highlightColorLabel, m_highlightColorPushButton);
764
765 layout->addLayout(form);
766
767 layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
768
769 setLayout(layout);
770
771 loadViewOptions();
772
773 connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int)));
774 connect(m_highlightColorPushButton, SIGNAL(clicked()), this, SLOT(onHighlightColorChoose()));
775 }
776
onThemeComboBoxIndexChanged(int)777 void ViewOptionsWidget::onThemeComboBoxIndexChanged(int)
778 {
779 MainWindow::Theme theme = static_cast<MainWindow::Theme>(m_themeComboBox->currentData(Qt::UserRole).toInt());
780
781 if (theme == MainWindow::THEME_CUSTOM)
782 {
783 QString filePath = QFileDialog::getOpenFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_THEME));
784
785 if (filePath.isEmpty())
786 {
787 int oldThemeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString()));
788
789 if (m_themeComboBox->count() > oldThemeIndex)
790 {
791 disconnect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int)));
792 m_themeComboBox->setCurrentIndex(oldThemeIndex);
793 connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onThemeComboBoxIndexChanged(int)));
794 }
795 }
796 else
797 {
798 m_customThemePath = filePath;
799
800 if (m_mainwindow->setCustomThemeFile(filePath))
801 m_mainwindow->setTheme(theme);
802 }
803 }
804 else
805 m_mainwindow->setTheme(theme);
806
807 showOrHideHighlightColor();
808 }
809
onHighlightColorChoose()810 void ViewOptionsWidget::onHighlightColorChoose()
811 {
812 QPixmap highlightPixmap(m_highlightColorPushButton->iconSize());
813 QColor currentHighlightColor = m_settings->value("highlight_color",
814 QApplication::palette().highlight().color()).value<QColor>();
815 QColor newHighlightColor = QColorDialog::getColor(
816 currentHighlightColor, this,
817 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SELECT_COLOR));
818
819 if (newHighlightColor.isValid())
820 {
821 MainWindow::Theme theme = static_cast<MainWindow::Theme>(
822 m_themeComboBox->currentData(Qt::UserRole).toInt());
823
824 m_highlightColor = newHighlightColor;
825 m_settings->setValue("highlight_color", m_highlightColor);
826 highlightPixmap.fill(m_highlightColor);
827 m_highlightColorPushButton->setIcon(highlightPixmap);
828 m_mainwindow->setTheme(theme);
829 }
830 }
831
loadViewOptions()832 void ViewOptionsWidget::loadViewOptions()
833 {
834 int i;
835 int themeIndex = 0;
836 int playlistIndex = 0;
837 QColor highlightColor =
838 m_settings->value("highlight_color",
839 QApplication::palette().highlight().color()).value<QColor>();
840 QPixmap highlightPixmap(m_highlightColorPushButton->iconSize());
841 QVector<QPair<QString, QString> > playlists = m_mainwindow->getPlaylists();
842 QString initialPlaylist = m_settings->value("initial_playlist",
843 m_mainwindow->getSpecialPlaylistPath(
844 SPECIAL_PLAYLIST_HISTORY)).toString();
845
846 m_saveGeometryCheckBox->setChecked(m_settings->value("save_geometry", false).toBool());
847 m_saveDockPositionsCheckBox->setChecked(m_settings->value("save_dock_positions", false).toBool());
848 m_saveLastTabCheckBox->setChecked(m_settings->value("save_last_tab", false).toBool());
849 m_showHiddenFilesCheckBox->setChecked(m_settings->value("show_hidden_files", true).toBool());
850 m_suggestLoadedCoreFirstCheckBox->setChecked(m_settings->value("suggest_loaded_core_first", false).toBool());
851 #if 0
852 m_allPlaylistsListMaxCountSpinBox->setValue(m_settings->value("all_playlists_list_max_count", 0).toInt());
853 m_allPlaylistsGridMaxCountSpinBox->setValue(m_settings->value("all_playlists_grid_max_count", 5000).toInt());
854 #endif
855 m_thumbnailCacheSpinBox->setValue(m_settings->value("thumbnail_cache_limit", 512).toInt());
856 m_thumbnailDropSizeSpinBox->setValue(m_settings->value("thumbnail_max_size", 0).toInt());
857
858 themeIndex = m_themeComboBox->findData(m_mainwindow->getThemeFromString(m_settings->value("theme", "default").toString()));
859
860 if (m_themeComboBox->count() > themeIndex)
861 m_themeComboBox->setCurrentIndex(themeIndex);
862
863 if (highlightColor.isValid())
864 {
865 m_highlightColor = highlightColor;
866 highlightPixmap.fill(m_highlightColor);
867 m_highlightColorPushButton->setIcon(highlightPixmap);
868 }
869
870 showOrHideHighlightColor();
871
872 m_startupPlaylistComboBox->clear();
873
874 for (i = 0; i < playlists.count(); i++)
875 {
876 const QPair<QString, QString> &pair = playlists.at(i);
877
878 m_startupPlaylistComboBox->addItem(pair.first, pair.second);
879 }
880
881 playlistIndex = m_startupPlaylistComboBox->findData(
882 initialPlaylist, Qt::UserRole, Qt::MatchFixedString);
883
884 if (playlistIndex >= 0)
885 m_startupPlaylistComboBox->setCurrentIndex(playlistIndex);
886 }
887
showOrHideHighlightColor()888 void ViewOptionsWidget::showOrHideHighlightColor()
889 {
890 if (m_mainwindow->theme() == MainWindow::THEME_DARK)
891 {
892 m_highlightColorLabel->show();
893 m_highlightColorPushButton->show();
894 }
895 else
896 {
897 m_highlightColorLabel->hide();
898 m_highlightColorPushButton->hide();
899 }
900 }
901
saveViewOptions()902 void ViewOptionsWidget::saveViewOptions()
903 {
904 m_settings->setValue("save_geometry", m_saveGeometryCheckBox->isChecked());
905 m_settings->setValue("save_dock_positions", m_saveDockPositionsCheckBox->isChecked());
906 m_settings->setValue("save_last_tab", m_saveLastTabCheckBox->isChecked());
907 m_settings->setValue("theme", m_mainwindow->getThemeString(static_cast<MainWindow::Theme>(m_themeComboBox->currentData(Qt::UserRole).toInt())));
908 m_settings->setValue("show_hidden_files", m_showHiddenFilesCheckBox->isChecked());
909 m_settings->setValue("highlight_color", m_highlightColor);
910 m_settings->setValue("suggest_loaded_core_first", m_suggestLoadedCoreFirstCheckBox->isChecked());
911 #if 0
912 m_settings->setValue("all_playlists_list_max_count", m_allPlaylistsListMaxCountSpinBox->value());
913 m_settings->setValue("all_playlists_grid_max_count", m_allPlaylistsGridMaxCountSpinBox->value());
914 #endif
915 m_settings->setValue("initial_playlist", m_startupPlaylistComboBox->currentData(Qt::UserRole).toString());
916 m_settings->setValue("thumbnail_cache_limit", m_thumbnailCacheSpinBox->value());
917 m_settings->setValue("thumbnail_max_size", m_thumbnailDropSizeSpinBox->value());
918
919 if (!m_mainwindow->customThemeString().isEmpty())
920 m_settings->setValue("custom_theme", m_customThemePath);
921
922 #if 0
923 m_mainwindow->setAllPlaylistsListMaxCount(m_allPlaylistsListMaxCountSpinBox->value());
924 m_mainwindow->setAllPlaylistsGridMaxCount(m_allPlaylistsGridMaxCountSpinBox->value());
925 #endif
926 m_mainwindow->setThumbnailCacheLimit(m_thumbnailCacheSpinBox->value());
927 }
928
onAccepted()929 void ViewOptionsWidget::onAccepted()
930 {
931 saveViewOptions();
932 }
933
onRejected()934 void ViewOptionsWidget::onRejected()
935 {
936 loadViewOptions();
937 }
938
CoreOptionsDialog(QWidget * parent)939 CoreOptionsDialog::CoreOptionsDialog(QWidget *parent) :
940 QDialog(parent)
941 ,m_layout()
942 ,m_scrollArea()
943 {
944 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CORE_OPTIONS));
945 setObjectName("coreOptionsDialog");
946
947 resize(720, 480);
948
949 QTimer::singleShot(0, this, SLOT(clearLayout()));
950 }
951
~CoreOptionsDialog()952 CoreOptionsDialog::~CoreOptionsDialog()
953 {
954 }
955
resizeEvent(QResizeEvent * event)956 void CoreOptionsDialog::resizeEvent(QResizeEvent *event)
957 {
958 QDialog::resizeEvent(event);
959
960 if (!m_scrollArea)
961 return;
962
963 m_scrollArea->resize(event->size());
964
965 emit resized(event->size());
966 }
967
closeEvent(QCloseEvent * event)968 void CoreOptionsDialog::closeEvent(QCloseEvent *event)
969 {
970 QDialog::closeEvent(event);
971
972 emit closed();
973 }
974
paintEvent(QPaintEvent * event)975 void CoreOptionsDialog::paintEvent(QPaintEvent *event)
976 {
977 QStyleOption o;
978 QPainter p;
979 o.initFrom(this);
980 p.begin(this);
981 style()->drawPrimitive(
982 QStyle::PE_Widget, &o, &p, this);
983 p.end();
984
985 QDialog::paintEvent(event);
986 }
987
clearLayout()988 void CoreOptionsDialog::clearLayout()
989 {
990 QWidget *widget = NULL;
991
992 if (m_scrollArea)
993 {
994 foreach (QObject *obj, children())
995 {
996 obj->deleteLater();
997 }
998 }
999
1000 m_layout = new QVBoxLayout();
1001
1002 widget = new QWidget();
1003 widget->setLayout(m_layout);
1004 widget->setObjectName("coreOptionsWidget");
1005
1006 m_scrollArea = new QScrollArea();
1007
1008 m_scrollArea->setParent(this);
1009 m_scrollArea->setWidgetResizable(true);
1010 m_scrollArea->setWidget(widget);
1011 m_scrollArea->setObjectName("coreOptionsScrollArea");
1012 m_scrollArea->show();
1013 }
1014
reload()1015 void CoreOptionsDialog::reload()
1016 {
1017 buildLayout();
1018 }
1019
onSaveGameSpecificOptions()1020 void CoreOptionsDialog::onSaveGameSpecificOptions()
1021 {
1022 #ifdef HAVE_MENU
1023 bool refresh = false;
1024 #endif
1025
1026 if (!core_options_create_override(true))
1027 QMessageBox::critical(this, msg_hash_to_str(MSG_ERROR), msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE));
1028
1029 #ifdef HAVE_MENU
1030 menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
1031 menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1032 #endif
1033 }
1034
onSaveFolderSpecificOptions()1035 void CoreOptionsDialog::onSaveFolderSpecificOptions()
1036 {
1037 #ifdef HAVE_MENU
1038 bool refresh = false;
1039 #endif
1040
1041 if (!core_options_create_override(false))
1042 QMessageBox::critical(this, msg_hash_to_str(MSG_ERROR), msg_hash_to_str(MSG_ERROR_SAVING_CORE_OPTIONS_FILE));
1043
1044 #ifdef HAVE_MENU
1045 menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
1046 menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
1047 #endif
1048 }
1049
onCoreOptionComboBoxCurrentIndexChanged(int index)1050 void CoreOptionsDialog::onCoreOptionComboBoxCurrentIndexChanged(int index)
1051 {
1052 unsigned i, k;
1053 QString key, val;
1054 size_t opts = 0;
1055 QComboBox *combo_box = qobject_cast<QComboBox*>(sender());
1056
1057 if (!combo_box)
1058 return;
1059
1060 key = combo_box->itemData(index, Qt::UserRole).toString();
1061 val = combo_box->itemText(index);
1062
1063 if (rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL))
1064 {
1065 rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts);
1066
1067 if (opts)
1068 {
1069 core_option_manager_t *coreopts = NULL;
1070
1071 rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
1072
1073 if (coreopts)
1074 {
1075 for (i = 0; i < opts; i++)
1076 {
1077 QString optKey;
1078 struct core_option *option = static_cast<struct core_option*>(&coreopts->opts[i]);
1079
1080 if (!option)
1081 continue;
1082
1083 optKey = option->key;
1084
1085 if (key == optKey)
1086 {
1087 for (k = 0; k < option->vals->size; k++)
1088 {
1089 QString str = option->vals->elems[k].data;
1090
1091 if (!str.isEmpty() && str == val)
1092 core_option_manager_set_val(coreopts, i, k);
1093 }
1094 }
1095 }
1096 }
1097 }
1098 }
1099 }
1100
buildLayout()1101 void CoreOptionsDialog::buildLayout()
1102 {
1103 unsigned j, k;
1104 size_t opts = 0;
1105 QFormLayout *form = NULL;
1106 settings_t *settings = config_get_ptr();
1107 bool has_core_options = rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL);
1108
1109 clearLayout();
1110
1111 if (has_core_options)
1112 {
1113 rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts);
1114
1115 if (opts)
1116 {
1117 core_option_manager_t *coreopts = NULL;
1118
1119 form = new QFormLayout();
1120
1121 if (settings->bools.game_specific_options)
1122 {
1123 QString contentLabel;
1124 QString label;
1125 rarch_system_info_t *system = runloop_get_system_info();
1126
1127 /* TODO/FIXME - why have this check here? system is not used */
1128 if (system)
1129 contentLabel = QFileInfo(path_get(RARCH_PATH_BASENAME)).completeBaseName();
1130
1131 if (!contentLabel.isEmpty())
1132 {
1133 if (!rarch_ctl(RARCH_CTL_IS_GAME_OPTIONS_ACTIVE, NULL))
1134 label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE);
1135 else
1136 label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE);
1137
1138 if (!label.isEmpty())
1139 {
1140 QHBoxLayout *gameOptionsLayout = new QHBoxLayout();
1141 QPushButton *button = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SAVE), this);
1142
1143 connect(button, SIGNAL(clicked()), this, SLOT(onSaveGameSpecificOptions()));
1144
1145 gameOptionsLayout->addWidget(new QLabel(contentLabel, this));
1146 gameOptionsLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred));
1147 gameOptionsLayout->addWidget(button);
1148
1149 form->addRow(label, gameOptionsLayout);
1150 }
1151 }
1152 }
1153
1154 rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
1155
1156 if (coreopts)
1157 {
1158 QToolButton *resetAllButton = new QToolButton(this);
1159
1160 resetAllButton->setDefaultAction(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL), this));
1161 connect(resetAllButton, SIGNAL(clicked()), this, SLOT(onCoreOptionResetAllClicked()));
1162
1163 for (j = 0; j < opts; j++)
1164 {
1165 QString desc =
1166 core_option_manager_get_desc(coreopts, j);
1167 QString val =
1168 core_option_manager_get_val(coreopts, j);
1169 QComboBox *combo_box = NULL;
1170 QLabel *descLabel = NULL;
1171 QHBoxLayout *comboLayout = NULL;
1172 QToolButton *resetButton = NULL;
1173 struct core_option *option = NULL;
1174
1175 if (desc.isEmpty() || !coreopts->opts)
1176 continue;
1177
1178 option = static_cast<struct core_option*>(&coreopts->opts[j]);
1179
1180 if (!option->vals || option->vals->size == 0)
1181 continue;
1182
1183 comboLayout = new QHBoxLayout();
1184 descLabel = new QLabel(desc, this);
1185 combo_box = new QComboBox(this);
1186 combo_box->setObjectName("coreOptionComboBox");
1187 resetButton = new QToolButton(this);
1188 resetButton->setObjectName("resetButton");
1189 resetButton->setDefaultAction(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET), this));
1190 resetButton->setProperty("comboBox",
1191 QVariant::fromValue(combo_box));
1192
1193 connect(resetButton, SIGNAL(clicked()),
1194 this, SLOT(onCoreOptionResetClicked()));
1195
1196 if (!string_is_empty(option->info))
1197 {
1198 char *new_info;
1199 size_t new_info_len = strlen(option->info) + 1;
1200
1201 new_info = (char *)malloc(new_info_len);
1202 if (!new_info)
1203 return;
1204 new_info[0] = '\0';
1205
1206 word_wrap(new_info, new_info_len, option->info, 50, 100, 0);
1207 descLabel->setToolTip(new_info);
1208 combo_box->setToolTip(new_info);
1209 free(new_info);
1210 }
1211
1212 for (k = 0; k < option->vals->size; k++)
1213 combo_box->addItem(option->vals->elems[k].data, option->key);
1214
1215 combo_box->setCurrentText(val);
1216 combo_box->setProperty("default_index",
1217 static_cast<unsigned>(option->default_index));
1218
1219 /* Only connect the signal after setting the default item */
1220 connect(combo_box, SIGNAL(currentIndexChanged(int)),
1221 this,
1222 SLOT(onCoreOptionComboBoxCurrentIndexChanged(int)));
1223
1224 comboLayout->addWidget(combo_box);
1225 comboLayout->addWidget(resetButton);
1226
1227 form->addRow(descLabel, comboLayout);
1228 }
1229
1230 form->addRow(resetAllButton, new QWidget(this));
1231
1232 m_layout->addLayout(form);
1233 }
1234 }
1235 }
1236
1237 if (!opts)
1238 {
1239 QLabel *noParamsLabel = new QLabel(msg_hash_to_str(
1240 MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE), this);
1241 noParamsLabel->setAlignment(Qt::AlignCenter);
1242
1243 m_layout->addWidget(noParamsLabel);
1244 }
1245
1246 m_layout->addItem(new QSpacerItem(20, 20,
1247 QSizePolicy::Minimum, QSizePolicy::Expanding));
1248
1249 resize(width() + 1, height());
1250 show();
1251 resize(width() - 1, height());
1252 }
1253
onCoreOptionResetClicked()1254 void CoreOptionsDialog::onCoreOptionResetClicked()
1255 {
1256 bool ok = false;
1257 QToolButton *button = qobject_cast<QToolButton*>(sender());
1258 QComboBox *combo_box = NULL;
1259 int default_index = 0;
1260
1261 if (!button)
1262 return;
1263
1264 combo_box = qobject_cast<QComboBox*>(button->property("comboBox").value<QComboBox*>());
1265
1266 if (!combo_box)
1267 return;
1268
1269 default_index = combo_box->property("default_index").toInt(&ok);
1270
1271 if (!ok)
1272 return;
1273
1274 if (default_index >= 0 && default_index < combo_box->count())
1275 combo_box->setCurrentIndex(default_index);
1276 }
1277
onCoreOptionResetAllClicked()1278 void CoreOptionsDialog::onCoreOptionResetAllClicked()
1279 {
1280 int i;
1281 QList<QComboBox*> combo_boxes = findChildren<QComboBox*>("coreOptionComboBox");
1282
1283 for (i = 0; i < combo_boxes.count(); i++)
1284 {
1285 int default_index = 0;
1286 bool ok = false;
1287 QComboBox *combo_box = combo_boxes.at(i);
1288
1289 if (!combo_box)
1290 continue;
1291
1292 default_index = combo_box->property("default_index").toInt(&ok);
1293
1294 if (!ok)
1295 continue;
1296
1297 if (default_index >= 0 && default_index < combo_box->count())
1298 combo_box->setCurrentIndex(default_index);
1299 }
1300 }
1301
1302 #if defined(HAVE_MENU)
1303 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
1304 enum
1305 {
1306 QT_SHADER_PRESET_GLOBAL = 0,
1307 QT_SHADER_PRESET_CORE,
1308 QT_SHADER_PRESET_PARENT,
1309 QT_SHADER_PRESET_GAME,
1310 QT_SHADER_PRESET_NORMAL
1311 };
1312
ShaderPass(struct video_shader_pass * passToCopy)1313 ShaderPass::ShaderPass(struct video_shader_pass *passToCopy) :
1314 pass(NULL)
1315 {
1316 if (passToCopy)
1317 {
1318 pass = (struct video_shader_pass*)calloc(1, sizeof(*pass));
1319 memcpy(pass, passToCopy, sizeof(*pass));
1320 }
1321 }
1322
~ShaderPass()1323 ShaderPass::~ShaderPass()
1324 {
1325 if (pass)
1326 free(pass);
1327 }
1328
operator =(const ShaderPass & other)1329 ShaderPass& ShaderPass::operator=(const ShaderPass &other)
1330 {
1331 if (this != &other && other.pass)
1332 {
1333 pass = (struct video_shader_pass*)calloc(1, sizeof(*pass));
1334 memcpy(pass, other.pass, sizeof(*pass));
1335 }
1336
1337 return *this;
1338 }
1339
ShaderParamsDialog(QWidget * parent)1340 ShaderParamsDialog::ShaderParamsDialog(QWidget *parent) :
1341 QDialog(parent)
1342 ,m_layout()
1343 ,m_scrollArea()
1344 {
1345 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS));
1346 setObjectName("shaderParamsDialog");
1347
1348 resize(720, 480);
1349
1350 QTimer::singleShot(0, this, SLOT(clearLayout()));
1351 }
1352
~ShaderParamsDialog()1353 ShaderParamsDialog::~ShaderParamsDialog()
1354 {
1355 }
1356
resizeEvent(QResizeEvent * event)1357 void ShaderParamsDialog::resizeEvent(QResizeEvent *event)
1358 {
1359 QDialog::resizeEvent(event);
1360
1361 if (!m_scrollArea)
1362 return;
1363
1364 m_scrollArea->resize(event->size());
1365
1366 emit resized(event->size());
1367 }
1368
closeEvent(QCloseEvent * event)1369 void ShaderParamsDialog::closeEvent(QCloseEvent *event)
1370 {
1371 QDialog::closeEvent(event);
1372
1373 emit closed();
1374 }
1375
paintEvent(QPaintEvent * event)1376 void ShaderParamsDialog::paintEvent(QPaintEvent *event)
1377 {
1378 QStyleOption o;
1379 QPainter p;
1380 o.initFrom(this);
1381 p.begin(this);
1382 style()->drawPrimitive(
1383 QStyle::PE_Widget, &o, &p, this);
1384 p.end();
1385
1386 QDialog::paintEvent(event);
1387 }
1388
getFilterLabel(unsigned filter)1389 QString ShaderParamsDialog::getFilterLabel(unsigned filter)
1390 {
1391 QString filterString;
1392
1393 switch (filter)
1394 {
1395 case 0:
1396 filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE);
1397 break;
1398 case 1:
1399 filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LINEAR);
1400 break;
1401 case 2:
1402 filterString = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NEAREST);
1403 break;
1404 default:
1405 break;
1406 }
1407
1408 return filterString;
1409 }
1410
clearLayout()1411 void ShaderParamsDialog::clearLayout()
1412 {
1413 QWidget *widget = NULL;
1414
1415 if (m_scrollArea)
1416 {
1417 foreach (QObject *obj, children())
1418 delete obj;
1419 }
1420
1421 m_layout = new QVBoxLayout();
1422
1423 widget = new QWidget();
1424 widget->setLayout(m_layout);
1425 widget->setObjectName("shaderParamsWidget");
1426
1427 m_scrollArea = new QScrollArea();
1428
1429 m_scrollArea->setParent(this);
1430 m_scrollArea->setWidgetResizable(true);
1431 m_scrollArea->setWidget(widget);
1432 m_scrollArea->setObjectName("shaderParamsScrollArea");
1433 m_scrollArea->show();
1434 }
1435
getShaders(struct video_shader ** menu_shader,struct video_shader ** video_shader)1436 void ShaderParamsDialog::getShaders(struct video_shader **menu_shader, struct video_shader **video_shader)
1437 {
1438 video_shader_ctx_t shader_info = {0};
1439 struct video_shader *shader = menu_shader_get();
1440
1441 if (menu_shader)
1442 {
1443 if (shader)
1444 *menu_shader = shader;
1445 else
1446 *menu_shader = NULL;
1447 }
1448
1449 if (video_shader)
1450 {
1451 if (shader)
1452 *video_shader = shader_info.data;
1453 else
1454 *video_shader = NULL;
1455 }
1456
1457 if (video_shader)
1458 {
1459 if (!video_shader_driver_get_current_shader(&shader_info))
1460 {
1461 *video_shader = NULL;
1462 return;
1463 }
1464
1465 if (!shader_info.data || shader_info.data->num_parameters > GFX_MAX_PARAMETERS)
1466 {
1467 *video_shader = NULL;
1468 return;
1469 }
1470
1471 if (shader_info.data)
1472 *video_shader = shader_info.data;
1473 else
1474 *video_shader = NULL;
1475 }
1476 }
1477
onFilterComboBoxIndexChanged(int)1478 void ShaderParamsDialog::onFilterComboBoxIndexChanged(int)
1479 {
1480 QVariant passVariant;
1481 QComboBox *comboBox = qobject_cast<QComboBox*>(sender());
1482 int pass = 0;
1483 bool ok = false;
1484 struct video_shader *menu_shader = NULL;
1485 struct video_shader *video_shader = NULL;
1486
1487 getShaders(&menu_shader, &video_shader);
1488
1489 if (!comboBox)
1490 return;
1491
1492 passVariant = comboBox->property("pass");
1493
1494 if (!passVariant.isValid())
1495 return;
1496
1497 pass = passVariant.toInt(&ok);
1498
1499 if (!ok)
1500 return;
1501
1502 if ( menu_shader
1503 && (pass >= 0)
1504 && (pass < static_cast<int>(menu_shader->passes)))
1505 {
1506 QVariant data = comboBox->currentData();
1507
1508 if (data.isValid())
1509 {
1510 unsigned filter = data.toUInt(&ok);
1511
1512 if (ok)
1513 {
1514 if (menu_shader)
1515 menu_shader->pass[pass].filter = filter;
1516 if (video_shader)
1517 video_shader->pass[pass].filter = filter;
1518
1519 video_shader->modified = true;
1520
1521 command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
1522 }
1523 }
1524 }
1525 }
1526
onScaleComboBoxIndexChanged(int)1527 void ShaderParamsDialog::onScaleComboBoxIndexChanged(int)
1528 {
1529 QVariant passVariant;
1530 QComboBox *comboBox = qobject_cast<QComboBox*>(sender());
1531 int pass = 0;
1532 bool ok = false;
1533 struct video_shader *menu_shader = NULL;
1534 struct video_shader *video_shader = NULL;
1535
1536 getShaders(&menu_shader, &video_shader);
1537
1538 if (!comboBox)
1539 return;
1540
1541 passVariant = comboBox->property("pass");
1542
1543 if (!passVariant.isValid())
1544 return;
1545
1546 pass = passVariant.toInt(&ok);
1547
1548 if (!ok)
1549 return;
1550
1551 if (menu_shader && pass >= 0 && pass < static_cast<int>(menu_shader->passes))
1552 {
1553 QVariant data = comboBox->currentData();
1554
1555 if (data.isValid())
1556 {
1557 unsigned scale = data.toUInt(&ok);
1558
1559 if (ok)
1560 {
1561 if (menu_shader)
1562 {
1563 menu_shader->pass[pass].fbo.scale_x = scale;
1564 menu_shader->pass[pass].fbo.scale_y = scale;
1565 menu_shader->pass[pass].fbo.valid = scale;
1566 }
1567
1568 if (video_shader)
1569 {
1570 video_shader->pass[pass].fbo.scale_x = scale;
1571 video_shader->pass[pass].fbo.scale_y = scale;
1572 video_shader->pass[pass].fbo.valid = scale;
1573 }
1574
1575 video_shader->modified = true;
1576
1577 command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
1578 }
1579 }
1580 }
1581 }
1582
onShaderPassMoveDownClicked()1583 void ShaderParamsDialog::onShaderPassMoveDownClicked()
1584 {
1585 QVariant passVariant;
1586 bool ok = false;
1587 struct video_shader *menu_shader = NULL;
1588 struct video_shader *video_shader = NULL;
1589 QToolButton *button = qobject_cast<QToolButton*>(sender());
1590 int pass = 0;
1591
1592 getShaders(&menu_shader, &video_shader);
1593
1594 if (!button)
1595 return;
1596
1597 passVariant = button->property("pass");
1598
1599 if (!passVariant.isValid())
1600 return;
1601
1602 pass = passVariant.toInt(&ok);
1603
1604 if (!ok || pass < 0)
1605 return;
1606
1607 if (video_shader)
1608 {
1609 ShaderPass tempPass;
1610 int i;
1611
1612 if (pass >= static_cast<int>(video_shader->passes) - 1)
1613 return;
1614
1615 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
1616 {
1617 struct video_shader_parameter *param = &video_shader->parameters[i];
1618
1619 if (param->pass == pass)
1620 param->pass += 1;
1621 else if (param->pass == pass + 1)
1622 param->pass -= 1;
1623 }
1624
1625 tempPass = ShaderPass(&video_shader->pass[pass]);
1626 memcpy(&video_shader->pass[pass], &video_shader->pass[pass + 1], sizeof(struct video_shader_pass));
1627 memcpy(&video_shader->pass[pass + 1], tempPass.pass, sizeof(struct video_shader_pass));
1628 }
1629
1630 if (menu_shader)
1631 {
1632 ShaderPass tempPass;
1633 int i;
1634
1635 if (pass >= static_cast<int>(menu_shader->passes) - 1)
1636 return;
1637
1638 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
1639 {
1640 struct video_shader_parameter *param = &menu_shader->parameters[i];
1641
1642 if (param->pass == pass)
1643 param->pass += 1;
1644 else if (param->pass == pass + 1)
1645 param->pass -= 1;
1646 }
1647
1648 tempPass = ShaderPass(&menu_shader->pass[pass]);
1649 memcpy(&menu_shader->pass[pass], &menu_shader->pass[pass + 1], sizeof(struct video_shader_pass));
1650 memcpy(&menu_shader->pass[pass + 1], tempPass.pass, sizeof(struct video_shader_pass));
1651 }
1652
1653 menu_shader->modified = true;
1654
1655 reload();
1656 }
1657
onShaderPassMoveUpClicked()1658 void ShaderParamsDialog::onShaderPassMoveUpClicked()
1659 {
1660 QVariant passVariant;
1661 int pass = 0;
1662 bool ok = false;
1663 struct video_shader *menu_shader = NULL;
1664 struct video_shader *video_shader = NULL;
1665 QToolButton *button = qobject_cast<QToolButton*>(sender());
1666
1667 getShaders(&menu_shader, &video_shader);
1668
1669 if (!button)
1670 return;
1671
1672 passVariant = button->property("pass");
1673
1674 if (!passVariant.isValid())
1675 return;
1676
1677 pass = passVariant.toInt(&ok);
1678
1679 if (!ok || pass <= 0)
1680 return;
1681
1682 if (video_shader)
1683 {
1684 ShaderPass tempPass;
1685 int i;
1686
1687 if (pass > static_cast<int>(video_shader->passes) - 1)
1688 return;
1689
1690 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
1691 {
1692 struct video_shader_parameter *param = &video_shader->parameters[i];
1693
1694 if (param->pass == pass)
1695 param->pass -= 1;
1696 else if (param->pass == pass - 1)
1697 param->pass += 1;
1698 }
1699
1700 tempPass = ShaderPass(&video_shader->pass[pass - 1]);
1701 memcpy(&video_shader->pass[pass - 1], &video_shader->pass[pass], sizeof(struct video_shader_pass));
1702 memcpy(&video_shader->pass[pass], tempPass.pass, sizeof(struct video_shader_pass));
1703 }
1704
1705 if (menu_shader)
1706 {
1707 ShaderPass tempPass;
1708 int i;
1709
1710 if (pass > static_cast<int>(menu_shader->passes) - 1)
1711 return;
1712
1713 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
1714 {
1715 struct video_shader_parameter *param = &menu_shader->parameters[i];
1716
1717 if (param->pass == pass)
1718 param->pass -= 1;
1719 else if (param->pass == pass - 1)
1720 param->pass += 1;
1721 }
1722
1723 tempPass = ShaderPass(&menu_shader->pass[pass - 1]);
1724 memcpy(&menu_shader->pass[pass - 1], &menu_shader->pass[pass], sizeof(struct video_shader_pass));
1725 memcpy(&menu_shader->pass[pass], tempPass.pass, sizeof(struct video_shader_pass));
1726 }
1727
1728 menu_shader->modified = true;
1729
1730 reload();
1731 }
1732
onShaderLoadPresetClicked()1733 void ShaderParamsDialog::onShaderLoadPresetClicked()
1734 {
1735 QString path, filter;
1736 QByteArray pathArray;
1737 struct video_shader *menu_shader = NULL;
1738 struct video_shader *video_shader = NULL;
1739 const char *pathData = NULL;
1740 enum rarch_shader_type type = RARCH_SHADER_NONE;
1741 #if !defined(HAVE_MENU)
1742 settings_t *settings = config_get_ptr();
1743 const char *shader_preset_dir = settings->paths.directory_video_shader;
1744 #else
1745 const char *shader_preset_dir = NULL;
1746
1747 menu_driver_get_last_shader_preset_path(&shader_preset_dir, NULL);
1748 #endif
1749
1750 getShaders(&menu_shader, &video_shader);
1751
1752 if (!menu_shader)
1753 return;
1754
1755 filter.append("Shader Preset (");
1756
1757 /* NOTE: Maybe we should have a way to get a list
1758 * of all shader types instead of hard-coding this? */
1759 if (video_shader_is_supported(RARCH_SHADER_CG))
1760 {
1761 filter.append(QLatin1Literal(" *"));
1762 filter.append(".cgp");
1763 }
1764
1765 if (video_shader_is_supported(RARCH_SHADER_GLSL))
1766 {
1767 filter.append(QLatin1Literal(" *"));
1768 filter.append(".glslp");
1769 }
1770
1771 if (video_shader_is_supported(RARCH_SHADER_SLANG))
1772 {
1773 filter.append(QLatin1Literal(" *"));
1774 filter.append(".slangp");
1775 }
1776
1777 filter.append(")");
1778 path = QFileDialog::getOpenFileName(
1779 this,
1780 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET),
1781 shader_preset_dir, filter);
1782
1783 if (path.isEmpty())
1784 return;
1785
1786 pathArray = path.toUtf8();
1787 pathData = pathArray.constData();
1788 type = video_shader_parse_type(pathData);
1789
1790 #if defined(HAVE_MENU)
1791 /* Cache selected shader parent directory */
1792 menu_driver_set_last_shader_preset_path(pathData);
1793 #endif
1794
1795 menu_shader_manager_set_preset(menu_shader, type, pathData, true);
1796 }
1797
onShaderResetPass(int pass)1798 void ShaderParamsDialog::onShaderResetPass(int pass)
1799 {
1800 unsigned i;
1801 struct video_shader *menu_shader = NULL;
1802 struct video_shader *video_shader = NULL;
1803
1804 getShaders(&menu_shader, &video_shader);
1805
1806 if (menu_shader)
1807 {
1808 for (i = 0; i < menu_shader->num_parameters; i++)
1809 {
1810 struct video_shader_parameter *param = &menu_shader->parameters[i];
1811
1812 /* if pass < 0, reset all params,
1813 * otherwise only reset the selected pass */
1814 if (pass >= 0 && param->pass != pass)
1815 continue;
1816
1817 param->current = param->initial;
1818 }
1819 }
1820
1821 if (video_shader)
1822 {
1823 for (i = 0; i < video_shader->num_parameters; i++)
1824 {
1825 struct video_shader_parameter *param = &video_shader->parameters[i];
1826
1827 /* if pass < 0, reset all params,
1828 * otherwise only reset the selected pass */
1829 if (pass >= 0 && param->pass != pass)
1830 continue;
1831
1832 param->current = param->initial;
1833 }
1834
1835 video_shader->modified = true;
1836 }
1837
1838 reload();
1839 }
1840
onShaderResetParameter(QString parameter)1841 void ShaderParamsDialog::onShaderResetParameter(QString parameter)
1842 {
1843 struct video_shader *menu_shader = NULL;
1844 struct video_shader *video_shader = NULL;
1845
1846 getShaders(&menu_shader, &video_shader);
1847
1848 if (menu_shader)
1849 {
1850 int i;
1851 struct video_shader_parameter *param = NULL;
1852
1853 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
1854 {
1855 QString id = menu_shader->parameters[i].id;
1856
1857 if (id == parameter)
1858 param = &menu_shader->parameters[i];
1859 }
1860
1861 if (param)
1862 param->current = param->initial;
1863 }
1864
1865 if (video_shader)
1866 {
1867 int i;
1868 struct video_shader_parameter *param = NULL;
1869
1870 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
1871 {
1872 QString id = video_shader->parameters[i].id;
1873
1874 if (id == parameter)
1875 param = &video_shader->parameters[i];
1876 }
1877
1878 if (param)
1879 param->current = param->initial;
1880
1881 video_shader->modified = true;
1882 }
1883
1884 reload();
1885 }
1886
onShaderResetAllPasses()1887 void ShaderParamsDialog::onShaderResetAllPasses()
1888 {
1889 onShaderResetPass(-1);
1890 }
1891
onShaderAddPassClicked()1892 void ShaderParamsDialog::onShaderAddPassClicked()
1893 {
1894 QString path, filter;
1895 QByteArray pathArray;
1896 struct video_shader *menu_shader = NULL;
1897 struct video_shader *video_shader = NULL;
1898 struct video_shader_pass *shader_pass = NULL;
1899 const char *pathData = NULL;
1900 #if !defined(HAVE_MENU)
1901 settings_t *settings = config_get_ptr();
1902 const char *shader_pass_dir = settings->paths.directory_video_shader;
1903 #else
1904 const char *shader_pass_dir = NULL;
1905
1906 menu_driver_get_last_shader_pass_path(&shader_pass_dir, NULL);
1907 #endif
1908
1909 getShaders(&menu_shader, &video_shader);
1910
1911 if (!menu_shader)
1912 return;
1913
1914 filter.append("Shader (");
1915
1916 /* NOTE: Maybe we should have a way to get a list
1917 * of all shader types instead of hard-coding this? */
1918 if (video_shader_is_supported(RARCH_SHADER_CG))
1919 filter.append(QLatin1Literal(" *.cg"));
1920
1921 if (video_shader_is_supported(RARCH_SHADER_GLSL))
1922 filter.append(QLatin1Literal(" *.glsl"));
1923
1924 if (video_shader_is_supported(RARCH_SHADER_SLANG))
1925 filter.append(QLatin1Literal(" *.slang"));
1926
1927 filter.append(")");
1928
1929 path = QFileDialog::getOpenFileName(
1930 this,
1931 msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET),
1932 shader_pass_dir, filter);
1933
1934 if (path.isEmpty())
1935 return;
1936
1937 /* Qt uses '/' as a directory separator regardless
1938 * of host platform. Have to convert to native separators,
1939 * or video_shader_resolve_parameters() will fail on
1940 * non-Linux platforms */
1941 path = QDir::toNativeSeparators(path);
1942
1943 pathArray = path.toUtf8();
1944 pathData = pathArray.constData();
1945
1946 if (menu_shader->passes < GFX_MAX_SHADERS)
1947 menu_shader->passes++;
1948 else
1949 return;
1950
1951 menu_shader->modified = true;
1952 shader_pass = &menu_shader->pass[menu_shader->passes - 1];
1953
1954 if (!shader_pass)
1955 return;
1956
1957 strlcpy(shader_pass->source.path,
1958 pathData,
1959 sizeof(shader_pass->source.path));
1960
1961 #if defined(HAVE_MENU)
1962 /* Cache selected shader parent directory */
1963 menu_driver_set_last_shader_pass_path(pathData);
1964 #endif
1965
1966 video_shader_resolve_parameters(menu_shader);
1967
1968 command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
1969 }
1970
onShaderSavePresetAsClicked()1971 void ShaderParamsDialog::onShaderSavePresetAsClicked()
1972 {
1973 QByteArray pathArray;
1974 const char *pathData = NULL;
1975 settings_t *settings = config_get_ptr();
1976 const char *path_dir_video_shader = settings->paths.directory_video_shader;
1977 QString path = QFileDialog::getSaveFileName(this, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS), path_dir_video_shader);
1978
1979 if (path.isEmpty())
1980 return;
1981
1982 pathArray = path.toUtf8();
1983 pathData = pathArray.constData();
1984
1985 operateShaderPreset(true, pathData, QT_SHADER_PRESET_NORMAL);
1986 }
1987
1988 /** save or remove shader preset */
operateShaderPreset(bool save,const char * path,unsigned action_type)1989 void ShaderParamsDialog::operateShaderPreset(bool save, const char *path, unsigned action_type)
1990 {
1991 bool ret;
1992 enum auto_shader_type preset_type;
1993 settings_t *settings = config_get_ptr();
1994 const char *path_dir_video_shader = settings->paths.directory_video_shader;
1995 const char *path_dir_menu_config = settings->paths.directory_menu_config;
1996
1997 switch (action_type)
1998 {
1999 case QT_SHADER_PRESET_GLOBAL:
2000 preset_type = SHADER_PRESET_GLOBAL;
2001 break;
2002 case QT_SHADER_PRESET_CORE:
2003 preset_type = SHADER_PRESET_CORE;
2004 break;
2005 case QT_SHADER_PRESET_PARENT:
2006 preset_type = SHADER_PRESET_PARENT;
2007 break;
2008 case QT_SHADER_PRESET_GAME:
2009 preset_type = SHADER_PRESET_GAME;
2010 break;
2011 case QT_SHADER_PRESET_NORMAL:
2012 break;
2013 default:
2014 return;
2015 }
2016
2017 if (save)
2018 {
2019 if (action_type == QT_SHADER_PRESET_NORMAL)
2020 ret = menu_shader_manager_save_preset(
2021 menu_shader_get(),
2022 path,
2023 path_dir_video_shader,
2024 path_dir_menu_config,
2025 true);
2026 else
2027 ret = menu_shader_manager_save_auto_preset(
2028 menu_shader_get(),
2029 preset_type,
2030 path_dir_video_shader,
2031 path_dir_menu_config,
2032 true);
2033
2034 if (ret)
2035 runloop_msg_queue_push(
2036 msg_hash_to_str(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY),
2037 1, 100, true, NULL,
2038 MESSAGE_QUEUE_ICON_DEFAULT,
2039 MESSAGE_QUEUE_CATEGORY_INFO
2040 );
2041 else
2042 runloop_msg_queue_push(
2043 msg_hash_to_str(MSG_ERROR_SAVING_SHADER_PRESET),
2044 1, 100, true, NULL,
2045 MESSAGE_QUEUE_ICON_DEFAULT,
2046 MESSAGE_QUEUE_CATEGORY_ERROR
2047 );
2048 }
2049 else
2050 {
2051 if (action_type != QT_SHADER_PRESET_NORMAL &&
2052 menu_shader_manager_remove_auto_preset(preset_type,
2053 path_dir_video_shader,
2054 path_dir_menu_config))
2055 {
2056 #ifdef HAVE_MENU
2057 bool refresh = false;
2058 #endif
2059
2060 runloop_msg_queue_push(
2061 msg_hash_to_str(MSG_SHADER_PRESET_REMOVED_SUCCESSFULLY),
2062 1, 100, true, NULL,
2063 MESSAGE_QUEUE_ICON_DEFAULT,
2064 MESSAGE_QUEUE_CATEGORY_INFO
2065 );
2066
2067 #ifdef HAVE_MENU
2068 menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
2069 #endif
2070 }
2071 else
2072 runloop_msg_queue_push(
2073 msg_hash_to_str(MSG_ERROR_REMOVING_SHADER_PRESET),
2074 1, 100, true, NULL,
2075 MESSAGE_QUEUE_ICON_DEFAULT,
2076 MESSAGE_QUEUE_CATEGORY_ERROR
2077 );
2078 }
2079 }
2080
onShaderSaveGlobalPresetClicked()2081 void ShaderParamsDialog::onShaderSaveGlobalPresetClicked()
2082 {
2083 operateShaderPreset(true, NULL, QT_SHADER_PRESET_GLOBAL);
2084 }
2085
onShaderSaveCorePresetClicked()2086 void ShaderParamsDialog::onShaderSaveCorePresetClicked()
2087 {
2088 operateShaderPreset(true, NULL, QT_SHADER_PRESET_CORE);
2089 }
2090
onShaderSaveParentPresetClicked()2091 void ShaderParamsDialog::onShaderSaveParentPresetClicked()
2092 {
2093 operateShaderPreset(true, NULL, QT_SHADER_PRESET_PARENT);
2094 }
2095
onShaderSaveGamePresetClicked()2096 void ShaderParamsDialog::onShaderSaveGamePresetClicked()
2097 {
2098 operateShaderPreset(true, NULL, QT_SHADER_PRESET_GAME);
2099 }
2100
onShaderRemoveGlobalPresetClicked()2101 void ShaderParamsDialog::onShaderRemoveGlobalPresetClicked()
2102 {
2103 operateShaderPreset(false, NULL, QT_SHADER_PRESET_GLOBAL);
2104 }
2105
onShaderRemoveCorePresetClicked()2106 void ShaderParamsDialog::onShaderRemoveCorePresetClicked()
2107 {
2108 operateShaderPreset(false, NULL, QT_SHADER_PRESET_CORE);
2109 }
2110
onShaderRemoveParentPresetClicked()2111 void ShaderParamsDialog::onShaderRemoveParentPresetClicked()
2112 {
2113 operateShaderPreset(false, NULL, QT_SHADER_PRESET_PARENT);
2114 }
2115
onShaderRemoveGamePresetClicked()2116 void ShaderParamsDialog::onShaderRemoveGamePresetClicked()
2117 {
2118 operateShaderPreset(false, NULL, QT_SHADER_PRESET_GAME);
2119 }
2120
onShaderRemoveAllPassesClicked()2121 void ShaderParamsDialog::onShaderRemoveAllPassesClicked()
2122 {
2123 struct video_shader *menu_shader = NULL;
2124 struct video_shader *video_shader = NULL;
2125
2126 getShaders(&menu_shader, &video_shader);
2127
2128 if (!menu_shader)
2129 return;
2130
2131 menu_shader->passes = 0;
2132 menu_shader->modified = true;
2133
2134 onShaderApplyClicked();
2135 }
2136
onShaderRemovePassClicked()2137 void ShaderParamsDialog::onShaderRemovePassClicked()
2138 {
2139 QVariant passVariant;
2140 QAction *action = qobject_cast<QAction*>(sender());
2141 int pass = 0;
2142 bool ok = false;
2143
2144 if (!action)
2145 return;
2146 passVariant = action->data();
2147
2148 if (!passVariant.isValid())
2149 return;
2150
2151 pass = passVariant.toInt(&ok);
2152
2153 if (!ok)
2154 return;
2155
2156 onShaderRemovePass(pass);
2157 }
2158
onShaderRemovePass(int pass)2159 void ShaderParamsDialog::onShaderRemovePass(int pass)
2160 {
2161 int i;
2162 struct video_shader *menu_shader = NULL;
2163 struct video_shader *video_shader = NULL;
2164
2165 getShaders(&menu_shader, &video_shader);
2166
2167 if (!menu_shader || menu_shader->passes == 0)
2168 return;
2169
2170 if (pass < 0 || pass > static_cast<int>(menu_shader->passes))
2171 return;
2172
2173 /* move selected pass to the bottom */
2174 for (i = pass; i < static_cast<int>(menu_shader->passes) - 1; i++)
2175 std::swap(menu_shader->pass[i], menu_shader->pass[i + 1]);
2176
2177 menu_shader->passes--;
2178
2179 menu_shader->modified = true;
2180
2181 onShaderApplyClicked();
2182 }
2183
onShaderApplyClicked()2184 void ShaderParamsDialog::onShaderApplyClicked()
2185 {
2186 command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
2187 }
2188
updateRemovePresetButtonsState()2189 void ShaderParamsDialog::updateRemovePresetButtonsState()
2190 {
2191 settings_t *settings = config_get_ptr();
2192 const char *path_dir_video_shader = settings->paths.directory_video_shader;
2193 const char *path_dir_menu_config = settings->paths.directory_menu_config;
2194
2195 if (removeGlobalPresetAction)
2196 removeGlobalPresetAction->setEnabled(
2197 menu_shader_manager_auto_preset_exists(
2198 SHADER_PRESET_GLOBAL,
2199 path_dir_video_shader,
2200 path_dir_menu_config
2201 ));
2202 if (removeCorePresetAction)
2203 removeCorePresetAction->setEnabled(
2204 menu_shader_manager_auto_preset_exists(
2205 SHADER_PRESET_CORE,
2206 path_dir_video_shader,
2207 path_dir_menu_config
2208 ));
2209 if (removeParentPresetAction)
2210 removeParentPresetAction->setEnabled(
2211 menu_shader_manager_auto_preset_exists(
2212 SHADER_PRESET_PARENT,
2213 path_dir_video_shader,
2214 path_dir_menu_config
2215 ));
2216 if (removeGamePresetAction)
2217 removeGamePresetAction->setEnabled(
2218 menu_shader_manager_auto_preset_exists(
2219 SHADER_PRESET_GAME,
2220 path_dir_video_shader,
2221 path_dir_menu_config
2222 ));
2223 }
2224
reload()2225 void ShaderParamsDialog::reload()
2226 {
2227 buildLayout();
2228 }
2229
buildLayout()2230 void ShaderParamsDialog::buildLayout()
2231 {
2232 unsigned i;
2233 bool hasPasses = false;
2234 #if defined(HAVE_MENU)
2235 CheckableSettingsGroup *topSettingsGroup = NULL;
2236 #endif
2237 QPushButton *loadButton = NULL;
2238 QPushButton *saveButton = NULL;
2239 QPushButton *removeButton = NULL;
2240 QPushButton *removePassButton = NULL;
2241 QPushButton *applyButton = NULL;
2242 QHBoxLayout *topButtonLayout = NULL;
2243 QMenu *loadMenu = NULL;
2244 QMenu *saveMenu = NULL;
2245 QMenu *removeMenu = NULL;
2246 QMenu *removePassMenu = NULL;
2247 struct video_shader *menu_shader = NULL;
2248 struct video_shader *video_shader = NULL;
2249 struct video_shader *avail_shader = NULL;
2250 const char *shader_path = NULL;
2251
2252 getShaders(&menu_shader, &video_shader);
2253
2254 /* NOTE: For some reason, menu_shader_get() returns a COPY
2255 * of what get_current_shader() gives us.
2256 * And if you want to be able to change shader settings/parameters
2257 * from both the raster menu and
2258 * Qt at the same time... you must change BOTH or one will
2259 * overwrite the other.
2260 *
2261 * AND, during a context reset, video_shader will be NULL
2262 * but not menu_shader, so don't totally bail
2263 * just because video_shader is NULL.
2264 *
2265 * Someone please fix this mess.
2266 */
2267
2268 if (video_shader)
2269 {
2270 avail_shader = video_shader;
2271
2272 if (video_shader->passes == 0)
2273 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS));
2274 }
2275 /* Normally we'd only use video_shader,
2276 * but the Vulkan driver returns a NULL shader when there
2277 * are zero passes, so just fall back to menu_shader.
2278 */
2279 else if (menu_shader)
2280 {
2281 avail_shader = menu_shader;
2282
2283 if (menu_shader->passes == 0)
2284 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS));
2285 }
2286 else
2287 {
2288 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS));
2289
2290 /* no shader is available yet, just keep retrying until it is */
2291 QTimer::singleShot(0, this, SLOT(buildLayout()));
2292 return;
2293 }
2294
2295 clearLayout();
2296
2297 /* Only check video_shader for the path, menu_shader seems stale...
2298 * e.g. if you remove all the shader passes,
2299 * it still has the old path in it, but video_shader does not
2300 */
2301 if (video_shader)
2302 {
2303 if (!string_is_empty(video_shader->path))
2304 {
2305 shader_path = video_shader->path;
2306 setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName());
2307 }
2308 }
2309 else if (menu_shader)
2310 {
2311 if (!string_is_empty(menu_shader->path))
2312 {
2313 shader_path = menu_shader->path;
2314 setWindowTitle(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_CURRENT_SHADER)) + ": " + QFileInfo(shader_path).fileName());
2315 }
2316 }
2317 else
2318 setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS));
2319
2320 loadButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_LOAD), this);
2321 saveButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SAVE), this);
2322 removeButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_REMOVE), this);
2323 removePassButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_REMOVE_PASSES), this);
2324 applyButton = new QPushButton(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_APPLY), this);
2325
2326 loadMenu = new QMenu(loadButton);
2327
2328 loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET), this, SLOT(onShaderLoadPresetClicked()));
2329 loadMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_ADD_PASS), this, SLOT(onShaderAddPassClicked()));
2330
2331 loadButton->setMenu(loadMenu);
2332
2333 saveMenu = new QMenu(saveButton);
2334 saveMenu->addAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS)) + "...", this, SLOT(onShaderSavePresetAsClicked()));
2335 saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GLOBAL), this, SLOT(onShaderSaveGlobalPresetClicked()));
2336 saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE), this, SLOT(onShaderSaveCorePresetClicked()));
2337 saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT), this, SLOT(onShaderSaveParentPresetClicked()));
2338 saveMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME), this, SLOT(onShaderSaveGamePresetClicked()));
2339
2340 saveButton->setMenu(saveMenu);
2341
2342 removeMenu = new QMenu(removeButton);
2343 removeGlobalPresetAction = removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GLOBAL), this, SLOT(onShaderRemoveGlobalPresetClicked()));
2344 removeCorePresetAction = removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_CORE), this, SLOT(onShaderRemoveCorePresetClicked()));
2345 removeParentPresetAction = removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_PARENT), this, SLOT(onShaderRemoveParentPresetClicked()));
2346 removeGamePresetAction = removeMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GAME), this, SLOT(onShaderRemoveGamePresetClicked()));
2347
2348 removeButton->setMenu(removeMenu);
2349
2350 connect(removeMenu, SIGNAL(aboutToShow()), this, SLOT(updateRemovePresetButtonsState()));
2351
2352 removePassMenu = new QMenu(removeButton);
2353
2354 /* When there are no passes, at least on first startup, it seems video_shader erroneously shows 1 pass, with an empty source file.
2355 * So we use menu_shader instead for that.
2356 */
2357 if (menu_shader)
2358 {
2359 for (i = 0; i < menu_shader->passes; i++)
2360 {
2361 QFileInfo fileInfo(menu_shader->pass[i].source.path);
2362 QString shaderBasename = fileInfo.completeBaseName();
2363 QAction *action = removePassMenu->addAction(shaderBasename, this, SLOT(onShaderRemovePassClicked()));
2364
2365 action->setData(i);
2366 }
2367 }
2368
2369 removePassMenu->addAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_CLEAR_ALL_PASSES), this, SLOT(onShaderRemoveAllPassesClicked()));
2370
2371 removePassButton->setMenu(removePassMenu);
2372
2373 connect(applyButton, SIGNAL(clicked()), this, SLOT(onShaderApplyClicked()));
2374
2375 #if defined(HAVE_MENU)
2376 topSettingsGroup = new CheckableSettingsGroup(MENU_ENUM_LABEL_VIDEO_SHADERS_ENABLE);
2377 topSettingsGroup->add(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE);
2378 topSettingsGroup->add(MENU_ENUM_LABEL_SHADER_WATCH_FOR_CHANGES);
2379 topSettingsGroup->add(MENU_ENUM_LABEL_VIDEO_SHADER_REMEMBER_LAST_DIR);
2380 #endif
2381
2382 topButtonLayout = new QHBoxLayout();
2383 topButtonLayout->addWidget(loadButton);
2384 topButtonLayout->addWidget(saveButton);
2385 topButtonLayout->addWidget(removeButton);
2386 topButtonLayout->addWidget(removePassButton);
2387 topButtonLayout->addWidget(applyButton);
2388
2389 #if defined(HAVE_MENU)
2390 m_layout->addWidget(topSettingsGroup);
2391 #endif
2392 m_layout->addLayout(topButtonLayout);
2393
2394 /* NOTE: We assume that parameters are always grouped in order by the pass number, e.g., all parameters for pass 0 come first, then params for pass 1, etc. */
2395 for (i = 0; avail_shader && i < avail_shader->passes; i++)
2396 {
2397 QFormLayout *form = NULL;
2398 QGroupBox *groupBox = NULL;
2399 QFileInfo fileInfo(avail_shader->pass[i].source.path);
2400 QString shaderBasename = fileInfo.completeBaseName();
2401 QHBoxLayout *filterScaleHBoxLayout = NULL;
2402 QComboBox *filterComboBox = new QComboBox(this);
2403 QComboBox *scaleComboBox = new QComboBox(this);
2404 QToolButton *moveDownButton = NULL;
2405 QToolButton *moveUpButton = NULL;
2406 unsigned j = 0;
2407
2408 /* Sometimes video_shader shows 1 pass with no source file, when there are really 0 passes. */
2409 if (shaderBasename.isEmpty())
2410 continue;
2411
2412 hasPasses = true;
2413
2414 filterComboBox->setProperty("pass", i);
2415 scaleComboBox->setProperty("pass", i);
2416
2417 moveDownButton = new QToolButton(this);
2418 moveDownButton->setText("↓");
2419 moveDownButton->setProperty("pass", i);
2420
2421 moveUpButton = new QToolButton(this);
2422 moveUpButton->setText("↑");
2423 moveUpButton->setProperty("pass", i);
2424
2425 /* Can't move down if we're already at the bottom. */
2426 if (i < avail_shader->passes - 1)
2427 connect(moveDownButton, SIGNAL(clicked()),
2428 this, SLOT(onShaderPassMoveDownClicked()));
2429 else
2430 moveDownButton->setDisabled(true);
2431
2432 /* Can't move up if we're already at the top. */
2433 if (i > 0)
2434 connect(moveUpButton, SIGNAL(clicked()),
2435 this, SLOT(onShaderPassMoveUpClicked()));
2436 else
2437 moveUpButton->setDisabled(true);
2438
2439 for (;;)
2440 {
2441 QString filterLabel = getFilterLabel(j);
2442
2443 if (filterLabel.isEmpty())
2444 break;
2445
2446 if (j == 0)
2447 filterLabel = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE);
2448
2449 filterComboBox->addItem(filterLabel, j);
2450
2451 j++;
2452 }
2453
2454 for (j = 0; j < 7; j++)
2455 {
2456 QString label;
2457
2458 if (j == 0)
2459 label = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE);
2460 else
2461 label = QString::number(j) + "x";
2462
2463 scaleComboBox->addItem(label, j);
2464 }
2465
2466 filterComboBox->setCurrentIndex(static_cast<int>(avail_shader->pass[i].filter));
2467 scaleComboBox->setCurrentIndex(static_cast<int>(avail_shader->pass[i].fbo.scale_x));
2468
2469 /* connect the signals only after the initial index is set */
2470 connect(filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onFilterComboBoxIndexChanged(int)));
2471 connect(scaleComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onScaleComboBoxIndexChanged(int)));
2472
2473 form = new QFormLayout();
2474 groupBox = new QGroupBox(shaderBasename);
2475 groupBox->setLayout(form);
2476 groupBox->setProperty("pass", i);
2477 groupBox->setContextMenuPolicy(Qt::CustomContextMenu);
2478
2479 connect(groupBox, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onGroupBoxContextMenuRequested(const QPoint&)));
2480
2481 m_layout->addWidget(groupBox);
2482
2483 filterScaleHBoxLayout = new QHBoxLayout();
2484 filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Preferred));
2485 filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER)) + ":", this));
2486 filterScaleHBoxLayout->addWidget(filterComboBox);
2487 filterScaleHBoxLayout->addWidget(new QLabel(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE)) + ":", this));
2488 filterScaleHBoxLayout->addWidget(scaleComboBox);
2489 filterScaleHBoxLayout->addSpacerItem(new QSpacerItem(20, 0, QSizePolicy::Preferred, QSizePolicy::Preferred));
2490
2491 if (moveUpButton)
2492 filterScaleHBoxLayout->addWidget(moveUpButton);
2493
2494 if (moveDownButton)
2495 filterScaleHBoxLayout->addWidget(moveDownButton);
2496
2497 form->addRow("", filterScaleHBoxLayout);
2498
2499 for (j = 0; j < avail_shader->num_parameters; j++)
2500 {
2501 struct video_shader_parameter *param = &avail_shader->parameters[j];
2502
2503 if (param->pass != static_cast<int>(i))
2504 continue;
2505
2506 addShaderParam(param, form);
2507 }
2508 }
2509
2510 if (!hasPasses)
2511 {
2512 QLabel *noParamsLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_SHADER_NO_PASSES), this);
2513 noParamsLabel->setAlignment(Qt::AlignCenter);
2514
2515 m_layout->addWidget(noParamsLabel);
2516 }
2517
2518 m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
2519
2520 /* Why is this required?? The layout is corrupt without both resizes. */
2521 resize(width() + 1, height());
2522 show();
2523 resize(width() - 1, height());
2524 }
2525
onParameterLabelContextMenuRequested(const QPoint &)2526 void ShaderParamsDialog::onParameterLabelContextMenuRequested(const QPoint&)
2527 {
2528 QVariant paramVariant;
2529 QString parameter;
2530 QPointer<QAction> action;
2531 QList<QAction*> actions;
2532 QScopedPointer<QAction> resetParamAction;
2533 QLabel *label = qobject_cast<QLabel*>(sender());
2534
2535 if (!label)
2536 return;
2537
2538 paramVariant = label->property("parameter");
2539
2540 if (!paramVariant.isValid())
2541 return;
2542
2543 parameter = paramVariant.toString();
2544
2545 resetParamAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_PARAMETER), 0));
2546
2547 actions.append(resetParamAction.data());
2548
2549 action = QMenu::exec(actions, QCursor::pos(), NULL, label);
2550
2551 if (!action)
2552 return;
2553
2554 if (action == resetParamAction.data())
2555 onShaderResetParameter(parameter);
2556 }
2557
onGroupBoxContextMenuRequested(const QPoint &)2558 void ShaderParamsDialog::onGroupBoxContextMenuRequested(const QPoint&)
2559 {
2560 QPointer<QAction> action;
2561 QList<QAction*> actions;
2562 QScopedPointer<QAction> resetPassAction;
2563 QScopedPointer<QAction> resetAllPassesAction;
2564 QVariant passVariant;
2565 int pass = 0;
2566 bool ok = false;
2567 QGroupBox *groupBox = qobject_cast<QGroupBox*>(sender());
2568
2569 if (!groupBox)
2570 return;
2571
2572 passVariant = groupBox->property("pass");
2573
2574 if (!passVariant.isValid())
2575 return;
2576
2577 pass = passVariant.toInt(&ok);
2578
2579 if (!ok)
2580 return;
2581
2582 resetPassAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_PASS), 0));
2583 resetAllPassesAction.reset(new QAction(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_RESET_ALL_PASSES), 0));
2584
2585 actions.append(resetPassAction.data());
2586 actions.append(resetAllPassesAction.data());
2587
2588 action = QMenu::exec(actions, QCursor::pos(), NULL, groupBox);
2589
2590 if (!action)
2591 return;
2592
2593 if (action == resetPassAction.data())
2594 onShaderResetPass(pass);
2595 else if (action == resetAllPassesAction.data())
2596 onShaderResetAllPasses();
2597 }
2598
addShaderParam(struct video_shader_parameter * param,QFormLayout * form)2599 void ShaderParamsDialog::addShaderParam(struct video_shader_parameter *param, QFormLayout *form)
2600 {
2601 QString desc = param->desc;
2602 QString parameter = param->id;
2603 QLabel *label = new QLabel(desc);
2604
2605 label->setProperty("parameter", parameter);
2606 label->setContextMenuPolicy(Qt::CustomContextMenu);
2607
2608 connect(label, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onParameterLabelContextMenuRequested(const QPoint&)));
2609
2610 if ((param->minimum == 0.0)
2611 && (param->maximum
2612 == (param->minimum
2613 + param->step)))
2614 {
2615 /* option is basically a bool, so use a checkbox */
2616 QCheckBox *checkBox = new QCheckBox(this);
2617 checkBox->setChecked(param->current == param->maximum ? true : false);
2618 checkBox->setProperty("param", parameter);
2619
2620 connect(checkBox, SIGNAL(clicked()), this, SLOT(onShaderParamCheckBoxClicked()));
2621
2622 form->addRow(label, checkBox);
2623 }
2624 else
2625 {
2626 QDoubleSpinBox *doubleSpinBox = NULL;
2627 QSpinBox *spinBox = NULL;
2628 QHBoxLayout *box = new QHBoxLayout();
2629 QSlider *slider = new QSlider(Qt::Horizontal, this);
2630 double value = MainWindow::lerp(
2631 param->minimum, param->maximum, 0, 100, param->current);
2632 double intpart = 0;
2633 bool stepIsFractional = modf(param->step, &intpart);
2634
2635 slider->setRange(0, 100);
2636 slider->setSingleStep(1);
2637 slider->setValue(value);
2638 slider->setProperty("param", parameter);
2639
2640 connect(slider, SIGNAL(valueChanged(int)),
2641 this, SLOT(onShaderParamSliderValueChanged(int)));
2642
2643 box->addWidget(slider);
2644
2645 if (stepIsFractional)
2646 {
2647 doubleSpinBox = new QDoubleSpinBox(this);
2648 doubleSpinBox->setRange(param->minimum, param->maximum);
2649 doubleSpinBox->setSingleStep(param->step);
2650 doubleSpinBox->setValue(param->current);
2651 doubleSpinBox->setProperty("slider", QVariant::fromValue(slider));
2652 slider->setProperty("doubleSpinBox", QVariant::fromValue(doubleSpinBox));
2653
2654 connect(doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onShaderParamDoubleSpinBoxValueChanged(double)));
2655
2656 box->addWidget(doubleSpinBox);
2657 }
2658 else
2659 {
2660 spinBox = new QSpinBox(this);
2661 spinBox->setRange(param->minimum, param->maximum);
2662 spinBox->setSingleStep(param->step);
2663 spinBox->setValue(param->current);
2664 spinBox->setProperty("slider", QVariant::fromValue(slider));
2665 slider->setProperty("spinBox", QVariant::fromValue(spinBox));
2666
2667 connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(onShaderParamSpinBoxValueChanged(int)));
2668
2669 box->addWidget(spinBox);
2670 }
2671
2672 form->addRow(label, box);
2673 }
2674 }
2675
onShaderParamCheckBoxClicked()2676 void ShaderParamsDialog::onShaderParamCheckBoxClicked()
2677 {
2678 QVariant paramVariant;
2679 QCheckBox *checkBox = qobject_cast<QCheckBox*>(sender());
2680 struct video_shader *menu_shader = NULL;
2681 struct video_shader *video_shader = NULL;
2682
2683 getShaders(&menu_shader, &video_shader);
2684
2685 if (!checkBox)
2686 return;
2687
2688 if (menu_shader && menu_shader->passes == 0)
2689 return;
2690
2691 paramVariant = checkBox->property("param");
2692
2693 if (paramVariant.isValid())
2694 {
2695 QString parameter = paramVariant.toString();
2696
2697 if (menu_shader)
2698 {
2699 int i;
2700 struct video_shader_parameter *param = NULL;
2701
2702 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
2703 {
2704 QString id = menu_shader->parameters[i].id;
2705
2706 if (id == parameter)
2707 param = &menu_shader->parameters[i];
2708 }
2709
2710 if (param)
2711 param->current = (checkBox->isChecked() ? param->maximum : param->minimum);
2712 }
2713
2714 if (video_shader)
2715 {
2716 int i;
2717 struct video_shader_parameter *param = NULL;
2718
2719 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
2720 {
2721 QString id = video_shader->parameters[i].id;
2722
2723 if (id == parameter)
2724 param = &video_shader->parameters[i];
2725 }
2726
2727 if (param)
2728 param->current = (checkBox->isChecked() ? param->maximum : param->minimum);
2729 }
2730
2731 video_shader->modified = true;
2732 }
2733 }
2734
onShaderParamSliderValueChanged(int)2735 void ShaderParamsDialog::onShaderParamSliderValueChanged(int)
2736 {
2737 QVariant spinBoxVariant;
2738 QVariant paramVariant;
2739 QSlider *slider = qobject_cast<QSlider*>(sender());
2740 struct video_shader *menu_shader = NULL;
2741 struct video_shader *video_shader = NULL;
2742 double newValue = 0.0;
2743
2744 getShaders(&menu_shader, &video_shader);
2745
2746 if (!slider)
2747 return;
2748
2749 spinBoxVariant = slider->property("spinBox");
2750 paramVariant = slider->property("param");
2751
2752 if (paramVariant.isValid())
2753 {
2754 QString parameter = paramVariant.toString();
2755
2756 if (menu_shader)
2757 {
2758 int i;
2759 struct video_shader_parameter *param = NULL;
2760
2761 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
2762 {
2763 QString id = menu_shader->parameters[i].id;
2764
2765 if (id == parameter)
2766 param = &menu_shader->parameters[i];
2767 }
2768
2769 if (param)
2770 {
2771 newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value());
2772 newValue = round(newValue / param->step) * param->step;
2773 param->current = newValue;
2774 }
2775 }
2776
2777 if (video_shader)
2778 {
2779 int i;
2780 struct video_shader_parameter *param = NULL;
2781
2782 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
2783 {
2784 QString id = video_shader->parameters[i].id;
2785
2786 if (id == parameter)
2787 param = &video_shader->parameters[i];
2788 }
2789
2790 if (param)
2791 {
2792 newValue = MainWindow::lerp(0, 100, param->minimum, param->maximum, slider->value());
2793 newValue = round(newValue / param->step) * param->step;
2794 param->current = newValue;
2795 }
2796
2797 video_shader->modified = true;
2798 }
2799
2800 }
2801
2802 if (spinBoxVariant.isValid())
2803 {
2804 QSpinBox *spinBox = spinBoxVariant.value<QSpinBox*>();
2805
2806 if (!spinBox)
2807 return;
2808
2809 spinBox->blockSignals(true);
2810 spinBox->setValue(newValue);
2811 spinBox->blockSignals(false);
2812 }
2813 else
2814 {
2815 QVariant doubleSpinBoxVariant = slider->property("doubleSpinBox");
2816 QDoubleSpinBox *doubleSpinBox = doubleSpinBoxVariant.value<QDoubleSpinBox*>();
2817
2818 if (!doubleSpinBox)
2819 return;
2820
2821 doubleSpinBox->blockSignals(true);
2822 doubleSpinBox->setValue(newValue);
2823 doubleSpinBox->blockSignals(false);
2824 }
2825 }
2826
onShaderParamSpinBoxValueChanged(int value)2827 void ShaderParamsDialog::onShaderParamSpinBoxValueChanged(int value)
2828 {
2829 QVariant sliderVariant;
2830 QVariant paramVariant;
2831 QSpinBox *spinBox = qobject_cast<QSpinBox*>(sender());
2832 QSlider *slider = NULL;
2833 struct video_shader *menu_shader = NULL;
2834 struct video_shader *video_shader = NULL;
2835
2836 getShaders(&menu_shader, &video_shader);
2837
2838 if (!spinBox)
2839 return;
2840
2841 sliderVariant = spinBox->property("slider");
2842
2843 if (!sliderVariant.isValid())
2844 return;
2845
2846 slider = sliderVariant.value<QSlider*>();
2847
2848 if (!slider)
2849 return;
2850
2851 paramVariant = slider->property("param");
2852
2853 if (paramVariant.isValid())
2854 {
2855 QString parameter = paramVariant.toString();
2856 double newValue = 0.0;
2857
2858 if (menu_shader)
2859 {
2860 int i;
2861 struct video_shader_parameter *param = NULL;
2862
2863 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
2864 {
2865 QString id = menu_shader->parameters[i].id;
2866
2867 if (id == parameter)
2868 param = &menu_shader->parameters[i];
2869 }
2870
2871 if (param)
2872 {
2873 param->current = value;
2874 newValue = MainWindow::lerp(
2875 param->minimum, param->maximum, 0, 100, param->current);
2876 slider->blockSignals(true);
2877 slider->setValue(newValue);
2878 slider->blockSignals(false);
2879 }
2880 }
2881
2882 if (video_shader)
2883 {
2884 int i;
2885 struct video_shader_parameter *param = NULL;
2886
2887 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
2888 {
2889 QString id = video_shader->parameters[i].id;
2890
2891 if (id == parameter)
2892 param = &video_shader->parameters[i];
2893 }
2894
2895 if (param)
2896 {
2897 param->current = value;
2898 newValue = MainWindow::lerp(
2899 param->minimum, param->maximum, 0, 100, param->current);
2900 slider->blockSignals(true);
2901 slider->setValue(newValue);
2902 slider->blockSignals(false);
2903 }
2904
2905 video_shader->modified = true;
2906 }
2907 }
2908 }
2909
onShaderParamDoubleSpinBoxValueChanged(double value)2910 void ShaderParamsDialog::onShaderParamDoubleSpinBoxValueChanged(double value)
2911 {
2912 QVariant sliderVariant;
2913 QVariant paramVariant;
2914 QSlider *slider = NULL;
2915 QDoubleSpinBox *doubleSpinBox = qobject_cast<QDoubleSpinBox*>(sender());
2916 struct video_shader *menu_shader = NULL;
2917 struct video_shader *video_shader = NULL;
2918
2919 getShaders(&menu_shader, &video_shader);
2920
2921 if (!doubleSpinBox)
2922 return;
2923
2924 sliderVariant = doubleSpinBox->property("slider");
2925
2926 if (!sliderVariant.isValid())
2927 return;
2928
2929 slider = sliderVariant.value<QSlider*>();
2930
2931 if (!slider)
2932 return;
2933
2934 paramVariant = slider->property("param");
2935
2936 if (paramVariant.isValid())
2937 {
2938 QString parameter = paramVariant.toString();
2939 double newValue = 0.0;
2940
2941 if (menu_shader)
2942 {
2943 int i;
2944 struct video_shader_parameter *param = NULL;
2945
2946 for (i = 0; i < static_cast<int>(menu_shader->num_parameters); i++)
2947 {
2948 QString id = menu_shader->parameters[i].id;
2949
2950 if (id == parameter)
2951 param = &menu_shader->parameters[i];
2952 }
2953
2954 if (param)
2955 {
2956 param->current = value;
2957 newValue = MainWindow::lerp(
2958 param->minimum, param->maximum, 0, 100, param->current);
2959 slider->blockSignals(true);
2960 slider->setValue(newValue);
2961 slider->blockSignals(false);
2962 }
2963 }
2964
2965 if (video_shader)
2966 {
2967 int i;
2968 struct video_shader_parameter *param = NULL;
2969
2970 for (i = 0; i < static_cast<int>(video_shader->num_parameters); i++)
2971 {
2972 QString id = video_shader->parameters[i].id;
2973
2974 if (id == parameter)
2975 param = &video_shader->parameters[i];
2976 }
2977
2978 if (param)
2979 {
2980 param->current = value;
2981 newValue = MainWindow::lerp(
2982 param->minimum, param->maximum, 0, 100, param->current);
2983 slider->blockSignals(true);
2984 slider->setValue(newValue);
2985 slider->blockSignals(false);
2986 }
2987
2988 video_shader->modified = true;
2989 }
2990 }
2991 }
2992 #endif
2993 #endif
2994