/[pcsx2_0.9.7]/trunk/common/src/Utilities/wxHelpers.cpp
ViewVC logotype

Contents of /trunk/common/src/Utilities/wxHelpers.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 2 months ago) by william
File size: 14029 byte(s)
re-commit (had local access denied errors when committing)
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "wxGuiTools.h"
18 #include "pxStaticText.h"
19 #include "Threading.h"
20 #include "IniInterface.h"
21
22 #include <wx/cshelp.h>
23 #include <wx/tooltip.h>
24 #include <wx/spinctrl.h>
25
26 using namespace pxSizerFlags;
27
28 pxDialogCreationFlags pxDialogFlags()
29 {
30 return pxDialogCreationFlags().CloseBox().Caption().Vertical();
31 }
32
33
34 // --------------------------------------------------------------------------------------
35 // BaseDeletableObject Implementation
36 // --------------------------------------------------------------------------------------
37 // This code probably deserves a better home. It's general purpose non-GUI code (the single
38 // wxApp/Gui dependency is in wxGuiTools.cpp for now).
39 //
40 bool BaseDeletableObject::MarkForDeletion()
41 {
42 return !_InterlockedExchange( &m_IsBeingDeleted, true );
43 }
44
45 void BaseDeletableObject::DeleteSelf()
46 {
47 if( MarkForDeletion() )
48 DoDeletion();
49 }
50
51 BaseDeletableObject::BaseDeletableObject()
52 {
53 #ifdef _MSC_VER
54 // Bleh, this fails because _CrtIsValidHeapPointer calls HeapValidate on the
55 // pointer, but the pointer is a virtual base class, so it's not a valid block. >_<
56 //pxAssertDev( _CrtIsValidHeapPointer( this ), "BaseDeletableObject types cannot be created on the stack or as temporaries!" );
57 #endif
58
59 m_IsBeingDeleted = false;
60 }
61
62 BaseDeletableObject::~BaseDeletableObject() throw()
63 {
64 AffinityAssert_AllowFrom_MainUI();
65 }
66
67
68 // --------------------------------------------------------------------------------------
69
70
71 // Creates a text control which is right-justified and has it's minimum width configured to suit
72 // the number of digits requested.
73 wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits, long flags )
74 {
75 wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY );
76 ctrl->SetWindowStyleFlag( flags );
77 pxFitToDigits( ctrl, digits );
78 return ctrl;
79 }
80
81 void pxFitToDigits( wxWindow* win, int digits )
82 {
83 int ex;
84 win->GetTextExtent( wxString( L'0', digits+1 ), &ex, NULL );
85 win->SetMinSize( wxSize( ex+10, wxDefaultCoord ) ); // +10 for text control borders/insets and junk.
86 }
87
88 void pxFitToDigits( wxSpinCtrl* win, int digits )
89 {
90 // HACK!! The better way would be to create a pxSpinCtrl class that extends wxSpinCtrl and thus
91 // have access to wxSpinButton::DoGetBestSize(). But since I don't want to do that, we'll just
92 // make/fake it with a value it's pretty common to Win32/GTK/Mac:
93
94 static const int MagicSpinnerSize = 18;
95
96 int ex;
97 win->GetTextExtent( wxString( L'0', digits+1 ), &ex, NULL );
98 win->SetMinSize( wxSize( ex+10+MagicSpinnerSize, wxDefaultCoord ) ); // +10 for text control borders/insets and junk.
99 }
100
101 bool pxDialogExists( const wxString& name )
102 {
103 return wxFindWindowByName( name ) != NULL;
104 }
105
106 // =====================================================================================================
107 // wxDialogWithHelpers Class Implementations
108 // =====================================================================================================
109
110 DEFINE_EVENT_TYPE( pxEvt_OnDialogCreated )
111
112 IMPLEMENT_DYNAMIC_CLASS(wxDialogWithHelpers, wxDialog)
113
114 wxDialogWithHelpers::wxDialogWithHelpers()
115 {
116 m_hasContextHelp = false;
117 m_extraButtonSizer = NULL;
118
119 Init( pxDialogFlags() );
120 }
121
122 wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, const wxString& title, const pxDialogCreationFlags& cflags )
123 : wxDialog( parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, cflags.GetWxWindowFlags() )
124 {
125 m_hasContextHelp = cflags.hasContextHelp;
126 if( (int)cflags.BoxSizerOrient != 0 )
127 {
128 SetSizer( new wxBoxSizer( cflags.BoxSizerOrient ) );
129 *this += StdPadding;
130 }
131
132 Init( cflags );
133 SetMinSize( cflags.MinimumSize );
134 }
135
136 wxDialogWithHelpers::~wxDialogWithHelpers() throw()
137 {
138 }
139
140 void wxDialogWithHelpers::Init( const pxDialogCreationFlags& cflags )
141 {
142 // This fixes it so that the dialogs show up in the task bar in Vista:
143 // (otherwise they go stupid iconized mode if the user minimizes them)
144 if( cflags.hasMinimizeBox )
145 SetExtraStyle(GetExtraStyle() & ~wxTOPLEVEL_EX_DIALOG);
146
147 m_extraButtonSizer = NULL;
148
149 if( m_hasContextHelp )
150 delete wxHelpProvider::Set( new wxSimpleHelpProvider() );
151
152 // GTK/Linux Note: currently the Close (X) button doesn't appear to work in dialogs. Docs
153 // indicate that it should, so I presume the problem is in wxWidgets and that (hopefully!)
154 // an updated version will fix it later. I tried to fix it using a manual Connect but it
155 // didn't do any good. (problem could also be my Co-Linux / x-window manager)
156
157 Connect( pxEvt_OnDialogCreated, wxCommandEventHandler (wxDialogWithHelpers::OnDialogCreated) );
158
159 Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
160 Connect( wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
161 Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (wxDialogWithHelpers::OnCloseWindow) );
162
163 wxCommandEvent createEvent( pxEvt_OnDialogCreated );
164 createEvent.SetId( GetId() );
165 AddPendingEvent( createEvent );
166 }
167
168 void wxDialogWithHelpers::OnDialogCreated( wxCommandEvent& evt )
169 {
170 evt.Skip();
171 if( (evt.GetId() == GetId()) && !GetDialogName().IsEmpty() )
172 SetName( L"Dialog:" + GetDialogName() );
173 }
174
175 wxString wxDialogWithHelpers::GetDialogName() const
176 {
177 return wxEmptyString;
178 }
179
180 void wxDialogWithHelpers::DoAutoCenter()
181 {
182 // Smart positioning logic! If our parent window is larger than our window by some
183 // good amount, then we center on that. If not, center relative to the screen. This
184 // avoids the popup automatically eclipsing the parent window (which happens in PCSX2
185 // a lot since the main window is small).
186
187 bool centerfail = true;
188 if( wxWindow* parent = GetParent() )
189 {
190 const wxSize parentSize( parent->GetSize() );
191
192 if( (parentSize.x > ((int)GetSize().x * 1.5)) || (parentSize.y > ((int)GetSize().y * 1.5)) )
193 {
194 CenterOnParent();
195 centerfail = false;
196 }
197 }
198
199 if( centerfail ) CenterOnScreen();
200 }
201
202 void wxDialogWithHelpers::SmartCenterFit()
203 {
204 Fit();
205
206 const wxString dlgName( GetDialogName() );
207 if( dlgName.IsEmpty() )
208 {
209 DoAutoCenter(); return;
210 }
211
212 if( wxConfigBase* cfg = wxConfigBase::Get( false ) )
213 {
214 wxRect screenRect( GetScreenRect() );
215
216 IniLoader loader( cfg );
217 ScopedIniGroup group( loader, L"DialogPositions" );
218 cfg->SetRecordDefaults( false );
219
220 if( GetWindowStyle() & wxRESIZE_BORDER )
221 {
222 wxSize size;
223 loader.Entry( dlgName + L"_Size", size, screenRect.GetSize() );
224 SetSize( size );
225 }
226
227 if( !cfg->Exists( dlgName + L"_Pos" ) )
228 DoAutoCenter();
229 else
230 {
231 wxPoint pos;
232 loader.Entry( dlgName + L"_Pos", pos, screenRect.GetPosition() );
233 SetPosition( pos );
234 }
235 cfg->SetRecordDefaults( true );
236 }
237 }
238
239 // Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
240 // is based on a heuristic the centers against the parent window if the parent window is at least
241 // 75% larger than the fitted dialog.
242 int wxDialogWithHelpers::ShowModal()
243 {
244 SmartCenterFit();
245 m_CreatedRect = GetScreenRect();
246 return wxDialog::ShowModal();
247 }
248
249 // Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
250 // is based on a heuristic the centers against the parent window if the parent window is at least
251 // 75% larger than the fitted dialog.
252 bool wxDialogWithHelpers::Show( bool show )
253 {
254 if( show )
255 {
256 SmartCenterFit();
257 m_CreatedRect = GetScreenRect();
258 }
259 return wxDialog::Show( show );
260 }
261
262 wxStaticText& wxDialogWithHelpers::Label( const wxString& label )
263 {
264 return *new wxStaticText( this, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_VERTICAL );
265 }
266
267 pxStaticText& wxDialogWithHelpers::Text( const wxString& label )
268 {
269 return *new pxStaticText( this, label );
270 }
271
272 pxStaticText& wxDialogWithHelpers::Heading( const wxString& label )
273 {
274 return *new pxStaticHeading( this, label );
275 }
276
277 bool wxDialogWithHelpers::Destroy()
278 {
279 // Save the dialog position if the dialog is named...
280 // FIXME : This doesn't get called if the app is exited by alt-f4'ing the main app window.
281 // ... not sure how to fix that yet. I could register a list of open windows into wxAppWithHelpers
282 // that systematically get closed. Seems like work, maybe later. --air
283
284 if( wxConfigBase* cfg = IsIconized() ? NULL : wxConfigBase::Get( false ) )
285 {
286 const wxString dlgName( GetDialogName() );
287 const wxRect screenRect( GetScreenRect() );
288 if( !dlgName.IsEmpty() && ( m_CreatedRect != screenRect) )
289 {
290 wxPoint pos( screenRect.GetPosition() );
291 IniSaver saver( cfg );
292 ScopedIniGroup group( saver, L"DialogPositions" );
293
294 if( GetWindowStyle() & wxRESIZE_BORDER )
295 {
296 wxSize size( screenRect.GetSize() );
297 saver.Entry( dlgName + L"_Size", size, screenRect.GetSize() );
298 }
299 saver.Entry( dlgName + L"_Pos", pos, screenRect.GetPosition() );
300 }
301 }
302
303 return _parent::Destroy();
304 }
305
306 void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt )
307 {
308 if( !IsModal() ) Destroy();
309 evt.Skip();
310 }
311
312 void wxDialogWithHelpers::OnOkCancel( wxCommandEvent& evt )
313 {
314 Close();
315 evt.Skip();
316 }
317
318 void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
319 {
320 wxStdDialogButtonSizer& s_buttons( *new wxStdDialogButtonSizer() );
321
322 s_buttons.AddButton( new wxButton( this, wxID_OK ) );
323 s_buttons.AddButton( new wxButton( this, wxID_CANCEL ) );
324
325 if( hasApply )
326 s_buttons.AddButton( new wxButton( this, wxID_APPLY ) );
327
328 m_extraButtonSizer = new wxBoxSizer( wxHORIZONTAL );
329
330 // Add the context-sensitive help button on the caption for the platforms
331 // which support it (currently MSW only)
332 if( m_hasContextHelp )
333 {
334 SetExtraStyle( wxDIALOG_EX_CONTEXTHELP );
335 #ifndef __WXMSW__
336 *m_extraButtonSizer += new wxContextHelpButton(this) | StdButton();
337 #endif
338 }
339
340 // create a sizer to hold the help and ok/cancel buttons, for platforms
341 // that need a custom help icon. [fixme: help icon prolly better off somewhere else]
342 wxFlexGridSizer& flex( *new wxFlexGridSizer( 2 ) );
343 flex.AddGrowableCol( 0, 1 );
344 flex.AddGrowableCol( 1, 15 );
345
346 flex += m_extraButtonSizer | pxAlignLeft;
347 flex += s_buttons | (pxExpand & pxCenter);
348
349 sizer += flex | StdExpand();
350
351 s_buttons.Realize();
352 }
353
354 void wxDialogWithHelpers::AddOkCancel( wxSizer *sizer, bool hasApply )
355 {
356 if( sizer == NULL ) sizer = GetSizer();
357 pxAssume( sizer );
358 AddOkCancel( *sizer, hasApply );
359 }
360
361 wxDialogWithHelpers& wxDialogWithHelpers::SetMinWidth( int newWidth )
362 {
363 SetMinSize( wxSize( newWidth, GetMinHeight() ) );
364 if( wxSizer* sizer = GetSizer() )
365 sizer->SetMinSize( wxSize( newWidth, sizer->GetMinSize().GetHeight() ) );
366 return *this;
367 }
368
369 wxDialogWithHelpers& wxDialogWithHelpers::SetMinHeight( int newHeight )
370 {
371 SetMinSize( wxSize( GetMinWidth(), newHeight ) );
372 if( wxSizer* sizer = GetSizer() )
373 sizer->SetMinSize( wxSize( sizer->GetMinSize().GetWidth(), newHeight ) );
374 return *this;
375 }
376
377 int wxDialogWithHelpers::GetCharHeight() const
378 {
379 return pxGetCharHeight( this, 1 );
380 }
381
382 // --------------------------------------------------------------------------------------
383 // wxPanelWithHelpers Implementations
384 // --------------------------------------------------------------------------------------
385
386 IMPLEMENT_DYNAMIC_CLASS(wxPanelWithHelpers, wxPanel)
387
388 void wxPanelWithHelpers::Init()
389 {
390 }
391
392 // Creates a Static Box container for this panel. the static box sizer becomes the default
393 // sizer for this panel. If the panel already has a sizer set, then that sizer will be
394 // transfered to the new StaticBoxSizer (and will be the first item in it's list, retaining
395 // consistent and expected layout)
396 wxPanelWithHelpers* wxPanelWithHelpers::AddFrame( const wxString& label, wxOrientation orient )
397 {
398 wxSizer* oldSizer = GetSizer();
399
400 SetSizer( new wxStaticBoxSizer( orient, this, label ), false );
401 Init();
402
403 if( oldSizer )
404 *this += oldSizer | pxExpand;
405
406 return this;
407 }
408
409 wxStaticText& wxPanelWithHelpers::Label( const wxString& label )
410 {
411 return *new wxStaticText( this, wxID_ANY, label );
412 }
413
414 pxStaticText& wxPanelWithHelpers::Text( const wxString& label )
415 {
416 return *new pxStaticText( this, label );
417 }
418
419 pxStaticText& wxPanelWithHelpers::Heading( const wxString& label )
420 {
421 return *new pxStaticHeading( this, label );
422 }
423
424 wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, wxOrientation orient, const wxString& staticBoxLabel )
425 : wxPanel( parent )
426 {
427 SetSizer( new wxStaticBoxSizer( orient, this, staticBoxLabel ) );
428 Init();
429 }
430
431 wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, wxOrientation orient )
432 : wxPanel( parent )
433 {
434 SetSizer( new wxBoxSizer( orient ) );
435 Init();
436 }
437
438 wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent )
439 : wxPanel( parent )
440 {
441 Init();
442 }
443
444 wxPanelWithHelpers::wxPanelWithHelpers( wxWindow* parent, const wxPoint& pos, const wxSize& size )
445 : wxPanel( parent, wxID_ANY, pos, size )
446 {
447 Init();
448 }
449
450 wxPanelWithHelpers& wxPanelWithHelpers::SetMinWidth( int newWidth )
451 {
452 SetMinSize( wxSize( newWidth, GetMinHeight() ) );
453 if( wxSizer* sizer = GetSizer() )
454 sizer->SetMinSize( wxSize( newWidth, sizer->GetMinSize().GetHeight() ) );
455 return *this;
456 }
457
458 int pxGetCharHeight( const wxWindow* wind, int rows )
459 {
460 if( !wind ) return 0;
461 wxClientDC dc(wx_const_cast(wxWindow*, wind));
462 dc.SetFont( wind->GetFont() );
463 return (dc.GetCharHeight() + 1 ) * rows;
464 }
465
466 int pxGetCharHeight( const wxWindow& wind, int rows )
467 {
468 return pxGetCharHeight( &wind, rows );
469 }

  ViewVC Help
Powered by ViewVC 1.1.22