diff --git a/include/wx/textctrl.h b/include/wx/textctrl.h index 341409530e..0d1f3892eb 100644 --- a/include/wx/textctrl.h +++ b/include/wx/textctrl.h @@ -270,6 +270,14 @@ enum wxTextAttrLineSpacing wxTEXT_ATTR_LINE_SPACING_TWICE = 20 }; +enum wxTextAttrUnderlineType + { + wxTEXT_ATTR_UNDERLINE_NONE, + wxTEXT_ATTR_UNDERLINE_SOLID, + wxTEXT_ATTR_UNDERLINE_DOUBLE, + wxTEXT_ATTR_UNDERLINE_WAVE +}; + // ---------------------------------------------------------------------------- // wxTextAttr: a structure containing the visual attributes of a text // ---------------------------------------------------------------------------- @@ -321,6 +329,14 @@ public: void SetFontWeight(wxFontWeight fontWeight) { m_fontWeight = fontWeight; m_flags |= wxTEXT_ATTR_FONT_WEIGHT; } void SetFontFaceName(const wxString& faceName) { m_fontFaceName = faceName; m_flags |= wxTEXT_ATTR_FONT_FACE; } void SetFontUnderlined(bool underlined) { m_fontUnderlined = underlined; m_flags |= wxTEXT_ATTR_FONT_UNDERLINE; } + void SetFontUnderline(/*bool underlined, */wxTextAttrUnderlineType type = wxTEXT_ATTR_UNDERLINE_NONE, const wxColour& colour = wxNullColour) + { + if( type != wxTEXT_ATTR_UNDERLINE_NONE ) + m_flags |= wxTEXT_ATTR_FONT_UNDERLINE; +// m_fontUnderlined = underlined; + m_fontUnderlineType = type; + m_colUnderline = colour; + } void SetFontStrikethrough(bool strikethrough) { m_fontStrikethrough = strikethrough; m_flags |= wxTEXT_ATTR_FONT_STRIKETHROUGH; } void SetFontEncoding(wxFontEncoding encoding) { m_fontEncoding = encoding; m_flags |= wxTEXT_ATTR_FONT_ENCODING; } void SetFontFamily(wxFontFamily family) { m_fontFamily = family; m_flags |= wxTEXT_ATTR_FONT_FAMILY; } @@ -360,6 +376,8 @@ public: wxFontStyle GetFontStyle() const { return m_fontStyle; } wxFontWeight GetFontWeight() const { return m_fontWeight; } bool GetFontUnderlined() const { return m_fontUnderlined; } + wxTextAttrUnderlineType GetUnderlineType() const { return m_fontUnderlineType; } + const wxColour& GetUnderlineColour() const { return m_colUnderline; } bool GetFontStrikethrough() const { return m_fontStrikethrough; } const wxString& GetFontFaceName() const { return m_fontFaceName; } wxFontEncoding GetFontEncoding() const { return m_fontEncoding; } @@ -396,7 +414,8 @@ public: bool HasFontPointSize() const { return HasFlag(wxTEXT_ATTR_FONT_POINT_SIZE); } bool HasFontPixelSize() const { return HasFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE); } bool HasFontItalic() const { return HasFlag(wxTEXT_ATTR_FONT_ITALIC); } - bool HasFontUnderlined() const { return HasFlag(wxTEXT_ATTR_FONT_UNDERLINE); } + bool HasFontUnderlined() const { return m_fontUnderlined; } + bool HasFontUnderline() const { return HasFlag(wxTEXT_ATTR_FONT_UNDERLINE); } bool HasFontStrikethrough() const { return HasFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH); } bool HasFontFaceName() const { return HasFlag(wxTEXT_ATTR_FONT_FACE); } bool HasFontEncoding() const { return HasFlag(wxTEXT_ATTR_FONT_ENCODING); } @@ -509,6 +528,8 @@ private: wxFontWeight m_fontWeight; wxFontFamily m_fontFamily; bool m_fontUnderlined; + wxTextAttrUnderlineType m_fontUnderlineType; + wxColour m_colUnderline; bool m_fontStrikethrough; wxString m_fontFaceName; diff --git a/interface/wx/textctrl.h b/interface/wx/textctrl.h index a0b6b7464f..9f70fbce03 100644 --- a/interface/wx/textctrl.h +++ b/interface/wx/textctrl.h @@ -219,6 +219,19 @@ enum wxTextAttrLineSpacing }; +/** + The values that can be used with SetFontUnderline + + @since 3.1.3 +*/ +enum wxTextAttrUnderlineType +{ + wxTEXT_ATTR_UNDERLINE_NONE, + wxTEXT_ATTR_UNDERLINE_SOLID, + wxTEXT_ATTR_UNDERLINE_DOUBLE, + wxTEXT_ATTR_UNDERLINE_WAVE +}; + /** Describes the possible return values of wxTextCtrl::HitTest(). @@ -422,6 +435,20 @@ public: */ bool GetFontUnderlined() const; + /** + Returns the underline type, which is one of the @wxTextAttrUnderlineType values + + @since 3.1.3 + */ + wxTextAttrUnderlineType GetUnderlinedType() const; + + /** + Returns the underline color used + + @since 3.1.3 + */ + const wxColour& GetUnderlineColour() const; + /** Returns the font weight. */ @@ -604,6 +631,14 @@ public: */ bool HasFontUnderlined() const; + /** + Returns @true if the attribute object specifies different underline types + and color + + @since 3.1.3 + */ + bool HasFontUnderline() const; + /** Returns @true if the attribute object specifies font weight (bold, light or normal). @@ -807,6 +842,13 @@ public: */ void SetFontUnderlined(bool underlined); + /** + Set the different underline type and the underline color + + @since 3.1.3 + */ + void SetFontUnderline(wxTextAttrUnderlineType type = wxTEXT_ATTR_UNDERLINE_SOLID, wxColour colour = *wxBLACK); + /** Sets the font weight. */ diff --git a/samples/text/text.cpp b/samples/text/text.cpp index 7e5256b0b9..a8ad333492 100644 --- a/samples/text/text.cpp +++ b/samples/text/text.cpp @@ -1228,7 +1228,17 @@ MyPanel::MyPanel( wxFrame *frame, int x, int y, int w, int h ) m_textrich->AppendText("This text should be cyan on blue\n"); m_textrich->SetDefaultStyle(wxTextAttr(*wxBLUE, *wxWHITE)); m_textrich->AppendText("And this should be in blue and the text you " - "type should be in blue as well"); + "type should be in blue as well.\n"); + m_textrich->SetDefaultStyle( wxTextAttr() ); + m_textrich->AppendText("And there is a "); + wxTextAttr attr = m_textrich->GetDefaultStyle(); + attr.SetFontUnderline( /*true, */wxTEXT_ATTR_UNDERLINE_WAVE, *wxRED ); + m_textrich->SetDefaultStyle( attr ); + m_textrich->AppendText("mispeled "); + attr.SetFontUnderline( /*false, */wxTEXT_ATTR_UNDERLINE_NONE ); + m_textrich->SetDefaultStyle( attr ); + m_textrich->AppendText("word"); + m_textrich->SetDefaultStyle(wxTextAttr(*wxBLUE, *wxWHITE)); // lay out the controls diff --git a/src/common/gdicmn.cpp b/src/common/gdicmn.cpp index 0b2d514408..1245e8c274 100644 --- a/src/common/gdicmn.cpp +++ b/src/common/gdicmn.cpp @@ -370,7 +370,13 @@ void wxColourDatabase::Initialize() {wxT("WHEAT"), 216, 216, 191}, {wxT("WHITE"), 255, 255, 255}, {wxT("YELLOW"), 255, 255, 0}, - {wxT("YELLOW GREEN"), 153, 204, 50} + {wxT("YELLOW GREEN"), 153, 204, 50}, + {wxT("wxNAVY"), 0, 0, 128}, + {wxT("wxTEAL"), 0, 128, 128}, + {wxT("wxLIGHT GREEN"), 0, 128, 0}, + {wxT("wxPURPLE"), 128, 0, 128}, + {wxT("wxMAROON"), 128, 0, 0}, + {wxT("wxDARK GREY"), 128, 128, 128} }; size_t n; diff --git a/src/common/textcmn.cpp b/src/common/textcmn.cpp index 2774635bbe..104f62a62d 100644 --- a/src/common/textcmn.cpp +++ b/src/common/textcmn.cpp @@ -163,6 +163,7 @@ void wxTextAttr::Init() m_fontStyle = wxFONTSTYLE_NORMAL; m_fontWeight = wxFONTWEIGHT_NORMAL; m_fontUnderlined = false; + m_fontUnderlineType = wxTEXT_ATTR_UNDERLINE_NONE; m_fontStrikethrough = false; m_fontEncoding = wxFONTENCODING_DEFAULT; m_fontFamily = wxFONTFAMILY_DEFAULT; @@ -175,6 +176,7 @@ void wxTextAttr::Init() m_textEffectFlags = wxTEXT_ATTR_EFFECT_NONE; m_outlineLevel = 0; m_bulletNumber = 0; + m_colUnderline = wxNullColour; } // Copy @@ -193,6 +195,8 @@ void wxTextAttr::Copy(const wxTextAttr& attr) m_fontStyle = attr.m_fontStyle; m_fontWeight = attr.m_fontWeight; m_fontUnderlined = attr.m_fontUnderlined; + m_fontUnderlineType = attr.m_fontUnderlineType; + m_colUnderline = attr.m_colUnderline; m_fontStrikethrough = attr.m_fontStrikethrough; m_fontFaceName = attr.m_fontFaceName; m_fontEncoding = attr.m_fontEncoding; @@ -258,6 +262,7 @@ bool wxTextAttr::operator== (const wxTextAttr& attr) const (!HasFontItalic() || (GetFontStyle() == attr.GetFontStyle())) && (!HasFontWeight() || (GetFontWeight() == attr.GetFontWeight())) && (!HasFontUnderlined() || (GetFontUnderlined() == attr.GetFontUnderlined())) && + ( ( GetUnderlineType() == attr.GetUnderlineType() ) && ( GetUnderlineColour() == attr.GetUnderlineColour() ) ) && (!HasFontStrikethrough() || (GetFontStrikethrough() == attr.GetFontStrikethrough())) && (!HasFontFaceName() || (GetFontFaceName() == attr.GetFontFaceName())) && (!HasFontEncoding() || (GetFontEncoding() == attr.GetFontEncoding())) && @@ -791,6 +796,7 @@ wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, } wxTextAttr newAttr(colFg, colBg, font); + newAttr.SetFontUnderline( /*attr.GetFontUnderlined(), */attr.GetUnderlineType(), attr.GetUnderlineColour()); if (attr.HasAlignment()) newAttr.SetAlignment(attr.GetAlignment()); diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 54af9c1def..f059ee2d10 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -124,6 +124,64 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, } } + if ( attr.HasFontUnderlined() ) + { + GtkTextTag *underlineColorTag; + PangoUnderline pangoUnderlineStyle; + switch ( attr.GetUnderlineType() ) + { + case wxTEXT_ATTR_UNDERLINE_NONE: + pangoUnderlineStyle = PANGO_UNDERLINE_NONE; + break; + case wxTEXT_ATTR_UNDERLINE_SOLID: + pangoUnderlineStyle = PANGO_UNDERLINE_SINGLE; + break; + case wxTEXT_ATTR_UNDERLINE_DOUBLE: + pangoUnderlineStyle = PANGO_UNDERLINE_DOUBLE; + break; + case wxTEXT_ATTR_UNDERLINE_WAVE: + pangoUnderlineStyle = PANGO_UNDERLINE_ERROR; + break; + } + + g_snprintf(buf, sizeof(buf), "WXFONTUNDERLINEWITHEFFECT"); + tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ), + buf ); + if (!tag) + { + tag = gtk_text_buffer_create_tag( text_buffer, buf, + "underline-set", TRUE, + "underline", pangoUnderlineStyle, + NULL ); + } + gtk_text_buffer_apply_tag (text_buffer, tag, start, end); + +#ifdef __WXGTK3__ + if ( gtk_check_version( 3, 16, 0 ) ) + { + wxColour color = attr.GetUnderlineColour(); + if ( !color.IsOk() ) + { + color = attr.GetTextColour(); + if( !color.IsOk() ) + color = *wxBLACK; + } + const GdkColor *gdkColor = attr.GetUnderlineColour().GetColor(); + GdkRGBA color_rgba = { + .red = CLAMP( (double) gdkColor->red / 65535.0, 0.0, 1.0 ), + .green = CLAMP( (double) gdkColor->green / 65535.0, 0.0, 1.0 ), + .blue = CLAMP ((double) gdkColor->blue / 65535.0, 0.0, 1.0 ), + .alpha = 1.0, + }; + underlineColorTag = gtk_text_buffer_create_tag( text_buffer, buf, + "underline-rgba-set", TRUE, + "underline-rgba", color_rgba, + NULL ); + gtk_text_buffer_apply_tag (text_buffer, underlineColorTag, start, end); + } +#endif + } + if (attr.HasTextColour()) { wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXFORECOLOR", start, end); diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index fed5741b58..164935b07b 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -80,6 +80,23 @@ #define CFE_AUTOBACKCOLOR 0x04000000 #endif +// missing defines for MinGW build +#ifndef CFM_UNDERLINETYPE +#define CFM_UNDERLINETYPE 0x00800000 +#endif + +#ifndef CFU_UNDERLINE +#define CFU_UNDERLINE 1 +#endif + +#ifndef CFU_UNDERLINEDOUBLE +#define CFU_UNDERLINEDOUBLE 3 +#endif + +#ifndef CFU_UNDERLINEWAVE +#define CFU_UNDERLINEWAVE 8 +#endif + #if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT // dummy value used for m_dropTarget, different from any valid pointer value @@ -2862,6 +2879,65 @@ bool wxTextCtrl::MSWSetCharFormat(const wxTextAttr& style, long start, long end) } } + if ( style.HasFontUnderline() ) + { + cf.dwMask |= CFM_UNDERLINETYPE; + wxTextAttrUnderlineType underlineType = style.GetUnderlineType(); + switch ( underlineType ) + { + case wxTEXT_ATTR_UNDERLINE_SOLID: + cf.bUnderlineType = CFU_UNDERLINE; + break; + case wxTEXT_ATTR_UNDERLINE_DOUBLE: + cf.bUnderlineType = CFU_UNDERLINEDOUBLE; + break; + case wxTEXT_ATTR_UNDERLINE_WAVE: + cf.bUnderlineType = CFU_UNDERLINEWAVE; + break; + } + +#if _RICHEDIT_VER >= 0x0800 + // The colours are coming from https://docs.microsoft.com/en-us/windows/desktop/api/tom/nf-tom-itextdocument2-geteffectcolor. + // Not all values from wxTheColourDatabase are supported as can be seen from the code + // Those are commented out currently + BYTE colour = 0; + wxColour col = style.GetUnderlineColour(); + if ( col == wxTheColourDatabase->Find( "BLACK" ) ) + colour = 0x01; + else if ( col == wxTheColourDatabase->Find( "BLUE" ) ) + colour = 0x02; + else if ( col == wxTheColourDatabase->Find( "CYAN" ) ) + colour = 0x03; + else if ( col == wxTheColourDatabase->Find( "GREEN" ) ) + colour = 0x04; + else if ( col == wxTheColourDatabase->Find( "MAGENTA" ) ) + colour = 0x05; + else if ( col == wxTheColourDatabase->Find( "RED" ) ) + colour = 0x06; + else if ( col == wxTheColourDatabase->Find( "YELLOW" ) ) + colour = 0x07; + else if ( col == wxTheColourDatabase->Find( "WHITE" ) ) + colour = 0x08; + else if ( col == wxTheColourDatabase->Find( "WXNAVY" ) ) + colour = 0x09; + else if ( col == wxTheColourDatabase->Find( "WXTEAL" ) ) + colour = 0x0A; + else if ( col == wxTheColourDatabase->Find( "WXLIGHT GREEN" ) ) + colour = 0x0B; + else if ( col == wxTheColourDatabase->Find( "WXPURPLE" ) ) + colour = 0x0C; + else if ( col == wxTheColourDatabase->Find( "WXMAROON" ) ) + colour = 0x0D; + else if ( col == wxTheColourDatabase->Find( "OLIVE" ) ) + colour = 0x0E; + else if ( col == wxTheColourDatabase->Find( "wxDARK GREY" ) ) + colour = 0x0F; + else if ( col == wxTheColourDatabase->Find( "LIGHT GREY" ) ) + colour = 0x10; + cf.bUnderlineColor = colour; +#endif + } + if ( style.HasTextColour() ) { cf.dwMask |= CFM_COLOR; @@ -3025,7 +3101,7 @@ bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style) // even try to do anything if it's the only thing we want to change if ( m_verRichEdit == 1 && !style.HasFont() && !style.HasTextColour() && !style.HasLeftIndent() && !style.HasRightIndent() && !style.HasAlignment() && - !style.HasTabs() ) + !style.HasTabs() && !style.GetFontUnderlined() ) { // nothing to do: return true if there was really nothing to do and // false if we failed to set bg colour diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index 089a1eef7c..6561fc4fb5 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -1082,14 +1082,43 @@ void wxNSTextViewControl::SetStyle(long start, if ( start == -1 && end == -1 ) { NSMutableDictionary* const - attrs = [NSMutableDictionary dictionaryWithCapacity:3]; + attrs = [NSMutableDictionary dictionaryWithCapacity:5]; if ( style.HasFont() ) [attrs setValue:style.GetFont().OSXGetNSFont() forKey:NSFontAttributeName]; if ( style.HasBackgroundColour() ) [attrs setValue:style.GetBackgroundColour().OSXGetNSColor() forKey:NSBackgroundColorAttributeName]; if ( style.HasTextColour() ) [attrs setValue:style.GetTextColour().OSXGetNSColor() forKey:NSForegroundColorAttributeName]; + if ( style.GetUnderlineType() ) + { + wxTextAttrUnderlineType underlineType = style.GetUnderlineType(); + switch ( underlineType ) + { + case wxTEXT_ATTR_UNDERLINE_NONE: + [attrs setObject:[NSNumber numberWithInt:( NSUnderlineStyleNone )] forKey:NSUnderlineStyleAttributeName]; + break; + case wxTEXT_ATTR_UNDERLINE_SOLID: + [attrs setObject:[NSNumber numberWithInt:( NSUnderlineStyleSingle | NSUnderlineStyleSingle )] forKey:NSUnderlineStyleAttributeName]; + break; + + case wxTEXT_ATTR_UNDERLINE_DOUBLE: + [attrs setObject:[NSNumber numberWithInt:( NSUnderlineStyleSingle | NSUnderlineStyleDouble )] forKey:NSUnderlineStyleAttributeName]; + break; + + case wxTEXT_ATTR_UNDERLINE_WAVE: + [attrs setObject:[NSNumber numberWithInt:( NSUnderlineStyleSingle | NSUnderlinePatternDot )] forKey:NSUnderlineStyleAttributeName]; + break; + } + wxColour color = style.GetUnderlineColour(); + if ( !color.IsOk() ) + { + color = style.GetTextColour(); + if ( !color.IsOk() ) + color = *wxBLACK; + } + [attrs setValue:color.OSXGetNSColor() forKey:NSUnderlineColorAttributeName]; + } [m_textView setTypingAttributes:attrs]; } else // Set the attributes just for this range. @@ -1105,6 +1134,33 @@ void wxNSTextViewControl::SetStyle(long start, if ( style.HasTextColour() ) [storage addAttribute:NSForegroundColorAttributeName value:style.GetTextColour().OSXGetNSColor() range:range]; + + if( style.HasFontUnderlined() ) + { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + if( style.GetUnderlineType() == wxTEXT_ATTR_UNDERLINE_NONE ) + [dict setObject:[NSNumber numberWithInt:(NSUnderlineStyleNone)] forKey:NSUnderlineStyleAttributeName]; + + if( style.GetUnderlineType() == wxTEXT_ATTR_UNDERLINE_SOLID ) + [dict setObject:[NSNumber numberWithInt:( NSUnderlineStyleSingle )] forKey:NSUnderlineStyleAttributeName]; + + if( style.GetUnderlineType() == wxTEXT_ATTR_UNDERLINE_DOUBLE ) + [dict setObject:[NSNumber numberWithInt:( NSUnderlineStyleDouble )] forKey:NSUnderlineStyleAttributeName]; + + if( style.GetUnderlineType() == wxTEXT_ATTR_UNDERLINE_WAVE ) + [dict setObject:[NSNumber numberWithInt:( NSUnderlinePatternDot )] forKey:NSUnderlineStyleAttributeName]; + wxColour color = style.GetUnderlineColour(); + if( !color.IsOk() ) + { + color = style.GetTextColour(); + if( !color.IsOk() ) + color = *wxBLACK; + } + [dict setValue:color.OSXGetNSColor() forKey:NSUnderlineColorAttributeName]; + + [storage addAttributes:dict range:range]; + [dict release]; + } } if ( style.HasAlignment() )