mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	citra-qt: game list search function (#2673)
* citra-qt: game list search function * Empty search field during game list refresh * Code improvements * Code formatting * Autofocus search field * JayFoxRox's recommendations * lioncash's review
This commit is contained in:
		
							parent
							
								
									ea53d6085a
								
							
						
					
					
						commit
						06d4654966
					
				@ -177,6 +177,7 @@ void Config::ReadValues() {
 | 
			
		||||
 | 
			
		||||
    UISettings::values.single_window_mode = qt_config->value("singleWindowMode", true).toBool();
 | 
			
		||||
    UISettings::values.display_titlebar = qt_config->value("displayTitleBars", true).toBool();
 | 
			
		||||
    UISettings::values.show_filter_bar = qt_config->value("showFilterBar", true).toBool();
 | 
			
		||||
    UISettings::values.show_status_bar = qt_config->value("showStatusBar", true).toBool();
 | 
			
		||||
    UISettings::values.confirm_before_closing = qt_config->value("confirmClose", true).toBool();
 | 
			
		||||
    UISettings::values.first_start = qt_config->value("firstStart", true).toBool();
 | 
			
		||||
@ -295,6 +296,7 @@ void Config::SaveValues() {
 | 
			
		||||
 | 
			
		||||
    qt_config->setValue("singleWindowMode", UISettings::values.single_window_mode);
 | 
			
		||||
    qt_config->setValue("displayTitleBars", UISettings::values.display_titlebar);
 | 
			
		||||
    qt_config->setValue("showFilterBar", UISettings::values.show_filter_bar);
 | 
			
		||||
    qt_config->setValue("showStatusBar", UISettings::values.show_status_bar);
 | 
			
		||||
    qt_config->setValue("confirmClose", UISettings::values.confirm_before_closing);
 | 
			
		||||
    qt_config->setValue("firstStart", UISettings::values.first_start);
 | 
			
		||||
 | 
			
		||||
@ -4,9 +4,9 @@
 | 
			
		||||
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
#include <QHeaderView>
 | 
			
		||||
#include <QKeyEvent>
 | 
			
		||||
#include <QMenu>
 | 
			
		||||
#include <QThreadPool>
 | 
			
		||||
#include <QVBoxLayout>
 | 
			
		||||
#include "common/common_paths.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
@ -15,10 +15,189 @@
 | 
			
		||||
#include "game_list_p.h"
 | 
			
		||||
#include "ui_settings.h"
 | 
			
		||||
 | 
			
		||||
GameList::GameList(QWidget* parent) : QWidget{parent} {
 | 
			
		||||
    QVBoxLayout* layout = new QVBoxLayout;
 | 
			
		||||
GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) {
 | 
			
		||||
    this->gamelist = gamelist;
 | 
			
		||||
    edit_filter_text_old = "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EventFilter in order to process systemkeys while editing the searchfield
 | 
			
		||||
bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
 | 
			
		||||
    // If it isn't a KeyRelease event then continue with standard event processing
 | 
			
		||||
    if (event->type() != QEvent::KeyRelease)
 | 
			
		||||
        return QObject::eventFilter(obj, event);
 | 
			
		||||
 | 
			
		||||
    QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
 | 
			
		||||
    int rowCount = gamelist->tree_view->model()->rowCount();
 | 
			
		||||
    QString edit_filter_text = gamelist->search_field->edit_filter->text().toLower();
 | 
			
		||||
 | 
			
		||||
    // If the searchfield's text hasn't changed special function keys get checked
 | 
			
		||||
    // If no function key changes the searchfield's text the filter doesn't need to get reloaded
 | 
			
		||||
    if (edit_filter_text == edit_filter_text_old) {
 | 
			
		||||
        switch (keyEvent->key()) {
 | 
			
		||||
        // Escape: Resets the searchfield
 | 
			
		||||
        case Qt::Key_Escape: {
 | 
			
		||||
            if (edit_filter_text_old.isEmpty()) {
 | 
			
		||||
                return QObject::eventFilter(obj, event);
 | 
			
		||||
            } else {
 | 
			
		||||
                gamelist->search_field->edit_filter->clear();
 | 
			
		||||
                edit_filter_text = "";
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        // Return and Enter
 | 
			
		||||
        // If the enter key gets pressed first checks how many and which entry is visable
 | 
			
		||||
        // If there is only one result launch this game
 | 
			
		||||
        case Qt::Key_Return:
 | 
			
		||||
        case Qt::Key_Enter: {
 | 
			
		||||
            QStandardItemModel* item_model = new QStandardItemModel(gamelist->tree_view);
 | 
			
		||||
            QModelIndex root_index = item_model->invisibleRootItem()->index();
 | 
			
		||||
            QStandardItem* child_file;
 | 
			
		||||
            QString file_path;
 | 
			
		||||
            int resultCount = 0;
 | 
			
		||||
            for (int i = 0; i < rowCount; ++i) {
 | 
			
		||||
                if (!gamelist->tree_view->isRowHidden(i, root_index)) {
 | 
			
		||||
                    ++resultCount;
 | 
			
		||||
                    child_file = gamelist->item_model->item(i, 0);
 | 
			
		||||
                    file_path = child_file->data(GameListItemPath::FullPathRole).toString();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (resultCount == 1) {
 | 
			
		||||
                // To avoid loading error dialog loops while confirming them using enter
 | 
			
		||||
                // Also users usually want to run a diffrent game after closing one
 | 
			
		||||
                gamelist->search_field->edit_filter->setText("");
 | 
			
		||||
                edit_filter_text = "";
 | 
			
		||||
                emit gamelist->GameChosen(file_path);
 | 
			
		||||
            } else {
 | 
			
		||||
                return QObject::eventFilter(obj, event);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            return QObject::eventFilter(obj, event);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    edit_filter_text_old = edit_filter_text;
 | 
			
		||||
    return QObject::eventFilter(obj, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::SearchField::setFilterResult(int visable, int total) {
 | 
			
		||||
    QString result_of_text = tr("of");
 | 
			
		||||
    QString result_text;
 | 
			
		||||
    if (total == 1) {
 | 
			
		||||
        result_text = tr("result");
 | 
			
		||||
    } else {
 | 
			
		||||
        result_text = tr("results");
 | 
			
		||||
    }
 | 
			
		||||
    label_filter_result->setText(
 | 
			
		||||
        QString("%1 %2 %3 %4").arg(visable).arg(result_of_text).arg(total).arg(result_text));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::SearchField::clear() {
 | 
			
		||||
    edit_filter->setText("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::SearchField::setFocus() {
 | 
			
		||||
    if (edit_filter->isVisible()) {
 | 
			
		||||
        edit_filter->setFocus();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} {
 | 
			
		||||
    KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent);
 | 
			
		||||
    layout_filter = new QHBoxLayout;
 | 
			
		||||
    layout_filter->setMargin(8);
 | 
			
		||||
    label_filter = new QLabel;
 | 
			
		||||
    label_filter->setText(tr("Filter:"));
 | 
			
		||||
    edit_filter = new QLineEdit;
 | 
			
		||||
    edit_filter->setText("");
 | 
			
		||||
    edit_filter->setPlaceholderText(tr("Enter pattern to filter"));
 | 
			
		||||
    edit_filter->installEventFilter(keyReleaseEater);
 | 
			
		||||
    edit_filter->setClearButtonEnabled(true);
 | 
			
		||||
    connect(edit_filter, SIGNAL(textChanged(const QString&)), parent,
 | 
			
		||||
            SLOT(onTextChanged(const QString&)));
 | 
			
		||||
    label_filter_result = new QLabel;
 | 
			
		||||
    button_filter_close = new QToolButton(this);
 | 
			
		||||
    button_filter_close->setText("X");
 | 
			
		||||
    button_filter_close->setCursor(Qt::ArrowCursor);
 | 
			
		||||
    button_filter_close->setStyleSheet("QToolButton{ border: none; padding: 0px; color: "
 | 
			
		||||
                                       "#000000; font-weight: bold; background: #F0F0F0; }"
 | 
			
		||||
                                       "QToolButton:hover{ border: none; padding: 0px; color: "
 | 
			
		||||
                                       "#EEEEEE; font-weight: bold; background: #E81123}");
 | 
			
		||||
    connect(button_filter_close, SIGNAL(clicked()), parent, SLOT(onFilterCloseClicked()));
 | 
			
		||||
    layout_filter->setSpacing(10);
 | 
			
		||||
    layout_filter->addWidget(label_filter);
 | 
			
		||||
    layout_filter->addWidget(edit_filter);
 | 
			
		||||
    layout_filter->addWidget(label_filter_result);
 | 
			
		||||
    layout_filter->addWidget(button_filter_close);
 | 
			
		||||
    setLayout(layout_filter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Checks if all words separated by spaces are contained in another string
 | 
			
		||||
* This offers a word order insensitive search function
 | 
			
		||||
*
 | 
			
		||||
* @param String that gets checked if it contains all words of the userinput string
 | 
			
		||||
* @param String containing all words getting checked
 | 
			
		||||
* @return true if the haystack contains all words of userinput
 | 
			
		||||
*/
 | 
			
		||||
bool GameList::containsAllWords(QString haystack, QString userinput) {
 | 
			
		||||
    QStringList userinput_split = userinput.split(" ", QString::SplitBehavior::SkipEmptyParts);
 | 
			
		||||
    return std::all_of(userinput_split.begin(), userinput_split.end(),
 | 
			
		||||
                       [haystack](QString s) { return haystack.contains(s); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Event in order to filter the gamelist after editing the searchfield
 | 
			
		||||
void GameList::onTextChanged(const QString& newText) {
 | 
			
		||||
    int rowCount = tree_view->model()->rowCount();
 | 
			
		||||
    QString edit_filter_text = newText.toLower();
 | 
			
		||||
 | 
			
		||||
    QModelIndex root_index = item_model->invisibleRootItem()->index();
 | 
			
		||||
 | 
			
		||||
    // If the searchfield is empty every item is visible
 | 
			
		||||
    // Otherwise the filter gets applied
 | 
			
		||||
    if (edit_filter_text.isEmpty()) {
 | 
			
		||||
        for (int i = 0; i < rowCount; ++i) {
 | 
			
		||||
            tree_view->setRowHidden(i, root_index, false);
 | 
			
		||||
        }
 | 
			
		||||
        search_field->setFilterResult(rowCount, rowCount);
 | 
			
		||||
    } else {
 | 
			
		||||
        QStandardItem* child_file;
 | 
			
		||||
        QString file_path, file_name, file_title, file_programmid;
 | 
			
		||||
        int result_count = 0;
 | 
			
		||||
        for (int i = 0; i < rowCount; ++i) {
 | 
			
		||||
            child_file = item_model->item(i, 0);
 | 
			
		||||
            file_path = child_file->data(GameListItemPath::FullPathRole).toString().toLower();
 | 
			
		||||
            file_name = file_path.mid(file_path.lastIndexOf("/") + 1);
 | 
			
		||||
            file_title = child_file->data(GameListItemPath::TitleRole).toString().toLower();
 | 
			
		||||
            file_programmid =
 | 
			
		||||
                child_file->data(GameListItemPath::ProgramIdRole).toString().toLower();
 | 
			
		||||
 | 
			
		||||
            // Only items which filename in combination with its title contains all words
 | 
			
		||||
            // that are in the searchfiel will be visible in the gamelist
 | 
			
		||||
            // The search is case insensitive because of toLower()
 | 
			
		||||
            // I decided not to use Qt::CaseInsensitive in containsAllWords to prevent
 | 
			
		||||
            // multiple conversions of edit_filter_text for each game in the gamelist
 | 
			
		||||
            if (containsAllWords(file_name.append(" ").append(file_title), edit_filter_text) ||
 | 
			
		||||
                (file_programmid.count() == 16 && edit_filter_text.contains(file_programmid))) {
 | 
			
		||||
                tree_view->setRowHidden(i, root_index, false);
 | 
			
		||||
                ++result_count;
 | 
			
		||||
            } else {
 | 
			
		||||
                tree_view->setRowHidden(i, root_index, true);
 | 
			
		||||
            }
 | 
			
		||||
            search_field->setFilterResult(result_count, rowCount);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::onFilterCloseClicked() {
 | 
			
		||||
    main_window->filterBarSetChecked(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GameList::GameList(GMainWindow* parent) : QWidget{parent} {
 | 
			
		||||
    this->main_window = parent;
 | 
			
		||||
    layout = new QVBoxLayout;
 | 
			
		||||
    tree_view = new QTreeView;
 | 
			
		||||
    search_field = new SearchField(this);
 | 
			
		||||
    item_model = new QStandardItemModel(tree_view);
 | 
			
		||||
    tree_view->setModel(item_model);
 | 
			
		||||
 | 
			
		||||
@ -46,7 +225,9 @@ GameList::GameList(QWidget* parent) : QWidget{parent} {
 | 
			
		||||
    qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
 | 
			
		||||
 | 
			
		||||
    layout->setContentsMargins(0, 0, 0, 0);
 | 
			
		||||
    layout->setSpacing(0);
 | 
			
		||||
    layout->addWidget(tree_view);
 | 
			
		||||
    layout->addWidget(search_field);
 | 
			
		||||
    setLayout(layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -54,6 +235,18 @@ GameList::~GameList() {
 | 
			
		||||
    emit ShouldCancelWorker();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::setFilterFocus() {
 | 
			
		||||
    search_field->setFocus();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::setFilterVisible(bool visablility) {
 | 
			
		||||
    search_field->setVisible(visablility);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::clearFilter() {
 | 
			
		||||
    search_field->clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::AddEntry(const QList<QStandardItem*>& entry_items) {
 | 
			
		||||
    item_model->invisibleRootItem()->appendRow(entry_items);
 | 
			
		||||
}
 | 
			
		||||
@ -69,11 +262,16 @@ void GameList::ValidateEntry(const QModelIndex& item) {
 | 
			
		||||
    std::string std_file_path(file_path.toStdString());
 | 
			
		||||
    if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path))
 | 
			
		||||
        return;
 | 
			
		||||
    // Users usually want to run a diffrent game after closing one
 | 
			
		||||
    search_field->clear();
 | 
			
		||||
    emit GameChosen(file_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::DonePopulating() {
 | 
			
		||||
    tree_view->setEnabled(true);
 | 
			
		||||
    int rowCount = tree_view->model()->rowCount();
 | 
			
		||||
    search_field->setFilterResult(rowCount, rowCount);
 | 
			
		||||
    search_field->setFocus();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameList::PopupContextMenu(const QPoint& menu_location) {
 | 
			
		||||
@ -151,25 +349,26 @@ static bool HasSupportedFileExtension(const std::string& file_name) {
 | 
			
		||||
void GameList::RefreshGameDirectory() {
 | 
			
		||||
    if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) {
 | 
			
		||||
        LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list.");
 | 
			
		||||
        search_field->clear();
 | 
			
		||||
        PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adds the game list folder to the QFileSystemWatcher to check for updates.
 | 
			
		||||
 *
 | 
			
		||||
 * The file watcher will fire off an update to the game list when a change is detected in the game
 | 
			
		||||
 * list folder.
 | 
			
		||||
 *
 | 
			
		||||
 * Notice: This method is run on the UI thread because QFileSystemWatcher is not thread safe and
 | 
			
		||||
 * this function is fast enough to not stall the UI thread. If performance is an issue, it should
 | 
			
		||||
 * be moved to another thread and properly locked to prevent concurrency issues.
 | 
			
		||||
 *
 | 
			
		||||
 * @param dir folder to check for changes in
 | 
			
		||||
 * @param recursion 0 if recursion is disabled. Any positive number passed to this will add each
 | 
			
		||||
 *        directory recursively to the watcher and will update the file list if any of the folders
 | 
			
		||||
 *        change. The number determines how deep the recursion should traverse.
 | 
			
		||||
 */
 | 
			
		||||
* Adds the game list folder to the QFileSystemWatcher to check for updates.
 | 
			
		||||
*
 | 
			
		||||
* The file watcher will fire off an update to the game list when a change is detected in the game
 | 
			
		||||
* list folder.
 | 
			
		||||
*
 | 
			
		||||
* Notice: This method is run on the UI thread because QFileSystemWatcher is not thread safe and
 | 
			
		||||
* this function is fast enough to not stall the UI thread. If performance is an issue, it should
 | 
			
		||||
* be moved to another thread and properly locked to prevent concurrency issues.
 | 
			
		||||
*
 | 
			
		||||
* @param dir folder to check for changes in
 | 
			
		||||
* @param recursion 0 if recursion is disabled. Any positive number passed to this will add each
 | 
			
		||||
*        directory recursively to the watcher and will update the file list if any of the folders
 | 
			
		||||
*        change. The number determines how deep the recursion should traverse.
 | 
			
		||||
*/
 | 
			
		||||
void GameList::UpdateWatcherList(const std::string& dir, unsigned int recursion) {
 | 
			
		||||
    const auto callback = [this, recursion](unsigned* num_entries_out, const std::string& directory,
 | 
			
		||||
                                            const std::string& virtual_name) -> bool {
 | 
			
		||||
 | 
			
		||||
@ -5,13 +5,19 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QFileSystemWatcher>
 | 
			
		||||
#include <QHBoxLayout>
 | 
			
		||||
#include <QLabel>
 | 
			
		||||
#include <QLineEdit>
 | 
			
		||||
#include <QModelIndex>
 | 
			
		||||
#include <QSettings>
 | 
			
		||||
#include <QStandardItem>
 | 
			
		||||
#include <QStandardItemModel>
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QToolButton>
 | 
			
		||||
#include <QTreeView>
 | 
			
		||||
#include <QVBoxLayout>
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
#include "main.h"
 | 
			
		||||
 | 
			
		||||
class GameListWorker;
 | 
			
		||||
 | 
			
		||||
@ -26,9 +32,40 @@ public:
 | 
			
		||||
        COLUMN_COUNT, // Number of columns
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    explicit GameList(QWidget* parent = nullptr);
 | 
			
		||||
    class SearchField : public QWidget {
 | 
			
		||||
    public:
 | 
			
		||||
        void setFilterResult(int visable, int total);
 | 
			
		||||
        void clear();
 | 
			
		||||
        void setFocus();
 | 
			
		||||
        explicit SearchField(GameList* parent = nullptr);
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        class KeyReleaseEater : public QObject {
 | 
			
		||||
        public:
 | 
			
		||||
            explicit KeyReleaseEater(GameList* gamelist);
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            GameList* gamelist = nullptr;
 | 
			
		||||
            QString edit_filter_text_old;
 | 
			
		||||
 | 
			
		||||
        protected:
 | 
			
		||||
            bool eventFilter(QObject* obj, QEvent* event);
 | 
			
		||||
        };
 | 
			
		||||
        QHBoxLayout* layout_filter = nullptr;
 | 
			
		||||
        QTreeView* tree_view = nullptr;
 | 
			
		||||
        QLabel* label_filter = nullptr;
 | 
			
		||||
        QLineEdit* edit_filter = nullptr;
 | 
			
		||||
        QLabel* label_filter_result = nullptr;
 | 
			
		||||
        QToolButton* button_filter_close = nullptr;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    explicit GameList(GMainWindow* parent = nullptr);
 | 
			
		||||
    ~GameList() override;
 | 
			
		||||
 | 
			
		||||
    void clearFilter();
 | 
			
		||||
    void setFilterFocus();
 | 
			
		||||
    void setFilterVisible(bool visablility);
 | 
			
		||||
 | 
			
		||||
    void PopulateAsync(const QString& dir_path, bool deep_scan);
 | 
			
		||||
 | 
			
		||||
    void SaveInterfaceLayout();
 | 
			
		||||
@ -41,6 +78,10 @@ signals:
 | 
			
		||||
    void ShouldCancelWorker();
 | 
			
		||||
    void OpenSaveFolderRequested(u64 program_id);
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
    void onTextChanged(const QString& newText);
 | 
			
		||||
    void onFilterCloseClicked();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void AddEntry(const QList<QStandardItem*>& entry_items);
 | 
			
		||||
    void ValidateEntry(const QModelIndex& item);
 | 
			
		||||
@ -49,7 +90,11 @@ private:
 | 
			
		||||
    void PopupContextMenu(const QPoint& menu_location);
 | 
			
		||||
    void UpdateWatcherList(const std::string& path, unsigned int recursion);
 | 
			
		||||
    void RefreshGameDirectory();
 | 
			
		||||
    bool containsAllWords(QString haystack, QString userinput);
 | 
			
		||||
 | 
			
		||||
    SearchField* search_field;
 | 
			
		||||
    GMainWindow* main_window = nullptr;
 | 
			
		||||
    QVBoxLayout* layout = nullptr;
 | 
			
		||||
    QTreeView* tree_view = nullptr;
 | 
			
		||||
    QStandardItemModel* item_model = nullptr;
 | 
			
		||||
    GameListWorker* current_worker = nullptr;
 | 
			
		||||
 | 
			
		||||
@ -93,7 +93,7 @@ void GMainWindow::InitializeWidgets() {
 | 
			
		||||
    render_window = new GRenderWindow(this, emu_thread.get());
 | 
			
		||||
    render_window->hide();
 | 
			
		||||
 | 
			
		||||
    game_list = new GameList();
 | 
			
		||||
    game_list = new GameList(this);
 | 
			
		||||
    ui.horizontalLayout->addWidget(game_list);
 | 
			
		||||
 | 
			
		||||
    // Create status bar
 | 
			
		||||
@ -247,6 +247,9 @@ void GMainWindow::RestoreUIState() {
 | 
			
		||||
    ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
 | 
			
		||||
    OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
 | 
			
		||||
 | 
			
		||||
    ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
 | 
			
		||||
    game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
 | 
			
		||||
 | 
			
		||||
    ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
 | 
			
		||||
    statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
 | 
			
		||||
}
 | 
			
		||||
@ -283,6 +286,8 @@ void GMainWindow::ConnectMenuEvents() {
 | 
			
		||||
            &GMainWindow::ToggleWindowMode);
 | 
			
		||||
    connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
 | 
			
		||||
            &GMainWindow::OnDisplayTitleBars);
 | 
			
		||||
    ui.action_Show_Filter_Bar->setShortcut(tr("CTRL+F"));
 | 
			
		||||
    connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
 | 
			
		||||
    connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -444,6 +449,7 @@ void GMainWindow::ShutdownGame() {
 | 
			
		||||
    ui.action_Stop->setEnabled(false);
 | 
			
		||||
    render_window->hide();
 | 
			
		||||
    game_list->show();
 | 
			
		||||
    game_list->setFilterFocus();
 | 
			
		||||
 | 
			
		||||
    // Disable status bar updates
 | 
			
		||||
    status_bar_update_timer.stop();
 | 
			
		||||
@ -617,6 +623,15 @@ void GMainWindow::OnConfigure() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnToggleFilterBar() {
 | 
			
		||||
    game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
 | 
			
		||||
    if (ui.action_Show_Filter_Bar->isChecked()) {
 | 
			
		||||
        game_list->setFilterFocus();
 | 
			
		||||
    } else {
 | 
			
		||||
        game_list->clearFilter();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnSwapScreens() {
 | 
			
		||||
    Settings::values.swap_screen = !Settings::values.swap_screen;
 | 
			
		||||
    Settings::Apply();
 | 
			
		||||
@ -671,6 +686,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
 | 
			
		||||
#endif
 | 
			
		||||
    UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
 | 
			
		||||
    UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
 | 
			
		||||
    UISettings::values.show_filter_bar = ui.action_Show_Filter_Bar->isChecked();
 | 
			
		||||
    UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked();
 | 
			
		||||
    UISettings::values.first_start = false;
 | 
			
		||||
 | 
			
		||||
@ -720,6 +736,11 @@ bool GMainWindow::ConfirmChangeGame() {
 | 
			
		||||
    return answer != QMessageBox::No;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::filterBarSetChecked(bool state) {
 | 
			
		||||
    ui.action_Show_Filter_Bar->setChecked(state);
 | 
			
		||||
    emit(OnToggleFilterBar());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef main
 | 
			
		||||
#undef main
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QMainWindow>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
#include "ui_main.h"
 | 
			
		||||
 | 
			
		||||
class CallstackWidget;
 | 
			
		||||
@ -41,6 +42,7 @@ class GMainWindow : public QMainWindow {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    void filterBarSetChecked(bool state);
 | 
			
		||||
    GMainWindow();
 | 
			
		||||
    ~GMainWindow();
 | 
			
		||||
 | 
			
		||||
@ -122,6 +124,7 @@ private slots:
 | 
			
		||||
    void OnMenuRecentFile();
 | 
			
		||||
    void OnSwapScreens();
 | 
			
		||||
    void OnConfigure();
 | 
			
		||||
    void OnToggleFilterBar();
 | 
			
		||||
    void OnDisplayTitleBars(bool);
 | 
			
		||||
    void ToggleWindowMode();
 | 
			
		||||
    void OnCreateGraphicsSurfaceViewer();
 | 
			
		||||
 | 
			
		||||
@ -88,6 +88,7 @@
 | 
			
		||||
    </widget>
 | 
			
		||||
    <addaction name="action_Single_Window_Mode"/>
 | 
			
		||||
    <addaction name="action_Display_Dock_Widget_Headers"/>
 | 
			
		||||
    <addaction name="action_Show_Filter_Bar"/>
 | 
			
		||||
    <addaction name="action_Show_Status_Bar"/>
 | 
			
		||||
    <addaction name="menu_View_Debugging"/>
 | 
			
		||||
   </widget>
 | 
			
		||||
@ -167,6 +168,14 @@
 | 
			
		||||
    <string>Display Dock Widget Headers</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="action_Show_Filter_Bar">
 | 
			
		||||
   <property name="checkable">
 | 
			
		||||
    <bool>true</bool>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="text">
 | 
			
		||||
    <string>Show Filter Bar</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="action_Show_Status_Bar">
 | 
			
		||||
   <property name="checkable">
 | 
			
		||||
    <bool>true</bool>
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ struct Values {
 | 
			
		||||
 | 
			
		||||
    bool single_window_mode;
 | 
			
		||||
    bool display_titlebar;
 | 
			
		||||
    bool show_filter_bar;
 | 
			
		||||
    bool show_status_bar;
 | 
			
		||||
 | 
			
		||||
    bool confirm_before_closing;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user