forked from dolphin-emu/dolphin
		
	The original reason I wanted to do this was so that we can replace the Android-specific code with this in the future, but of course, just deduplicating between DolphinWX and DolphinQt2 is nice too. Fixes: - DolphinQt2 showing the wrong size for split WBFS disc images. - DolphinQt2 being case sensitive when checking if a file is a DOL/ELF. - DolphinQt2 not detecting when a Wii banner has become available after the game list cache was created. Removes: - DolphinWX's ability to load PNGs as custom banners. But it was already rather broken (see https://bugs.dolphin-emu.org/issues/10365 and https://bugs.dolphin-emu.org/issues/10366). The reason I removed this was because PNG decoding relied on wx code and we don't have any good non-wx/Qt code for loading PNG files right now (let's not use SOIL), but we should be able to use libpng directly to implement PNG loading in the future. - DolphinQt2's ability to ignore a cached game if the last modified time differs. We currently don't have a non-wx/Qt way to get the time.
		
			
				
	
	
		
			183 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2018 Dolphin Emulator Project
 | 
						|
// Licensed under GPLv2+
 | 
						|
// Refer to the license.txt file included.
 | 
						|
 | 
						|
#include "DolphinQt2/Config/ARCodeWidget.h"
 | 
						|
 | 
						|
#include <QButtonGroup>
 | 
						|
#include <QHBoxLayout>
 | 
						|
#include <QListWidget>
 | 
						|
#include <QPushButton>
 | 
						|
#include <QVBoxLayout>
 | 
						|
 | 
						|
#include "Common/FileUtil.h"
 | 
						|
#include "Common/IniFile.h"
 | 
						|
#include "Core/ActionReplay.h"
 | 
						|
#include "Core/ConfigManager.h"
 | 
						|
#include "DolphinQt2/Config/CheatCodeEditor.h"
 | 
						|
#include "DolphinQt2/Config/CheatWarningWidget.h"
 | 
						|
#include "UICommon/GameFile.h"
 | 
						|
 | 
						|
ARCodeWidget::ARCodeWidget(const UICommon::GameFile& game)
 | 
						|
    : m_game(game), m_game_id(game.GetGameID()), m_game_revision(game.GetRevision())
 | 
						|
{
 | 
						|
  CreateWidgets();
 | 
						|
  ConnectWidgets();
 | 
						|
 | 
						|
  IniFile game_ini_local;
 | 
						|
 | 
						|
  // We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
 | 
						|
  // will always be stored in GS/${GAMEID}.ini
 | 
						|
  game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");
 | 
						|
 | 
						|
  IniFile game_ini_default = SConfig::GetInstance().LoadDefaultGameIni(m_game_id, m_game_revision);
 | 
						|
  m_ar_codes = ActionReplay::LoadCodes(game_ini_default, game_ini_local);
 | 
						|
 | 
						|
  UpdateList();
 | 
						|
  OnSelectionChanged();
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::CreateWidgets()
 | 
						|
{
 | 
						|
  m_warning = new CheatWarningWidget(m_game_id);
 | 
						|
  m_code_list = new QListWidget;
 | 
						|
  m_code_add = new QPushButton(tr("&Add New Code..."));
 | 
						|
  m_code_edit = new QPushButton(tr("&Edit Code..."));
 | 
						|
  m_code_remove = new QPushButton(tr("&Remove Code"));
 | 
						|
 | 
						|
  auto* button_layout = new QHBoxLayout;
 | 
						|
 | 
						|
  button_layout->addWidget(m_code_add);
 | 
						|
  button_layout->addWidget(m_code_edit);
 | 
						|
  button_layout->addWidget(m_code_remove);
 | 
						|
 | 
						|
  QVBoxLayout* layout = new QVBoxLayout;
 | 
						|
 | 
						|
  layout->addWidget(m_warning);
 | 
						|
  layout->addWidget(m_code_list);
 | 
						|
  layout->addLayout(button_layout);
 | 
						|
 | 
						|
  setLayout(layout);
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::ConnectWidgets()
 | 
						|
{
 | 
						|
  connect(m_warning, &CheatWarningWidget::OpenCheatEnableSettings, this,
 | 
						|
          &ARCodeWidget::OpenGeneralSettings);
 | 
						|
  connect(m_code_list, &QListWidget::itemChanged, this, &ARCodeWidget::OnItemChanged);
 | 
						|
  connect(m_code_list, &QListWidget::itemSelectionChanged, this, &ARCodeWidget::OnSelectionChanged);
 | 
						|
 | 
						|
  connect(m_code_add, &QPushButton::pressed, this, &ARCodeWidget::OnCodeAddPressed);
 | 
						|
  connect(m_code_edit, &QPushButton::pressed, this, &ARCodeWidget::OnCodeEditPressed);
 | 
						|
  connect(m_code_remove, &QPushButton::pressed, this, &ARCodeWidget::OnCodeRemovePressed);
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::OnItemChanged(QListWidgetItem* item)
 | 
						|
{
 | 
						|
  m_ar_codes[m_code_list->row(item)].active = (item->checkState() == Qt::Checked);
 | 
						|
  SaveCodes();
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::OnSelectionChanged()
 | 
						|
{
 | 
						|
  auto items = m_code_list->selectedItems();
 | 
						|
 | 
						|
  if (items.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  const auto* selected = items[0];
 | 
						|
 | 
						|
  bool user_defined = m_ar_codes[m_code_list->row(selected)].user_defined;
 | 
						|
 | 
						|
  m_code_remove->setEnabled(user_defined);
 | 
						|
  m_code_edit->setText(user_defined ? tr("&Edit Code...") : tr("Clone and &Edit Code..."));
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::UpdateList()
 | 
						|
{
 | 
						|
  m_code_list->clear();
 | 
						|
 | 
						|
  for (const auto& ar : m_ar_codes)
 | 
						|
  {
 | 
						|
    auto* item = new QListWidgetItem(QString::fromStdString(ar.name)
 | 
						|
                                         .replace(QStringLiteral("<"), QStringLiteral("<"))
 | 
						|
                                         .replace(QStringLiteral(">"), QStringLiteral(">")));
 | 
						|
 | 
						|
    item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
 | 
						|
    item->setCheckState(ar.active ? Qt::Checked : Qt::Unchecked);
 | 
						|
 | 
						|
    m_code_list->addItem(item);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::SaveCodes()
 | 
						|
{
 | 
						|
  IniFile game_ini_local;
 | 
						|
  game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");
 | 
						|
  ActionReplay::SaveCodes(&game_ini_local, m_ar_codes);
 | 
						|
 | 
						|
  game_ini_local.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::OnCodeAddPressed()
 | 
						|
{
 | 
						|
  ActionReplay::ARCode ar;
 | 
						|
  ar.active = true;
 | 
						|
 | 
						|
  CheatCodeEditor ed;
 | 
						|
 | 
						|
  ed.SetARCode(&ar);
 | 
						|
 | 
						|
  if (ed.exec())
 | 
						|
  {
 | 
						|
    m_ar_codes.push_back(std::move(ar));
 | 
						|
 | 
						|
    UpdateList();
 | 
						|
    SaveCodes();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::OnCodeEditPressed()
 | 
						|
{
 | 
						|
  auto items = m_code_list->selectedItems();
 | 
						|
 | 
						|
  if (items.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  const auto* selected = items[0];
 | 
						|
 | 
						|
  auto& current_ar = m_ar_codes[m_code_list->row(selected)];
 | 
						|
 | 
						|
  bool user_defined = current_ar.user_defined;
 | 
						|
 | 
						|
  ActionReplay::ARCode ar = current_ar;
 | 
						|
 | 
						|
  CheatCodeEditor ed;
 | 
						|
 | 
						|
  ed.SetARCode(user_defined ? ¤t_ar : &ar);
 | 
						|
  ed.exec();
 | 
						|
 | 
						|
  if (!user_defined)
 | 
						|
    m_ar_codes.push_back(ar);
 | 
						|
 | 
						|
  SaveCodes();
 | 
						|
  UpdateList();
 | 
						|
}
 | 
						|
 | 
						|
void ARCodeWidget::OnCodeRemovePressed()
 | 
						|
{
 | 
						|
  auto items = m_code_list->selectedItems();
 | 
						|
 | 
						|
  if (items.empty())
 | 
						|
    return;
 | 
						|
 | 
						|
  const auto* selected = items[0];
 | 
						|
 | 
						|
  m_ar_codes.erase(m_ar_codes.begin() + m_code_list->row(selected));
 | 
						|
 | 
						|
  SaveCodes();
 | 
						|
  UpdateList();
 | 
						|
 | 
						|
  m_code_remove->setEnabled(false);
 | 
						|
}
 |