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