1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3  *  Copyright (C) 2011-2017 - Daniel De Matteis
4  *  Copyright (C) 2016-2019 - Brad Parker
5  *
6  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
7  *  of the GNU General Public License as published by the Free Software Found-
8  *  ation, either version 3 of the License, or (at your option) any later version.
9  *
10  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  *  PURPOSE.  See the GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along with RetroArch.
15  *  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef _QT_UI
19 #define _QT_UI
20 
21 #include <QObject>
22 #include <QMainWindow>
23 #include <QTreeView>
24 #include <QListWidget>
25 #include <QTableView>
26 #include <QFrame>
27 #include <QWidget>
28 #include <QDialog>
29 #include <QLabel>
30 #include <QRegularExpression>
31 #include <QPalette>
32 #include <QPlainTextEdit>
33 #include <QFutureWatcher>
34 #include <QPixmap>
35 #include <QImage>
36 #include <QPointer>
37 #include <QProgressBar>
38 #include <QElapsedTimer>
39 #include <QSslError>
40 #include <QNetworkReply>
41 #include <QStyledItemDelegate>
42 #include <QCache>
43 #include <QSortFilterProxyModel>
44 #include <QDir>
45 
46 #include "qt/filedropwidget.h"
47 
48 #ifndef CXX_BUILD
49 extern "C" {
50 #endif
51 
52 #ifdef HAVE_CONFIG_H
53 #include "../../config.h"
54 #endif
55 
56 #include <retro_assert.h>
57 #include <retro_common_api.h>
58 #include <queues/task_queue.h>
59 
60 #include "../ui_companion_driver.h"
61 #include "../../retroarch.h"
62 
63 #ifndef CXX_BUILD
64 }
65 #endif
66 
67 #define ALL_PLAYLISTS_TOKEN "|||ALL|||"
68 #define ICON_PATH "/xmb/dot-art/png/"
69 #define THUMBNAIL_BOXART "Named_Boxarts"
70 #define THUMBNAIL_SCREENSHOT "Named_Snaps"
71 #define THUMBNAIL_TITLE "Named_Titles"
72 
73 class QApplication;
74 class QCloseEvent;
75 class QKeyEvent;
76 class QTimer;
77 class QFileSystemModel;
78 class QListWidgetItem;
79 class QTableWidgetItem;
80 class QResizeEvent;
81 class QDockWidget;
82 class QComboBox;
83 class QPushButton;
84 class QToolButton;
85 class QTabWidget;
86 class QPixmap;
87 class QPaintEvent;
88 class QSettings;
89 class QCheckBox;
90 class QSpinBox;
91 class QFormLayout;
92 class QStyle;
93 class QScrollArea;
94 class QSlider;
95 class QDragEnterEvent;
96 class QDropEvent;
97 class QNetworkAccessManager;
98 class QNetworkReply;
99 class QProgressDialog;
100 class LoadCoreWindow;
101 class MainWindow;
102 class ThumbnailWidget;
103 class ThumbnailLabel;
104 class GridView;
105 class ShaderParamsDialog;
106 class CoreOptionsDialog;
107 class CoreInfoDialog;
108 class PlaylistEntryDialog;
109 class ViewOptionsDialog;
110 
111 enum SpecialPlaylist
112 {
113    SPECIAL_PLAYLIST_HISTORY
114 };
115 
116 enum ThumbnailType
117 {
118    THUMBNAIL_TYPE_BOXART,
119    THUMBNAIL_TYPE_SCREENSHOT,
120    THUMBNAIL_TYPE_TITLE_SCREEN,
121 };
122 
123 class PlaylistModel : public QAbstractListModel
124 {
125    Q_OBJECT
126 
127 public:
128    enum Roles
129    {
130       HASH = Qt::UserRole + 1,
131       THUMBNAIL
132    };
133 
134    PlaylistModel(QObject *parent = 0);
135 
136    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
137    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
138    Qt::ItemFlags flags(const QModelIndex &index) const;
139    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
140    int rowCount(const QModelIndex &parent = QModelIndex()) const;
141    int columnCount(const QModelIndex &parent = QModelIndex()) const;
142    void addPlaylistItems(const QStringList &paths, bool add = false);
143    void addDir(QString path, QFlags<QDir::Filter> showHidden);
144    void setThumbnailType(const ThumbnailType type);
145    void loadThumbnail(const QModelIndex &index);
146    void reloadThumbnail(const QModelIndex &index);
147    void reloadThumbnailPath(const QString path);
148    void reloadSystemThumbnails(const QString system);
149    void setThumbnailCacheLimit(int limit);
150    bool isSupportedImage(const QString path) const;
151    QString getPlaylistThumbnailsDir(const QString playlistName) const;
152    QString getSanitizedThumbnailName(QString label) const;
153 
154 signals:
155    void imageLoaded(const QImage image, const QModelIndex &index, const QString &path);
156 
157 private slots:
158    void onImageLoaded(const QImage image, const QModelIndex &index, const QString &path);
159 
160 private:
161    QVector<QHash<QString, QString> > m_contents;
162    QCache<QString, QPixmap> m_cache;
163    QSet<QString> m_pendingImages;
164    QVector<QByteArray> m_imageFormats;
165    QRegularExpression m_fileSanitizerRegex;
166    ThumbnailType m_thumbnailType = THUMBNAIL_TYPE_BOXART;
167    QString getThumbnailPath(const QModelIndex &index, QString type) const;
168    QString getThumbnailPath(const QHash<QString, QString> &hash, QString type) const;
169    QString getCurrentTypeThumbnailPath(const QModelIndex &index) const;
170    void getPlaylistItems(QString path);
171    void loadImage(const QModelIndex &index, const QString &path);
172 };
173 
174 class ThumbnailWidget : public QStackedWidget
175 {
176    Q_OBJECT
177 public:
178    ThumbnailWidget(QWidget *parent = 0);
179    ThumbnailWidget(ThumbnailType type, QWidget *parent = 0);
ThumbnailWidget(const ThumbnailWidget & other)180    ThumbnailWidget(const ThumbnailWidget& other) { retro_assert(false && "DONT EVER USE THIS"); }
181 
182    void setPixmap(const QPixmap &pixmap, bool acceptDrops);
183 signals:
184    void filesDropped(const QImage& image, ThumbnailType type);
185 private:
186    QSize m_sizeHint;
187    ThumbnailType m_thumbnailType;
188    ThumbnailLabel *m_thumbnailLabel;
189    QLabel *m_dropIndicator;
190 protected:
191    void dragEnterEvent(QDragEnterEvent *event);
192    void dragMoveEvent(QDragMoveEvent *event);
193    void dropEvent(QDropEvent *event);
194 };
195 
196 class ThumbnailLabel : public QWidget
197 {
198    Q_OBJECT
199 public:
200    ThumbnailLabel(QWidget *parent = 0);
201    ~ThumbnailLabel();
202    QSize sizeHint() const;
203 public slots:
204    void setPixmap(const QPixmap &pixmap);
205 protected:
206    void paintEvent(QPaintEvent *event);
207    void resizeEvent(QResizeEvent *event);
208 private:
209    void updateMargins();
210 
211    QPixmap *m_pixmap;
212    int m_pixmapWidth;
213    int m_pixmapHeight;
214 };
215 
216 class TreeView : public QTreeView
217 {
218    Q_OBJECT
219 public:
220    TreeView(QWidget *parent = 0);
221 signals:
222    void itemsSelected(QModelIndexList selectedIndexes);
223 protected slots:
224    void columnCountChanged(int oldCount, int newCount);
225    void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
226 };
227 
228 class TableView : public QTableView
229 {
230    Q_OBJECT
231 public:
232    TableView(QWidget *parent = 0);
233    bool isEditorOpen();
234 };
235 
236 class ListWidget : public QListWidget
237 {
238    Q_OBJECT
239 public:
240    ListWidget(QWidget *parent = 0);
241    bool isEditorOpen();
242 signals:
243    void enterPressed();
244    void deletePressed();
245 protected:
246    void keyPressEvent(QKeyEvent *event);
247 };
248 
249 class AppHandler : public QObject
250 {
251    Q_OBJECT
252 
253 public:
254    AppHandler(QObject *parent = 0);
255    ~AppHandler();
256    void exit();
257    bool isExiting() const;
258 
259 private slots:
260    void onLastWindowClosed();
261 };
262 
263 class CoreInfoLabel : public QLabel
264 {
265    Q_OBJECT
266 public:
267    CoreInfoLabel(QString text = QString(), QWidget *parent = 0);
268 };
269 
270 class CoreInfoWidget : public QWidget
271 {
272    Q_OBJECT
273 public:
274    CoreInfoWidget(CoreInfoLabel *label, QWidget *parent = 0);
275    QSize sizeHint() const;
276 protected:
277    void resizeEvent(QResizeEvent *event);
278 private:
279    CoreInfoLabel *m_label;
280    QScrollArea *m_scrollArea;
281 };
282 
283 class LogTextEdit : public QPlainTextEdit
284 {
285    Q_OBJECT
286 public:
287    LogTextEdit(QWidget *parent = 0);
288 public slots:
289    void appendMessage(const QString& text);
290 };
291 
292 /* Used to store styling since delegates don't inherit QWidget. */
293 class GridItem : public QWidget
294 {
295    Q_OBJECT
296 
297    Q_PROPERTY(QString thumbnailvalign READ getThumbnailVerticalAlign WRITE setThumbnailVerticalAlign)
298    Q_PROPERTY(int padding READ getPadding WRITE setPadding)
299 
300 public:
301    GridItem(QWidget* parent);
302 
303    Qt::AlignmentFlag thumbnailVerticalAlignmentFlag;
304    int padding;
305 
306    int getPadding() const;
307    void setPadding(const int value);
308    QString getThumbnailVerticalAlign() const;
309    void setThumbnailVerticalAlign(const QString valign);
310 };
311 
312 class FileSystemProxyModel : public QSortFilterProxyModel
313 {
314 protected:
315    virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
316    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
317 };
318 
319 class MainWindow : public QMainWindow
320 {
321    Q_OBJECT
322 
323 public:
324    enum ViewType
325    {
326       VIEW_TYPE_ICONS,
327       VIEW_TYPE_LIST
328    };
329 
330    enum BrowserType
331    {
332       BROWSER_TYPE_PLAYLISTS,
333       BROWSER_TYPE_FILES
334    };
335 
336    enum Theme
337    {
338       THEME_SYSTEM_DEFAULT,
339       THEME_DARK,
340       THEME_CUSTOM
341    };
342 
343    enum MessageBoxType
344    {
345       MSGBOX_TYPE_INFO,
346       MSGBOX_TYPE_WARNING,
347       MSGBOX_TYPE_ERROR,
348       MSGBOX_TYPE_QUESTION_YESNO,
349       MSGBOX_TYPE_QUESTION_OKCANCEL,
350    };
351 
352    MainWindow(QWidget *parent = NULL);
353    ~MainWindow();
354    TreeView* dirTreeView();
355    PlaylistModel* playlistModel();
356    ListWidget* playlistListWidget();
357    QStackedWidget* centralWidget();
358    TableView* contentTableView();
359    QTableView* fileTableView();
360    FileDropWidget* playlistViews();
361    GridView* contentGridView();
362    QWidget* playlistViewsAndFooter();
363    QWidget* searchWidget();
364    QLineEdit* searchLineEdit();
365    QComboBox* launchWithComboBox();
366    QToolButton* startCorePushButton();
367    QToolButton* coreInfoPushButton();
368    QToolButton* runPushButton();
369    QToolButton* stopPushButton();
370    QTabWidget* browserAndPlaylistTabWidget();
371    QString getPlaylistDefaultCore(QString plName);
372    ViewOptionsDialog* viewOptionsDialog();
373    QSettings* settings();
374    QVector<QHash<QString, QString> > getCoreInfo();
375    void setTheme(Theme theme = THEME_SYSTEM_DEFAULT);
376    Theme theme();
377    Theme getThemeFromString(QString themeString);
378    QString getThemeString(Theme theme);
379    QHash<QString, QString> getSelectedCore();
380    void showStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush);
381    bool showMessageBox(QString msg, MessageBoxType msgType = MSGBOX_TYPE_INFO, Qt::WindowModality modality = Qt::ApplicationModal, bool showDontAsk = true, bool *dontAsk = NULL);
382    bool setCustomThemeFile(QString filePath);
383    void setCustomThemeString(QString qss);
384    const QString& customThemeString() const;
385    void setCurrentViewType(ViewType viewType);
386    QString getCurrentViewTypeString();
387    ViewType getCurrentViewType();
388    void setCurrentThumbnailType(ThumbnailType thumbnailType);
389    QString getCurrentThumbnailTypeString();
390    ThumbnailType getCurrentThumbnailType();
391    ThumbnailType getThumbnailTypeFromString(QString thumbnailType);
392    void setAllPlaylistsListMaxCount(int count);
393    void setAllPlaylistsGridMaxCount(int count);
394    void setThumbnailCacheLimit(int count);
395    PlaylistEntryDialog* playlistEntryDialog();
396    void addFilesToPlaylist(QStringList files);
397    QString getCurrentPlaylistPath();
398    QModelIndex getCurrentContentIndex();
399    QHash<QString, QString> getCurrentContentHash();
400    QHash<QString, QString> getFileContentHash(const QModelIndex &index);
401    static double lerp(double x, double y, double a, double b, double d);
402    QString getSpecialPlaylistPath(SpecialPlaylist playlist);
403    QVector<QPair<QString, QString> > getPlaylists();
404    QString getScrubbedString(QString str);
405    void setDefaultCustomProperties();
406    void setIconViewZoom(int zoomValue);
407 
408 signals:
409    void thumbnailChanged(const QPixmap &pixmap);
410    void thumbnail2Changed(const QPixmap &pixmap);
411    void thumbnail3Changed(const QPixmap &pixmap);
412    void gotLogMessage(const QString &msg);
413    void gotStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush);
414    void gotReloadPlaylists();
415    void gotReloadShaderParams();
416    void gotReloadCoreOptions();
417    void showErrorMessageDeferred(QString msg);
418    void showInfoMessageDeferred(QString msg);
419    void extractArchiveDeferred(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb);
420    void itemChanged();
421    void updateThumbnails();
422    void gridItemChanged(QString title);
423    void gotThumbnailDownload(QString system, QString title);
424    void scrollToDownloads(QString path);
425    void scrollToDownloadsAgain(QString path);
426 
427 public slots:
428    void onBrowserDownloadsClicked();
429    void onBrowserUpClicked();
430    void onBrowserStartClicked();
431    void initContentTableWidget();
432    void onViewClosedDocksAboutToShow();
433    void onShowHiddenDockWidgetAction();
434    void setCoreActions();
435    void onRunClicked();
436    void loadContent(const QHash<QString, QString> &contentHash);
437    void onStartCoreClicked();
438    void onDropWidgetEnterPressed();
439    void selectBrowserDir(QString path);
440    void setThumbnail(QString widgetName, QPixmap &pixmap, bool acceptDrop);
441    void onResizeThumbnailOne(QPixmap &pixmap, bool acceptDrop);
442    void onResizeThumbnailTwo(QPixmap &pixmap, bool acceptDrop);
443    void onResizeThumbnailThree(QPixmap &pixmap, bool acceptDrop);
444    void appendLogMessage(const QString &msg);
445    void onGotLogMessage(const QString &msg);
446    void onGotStatusMessage(QString msg, unsigned priority, unsigned duration, bool flush);
447    void reloadPlaylists();
448    void deferReloadPlaylists();
449    void onGotReloadPlaylists();
450    void onGotReloadShaderParams();
451    void onGotReloadCoreOptions();
452    void showWelcomeScreen();
453    void onIconViewClicked();
454    void onListViewClicked();
455    void onBoxartThumbnailClicked();
456    void onScreenshotThumbnailClicked();
457    void onTitleThumbnailClicked();
458    void onTabWidgetIndexChanged(int index);
459    void deleteCurrentPlaylistItem();
460    void onFileDropWidgetContextMenuRequested(const QPoint &pos);
461    void showAbout();
462    void showDocs();
463    void onThumbnailPackExtractFinished(bool success);
464    void deferReloadShaderParams();
465    void downloadThumbnail(QString system, QString title, QUrl url = QUrl());
466    void downloadAllThumbnails(QString system, QUrl url = QUrl());
467    void downloadPlaylistThumbnails(QString playlistPath);
468    void downloadNextPlaylistThumbnail(QString system, QString title, QString type, QUrl url = QUrl());
469    void changeThumbnailType(ThumbnailType type);
470    void onThumbnailDropped(const QImage &image, ThumbnailType type);
471 
472 private slots:
473    void onLoadCoreClicked(const QStringList &extensionFilters = QStringList());
474    void onUnloadCoreMenuAction();
475    void onTimeout();
476    void onCoreLoaded();
477    void onCurrentTableItemDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
478    void onCurrentListItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
479    void onCurrentListItemDataChanged(QListWidgetItem *item);
480    void onCurrentItemChanged(const QModelIndex &index);
481    void onCurrentItemChanged(const QHash<QString, QString> &hash);
482    void onCurrentFileChanged(const QModelIndex &index);
483    void onSearchEnterPressed();
484    void onSearchLineEditEdited(const QString &text);
485    void onContentItemDoubleClicked(const QModelIndex &index);
486    void onFileDoubleClicked(const QModelIndex &index);
487    void onCoreLoadWindowClosed();
488    void onTreeViewItemsSelected(QModelIndexList selectedIndexes);
489    void onSearchResetClicked();
490    void onLaunchWithComboBoxIndexChanged(int index);
491    void onFileBrowserTreeContextMenuRequested(const QPoint &pos);
492    void onPlaylistWidgetContextMenuRequested(const QPoint &pos);
493    void onStopClicked();
494    void onZoomValueChanged(int value);
495    void onPlaylistFilesDropped(QStringList files);
496    void onShaderParamsClicked();
497    void onCoreOptionsClicked();
498    void onShowErrorMessage(QString msg);
499    void onShowInfoMessage(QString msg);
500    void onContributorsClicked();
501    void onItemChanged();
502    void onFileSystemDirLoaded(const QString &path);
503    void onFileBrowserTableDirLoaded(const QString &path);
504    void onDownloadScroll(QString path);
505    void onDownloadScrollAgain(QString path);
506    int onExtractArchive(QString path, QString extractionDir, QString tempExtension, retro_task_callback_t cb);
507 
508    void onThumbnailDownloadNetworkError(QNetworkReply::NetworkError code);
509    void onThumbnailDownloadNetworkSslErrors(const QList<QSslError> &errors);
510    void onThumbnailDownloadFinished();
511    void onThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
512    void onThumbnailDownloadReadyRead();
513    void onThumbnailDownloadCanceled();
514    void onDownloadThumbnail(QString system, QString title);
515 
516    void onThumbnailPackDownloadNetworkError(QNetworkReply::NetworkError code);
517    void onThumbnailPackDownloadNetworkSslErrors(const QList<QSslError> &errors);
518    void onThumbnailPackDownloadFinished();
519    void onThumbnailPackDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
520    void onThumbnailPackDownloadReadyRead();
521    void onThumbnailPackDownloadCanceled();
522 
523    void onPlaylistThumbnailDownloadNetworkError(QNetworkReply::NetworkError code);
524    void onPlaylistThumbnailDownloadNetworkSslErrors(const QList<QSslError> &errors);
525    void onPlaylistThumbnailDownloadFinished();
526    void onPlaylistThumbnailDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
527    void onPlaylistThumbnailDownloadReadyRead();
528    void onPlaylistThumbnailDownloadCanceled();
529 
530    void startTimer();
531    void updateVisibleItems();
532 
533 private:
534    void setCurrentCoreLabel();
535    void getPlaylistFiles();
536    bool isCoreLoaded();
537    bool isContentLessCore();
538    bool updateCurrentPlaylistEntry(const QHash<QString, QString> &contentHash);
539    int extractArchive(QString path);
540    bool addDirectoryFilesToList(QProgressDialog *dialog, QStringList &list, QDir &dir, QStringList &extensions);
541    void renamePlaylistItem(QListWidgetItem *item, QString newName);
542    bool currentPlaylistIsSpecial();
543    bool currentPlaylistIsAll();
544    void applySearch();
545    void updateItemsCount();
546    QString changeThumbnail(const QImage &image, QString type);
547 
548    PlaylistModel *m_playlistModel;
549    QSortFilterProxyModel *m_proxyModel;
550    FileSystemProxyModel *m_proxyFileModel;
551    LoadCoreWindow *m_loadCoreWindow;
552    QTimer *m_timer;
553    QString m_currentCore;
554    QString m_currentCoreVersion;
555    QLabel *m_statusLabel;
556    TreeView *m_dirTree;
557    QFileSystemModel *m_dirModel;
558    QFileSystemModel *m_fileModel;
559    ListWidget *m_listWidget;
560    QStackedWidget *m_centralWidget;
561    TableView *m_tableView;
562    QTableView *m_fileTableView;
563    FileDropWidget *m_playlistViews;
564    QWidget *m_searchWidget;
565    QLineEdit *m_searchLineEdit;
566    QDockWidget *m_searchDock;
567    QStringList m_playlistFiles;
568    QComboBox *m_launchWithComboBox;
569    QToolButton *m_startCorePushButton;
570    QToolButton *m_coreInfoPushButton;
571    QToolButton *m_runPushButton;
572    QToolButton *m_stopPushButton;
573    QTabWidget *m_browserAndPlaylistTabWidget;
574    bool m_pendingRun;
575    QPixmap *m_thumbnailPixmap;
576    QPixmap *m_thumbnailPixmap2;
577    QPixmap *m_thumbnailPixmap3;
578    QSettings *m_settings;
579    ViewOptionsDialog *m_viewOptionsDialog;
580    CoreInfoDialog *m_coreInfoDialog;
581    QStyle *m_defaultStyle;
582    QPalette m_defaultPalette;
583    Theme m_currentTheme;
584    QDockWidget *m_coreInfoDock;
585    CoreInfoLabel *m_coreInfoLabel;
586    CoreInfoWidget *m_coreInfoWidget;
587    QDockWidget *m_logDock;
588    QFrame *m_logWidget;
589    LogTextEdit *m_logTextEdit;
590    QVector<QByteArray> m_imageFormats;
591    QListWidgetItem *m_historyPlaylistsItem;
592    QIcon m_folderIcon;
593    QString m_customThemeString;
594    GridView *m_gridView;
595    QWidget *m_playlistViewsAndFooter;
596    QWidget *m_gridLayoutWidget;
597    QSlider *m_zoomSlider;
598    int m_lastZoomSliderValue;
599    ViewType m_viewType;
600    ThumbnailType m_thumbnailType;
601    QProgressBar *m_gridProgressBar;
602    QWidget *m_gridProgressWidget;
603    QHash<QString, QString> m_currentGridHash;
604    QPointer<ThumbnailWidget> m_currentGridWidget;
605    int m_allPlaylistsListMaxCount;
606    int m_allPlaylistsGridMaxCount;
607    PlaylistEntryDialog *m_playlistEntryDialog;
608    QElapsedTimer m_statusMessageElapsedTimer;
609    QPointer<ShaderParamsDialog> m_shaderParamsDialog;
610    QPointer<CoreOptionsDialog> m_coreOptionsDialog;
611    QNetworkAccessManager *m_networkManager;
612 
613    QProgressDialog *m_updateProgressDialog;
614    QFile m_updateFile;
615    QPointer<QNetworkReply> m_updateReply;
616 
617    QProgressDialog *m_thumbnailDownloadProgressDialog;
618    QFile m_thumbnailDownloadFile;
619    QPointer<QNetworkReply> m_thumbnailDownloadReply;
620    QStringList m_pendingThumbnailDownloadTypes;
621 
622    QProgressDialog *m_thumbnailPackDownloadProgressDialog;
623    QFile m_thumbnailPackDownloadFile;
624    QPointer<QNetworkReply> m_thumbnailPackDownloadReply;
625 
626    QProgressDialog *m_playlistThumbnailDownloadProgressDialog;
627    QFile m_playlistThumbnailDownloadFile;
628    QPointer<QNetworkReply> m_playlistThumbnailDownloadReply;
629    QVector<QHash<QString, QString> > m_pendingPlaylistThumbnails;
630    unsigned m_downloadedThumbnails;
631    unsigned m_failedThumbnails;
632    bool m_playlistThumbnailDownloadWasCanceled;
633    QString m_pendingDirScrollPath;
634 
635    QTimer *m_thumbnailTimer;
636    GridItem m_gridItem;
637    BrowserType m_currentBrowser;
638    QRegExp m_searchRegExp;
639    QByteArray m_fileTableHeaderState;
640    QWidget *m_zoomWidget;
641    QString m_itemsCountLiteral;
642    QLabel *m_itemsCountLabel;
643 
644 protected:
645    void closeEvent(QCloseEvent *event);
646    void keyPressEvent(QKeyEvent *event);
647 };
648 
649 Q_DECLARE_METATYPE(ThumbnailWidget)
650 Q_DECLARE_METATYPE(QPointer<ThumbnailWidget>)
651 #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
652 Q_DECLARE_METATYPE(struct video_shader_parameter*)
653 #endif
654 
655 RETRO_BEGIN_DECLS
656 
657 typedef struct ui_application_qt
658 {
659    QApplication *app;
660 } ui_application_qt_t;
661 
662 typedef struct ui_window_qt
663 {
664    MainWindow *qtWindow;
665 } ui_window_qt_t;
666 
667 QStringList string_split_to_qt(QString str, char delim);
668 
669 RETRO_END_DECLS
670 
671 #endif
672