From 5d1b49193b778e39901b83097a34429db2e5b47b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 16 Aug 2005 23:14:34 +0000 Subject: [PATCH] added wxStaticText::Wrap() git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35202 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + docs/latex/wx/stattext.tex | 13 ++ include/wx/stattext.h | 6 + src/common/dlgcmn.cpp | 255 ++++++++++++++++++++++++++----------- version-script.in | 1 + 5 files changed, 199 insertions(+), 77 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 31f1fb7990..1b00eddd20 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -18,6 +18,7 @@ All: All (GUI): +- Added wxStaticText::Wrap() - Added wxXmlResource::Unload(). - Possibility of modeless wxWizard dialog (with presentation in sample). - Fixed a rare crash due to malformed HTML in wxHTML (Xavier Nodet). diff --git a/docs/latex/wx/stattext.tex b/docs/latex/wx/stattext.tex index 8f11d0bd7c..ab6f61f2c8 100644 --- a/docs/latex/wx/stattext.tex +++ b/docs/latex/wx/stattext.tex @@ -36,6 +36,7 @@ See also \helpref{window styles overview}{windowstyles}. \latexignore{\rtfignore{\wxheading{Members}}} + \membersection{wxStaticText::wxStaticText}\label{wxstatictextconstr} \func{}{wxStaticText}{\void} @@ -68,6 +69,7 @@ Constructor, creating and showing a text control. \helpref{wxStaticText::Create}{wxstatictextcreate} + \membersection{wxStaticText::Create}\label{wxstatictextcreate} \func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID}{ id},\rtfsp @@ -76,12 +78,14 @@ Constructor, creating and showing a text control. Creation function, for two-step construction. For details see \helpref{wxStaticText::wxStaticText}{wxstatictextconstr}. + \membersection{wxStaticText::GetLabel}\label{wxstatictextgetlabel} \constfunc{wxString}{GetLabel}{\void} Returns the contents of the control. + \membersection{wxStaticText::SetLabel}\label{wxstatictextsetlabel} \func{virtual void}{SetLabel}{\param{const wxString\& }{ label}} @@ -93,3 +97,12 @@ label unless the control has wxST\_NO\_AUTORESIZE flag. \docparam{label}{The new label to set. It may contain newline characters.} + +\membersection{wxStaticText::Wrap}\label{wxstatictextwrpa} + +\func{void}{Wrap}{\param{int }{width}} + +This functions wraps the controls label so that each of its lines becomes at +most \arg{width} pixels wide if possible (the lines are broken at words +boundaries so it might not be the case if words are too long). If \arg{width} +is negative, no wrapping is done. diff --git a/include/wx/stattext.h b/include/wx/stattext.h index 4bfeec3318..8b0c667eb1 100644 --- a/include/wx/stattext.h +++ b/include/wx/stattext.h @@ -25,6 +25,12 @@ class WXDLLEXPORT wxStaticTextBase : public wxControl public: wxStaticTextBase() { } + // wrap the text of the control so that no line is longer than the given + // width (if possible: this function won't break words) + // + // NB: implemented in dlgcmn.cpp for now + void Wrap(int width); + // overriden base virtuals virtual bool AcceptsFocus() const { return false; } virtual bool HasTransparentBackground() { return true; } diff --git a/src/common/dlgcmn.cpp b/src/common/dlgcmn.cpp index d32ba91318..6d3e218315 100644 --- a/src/common/dlgcmn.cpp +++ b/src/common/dlgcmn.cpp @@ -40,11 +40,63 @@ #include "wx/containr.h" #endif -//-------------------------------------------------------------------------- +#if wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxTextWrapper +// ---------------------------------------------------------------------------- + +// this class is used to wrap the text on word boundary: wrapping is done by +// calling OnStartLine() and OnOutputLine() functions +class wxTextWrapper +{ +public: + wxTextWrapper() { m_eol = false; } + + // win is used for getting the font, text is the text to wrap, width is the + // max line width or -1 to disable wrapping + void Wrap(wxWindow *win, const wxString& text, int widthMax); + +protected: + // line may be empty + virtual void OnOutputLine(const wxString& line) = 0; + + // called at the start of every new line (except the very first one) + virtual void OnNewLine() { } + +private: + // call OnOutputLine() and set m_eol to true + void DoOutputLine(const wxString& line) + { + OnOutputLine(line); + + m_eol = true; + } + + // this function is a destructive inspector: when it returns true it also + // resets the flag to false so calling it again woulnd't return true any + // more + bool IsStartOfNewLine() + { + if ( !m_eol ) + return false; + + m_eol = false; + + return true; + } + + + bool m_eol; +}; + +#endif // wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- // wxDialogBase -//-------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- -// FIXME - temporary hack in absence of wxtopLevelWindow, should be always used +// FIXME - temporary hack in absence of wxTopLevelWindow, should be always used #ifdef wxTopLevelWindowNative BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) @@ -68,104 +120,153 @@ void wxDialogBase::Init() #endif } -#if wxUSE_STATTEXT // && wxUSE_TEXTCTRL +#if wxUSE_STATTEXT -wxSizer *wxDialogBase::CreateTextSizer( const wxString& message ) +void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) { - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + const wxChar *lastSpace = NULL; + wxString line; + + const wxChar *lineStart = text.c_str(); + for ( const wxChar *p = lineStart; ; p++ ) + { + if ( IsStartOfNewLine() ) + { + OnNewLine(); + + lastSpace = NULL; + line.clear(); + lineStart = p; + } + + if ( *p == _T('\n') || *p == _T('\0') ) + { + DoOutputLine(line); + + if ( *p == _T('\0') ) + break; + } + else // not EOL + { + if ( *p == _T(' ') ) + lastSpace = p; + + line += *p; - wxString text = message; + if ( widthMax >= 0 && lastSpace ) + { + int width; + win->GetTextExtent(line, &width, NULL); + if ( width > widthMax ) + { + // remove the last word from this line + line.erase(lastSpace - lineStart, p + 1 - lineStart); + DoOutputLine(line); + + // go back to the last word of this line which we didn't + // output yet + p = lastSpace; + } + } + //else: no wrapping at all or impossible to wrap + } + } +} + +wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) +{ // I admit that this is complete bogus, but it makes // message boxes work for pda screens temporarily.. - int max_width = -1; + int widthMax = -1; + const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; if (is_pda) { - max_width = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; - text += wxT('\n'); + widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; } + // '&' is used as accel mnemonic prefix in the wxWidgets controls but in + // the static messages created by CreateTextSizer() (used by wxMessageBox, + // for example), we don't want this special meaning, so we need to quote it + wxString text(message); + text.Replace(_T("&"), _T("&&")); - wxBoxSizer *box = new wxBoxSizer( wxVERTICAL ); - - // get line height for empty lines - int y = 0; - wxFont font( GetFont() ); - if (!font.Ok()) - font = *wxSWISS_FONT; - GetTextExtent( wxT("H"), (int*)NULL, &y, (int*)NULL, (int*)NULL, &font); - size_t last_space = 0; - wxString line; - for ( size_t pos = 0; pos < text.length(); pos++ ) + class TextSizerWrapper : public wxTextWrapper { - switch ( text[pos] ) + public: + TextSizerWrapper(wxWindow *win) { - case wxT('\n'): - if (!line.empty()) - { - wxStaticText *s = new wxStaticText( this, wxID_ANY, line ); - box->Add( s ); - line = wxEmptyString; - } - else - { - box->Add( 5, y ); - } - break; + m_win = win; + m_hLine = 0; + } + + wxSizer *CreateSizer(const wxString& text, int widthMax) + { + m_sizer = new wxBoxSizer(wxVERTICAL); + Wrap(m_win, text, widthMax); + return m_sizer; + } - case wxT('&'): - // this is used as accel mnemonic prefix in the wxWidgets - // controls but in the static messages created by - // CreateTextSizer() (used by wxMessageBox, for example), we - // don't want this special meaning, so we need to quote it - line += wxT('&'); + protected: + virtual void OnOutputLine(const wxString& line) + { + if ( !line.empty() ) + { + m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); + } + else // empty line, no need to create a control for it + { + if ( !m_hLine ) + m_hLine = m_win->GetCharHeight(); + + m_sizer->Add(5, m_hLine); + } + } - // fall through to add it normally too + private: + wxWindow *m_win; + wxSizer *m_sizer; + int m_hLine; + }; - default: - if (text[pos] == wxT(' ')) - last_space = pos; + TextSizerWrapper wrapper(this); - line += message[pos]; + return wrapper.CreateSizer(text, widthMax); +} - if (is_pda) - { - int width = 0; - GetTextExtent( line, &width, (int*)NULL, (int*)NULL, (int*)NULL, &font ); - - if (width > max_width) - { - // exception if there was no previous space - if (last_space == 0) - last_space = pos; - - int diff = pos-last_space; - int len = line.Len(); - line.Remove( len-diff, diff ); - - wxStaticText *s = new wxStaticText( this, wxID_ANY, line ); - box->Add( s ); - - pos = last_space; - last_space = 0; - line = wxEmptyString; - } - } +void wxStaticTextBase::Wrap(int width) +{ + class LabelWrapper : public wxTextWrapper + { + public: + void WrapLabel(wxStaticTextBase *text, int widthMax) + { + m_text.clear(); + Wrap(text, text->GetLabel(), widthMax); + text->SetLabel(m_text); } - } - // remaining text behind last '\n' - if (!line.empty()) - { - wxStaticText *s2 = new wxStaticText( this, wxID_ANY, line ); - box->Add( s2 ); - } + protected: + virtual void OnOutputLine(const wxString& line) + { + m_text += line; + } + + virtual void OnNewLine() + { + m_text += _T('\n'); + } + + private: + wxString m_text; + }; - return box; + LabelWrapper wrapper; + wrapper.WrapLabel(this, width); } -#endif // wxUSE_STATTEXT // && wxUSE_TEXTCTRL +#endif // wxUSE_STATTEXT #if wxUSE_BUTTON diff --git a/version-script.in b/version-script.in index 36ef28913f..691247f8bd 100644 --- a/version-script.in +++ b/version-script.in @@ -23,6 +23,7 @@ *wxMediaCtrl*ShowPlayerControls*wxMediaPlayerControls*; *wxMessageOutputBest*; *wxShadowObject*; + *wxStaticText*Wrap*; *wxTopLevelWindowGTK*RequestUserAttention*; *wxWindowMSW*MSWWindowProc*; *wxWizard*FinishLayout*; -- 2.45.2