1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/stattext.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // Copyright:   (c) 1998 Robert Roebling
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #if wxUSE_STATTEXT
13 
14 #include "wx/stattext.h"
15 
16 #include "wx/gtk/private.h"
17 
18 //-----------------------------------------------------------------------------
19 // wxStaticText
20 //-----------------------------------------------------------------------------
21 
wxStaticText()22 wxStaticText::wxStaticText()
23 {
24 }
25 
wxStaticText(wxWindow * parent,wxWindowID id,const wxString & label,const wxPoint & pos,const wxSize & size,long style,const wxString & name)26 wxStaticText::wxStaticText(wxWindow *parent,
27                            wxWindowID id,
28                            const wxString &label,
29                            const wxPoint &pos,
30                            const wxSize &size,
31                            long style,
32                            const wxString &name)
33 {
34     Create( parent, id, label, pos, size, style, name );
35 }
36 
Create(wxWindow * parent,wxWindowID id,const wxString & label,const wxPoint & pos,const wxSize & size,long style,const wxString & name)37 bool wxStaticText::Create(wxWindow *parent,
38                           wxWindowID id,
39                           const wxString &label,
40                           const wxPoint &pos,
41                           const wxSize &size,
42                           long style,
43                           const wxString &name )
44 {
45     if (!PreCreation( parent, pos, size ) ||
46         !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
47     {
48         wxFAIL_MSG( wxT("wxStaticText creation failed") );
49         return false;
50     }
51 
52     m_widget = gtk_label_new(NULL);
53     g_object_ref(m_widget);
54 
55     GtkJustification justify;
56     if ( style & wxALIGN_CENTER_HORIZONTAL )
57     {
58 #ifndef __WXGTK3__
59         // This looks like a bug in GTK+ and seems to be fixed in GTK+3, but
60         // using non-default justification with default ellipsize mode doesn't
61         // work: the justification is just ignored. In practice, alignment is
62         // more important, so turn on ellipsize mode even if it was not
63         // specified to make it work if necessary.
64         if ( !(style & wxST_ELLIPSIZE_MASK) )
65             style |= wxST_ELLIPSIZE_MIDDLE;
66 #endif // GTK+ 2
67 
68         justify = GTK_JUSTIFY_CENTER;
69     }
70     else if ( style & wxALIGN_RIGHT )
71     {
72 #ifndef __WXGTK3__
73         // As above, we need to use a non-default ellipsize mode for the
74         // alignment to have any effect.
75         if ( !(style & wxST_ELLIPSIZE_MASK) )
76             style |= wxST_ELLIPSIZE_START;
77 #endif // GTK+ 2
78 
79         justify = GTK_JUSTIFY_RIGHT;
80     }
81     else // must be wxALIGN_LEFT which is 0
82     {
83         // No need to play games with wxST_ELLIPSIZE_XXX.
84         justify = GTK_JUSTIFY_LEFT;
85     }
86 
87     if (GetLayoutDirection() == wxLayout_RightToLeft)
88     {
89         if (justify == GTK_JUSTIFY_RIGHT)
90             justify = GTK_JUSTIFY_LEFT;
91         else if (justify == GTK_JUSTIFY_LEFT)
92             justify = GTK_JUSTIFY_RIGHT;
93     }
94 
95     gtk_label_set_justify(GTK_LABEL(m_widget), justify);
96 
97     // set ellipsize mode
98     PangoEllipsizeMode ellipsizeMode = PANGO_ELLIPSIZE_NONE;
99     if ( style & wxST_ELLIPSIZE_START )
100         ellipsizeMode = PANGO_ELLIPSIZE_START;
101     else if ( style & wxST_ELLIPSIZE_MIDDLE )
102         ellipsizeMode = PANGO_ELLIPSIZE_MIDDLE;
103     else if ( style & wxST_ELLIPSIZE_END )
104         ellipsizeMode = PANGO_ELLIPSIZE_END;
105 
106     gtk_label_set_ellipsize( GTK_LABEL(m_widget), ellipsizeMode );
107 
108     // GTK_JUSTIFY_LEFT is 0, RIGHT 1 and CENTER 2
109     static const float labelAlignments[] = { 0.0, 1.0, 0.5 };
110 #ifdef __WXGTK4__
111     g_object_set(m_widget, "xalign", labelAlignments[justify], NULL);
112 #else
113     wxGCC_WARNING_SUPPRESS(deprecated-declarations)
114     gtk_misc_set_alignment(GTK_MISC(m_widget), labelAlignments[justify], 0.0);
115     wxGCC_WARNING_RESTORE()
116 #endif
117 
118     gtk_label_set_line_wrap( GTK_LABEL(m_widget), TRUE );
119 
120     SetLabel(label);
121 
122     m_parent->DoAddChild( this );
123 
124     PostCreation(size);
125 
126 #ifndef __WXGTK3__
127     // GtkLabel does its layout based on its size-request, rather than its
128     // actual size. The size-request may not always get set, specifically if
129     // the initial size is fully specified. So make sure it's set here.
130     gtk_widget_set_size_request(m_widget, m_width, m_height);
131 #endif
132 
133     return true;
134 }
135 
GTKDoSetLabel(GTKLabelSetter setter,const wxString & label)136 void wxStaticText::GTKDoSetLabel(GTKLabelSetter setter, const wxString& label)
137 {
138     wxCHECK_RET( m_widget != NULL, wxT("invalid static text") );
139 
140     (this->*setter)(GTK_LABEL(m_widget), label);
141 
142     AutoResizeIfNecessary();
143 }
144 
SetLabel(const wxString & label)145 void wxStaticText::SetLabel(const wxString& label)
146 {
147     if ( label == m_labelOrig )
148         return;
149 
150     m_labelOrig = label;
151 
152     GTKDoSetLabel(&wxStaticText::GTKSetLabelForLabel, label);
153 }
154 
155 #if wxUSE_MARKUP
156 
DoSetLabelMarkup(const wxString & markup)157 bool wxStaticText::DoSetLabelMarkup(const wxString& markup)
158 {
159     const wxString stripped = RemoveMarkup(markup);
160     if ( stripped.empty() && !markup.empty() )
161         return false;
162 
163     m_labelOrig = stripped;
164 
165     GTKDoSetLabel(&wxStaticText::GTKSetLabelWithMarkupForLabel, markup);
166 
167     return true;
168 }
169 
170 #endif // wxUSE_MARKUP
171 
SetFont(const wxFont & font)172 bool wxStaticText::SetFont( const wxFont &font )
173 {
174     const bool wasUnderlined = GetFont().GetUnderlined();
175     const bool wasStrickenThrough = GetFont().GetStrikethrough();
176 
177     if ( !wxControl::SetFont(font) )
178         return false;
179 
180     const bool isUnderlined = GetFont().GetUnderlined();
181     const bool isStrickenThrough = GetFont().GetStrikethrough();
182 
183     if ( (isUnderlined != wasUnderlined) ||
184             (isStrickenThrough != wasStrickenThrough) )
185     {
186         // We need to update the Pango attributes used for the text.
187         if ( isUnderlined || isStrickenThrough )
188         {
189             PangoAttrList* const attrs = pango_attr_list_new();
190             if ( isUnderlined )
191             {
192                 PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
193                 a->start_index = 0;
194                 a->end_index = (guint)-1;
195                 pango_attr_list_insert(attrs, a);
196             }
197 
198             if ( isStrickenThrough )
199             {
200                 PangoAttribute *a = pango_attr_strikethrough_new( TRUE );
201                 a->start_index = 0;
202                 a->end_index = (guint) -1;
203                 pango_attr_list_insert(attrs, a);
204             }
205 
206             gtk_label_set_attributes(GTK_LABEL(m_widget), attrs);
207             pango_attr_list_unref(attrs);
208         }
209         else // No special attributes any more.
210         {
211             // Just remove any attributes we had set.
212             gtk_label_set_attributes(GTK_LABEL(m_widget), NULL);
213         }
214 
215         // The underlines for mnemonics are incompatible with using attributes
216         // so turn them off when setting underlined font.
217         gtk_label_set_use_underline(GTK_LABEL(m_widget), !isUnderlined);
218     }
219 
220     AutoResizeIfNecessary();
221 
222     return true;
223 }
224 
DoGetBestSize() const225 wxSize wxStaticText::DoGetBestSize() const
226 {
227     // Do not return any arbitrary default value...
228     wxASSERT_MSG( m_widget, wxT("wxStaticText::DoGetBestSize called before creation") );
229 
230     // GetBestSize is supposed to return unwrapped size but calling
231     // gtk_label_set_line_wrap() from here is a bad idea as it queues another
232     // size request by calling gtk_widget_queue_resize() and we end up in
233     // infinite loop sometimes (notably when the control is in a toolbar)
234     // With GTK3 however, there is no simple alternative, and the sizing loop
235     // no longer seems to occur.
236 #ifdef __WXGTK3__
237     gtk_label_set_line_wrap(GTK_LABEL(m_widget), false);
238 #else
239     GTK_LABEL(m_widget)->wrap = FALSE;
240 
241     // Reset the ellipsize mode while computing the best size, otherwise it's
242     // going to be too small as the control knows that it can be shrunk to the
243     // bare minimum and just hide most of the text replacing it with ellipsis.
244     // This is especially important because we can enable ellipsization
245     // implicitly for GTK+ 2, see the code dealing with alignment in the ctor.
246     const PangoEllipsizeMode ellipsizeMode = gtk_label_get_ellipsize(GTK_LABEL(m_widget));
247     gtk_label_set_ellipsize(GTK_LABEL(m_widget), PANGO_ELLIPSIZE_NONE);
248 #endif
249     wxSize size = wxStaticTextBase::DoGetBestSize();
250 #ifdef __WXGTK3__
251     gtk_label_set_line_wrap(GTK_LABEL(m_widget), true);
252 #else
253     gtk_label_set_ellipsize(GTK_LABEL(m_widget), ellipsizeMode);
254     GTK_LABEL(m_widget)->wrap = TRUE; // restore old value
255 #endif
256 
257     // Adding 1 to width to workaround GTK sometimes wrapping the text needlessly
258     size.x++;
259     return size;
260 }
261 
GTKWidgetNeedsMnemonic() const262 bool wxStaticText::GTKWidgetNeedsMnemonic() const
263 {
264     return true;
265 }
266 
GTKWidgetDoSetMnemonic(GtkWidget * w)267 void wxStaticText::GTKWidgetDoSetMnemonic(GtkWidget* w)
268 {
269     gtk_label_set_mnemonic_widget(GTK_LABEL(m_widget), w);
270 }
271 
272 
273 // These functions are not used as GTK supports ellipsization natively and we
274 // never call the base class UpdateText() which uses them.
275 //
276 // Note that, unfortunately, we still need to define them because they still
277 // exist, as pure virtuals, in the base class even in wxGTK to allow
278 // wxGenericStaticText to override them.
279 
WXGetVisibleLabel() const280 wxString wxStaticText::WXGetVisibleLabel() const
281 {
282     wxFAIL_MSG(wxS("Unreachable"));
283 
284     return wxString();
285 }
286 
WXSetVisibleLabel(const wxString & WXUNUSED (str))287 void wxStaticText::WXSetVisibleLabel(const wxString& WXUNUSED(str))
288 {
289     wxFAIL_MSG(wxS("Unreachable"));
290 }
291 
292 // static
293 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))294 wxStaticText::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
295 {
296     return GetDefaultAttributesFromGTKWidget(gtk_label_new(""));
297 }
298 
299 #endif // wxUSE_STATTEXT
300