]> git.saurik.com Git - wxWidgets.git/blob - src/common/textmeasurecmn.cpp
Fix wxTextEntryDialog::GetValue() when using SetTextValidator().
[wxWidgets.git] / src / common / textmeasurecmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/textmeasurecmn.cpp
3 // Purpose: wxTextMeasureBase implementation
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/dc.h"
24 #include "wx/window.h"
25 #endif //WX_PRECOMP
26
27 #include "wx/private/textmeasure.h"
28
29 // ============================================================================
30 // wxTextMeasureBase implementation
31 // ============================================================================
32
33 wxTextMeasureBase::wxTextMeasureBase(const wxDC *dc, const wxFont *theFont)
34 : m_dc(dc),
35 m_win(NULL),
36 m_font(theFont)
37 {
38 wxASSERT_MSG( dc, wxS("wxTextMeasure needs a valid wxDC") );
39
40 // By default, use wxDC version, we'll explicitly reset this to false in
41 // the derived classes if the DC is of native variety.
42 m_useDCImpl = true;
43 }
44
45 wxTextMeasureBase::wxTextMeasureBase(const wxWindow *win, const wxFont *theFont)
46 : m_dc(NULL),
47 m_win(win),
48 m_font(theFont)
49 {
50 wxASSERT_MSG( win, wxS("wxTextMeasure needs a valid wxWindow") );
51
52 // We don't have any wxDC so we can't forward to it.
53 m_useDCImpl = false;
54 }
55
56 wxFont wxTextMeasureBase::GetFont() const
57 {
58 return m_font ? *m_font
59 : m_win ? m_win->GetFont()
60 : m_dc->GetFont();
61 }
62
63 void wxTextMeasureBase::CallGetTextExtent(const wxString& string,
64 wxCoord *width,
65 wxCoord *height,
66 wxCoord *descent,
67 wxCoord *externalLeading)
68 {
69 if ( m_useDCImpl )
70 m_dc->GetTextExtent(string, width, height, descent, externalLeading);
71 else
72 DoGetTextExtent(string, width, height, descent, externalLeading);
73 }
74
75 void wxTextMeasureBase::GetTextExtent(const wxString& string,
76 wxCoord *width,
77 wxCoord *height,
78 wxCoord *descent,
79 wxCoord *externalLeading)
80 {
81 // To make the code simpler, make sure that the width and height pointers
82 // are always valid, even if they point to dummy variables.
83 int unusedWidth, unusedHeight;
84 if ( !width )
85 width = &unusedWidth;
86 if ( !height )
87 height = &unusedHeight;
88
89 if ( string.empty() )
90 {
91 *width =
92 *height = 0;
93
94 return;
95 }
96
97 MeasuringGuard guard(*this);
98
99 CallGetTextExtent(string, width, height, descent, externalLeading);
100 }
101
102 void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
103 wxCoord *width,
104 wxCoord *height,
105 wxCoord *heightOneLine)
106 {
107 MeasuringGuard guard(*this);
108
109 wxCoord widthTextMax = 0, widthLine,
110 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
111
112 wxString curLine;
113 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
114 {
115 if ( pc == text.end() || *pc == wxS('\n') )
116 {
117 if ( curLine.empty() )
118 {
119 // we can't use GetTextExtent - it will return 0 for both width
120 // and height and an empty line should count in height
121 // calculation
122
123 // assume that this line has the same height as the previous
124 // one
125 if ( !heightLineDefault )
126 heightLineDefault = heightLine;
127
128 if ( !heightLineDefault )
129 {
130 // but we don't know it yet - choose something reasonable
131 int dummy;
132 CallGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
133 }
134
135 heightTextTotal += heightLineDefault;
136 }
137 else
138 {
139 CallGetTextExtent(curLine, &widthLine, &heightLine);
140 if ( widthLine > widthTextMax )
141 widthTextMax = widthLine;
142 heightTextTotal += heightLine;
143 }
144
145 if ( pc == text.end() )
146 {
147 break;
148 }
149 else // '\n'
150 {
151 curLine.clear();
152 }
153 }
154 else
155 {
156 curLine += *pc;
157 }
158 }
159
160 if ( width )
161 *width = widthTextMax;
162 if ( height )
163 *height = heightTextTotal;
164 if ( heightOneLine )
165 *heightOneLine = heightLine;
166 }
167
168 wxSize wxTextMeasureBase::GetLargestStringExtent(size_t n,
169 const wxString* strings)
170 {
171 MeasuringGuard guard(*this);
172
173 wxCoord w, h, widthMax = 0, heightMax = 0;
174 for ( size_t i = 0; i < n; ++i )
175 {
176 CallGetTextExtent(strings[i], &w, &h);
177
178 if ( w > widthMax )
179 widthMax = w;
180 if ( h > heightMax )
181 heightMax = h;
182 }
183
184 return wxSize(widthMax, heightMax);
185 }
186
187 bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
188 wxArrayInt& widths,
189 double scaleX)
190 {
191 widths.Empty();
192 if ( text.empty() )
193 return true;
194
195 MeasuringGuard guard(*this);
196
197 widths.Add(0, text.length());
198
199 return DoGetPartialTextExtents(text, widths, scaleX);
200 }
201
202 // ----------------------------------------------------------------------------
203 // Generic and inefficient DoGetPartialTextExtents() implementation.
204 // ----------------------------------------------------------------------------
205
206 // Each element of the widths array will be the width of the string up to and
207 // including the corresponding character in text. This is the generic
208 // implementation, the port-specific classes should do this with native APIs
209 // if available and if faster. Note: pango_layout_index_to_pos is much slower
210 // than calling GetTextExtent!!
211
212 #define FWC_SIZE 256
213
214 class FontWidthCache
215 {
216 public:
217 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
218 ~FontWidthCache() { delete []m_widths; }
219
220 void Reset()
221 {
222 if ( !m_widths )
223 m_widths = new int[FWC_SIZE];
224
225 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
226 }
227
228 wxFont m_font;
229 double m_scaleX;
230 int *m_widths;
231 };
232
233 static FontWidthCache s_fontWidthCache;
234
235 bool wxTextMeasureBase::DoGetPartialTextExtents(const wxString& text,
236 wxArrayInt& widths,
237 double scaleX)
238 {
239 int totalWidth = 0;
240
241 // reset the cache if font or horizontal scale have changed
242 if ( !s_fontWidthCache.m_widths ||
243 !wxIsSameDouble(s_fontWidthCache.m_scaleX, scaleX) ||
244 (s_fontWidthCache.m_font != *m_font) )
245 {
246 s_fontWidthCache.Reset();
247 s_fontWidthCache.m_font = *m_font;
248 s_fontWidthCache.m_scaleX = scaleX;
249 }
250
251 // Calculate the position of each character based on the widths of
252 // the previous characters. This is inexact for not fixed fonts.
253 int n = 0;
254 for ( wxString::const_iterator it = text.begin();
255 it != text.end();
256 ++it )
257 {
258 const wxChar c = *it;
259 unsigned int c_int = (unsigned int)c;
260
261 int w;
262 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
263 {
264 w = s_fontWidthCache.m_widths[c_int];
265 }
266 else
267 {
268 DoGetTextExtent(c, &w, NULL);
269 if (c_int < FWC_SIZE)
270 s_fontWidthCache.m_widths[c_int] = w;
271 }
272
273 totalWidth += w;
274 widths[n++] = totalWidth;
275 }
276
277 return true;
278 }
279