/* 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 . */ #pragma once // ---------------------------------------------------------------------------- // wxGuiTools.h // // This file is meant to contain utility classes for users of the wxWidgets library. // All classes in this file are dependent on wxBase and wxCore libraries! Meaning // you will have to use wxCore header files and link against wxCore (GUI) to build // them. For tools which require only wxBase, see wxBaseTools.h // ---------------------------------------------------------------------------- #if wxUSE_GUI #include "Dependencies.h" #include #include #include class pxStaticText; class pxStaticHeading; class pxCheckBox; class wxSpinCtrl; namespace pxSizerFlags { static const int StdPadding = 4; extern wxSizerFlags StdSpace(); extern wxSizerFlags StdCenter(); extern wxSizerFlags StdExpand(); extern wxSizerFlags TopLevelBox(); extern wxSizerFlags SubGroup(); extern wxSizerFlags StdButton(); extern wxSizerFlags Checkbox(); }; #define wxSF wxSizerFlags() // -------------------------------------------------------------------------------------- // pxAlignment / pxStretchType // -------------------------------------------------------------------------------------- // These are full blown class types instead of enumerations because wxSizerFlags has an // implicit conversion from integer (silly design flaw creating more work for me!) // struct pxAlignmentType { enum { Centre, Center = Centre, Middle, Left, Right, Top, Bottom }; int intval; wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const; wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const { return Apply( _flgs ); } wxSizerFlags Expand() const { return Apply().Expand(); } wxSizerFlags Border( int dir, int padding ) const { return Apply().Border( dir, padding ); } wxSizerFlags Proportion() const { return Apply().Proportion( intval ); } operator wxSizerFlags() const { return Apply(); } }; struct pxStretchType { enum { Shrink, Expand, Shaped, ReserveHidden, FixedMinimum }; int intval; wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const; wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const { return Apply( _flgs ); } wxSizerFlags Border( int dir, int padding ) const { return Apply().Border( dir, padding ); } wxSizerFlags Proportion() const { return Apply().Proportion( intval ); } operator wxSizerFlags() const { return Apply(); } }; static __fi wxSizerFlags pxProportion( int prop ) { return wxSizerFlags( prop ); } static __fi wxSizerFlags pxBorder( int dir=wxALL, int pad=pxSizerFlags::StdPadding ) { return wxSizerFlags().Border( dir, pad ); } class pxStretchSpacer { public: int proportion; pxStretchSpacer( int prop=0 ) { proportion = prop; } }; extern const pxAlignmentType pxCentre, // Horizontal centered alignment pxCenter, pxMiddle, // vertical centered alignment pxAlignLeft, pxAlignRight, pxAlignTop, pxAlignBottom; extern const pxStretchType pxShrink, pxExpand, pxShaped, pxReserveHidden, pxFixedMinimum; // -------------------------------------------------------------------------------------- // pxWindowAndFlags // -------------------------------------------------------------------------------------- // This struct is a go-between for combining windows and sizer flags in "neat" fashion. // To create the struct, use the | operator, like so: // // myPanel | wxSizerFlags().Expand() // // Implementation Note: This struct is a template as it allows us to use a special // version of the += operator that retains the type information of the window, in case // the window implements its own += overloads (one example is pxStaticText). Without the // template, the type of the window would only be known as "wxWindow" when it's added to the // sizer, and would thus fail to invoke the correct operator overload. // template< typename WinType > struct pxWindowAndFlags { WinType* window; wxSizerFlags flags; }; extern wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 ); template< typename WinType > pxWindowAndFlags operator | ( WinType* _win, const wxSizerFlags& _flgs ) { pxWindowAndFlags result = { _win, _flgs }; return result; } template< typename WinType > pxWindowAndFlags operator | ( WinType& _win, const wxSizerFlags& _flgs ) { pxWindowAndFlags result = { &_win, _flgs }; return result; } // -------------------------------------------------------------------------------------- // wxSizer Operator += .. a wxSizer.Add() Substitute // -------------------------------------------------------------------------------------- // This set of operators is the *recommended* method for adding windows to sizers, not just // because it's a lot prettier but also because it allows controls like pxStaticText to over- // ride default sizerflags behavior. // // += operator works on either sizers, wxDialogs or wxPanels. In the latter case, the window // is added to the dialog/panel's toplevel sizer (wxPanel.GetSizer() is used). If the panel // has no sizer set via SetSizer(), an assertion is generated. // extern void operator+=( wxSizer& target, wxWindow* src ); extern void operator+=( wxSizer& target, wxSizer* src ); extern void operator+=( wxSizer& target, wxWindow& src ); extern void operator+=( wxSizer& target, wxSizer& src ); extern void operator+=( wxSizer* target, wxWindow& src ); extern void operator+=( wxSizer* target, wxSizer& src ); extern void operator+=( wxSizer& target, int spacer ); extern void operator+=( wxWindow& target, int spacer ); extern void operator+=( wxSizer& target, const pxStretchSpacer& spacer ); extern void operator+=( wxWindow& target, const pxStretchSpacer& spacer ); // ---------------------------------------------------------------------------- // Important: This template is needed in order to retain window type information and // invoke the proper overloaded version of += (which is used by pxStaticText and other // classes to perform special actions when added to sizers). template< typename WinType > void operator+=( wxWindow& target, WinType* src ) { if( !pxAssert( target.GetSizer() != NULL ) ) return; *target.GetSizer() += src; } template< typename WinType > void operator+=( wxWindow& target, WinType& src ) { if( !pxAssert( target.GetSizer() != NULL ) ) return; *target.GetSizer() += src; } template< typename WinType > void operator+=( wxWindow& target, const pxWindowAndFlags& src ) { if( !pxAssert( target.GetSizer() != NULL ) ) return; *target.GetSizer() += src; } template< typename WinType > void operator+=( wxSizer& target, const pxWindowAndFlags& src ) { target.Add( src.window, src.flags ); } BEGIN_DECLARE_EVENT_TYPES() // Added to the event queue by pxDialogWithHelpers DECLARE_EVENT_TYPE( pxEvt_OnDialogCreated, -1 ) END_DECLARE_EVENT_TYPES() // -------------------------------------------------------------------------------------- // pxDialogCreationFlags // -------------------------------------------------------------------------------------- class pxDialogCreationFlags { public: wxSize MinimumSize; wxOrientation BoxSizerOrient; bool isResizable; bool hasContextHelp; bool hasCaption; bool hasMinimizeBox; bool hasMaximizeBox; bool hasSystemMenu; bool hasCloseBox; public: virtual ~pxDialogCreationFlags() throw() {} pxDialogCreationFlags() { MinimumSize = wxDefaultSize; BoxSizerOrient = wxVERTICAL; isResizable = false; hasContextHelp = false; hasCloseBox = true; hasSystemMenu = true; hasMinimizeBox = false; hasMaximizeBox = false; hasCaption = true; } pxDialogCreationFlags& SetSizerOrient( wxOrientation orient ) { BoxSizerOrient = orient; return *this; } pxDialogCreationFlags& SetResize( bool enable=true ) { isResizable = enable; return *this; } pxDialogCreationFlags& SetMinimize( bool enable=true ) { hasMinimizeBox = enable; return *this; } pxDialogCreationFlags& SetMaximize( bool enable=true ) { hasMaximizeBox = enable; return *this; } // NOTE: Enabling system menu on dialogs usually doesn't work, and might cause // other unwanted behavior, such as a missing close button. pxDialogCreationFlags& SetSystemMenu( bool enable=true ) { hasSystemMenu = enable; return *this; } pxDialogCreationFlags& SetCaption( bool enable=true ) { hasCaption = enable; return *this; } pxDialogCreationFlags& SetCloseBox( bool enable=true ) { hasCloseBox = enable; return *this; } pxDialogCreationFlags SetContextHelp( bool enabled=true ) { hasContextHelp = enabled; return *this; } pxDialogCreationFlags& SetMinWidth( int width ) { if( width > MinimumSize.x ) MinimumSize.SetWidth( width ); return *this; } pxDialogCreationFlags& SetMinHeight( int height ) { if( height > MinimumSize.y ) MinimumSize.SetHeight( height ); return *this; } pxDialogCreationFlags& SetMinSize( const wxSize& size ) { return SetMinWidth(size.x).SetMinHeight(size.y); } pxDialogCreationFlags Horizontal() const { return pxDialogCreationFlags(*this).SetSizerOrient( wxHORIZONTAL ); } pxDialogCreationFlags Vertical() const { return pxDialogCreationFlags(*this).SetSizerOrient( wxVERTICAL ); } pxDialogCreationFlags NoSizer() const { return pxDialogCreationFlags(*this).SetSizerOrient( (wxOrientation)0 ); } pxDialogCreationFlags Resize( bool enable=true ) const { return pxDialogCreationFlags(*this).SetResize( enable ); } pxDialogCreationFlags Minimize( bool enable=true ) const { return pxDialogCreationFlags(*this).SetMinimize( enable ); } pxDialogCreationFlags Maximize( bool enable=true ) const { return pxDialogCreationFlags(*this).SetMaximize( enable ); } // NOTE: Enabling system menu on dialogs usually doesn't work, and might cause // other unwanted behavior, such as a missing close button. pxDialogCreationFlags SystemMenu( bool enable=true ) const { return pxDialogCreationFlags(*this).SetSystemMenu( false ); } pxDialogCreationFlags Caption( bool enable=true ) const { return pxDialogCreationFlags(*this).SetCaption( enable ); } pxDialogCreationFlags CloseBox( bool enable=true ) const { return pxDialogCreationFlags(*this).SetCloseBox( enable ); } pxDialogCreationFlags NoResize() const { return pxDialogCreationFlags(*this).SetResize( false ); } pxDialogCreationFlags NoMinimize() const { return pxDialogCreationFlags(*this).SetMinimize( false ); } pxDialogCreationFlags NoMaximize() const { return pxDialogCreationFlags(*this).SetMaximize( false ); } pxDialogCreationFlags NoSystemMenu() const { return pxDialogCreationFlags(*this).SetSystemMenu( false ); } pxDialogCreationFlags NoCaption() const { return pxDialogCreationFlags(*this).SetCaption( false ); } pxDialogCreationFlags NoCloseBox() const { return pxDialogCreationFlags(*this).SetCloseBox( false ); } pxDialogCreationFlags MinWidth( int width ) const { return pxDialogCreationFlags(*this).SetMinWidth( width ); } pxDialogCreationFlags MinHeight( int height ) const { return pxDialogCreationFlags(*this).SetMinHeight( height ); } pxDialogCreationFlags MinSize( const wxSize& size ) const { return pxDialogCreationFlags(*this).SetMinSize( size ); } pxDialogCreationFlags MinSize( int width, int height ) const { return pxDialogCreationFlags(*this).SetMinWidth( width ).SetMinHeight( height ); } int GetWxWindowFlags() const { int retval = 0; if( isResizable ) retval |= wxRESIZE_BORDER; if( hasCaption ) retval |= wxCAPTION; if( hasMaximizeBox ) retval |= wxMAXIMIZE_BOX; if( hasMinimizeBox ) retval |= wxMINIMIZE_BOX; if( hasSystemMenu ) retval |= wxSYSTEM_MENU; if( hasCloseBox ) retval |= wxCLOSE_BOX; return retval; } }; // -------------------------------------------------------------------------------------- // wxDialogWithHelpers // -------------------------------------------------------------------------------------- class wxDialogWithHelpers : public wxDialog { typedef wxDialog _parent; DECLARE_DYNAMIC_CLASS_NO_COPY(wxDialogWithHelpers) protected: bool m_hasContextHelp; wxBoxSizer* m_extraButtonSizer; wxRect m_CreatedRect; public: wxDialogWithHelpers(); wxDialogWithHelpers(wxWindow* parent, const wxString& title, const pxDialogCreationFlags& cflags = pxDialogCreationFlags() ); virtual ~wxDialogWithHelpers() throw(); void Init( const pxDialogCreationFlags& cflags ); void AddOkCancel( wxSizer& sizer, bool hasApply=false ); void AddOkCancel( wxSizer* sizer=NULL, bool hasApply=false ); void RememberPosition(); virtual void SmartCenterFit(); virtual int ShowModal(); virtual bool Show( bool show=true ); // 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; virtual wxStaticText& Label( const wxString& label ); virtual pxStaticText& Text( const wxString& label ); virtual pxStaticText& Heading( const wxString& label ); wxDialogWithHelpers& SetMinWidth( int newWidth ); wxDialogWithHelpers& SetMinHeight( int newHeight ); int GetCharHeight() const; protected: void OnDialogCreated( wxCommandEvent& evt ); void OnOkCancel(wxCommandEvent& evt); bool ShouldPreventAppExit() const { return false; } void DoAutoCenter(); }; // -------------------------------------------------------------------------------------- // wxPanelWithHelpers // -------------------------------------------------------------------------------------- // Overview of Helpers provided by this class: // * Simpler constructors that have wxID, position, and size parameters removed (We never // use them in pcsx2) // // * Automatic 'primary box sizer' creation, assigned via SetSizer() -- use GetSizer() // to retrieve it, or use the "*this += window;" syntax to add windows directly to it. // // * Built-in support for StaticBoxes (aka groupboxes). Create one at construction with // a wxString label, or add one "after the fact" using AddFrame. // // * Propagates IdealWidth settings from parenting wxPanelWithHelpers classes, and auto- // matically adjusts the width based on the sizer type (groupsizers get truncated to // account for borders). // class wxPanelWithHelpers : public wxPanel { DECLARE_DYNAMIC_CLASS_NO_COPY(wxPanelWithHelpers) public: wxPanelWithHelpers( wxWindow* parent, wxOrientation orient, const wxString& staticBoxLabel ); wxPanelWithHelpers( wxWindow* parent, wxOrientation orient ); wxPanelWithHelpers( wxWindow* parent, const wxPoint& pos, const wxSize& size=wxDefaultSize ); explicit wxPanelWithHelpers( wxWindow* parent=NULL ); wxPanelWithHelpers* AddFrame( const wxString& label, wxOrientation orient=wxVERTICAL ); wxStaticText& Label( const wxString& label ); pxStaticText& Text( const wxString& label ); pxStaticText& Heading( const wxString& label ); virtual wxPanelWithHelpers& SetMinWidth( int newWidth ); protected: void Init(); }; // -------------------------------------------------------------------------------------- // pxTextWrapperBase // -------------------------------------------------------------------------------------- // this class is used to wrap the text on word boundary: wrapping is done by calling // OnStartLine() and OnOutputLine() functions. This class by itself can be used as a // line counting tool, but produces no formatted text output. // // [class "borrowed" from wxWidgets private code, made public, and renamed to avoid possible // conflicts with future editions of wxWidgets which might make it public. Why this isn't // publicly available already in wxBase I'll never know-- air] // class pxTextWrapperBase { protected: bool m_eol; int m_linecount; wxString m_indent; public: virtual ~pxTextWrapperBase() throw() { } pxTextWrapperBase( const wxString& indent=wxEmptyString ) : m_indent( indent ) { m_eol = false; m_linecount = 0; } // win is used for getting the font, text is the text to wrap, width is the // max line width or -1 to disable wrapping pxTextWrapperBase& Wrap( const wxWindow& win, const wxString& text, int widthMax ); int GetLineCount() const { return m_linecount; } protected: // line may be empty virtual void OnOutputLine(const wxString& line) { } // called at the start of every new line (except the very first one) virtual void OnNewLine() { } void DoOutputLine(const wxString& line); bool IsStartOfNewLine(); }; // -------------------------------------------------------------------------------------- // pxTextWrapper // -------------------------------------------------------------------------------------- // This class extends pxTextWrapperBase and adds the ability to retrieve the formatted // result of word wrapping. // class pxTextWrapper : public pxTextWrapperBase { typedef pxTextWrapperBase _parent; protected: wxString m_text; public: pxTextWrapper( const wxString& wrapPrefix=wxEmptyString ) : pxTextWrapperBase( wrapPrefix ) { } virtual ~pxTextWrapper() throw() { } const wxString& GetResult() const { return m_text; } pxTextWrapper& Wrap( const wxWindow& win, const wxString& text, int widthMax ); pxTextWrapper& Wrap( const wxWindow* win, const wxString& text, int widthMax ); protected: void OnOutputLine(const wxString& line); void OnNewLine(); }; // -------------------------------------------------------------------------------------- // pxWindowTextWriter // -------------------------------------------------------------------------------------- class pxWindowTextWriter { protected: wxDC& m_dc; wxAlignment m_align; wxPoint m_curpos; int m_leading; virtual void _DoWriteLn( const wxChar* msg ); void _DoWriteLn( const wxString msg ); void _DoWrite( const wxChar* msg ); public: pxWindowTextWriter( wxDC& dc ); virtual ~pxWindowTextWriter() throw() { } virtual void OnFontChanged(); pxWindowTextWriter& WriteLn(); pxWindowTextWriter& FormatLn( const wxChar* fmt, ... ); pxWindowTextWriter& WriteLn( const wxChar* fmt ); pxWindowTextWriter& SetFont( const wxFont& font ); pxWindowTextWriter& Align( const wxAlignment& align ); pxWindowTextWriter& WriteLn( const wxString fmt ); pxWindowTextWriter& SetLeading( int lead ) { m_leading = lead; return *this; } pxWindowTextWriter& SetWeight( wxFontWeight weight ); pxWindowTextWriter& SetStyle( wxFontStyle style ); pxWindowTextWriter& Normal(); pxWindowTextWriter& Bold() { return SetWeight(wxFONTWEIGHT_BOLD); } pxWindowTextWriter& Italic() { return SetStyle(wxFONTSTYLE_ITALIC); } pxWindowTextWriter& SetPos( const wxPoint& pos ); pxWindowTextWriter& MovePos( const wxSize& delta ); pxWindowTextWriter& SetPos( int xpos, int ypos ) { return SetPos( wxPoint(xpos,ypos) ); } pxWindowTextWriter& MovePos( int xdelta, int ydelta ) { return MovePos( wxSize(xdelta, ydelta) ); } pxWindowTextWriter& SetY( int ypos ); pxWindowTextWriter& MoveY( int ydelta ); }; // -------------------------------------------------------------------------------------- // MoreStockCursors // -------------------------------------------------------------------------------------- // Because (inexplicably) the ArrowWait cursor isn't in wxWidgets stock list. // class MoreStockCursors { protected: std::unique_ptr m_arrowWait; public: MoreStockCursors() { } virtual ~MoreStockCursors() throw() { } const wxCursor& GetArrowWait(); }; enum BusyCursorType { Cursor_NotBusy, Cursor_KindaBusy, Cursor_ReallyBusy, }; extern MoreStockCursors StockCursors; // -------------------------------------------------------------------------------------- // ScopedBusyCursor // -------------------------------------------------------------------------------------- // ... because wxWidgets wxBusyCursor doesn't really do proper nesting (doesn't let me // override a partially-busy cursor with a really busy one) class ScopedBusyCursor { protected: static std::stack m_cursorStack; static BusyCursorType m_defBusyType; public: ScopedBusyCursor( BusyCursorType busytype ); virtual ~ScopedBusyCursor() throw(); static void SetDefault( BusyCursorType busytype ); static void SetManualBusyCursor( BusyCursorType busytype ); }; // -------------------------------------------------------------------------------------- // pxFitToDigits // -------------------------------------------------------------------------------------- // Fits a given text or spinner control to the number of digits requested, since by default // they're usually way over-sized. extern void pxFitToDigits( wxWindow* win, int digits ); extern void pxFitToDigits( wxSpinCtrl* win, int digits ); extern wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits, long flags = wxTE_RIGHT ); ////////////////////////////////////////////////////////////////////////////////////////////// extern bool pxDialogExists( const wxString& name ); extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos ); extern wxRect wxGetDisplayArea(); extern wxString pxGetAppName(); extern int pxGetCharHeight( const wxWindow* wind, int rows=1 ); extern int pxGetCharHeight( const wxWindow& wind, int rows=1 ); extern void pxSetToolTip( wxWindow* wind, const wxString& src ); extern void pxSetToolTip( wxWindow& wind, const wxString& src ); extern wxFont pxGetFixedFont( int ptsize = 8, wxFontWeight weight = wxFONTWEIGHT_NORMAL ); extern pxDialogCreationFlags pxDialogFlags(); #endif