pcsx2/pcsx2/gui/ApplyState.h

244 lines
8.4 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <list>
#include <wx/wizard.h>
#include "AppCommon.h"
class BaseApplicableConfigPanel;
class BaseApplicableDialog;
wxDECLARE_EVENT(pxEvt_ApplySettings, wxCommandEvent);
namespace Exception
{
// --------------------------------------------------------------------------
// Exception used to perform an abort of Apply/Ok action on settings panels.
// When thrown, the user receives a popup message containing the information
// specified in the exception message, and is returned to the settings dialog
// to correct the invalid input fields.
//
class CannotApplySettings : public BaseException
{
DEFINE_EXCEPTION_COPYTORS( CannotApplySettings, BaseException )
DEFINE_EXCEPTION_MESSAGES( CannotApplySettings )
public:
bool IsVerbose;
protected:
BaseApplicableConfigPanel* m_Panel;
protected:
CannotApplySettings() { IsVerbose = true; }
public:
explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel )
{
SetBothMsgs("Cannot apply new settings, one of the settings is invalid.");
m_Panel = thispanel;
IsVerbose = true;
}
virtual CannotApplySettings& Quiet() { IsVerbose = false; return *this; }
BaseApplicableConfigPanel* GetPanel() { return m_Panel; }
};
}
typedef std::list<BaseApplicableConfigPanel*> PanelApplyList_t;
struct ApplyStateStruct
{
// collection of ApplicableConfigPanels that belong to a dialog box.
PanelApplyList_t PanelList;
// Current book page being initialized. Any apply objects created will use
// this page as their "go here on error" page. (used to take the user to the
// page with the option that failed apply validation).
int CurOwnerPage;
// TODO : Rename me to CurOwnerBook, or rename the one above to ParentPage.
wxBookCtrlBase* ParentBook;
ApplyStateStruct()
{
CurOwnerPage = wxID_NONE;
ParentBook = NULL;
}
void SetCurrentPage( int page )
{
CurOwnerPage = page;
}
void ClearCurrentPage()
{
CurOwnerPage = wxID_NONE;
}
void StartBook( wxBookCtrlBase* book );
void StartWizard();
bool ApplyAll();
bool ApplyPage( int pageid );
void DoCleanup() noexcept;
};
class IApplyState
{
protected:
ApplyStateStruct m_ApplyState;
public:
virtual ApplyStateStruct& GetApplyState() { return m_ApplyState; }
};
// --------------------------------------------------------------------------------------
// BaseApplicableDialog
// --------------------------------------------------------------------------------------
class BaseApplicableDialog
: public wxDialogWithHelpers
, public IApplyState
{
wxDECLARE_DYNAMIC_CLASS_NO_COPY(BaseApplicableDialog);
public:
BaseApplicableDialog() {}
virtual ~BaseApplicableDialog();
// Must return the same thing as GetNameStatic; a name ideal for use in uniquely
// identifying dialogs. (this version is the 'instance' version, which is called
// by BaseConfigurationDialog to assign the wxWidgets dialog name, and for saving
// screenshots to disk)
virtual wxString GetDialogName() const;
protected:
void Init();
BaseApplicableDialog(wxWindow* parent, const wxString& title, const pxDialogCreationFlags& cflags = pxDialogCreationFlags() );
virtual void OnSettingsApplied( wxCommandEvent& evt );
// Note: This method *will* be called automatically after a successful Apply, but will not
// be called after a failed Apply (canceled due to error).
virtual void AppStatusEvent_OnSettingsApplied() {}
virtual void AppStatusEvent_OnUiSettingsLoadSave( const AppSettingsEventInfo& ) {}
virtual void AppStatusEvent_OnExit() {}
};
// --------------------------------------------------------------------------------------
// BaseApplicableConfigPanel
// --------------------------------------------------------------------------------------
// Extends the Panel class to add an Apply() method, which is invoked from the parent
// window (usually the ConfigurationDialog) when either Ok or Apply is clicked.
//
// Thread Safety: None. This class is only safe when used from the GUI thread, as it uses
// static vars and assumes that only one ApplicableConfig system is available to the
// user at any time (ie, a singular modal dialog).
//
class BaseApplicableConfigPanel
: public wxPanelWithHelpers
{
protected:
int m_OwnerPage;
wxBookCtrlBase* m_OwnerBook;
EventListenerHelper_AppStatus<BaseApplicableConfigPanel> m_AppStatusHelper;
public:
virtual ~BaseApplicableConfigPanel();
BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient=wxVERTICAL );
BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient, const wxString& staticLabel );
int GetOwnerPage() const { return m_OwnerPage; }
wxBookCtrlBase* GetOwnerBook() { return m_OwnerBook; }
void SetFocusToMe();
IApplyState* FindApplyStateManager() const;
// Returns true if this ConfigPanel belongs to the specified page. Useful for doing
// selective application of options for specific pages.
bool IsOnPage( int pageid ) { return m_OwnerPage == pageid; }
// This method attempts to assign the settings for the panel into the given
// configuration structure (which is typically a copy of g_Conf). If validation
// of form contents fails, the function should throw Exception::CannotApplySettings.
// If no exceptions are thrown, then the operation is assumed a success. :)
virtual void Apply()=0;
//Enable the apply button manually if required (in case the auto-trigger doesn't kick in, e.g. when clicking a button)
void SomethingChanged();
void Init();
// Mandatory override: As a rule for proper interface design, all deriving classes need
// to implement this OnSettingsApplied function. There's no implementation of an options/
// settings panel that does not heed the changes of application status/settings changes. ;)
//
// Note: This method *will* be called automatically after a successful Apply, but will not
// be called after a failed Apply (canceled due to error).
virtual void AppStatusEvent_OnSettingsApplied()=0;
virtual void AppStatusEvent_OnUiSettingsLoadSave( const AppSettingsEventInfo& ) {}
virtual void AppStatusEvent_OnVmSettingsLoadSave( const AppSettingsEventInfo& ) {}
virtual void AppStatusEvent_OnExit() {}
virtual bool IsSpecificConfig(){return false;} //lame RTTI
protected:
virtual void OnSettingsApplied( wxCommandEvent& evt );
};
class BaseApplicableConfigPanel_SpecificConfig : public BaseApplicableConfigPanel
{
//This class only differs from BaseApplicableConfigPanel by systematically allowing the gui to be updated
//from a specific config (used by the presets system to trash not g_Conf in case the user pressed "Cancel").
//Every panel that the Presets affect should be derived from this and not from BaseApplicableConfigPanel.
//
//Multiple inheritance would have been better (also for cases of non BaseApplicableConfigPanel which are effected by presets),
//but multiple inheritance sucks. So, subclass.
//NOTE: because ApplyConfigToGui is called manually and not via an event, it must consider manuallyPropagate and call sub panels.
public:
virtual bool IsSpecificConfig(){return true;};
BaseApplicableConfigPanel_SpecificConfig( wxWindow* parent, wxOrientation orient=wxVERTICAL );
BaseApplicableConfigPanel_SpecificConfig( wxWindow* parent, wxOrientation orient, const wxString& staticLabel );
//possible flags are: AppConfig: APPLY_FLAG_MANUALLY_PROPAGATE and APPLY_FLAG_IS_FROM_PRESET
virtual void ApplyConfigToGui(AppConfig& configToApply, int flags=0) = 0;
};
class ApplicableWizardPage : public wxWizardPageSimple, public IApplyState
{
wxDECLARE_DYNAMIC_CLASS_NO_COPY(ApplicableWizardPage);
public:
ApplicableWizardPage(
wxWizard* parent=NULL,
wxWizardPage *prev = NULL,
wxWizardPage *next = NULL,
const wxBitmap& bitmap = wxNullBitmap
);
virtual ~ApplicableWizardPage() { m_ApplyState.DoCleanup(); }
virtual bool PrepForApply();
};