Grid Mode + Tool Bar (#2857)

* Grid layout

* Add Tiny Mode
fix scrolling
fix maxGamesPerRow calculation

* prime empty toolbar

* Add Search Bar, Icon Size and List Mode to ToolBar
Fix some minor glitches

* fix toolbar save and adjust default margin

* fix toolbar regression
minor simplification in Refresh

* Implement search and rename PopulateUI to PopulateGameList

* minor refactoring hehehehehehe

* Fix crash

* refresh speedboost optimizations

* Small refactoring of refresh to have default argument of false.

* add icons to toolbar

* fix scrambed order

* search for serial as well
This commit is contained in:
Megamouse 2017-06-11 16:07:00 +02:00 committed by Ani
parent 9aa632bcc1
commit a3d1f7b7b0
28 changed files with 1023 additions and 425 deletions

BIN
rpcs3/Icons/copy_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
rpcs3/Icons/copy_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
rpcs3/Icons/disc_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
rpcs3/Icons/disc_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
rpcs3/Icons/grid_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
rpcs3/Icons/grid_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
rpcs3/Icons/home_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
rpcs3/Icons/home_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
rpcs3/Icons/info_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
rpcs3/Icons/info_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
rpcs3/Icons/list_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
rpcs3/Icons/list_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
rpcs3/Icons/media_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
rpcs3/Icons/media_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -5,5 +5,21 @@
<file>Icons/restart.png</file> <file>Icons/restart.png</file>
<file>Icons/stop.png</file> <file>Icons/stop.png</file>
<file>rpcs3.ico</file> <file>rpcs3.ico</file>
<file>Icons/copy_blue.png</file>
<file>Icons/disc_blue.png</file>
<file>Icons/grid_blue.png</file>
<file>Icons/harddisk_blue.png</file>
<file>Icons/home_blue.png</file>
<file>Icons/info_blue.png</file>
<file>Icons/list_blue.png</file>
<file>Icons/media_blue.png</file>
<file>Icons/copy_gray.png</file>
<file>Icons/disc_gray.png</file>
<file>Icons/grid_gray.png</file>
<file>Icons/harddisk_gray.png</file>
<file>Icons/home_gray.png</file>
<file>Icons/info_gray.png</file>
<file>Icons/list_gray.png</file>
<file>Icons/media_gray.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -392,6 +392,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_game_list_grid.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_graphics_tab.cpp"> <ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_graphics_tab.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@ -532,6 +537,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_game_list_grid.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_graphics_tab.cpp"> <ClCompile Include="QTGeneratedFiles\Debug\moc_graphics_tab.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
@ -682,6 +692,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_game_list_grid.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_graphics_tab.cpp"> <ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_graphics_tab.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
@ -822,6 +837,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_game_list_grid.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_graphics_tab.cpp"> <ClCompile Include="QTGeneratedFiles\Release\moc_graphics_tab.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@ -917,6 +937,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="rpcs3qt\game_list_grid.cpp" />
<ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp" />
<ClCompile Include="rpcs3qt\welcome_dialog.cpp" /> <ClCompile Include="rpcs3qt\welcome_dialog.cpp" />
<ClCompile Include="rpcs3_app.cpp" /> <ClCompile Include="rpcs3_app.cpp" />
<ClCompile Include="rpcs3qt\audio_tab.cpp" /> <ClCompile Include="rpcs3qt\audio_tab.cpp" />
@ -1387,6 +1409,25 @@
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild> </CustomBuild>
<CustomBuild Include="rpcs3qt\game_list_grid.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">Moc%27ing game_list_grid.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing game_list_grid.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing game_list_grid.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">Moc%27ing game_list_grid.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
</CustomBuild>
<ClInclude Include="rpcs3qt\game_list_grid_delegate.h" />
<ClInclude Include="rpcs3qt\gl_gs_frame.h" /> <ClInclude Include="rpcs3qt\gl_gs_frame.h" />
<ClInclude Include="rpcs3qt\instruction_editor_dialog.h" /> <ClInclude Include="rpcs3qt\instruction_editor_dialog.h" />
<ClInclude Include="rpcs3qt\memory_viewer_panel.h" /> <ClInclude Include="rpcs3qt\memory_viewer_panel.h" />

View File

@ -513,6 +513,24 @@
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_welcome_dialog.cpp"> <ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_welcome_dialog.cpp">
<Filter>Generated Files\Debug - LLVM</Filter> <Filter>Generated Files\Debug - LLVM</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="rpcs3qt\game_list_grid.cpp">
<Filter>Gui</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_game_list_grid.cpp">
<Filter>Generated Files\Release - LLVM</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_game_list_grid.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_game_list_grid.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_game_list_grid.cpp">
<Filter>Generated Files\Debug - LLVM</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp">
<Filter>Gui</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="\Gui\*.h"> <ClInclude Include="\Gui\*.h">
@ -549,6 +567,9 @@
<ClInclude Include="rpcs3qt\register_editor_dialog.h"> <ClInclude Include="rpcs3qt\register_editor_dialog.h">
<Filter>Gui</Filter> <Filter>Gui</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="rpcs3qt\game_list_grid_delegate.h">
<Filter>Gui</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="debug\moc_predefs.h.cbt"> <CustomBuild Include="debug\moc_predefs.h.cbt">
@ -644,5 +665,8 @@
<CustomBuild Include="rpcs3qt\welcome_dialog.h"> <CustomBuild Include="rpcs3qt\welcome_dialog.h">
<Filter>Gui</Filter> <Filter>Gui</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="rpcs3qt\game_list_grid.h">
<Filter>Gui</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -20,46 +20,134 @@
#include <QProcess> #include <QProcess>
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>
#include <QLabel>
static const std::string m_class_name = "GameViewer"; static const std::string m_class_name = "GameViewer";
inline std::string sstr(const QString& _in) { return _in.toUtf8().toStdString(); } inline std::string sstr(const QString& _in) { return _in.toUtf8().toStdString(); }
// Auxiliary classes
class sortGameData
{
int sortColumn;
bool sortAscending;
public:
sortGameData(u32 column, bool ascending) : sortColumn(column), sortAscending(ascending) {}
bool operator()(const GameInfo& game1, const GameInfo& game2) const
{
// Note that the column index has to match the appropriate GameInfo member
switch (sortColumn - 1) // skip *icon* column
{
case 0: return sortAscending ? (game1.name < game2.name) : (game1.name > game2.name);
case 1: return sortAscending ? (game1.serial < game2.serial) : (game1.serial > game2.serial);
case 2: return sortAscending ? (game1.fw < game2.fw) : (game1.fw > game2.fw);
case 3: return sortAscending ? (game1.app_ver < game2.app_ver) : (game1.app_ver > game2.app_ver);
case 4: return sortAscending ? (game1.category < game2.category) : (game1.category > game2.category);
case 5: return sortAscending ? (game1.root < game2.root) : (game1.root > game2.root);
default: return false;
}
}
};
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_Creator r_Creator, QWidget *parent) game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_Creator r_Creator, QWidget *parent)
: QDockWidget(tr("Game List"), parent), xgui_settings(settings), m_Render_Creator(r_Creator) : QDockWidget(tr("Game List"), parent), xgui_settings(settings), m_Render_Creator(r_Creator)
{ {
m_Icon_Size = GUI::gl_icon_size.at(m_gui_settings->GetValue(GUI::gl_iconSize).toString()); m_isListLayout = xgui_settings->GetValue(GUI::gl_listMode).toBool();
m_Icon_Size_Str = xgui_settings->GetValue(GUI::gl_iconSize).toString();
m_Margin_Factor = xgui_settings->GetValue(GUI::gl_marginFactor).toReal();
m_Text_Factor = xgui_settings->GetValue(GUI::gl_textFactor).toReal();
m_showToolBar = xgui_settings->GetValue(GUI::gl_toolBarVisible).toBool();
m_columns = columns_arr(m_Icon_Size); // get icon size from list
int icon_size_index = 0;
for (int i = 0; i < GUI::gl_icon_size.count(); i++)
{
if (GUI::gl_icon_size.at(i).first == m_Icon_Size_Str)
{
m_Icon_Size = GUI::gl_icon_size.at(i).second;
icon_size_index = i;
break;
}
}
gameList = new QTableWidget(this); // Save factors for first setup
xgui_settings->SetValue(GUI::gl_marginFactor, m_Margin_Factor);
xgui_settings->SetValue(GUI::gl_textFactor, m_Text_Factor);
xgui_settings->SetValue(GUI::gl_toolBarVisible, m_showToolBar);
m_Game_Dock = new QMainWindow(this);
m_Game_Dock->setWindowFlags(Qt::Widget);
// Set up toolbar
m_Tool_Bar = new QToolBar(m_Game_Dock);
m_Tool_Bar->setMovable(false);
m_Tool_Bar->setVisible(m_showToolBar);
// ToolBar Actions
m_catActHDD = { new QAction(""), QIcon(":/Icons/harddisk_blue.png"), QIcon(":/Icons/harddisk_gray.png") };
m_catActHDD.action->setIcon(xgui_settings->GetValue(GUI::cat_hdd_game).toBool() ? m_catActHDD.colored : m_catActHDD.gray);
m_catActHDD.action->setToolTip(tr("Show HDD Category"));
m_catActDisc = { new QAction(""), QIcon(":/Icons/disc_blue.png"), QIcon(":/Icons/disc_gray.png") };
m_catActDisc.action->setIcon(xgui_settings->GetValue(GUI::cat_disc_game).toBool() ? m_catActDisc.colored : m_catActDisc.gray);
m_catActDisc.action->setToolTip(tr("Show Disc Category"));
m_catActHome = { new QAction(""), QIcon(":/Icons/home_blue.png"), QIcon(":/Icons/home_gray.png") };
m_catActHome.action->setIcon(xgui_settings->GetValue(GUI::cat_home).toBool() ? m_catActHome.colored : m_catActHome.gray);
m_catActHome.action->setToolTip(tr("Show Home Category"));
m_catActAudioVideo = { new QAction(""), QIcon(":/Icons/media_blue.png"), QIcon(":/Icons/media_gray.png") };
m_catActAudioVideo.action->setIcon(xgui_settings->GetValue(GUI::cat_audio_video).toBool() ? m_catActAudioVideo.colored : m_catActAudioVideo.gray);
m_catActAudioVideo.action->setToolTip(tr("Show Audio/Video Category"));
m_catActGameData = { new QAction(""), QIcon(":/Icons/copy_blue.png"), QIcon(":/Icons/copy_gray.png") };
m_catActGameData.action->setIcon(xgui_settings->GetValue(GUI::cat_game_data).toBool() ? m_catActGameData.colored : m_catActGameData.gray);
m_catActGameData.action->setToolTip(tr("Show GameData Category"));
m_catActUnknown = { new QAction(""), QIcon(":/Icons/info_blue.png"), QIcon(":/Icons/info_gray.png") };
m_catActUnknown.action->setIcon(xgui_settings->GetValue(GUI::cat_unknown).toBool() ? m_catActUnknown.colored : m_catActUnknown.gray);
m_catActUnknown.action->setToolTip(tr("Show Unknown Category"));
m_categoryButtons = { m_catActHDD , m_catActDisc, m_catActHome, m_catActAudioVideo, m_catActGameData, m_catActUnknown };
m_categoryActs = new QActionGroup(m_Tool_Bar);
m_categoryActs->addAction(m_catActHDD.action);
m_categoryActs->addAction(m_catActDisc.action);
m_categoryActs->addAction(m_catActHome.action);
m_categoryActs->addAction(m_catActAudioVideo.action);
m_categoryActs->addAction(m_catActGameData.action);
m_categoryActs->addAction(m_catActUnknown.action);
m_categoryActs->setEnabled(m_isListLayout);
m_modeActList = { new QAction(""), QIcon(":/Icons/list_blue.png"), QIcon(":/Icons/list_gray.png") };
m_modeActList.action->setIcon(m_isListLayout ? m_modeActList.colored : m_modeActList.gray);
m_modeActList.action->setToolTip(tr("Enable List Mode"));
m_modeActGrid = { new QAction(""), QIcon(":/Icons/grid_blue.png"), QIcon(":/Icons/grid_gray.png") };
m_modeActGrid.action->setIcon(m_isListLayout ? m_modeActGrid.gray : m_modeActGrid.colored);
m_modeActGrid.action->setToolTip(tr("Enable Grid Mode"));
m_modeActs = new QActionGroup(m_Tool_Bar);
m_modeActs->addAction(m_modeActList.action);
m_modeActs->addAction(m_modeActGrid.action);
// Search Bar
m_Search_Bar = new QLineEdit(m_Tool_Bar);
m_Search_Bar->setPlaceholderText(tr("Search games ..."));
connect(m_Search_Bar, &QLineEdit::textChanged, [this]() {
Refresh();
});
// Icon Size Slider
m_Slider_Size = new QSlider(Qt::Horizontal , m_Tool_Bar);
m_Slider_Size->setRange(0, GUI::gl_icon_size.size() - 1);
m_Slider_Size->setSliderPosition(icon_size_index);
m_Slider_Size->setFixedWidth(100);
m_Tool_Bar->addWidget(m_Search_Bar);
m_Tool_Bar->addWidget(new QLabel(" "));
m_Tool_Bar->addSeparator();
m_Tool_Bar->addWidget(new QLabel(" "));
m_Tool_Bar->addActions(m_categoryActs->actions());
m_Tool_Bar->addWidget(new QLabel(" "));
m_Tool_Bar->addSeparator();
m_Tool_Bar->addWidget(new QLabel(tr(" View Mode ")));
m_Tool_Bar->addAction(m_modeActList.action);
m_Tool_Bar->addAction(m_modeActGrid.action);
m_Tool_Bar->addWidget(new QLabel(tr(" ")));
m_Tool_Bar->addSeparator();
m_Tool_Bar->addWidget(new QLabel(tr(" Tiny "))); // Can this be any easier?
m_Tool_Bar->addWidget(m_Slider_Size);
m_Tool_Bar->addWidget(new QLabel(tr(" Large ")));
m_Game_Dock->addToolBar(m_Tool_Bar);
setWidget(m_Game_Dock);
bool showText = (m_Icon_Size_Str != GUI::gl_icon_key_small && m_Icon_Size_Str != GUI::gl_icon_key_tiny);
m_xgrid.reset(new game_list_grid(m_Icon_Size, m_Margin_Factor, m_Text_Factor, showText));
gameList = new QTableWidget();
gameList->setShowGrid(false); gameList->setShowGrid(false);
gameList->setItemDelegate(new table_item_delegate(this)); gameList->setItemDelegate(new table_item_delegate(this));
gameList->setSelectionBehavior(QAbstractItemView::SelectRows); gameList->setSelectionBehavior(QAbstractItemView::SelectRows);
gameList->setSelectionMode(QAbstractItemView::SingleSelection); gameList->setSelectionMode(QAbstractItemView::SingleSelection);
gameList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
gameList->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); gameList->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height()); gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height());
gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height()); gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height());
@ -67,7 +155,7 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_
gameList->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); gameList->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
gameList->setContextMenuPolicy(Qt::CustomContextMenu); gameList->setContextMenuPolicy(Qt::CustomContextMenu);
gameList->setColumnCount(7); gameList->setColumnCount(8);
gameList->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Icon"))); gameList->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Icon")));
gameList->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Name"))); gameList->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Name")));
gameList->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Serial"))); gameList->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Serial")));
@ -75,8 +163,16 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_
gameList->setHorizontalHeaderItem(4, new QTableWidgetItem(tr("App version"))); gameList->setHorizontalHeaderItem(4, new QTableWidgetItem(tr("App version")));
gameList->setHorizontalHeaderItem(5, new QTableWidgetItem(tr("Category"))); gameList->setHorizontalHeaderItem(5, new QTableWidgetItem(tr("Category")));
gameList->setHorizontalHeaderItem(6, new QTableWidgetItem(tr("Path"))); gameList->setHorizontalHeaderItem(6, new QTableWidgetItem(tr("Path")));
gameList->setHorizontalHeaderItem(7, new QTableWidgetItem(tr("Missingno"))); // Holds index which points back to original array
setWidget(gameList); gameList->setColumnHidden(7, true); // Comment this if your sorting ever for whatever reason messes up.
m_Central_Widget = new QStackedWidget(this);
m_Central_Widget->addWidget(gameList);
m_Central_Widget->addWidget(m_xgrid.get());
m_Central_Widget->setCurrentWidget(m_isListLayout ? gameList : m_xgrid.get());
m_Game_Dock->setCentralWidget(m_Central_Widget);
// Actions // Actions
showIconColAct = new QAction(tr("Show Icons"), this); showIconColAct = new QAction(tr("Show Icons"), this);
@ -99,6 +195,21 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_
connect(gameList, &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot); connect(gameList, &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot);
connect(gameList->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnColClicked); connect(gameList->horizontalHeader(), &QHeaderView::sectionClicked, this, &game_list_frame::OnColClicked);
connect(m_xgrid.get(), &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot);
connect(m_xgrid.get(), &QTableWidget::customContextMenuRequested, this, &game_list_frame::ShowContextMenu);
connect(m_Slider_Size, &QSlider::valueChanged, [=](int value) { emit RequestIconSizeActSet(value); });
connect(m_modeActs, &QActionGroup::triggered, [=](QAction* act) {
emit RequestListModeActSet(act == m_modeActList.action);
m_modeActList.action->setIcon(m_isListLayout ? m_modeActList.colored : m_modeActList.gray);
m_modeActGrid.action->setIcon(m_isListLayout ? m_modeActGrid.gray : m_modeActGrid.colored);
});
connect(m_categoryActs, &QActionGroup::triggered, [=](QAction* act) {
emit RequestCategoryActSet(m_categoryActs->actions().indexOf(act));
});
for (int col = 0; col < columnActs.count(); ++col) for (int col = 0; col < columnActs.count(); ++col)
{ {
columnActs[col]->setCheckable(true); columnActs[col]->setCheckable(true);
@ -120,11 +231,11 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> settings, Render_
gameList->setColumnHidden(col, !val); // Negate because it's a set col hidden and we have menu say show. gameList->setColumnHidden(col, !val); // Negate because it's a set col hidden and we have menu say show.
xgui_settings->SetGamelistColVisibility(col, val); xgui_settings->SetGamelistColVisibility(col, val);
}; };
columnActs[col]->setChecked(xgui_settings->GetGamelistColVisibility(col));
connect(columnActs[col], &QAction::triggered, l_CallBack); connect(columnActs[col], &QAction::triggered, l_CallBack);
} }
// Init // Init
Refresh(); // Data MUST be loaded so that first settings load will reset columns to correct width w/r to data.
LoadSettings(); LoadSettings();
} }
@ -138,7 +249,9 @@ void game_list_frame::LoadSettings()
columnActs[col]->setChecked(vis); columnActs[col]->setChecked(vis);
gameList->setColumnHidden(col, !vis); gameList->setColumnHidden(col, !vis);
} }
m_sortAscending = xgui_settings->GetValue(GUI::gl_sortAsc).toBool(); bool sortAsc = Qt::SortOrder(xgui_settings->GetValue(GUI::gl_sortAsc).toBool());
m_colSortOrder = sortAsc ? Qt::AscendingOrder : Qt::DescendingOrder;
m_sortColumn = xgui_settings->GetValue(GUI::gl_sortCol).toInt(); m_sortColumn = xgui_settings->GetValue(GUI::gl_sortCol).toInt();
m_categoryFilters = xgui_settings->GetGameListCategoryFilters(); m_categoryFilters = xgui_settings->GetGameListCategoryFilters();
@ -154,7 +267,7 @@ void game_list_frame::LoadSettings()
gameList->horizontalHeader()->restoreState(state); gameList->horizontalHeader()->restoreState(state);
} }
Refresh(); Refresh(true);
} }
game_list_frame::~game_list_frame() game_list_frame::~game_list_frame()
@ -164,46 +277,64 @@ game_list_frame::~game_list_frame()
void game_list_frame::OnColClicked(int col) void game_list_frame::OnColClicked(int col)
{ {
if (col == 0) return; // Don't "sort" icons.
if (col == m_sortColumn) if (col == m_sortColumn)
{ {
m_sortAscending ^= true; m_colSortOrder = (m_colSortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder;
} }
else else
{ {
m_sortAscending = true; m_colSortOrder = Qt::AscendingOrder;
} }
m_sortColumn = col; m_sortColumn = col;
xgui_settings->SetValue(GUI::gl_sortAsc, m_sortAscending); xgui_settings->SetValue(GUI::gl_sortAsc, m_colSortOrder == Qt::AscendingOrder);
xgui_settings->SetValue(GUI::gl_sortCol, col); xgui_settings->SetValue(GUI::gl_sortCol, col);
// Sort entries, update columns and refresh the panel gameList->sortByColumn(m_sortColumn, m_colSortOrder);
Refresh();
} }
// Filter for Categories
void game_list_frame::LoadGames() void game_list_frame::FilterData()
{ {
m_games.clear(); for (int i = 0; i < gameList->rowCount(); ++i)
for (const auto& entry : fs::dir(Emu.GetGameDir()))
{ {
if (entry.is_directory) bool match = false;
for (auto filter : m_categoryFilters)
{ {
m_games.push_back(entry.name); for (int j = 0; j < gameList->columnCount(); ++j)
{
if (gameList->horizontalHeaderItem(j)->text() == tr("Category") && gameList->item(i, j)->text().contains(filter))
{
match = true;
goto OutOfThis;
} }
} }
} }
OutOfThis:
gameList->setRowHidden(i, !match);
}
}
void game_list_frame::LoadPSF() void game_list_frame::Refresh(bool fromDrive)
{ {
if (fromDrive)
{
// Load PSF
m_game_data.clear(); m_game_data.clear();
const std::string& game_path = Emu.GetGameDir(); const std::string& game_path = Emu.GetGameDir();
for (u32 i = 0; i < m_games.size(); ++i) for (const auto& entry : fs::dir(Emu.GetGameDir()))
{ {
const std::string& dir = game_path + m_games[i]; if (!entry.is_directory)
{
continue;
}
const std::string& dir = game_path + entry.name;
const std::string& sfb = dir + "/PS3_DISC.SFB"; const std::string& sfb = dir + "/PS3_DISC.SFB";
const std::string& sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO"); const std::string& sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
@ -216,7 +347,7 @@ void game_list_frame::LoadPSF()
const auto& psf = psf::load_object(sfo_file); const auto& psf = psf::load_object(sfo_file);
GameInfo game; GameInfo game;
game.root = m_games[i]; game.root = entry.name;
game.serial = psf::get_string(psf, "TITLE_ID", ""); game.serial = psf::get_string(psf, "TITLE_ID", "");
game.name = psf::get_string(psf, "TITLE", "unknown"); game.name = psf::get_string(psf, "TITLE", "unknown");
game.app_ver = psf::get_string(psf, "APP_VER", "unknown"); game.app_ver = psf::get_string(psf, "APP_VER", "unknown");
@ -256,49 +387,68 @@ void game_list_frame::LoadPSF()
game.category = sstr(category::unknown); game.category = sstr(category::unknown);
} }
m_game_data.push_back(game); // Load Image
QImage img;
QPixmap pxmap;
if (!game.icon_path.empty() && img.load(qstr(game.icon_path)))
{
QImage scaled = img.scaled(m_Icon_Size, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation);
pxmap = QPixmap::fromImage(scaled);
}
else
{
img = QImage(m_Icon_Size, QImage::Format_ARGB32);
QString abspath = QDir(qstr(game.icon_path)).absolutePath();
LOG_ERROR(HLE, "Count not load image from path %s", sstr(abspath));
img.fill(QColor(0, 0, 0, 0));
pxmap = QPixmap::fromImage(img);
} }
// Sort entries and update columns m_game_data.push_back({ game, img, pxmap });
std::sort(m_game_data.begin(), m_game_data.end(), sortGameData(m_sortColumn, m_sortAscending));
m_columns.Update(m_game_data);
} }
void game_list_frame::ShowData() auto op = [](const GUI_GameInfo& game1, const GUI_GameInfo& game2) {
{ return game1.info.name < game2.info.name;
m_columns.ShowData(gameList); };
// Sort by name at the very least.
std::sort(m_game_data.begin(), m_game_data.end(), op);
} }
// Filter for Categories // Fill Game List / Game Grid
void game_list_frame::FilterData()
{
for (int i = 0; i < gameList->rowCount(); ++i)
{
bool match = false;
for (auto filter : m_categoryFilters)
{
for (int j = 0; j < gameList->columnCount(); ++j)
{
if (gameList->horizontalHeaderItem(j)->text() == tr("Category") && gameList->item(i, j)->text().contains(filter))
{
match = true;
goto OutOfThis;
}
}
}
OutOfThis:
gameList->setRowHidden(i, !match);
}
}
void game_list_frame::Refresh() if (m_isListLayout)
{ {
int row = gameList->currentRow(); int row = gameList->currentRow();
LoadGames();
LoadPSF(); PopulateGameList();
ShowData();
FilterData(); FilterData();
gameList->selectRow(row); gameList->selectRow(row);
gameList->sortByColumn(m_sortColumn, m_colSortOrder);
gameList->setColumnHidden(7, true);
gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height());
gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height());
gameList->resizeRowsToContents();
gameList->resizeColumnToContents(0);
}
else
{
if (m_Icon_Size.width() > 0 && m_Icon_Size.height() > 0)
{
m_games_per_row = width() / (m_Icon_Size.width() + m_Icon_Size.width() * m_xgrid.get()->getMarginFactor() * 2);
}
else
{
m_games_per_row = 0;
}
m_xgrid.reset(MakeGrid(m_games_per_row, m_Icon_Size));
connect(m_xgrid.get(), &QTableWidget::doubleClicked, this, &game_list_frame::doubleClickedSlot);
connect(m_xgrid.get(), &QTableWidget::customContextMenuRequested, this, &game_list_frame::ShowContextMenu);
m_Central_Widget->addWidget(m_xgrid.get());
m_Central_Widget->setCurrentWidget(m_xgrid.get());
}
} }
void game_list_frame::ToggleCategoryFilter(QString category, bool show) void game_list_frame::ToggleCategoryFilter(QString category, bool show)
@ -314,7 +464,7 @@ void game_list_frame::SaveSettings()
xgui_settings->SetGamelistColVisibility(col, columnActs[col]->isChecked()); xgui_settings->SetGamelistColVisibility(col, columnActs[col]->isChecked());
} }
xgui_settings->SetValue(GUI::gl_sortCol, m_sortColumn); xgui_settings->SetValue(GUI::gl_sortCol, m_sortColumn);
xgui_settings->SetValue(GUI::gl_sortAsc, m_sortAscending); xgui_settings->SetValue(GUI::gl_sortAsc, m_colSortOrder == Qt::AscendingOrder);
xgui_settings->SetValue(GUI::gl_state, gameList->horizontalHeader()->saveState()); xgui_settings->SetValue(GUI::gl_state, gameList->horizontalHeader()->saveState());
} }
@ -338,46 +488,83 @@ static void open_dir(const std::string& spath)
void game_list_frame::doubleClickedSlot(const QModelIndex& index) void game_list_frame::doubleClickedSlot(const QModelIndex& index)
{ {
int i = index.row(); int i;
QString category = qstr(m_game_data[i].category);
if (m_isListLayout)
{
i = gameList->item(index.row(), 7)->text().toInt();
}
else
{
i = m_xgrid->item(index.row(), index.column())->data(Qt::ItemDataRole::UserRole).toInt();
}
QString category = qstr(m_game_data[i].info.category);
// Boot these categories // Boot these categories
if (category == category::hdd_Game || category == category::disc_Game || category == category::audio_Video) if (category == category::hdd_Game || category == category::disc_Game || category == category::audio_Video)
{ {
const std::string& path = Emu.GetGameDir() + m_game_data[i].root; const std::string& path = Emu.GetGameDir() + m_game_data[i].info.root;
emit RequestIconPathSet(path); emit RequestIconPathSet(path);
Emu.Stop(); Emu.Stop();
if (!Emu.BootGame(path)) if (!Emu.BootGame(path))
{ {
LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].root); LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[i].info.root);
} }
else else
{ {
LOG_SUCCESS(LOADER, "Boot from gamelist per doubleclick: done"); LOG_SUCCESS(LOADER, "Boot from gamelist per doubleclick: done");
emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[i].serial + "] " + m_game_data[i].name))); emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[i].info.serial + "] " + m_game_data[i].info.name)));
} }
} }
else else
{ {
open_dir(Emu.GetGameDir() + m_game_data[i].root); open_dir(Emu.GetGameDir() + m_game_data[i].info.root);
} }
} }
void game_list_frame::ShowContextMenu(const QPoint &pos) // this is a slot void game_list_frame::ShowContextMenu(const QPoint &pos)
{
int index;
if (m_isListLayout)
{ {
int row = gameList->indexAt(pos).row(); int row = gameList->indexAt(pos).row();
QTableWidgetItem* item = gameList->item(row, 7);
if (item == nullptr) return; // null happens if you are double clicking in dockwidget area on nothing.
index = item->text().toInt();
}
else
{
int row = m_xgrid->indexAt(pos).row();
int col = m_xgrid->indexAt(pos).column();
QTableWidgetItem* item = m_xgrid->item(row, col);
if (item == nullptr) return; // null happens if you are double clicking in dockwidget area on nothing.
index = item->data(Qt::ItemDataRole::UserRole).toInt();
if (index == -1) return; // empty item shouldn't have context menu
}
ShowSpecifiedContextMenu(pos, index);
}
void game_list_frame::ShowSpecifiedContextMenu(const QPoint &pos, int row)
{
if (row == -1) if (row == -1)
{ {
return; // invalid return; // invalid
} }
// for most widgets QPoint globalPos;
QPoint globalPos = gameList->mapToGlobal(pos);
// for QAbstractScrollArea and derived classes you would use: if (m_isListLayout)
// QPoint globalPos = myWidget->viewport()->mapToGlobal(pos); {
globalPos = gameList->mapToGlobal(pos);
}
else
{
globalPos = m_xgrid->mapToGlobal(pos);
}
QMenu myMenu; QMenu myMenu;
@ -398,24 +585,27 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) // this is a slot
connect(boot, &QAction::triggered, [=]() {Boot(row); }); connect(boot, &QAction::triggered, [=]() {Boot(row); });
connect(configure, &QAction::triggered, [=]() { connect(configure, &QAction::triggered, [=]() {
settings_dialog(xgui_settings, m_Render_Creator, this, &m_game_data[row]).exec(); settings_dialog(xgui_settings, m_Render_Creator, this, &m_game_data[row].info).exec();
}); });
connect(removeGame, &QAction::triggered, [=]() { connect(removeGame, &QAction::triggered, [=]() {
if (QMessageBox::question(this, tr("Confirm Delete"), tr("Permanently delete files?")) == QMessageBox::Yes) if (QMessageBox::question(this, tr("Confirm Delete"), tr("Permanently delete files?")) == QMessageBox::Yes)
fs::remove_all(Emu.GetGameDir() + m_game_data[row].root); {
fs::remove_all(Emu.GetGameDir() + m_game_data[row].info.root);
m_game_data.erase(m_game_data.begin() + row);
Refresh(); Refresh();
}
}); });
connect(removeConfig, &QAction::triggered, [=]() {RemoveCustomConfiguration(row); }); connect(removeConfig, &QAction::triggered, [=]() {RemoveCustomConfiguration(row); });
connect(openGameFolder, &QAction::triggered, [=]() {open_dir(Emu.GetGameDir() + m_game_data[row].root); }); connect(openGameFolder, &QAction::triggered, [=]() {open_dir(Emu.GetGameDir() + m_game_data[row].info.root); });
connect(openConfig, &QAction::triggered, [=]() {open_dir(fs::get_config_dir() + "data/" + m_game_data[row].serial); }); connect(openConfig, &QAction::triggered, [=]() {open_dir(fs::get_config_dir() + "data/" + m_game_data[row].info.serial); });
connect(checkCompat, &QAction::triggered, [=]() { connect(checkCompat, &QAction::triggered, [=]() {
QString serial = qstr(m_game_data[row].serial); QString serial = qstr(m_game_data[row].info.serial);
QString link = "https://rpcs3.net/compatibility?g=" + serial; QString link = "https://rpcs3.net/compatibility?g=" + serial;
QDesktopServices::openUrl(QUrl(link)); QDesktopServices::openUrl(QUrl(link));
}); });
//Disable options depending on software category //Disable options depending on software category
QString category = qstr(m_game_data[row].category); QString category = qstr(m_game_data[row].info.category);
if (category == category::disc_Game) if (category == category::disc_Game)
{ {
@ -442,26 +632,26 @@ void game_list_frame::ShowContextMenu(const QPoint &pos) // this is a slot
void game_list_frame::Boot(int row) void game_list_frame::Boot(int row)
{ {
const std::string& path = Emu.GetGameDir() + m_game_data[row].root; const std::string& path = Emu.GetGameDir() + m_game_data[row].info.root;
emit RequestIconPathSet(path); emit RequestIconPathSet(path);
Emu.Stop(); Emu.Stop();
if (!Emu.BootGame(path)) if (!Emu.BootGame(path))
{ {
QMessageBox::warning(this, tr("Warning!"), tr("Failed to boot ") + qstr(m_game_data[row].root)); QMessageBox::warning(this, tr("Warning!"), tr("Failed to boot ") + qstr(m_game_data[row].info.root));
LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[row].root); LOG_ERROR(LOADER, "Failed to boot /dev_hdd0/game/%s", m_game_data[row].info.root);
} }
else else
{ {
LOG_SUCCESS(LOADER, "Boot from gamelist per Boot: done"); LOG_SUCCESS(LOADER, "Boot from gamelist per Boot: done");
emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[row].serial + "] " + m_game_data[row].name))); emit RequestAddRecentGame(q_string_pair(qstr(path), qstr("[" + m_game_data[row].info.serial + "] " + m_game_data[row].info.name)));
} }
} }
void game_list_frame::RemoveCustomConfiguration(int row) void game_list_frame::RemoveCustomConfiguration(int row)
{ {
const std::string config_path = fs::get_config_dir() + "data/" + m_game_data[row].serial + "/config.yml"; const std::string config_path = fs::get_config_dir() + "data/" + m_game_data[row].info.serial + "/config.yml";
if (fs::is_file(config_path)) if (fs::is_file(config_path))
{ {
@ -485,164 +675,48 @@ void game_list_frame::RemoveCustomConfiguration(int row)
} }
} }
void game_list_frame::ResizeIcons(QSize size) void game_list_frame::ResizeIcons(const QSize& size, const int& idx)
{ {
m_columns.m_Icon_Size = size; m_Slider_Size->setSliderPosition(idx);
m_Icon_Size_Str = GUI::gl_icon_size.at(idx).first;
xgui_settings->SetValue(GUI::gl_iconSize, m_Icon_Size_Str);
m_Icon_Size = size; m_Icon_Size = size;
gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height());
gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height()); for (size_t i = 0; i < m_game_data.size(); i++)
{
m_game_data[i].pxmap = QPixmap::fromImage(m_game_data[i].icon.scaled(m_Icon_Size, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation));
}
Refresh(); Refresh();
} }
columns_arr::columns_arr(QSize icon_Size) : m_Icon_Size(icon_Size) void game_list_frame::SetListMode(const bool& isList)
{ {
m_img_list = new QList<QImage*>(); m_isListLayout = isList;
m_columns.clear(); xgui_settings->SetValue(GUI::gl_listMode, isList);
m_columns.emplace_back(0, 90, "Icon");
m_columns.emplace_back(1, 160, "Name"); m_categoryActs->setEnabled(isList);
m_columns.emplace_back(2, 85, "Serial"); m_modeActList.action->setIcon(m_isListLayout ? m_modeActList.colored : m_modeActList.gray);
m_columns.emplace_back(3, 55, "FW"); m_modeActGrid.action->setIcon(m_isListLayout ? m_modeActGrid.gray : m_modeActGrid.colored);
m_columns.emplace_back(4, 55, "App version");
m_columns.emplace_back(5, 75, "Category"); Refresh();
m_columns.emplace_back(6, 160, "Path");
m_col_icon = &m_columns[0]; m_Central_Widget->setCurrentWidget(m_isListLayout ? gameList : m_xgrid.get());
m_col_name = &m_columns[1];
m_col_serial = &m_columns[2];
m_col_fw = &m_columns[3];
m_col_app_ver = &m_columns[4];
m_col_category = &m_columns[5];
m_col_path = &m_columns[6];
} }
Column* columns_arr::GetColumnByPos(u32 pos) void game_list_frame::SetToolBarVisible(const bool& showToolBar)
{ {
std::vector<Column *> columns; m_showToolBar = showToolBar;
for (u32 pos = 0; pos<m_columns.size(); pos++) m_Tool_Bar->setVisible(showToolBar);
{ xgui_settings->SetValue(GUI::gl_toolBarVisible, showToolBar);
for (u32 c = 0; c<m_columns.size(); ++c)
{
if (m_columns[c].pos != pos) continue;
columns.push_back(&m_columns[c]);
}
}
for (u32 c = 0; c<columns.size(); ++c)
{
if (!columns[c]->shown)
{
pos++;
continue;
}
if (columns[c]->pos != pos) continue;
return columns[c];
} }
return NULL; void game_list_frame::SetCategoryActIcon(const int& id, const bool& active)
}
void columns_arr::Update(const std::vector<GameInfo>& game_data)
{ {
m_img_list->clear(); m_categoryButtons.at(id).action->setIcon(active ? m_categoryButtons.at(id).colored : m_categoryButtons.at(id).gray);
m_col_icon->data.clear();
m_col_name->data.clear();
m_col_serial->data.clear();
m_col_fw->data.clear();
m_col_app_ver->data.clear();
m_col_category->data.clear();
m_col_path->data.clear();
m_icon_indexes.clear();
if (m_columns.size() == 0) return;
for (const auto& game : game_data)
{
m_col_icon->data.push_back(game.icon_path);
m_col_name->data.push_back(game.name);
m_col_serial->data.push_back(game.serial);
m_col_fw->data.push_back(game.fw);
m_col_app_ver->data.push_back(game.app_ver);
m_col_category->data.push_back(game.category);
m_col_path->data.push_back(game.root);
}
int c = 0;
// load icons
for (const auto& path : m_col_icon->data)
{
QImage* img = new QImage(m_Icon_Size, QImage::Format_ARGB32);
if (!path.empty())
{
// Load image.
bool success = img->load(qstr(path));
if (success)
{
m_img_list->append(new QImage(img->scaled(m_Icon_Size, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation)));
}
else {
// IIRC a load failure means blank image which is fine to have as a placeholder.
QString abspath = QDir(qstr(path)).absolutePath();
LOG_ERROR(HLE, "Could not load game icon image from path %s", sstr(abspath));
img->fill(QColor(0, 0, 0, 0));
m_img_list->append(img);
}
}
else
{
LOG_ERROR(HLE, "Could not load game icon image from empty path");
img->fill(QColor(0, 0, 0, 0));
m_img_list->append(img);
}
m_icon_indexes.push_back(c);
c++;
}
}
void columns_arr::ShowData(QTableWidget* table)
{
// Hack to delete everything without removing the headers.
table->setRowCount(0);
// Expect number of columns to be the same as number of icons.
table->setRowCount(m_img_list->length());
// Add icons.
for (int r = 0; r < m_img_list->length(); ++r)
{
QTableWidgetItem* iconItem = new QTableWidgetItem;
iconItem->setFlags(iconItem->flags() & ~Qt::ItemIsEditable);
iconItem->setData(Qt::DecorationRole, QPixmap::fromImage(*m_img_list->at(m_icon_indexes[r])));
table->setItem(r, 0, iconItem);
}
// Add the other data.
for (int c = 1; c < table->columnCount(); ++c)
{
Column* col = GetColumnByPos(c);
if (!col)
{
LOG_ERROR(HLE, "Columns loaded with error!");
return;
}
int numRows = col->data.size();
if (numRows != table->rowCount())
{
table->setRowCount(numRows);
LOG_WARNING(HLE, "Warning. Columns are of different size: number of icons %d number wanted: %d", m_img_list->length(), numRows);
}
for (int r = 0; r<col->data.size(); ++r)
{
QTableWidgetItem* curr = new QTableWidgetItem;
curr->setFlags(curr->flags() & ~Qt::ItemIsEditable);
QString text = qstr(col->data[r]);
curr->setText(text);
table->setItem(r, c, curr);
}
table->resizeRowsToContents();
table->resizeColumnToContents(0);
}
} }
void game_list_frame::closeEvent(QCloseEvent *event) void game_list_frame::closeEvent(QCloseEvent *event)
@ -650,3 +724,166 @@ void game_list_frame::closeEvent(QCloseEvent *event)
QDockWidget::closeEvent(event); QDockWidget::closeEvent(event);
emit game_list_frameClosed(); emit game_list_frameClosed();
} }
void game_list_frame::resizeEvent(QResizeEvent *event)
{
if (!m_isListLayout)
{
Refresh();
}
QDockWidget::resizeEvent(event);
}
/**
Cleans and readds entries to table widget in UI.
*/
void game_list_frame::PopulateGameList()
{
// Hack to delete everything without removing the headers.
gameList->setRowCount(0);
gameList->setRowCount(m_game_data.size());
auto l_GetItem = [](const std::string& text)
{
QTableWidgetItem* curr = new QTableWidgetItem;
curr->setFlags(curr->flags() & ~Qt::ItemIsEditable);
QString qtext = qstr(text);
curr->setText(qtext);
return curr;
};
int row = 0;
for (GUI_GameInfo game : m_game_data)
{
if (SearchMatchesApp(game.info.name, game.info.serial) == false)
{
// We aren't showing this entry. Decrement row count to avoid empty entries at end.
gameList->setRowCount(gameList->rowCount() - 1);
continue;
}
// Icon
QTableWidgetItem* iconItem = new QTableWidgetItem;
iconItem->setFlags(iconItem->flags() & ~Qt::ItemIsEditable);
iconItem->setData(Qt::DecorationRole, game.pxmap);
gameList->setItem(row, 0, iconItem);
gameList->setItem(row, 1, l_GetItem(game.info.name));
gameList->setItem(row, 2, l_GetItem(game.info.serial));
gameList->setItem(row, 3, l_GetItem(game.info.fw));
gameList->setItem(row, 4, l_GetItem(game.info.app_ver));
gameList->setItem(row, 5, l_GetItem(game.info.category));
gameList->setItem(row, 6, l_GetItem(game.info.root));
// A certain magical index which points back to the original game index.
// Essentially, this column makes the tablewidget's row into a map, accomplishing what columns did but much simpler.
QTableWidgetItem* index = new QTableWidgetItem;
index->setText(QString::number(row));
gameList->setItem(row, 7, index);
row++;
}
}
game_list_grid* game_list_frame::MakeGrid(uint maxCols, const QSize& image_size)
{
uint r = 0;
uint c = 0;
game_list_grid* grid;
bool showText = m_Icon_Size_Str != GUI::gl_icon_key_small && m_Icon_Size_Str != GUI::gl_icon_key_tiny;
if (m_Icon_Size_Str == GUI::gl_icon_key_medium)
{
grid = new game_list_grid(image_size, m_Margin_Factor, m_Text_Factor * 2, showText);
}
else
{
grid = new game_list_grid(image_size, m_Margin_Factor, m_Text_Factor, showText);
}
// Get number of things that'll be in grid and precompute grid size.
int entries = 0;
for (GUI_GameInfo game : m_game_data)
{
if (qstr(game.info.category) == category::disc_Game || qstr(game.info.category) == category::hdd_Game)
{
if (SearchMatchesApp(game.info.name, game.info.serial) == false)
{
continue;
}
++entries;
}
}
// Edge cases!
if (entries == 0)
{ // For whatever reason, 0%x is division by zero. Absolute nonsense by definition of modulus. But, I'll acquiesce.
return grid;
}
if (maxCols == 0)
{
maxCols = 1;
}
if (maxCols > entries)
{
maxCols = entries;
}
int needsExtraRow = (entries % maxCols) != 0;
int maxRows = needsExtraRow + entries / maxCols;
grid->setRowCount(maxRows);
grid->setColumnCount(maxCols);
for (uint i = 0; i < m_game_data.size(); i++)
{
if (SearchMatchesApp(m_game_data[i].info.name, m_game_data[i].info.serial) == false)
{
continue;
}
QString category = qstr(m_game_data[i].info.category);
if (category == category::hdd_Game || category == category::disc_Game)
{
grid->addItem(m_game_data[i].pxmap, qstr(m_game_data[i].info.name), i, r, c);
if (++c >= maxCols)
{
c = 0;
r++;
}
}
}
if (c != 0)
{ // if left over games exist -- if empty entries exist
for (int col = c; col < maxCols; ++col)
{
QTableWidgetItem* emptyItem = new QTableWidgetItem();
emptyItem->setFlags(Qt::NoItemFlags);
emptyItem->setData(Qt::UserRole, -1);
grid->setItem(r, col, emptyItem);
}
}
grid->resizeColumnsToContents();
grid->resizeRowsToContents();
return grid;
}
/**
* Returns false if the game should be hidden because it doesn't match search term in toolbar.
*/
bool game_list_frame::SearchMatchesApp(const std::string& name, const std::string& serial)
{
if (m_Search_Bar->text() != "")
{
QString searchText = m_Search_Bar->text().toLower();
return qstr(name).toLower().contains(searchText) || qstr(serial).toLower().contains(searchText);
}
return true;
}

