]>
Commit | Line | Data |
---|---|---|
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 |