From eda40bfc08b7c15d395316768ea662959b5884b9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 26 Nov 2001 14:50:50 +0000 Subject: [PATCH] superposition of text styles in wxTextCtrl now works as expected (and as documented) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12709 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/text.tex | 161 +++++++++++++++++++++++++++++++++++++++++ include/wx/textctrl.h | 8 ++ samples/text/text.cpp | 3 +- src/common/textcmn.cpp | 41 ++++++++++- src/gtk/textctrl.cpp | 67 +++++++++-------- src/gtk1/textctrl.cpp | 67 +++++++++-------- 6 files changed, 282 insertions(+), 65 deletions(-) diff --git a/docs/latex/wx/text.tex b/docs/latex/wx/text.tex index 09e9b045fa..92cde1a233 100644 --- a/docs/latex/wx/text.tex +++ b/docs/latex/wx/text.tex @@ -1,3 +1,75 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%% wxTextAttr %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxTextAttr}}\label{wxtextattr} + +wxTextAttr represents the attributes, or style, for a range of text in a\rtfsp +\helpref{wxTextCtrl}{wxtextctrl}. + +\wxheading{Derived from} + +No base class + +\wxheading{Include files} + + + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxTextAttr::wxTextAttr}\label{wxtextattrctor} + +\func{}{wxTextAttr}{\void} + +\func{}{wxTextAttr}{\param{const wxColour\& }{colText}, \param{const wxColour\& }{colBack = wxNullColour}, \param{const wxFont\& }{font = wxNullFont}} + +The constructors initialize one or more of the text foreground and background +colours and font. The values not initialized in the constructor can be set +later, otherwise \helpref{wxTextCtrl::SetStyle}{wxtextctrlsetstyle} will use +the default values for them. + +\membersection{wxTextAttr::GetBackgroundColour} + +\constfunc{const wxColour\&}{GetBackgroundColour}{\void} + +Return the background colour specified by this attribute. + +\membersection{wxTextAttr::GetFont} + +\constfunc{const wxFont\&}{GetFont}{\void} + +Return the text font specified by this attribute. + +\membersection{wxTextAttr::GetTextColour} + +\constfunc{const wxColour\&}{GetTextColour}{\void} + +Return the text colour specified by this attribute. + +\membersection{wxTextAttr::HasBackgroundColour} + +\constfunc{bool}{HasBackgroundColour}{\void} + +Returns {\tt TRUE} if this style specifies the background colour to use. + +\membersection{wxTextAttr::HasFont} + +\constfunc{bool}{HasFont}{\void} + +Returns {\tt TRUE} if this style specifies the font to use. + +\membersection{wxTextAttr::HasTextColour} + +\constfunc{bool}{HasTextColour}{\void} + +Returns {\tt TRUE} if this style specifies the foreground colour to use. + +\membersection{wxTextAttr::IsDefault} + +\constfunc{bool}{IsDefault}{\void} + +Returns {\tt TRUE} if this style specifies any non-default attributes. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% wxTextCtrl %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \section{\class{wxTextCtrl}}\label{wxtextctrl} A text control allows text to be displayed and edited. It may be @@ -45,6 +117,38 @@ it to always show it. It doesn't do anything under other platforms.} See also \helpref{window styles overview}{windowstyles} and \helpref{wxTextCtrl::wxTextCtrl}{wxtextctrlconstr}. +\wxheading{wxTextCtrl styles} + +Multi-line text controls support the styles, i.e. provide a possibility to set +colours and font for individual characters in it (note that under Windows {\tt +wxTE\_RICH} style is required for style support). To use the styles you can +either call \helpref{SetDefaultStyle}{wxtextctrlsetdefaultstyle} before +inserting the text or call \helpref{SetStyle}{wxtextctrlsetstyle} later to +change the style of the text already in the control (the first solution is +much more efficient). + +In either case, if the style doesn't specify some of the attributes (for +example you only want to set the text colour but without changing the font nor +the text background), the values of the default style will be used for them. +If there is no default style, the attributes of the text control itself are +used. + +So the following code correctly describes what it does: the second call +to \helpref{SetDefaultStyle}{wxtextctrlsetdefaultstyle} doesn't change the +text foreground colour (which stays red) while the last one doesn't change the +background colour (which stays grey): + +{\small% +\begin{verbatim} + text->SetDefaultStyle(wxTextAttr(*wxRED)); + text->AppendText("Red text\n"); + text->SetDefaultStyle(wxTextAttr(wxNullColour, *wxLIGHT_GREY)); + text->AppendText("Red on grey text\n"); + text->SetDefaultStyle(wxTextAttr(*wxBLUE); + text->AppendText("Blue on grey text\n"); +\end{verbatim} +}% + \wxheading{wxTextCtrl and C++ streams} This class multiply-inherits from {\bf streambuf} where compilers allow, @@ -285,6 +389,16 @@ Copies the selected text to the clipboard and removes the selection. Resets the internal `modified' flag as if the current edits had been saved. +\membersection{wxTextCtrl::GetDefaultStyle}{wxtextctrlgetdefaultstyle} + +\constfunc{const wxTextAttr\& }{GetDefaultStyle}{\void} + +Returns the style currently used for the new text. + +\wxheading{See also} + +\helpref{SetDefaultStyle}{wxtextctrlsetdefaultstyle} + \membersection{wxTextCtrl::GetInsertionPoint}\label{wxtextctrlgetinsertionpoint} \constfunc{virtual long}{GetInsertionPoint}{\void} @@ -554,6 +668,32 @@ Saves the contents of the control in a text file. TRUE if the operation was successful, FALSE otherwise. +\membersection{wxTextCtrl::SetDefaultStyle}\label{wxtextctrlsetdefaultstyle} + +\func{bool}{SetDefaultStyle}{\param{const wxTextAttr\& }{style}} + +Changes the default style to use for the new text which is going to be added +to the control using \helpref{WriteText}{wxtextctrlwritetext} or\rtfsp +\helpref{AppendText}{wxtextctrlappendtext}. + +If either of the font, foreground, or background colour is not set in\rtfsp +{\it style}, the values of the previous default style are used for them. If +the previous default style didn't set them neither, the global font or colours +of the text control itself are used as fall back. + +\wxheading{Parameters} + +\docparam{style}{The style for the new text.} + +\wxheading{Return value} + +{\tt TRUE} on success, {\tt FALSE} if an error occured - may also mean that +the styles are not supported under this platform. + +\wxheading{See also} + +\helpref{GetDefaultStyle}{wxtextctrlgetdefaultstyle} + \membersection{wxTextCtrl::SetEditable}\label{wxtextctrlseteditable} \func{virtual void}{SetEditable}{\param{const bool}{ editable}} @@ -617,6 +757,27 @@ Selects the text starting at the first position up to (but not including) the ch \docparam{to}{The last position.} +\membersection{wxTextCtrl::SetStyle}\label{wxtextctrlsetstyle} + +\func{bool}{SetStyle}{\param{long }{start}, \param{long }{end}, \param{const wxTextAttr\& }{style}} + +Changes the style of the selection. If either of the font, foreground, or +background colour is not set in {\it style}, the values of\rtfsp +\helpref{GetDefaultStyle()}{wxtextctrlgetdefaultstyle} are used. + +\wxheading{Parameters} + +\docparam{start}{The start of selection to change.} + +\docparam{end}{The end of selection to change.} + +\docparam{style}{The new style for the selection.} + +\wxheading{Return value} + +{\tt TRUE} on success, {\tt FALSE} if an error occured - may also mean that +the styles are not supported under this platform. + \membersection{wxTextCtrl::SetValue}\label{wxtextctrlsetvalue} \func{virtual void}{SetValue}{\param{const wxString\& }{ value}} diff --git a/include/wx/textctrl.h b/include/wx/textctrl.h index 49abd90947..05d53de239 100644 --- a/include/wx/textctrl.h +++ b/include/wx/textctrl.h @@ -45,6 +45,7 @@ #endif class WXDLLEXPORT wxTextCtrl; +class WXDLLEXPORT wxTextCtrlBase; // ---------------------------------------------------------------------------- // constants @@ -123,6 +124,13 @@ public: return !HasTextColour() && !HasBackgroundColour() && !HasFont(); } + // return the attribute having the valid font and colours: it uses the + // attributes set in attr and falls back first to attrDefault and then to + // the text control font/colours for those attributes which are not set + static wxTextAttr Combine(const wxTextAttr& attr, + const wxTextAttr& attrDef, + const wxTextCtrlBase *text); + private: wxColour m_colText, m_colBack; diff --git a/samples/text/text.cpp b/samples/text/text.cpp index f805cbf505..db31501cd2 100644 --- a/samples/text/text.cpp +++ b/samples/text/text.cpp @@ -814,6 +814,7 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) wxTE_AUTO_URL | wxHSCROLL); + #if 1 m_textrich->SetStyle(0, 10, *wxRED); m_textrich->SetStyle(10, 20, *wxBLUE); @@ -826,7 +827,7 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) m_textrich->AppendText(_T("And the next 10 characters should be green and italic\n")); m_textrich->SetDefaultStyle(wxTextAttr(*wxCYAN, *wxBLUE)); m_textrich->AppendText(_T("This text should be cyan on blue\n")); - m_textrich->SetDefaultStyle(*wxBLUE); + m_textrich->SetDefaultStyle(wxTextAttr(*wxBLUE, *wxWHITE)); m_textrich->AppendText(_T("And this should be in blue and the text you ") _T("type should be in blue as well")); #else diff --git a/src/common/textcmn.cpp b/src/common/textcmn.cpp index 8b5744f1bf..7e081b9037 100644 --- a/src/common/textcmn.cpp +++ b/src/common/textcmn.cpp @@ -69,6 +69,41 @@ wxTextCtrlBase::~wxTextCtrlBase() // style functions - not implemented here // ---------------------------------------------------------------------------- +/* static */ +wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, + const wxTextAttr& attrDef, + const wxTextCtrlBase *text) +{ + wxFont font = attr.GetFont(); + if ( !font.Ok() ) + { + font = attrDef.GetFont(); + + if ( text && !font.Ok() ) + font = text->GetFont(); + } + + wxColour colFg = attr.GetTextColour(); + if ( !colFg.Ok() ) + { + colFg = attrDef.GetTextColour(); + + if ( text && !colFg.Ok() ) + colFg = text->GetForegroundColour(); + } + + wxColour colBg = attr.GetBackgroundColour(); + if ( !colBg.Ok() ) + { + colBg = attrDef.GetBackgroundColour(); + + if ( text && !colBg.Ok() ) + colBg = text->GetBackgroundColour(); + } + + return wxTextAttr(colFg, colBg, font); +} + // apply styling to text range bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), const wxTextAttr& WXUNUSED(style)) @@ -78,9 +113,11 @@ bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), } // change default text attributes -bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr &style) +bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style) { - m_defaultStyle = style; + // keep the old attributes if the new style doesn't specify them + m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this); + return TRUE; } diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 2cb16ddea1..0441064567 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -41,6 +41,28 @@ extern bool g_isIdle; extern bool g_blockEventsOnDrag; extern wxCursor g_globalCursor; +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +static void wxGtkTextInsert(GtkWidget *text, + const wxTextAttr& attr, + const char *txt, + size_t len) +{ + GdkFont *font = attr.HasFont() ? attr.GetFont().GetInternalFont() + : NULL; + + GdkColor *colFg = attr.HasTextColour() ? attr.GetTextColour().GetColor() + : NULL; + + GdkColor *colBg = attr.HasBackgroundColour() + ? attr.GetBackgroundColour().GetColor() + : NULL; + + gtk_text_insert( GTK_TEXT(text), font, colFg, colBg, txt, len ); +} + // ---------------------------------------------------------------------------- // "insert_text" for GtkEntry // ---------------------------------------------------------------------------- @@ -245,7 +267,7 @@ bool wxTextCtrl::Create( wxWindow *parent, } m_parent->DoAddChild( this ); - + m_focusWidget = m_text; PostCreation(); @@ -425,31 +447,20 @@ void wxTextCtrl::WriteText( const wxString &text ) { // After cursor movements, gtk_text_get_point() is wrong by one. gtk_text_set_point( GTK_TEXT(m_text), GTK_EDITABLE(m_text)->current_pos ); - + // if we have any special style, use it if ( !m_defaultStyle.IsDefault() ) { - GdkFont *font = m_defaultStyle.HasFont() - ? m_defaultStyle.GetFont().GetInternalFont() - : NULL; - - GdkColor *colFg = m_defaultStyle.HasTextColour() - ? m_defaultStyle.GetTextColour().GetColor() - : NULL; - - GdkColor *colBg = m_defaultStyle.HasBackgroundColour() - ? m_defaultStyle.GetBackgroundColour().GetColor() - : NULL; - GetInsertionPoint(); - gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, -1 ); + + wxGtkTextInsert(m_text, m_defaultStyle, txt, txtlen); } else // no style { gint len = GTK_EDITABLE(m_text)->current_pos; gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len ); } - + // Bring editable's cursor back uptodate. GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) ); } @@ -465,7 +476,7 @@ void wxTextCtrl::WriteText( const wxString &text ) // Bring entry's cursor uptodate. gtk_entry_set_position( GTK_ENTRY(m_text), GTK_EDITABLE(m_text)->current_pos ); } - + m_modified = TRUE; } @@ -1075,7 +1086,7 @@ bool wxTextCtrl::SetBackgroundColour( const wxColour &colour ) return TRUE; } -bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style ) +bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style ) { /* VERY dirty way to do that - removes the required text and re-adds it with styling (FIXME) */ @@ -1109,19 +1120,13 @@ bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style ) size_t txtlen = tmp.length(); #endif - GdkFont *font = style.HasFont() - ? style.GetFont().GetInternalFont() - : NULL; - - GdkColor *colFg = style.HasTextColour() - ? style.GetTextColour().GetColor() - : NULL; - - GdkColor *colBg = style.HasBackgroundColour() - ? style.GetBackgroundColour().GetColor() - : NULL; - - gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen ); + // use the attributes from style which are set in it and fall back + // first to the default style and then to the text control default + // colours for the others + wxGtkTextInsert(m_text, + wxTextAttr::Combine(style, m_defaultStyle, this), + txt, + txtlen); /* does not seem to help under GTK+ 1.2 !!! gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */ diff --git a/src/gtk1/textctrl.cpp b/src/gtk1/textctrl.cpp index 2cb16ddea1..0441064567 100644 --- a/src/gtk1/textctrl.cpp +++ b/src/gtk1/textctrl.cpp @@ -41,6 +41,28 @@ extern bool g_isIdle; extern bool g_blockEventsOnDrag; extern wxCursor g_globalCursor; +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +static void wxGtkTextInsert(GtkWidget *text, + const wxTextAttr& attr, + const char *txt, + size_t len) +{ + GdkFont *font = attr.HasFont() ? attr.GetFont().GetInternalFont() + : NULL; + + GdkColor *colFg = attr.HasTextColour() ? attr.GetTextColour().GetColor() + : NULL; + + GdkColor *colBg = attr.HasBackgroundColour() + ? attr.GetBackgroundColour().GetColor() + : NULL; + + gtk_text_insert( GTK_TEXT(text), font, colFg, colBg, txt, len ); +} + // ---------------------------------------------------------------------------- // "insert_text" for GtkEntry // ---------------------------------------------------------------------------- @@ -245,7 +267,7 @@ bool wxTextCtrl::Create( wxWindow *parent, } m_parent->DoAddChild( this ); - + m_focusWidget = m_text; PostCreation(); @@ -425,31 +447,20 @@ void wxTextCtrl::WriteText( const wxString &text ) { // After cursor movements, gtk_text_get_point() is wrong by one. gtk_text_set_point( GTK_TEXT(m_text), GTK_EDITABLE(m_text)->current_pos ); - + // if we have any special style, use it if ( !m_defaultStyle.IsDefault() ) { - GdkFont *font = m_defaultStyle.HasFont() - ? m_defaultStyle.GetFont().GetInternalFont() - : NULL; - - GdkColor *colFg = m_defaultStyle.HasTextColour() - ? m_defaultStyle.GetTextColour().GetColor() - : NULL; - - GdkColor *colBg = m_defaultStyle.HasBackgroundColour() - ? m_defaultStyle.GetBackgroundColour().GetColor() - : NULL; - GetInsertionPoint(); - gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, -1 ); + + wxGtkTextInsert(m_text, m_defaultStyle, txt, txtlen); } else // no style { gint len = GTK_EDITABLE(m_text)->current_pos; gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len ); } - + // Bring editable's cursor back uptodate. GTK_EDITABLE(m_text)->current_pos = gtk_text_get_point( GTK_TEXT(m_text) ); } @@ -465,7 +476,7 @@ void wxTextCtrl::WriteText( const wxString &text ) // Bring entry's cursor uptodate. gtk_entry_set_position( GTK_ENTRY(m_text), GTK_EDITABLE(m_text)->current_pos ); } - + m_modified = TRUE; } @@ -1075,7 +1086,7 @@ bool wxTextCtrl::SetBackgroundColour( const wxColour &colour ) return TRUE; } -bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style ) +bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr& style ) { /* VERY dirty way to do that - removes the required text and re-adds it with styling (FIXME) */ @@ -1109,19 +1120,13 @@ bool wxTextCtrl::SetStyle( long start, long end, const wxTextAttr &style ) size_t txtlen = tmp.length(); #endif - GdkFont *font = style.HasFont() - ? style.GetFont().GetInternalFont() - : NULL; - - GdkColor *colFg = style.HasTextColour() - ? style.GetTextColour().GetColor() - : NULL; - - GdkColor *colBg = style.HasBackgroundColour() - ? style.GetBackgroundColour().GetColor() - : NULL; - - gtk_text_insert( GTK_TEXT(m_text), font, colFg, colBg, txt, txtlen ); + // use the attributes from style which are set in it and fall back + // first to the default style and then to the text control default + // colours for the others + wxGtkTextInsert(m_text, + wxTextAttr::Combine(style, m_defaultStyle, this), + txt, + txtlen); /* does not seem to help under GTK+ 1.2 !!! gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */