]> git.saurik.com Git - wxWidgets.git/blob - src/generic/markuptext.cpp
Add markup support to wxMSW wxButton and show it in the sample.
[wxWidgets.git] / src / generic / markuptext.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/markuptext.cpp
3 // Purpose: wxMarkupText implementation
4 // Author: Vadim Zeitlin
5 // Created: 2011-02-21
6 // RCS-ID: $Id: wxhead.cpp,v 1.11 2010-04-22 12:44:51 zeitlin Exp $
7 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
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 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_MARKUP
27
28 #ifndef WX_PRECOMP
29 #include "wx/gdicmn.h"
30 #include "wx/dc.h"
31 #endif // WX_PRECOMP
32
33 #include "wx/generic/private/markuptext.h"
34
35 #include "wx/private/markupparserattr.h"
36
37 namespace
38 {
39
40 // ----------------------------------------------------------------------------
41 // wxMarkupParserMeasureOutput: measure the extends of a markup string.
42 // ----------------------------------------------------------------------------
43
44 class wxMarkupParserMeasureOutput : public wxMarkupParserAttrOutput
45 {
46 public:
47 // Initialize the base class with the font to use. As we don't care about
48 // colours (which don't affect the text measurements), don't bother to
49 // specify them at all.
50 wxMarkupParserMeasureOutput(wxDC& dc, int *visibleHeight)
51 : wxMarkupParserAttrOutput(dc.GetFont(), wxColour(), wxColour()),
52 m_dc(dc),
53 m_visibleHeight(visibleHeight)
54 {
55 if ( visibleHeight )
56 *visibleHeight = 0;
57 }
58
59 const wxSize& GetSize() const { return m_size; }
60
61
62 virtual void OnText(const wxString& text_)
63 {
64 const wxString text(wxControl::RemoveMnemonics(text_));
65
66 // TODO-MULTILINE-MARKUP: Must use GetMultiLineTextExtent().
67 const wxSize size = m_dc.GetTextExtent(text);
68
69 m_size.x += size.x;
70 if ( size.y > m_size.y )
71 m_size.y = size.y;
72
73 if ( m_visibleHeight )
74 {
75 wxFontMetrics tm = m_dc.GetFontMetrics();
76 int visibleHeight = tm.ascent - tm.internalLeading;
77 if ( *m_visibleHeight < visibleHeight )
78 *m_visibleHeight = visibleHeight;
79 }
80 }
81
82 virtual void OnAttrStart(const Attr& attr)
83 {
84 m_dc.SetFont(attr.font);
85 }
86
87 virtual void OnAttrEnd(const Attr& WXUNUSED(attr))
88 {
89 m_dc.SetFont(GetFont());
90 }
91
92 private:
93 wxDC& m_dc;
94
95 // The values that we compute.
96 wxSize m_size;
97 int * const m_visibleHeight; // may be NULL
98
99 wxDECLARE_NO_COPY_CLASS(wxMarkupParserMeasureOutput);
100 };
101
102 // ----------------------------------------------------------------------------
103 // wxMarkupParserRenderOutput: render a markup string.
104 // ----------------------------------------------------------------------------
105
106 class wxMarkupParserRenderOutput : public wxMarkupParserAttrOutput
107 {
108 public:
109 // Notice that the bottom of rectangle passed to our ctor is used as the
110 // baseline for the text we draw, i.e. it needs to be adjusted to exclude
111 // descent by the caller.
112 wxMarkupParserRenderOutput(wxDC& dc,
113 const wxRect& rect,
114 int flags)
115 : wxMarkupParserAttrOutput(dc.GetFont(),
116 dc.GetTextForeground(),
117 wxColour()),
118 m_dc(dc),
119 m_rect(rect),
120 m_flags(flags)
121 {
122 m_pos = m_rect.x;
123
124 // We don't initialize the base class initial text background colour to
125 // the valid value because we want to be able to detect when we revert
126 // to the "absence of background colour" and set the background mode to
127 // be transparent in OnAttrStart() below. But do remember it to be able
128 // to restore it there later -- this doesn't affect us as the text
129 // background isn't used anyhow when the background mode is transparent
130 // but it might affect the caller if it sets the background mode to
131 // opaque and draws some text after using us.
132 m_origTextBackground = dc.GetTextBackground();
133 }
134
135 virtual void OnText(const wxString& text_)
136 {
137 wxString text;
138 int indexAccel = wxControl::FindAccelIndex(text_, &text);
139 if ( !(m_flags & wxMarkupText::Render_ShowAccels) )
140 indexAccel = wxNOT_FOUND;
141
142 // Adjust the position (unfortunately we need to do this manually as
143 // there is no notion of current text position in wx API) rectangle to
144 // ensure that all text segments use the same baseline (as there is
145 // nothing equivalent to Windows SetTextAlign(TA_BASELINE) neither).
146 wxRect rect(m_rect);
147 rect.x = m_pos;
148
149 int descent;
150 m_dc.GetTextExtent(text, &rect.width, &rect.height, &descent);
151 rect.height -= descent;
152 rect.y += m_rect.height - rect.height;
153
154 wxRect bounds;
155 m_dc.DrawLabel(text, wxBitmap(),
156 rect, wxALIGN_LEFT | wxALIGN_TOP,
157 indexAccel,
158 &bounds);
159
160 // TODO-MULTILINE-MARKUP: Must update vertical position too.
161 m_pos += bounds.width;
162 }
163
164 virtual void OnAttrStart(const Attr& attr)
165 {
166 m_dc.SetFont(attr.font);
167 if ( attr.foreground.IsOk() )
168 m_dc.SetTextForeground(attr.foreground);
169
170 if ( attr.background.IsOk() )
171 {
172 // Setting the background colour is not enough, we must also change
173 // the mode to ensure that it is actually used.
174 m_dc.SetBackgroundMode(wxSOLID);
175 m_dc.SetTextBackground(attr.background);
176 }
177 }
178
179 virtual void OnAttrEnd(const Attr& attr)
180 {
181 // We always restore the font because we always change it...
182 m_dc.SetFont(GetFont());
183
184 // ...but we only need to restore the colours if we had changed them.
185 if ( attr.foreground.IsOk() )
186 m_dc.SetTextForeground(GetAttr().foreground);
187
188 if ( attr.background.IsOk() )
189 {
190 wxColour background = GetAttr().background;
191 if ( !background.IsOk() )
192 {
193 // Invalid background colour indicates that the background
194 // should actually be made transparent and in this case the
195 // actual value of background colour doesn't matter but we also
196 // restore it just in case, see comment in the ctor.
197 m_dc.SetBackgroundMode(wxTRANSPARENT);
198 background = m_origTextBackground;
199 }
200
201 m_dc.SetTextBackground(background);
202 }
203 }
204
205 private:
206 wxDC& m_dc;
207 const wxRect m_rect;
208 const int m_flags;
209
210 wxColour m_origTextBackground;
211
212 // Current horizontal text output position.
213 //
214 // TODO-MULTILINE-MARKUP: Must keep vertical position too.
215 int m_pos;
216
217 wxDECLARE_NO_COPY_CLASS(wxMarkupParserRenderOutput);
218 };
219
220 } // anonymous namespace
221
222 // ============================================================================
223 // wxMarkupText implementation
224 // ============================================================================
225
226 wxSize wxMarkupText::Measure(wxDC& dc, int *visibleHeight) const
227 {
228 wxMarkupParserMeasureOutput out(dc, visibleHeight);
229 wxMarkupParser parser(out);
230 if ( !parser.Parse(m_markup) )
231 {
232 wxFAIL_MSG( "Invalid markup" );
233 return wxDefaultSize;
234 }
235
236 return out.GetSize();
237 }
238
239 void wxMarkupText::Render(wxDC& dc, const wxRect& rect, int flags)
240 {
241 // We want to center the above-baseline parts of the letter vertically, so
242 // we use the visible height and not the total height (which includes
243 // descent and internal leading) here.
244 int visibleHeight;
245 wxRect rectText(rect.GetPosition(), Measure(dc, &visibleHeight));
246 rectText.height = visibleHeight;
247
248 wxMarkupParserRenderOutput out(dc, rectText.CentreIn(rect), flags);
249 wxMarkupParser parser(out);
250 parser.Parse(m_markup);
251 }
252
253 #endif // wxUSE_MARKUP