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