]>
git.saurik.com Git - wxWidgets.git/blob - src/common/stattextcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/stattextcmn.cpp
3 // Purpose: common (to all ports) wxStaticText functions
4 // Author: Vadim Zeitlin, Francesco Montorsi
5 // Created: 2007-01-07 (extracted from dlgcmn.cpp)
7 // Copyright: (c) 1999-2006 Vadim Zeitlin
8 // (c) 2007 Francesco Montorsi
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/private/stattext.h"
30 #include "wx/button.h"
31 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35 #include "wx/stattext.h"
37 #include "wx/containr.h"
42 const wxChar
*wxMarkupEntities
[][wxMARKUP_ENTITY_MAX
] =
44 // the entities handled by SetLabel() when wxST_MARKUP is used and their referenced string
46 { wxT("&"), wxT("<"), wxT(">"), wxT("'"), wxT(""") },
47 { wxT("&"), wxT("<"), wxT(">"), wxT("'"), wxT("\"") }
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 void wxTextWrapper::Wrap(wxWindow
*win
, const wxString
& text
, int widthMax
)
59 wxString::const_iterator lastSpace
= text
.end();
60 wxString::const_iterator lineStart
= text
.begin();
61 for ( wxString::const_iterator p
= lineStart
; ; ++p
)
63 if ( IsStartOfNewLine() )
67 lastSpace
= text
.end();
72 if ( p
== text
.end() || *p
== _T('\n') )
76 if ( p
== text
.end() )
86 if ( widthMax
>= 0 && lastSpace
!= text
.end() )
89 win
->GetTextExtent(line
, &width
, NULL
);
91 if ( width
> widthMax
)
93 // remove the last word from this line
94 line
.erase(lastSpace
- lineStart
, p
+ 1 - lineStart
);
97 // go back to the last word of this line which we didn't
102 //else: no wrapping at all or impossible to wrap
108 // ----------------------------------------------------------------------------
109 // wxLabelWrapper: helper class for wxStaticTextBase::Wrap()
110 // ----------------------------------------------------------------------------
112 class wxLabelWrapper
: public wxTextWrapper
115 void WrapLabel(wxWindow
*text
, int widthMax
)
118 Wrap(text
, text
->GetLabel(), widthMax
);
119 text
->SetLabel(m_text
);
123 virtual void OnOutputLine(const wxString
& line
)
128 virtual void OnNewLine()
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 void wxStaticTextBase::Wrap(int width
)
144 wxLabelWrapper wrapper
;
145 wrapper
.WrapLabel(this, width
);
148 wxString
wxStaticTextBase::GetLabelText() const
150 wxString
ret(GetLabel());
152 if (HasFlag(wxST_MARKUP
))
153 ret
= RemoveMarkup(ret
);
154 return RemoveMnemonics(ret
);
158 wxString
wxStaticTextBase::GetLabelText(const wxString
& label
)
161 wxString ret
= RemoveMarkup(label
);
162 return RemoveMnemonics(ret
);
166 wxString
wxStaticTextBase::RemoveMarkup(const wxString
& text
)
168 // strip out of "text" the markup for platforms which don't support it natively
169 bool inside_tag
= false;
172 for ( wxString::const_iterator source
= text
.begin();
173 source
!= text
.end(); ++source
)
175 switch ( (*source
).GetValue() )
180 wxLogDebug(wxT("Invalid markup !"));
181 return wxEmptyString
;
189 wxLogDebug(wxT("Invalid markup !"));
190 return wxEmptyString
;
197 if ( source
+1 == text
.end() )
199 wxLogDebug(wxT("Cannot use & as last character of the string '%s'"),
201 return wxEmptyString
;
204 // is this ampersand introducing a mnemonic or rather an entity?
205 bool isMnemonic
= true;
206 size_t distanceFromEnd
= text
.end() - source
;
207 for (size_t j
=0; j
< wxMARKUP_ENTITY_MAX
; j
++)
209 const wxChar
*entity
= wxMarkupEntities
[wxMARKUP_ELEMENT_NAME
][j
];
210 size_t entityLen
= wxStrlen(entity
);
212 if (distanceFromEnd
>= entityLen
&&
213 wxString(source
, source
+ entityLen
) == entity
)
215 // replace the &entity; string with the entity reference
216 label
<< wxMarkupEntities
[wxMARKUP_ELEMENT_VALUE
][j
];
217 // little exception: when the entity reference is
218 // "&" (i.e. when entity is "&"), substitute it
219 // with && instead of a single ampersand:
220 if (*wxMarkupEntities
[wxMARKUP_ELEMENT_VALUE
][j
] == wxT('&'))
222 // the -1 is because main for() loop already
224 source
+= entityLen
- 1;
246 wxString
wxStaticTextBase::EscapeMarkup(const wxString
& text
)
250 for (wxString::const_iterator source
= text
.begin();
251 source
!= text
.end(); ++source
)
253 bool isEntity
= false;
255 // search in the list of the entities and eventually escape this character
256 for (size_t j
=0; j
< wxMARKUP_ENTITY_MAX
; j
++)
258 if (*source
== *wxMarkupEntities
[wxMARKUP_ELEMENT_VALUE
][j
])
260 ret
<< wxMarkupEntities
[wxMARKUP_ELEMENT_NAME
][j
];
267 ret
<< *source
; // this character does not need to be escaped
275 // ----------------------------------------------------------------------------
276 // wxStaticTextBase - generic implementation for wxST_ELLIPSIZE_* support
277 // ----------------------------------------------------------------------------
279 void wxStaticTextBase::UpdateLabel()
284 wxString newlabel
= GetEllipsizedLabelWithoutMarkup();
286 // we need to touch the "real" label (i.e. the text set inside the control,
287 // using port-specific functions) instead of the string returned by GetLabel().
289 // In fact, we must be careful not to touch the original label passed to
290 // SetLabel() otherwise GetLabel() will behave in a strange way to the user
291 // (e.g. returning a "Ver...ing" instead of "Very long string") !
292 if (newlabel
== DoGetLabel())
294 DoSetLabel(newlabel
);
297 wxString
wxStaticTextBase::GetEllipsizedLabelWithoutMarkup() const
299 // this function should be used only by ports which do not support
300 // ellipsis in static texts: we first remove markup (which cannot
301 // be handled safely by Ellipsize()) and then ellipsize the result.
303 wxString
ret(m_labelOrig
);
305 // the order of the following two blocks is important!
307 if (HasFlag(wxST_MARKUP
))
308 ret
= RemoveMarkup(ret
);
311 ret
= Ellipsize(ret
);
316 #define wxELLIPSE_REPLACEMENT wxT("...")
318 wxString
wxStaticTextBase::Ellipsize(const wxString
& label
) const
320 wxSize
sz(GetSize());
321 if (sz
.GetWidth() < 2 || sz
.GetHeight() < 2)
323 // the size of this window is not valid (yet)
327 wxClientDC
dc(wx_const_cast(wxStaticTextBase
*, this));
328 dc
.SetFont(GetFont());
330 wxArrayInt charOffsets
;
333 // these cannot be cached as they can change because of e.g. a font change
334 int replacementWidth
= dc
.GetTextExtent(wxELLIPSE_REPLACEMENT
).GetWidth();
335 int marginWidth
= dc
.GetCharWidth()*2;
337 // handle correctly labels with newlines
341 for ( wxString::const_iterator pc
= label
.begin(); ; ++pc
)
343 if ( pc
== label
.end() || *pc
== _T('\n') )
345 len
= curLine
.length();
347 dc
.GetPartialTextExtents(curLine
, charOffsets
))
349 wxASSERT(charOffsets
.GetCount() == len
);
351 size_t totalWidth
= charOffsets
.Last();
352 if ( totalWidth
> (size_t)sz
.GetWidth() )
354 // we need to ellipsize this row
355 int excessPixels
= totalWidth
- sz
.GetWidth() +
357 marginWidth
; // security margin (NEEDED!)
359 // remove characters in excess
360 size_t initialChar
, // index of first char to erase
361 nChars
; // how many chars do we need to erase?
362 if (HasFlag(wxST_ELLIPSIZE_START
))
366 nChars
< len
&& charOffsets
[nChars
] < excessPixels
;
370 else if (HasFlag(wxST_ELLIPSIZE_MIDDLE
))
372 // the start & end of the removed span of chars
374 size_t endChar
= len
/2;
377 for ( ; removed
< excessPixels
; )
381 // width of the initialChar-th character
382 int width
= charOffsets
[initialChar
] -
383 charOffsets
[initialChar
-1];
385 // remove the initialChar-th character
390 if (endChar
< len
- 1 &&
391 removed
< excessPixels
)
393 // width of the (endChar+1)-th character
394 int width
= charOffsets
[endChar
+1] -
395 charOffsets
[endChar
];
397 // remove the endChar-th character
402 if (initialChar
== 0 && endChar
== len
-1)
410 nChars
= endChar
- initialChar
+ 1;
414 wxASSERT(HasFlag(wxST_ELLIPSIZE_END
));
417 int maxWidth
= totalWidth
- excessPixels
;
420 charOffsets
[initialChar
] < maxWidth
;
424 if (initialChar
== 0)
430 initialChar
--; // go back one character
431 nChars
= len
- initialChar
;
437 // need to remove the entire row!
442 // erase nChars characters after initialChar (included):
443 curLine
.erase(initialChar
, nChars
+1);
445 // if there is space for the replacement dots, add them
446 if (sz
.GetWidth() > replacementWidth
)
447 curLine
.insert(initialChar
, wxELLIPSE_REPLACEMENT
);
450 // if everything was ok, we should have shortened this line
451 // enough to make it fit in sz.GetWidth():
452 wxASSERT(dc
.GetTextExtent(curLine
).GetWidth() < sz
.GetWidth());
456 // add this (ellipsized) row to the rest of the label
458 if ( pc
== label
.end() )
468 // we need to remove mnemonics from the label for correct calculations
469 else if ( *pc
== _T('&') )
471 // pc+1 is safe: at worst we'll be at end()
472 wxString::const_iterator next
= pc
+ 1;
473 if ( next
!= label
.end() && *next
== _T('&') )
474 curLine
+= _T('&'); // && becomes &
475 //else: remove this ampersand
477 // we need also to expand tabs to properly calc their size
478 else if ( *pc
== _T('\t') )
480 // Windows natively expands the TABs to 6 spaces. Do the same:
492 #endif // wxUSE_STATTEXT