From 551f82110974b515f07c58130dd29447e305e1b1 Mon Sep 17 00:00:00 2001 From: bslhq Date: Fri, 7 Oct 2022 20:30:06 +0800 Subject: [PATCH] Auto resize last column (#265) --- src/config/CemuConfig.cpp | 21 ++- src/config/CemuConfig.h | 17 +- src/gui/TitleManager.cpp | 2 +- src/gui/components/wxGameList.cpp | 249 ++++++++++++++++++------------ src/gui/components/wxGameList.h | 9 +- 5 files changed, 185 insertions(+), 113 deletions(-) diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index dcd283ec..b257ead3 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -89,12 +89,21 @@ void CemuConfig::Load(XMLConfigParser& parser) auto gamelist = parser.get("GameList"); game_list_style = gamelist.get("style", 0); game_list_column_order = gamelist.get("order", ""); - column_width.name = gamelist.get("name_width", -3); - column_width.version = gamelist.get("version_width", -3); - column_width.dlc = gamelist.get("dlc_width", -3); - column_width.game_time = gamelist.get("game_time_width", -3); - column_width.game_started = gamelist.get("game_started_width", -3); - column_width.region = gamelist.get("region_width", -3); + + // return default width if value in config file out of range + auto loadColumnSize = [&gamelist] (const char *name, uint32 defaultWidth) + { + sint64 val = gamelist.get(name, DefaultColumnSize::name); + if (val < 0 || val > (sint64) std::numeric_limits::max) + return defaultWidth; + return static_cast(val); + }; + column_width.name = loadColumnSize("name_width", DefaultColumnSize::name); + column_width.version = loadColumnSize("version_width", DefaultColumnSize::version); + column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc); + column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time); + column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started); + column_width.region = loadColumnSize("region_width", DefaultColumnSize::region); recent_launch_files.clear(); auto launch_parser = parser.get("RecentLaunchFiles"); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index caabf082..e7cb1ca5 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -334,6 +334,16 @@ struct fmt::formatter : formatter { }; #endif +namespace DefaultColumnSize { + enum : uint32 { + name = 500u, + version = 60u, + dlc = 50u, + game_time = 140u, + game_started = 160u, + region = 80u, + }; +}; struct CemuConfig { @@ -402,7 +412,12 @@ struct CemuConfig std::string game_list_column_order; struct { - int name = -3, version = -3, dlc = -3, game_time = -3, game_started = -3, region = -3; + uint32 name = DefaultColumnSize::name; + uint32 version = DefaultColumnSize::version; + uint32 dlc = DefaultColumnSize::dlc; + uint32 game_time = DefaultColumnSize::game_time; + uint32 game_started = DefaultColumnSize::game_started; + uint32 region = DefaultColumnSize::region; } column_width{}; // graphics diff --git a/src/gui/TitleManager.cpp b/src/gui/TitleManager.cpp index 73e9d45c..519faf2b 100644 --- a/src/gui/TitleManager.cpp +++ b/src/gui/TitleManager.cpp @@ -219,7 +219,7 @@ wxPanel* TitleManager::CreateDownloadManagerPage() } TitleManager::TitleManager(wxWindow* parent, TitleManagerPage default_page) - : wxFrame(parent, wxID_ANY, _("Title manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) + : wxFrame(parent, wxID_ANY, _("Title Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) { SetIcon(wxICON(X_BOX)); diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 074722e0..904fd5b7 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -50,7 +50,16 @@ void _stripPathFilename(fs::path& path) wxGameList::wxGameList(wxWindow* parent, wxWindowID id) : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList) { - CreateListColumns(); + const auto& config = GetConfig(); + + InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0); + InsertColumn(ColumnIcon, "", wxLIST_FORMAT_LEFT, kListIconWidth); + InsertColumn(ColumnName, _("Game"), wxLIST_FORMAT_LEFT, config.column_width.name); + InsertColumn(ColumnVersion, _("Version"), wxLIST_FORMAT_RIGHT, config.column_width.version); + InsertColumn(ColumnDLC, _("DLC"), wxLIST_FORMAT_RIGHT, config.column_width.dlc); + InsertColumn(ColumnGameTime, _("You've played"), wxLIST_FORMAT_LEFT, config.column_width.game_time); + InsertColumn(ColumnGameStarted, _("Last played"), wxLIST_FORMAT_LEFT, config.column_width.game_started); + InsertColumn(ColumnRegion, _("Region"), wxLIST_FORMAT_LEFT, config.column_width.region); const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0}; wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth); @@ -87,6 +96,7 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id) Bind(wxEVT_LIST_COL_BEGIN_DRAG, &wxGameList::OnColumnBeginResize, this); Bind(wxEVT_LIST_COL_END_DRAG, &wxGameList::OnColumnResize, this); Bind(wxEVT_LIST_COL_RIGHT_CLICK, &wxGameList::OnColumnRightClick, this); + Bind(wxEVT_SIZE, &wxGameList::OnGameListSize, this); m_callbackIdTitleList = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((wxGameList*)ctx)->HandleTitleListCallback(evt); }, this); @@ -124,7 +134,7 @@ void wxGameList::LoadConfig() if (!config.game_list_column_order.empty()) { wxArrayInt order; - order.reserve(ColumnFavorite); + order.reserve(ColumnCounts); const auto order_string = std::string_view(config.game_list_column_order).substr(1); @@ -135,10 +145,88 @@ void wxGameList::LoadConfig() order.push_back(ConvertString(token, 10)); } - #ifdef wxHAS_LISTCTRL_COLUMN_ORDER - if(order.GetCount() == ColumnFavorite) +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(order.GetCount() == ColumnCounts) SetColumnsOrder(order); - #endif +#endif + } +} + +void wxGameList::OnGameListSize(wxSizeEvent &event) +{ + event.Skip(); + + // when using a sizer-based layout, do not change the size of the wxComponent in its own wxSizeEvent handler to avoid some UI issues. + int last_col_index = 0; + for(int i = GetColumnCount() - 1; i > 0; i--) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + break; + } +#else + if(GetColumnWidth(i) > 0) + { + last_col_index = i; + break; + } +#endif + } + wxListEvent column_resize_event(wxEVT_LIST_COL_END_DRAG); + column_resize_event.SetColumn(last_col_index); + wxPostEvent(this, column_resize_event); +} + +void wxGameList::AdjustLastColumnWidth() +{ + wxWindowUpdateLocker windowlock(this); + int last_col_index = 0; + int last_col_width = GetClientSize().GetWidth(); + for (int i = 1; i < GetColumnCount(); i++) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if (GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + last_col_width -= GetColumnWidth(last_col_index); + } +#else + if (GetColumnWidth(i) > 0) + { + last_col_index = i; + last_col_width -= GetColumnWidth(i); + } +#endif + } + last_col_width += GetColumnWidth(last_col_index); + if (last_col_width < GetColumnDefaultWidth(last_col_index)) // keep a minimum width + last_col_width = GetColumnDefaultWidth(last_col_index); + SetColumnWidth(last_col_index, last_col_width); +} + +// todo: scale all columns using a ratio instead of hardcoding exact widths +int wxGameList::GetColumnDefaultWidth(int column) +{ + switch (column) + { + case ColumnIcon: + return kListIconWidth; + case ColumnName: + return DefaultColumnSize::name; + case ColumnVersion: + return DefaultColumnSize::version; + case ColumnDLC: + return DefaultColumnSize::dlc; + case ColumnGameTime: + return DefaultColumnSize::game_time; + case ColumnGameStarted: + return DefaultColumnSize::game_started; + case ColumnRegion: + return DefaultColumnSize::region; + default: + return 80; } } @@ -339,7 +427,6 @@ void wxGameList::SortEntries(int column) column = s_last_column; else { - if (s_last_column == column) { s_last_column = 0; @@ -366,60 +453,6 @@ void wxGameList::SortEntries(int column) } } -void wxGameList::CreateListColumns() -{ - DeleteAllColumns(); - - const auto& config = GetConfig(); - wxListItem col0; - col0.SetId(ColumnHiddenName); - col0.SetWidth(0); - InsertColumn(ColumnHiddenName, col0); - - wxListItem col1; - col1.SetId(ColumnIcon); - col1.SetWidth(kListIconWidth); - InsertColumn(ColumnIcon, col1); - - wxListItem col2; - col2.SetId(ColumnName); - col2.SetText(_("Game")); - col2.SetWidth(config.column_width.name); - InsertColumn(ColumnName, col2); - - wxListItem col3; - col3.SetId(ColumnVersion); - col3.SetText(_("Version")); - col3.SetWidth(config.column_width.version); - col3.SetAlign(wxLIST_FORMAT_RIGHT); - InsertColumn(ColumnVersion, col3); - - wxListItem col4; - col4.SetId(ColumnDLC); - col4.SetText(_("DLC")); - col4.SetWidth(config.column_width.dlc); - col4.SetAlign(wxLIST_FORMAT_RIGHT); - InsertColumn(ColumnDLC, col4); - - wxListItem col5; - col5.SetId(ColumnGameTime); - col5.SetText(_("You've played")); - col5.SetWidth(config.column_width.game_time); - InsertColumn(ColumnGameTime, col5); - - wxListItem col6; - col6.SetId(ColumnGameStarted); - col6.SetText(_("Last played")); - col6.SetWidth(config.column_width.game_started); - InsertColumn(ColumnGameStarted, col6); - - wxListItem col7; - col7.SetId(ColumnRegion); - col7.SetText(_("Region")); - col7.SetWidth(config.column_width.region); - InsertColumn(ColumnRegion, col7); -} - void wxGameList::OnKeyDown(wxListEvent& event) { event.Skip(); @@ -688,9 +721,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) menu.AppendCheckItem(ShowDlc, _("Show &dlc"))->Check(GetColumnWidth(ColumnDLC) > 0); menu.AppendCheckItem(ShowGameTime, _("Show &game time"))->Check(GetColumnWidth(ColumnGameTime) > 0); menu.AppendCheckItem(ShowLastPlayed, _("Show &last played"))->Check(GetColumnWidth(ColumnGameStarted) > 0); - menu.AppendCheckItem(ColumnRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0); - //menu.AppendSeparator(); - //menu.Append(ResetOrder, _("&Reset order")); + menu.AppendCheckItem(ShowRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0); menu.Bind(wxEVT_COMMAND_MENU_SELECTED, [this](wxCommandEvent& event) { @@ -703,44 +734,46 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) switch (event.GetId()) { case ShowName: - config.column_width.name = menu->IsChecked(ShowName) ? 500 : 0; + config.column_width.name = menu->IsChecked(ShowName) ? DefaultColumnSize::name : 0; break; case ShowVersion: - config.column_width.version = menu->IsChecked(ShowVersion) ? 60 : 0; + config.column_width.version = menu->IsChecked(ShowVersion) ? DefaultColumnSize::version : 0; break; case ShowDlc: - config.column_width.dlc = menu->IsChecked(ShowDlc) ? 50 : 0; + config.column_width.dlc = menu->IsChecked(ShowDlc) ? DefaultColumnSize::dlc : 0; break; case ShowGameTime: - config.column_width.game_time = menu->IsChecked(ShowGameTime) ? 140 : 0; + config.column_width.game_time = menu->IsChecked(ShowGameTime) ? DefaultColumnSize::game_time : 0; break; case ShowLastPlayed: - config.column_width.game_started = menu->IsChecked(ShowLastPlayed) ? 160 : 0; + config.column_width.game_started = menu->IsChecked(ShowLastPlayed) ? DefaultColumnSize::game_started : 0; break; - case ColumnRegion: - config.column_width.region = menu->IsChecked(ColumnRegion) ? 80 : 0; + case ShowRegion: + config.column_width.region = menu->IsChecked(ShowRegion) ? DefaultColumnSize::region : 0; break; case ResetWidth: { switch (column) { + case ColumnIcon: + break; case ColumnName: - config.column_width.name = 500; + config.column_width.name = DefaultColumnSize::name; break; case ColumnVersion: - config.column_width.version = 60; + config.column_width.version = DefaultColumnSize::version; break; case ColumnDLC: - config.column_width.dlc = 50; + config.column_width.dlc = DefaultColumnSize::dlc; break; case ColumnGameTime: - config.column_width.game_time = 140; + config.column_width.game_time = DefaultColumnSize::game_time; break; case ColumnGameStarted: - config.column_width.game_started = 160; + config.column_width.game_started = DefaultColumnSize::game_started; break; case ColumnRegion: - config.column_width.region = 80; + config.column_width.region = DefaultColumnSize::region; break; default: return; @@ -751,13 +784,14 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) case ResetOrder: { config.game_list_column_order.clear(); - wxArrayInt order(ColumnFavorite); + wxArrayInt order(ColumnCounts); std::iota(order.begin(), order.end(), 0); #ifdef wxHAS_LISTCTRL_COLUMN_ORDER SetColumnsOrder(order); #endif - Refresh(); - return; + //ApplyGameListColumnWidths(); + //Refresh(); + //return; } } @@ -771,33 +805,46 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) void wxGameList::ApplyGameListColumnWidths() { - auto set_width = [this](int id, int width) - { - if (width == -3) - wxAutosizeColumn(this, id); - else - this->SetColumnWidth(id, width); - }; - const auto& config = GetConfig(); wxWindowUpdateLocker lock(this); - set_width(ColumnName, config.column_width.name); - set_width(ColumnVersion, config.column_width.version); - set_width(ColumnDLC, config.column_width.dlc); - set_width(ColumnGameTime, config.column_width.game_time); - set_width(ColumnGameStarted, config.column_width.game_started); - set_width(ColumnRegion, config.column_width.region); + SetColumnWidth(ColumnIcon, kListIconWidth); + SetColumnWidth(ColumnName, config.column_width.name); + SetColumnWidth(ColumnVersion, config.column_width.version); + SetColumnWidth(ColumnDLC, config.column_width.dlc); + SetColumnWidth(ColumnGameTime, config.column_width.game_time); + SetColumnWidth(ColumnGameStarted, config.column_width.game_started); + SetColumnWidth(ColumnRegion, config.column_width.region); + + AdjustLastColumnWidth(); } void wxGameList::OnColumnBeginResize(wxListEvent& event) { const int column = event.GetColumn(); const int width = GetColumnWidth(column); - if (width == 0) + int last_col_index = 0; + for(int i = GetColumnCount() - 1; i > 0; i--) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + break; + } +#else + if(GetColumnWidth(i) > 0) + { + last_col_index = i; + break; + } +#endif + } + if (width == 0 || column == ColumnIcon || column == last_col_index) // dont resize hidden name, icon, and last column event.Veto(); else event.Skip(); } + void wxGameList::OnColumnResize(wxListEvent& event) { event.Skip(); @@ -823,19 +870,15 @@ void wxGameList::OnColumnResize(wxListEvent& event) case ColumnGameStarted: config.column_width.game_started = width; break; + case ColumnRegion: + config.column_width.region = width; + break; default: - return; + break; } g_config.Save(); -} - -void wxGameList::OnColumnDrag(wxListEvent& event) -{ - const auto column = event.GetColumn(); - const auto width = GetColumnWidth(column); - if (column == ColumnHiddenName || width == 0) - event.Veto(); + AdjustLastColumnWidth(); } void wxGameList::OnClose(wxCloseEvent& event) diff --git a/src/gui/components/wxGameList.h b/src/gui/components/wxGameList.h index 1f422585..2cf9f6b7 100644 --- a/src/gui/components/wxGameList.h +++ b/src/gui/components/wxGameList.h @@ -53,7 +53,7 @@ public: long FindListItemByTitleId(uint64 title_id) const; void OnClose(wxCloseEvent& event); - + private: std::atomic_bool m_exit = false; Style m_style; @@ -74,7 +74,8 @@ private: ColumnGameTime, ColumnGameStarted, ColumnRegion, - ColumnFavorite + //ColumnFavorite, + ColumnCounts }; int s_last_column = ColumnName; @@ -143,6 +144,10 @@ private: void OnMouseMove(wxMouseEvent& event); void OnLeaveWindow(wxMouseEvent& event); + void OnGameListSize(wxSizeEvent& event); + void AdjustLastColumnWidth(); + int GetColumnDefaultWidth(int column); + static inline std::once_flag s_launch_file_once; };