View File

@ -4,63 +4,19 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/GameInfo.h" #include "Emu/GameInfo.h"
#include "game_list_grid.h"
#include "gui_settings.h" #include "gui_settings.h"
#include "emu_settings.h" #include "emu_settings.h"
#include <QDockWidget> #include <QDockWidget>
#include <QList> #include <QList>
#include <QTableWidget> #include <QTableWidget>
#include <QMainWindow>
#include <QToolBar>
#include <QLineEdit>
#include <QStackedWidget>
struct Column #include <memory>
{
u32 pos;
u32 width;
bool shown;
std::vector<std::string> data;
const std::string name;
const u32 def_pos;
const u32 def_width;
Column(const u32 _def_pos, const u32 _def_width, const std::string& _name)
: def_pos(_def_pos)
, def_width(_def_width)
, pos(_def_pos)
, width(_def_width)
, shown(true)
, name(_name)
{
data.clear();
}
};
struct columns_arr
{
std::vector<Column> m_columns;
columns_arr(){};
columns_arr(QSize icon_Size);
Column* GetColumnByPos(u32 pos);
public:
Column* m_col_icon;
Column* m_col_name;
Column* m_col_serial;
Column* m_col_fw;
Column* m_col_app_ver;
Column* m_col_category;
Column* m_col_path;
QSize m_Icon_Size;
QList<QImage*>* m_img_list;
std::vector<int> m_icon_indexes;
void Update(const std::vector<GameInfo>& game_data);
void ShowData(QTableWidget* list);
};
namespace category namespace category
{ {
@ -72,23 +28,28 @@ namespace category
const QString unknown = QObject::tr("Unknown"); const QString unknown = QObject::tr("Unknown");
} }
/* Having the icons associated with the game info simplifies logic internally */
typedef struct GUI_GameInfo
{
GameInfo info;
QImage icon;
QPixmap pxmap;
};
typedef struct Tool_Bar_Button
{
QAction* action;
QIcon colored;
QIcon gray;
};
class game_list_frame : public QDockWidget { class game_list_frame : public QDockWidget {
Q_OBJECT Q_OBJECT
int m_sortColumn;
bool m_sortAscending;
std::vector<std::string> m_games;
std::vector<GameInfo> m_game_data;
gui_settings* m_gui_settings = new gui_settings(this);
QSize m_Icon_Size;
columns_arr m_columns;
QStringList m_categoryFilters;
Render_Creator m_Render_Creator;
public: public:
explicit game_list_frame(std::shared_ptr<gui_settings> settings, Render_Creator r_Creator, QWidget *parent = nullptr); explicit game_list_frame(std::shared_ptr<gui_settings> settings, Render_Creator r_Creator, QWidget *parent = nullptr);
~game_list_frame(); ~game_list_frame();
void Refresh(); void Refresh(const bool fromDrive = false);
void ToggleCategoryFilter(QString category, bool show); void ToggleCategoryFilter(QString category, bool show);
/** Loads from settings. Public so that main frame can easily reset these settings if needed. */ /** Loads from settings. Public so that main frame can easily reset these settings if needed. */
@ -99,31 +60,46 @@ public:
public slots: public slots:
/** Resize Gamelist Icons to size */ /** Resize Gamelist Icons to size */
void ResizeIcons(QSize size); void ResizeIcons(const QSize& size, const int& idx);
void SetListMode(const bool& isList);
void SetToolBarVisible(const bool& showToolBar);
void SetCategoryActIcon(const int& id, const bool& active);
private slots: private slots:
void Boot(int row); void Boot(int row);
void RemoveCustomConfiguration(int row); void RemoveCustomConfiguration(int row);
void OnColClicked(int col); void OnColClicked(int col);
void ShowContextMenu(const QPoint &pos);
void ShowSpecifiedContextMenu(const QPoint &pos, int index); // Different name because the notation for overloaded connects is messy
void doubleClickedSlot(const QModelIndex& index);
signals: signals:
void game_list_frameClosed(); void game_list_frameClosed();
void RequestIconPathSet(const std::string path); void RequestIconPathSet(const std::string path);
void RequestAddRecentGame(const q_string_pair& entry); void RequestAddRecentGame(const q_string_pair& entry);
void RequestIconSizeActSet(const int& idx);
void RequestListModeActSet(const bool& isList);
void RequestCategoryActSet(const int& id);
protected: protected:
/** Override inherited method from Qt to allow signalling when close happened.*/ /** Override inherited method from Qt to allow signalling when close happened.*/
void closeEvent(QCloseEvent* event); void closeEvent(QCloseEvent* event);
void resizeEvent(QResizeEvent *event);
private: private:
QTableWidget *gameList; game_list_grid* MakeGrid(uint maxCols, const QSize& image_size);
void ShowContextMenu(const QPoint &pos);
void doubleClickedSlot(const QModelIndex& index);
void LoadGames();
void LoadPSF();
void ShowData();
void FilterData(); void FilterData();
void PopulateGameList();
bool SearchMatchesApp(const std::string& name, const std::string& serial);
// Which widget we are displaying depends on if we are in grid or list mode.
QMainWindow* m_Game_Dock;
QStackedWidget* m_Central_Widget;
QToolBar* m_Tool_Bar;
QLineEdit* m_Search_Bar;
QSlider* m_Slider_Size;
QTableWidget *gameList;
std::unique_ptr<game_list_grid> m_xgrid;
// Actions regarding showing/hiding columns // Actions regarding showing/hiding columns
QAction* showIconColAct; QAction* showIconColAct;
QAction* showNameColAct; QAction* showNameColAct;
@ -134,7 +110,41 @@ private:
QAction* showPathColAct; QAction* showPathColAct;
QList<QAction*> columnActs; QList<QAction*> columnActs;
// Actions regarding showing/hiding categories
Tool_Bar_Button m_catActHDD;
Tool_Bar_Button m_catActDisc;
Tool_Bar_Button m_catActHome;
Tool_Bar_Button m_catActGameData;
Tool_Bar_Button m_catActAudioVideo;
Tool_Bar_Button m_catActUnknown;
QList<Tool_Bar_Button> m_categoryButtons;
QActionGroup* m_categoryActs;
// Actions regarding switching list modes
Tool_Bar_Button m_modeActList;
Tool_Bar_Button m_modeActGrid;
QActionGroup* m_modeActs;
// TODO: Reorganize this into a sensible order for private variables.
std::shared_ptr<gui_settings> xgui_settings; std::shared_ptr<gui_settings> xgui_settings;
int m_sortColumn;
Qt::SortOrder m_colSortOrder;
bool m_isListLayout = true;
bool m_showToolBar = true;
std::vector<GUI_GameInfo> m_game_data;
QSize m_Icon_Size;
QString m_Icon_Size_Str;
qreal m_Margin_Factor;
qreal m_Text_Factor;
QStringList m_categoryFilters;
Render_Creator m_Render_Creator;
uint m_games_per_row = 0;
}; };
#endif // GAMELISTFRAME_H #endif // GAMELISTFRAME_H

