mirror of https://github.com/PCSX2/pcsx2.git
422 lines
13 KiB
C++
422 lines
13 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2010 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 <wx/event.h>
|
|
|
|
wxDECLARE_EVENT(pxEvt_StartIdleEventTimer, wxCommandEvent);
|
|
wxDECLARE_EVENT(pxEvt_DeleteObject, wxCommandEvent);
|
|
wxDECLARE_EVENT(pxEvt_DeleteThread, wxCommandEvent);
|
|
|
|
typedef void FnType_Void();
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// SynchronousActionState
|
|
// --------------------------------------------------------------------------------------
|
|
class SynchronousActionState
|
|
{
|
|
DeclareNoncopyableObject(SynchronousActionState);
|
|
|
|
protected:
|
|
bool m_posted;
|
|
Threading::Semaphore m_sema;
|
|
ScopedExcept m_exception;
|
|
|
|
public:
|
|
sptr return_value;
|
|
|
|
SynchronousActionState()
|
|
{
|
|
m_posted = false;
|
|
return_value = 0;
|
|
}
|
|
|
|
virtual ~SynchronousActionState() = default;
|
|
|
|
void SetException(const BaseException &ex);
|
|
void SetException(BaseException *ex);
|
|
|
|
Threading::Semaphore &GetSemaphore() { return m_sema; }
|
|
const Threading::Semaphore &GetSemaphore() const { return m_sema; }
|
|
|
|
void RethrowException() const;
|
|
int WaitForResult();
|
|
int WaitForResult_NoExceptions();
|
|
void PostResult(int res);
|
|
void ClearResult();
|
|
void PostResult();
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxSimpleEvent - non-abstract implementation of wxEvent
|
|
// --------------------------------------------------------------------------------------
|
|
// Why? I mean, why is wxEvent abstract? Over-designed OO is such a bad habit. And while
|
|
// I'm on my high horse (and it's so very high!), why use 'private'? Ever? Seriously, it
|
|
// sucks. Stop using it, people.
|
|
//
|
|
class pxSimpleEvent : public wxEvent
|
|
{
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSimpleEvent);
|
|
|
|
public:
|
|
explicit pxSimpleEvent(int evtid = 0)
|
|
: wxEvent(0, evtid)
|
|
{
|
|
}
|
|
|
|
pxSimpleEvent(wxWindowID winId, int evtid)
|
|
: wxEvent(winId, evtid)
|
|
{
|
|
}
|
|
|
|
pxSimpleEvent(const pxSimpleEvent&) = default;
|
|
virtual wxEvent *Clone() const { return new pxSimpleEvent(*this); }
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxActionEvent
|
|
// --------------------------------------------------------------------------------------
|
|
class pxActionEvent;
|
|
|
|
wxDECLARE_EVENT(pxEvt_InvokeAction, pxActionEvent);
|
|
|
|
class pxActionEvent : public wxEvent
|
|
{
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxActionEvent);
|
|
|
|
protected:
|
|
SynchronousActionState *m_state;
|
|
|
|
public:
|
|
virtual ~pxActionEvent() = default;
|
|
virtual pxActionEvent *Clone() const { return new pxActionEvent(*this); }
|
|
|
|
explicit pxActionEvent(SynchronousActionState *sema = NULL, int msgtype = pxEvt_InvokeAction);
|
|
explicit pxActionEvent(SynchronousActionState &sema, int msgtype = pxEvt_InvokeAction);
|
|
pxActionEvent(const pxActionEvent &src);
|
|
|
|
Threading::Semaphore *GetSemaphore() const { return m_state ? &m_state->GetSemaphore() : NULL; }
|
|
|
|
const SynchronousActionState *GetSyncState() const { return m_state; }
|
|
SynchronousActionState *GetSyncState() { return m_state; }
|
|
|
|
void SetSyncState(SynchronousActionState *obj) { m_state = obj; }
|
|
void SetSyncState(SynchronousActionState &obj) { m_state = &obj; }
|
|
|
|
virtual void SetException(BaseException *ex);
|
|
void SetException(const BaseException &ex);
|
|
|
|
virtual void _DoInvokeEvent();
|
|
|
|
protected:
|
|
// Extending classes should implement this method to perform whatever action it is
|
|
// the event is supposed to do. :) Thread affinity is guaranteed to be the Main/UI
|
|
// thread, and exceptions will be handled automatically.
|
|
//
|
|
// Exception note: exceptions are passed back to the thread that posted the event
|
|
// to the queue, when possible. If the calling thread is not blocking for a result
|
|
// from this event, then the exception will be posted to the Main/UI thread instead.
|
|
virtual void InvokeEvent() {}
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxExceptionEvent
|
|
// --------------------------------------------------------------------------------------
|
|
class pxExceptionEvent : public pxActionEvent
|
|
{
|
|
typedef pxActionEvent _parent;
|
|
|
|
protected:
|
|
BaseException *m_except;
|
|
|
|
public:
|
|
pxExceptionEvent(BaseException *ex = NULL)
|
|
{
|
|
m_except = ex;
|
|
}
|
|
|
|
pxExceptionEvent(const BaseException &ex);
|
|
|
|
virtual ~pxExceptionEvent()
|
|
{
|
|
}
|
|
|
|
virtual pxExceptionEvent *Clone() const { return new pxExceptionEvent(*this); }
|
|
|
|
protected:
|
|
void InvokeEvent();
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxSynchronousCommandEvent
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
class pxSynchronousCommandEvent : public wxCommandEvent
|
|
{
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxSynchronousCommandEvent);
|
|
|
|
protected:
|
|
SynchronousActionState *m_sync;
|
|
wxEventType m_realEvent;
|
|
|
|
public:
|
|
virtual ~pxSynchronousCommandEvent() = default;
|
|
virtual pxSynchronousCommandEvent *Clone() const { return new pxSynchronousCommandEvent(*this); }
|
|
|
|
pxSynchronousCommandEvent(SynchronousActionState *sema = NULL, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
|
pxSynchronousCommandEvent(SynchronousActionState &sema, wxEventType commandType = wxEVT_NULL, int winid = 0);
|
|
|
|
pxSynchronousCommandEvent(SynchronousActionState *sema, const wxCommandEvent &evt);
|
|
pxSynchronousCommandEvent(SynchronousActionState &sema, const wxCommandEvent &evt);
|
|
|
|
pxSynchronousCommandEvent(const pxSynchronousCommandEvent &src);
|
|
|
|
Threading::Semaphore *GetSemaphore() { return m_sync ? &m_sync->GetSemaphore() : NULL; }
|
|
wxEventType GetRealEventType() const { return m_realEvent; }
|
|
|
|
void SetException(BaseException *ex);
|
|
void SetException(const BaseException &ex);
|
|
};
|
|
|
|
wxDECLARE_EVENT(pxEvt_SynchronousCommand, pxSynchronousCommandEvent);
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// BaseMessageBoxEvent
|
|
// --------------------------------------------------------------------------------------
|
|
class BaseMessageBoxEvent : public pxActionEvent
|
|
{
|
|
typedef pxActionEvent _parent;
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent);
|
|
|
|
protected:
|
|
wxString m_Content;
|
|
|
|
public:
|
|
virtual ~BaseMessageBoxEvent() = default;
|
|
virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); }
|
|
|
|
explicit BaseMessageBoxEvent(const wxString &content = wxEmptyString, SynchronousActionState *instdata = NULL);
|
|
BaseMessageBoxEvent(const wxString &content, SynchronousActionState &instdata);
|
|
BaseMessageBoxEvent(const BaseMessageBoxEvent &event);
|
|
|
|
protected:
|
|
virtual void InvokeEvent();
|
|
virtual int _DoDialog() const;
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// MsgButtons
|
|
// --------------------------------------------------------------------------------------
|
|
class MsgButtons
|
|
{
|
|
protected:
|
|
BITFIELD32()
|
|
bool
|
|
m_OK : 1,
|
|
m_Cancel : 1,
|
|
m_Yes : 1,
|
|
m_No : 1,
|
|
m_AllowToAll : 1,
|
|
m_Apply : 1,
|
|
m_Abort : 1,
|
|
m_Retry : 1,
|
|
m_Ignore : 1,
|
|
m_Reset : 1,
|
|
m_Close : 1;
|
|
BITFIELD_END
|
|
|
|
wxString m_CustomLabel;
|
|
wxString m_CustomLabelId;
|
|
|
|
public:
|
|
MsgButtons() { bitset = 0; }
|
|
|
|
MsgButtons &OK()
|
|
{
|
|
m_OK = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Cancel()
|
|
{
|
|
m_Cancel = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Apply()
|
|
{
|
|
m_Apply = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Yes()
|
|
{
|
|
m_Yes = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &No()
|
|
{
|
|
m_No = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &ToAll()
|
|
{
|
|
m_AllowToAll = true;
|
|
return *this;
|
|
}
|
|
|
|
MsgButtons &Abort()
|
|
{
|
|
m_Abort = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Retry()
|
|
{
|
|
m_Retry = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Ignore()
|
|
{
|
|
m_Ignore = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Reset()
|
|
{
|
|
m_Reset = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &Close()
|
|
{
|
|
m_Close = true;
|
|
return *this;
|
|
}
|
|
|
|
// label - native language label displayed to user
|
|
// id - raw ASCII identifier used in the config file (do not translate, hence char*)
|
|
MsgButtons &Custom(const wxString &label, const char *id)
|
|
{
|
|
m_CustomLabel = label;
|
|
m_CustomLabelId = fromUTF8(id);
|
|
return *this;
|
|
}
|
|
|
|
MsgButtons &OKCancel()
|
|
{
|
|
m_OK = m_Cancel = true;
|
|
return *this;
|
|
}
|
|
MsgButtons &YesNo()
|
|
{
|
|
m_Yes = m_No = true;
|
|
return *this;
|
|
}
|
|
|
|
bool HasOK() const { return m_OK; }
|
|
bool HasCancel() const { return m_Cancel; }
|
|
bool HasApply() const { return m_Apply; }
|
|
bool HasYes() const { return m_Yes; }
|
|
bool HasNo() const { return m_No; }
|
|
bool AllowsToAll() const { return m_AllowToAll; }
|
|
|
|
bool HasAbort() const { return m_Abort; }
|
|
bool HasRetry() const { return m_Retry; }
|
|
bool HasIgnore() const { return m_Ignore; }
|
|
bool HasReset() const { return m_Reset; }
|
|
bool HasClose() const { return m_Close; }
|
|
|
|
bool HasCustom() const { return !m_CustomLabel.IsEmpty(); }
|
|
const wxString &GetCustomLabel() const { return m_CustomLabel; }
|
|
const wxString &GetCustomLabelId() const { return m_CustomLabelId; }
|
|
|
|
bool Allows(wxWindowID id) const;
|
|
void SetBestFocus(wxWindow *dialog) const;
|
|
void SetBestFocus(wxWindow &dialog) const;
|
|
|
|
bool operator==(const MsgButtons &right) const
|
|
{
|
|
return OpEqu(bitset);
|
|
}
|
|
|
|
bool operator!=(const MsgButtons &right) const
|
|
{
|
|
return !OpEqu(bitset);
|
|
}
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxMessageBoxEvent
|
|
// --------------------------------------------------------------------------------------
|
|
// This event type is used to transfer message boxes to the main UI thread, and return the
|
|
// result of the box. It's the only way a message box can be issued from non-main threads
|
|
// with complete safety in wx2.8.
|
|
//
|
|
// For simplicity sake this message box only supports two basic designs. The main design
|
|
// is a generic message box with confirmation buttons of your choosing. Additionally you
|
|
// can specify a "scrollableContent" text string, which is added into a read-only richtext
|
|
// control similar to the console logs and such.
|
|
//
|
|
// Future consideration: If wxWidgets 3.0 has improved thread safety, then it should probably
|
|
// be reasonable for it to work with a more flexable model where the dialog can be created
|
|
// on a child thread, passed to the main thread, where ShowModal() is run (keeping the nested
|
|
// message pumps on the main thread where they belong). But so far this is not possible,
|
|
// because of various subtle issues in wx2.8 design.
|
|
//
|
|
class pxMessageBoxEvent : public BaseMessageBoxEvent
|
|
{
|
|
typedef BaseMessageBoxEvent _parent;
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent);
|
|
|
|
protected:
|
|
wxString m_Title;
|
|
MsgButtons m_Buttons;
|
|
|
|
public:
|
|
virtual ~pxMessageBoxEvent() = default;
|
|
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
|
|
|
pxMessageBoxEvent() {}
|
|
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState &instdata);
|
|
pxMessageBoxEvent(const wxString &title, const wxString &content, const MsgButtons &buttons, SynchronousActionState *instdata = NULL);
|
|
pxMessageBoxEvent(const pxMessageBoxEvent &event) = default;
|
|
|
|
protected:
|
|
int _DoDialog() const;
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
// pxAssertionEvent
|
|
// --------------------------------------------------------------------------------------
|
|
class pxAssertionEvent : public BaseMessageBoxEvent
|
|
{
|
|
typedef BaseMessageBoxEvent _parent;
|
|
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxAssertionEvent);
|
|
|
|
protected:
|
|
wxString m_Stacktrace;
|
|
|
|
public:
|
|
virtual ~pxAssertionEvent() = default;
|
|
virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); }
|
|
|
|
pxAssertionEvent(const wxString &content = wxEmptyString, const wxString &trace = wxEmptyString, SynchronousActionState *instdata = NULL);
|
|
pxAssertionEvent(const wxString &content, const wxString &trace, SynchronousActionState &instdata);
|
|
pxAssertionEvent(const pxAssertionEvent &event) = default;
|
|
|
|
pxAssertionEvent &SetStacktrace(const wxString &trace);
|
|
|
|
protected:
|
|
int _DoDialog() const;
|
|
};
|