/* 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 . */ #include "PrecompiledHeader.h" #include "pxStaticText.h" #include // -------------------------------------------------------------------------------------- // pxStaticText (implementations) // -------------------------------------------------------------------------------------- pxStaticText::pxStaticText( wxWindow* parent ) : _parent( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER ) { m_heightInLines = 1; } pxStaticText::pxStaticText( wxWindow* parent, const wxString& label, wxAlignment align ) : _parent( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER ) { m_heightInLines = 1; m_align = align; SetPaddingDefaults(); Init( label ); } void pxStaticText::Init( const wxString& label ) { m_autowrap = true; m_wrappedWidth = -1; m_label = label; Connect( wxEVT_PAINT, wxPaintEventHandler(pxStaticText::paintEvent) ); } // we need to refresh the window after changing its size as the standard // control doesn't always update itself properly (fials typically on window resizes where // the control is expanded to fit -- ie the control's size changes but the position does not) void pxStaticText::DoSetSize(int x, int y, int w, int h, int sizeFlags) { _parent::DoSetSize(x, y, w, h, sizeFlags); Refresh(); } void pxStaticText::SetPaddingDefaults() { m_paddingPix_horiz = 7; m_paddingPix_vert = 1; m_paddingPct_horiz = 0.0f; m_paddingPct_vert = 0.0f; } pxStaticText& pxStaticText::SetMinWidth( int width ) { SetMinSize( wxSize( width, GetMinHeight() ) ); return *this; } pxStaticText& pxStaticText::SetMinHeight( int height ) { SetMinSize( wxSize( GetMinWidth(), height) ); return *this; } pxStaticText& pxStaticText::SetHeight( int lines ) { if( !pxAssert(lines > 0) ) lines = 2; m_heightInLines = lines; const int newHeight = (pxGetCharHeight(this)*m_heightInLines) + (m_paddingPix_vert*2); SetMinSize( wxSize(GetMinWidth(), newHeight) ); return *this; } pxStaticText& pxStaticText::Align( wxAlignment align ) { m_align = align; return *this; } pxStaticText& pxStaticText::Bold() { wxFont bold( GetFont() ); bold.SetWeight(wxBOLD); SetFont( bold ); return *this; } pxStaticText& pxStaticText::PaddingPixH( int pixels ) { m_paddingPix_horiz = pixels; UpdateWrapping( false ); Refresh(); return *this; } pxStaticText& pxStaticText::PaddingPixV( int pixels ) { m_paddingPix_vert = pixels; Refresh(); return *this; } pxStaticText& pxStaticText::PaddingPctH( float pct ) { pxAssert( pct < 0.5 ); m_paddingPct_horiz = pct; UpdateWrapping( false ); Refresh(); return *this; } pxStaticText& pxStaticText::PaddingPctV( float pct ) { pxAssert( pct < 0.5 ); m_paddingPct_vert = pct; Refresh(); return *this; } pxStaticText& pxStaticText::Unwrapped() { m_autowrap = false; UpdateWrapping( false ); return *this; } int pxStaticText::calcPaddingWidth( int newWidth ) const { return (int)(newWidth*m_paddingPct_horiz*2) + (m_paddingPix_horiz*2); } int pxStaticText::calcPaddingHeight( int newHeight ) const { return (int)(newHeight*m_paddingPct_vert*2) + (m_paddingPix_vert*2); } wxSize pxStaticText::GetBestWrappedSize( const wxClientDC& dc ) const { pxAssert( m_autowrap ); // Find an ideal(-ish) width, based on a search of all parent controls and their // valid Minimum sizes. int idealWidth = wxDefaultCoord; int parentalAdjust = 0; double parentalFactor = 1.0; const wxWindow* millrun = this; while( millrun ) { // IMPORTANT : wxWizard changes its min size and then expects everything else // to play nice and NOT resize according to the new min size. (wtf stupid) // Anyway, this fixes it -- ignore min size specifier on wxWizard! if( wxIsKindOf( millrun, wxWizard ) ) break; int min = (int)((millrun->GetMinWidth() - parentalAdjust) * parentalFactor); if( min > 0 && ((idealWidth < 0 ) || (min < idealWidth)) ) { idealWidth = min; } parentalAdjust += pxSizerFlags::StdPadding*2; millrun = millrun->GetParent(); } if( idealWidth <= 0 ) { // FIXME: The minimum size of this control is unknown, so let's just pick a guess based on // the size of the user's display area. idealWidth = (int)(wxGetDisplaySize().GetWidth() * 0.66) - (parentalAdjust*2); } return dc.GetMultiLineTextExtent(pxTextWrapper().Wrap( this, m_label, idealWidth - calcPaddingWidth(idealWidth) ).GetResult()); } pxStaticText& pxStaticText::WrapAt( int width ) { m_autowrap = false; if( (width <= 1) || (width == m_wrappedWidth) ) return *this; wxString wrappedLabel; m_wrappedWidth = width; if( width > 1 ) wrappedLabel = pxTextWrapper().Wrap( this, m_label, width ).GetResult(); if(m_wrappedLabel != wrappedLabel ) { m_wrappedLabel = wrappedLabel; wxSize area = wxClientDC( this ).GetMultiLineTextExtent(m_wrappedLabel); SetMinSize( wxSize( area.GetWidth() + calcPaddingWidth(area.GetWidth()), area.GetHeight() + calcPaddingHeight(area.GetHeight()) ) ); } return *this; } bool pxStaticText::_updateWrapping( bool textChanged ) { if( !m_autowrap ) { //m_wrappedLabel = wxEmptyString; //m_wrappedWidth = -1; return false; } wxString wrappedLabel; int newWidth = GetSize().GetWidth(); newWidth -= (int)(newWidth*m_paddingPct_horiz*2) + (m_paddingPix_horiz*2); if( !textChanged && (newWidth == m_wrappedWidth) ) return false; // Note: during various stages of sizer-calc, width can be 1, 0, or -1. // We ignore wrapping in these cases. (the PaintEvent also checks the wrapping // and updates it if needed, in case the control's size isn't figured out prior // to being painted). m_wrappedWidth = newWidth; if( m_wrappedWidth > 1 ) wrappedLabel = pxTextWrapper().Wrap( this, m_label, m_wrappedWidth ).GetResult(); if( m_wrappedLabel == wrappedLabel ) return false; m_wrappedLabel = wrappedLabel; return true; } void pxStaticText::UpdateWrapping( bool textChanged ) { if( _updateWrapping( textChanged ) ) Refresh(); } void pxStaticText::SetLabel(const wxString& label) { const bool labelChanged( label != m_label ); if( labelChanged ) { m_label = label; Refresh(); } // Always update wrapping, in case window width or something else also changed. UpdateWrapping( labelChanged ); InvalidateBestSize(); } wxFont pxStaticText::GetFontOk() const { wxFont font( GetFont() ); if( !font.Ok() ) return wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); return font; } bool pxStaticText::Enable( bool enabled ) { if( _parent::Enable(enabled)) { Refresh(); return true; } return false; } void pxStaticText::paintEvent(wxPaintEvent& evt) { wxPaintDC dc( this ); const int dcWidth = dc.GetSize().GetWidth(); const int dcHeight = dc.GetSize().GetHeight(); if( dcWidth < 1 ) return; dc.SetFont( GetFontOk() ); if( IsEnabled() ) dc.SetTextForeground(GetForegroundColour()); else dc.SetTextForeground(*wxLIGHT_GREY); pxWindowTextWriter writer( dc ); writer.Align( m_align ); const wxString& label( m_autowrap ? m_wrappedLabel : m_label ); if( m_autowrap ) _updateWrapping( false ); int tWidth, tHeight; dc.GetMultiLineTextExtent( label, &tWidth, &tHeight ); writer.Align( m_align ); if( m_align & wxALIGN_CENTER_VERTICAL ) writer.SetY( (dcHeight - tHeight) / 2 ); else writer.SetY( (int)(dcHeight*m_paddingPct_vert) + m_paddingPix_vert ); writer.WriteLn( label ); // without formatting please. //dc.SetBrush( *wxTRANSPARENT_BRUSH ); //dc.DrawRectangle(wxPoint(), dc.GetSize()); } // Overloaded form wxPanel and friends. wxSize pxStaticText::DoGetBestSize() const { wxClientDC dc( const_cast(this) ); dc.SetFont( GetFontOk() ); wxSize best; if( m_autowrap ) { best = GetBestWrappedSize(dc); //best.x = wxDefaultCoord; } else { // No autowrapping, so we can force a specific size here! best = dc.GetMultiLineTextExtent( GetLabel() ); best.x += calcPaddingWidth( best.x ); } best.y += calcPaddingHeight( best.y ); CacheBestSize(best); return best; } // -------------------------------------------------------------------------------------- // pxStaticHeading (implementations) // -------------------------------------------------------------------------------------- pxStaticHeading::pxStaticHeading( wxWindow* parent, const wxString& label ) : _parent( parent ) { m_align = wxALIGN_CENTER; SetPaddingDefaults(); Init( label ); } void pxStaticHeading::SetPaddingDefaults() { m_paddingPix_horiz = 4; m_paddingPix_vert = 1; m_paddingPct_horiz = 0.08f; m_paddingPct_vert = 0.0f; } void operator+=( wxSizer& target, pxStaticText* src ) { if( src ) target.Add( src, pxExpand ); } void operator+=( wxSizer& target, pxStaticText& src ) { target.Add( &src, pxExpand ); } void operator+=( wxSizer* target, pxStaticText& src ) { target->Add( &src, pxExpand ); }