View File

@ -0,0 +1,89 @@
#include "game_list_grid.h"
#include "game_list_grid_delegate.h"
#include <QHeaderView>
game_list_grid::game_list_grid(const QSize& icon_size, const qreal& margin_factor, const qreal& text_factor, const bool& showText)
: QTableWidget(), m_icon_size(icon_size), m_margin_factor(margin_factor), m_text_factor(text_factor), m_text_enabled(showText)
{
QSize item_size;
if (m_text_enabled)
{
item_size = m_icon_size + QSize(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
}
else
{
item_size = m_icon_size + m_icon_size * m_margin_factor * 2;
}
grid_item_delegate = new game_list_grid_delegate(item_size, m_margin_factor, m_text_factor, this);
setItemDelegate(grid_item_delegate);
setSelectionBehavior(QAbstractItemView::SelectItems);
setSelectionMode(QAbstractItemView::SingleSelection);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
setContextMenuPolicy(Qt::CustomContextMenu);
verticalHeader()->setVisible(false);
horizontalHeader()->setVisible(false);
setShowGrid(false);
}
game_list_grid::~game_list_grid()
{
}
void game_list_grid::enableText(const bool& enabled)
{
m_text_enabled = enabled;
}
void game_list_grid::setIconSize(const QSize& size)
{
if (m_text_enabled)
{
grid_item_delegate->setItemSize(size + QSize(size.width() * m_margin_factor * 2, size.height() * m_margin_factor * (m_text_factor + 1)));
}
else
{
grid_item_delegate->setItemSize(size + size * m_margin_factor * 2);
}
}
void game_list_grid::addItem(const QPixmap& img, const QString& name, const int& idx, const int& row, const int& col)
{
// define size of expanded image, which is raw image size + margins
QSize exp_size;
if (m_text_enabled)
{
exp_size = m_icon_size + QSize(m_icon_size.width() * m_margin_factor * 2, m_icon_size.height() * m_margin_factor * (m_text_factor + 1));
}
else
{
exp_size = m_icon_size + m_icon_size * m_margin_factor * 2;
}
// define offset for raw image placement
QPoint offset = QPoint(m_icon_size.width() * m_margin_factor, m_icon_size.height() * m_margin_factor);
// create empty canvas for expanded image
QImage exp_img = QImage(exp_size, QImage::Format_ARGB32);
exp_img.fill(Qt::transparent);
// place raw image inside expanded image
QPainter painter(&exp_img);
painter.drawPixmap(offset, img);
painter.end();
// create item with expanded image, title and position
QTableWidgetItem* item = new QTableWidgetItem();
item->setData(Qt::ItemDataRole::DecorationRole, QPixmap::fromImage(exp_img));
item->setData(Qt::ItemDataRole::UserRole, idx);
item->setData(Qt::ItemDataRole::ToolTipRole, name);
if (m_text_enabled) { item->setData(Qt::ItemDataRole::DisplayRole, name); }
setItem(row, col, item);
}
qreal game_list_grid::getMarginFactor()
{
return m_margin_factor;
}

View File

@ -0,0 +1,36 @@
#ifndef GAME_LIST_GRID_H
#define GAME_LIST_GRID_H
#include "game_list_grid_delegate.h"
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QScrollArea>
#include <QString>
#include <QTableWidget>
class game_list_grid : public QTableWidget
{
Q_OBJECT
QSize m_icon_size;
qreal m_margin_factor;
qreal m_text_factor;
bool m_text_enabled = true;
public:
explicit game_list_grid(const QSize& icon_size, const qreal& margin_factor, const qreal& text_factor, const bool& showText);
~game_list_grid();
void enableText(const bool& enabled);
void setIconSize(const QSize& size);
void addItem(const QPixmap& img, const QString& name, const int& idx, const int& row, const int& col);
qreal getMarginFactor();
private:
game_list_grid_delegate* grid_item_delegate;
};
#endif

View File

@ -0,0 +1,54 @@
#include "game_list_grid_delegate.h"
game_list_grid_delegate::game_list_grid_delegate(const QSize& size, const qreal& margin_factor, const qreal& text_factor, QObject *parent)
: QAbstractItemDelegate(parent), m_size(size), m_margin_factor(margin_factor), m_text_factor(text_factor)
{
}
game_list_grid_delegate::~game_list_grid_delegate()
{
}
void game_list_grid_delegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
QRect r = option.rect;
painter->eraseRect(r);
//Color: #333
QPen fontPen(QColor::fromRgb(51, 51, 51), 1, Qt::SolidLine);
//Get title and image
QPixmap image = (qvariant_cast<QPixmap>(index.data(Qt::DecorationRole)));
QString title = index.data(Qt::DisplayRole).toString();
// image
if (image.isNull() == false)
{
painter->drawPixmap(r, image);
}
// Add selection overlay
if (option.state & QStyle::State_Selected)
{
QLinearGradient gradientSelected(r.left(), r.top(), r.left(), r.height() + r.top());
gradientSelected.setColorAt(0.0, QColor::fromRgba(qRgba(119, 213, 247, 128)));
gradientSelected.setColorAt(0.9, QColor::fromRgba(qRgba(27, 134, 183, 128)));
gradientSelected.setColorAt(1.0, QColor::fromRgba(qRgba(0, 120, 174, 128)));
painter->fillRect(r, gradientSelected);
}
int h = r.height() / (1 + m_margin_factor + m_margin_factor*m_text_factor);
int height = r.height() - h - h * m_margin_factor;
int top = r.bottom() - height;
// title
painter->setPen(fontPen);
painter->setFont(QFont("Lucida Grande", 8, QFont::DemiBold));
painter->drawText(QRect(r.left(), top, r.width(), height), Qt::TextWordWrap | Qt::AlignCenter, title);
}
QSize game_list_grid_delegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
return m_size;
}

