2009-09-08 12:08:10 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
2009-09-17 02:12:32 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* 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.
|
2009-07-04 20:53:05 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* 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.
|
2009-07-04 20:53:05 +00:00
|
|
|
*
|
2009-09-08 12:08:10 +00:00
|
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
2009-07-04 20:53:05 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PrecompiledHeader.h"
|
2009-11-18 07:53:02 +00:00
|
|
|
#include "HashMap.h"
|
2009-11-23 06:54:24 +00:00
|
|
|
#include "wxGuiTools.h"
|
2009-11-18 07:53:02 +00:00
|
|
|
#include "pxStaticText.h"
|
2010-01-22 15:22:01 +00:00
|
|
|
#include "Threading.h"
|
2009-07-04 20:53:05 +00:00
|
|
|
|
|
|
|
#include <wx/cshelp.h>
|
2009-11-18 07:53:02 +00:00
|
|
|
#include <wx/tooltip.h>
|
2010-01-04 11:51:09 +00:00
|
|
|
#include <wx/spinctrl.h>
|
2009-07-04 20:53:05 +00:00
|
|
|
|
2009-11-25 15:38:24 +00:00
|
|
|
using namespace pxSizerFlags;
|
|
|
|
|
2010-04-27 13:12:03 +00:00
|
|
|
DEFINE_EVENT_TYPE( pxEvt_OnThreadCleanup );
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
// --------------------------------------------------------------------------------------
|
2010-04-27 13:12:03 +00:00
|
|
|
// BaseDeletableObject Implementation
|
2010-01-22 15:22:01 +00:00
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
// This code probably deserves a better home. It's general purpose non-GUI code (the single
|
|
|
|
// wxApp/Gui dependency is in wxGuiTools.cpp for now).
|
|
|
|
//
|
2010-04-27 13:12:03 +00:00
|
|
|
bool BaseDeletableObject::MarkForDeletion()
|
2010-01-22 15:22:01 +00:00
|
|
|
{
|
|
|
|
return !_InterlockedExchange( &m_IsBeingDeleted, true );
|
|
|
|
}
|
|
|
|
|
2010-04-27 13:12:03 +00:00
|
|
|
void BaseDeletableObject::DeleteSelf()
|
2010-01-22 15:22:01 +00:00
|
|
|
{
|
|
|
|
if( MarkForDeletion() )
|
|
|
|
DoDeletion();
|
|
|
|
}
|
|
|
|
|
2010-04-27 13:12:03 +00:00
|
|
|
BaseDeletableObject::BaseDeletableObject()
|
2010-01-22 15:22:01 +00:00
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
// Bleh, this fails because _CrtIsValidHeapPointer calls HeapValidate on the
|
|
|
|
// pointer, but the pointer is a virtual base class, so it's not a valid block. >_<
|
2010-04-27 13:12:03 +00:00
|
|
|
//pxAssertDev( _CrtIsValidHeapPointer( this ), "BaseDeletableObject types cannot be created on the stack or as temporaries!" );
|
2010-01-22 15:22:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
m_IsBeingDeleted = false;
|
|
|
|
}
|
|
|
|
|
2010-04-27 13:12:03 +00:00
|
|
|
BaseDeletableObject::~BaseDeletableObject() throw()
|
2010-01-22 15:22:01 +00:00
|
|
|
{
|
2010-04-27 13:12:03 +00:00
|
|
|
AffinityAssert_AllowFrom_MainUI();
|
2010-01-22 15:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
2010-01-04 11:51:09 +00:00
|
|
|
// Creates a text control which is right-justified and has it's minimum width configured to suit
|
|
|
|
// the number of digits requested.
|
|
|
|
wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits )
|
|
|
|
{
|
|
|
|
wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY );
|
|
|
|
ctrl->SetWindowStyleFlag( wxTE_RIGHT );
|
|
|
|
pxFitToDigits( ctrl, digits );
|
|
|
|
return ctrl;
|
|
|
|
}
|
2009-11-11 11:36:13 +00:00
|
|
|
|
2010-01-04 11:51:09 +00:00
|
|
|
void pxFitToDigits( wxWindow* win, int digits )
|
|
|
|
{
|
|
|
|
int ex;
|
|
|
|
win->GetTextExtent( wxString( L'0', digits+1 ), &ex, NULL );
|
|
|
|
win->SetMinSize( wxSize( ex+10, wxDefaultCoord ) ); // +10 for text control borders/insets and junk.
|
|
|
|
}
|
|
|
|
|
|
|
|
void pxFitToDigits( wxSpinCtrl* win, int digits )
|
|
|
|
{
|
|
|
|
// HACK!! The better way would be to create a pxSpinCtrl class that extends wxSpinCtrl and thus
|
|
|
|
// have access to wxSpinButton::DoGetBestSize(). But since I don't want to do that, we'll just
|
|
|
|
// make/fake it with a value it's pretty common to Win32/GTK/Mac:
|
|
|
|
|
|
|
|
static const int MagicSpinnerSize = 18;
|
|
|
|
|
|
|
|
int ex;
|
|
|
|
win->GetTextExtent( wxString( L'0', digits+1 ), &ex, NULL );
|
|
|
|
win->SetMinSize( wxSize( ex+10+MagicSpinnerSize, wxDefaultCoord ) ); // +10 for text control borders/insets and junk.
|
|
|
|
}
|
2009-11-08 01:56:24 +00:00
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
bool pxDialogExists( const wxString& name )
|
2009-09-16 17:23:02 +00:00
|
|
|
{
|
2009-12-14 12:18:55 +00:00
|
|
|
return wxFindWindowByName( name ) != NULL;
|
2009-09-16 17:23:02 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 11:51:09 +00:00
|
|
|
// =====================================================================================================
|
|
|
|
// wxDialogWithHelpers Class Implementations
|
|
|
|
// =====================================================================================================
|
|
|
|
|
2009-11-18 07:53:02 +00:00
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxDialogWithHelpers, wxDialog)
|
|
|
|
|
|
|
|
wxDialogWithHelpers::wxDialogWithHelpers()
|
|
|
|
{
|
|
|
|
m_hasContextHelp = false;
|
2009-11-25 15:38:24 +00:00
|
|
|
m_extraButtonSizer = NULL;
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, const wxString& title, bool hasContextHelp, bool resizable )
|
|
|
|
: wxDialog( parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize,
|
|
|
|
wxDEFAULT_DIALOG_STYLE | (resizable ? wxRESIZE_BORDER : 0)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
m_hasContextHelp = hasContextHelp;
|
|
|
|
Init();
|
2009-11-18 07:53:02 +00:00
|
|
|
}
|
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
wxDialogWithHelpers::wxDialogWithHelpers(wxWindow* parent, const wxString& title, wxOrientation orient)
|
|
|
|
: wxDialog( parent, wxID_ANY, title )
|
2009-07-04 20:53:05 +00:00
|
|
|
{
|
2009-12-14 12:18:55 +00:00
|
|
|
m_hasContextHelp = false;
|
|
|
|
SetSizer( new wxBoxSizer( orient ) );
|
|
|
|
Init();
|
2009-09-16 17:23:02 +00:00
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
m_idealWidth = 500;
|
|
|
|
*this += StdPadding;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxDialogWithHelpers::~wxDialogWithHelpers() throw()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void wxDialogWithHelpers::Init()
|
|
|
|
{
|
2009-11-25 15:38:24 +00:00
|
|
|
m_idealWidth = wxDefaultCoord;
|
|
|
|
m_extraButtonSizer = NULL;
|
2009-11-14 08:36:57 +00:00
|
|
|
|
|
|
|
if( m_hasContextHelp )
|
2009-10-25 22:33:23 +00:00
|
|
|
delete wxHelpProvider::Set( new wxSimpleHelpProvider() );
|
2009-07-04 20:53:05 +00:00
|
|
|
|
2009-11-16 03:23:59 +00:00
|
|
|
// GTK/Linux Note: currently the Close (X) button doesn't appear to work in dialogs. Docs
|
|
|
|
// indicate that it should, so I presume the problem is in wxWidgets and that (hopefully!)
|
|
|
|
// an updated version will fix it later. I tried to fix it using a manual Connect but it
|
|
|
|
// didn't do any good. (problem could also be my Co-Linux / x-window manager)
|
2009-12-14 12:18:55 +00:00
|
|
|
|
2009-11-16 03:23:59 +00:00
|
|
|
//Connect( wxEVT_ACTIVATE, wxActivateEventHandler(wxDialogWithHelpers::OnActivate) );
|
2009-12-14 12:18:55 +00:00
|
|
|
|
|
|
|
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
|
|
|
|
Connect( wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
|
|
|
|
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (wxDialogWithHelpers::OnCloseWindow) );
|
2009-07-04 20:53:05 +00:00
|
|
|
}
|
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
void wxDialogWithHelpers::SmartCenterFit()
|
2009-09-16 17:23:02 +00:00
|
|
|
{
|
2009-12-14 12:18:55 +00:00
|
|
|
Fit();
|
|
|
|
|
|
|
|
// Smart positioning logic! If our parent window is larger than our window by some
|
|
|
|
// good amount, then we center on that. If not, center relative to the screen. This
|
|
|
|
// avoids the popup automatically eclipsing the parent window (which happens in PCSX2
|
|
|
|
// a lot since the main window is small).
|
|
|
|
|
|
|
|
bool centerfail = true;
|
|
|
|
if( wxWindow* parent = GetParent() )
|
|
|
|
{
|
|
|
|
const wxSize parentSize( parent->GetSize() );
|
|
|
|
|
|
|
|
if( (parentSize.x > ((int)GetSize().x * 1.75)) && (parentSize.y > ((int)GetSize().y * 1.75)) )
|
|
|
|
{
|
|
|
|
CenterOnParent();
|
|
|
|
centerfail = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( centerfail ) CenterOnScreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
|
|
|
|
// is based on a heuristic the centers against the parent window if the parent window is at least
|
|
|
|
// 75% larger than the fitted dialog.
|
|
|
|
int wxDialogWithHelpers::ShowModal()
|
|
|
|
{
|
|
|
|
SmartCenterFit();
|
|
|
|
return wxDialog::ShowModal();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
|
|
|
|
// is based on a heuristic the centers against the parent window if the parent window is at least
|
|
|
|
// 75% larger than the fitted dialog.
|
|
|
|
bool wxDialogWithHelpers::Show( bool show )
|
|
|
|
{
|
|
|
|
if( show ) SmartCenterFit();
|
|
|
|
return wxDialog::Show( show );
|
2009-09-16 17:23:02 +00:00
|
|
|
}
|
|
|
|
|
2009-11-21 07:44:11 +00:00
|
|
|
pxStaticText* wxDialogWithHelpers::Text( const wxString& label )
|
2009-11-20 03:26:10 +00:00
|
|
|
{
|
|
|
|
return new pxStaticText( this, label );
|
|
|
|
}
|
|
|
|
|
2009-11-21 07:44:11 +00:00
|
|
|
pxStaticHeading* wxDialogWithHelpers::Heading( const wxString& label )
|
2009-11-20 03:26:10 +00:00
|
|
|
{
|
|
|
|
return new pxStaticHeading( this, label );
|
|
|
|
}
|
|
|
|
|
2009-12-14 12:18:55 +00:00
|
|
|
void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt )
|
|
|
|
{
|
|
|
|
if( !IsModal() ) Destroy();
|
|
|
|
evt.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wxDialogWithHelpers::OnOkCancel( wxCommandEvent& evt )
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
evt.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-16 03:23:59 +00:00
|
|
|
void wxDialogWithHelpers::OnActivate(wxActivateEvent& evt)
|
|
|
|
{
|
|
|
|
//evt.Skip();
|
|
|
|
}
|
|
|
|
|
2009-07-14 06:18:52 +00:00
|
|
|
void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
|
2009-07-04 20:53:05 +00:00
|
|
|
{
|
2009-11-25 15:38:24 +00:00
|
|
|
wxStdDialogButtonSizer& s_buttons( *new wxStdDialogButtonSizer() );
|
|
|
|
|
|
|
|
s_buttons.AddButton( new wxButton( this, wxID_OK ) );
|
|
|
|
s_buttons.AddButton( new wxButton( this, wxID_CANCEL ) );
|
|
|
|
|
|
|
|
if( hasApply )
|
|
|
|
s_buttons.AddButton( new wxButton( this, wxID_APPLY ) );
|
|
|
|
|
|
|
|
m_extraButtonSizer = new wxBoxSizer( wxHORIZONTAL );
|
|
|
|
|
|
|
|
// Add the context-sensitive help button on the caption for the platforms
|
|
|
|
// which support it (currently MSW only)
|
2009-07-04 20:53:05 +00:00
|
|
|
if( m_hasContextHelp )
|
|
|
|
{
|
|
|
|
SetExtraStyle( wxDIALOG_EX_CONTEXTHELP );
|
2009-11-27 06:47:32 +00:00
|
|
|
#ifndef __WXMSW__
|
2009-11-26 13:09:23 +00:00
|
|
|
*m_extraButtonSizer += new wxContextHelpButton(this) | StdButton();
|
2009-11-27 06:47:32 +00:00
|
|
|
#endif
|
2009-07-04 20:53:05 +00:00
|
|
|
}
|
2009-11-26 03:37:10 +00:00
|
|
|
|
2009-11-25 15:38:24 +00:00
|
|
|
// create a sizer to hold the help and ok/cancel buttons, for platforms
|
|
|
|
// that need a custom help icon. [fixme: help icon prolly better off somewhere else]
|
|
|
|
wxFlexGridSizer& flex( *new wxFlexGridSizer( 2 ) );
|
|
|
|
flex.AddGrowableCol( 0, 1 );
|
|
|
|
flex.AddGrowableCol( 1, 15 );
|
2009-07-11 08:31:38 +00:00
|
|
|
|
2009-11-26 03:37:10 +00:00
|
|
|
flex += m_extraButtonSizer | pxAlignLeft;
|
2009-12-14 12:18:55 +00:00
|
|
|
flex += s_buttons | (pxExpand & pxCenter);
|
2009-07-11 08:31:38 +00:00
|
|
|
|
2009-11-26 03:37:10 +00:00
|
|
|
sizer += flex | StdExpand();
|
2009-07-11 08:31:38 +00:00
|
|
|
|
|
|
|
s_buttons.Realize();
|
2009-07-04 20:53:05 +00:00
|
|
|
}
|
|
|
|
|
2009-11-18 07:53:02 +00:00
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
// wxPanelWithHelpers Implementations
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxPanelWithHelpers, wxPanel)
|
|
|
|
|
|
|
|
void wxPanelWithHelpers::Init()
|
2009-07-07 20:53:32 +00:00
|
|
|
{
|
2009-11-18 07:53:02 +00:00
|
|
|
m_idealWidth = wxDefaultCoord;
|
|
|
|
|
|
|
|
// Find the first parent with a fixed width:
|
|
|
|
wxWindow* millrun = this->GetParent();
|
|
|
|
while( (m_idealWidth == wxDefaultCoord) && millrun != NULL )
|
|
|
|
{
|
|
|
|
if( wxIsKindOf( millrun, wxPanelWithHelpers ) )
|
|
|
|
m_idealWidth = ((wxPanelWithHelpers*)millrun)->GetIdealWidth();
|
|
|
|
|
|
|
|
else if( wxIsKindOf( millrun, wxDialogWithHelpers ) )
|
|
|
|
m_idealWidth = ((wxDialogWithHelpers*)millrun)->GetIdealWidth();
|
|
|
|
|
|
|
|
millrun = millrun->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_idealWidth == wxDefaultCoord || GetParent() == NULL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Check for a StaticBox -- if we belong to one then we'll want to "downgrade" the
|
|
|
|
// inherited textbox width automatically.
|
|
|
|
|
|
|
|
wxSizer* guess = GetSizer();
|
|
|
|
if( guess == NULL ) guess = GetParent()->GetSizer();
|
|
|
|
if( guess == NULL ) guess = GetParent()->GetContainingSizer();
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2009-11-18 07:53:02 +00:00
|
|
|
if( guess != NULL )
|
|
|
|
{
|
|
|
|
if( wxIsKindOf( guess, wxStaticBoxSizer ) )
|
2010-01-31 02:21:58 +00:00
|
|
|
{
|
|
|
|
int top=0, others=0;
|
2009-11-18 07:53:02 +00:00
|
|
|
((wxStaticBoxSizer*)guess)->GetStaticBox()->GetBordersForSizer( &top, &others );
|
2010-01-31 02:21:58 +00:00
|
|
|
m_idealWidth -= others*2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_idealWidth -= 2; // generic padding compensation (no exact sciences to be found here)
|
2009-11-18 07:53:02 +00:00
|
|
|
}
|
2009-07-07 20:53:32 +00:00
|
|
|
}
|
|
|
|
|
2009-11-21 07:44:11 +00:00
|
|
|
// Creates a Static Box container for this panel. the static box sizer becomes the default
|
|
|
|
// sizer for this panel. If the panel already has a sizer set, then that sizer will be
|
|
|
|
// transfered to the new StaticBoxSizer (and will be the first item in it's list, retaining
|
|
|
|
// consistent and expected layout)
|
|
|
|
wxPanelWithHelpers* wxPanelWithHelpers::AddFrame( const wxString& label, wxOrientation orient )
|
2009-07-07 20:53:32 +00:00
|
|
|
{
|
2009-11-18 07:53:02 +00:00
|
|
|
wxSizer* oldSizer = GetSizer();
|
|
|
|
|
|
|
|
SetSizer( new wxStaticBoxSizer( orient, this, label ), false );
|
|
|
|
Init();
|
|
|
|
|
|
|
|
if( oldSizer )
|
2009-11-25 03:54:57 +00:00
|
|
|
*this += oldSizer | pxExpand;
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2009-11-18 07:53:02 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2009-11-21 07:44:11 +00:00
|
|
|
pxStaticText* wxPanelWithHelpers::Text( const wxString& label )
|
2009-11-20 03:26:10 +00:00
|
|
|
{
|
|
|
|
return new pxStaticText( this, label );
|
|
|
|
}
|
|
|
|
|
2009-11-21 07:44:11 +00:00
|
|
|
pxStaticHeading* wxPanelWithHelpers::Heading( const wxString& label )
|
2009-11-20 03:26:10 +00:00
|
|
|
{
|
|
|
|
return new pxStaticHeading( this, label );
|
|
|
|
}
|
|
|
|
|
2009-11-18 07:53:02 +00:00
|
|
|
wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, wxOrientation orient, const wxString& staticBoxLabel )
|
|
|
|
: wxPanel( parent )
|
|
|
|
{
|
|
|
|
SetSizer( new wxStaticBoxSizer( orient, this, staticBoxLabel ) );
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, wxOrientation orient )
|
|
|
|
: wxPanel( parent )
|
|
|
|
{
|
|
|
|
SetSizer( new wxBoxSizer( orient ) );
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent )
|
|
|
|
: wxPanel( parent )
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, const wxPoint& pos, const wxSize& size )
|
|
|
|
: wxPanel( parent, wxID_ANY, pos, size )
|
|
|
|
{
|
|
|
|
Init();
|
2009-07-07 20:53:32 +00:00
|
|
|
}
|