/* 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 #include "common/pxStaticText.h" #include "common/Assertions.h" // -------------------------------------------------------------------------------------- // pxStaticText (implementations) // -------------------------------------------------------------------------------------- pxStaticText::pxStaticText(wxWindow* parent) : _parent(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER) { m_align = wxALIGN_CENTRE_HORIZONTAL; m_autowrap = true; m_wrappedWidth = -1; m_heightInLines = 1; SetPaddingDefaults(); } 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; Bind(wxEVT_PAINT, &pxStaticText::paintEvent, this); } // 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(wxFONTWEIGHT_BOLD); 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(); 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); }