View File

@ -0,0 +1,22 @@
#ifndef GAME_LIST_GRID_DELEGATE
#define GAME_LIST_GRID_DELEGATE
#include <QPainter>
#include <QAbstractItemDelegate>
class game_list_grid_delegate : public QAbstractItemDelegate
{
public:
game_list_grid_delegate(const QSize& imageSize, const qreal& margin_factor, const qreal& margin_ratio, QObject *parent = 0);
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const;
void setItemSize(const QSize& size) { m_size = size; };
virtual ~game_list_grid_delegate();
private:
QSize m_size;
qreal m_margin_factor;
qreal m_text_factor;
};
#endif

View File

@ -28,15 +28,19 @@ typedef struct GUI_SAVE
typedef std::map<const QString, const QSize> icon_size; typedef std::map<const QString, const QSize> icon_size;
typedef QPair<QString, QString> q_string_pair; typedef QPair<QString, QString> q_string_pair;
typedef QPair<QString, QSize> q_size_pair;
typedef QList<q_string_pair> q_pair_list; typedef QList<q_string_pair> q_pair_list;
typedef QList<q_size_pair> q_size_list;
namespace GUI namespace GUI
{ {
const QString gl_icon_key_tiny = "tiny";
const QString gl_icon_key_small = "small"; const QString gl_icon_key_small = "small";
const QString gl_icon_key_medium = "medium"; const QString gl_icon_key_medium = "medium";
const QString gl_icon_key_large = "large"; const QString gl_icon_key_large = "large";
const icon_size gl_icon_size = { const q_size_list gl_icon_size = {
{ gl_icon_key_tiny, QSize(40, 22) },
{ gl_icon_key_small, QSize(80, 44) }, { gl_icon_key_small, QSize(80, 44) },
{ gl_icon_key_medium, QSize(160, 88) }, { gl_icon_key_medium, QSize(160, 88) },
{ gl_icon_key_large, QSize(320, 176) } { gl_icon_key_large, QSize(320, 176) }
@ -79,6 +83,10 @@ namespace GUI
const GUI_SAVE gl_sortCol = GUI_SAVE( game_list, "sortCol", 1 ); const GUI_SAVE gl_sortCol = GUI_SAVE( game_list, "sortCol", 1 );
const GUI_SAVE gl_state = GUI_SAVE( game_list, "state", QByteArray() ); const GUI_SAVE gl_state = GUI_SAVE( game_list, "state", QByteArray() );
const GUI_SAVE gl_iconSize = GUI_SAVE( game_list, "iconSize", gl_icon_key_small ); const GUI_SAVE gl_iconSize = GUI_SAVE( game_list, "iconSize", gl_icon_key_small );
const GUI_SAVE gl_listMode = GUI_SAVE( game_list, "listMode", true );
const GUI_SAVE gl_textFactor = GUI_SAVE( game_list, "textFactor", (qreal) 2.0 );
const GUI_SAVE gl_marginFactor = GUI_SAVE( game_list, "marginFactor", (qreal) 0.09 );
const GUI_SAVE gl_toolBarVisible = GUI_SAVE( game_list, "toolBarVisible", true );
const GUI_SAVE l_tty = GUI_SAVE( logger, "TTY", true ); const GUI_SAVE l_tty = GUI_SAVE( logger, "TTY", true );
const GUI_SAVE l_level = GUI_SAVE( logger, "level", (uint)(logs::level::success) ); const GUI_SAVE l_level = GUI_SAVE( logger, "level", (uint)(logs::level::success) );

View File

@ -351,7 +351,7 @@ void main_window::InstallPkg()
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{ {
fs::remove_all(local_path); fs::remove_all(local_path);
gameListFrame->Refresh(); gameListFrame->Refresh(true);
LOG_SUCCESS(LOADER, "PKG: removed incomplete installation in %s", local_path); LOG_SUCCESS(LOADER, "PKG: removed incomplete installation in %s", local_path);
return; return;
} }
@ -377,7 +377,7 @@ void main_window::InstallPkg()
if (progress >= 1.) if (progress >= 1.)
{ {
gameListFrame->Refresh(); gameListFrame->Refresh(true);
LOG_SUCCESS(GENERAL, "Successfully installed %s.", fileName); LOG_SUCCESS(GENERAL, "Successfully installed %s.", fileName);
guiSettings->ShowInfoBox(GUI::ib_pkg_success, tr("Success!"), tr("Successfully installed software from package!"), this); guiSettings->ShowInfoBox(GUI::ib_pkg_success, tr("Success!"), tr("Successfully installed software from package!"), this);
@ -1027,6 +1027,9 @@ void main_window::CreateActions()
showControlsAct = new QAction(tr("Show Controls"), this); showControlsAct = new QAction(tr("Show Controls"), this);
showControlsAct->setCheckable(true); showControlsAct->setCheckable(true);
showGameListToolBarAct = new QAction(tr("Show Tool Bar"), this);
showGameListToolBarAct->setCheckable(true);
refreshGameListAct = new QAction(tr("&Refresh Game List"), this); refreshGameListAct = new QAction(tr("&Refresh Game List"), this);
showCatHDDGameAct = new QAction(category::hdd_Game, this); showCatHDDGameAct = new QAction(category::hdd_Game, this);
@ -1047,6 +1050,18 @@ void main_window::CreateActions()
showCatUnknownAct = new QAction(category::unknown, this); showCatUnknownAct = new QAction(category::unknown, this);
showCatUnknownAct->setCheckable(true); showCatUnknownAct->setCheckable(true);
categoryVisibleActGroup = new QActionGroup(this);
categoryVisibleActGroup->addAction(showCatHDDGameAct);
categoryVisibleActGroup->addAction(showCatDiscGameAct);
categoryVisibleActGroup->addAction(showCatHomeAct);
categoryVisibleActGroup->addAction(showCatAudioVideoAct);
categoryVisibleActGroup->addAction(showCatGameDataAct);
categoryVisibleActGroup->addAction(showCatUnknownAct);
categoryVisibleActGroup->setExclusive(false);
setIconSizeTinyAct = new QAction(tr("Tiny"), this);
setIconSizeTinyAct->setCheckable(true);
setIconSizeSmallAct = new QAction(tr("Small"), this); setIconSizeSmallAct = new QAction(tr("Small"), this);
setIconSizeSmallAct->setCheckable(true); setIconSizeSmallAct->setCheckable(true);
@ -1057,11 +1072,23 @@ void main_window::CreateActions()
setIconSizeLargeAct->setCheckable(true); setIconSizeLargeAct->setCheckable(true);
iconSizeActGroup = new QActionGroup(this); iconSizeActGroup = new QActionGroup(this);
iconSizeActGroup->addAction(setIconSizeTinyAct);
iconSizeActGroup->addAction(setIconSizeSmallAct); iconSizeActGroup->addAction(setIconSizeSmallAct);
iconSizeActGroup->addAction(setIconSizeMediumAct); iconSizeActGroup->addAction(setIconSizeMediumAct);
iconSizeActGroup->addAction(setIconSizeLargeAct); iconSizeActGroup->addAction(setIconSizeLargeAct);
setIconSizeSmallAct->setChecked(true); setIconSizeSmallAct->setChecked(true);
setlistModeListAct = new QAction(tr("List"), this);
setlistModeListAct->setCheckable(true);
setlistModeGridAct = new QAction(tr("Grid"), this);
setlistModeGridAct->setCheckable(true);
listModeActGroup = new QActionGroup(this);
listModeActGroup->addAction(setlistModeListAct);
listModeActGroup->addAction(setlistModeGridAct);
setlistModeListAct->setChecked(true);
aboutAct = new QAction(tr("&About"), this); aboutAct = new QAction(tr("&About"), this);
aboutAct->setStatusTip(tr("Show the application's About box")); aboutAct->setStatusTip(tr("Show the application's About box"));
@ -1166,32 +1193,27 @@ void main_window::CreateConnects()
checked ? controls->show() : controls->hide(); checked ? controls->show() : controls->hide();
guiSettings->SetValue(GUI::mw_controls, checked); guiSettings->SetValue(GUI::mw_controls, checked);
}); });
connect(showGameListToolBarAct, &QAction::triggered, this, [=](bool checked){
gameListFrame->SetToolBarVisible(checked);
});
connect(refreshGameListAct, &QAction::triggered, [=](){ connect(refreshGameListAct, &QAction::triggered, [=](){
gameListFrame->Refresh(); gameListFrame->Refresh(true);
}); });
connect(showCatHDDGameAct, &QAction::triggered, [=](bool checked){ connect(categoryVisibleActGroup, &QActionGroup::triggered, [=](QAction* act)
gameListFrame->ToggleCategoryFilter(category::hdd_Game, checked); {
guiSettings->SetCategoryVisibility(category::hdd_Game, checked); QString cat;
}); const bool& checked = act->isChecked();
connect(showCatDiscGameAct, &QAction::triggered, [=](bool checked){
gameListFrame->ToggleCategoryFilter(category::disc_Game, checked); if (act == showCatHDDGameAct) cat = category::hdd_Game;
guiSettings->SetCategoryVisibility(category::disc_Game, checked); else if (act == showCatDiscGameAct) cat = category::disc_Game;
}); else if (act == showCatHomeAct) cat = category::home;
connect(showCatHomeAct, &QAction::triggered, [=](bool checked){ else if (act == showCatAudioVideoAct) cat = category::audio_Video;
gameListFrame->ToggleCategoryFilter(category::home, checked); else if (act == showCatGameDataAct) cat = category::game_Data;
guiSettings->SetCategoryVisibility(category::home, checked); else if (act == showCatUnknownAct) cat = category::unknown;
});
connect(showCatAudioVideoAct, &QAction::triggered, [=](bool checked){ gameListFrame->SetCategoryActIcon(categoryVisibleActGroup->actions().indexOf(act), checked);
gameListFrame->ToggleCategoryFilter(category::audio_Video, checked); gameListFrame->ToggleCategoryFilter(cat, checked);
guiSettings->SetCategoryVisibility(category::audio_Video, checked); guiSettings->SetCategoryVisibility(cat, checked);
});
connect(showCatGameDataAct, &QAction::triggered, [=](bool checked){
gameListFrame->ToggleCategoryFilter(category::game_Data, checked);
guiSettings->SetCategoryVisibility(category::game_Data, checked);
});
connect(showCatUnknownAct, &QAction::triggered, [=](bool checked) {
gameListFrame->ToggleCategoryFilter(category::unknown, checked);
guiSettings->SetCategoryVisibility(category::unknown, checked);
}); });
connect(aboutAct, &QAction::triggered, this, &main_window::About); connect(aboutAct, &QAction::triggered, this, &main_window::About);
connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt); connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
@ -1207,10 +1229,37 @@ void main_window::CreateConnects()
if (act == setIconSizeLargeAct) key = GUI::gl_icon_key_large; if (act == setIconSizeLargeAct) key = GUI::gl_icon_key_large;
else if (act == setIconSizeMediumAct) key = GUI::gl_icon_key_medium; else if (act == setIconSizeMediumAct) key = GUI::gl_icon_key_medium;
else key = GUI::gl_icon_key_small; else if (act == setIconSizeSmallAct) key = GUI::gl_icon_key_small;
else key = GUI::gl_icon_key_tiny;
guiSettings->SetValue(GUI::gl_iconSize, key); guiSettings->SetValue(GUI::gl_iconSize, key);
gameListFrame->ResizeIcons(GUI::gl_icon_size.at(key));
for (int i = 0; i < GUI::gl_icon_size.count(); i++)
{
if (GUI::gl_icon_size.at(i).first == key)
{
gameListFrame->ResizeIcons(GUI::gl_icon_size.at(i).second, i);
break;
}
}
});
connect (gameListFrame, &game_list_frame::RequestIconSizeActSet, [=](const int& idx)
{
iconSizeActGroup->actions().at(idx)->trigger();
});
connect(gameListFrame, &game_list_frame::RequestListModeActSet, [=](const bool& isList)
{
isList ? setlistModeListAct->trigger() : setlistModeGridAct->trigger();
});
connect(gameListFrame, &game_list_frame::RequestCategoryActSet, [=](const int& id)
{
categoryVisibleActGroup->actions().at(id)->trigger();
});
connect(listModeActGroup, &QActionGroup::triggered, [=](QAction* act)
{
bool isList = act == setlistModeListAct;
gameListFrame->SetListMode(isList);
categoryVisibleActGroup->setEnabled(isList);
}); });
} }
@ -1261,20 +1310,17 @@ void main_window::CreateMenus()
viewMenu->addAction(showControlsAct); viewMenu->addAction(showControlsAct);
viewMenu->addSeparator(); viewMenu->addSeparator();
viewMenu->addAction(showGameListAct); viewMenu->addAction(showGameListAct);
viewMenu->addAction(showGameListToolBarAct);
viewMenu->addAction(refreshGameListAct); viewMenu->addAction(refreshGameListAct);
QMenu *categoryMenu = viewMenu->addMenu(tr("Show Categories")); QMenu *categoryMenu = viewMenu->addMenu(tr("Show Categories"));
categoryMenu->addAction(showCatHDDGameAct); categoryMenu->addActions(categoryVisibleActGroup->actions());
categoryMenu->addAction(showCatDiscGameAct);
categoryMenu->addAction(showCatHomeAct);
categoryMenu->addAction(showCatAudioVideoAct);
categoryMenu->addAction(showCatGameDataAct);
categoryMenu->addAction(showCatUnknownAct);
QMenu *iconSizeMenu = viewMenu->addMenu(tr("Icon Size")); QMenu *iconSizeMenu = viewMenu->addMenu(tr("Icon Size"));
iconSizeMenu->addAction(setIconSizeSmallAct); iconSizeMenu->addActions(iconSizeActGroup->actions());
iconSizeMenu->addAction(setIconSizeMediumAct);
iconSizeMenu->addAction(setIconSizeLargeAct); QMenu *listModeMenu = viewMenu->addMenu(tr("Game List Mode"));
listModeMenu->addActions(listModeActGroup->actions());
QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(aboutAct); helpMenu->addAction(aboutAct);
@ -1385,6 +1431,7 @@ void main_window::ConfigureGuiFromSettings(bool configureAll)
showGameListAct->setChecked(guiSettings->GetValue(GUI::mw_gamelist).toBool()); showGameListAct->setChecked(guiSettings->GetValue(GUI::mw_gamelist).toBool());
showDebuggerAct->setChecked(guiSettings->GetValue(GUI::mw_debugger).toBool()); showDebuggerAct->setChecked(guiSettings->GetValue(GUI::mw_debugger).toBool());
showControlsAct->setChecked(guiSettings->GetValue(GUI::mw_controls).toBool()); showControlsAct->setChecked(guiSettings->GetValue(GUI::mw_controls).toBool());
showGameListToolBarAct->setChecked(guiSettings->GetValue(GUI::gl_toolBarVisible).toBool());
guiSettings->GetValue(GUI::mw_controls).toBool() ? controls->show() : controls->hide(); guiSettings->GetValue(GUI::mw_controls).toBool() ? controls->show() : controls->hide();
showCatHDDGameAct->setChecked(guiSettings->GetCategoryVisibility(category::hdd_Game)); showCatHDDGameAct->setChecked(guiSettings->GetCategoryVisibility(category::hdd_Game));
@ -1397,7 +1444,15 @@ void main_window::ConfigureGuiFromSettings(bool configureAll)
QString key = guiSettings->GetValue(GUI::gl_iconSize).toString(); QString key = guiSettings->GetValue(GUI::gl_iconSize).toString();
if (key == GUI::gl_icon_key_large) setIconSizeLargeAct->setChecked(true); if (key == GUI::gl_icon_key_large) setIconSizeLargeAct->setChecked(true);
else if (key == GUI::gl_icon_key_medium) setIconSizeMediumAct->setChecked(true); else if (key == GUI::gl_icon_key_medium) setIconSizeMediumAct->setChecked(true);
else setIconSizeSmallAct->setChecked(true); else if (key == GUI::gl_icon_key_small) setIconSizeSmallAct->setChecked(true);
else setIconSizeTinyAct->setChecked(true);
bool isListMode = guiSettings->GetValue(GUI::gl_listMode).toBool();
if (isListMode) setlistModeListAct->setChecked(true);
else setlistModeGridAct->setChecked(true);
categoryVisibleActGroup->setEnabled(isListMode);
if (configureAll) if (configureAll)
{ {

View File

@ -98,6 +98,8 @@ private:
QList<QAction*> m_recentGameActs; QList<QAction*> m_recentGameActs;
QActionGroup* iconSizeActGroup; QActionGroup* iconSizeActGroup;
QActionGroup* listModeActGroup;
QActionGroup* categoryVisibleActGroup;
QAction *bootElfAct; QAction *bootElfAct;
QAction *bootGameAct; QAction *bootGameAct;
@ -125,15 +127,19 @@ private:
QAction *showGameListAct; QAction *showGameListAct;
QAction *showControlsAct; QAction *showControlsAct;
QAction *refreshGameListAct; QAction *refreshGameListAct;
QAction *showGameListToolBarAct;
QAction* showCatHDDGameAct; QAction* showCatHDDGameAct;
QAction* showCatDiscGameAct; QAction* showCatDiscGameAct;
QAction* showCatHomeAct; QAction* showCatHomeAct;
QAction* showCatAudioVideoAct; QAction* showCatAudioVideoAct;
QAction* showCatGameDataAct; QAction* showCatGameDataAct;
QAction* showCatUnknownAct; QAction* showCatUnknownAct;
QAction* setIconSizeTinyAct;
QAction* setIconSizeSmallAct; QAction* setIconSizeSmallAct;
QAction* setIconSizeMediumAct; QAction* setIconSizeMediumAct;
QAction* setIconSizeLargeAct; QAction* setIconSizeLargeAct;
QAction* setlistModeListAct;
QAction* setlistModeGridAct;
QAction *aboutAct; QAction *aboutAct;
QAction *aboutQtAct; QAction *aboutQtAct;