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