update position for widgets in native containers, fixes #15231
[wxWidgets.git] / src / gtk / textmeasure.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/textmeasure.cpp
3 // Purpose: wxTextMeasure implementation for wxGTK
4 // Author: Manuel Martin
5 // Created: 2012-10-05
6 // RCS-ID: $Id:
7 // Copyright: (c) 1997-2012 wxWidgets team
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/window.h"
24 #include "wx/log.h"
25 #endif //WX_PRECOMP
26
27 #include "wx/private/textmeasure.h"
28
29 #include "wx/fontutil.h"
30 #include "wx/gtk/private.h"
31 #include "wx/gtk/dc.h"
32
33 #ifndef __WXGTK3__
34 #include "wx/gtk/dcclient.h"
35 #endif
36
37 // ============================================================================
38 // wxTextMeasure implementation
39 // ============================================================================
40
41 void wxTextMeasure::Init()
42 {
43 m_context = NULL;
44 m_layout = NULL;
45
46 #ifndef __WXGTK3__
47 m_wdc = NULL;
48
49 if ( m_dc )
50 {
51 wxClassInfo* const ci = m_dc->GetImpl()->GetClassInfo();
52
53 // Currently the code here only works with wxWindowDCImpl and only in
54 // wxGTK2 as wxGTK3 uses Cairo and not Pango for all its DCs.
55 if ( ci->IsKindOf(wxCLASSINFO(wxWindowDCImpl)))
56 {
57 m_useDCImpl = false;
58 }
59 }
60 #endif // GTK+ < 3
61 }
62
63 // Get Gtk needed elements, if we have not them yet.
64 void wxTextMeasure::BeginMeasuring()
65 {
66 if ( m_dc )
67 {
68 #ifndef __WXGTK3__
69 m_wdc = wxDynamicCast(m_dc->GetImpl(), wxWindowDCImpl);
70 if ( m_wdc )
71 {
72 m_context = m_wdc->m_context;
73 m_layout = m_wdc->m_layout;
74 }
75 #endif // GTK+ < 3
76 }
77 else if ( m_win )
78 {
79 m_context = gtk_widget_get_pango_context( m_win->GetHandle() );
80 if ( m_context )
81 m_layout = pango_layout_new(m_context);
82 }
83
84 // set the font to use
85 if ( m_layout )
86 {
87 pango_layout_set_font_description(m_layout,
88 GetFont().GetNativeFontInfo()->description);
89 }
90 }
91
92 void wxTextMeasure::EndMeasuring()
93 {
94 if ( !m_layout )
95 return;
96
97 #ifndef __WXGTK3__
98 if ( m_wdc )
99 {
100 // Reset dc own font description
101 pango_layout_set_font_description( m_wdc->m_layout, m_wdc->m_fontdesc );
102 }
103 else
104 #endif // GTK+ < 3
105 {
106 g_object_unref (m_layout);
107 }
108 }
109
110 // Notice we don't check here the font. It is supposed to be OK before the call.
111 void wxTextMeasure::DoGetTextExtent(const wxString& string,
112 wxCoord *width,
113 wxCoord *height,
114 wxCoord *descent,
115 wxCoord *externalLeading)
116 {
117 if ( !m_context )
118 {
119 if ( width )
120 *width = 0;
121
122 if ( height )
123 *height = 0;
124 return;
125 }
126
127 // Set layout's text
128 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, GetFont());
129 if ( !dataUTF8 )
130 {
131 // hardly ideal, but what else can we do if conversion failed?
132 wxLogLastError(wxT("GetTextExtent"));
133 return;
134 }
135 pango_layout_set_text(m_layout, dataUTF8, -1);
136
137 if ( m_dc )
138 {
139 // in device units
140 pango_layout_get_pixel_size(m_layout, width, height);
141 }
142 else // win
143 {
144 // the logical rect bounds the ink rect
145 PangoRectangle rect;
146 pango_layout_get_extents(m_layout, NULL, &rect);
147 *width = PANGO_PIXELS(rect.width);
148 *height = PANGO_PIXELS(rect.height);
149 }
150
151 if (descent)
152 {
153 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
154 int baseline = pango_layout_iter_get_baseline(iter);
155 pango_layout_iter_free(iter);
156 *descent = *height - PANGO_PIXELS(baseline);
157 }
158
159 if (externalLeading)
160 {
161 // No support for MSW-like "external leading" in Pango.
162 *externalLeading = 0;
163 }
164 }
165
166 bool wxTextMeasure::DoGetPartialTextExtents(const wxString& text,
167 wxArrayInt& widths,
168 double scaleX)
169 {
170 if ( !m_layout )
171 return wxTextMeasureBase::DoGetPartialTextExtents(text, widths, scaleX);
172
173 // Set layout's text
174 const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(text, GetFont());
175 if ( !dataUTF8 )
176 {
177 // hardly ideal, but what else can we do if conversion failed?
178 wxLogLastError(wxT("GetPartialTextExtents"));
179 return false;
180 }
181
182 pango_layout_set_text(m_layout, dataUTF8, -1);
183
184 // Calculate the position of each character based on the widths of
185 // the previous characters
186
187 // Code borrowed from Scintilla's PlatGTK
188 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
189 PangoRectangle pos;
190 pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
191 size_t i = 0;
192 while (pango_layout_iter_next_cluster(iter))
193 {
194 pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
195 int position = PANGO_PIXELS(pos.x);
196 widths[i++] = position;
197 }
198
199 const size_t len = text.length();
200 while (i < len)
201 widths[i++] = PANGO_PIXELS(pos.x + pos.width);
202 pango_layout_iter_free(iter);
203
204 return true;
205 }