]>
Commit | Line | Data |
---|---|---|
5f35b46a JS |
1 | \section{wxRichTextCtrl overview}\label{wxrichtextctrloverview} |
2 | ||
3 | Classes: \helpref{wxRichTextCtrl}{wxrichtextctrl}, \helpref{wxRichTextBuffer}{wxrichtextbuffer}, | |
4 | \helpref{wxRichTextAttr}{wxrichtextattr}, \helpref{wxTextAttrEx}{wxtextattrex}, | |
5 | \helpref{wxRichTextCharacterStyleDefinition}{wxrichtextcharacterstyledefinition}, | |
6 | \helpref{wxRichTextParagraphStyleDefinition}{wxrichtextparagraphstyledefinition}, | |
d2d0adc7 | 7 | \helpref{wxRichTextListStyleDefinition}{wxrichtextliststyledefinition}, |
5f35b46a | 8 | \helpref{wxRichTextStyleSheet}{wxrichtextstylesheet}, |
62a268cc | 9 | \helpref{wxRichTextStyleComboCtrl}{wxrichtextstylecomboctrl}, |
5f35b46a | 10 | \helpref{wxRichTextStyleListBox}{wxrichtextstylelistbox}, |
1f65137f | 11 | \helpref{wxRichTextStyleListCtrl}{wxrichtextstylelistctrl}, |
5f35b46a JS |
12 | \helpref{wxRichTextEvent}{wxrichtextevent}, \helpref{wxRichTextRange}{wxrichtextrange}, |
13 | \helpref{wxRichTextFileHandler}{wxrichtextfilehandler}, \helpref{wxRichTextHTMLHandler}{wxrichtexthtmlhandler}, | |
62a268cc JS |
14 | \helpref{wxRichTextXMLHandler}{wxrichtextxmlhandler}, |
15 | \helpref{wxRichTextFormattingDialog}{wxrichtextformattingdialog}, | |
62f4313b JS |
16 | \helpref{wxRichTextPrinting}{wxrichtextprinting}, |
17 | \helpref{wxRichTextPrintout}{wxrichtextprintout}, | |
18 | \helpref{wxRichTextHeaderFooterData}{wxrichtextheaderfooterdata}, | |
62a268cc | 19 | \helpref{wxSymbolPickerDialog}{wxsymbolpickerdialog} |
5f35b46a | 20 | |
27b12131 JS |
21 | wxRichTextCtrl provides a generic implementation of a rich text editor that can handle different character |
22 | styles, paragraph formatting, and images. It's aimed at editing 'natural' language text - if you need an editor that supports code editing, | |
23 | wxStyledTextCtrl is a better choice. | |
24 | ||
25 | Despite its name, it cannot currently read or write RTF (rich text format) files. Instead, it | |
26 | uses its own XML format, and can also read and write plain text. In future we expect to provide | |
27 | RTF file capabilities. Custom file formats can be supported by creating additional | |
28 | file handlers and registering them with the control. | |
29 | ||
30 | wxRichTextCtrl is largely compatible with the wxTextCtrl API, but extends it where necessary. | |
31 | The control can be used where the native rich text capabilities of wxTextCtrl are not | |
32 | adequate (this is particularly true on Windows) and where more direct access to | |
33 | the content representation is required. It is difficult and inefficient to read | |
34 | the style information in a wxTextCtrl, whereas this information is readily | |
35 | available in wxRichTextCtrl. Since it's written in pure wxWidgets, any customizations | |
36 | you make to wxRichTextCtrl will be reflected on all platforms. | |
37 | ||
38 | There are of course a few disadvantages to using wxRichTextCtrl. It is not native, | |
39 | so does not behave exactly as a native wxTextCtrl, although common editing conventions | |
40 | are followed. Users may miss the built-in spelling correction on Mac OS X, or any | |
41 | special character input that may be provided by the native control. It would also | |
42 | be a bad choice if intended users rely on screen readers that would be unhappy | |
43 | with non-native text input implementation. You might mitigate this by providing | |
44 | the choice between wxTextCtrl and wxRichTextCtrl, with fewer features in the | |
45 | former case. | |
46 | ||
47 | wxRichTextCtrl does not yet support printing directly, but content can be converted | |
48 | to HTML which can then be used with \helpref{wxHtmlEasyPrinting}{wxhtmleasyprinting}. | |
5f35b46a JS |
49 | |
50 | The following screenshot shows the wxRichTextCtrl sample in action: | |
51 | ||
52 | $$\image{8cm;0cm}{richtextctrl.gif}$$ | |
53 | ||
54 | \wxheading{Example}\label{wxrichtextctrlexample} | |
55 | ||
27b12131 | 56 | The following code is taken from the sample, and adds text and styles to a rich text control programmatically. |
5f35b46a JS |
57 | |
58 | {\small | |
59 | \begin{verbatim} | |
27b12131 JS |
60 | wxRichTextCtrl* richTextCtrl = new wxRichTextCtrl(splitter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS); |
61 | ||
62 | wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL); | |
63 | wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD); | |
64 | wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL); | |
65 | ||
66 | wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL); | |
67 | ||
68 | m_richTextCtrl->SetFont(font); | |
69 | ||
70 | wxRichTextCtrl& r = richTextCtrl; | |
71 | ||
72 | r.BeginSuppressUndo(); | |
73 | ||
74 | r.BeginParagraphSpacing(0, 20); | |
75 | ||
76 | r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE); | |
77 | r.BeginBold(); | |
78 | ||
79 | r.BeginFontSize(14); | |
80 | r.WriteText(wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images")); | |
81 | r.EndFontSize(); | |
82 | r.Newline(); | |
83 | ||
84 | r.BeginItalic(); | |
85 | r.WriteText(wxT("by Julian Smart")); | |
86 | r.EndItalic(); | |
87 | ||
88 | r.EndBold(); | |
89 | ||
90 | r.Newline(); | |
91 | r.WriteImage(wxBitmap(zebra_xpm)); | |
92 | ||
93 | r.EndAlignment(); | |
94 | ||
95 | r.Newline(); | |
96 | r.Newline(); | |
97 | ||
98 | r.WriteText(wxT("What can you do with this thing? ")); | |
99 | r.WriteImage(wxBitmap(smiley_xpm)); | |
100 | r.WriteText(wxT(" Well, you can change text ")); | |
101 | ||
102 | r.BeginTextColour(wxColour(255, 0, 0)); | |
103 | r.WriteText(wxT("colour, like this red bit.")); | |
104 | r.EndTextColour(); | |
105 | ||
106 | r.BeginTextColour(wxColour(0, 0, 255)); | |
107 | r.WriteText(wxT(" And this blue bit.")); | |
108 | r.EndTextColour(); | |
109 | ||
110 | r.WriteText(wxT(" Naturally you can make things ")); | |
111 | r.BeginBold(); | |
112 | r.WriteText(wxT("bold ")); | |
113 | r.EndBold(); | |
114 | r.BeginItalic(); | |
115 | r.WriteText(wxT("or italic ")); | |
116 | r.EndItalic(); | |
117 | r.BeginUnderline(); | |
118 | r.WriteText(wxT("or underlined.")); | |
119 | r.EndUnderline(); | |
120 | ||
121 | r.BeginFontSize(14); | |
122 | r.WriteText(wxT(" Different font sizes on the same line is allowed, too.")); | |
123 | r.EndFontSize(); | |
124 | ||
125 | r.WriteText(wxT(" Next we'll show an indented paragraph.")); | |
126 | ||
127 | r.BeginLeftIndent(60); | |
128 | r.Newline(); | |
129 | ||
130 | r.WriteText(wxT("Indented paragraph.")); | |
131 | r.EndLeftIndent(); | |
132 | ||
133 | r.Newline(); | |
134 | ||
135 | r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40).")); | |
136 | ||
137 | r.BeginLeftIndent(100, -40); | |
138 | r.Newline(); | |
139 | ||
140 | r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter.")); | |
141 | r.EndLeftIndent(); | |
142 | ||
143 | r.Newline(); | |
144 | ||
145 | r.WriteText(wxT("Numbered bullets are possible, again using subindents:")); | |
146 | ||
147 | r.BeginNumberedBullet(1, 100, 60); | |
148 | r.Newline(); | |
149 | ||
150 | r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later.")); | |
151 | r.EndNumberedBullet(); | |
152 | ||
153 | r.BeginNumberedBullet(2, 100, 60); | |
154 | r.Newline(); | |
155 | ||
156 | r.WriteText(wxT("This is my second item.")); | |
157 | r.EndNumberedBullet(); | |
158 | ||
159 | r.Newline(); | |
160 | ||
161 | r.WriteText(wxT("The following paragraph is right-indented:")); | |
162 | ||
163 | r.BeginRightIndent(200); | |
164 | r.Newline(); | |
165 | ||
166 | r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.")); | |
167 | r.EndRightIndent(); | |
168 | ||
169 | r.Newline(); | |
170 | ||
171 | wxArrayInt tabs; | |
172 | tabs.Add(400); | |
173 | tabs.Add(600); | |
174 | tabs.Add(800); | |
175 | tabs.Add(1000); | |
176 | wxTextAttrEx attr; | |
177 | attr.SetFlags(wxTEXT_ATTR_TABS); | |
178 | attr.SetTabs(tabs); | |
179 | r.SetDefaultStyle(attr); | |
180 | ||
181 | r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab")); | |
182 | ||
183 | r.Newline(); | |
184 | r.WriteText(wxT("Other notable features of wxRichTextCtrl include:")); | |
185 | ||
186 | r.BeginSymbolBullet(wxT('*'), 100, 60); | |
187 | r.Newline(); | |
188 | r.WriteText(wxT("Compatibility with wxTextCtrl API")); | |
189 | r.EndSymbolBullet(); | |
190 | ||
191 | r.WriteText(wxT("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!")); | |
192 | ||
193 | r.EndSuppressUndo(); | |
5f35b46a JS |
194 | \end{verbatim} |
195 | } | |
196 | ||
27b12131 JS |
197 | \subsection{Programming with wxRichTextCtrl} |
198 | ||
4f88b483 JS |
199 | \subsubsection{Starting to use wxRichTextCtrl} |
200 | ||
27b12131 JS |
201 | You need to include {\tt <wx/richtext/richtextctrl.h>} in your source, and link |
202 | with the appropriate wxWidgets library with {\tt richtext} suffix. Put the rich text | |
203 | library first in your link line to avoid unresolved symbols. | |
204 | ||
205 | Then you can create a wxRichTextCtrl, with the wxWANT\_CHARS style if you want tabs to | |
206 | be processed by the control rather than being used for navigation between controls. | |
207 | ||
4f88b483 JS |
208 | \subsubsection{wxRichTextCtrl and styles} |
209 | ||
210 | Styling attributes are represented by one of three classes: \helpref{wxTextAttr}{wxtextattr}, \helpref{wxTextAttrEx}{wxtextattrex} and \helpref{wxRichTextAttr}{wxrichtextattr}. | |
211 | wxTextAttr is shared across all controls that are derived from wxTextCtrl and | |
212 | can store basic character and paragraph attributes. wxTextAttrEx derives | |
213 | from wxTextAttr and adds some further attributes that are only supported | |
214 | by wxRichTextCtrl. Finally, wxRichTextAttr is a more efficient version | |
215 | of wxTextAttrEx that doesn't use a wxFont object and can be used to | |
216 | query styles more quickly. wxTextAttrEx and wxRichTextAttr are largely | |
217 | interchangeable and have suitable conversion operators between them. | |
218 | ||
219 | When setting a style, the flags of the attribute object determine which | |
220 | attributes are applied. When querying a style, the passed flags are ignored | |
221 | except (optionally) to determine whether attributes should be retrieved from | |
222 | character content or from the paragraph object. | |
223 | ||
224 | wxRichTextCtrl takes a layered approach to styles, so that different parts of | |
225 | the content may be responsible for contributing different attributes to the final | |
226 | style you see on the screen. | |
227 | ||
228 | There are four main notions of style within a control: | |
229 | ||
230 | \begin{enumerate}\itemsep=0pt | |
231 | \item {\bf Basic style:} the fundamental style of a control, onto which any other | |
232 | styles are layered. It provides default attributes, and changing the basic style | |
233 | may immediately change the look of the content depending on what other styles | |
234 | the content uses. Calling wxRichTextCtrl::SetFont changes the font for the basic style. | |
235 | The basic style is set with \helpref{wxRichTextCtrl::SetBasicStyle}{wxrichtextctrlsetbasicstyle}. | |
236 | \item {\bf Paragraph style:} each paragraph has attributes that are set independently | |
237 | from other paragraphs and independently from the content within the paragraph. | |
238 | Normally, these attributes are paragraph-related, such as alignment and indentation, | |
239 | but it is possible to set character attributes too. | |
240 | The paragraph style can be set independently of its content by passing wxRICHTEXT\_SETSTYLE\_PARAGRAPHS\_ONLY | |
241 | to \helpref{wxRichTextCtrl::SetStyleEx}{wxrichtextctrlsetstyleex}. | |
242 | \item {\bf Character style:} characters within each paragraph can have attributes. | |
243 | A single character, or a run of characters, can have a particular set of attributes. | |
244 | The character style can be with \helpref{wxRichTextCtrl::SetStyle}{wxrichtextctrlsetstyle} or | |
245 | \helpref{wxRichTextCtrl::SetStyleEx}{wxrichtextctrlsetstyleex}. | |
246 | \item {\bf Default style:} this is the `current' style that determines the | |
247 | style of content that is subsequently typed, pasted or programmatically inserted. | |
248 | The default style is set with \helpref{wxRichTextCtrl::SetDefaultStyle}{wxrichtextctrlsetdefaultstyle}. | |
249 | \end{enumerate} | |
250 | ||
251 | What you see on the screen is the dynamically {\it combined} style, found by merging | |
252 | the first three of the above style types (the fourth is only a guide for future content | |
253 | insertion and therefore does not affect the currently displayed content). | |
254 | ||
255 | To make all this more concrete, here are examples of where you might set these different | |
256 | styles: | |
257 | ||
258 | \begin{enumerate}\itemsep=0pt | |
259 | \item You might set the {\bf basic style} to have a Times Roman font in 12 point, | |
260 | left-aligned, with two millimetres of spacing after each paragraph. | |
261 | \item You might set the {\bf paragraph style} (for one particular paragraph) to | |
262 | be centred. | |
263 | \item You might set the {\bf character style} of one particular word to bold. | |
264 | \item You might set the {\bf default style} to be underlined, for subsequent | |
265 | inserted text. | |
266 | \end{enumerate} | |
267 | ||
268 | Naturally you can do any of these things either using your own UI, or programmatically. | |
269 | ||
270 | The basic wxTextCtrl doesn't make the same distinctions as wxRichTextCtrl regarding | |
271 | attribute storage. So we need finer control when setting and retrieving | |
272 | attributes. \helpref{wxRichTextCtrl::SetStyleEx}{wxrichtextctrlsetstyleex} takes a {\it flags} parameter: | |
273 | ||
274 | \begin{itemize}\itemsep=0pt | |
275 | \item wxRICHTEXT\_SETSTYLE\_OPTIMIZE specifies that the style should be changed only if | |
276 | the combined attributes are different from the attributes for the current object. This is important when | |
277 | applying styling that has been edited by the user, because he has just edited the {\it combined} (visible) | |
278 | style, and wxRichTextCtrl wants to leave unchanged attributes associated with their original objects | |
279 | instead of applying them to both paragraph and content objects. | |
280 | \item wxRICHTEXT\_SETSTYLE\_PARAGRAPHS\_ONLY specifies that only paragraph objects within the given range | |
281 | should take on the attributes. | |
282 | \item wxRICHTEXT\_SETSTYLE\_CHARACTERS\_ONLY specifies that only content objects (text or images) within the given range | |
283 | should take on the attributes. | |
284 | \item wxRICHTEXT\_SETSTYLE\_WITH\_UNDO specifies that the operation should be undoable. | |
285 | \end{itemize} | |
27b12131 | 286 | |
4f88b483 JS |
287 | It's great to be able to change arbitrary attributes in a wxRichTextCtrl, but |
288 | it can be unwieldy for the user or programmer to set attributes separately. Word processors have collections | |
289 | of styles that you can tailor or use as-is, and this means that you can set a heading with one click | |
290 | instead of marking text in bold, specifying a large font size, and applying a certain | |
291 | paragraph spacing and alignment for every such heading. Similarly, | |
292 | wxWidgets provides a class called \helpref{wxRichTextStyleSheet}{wxrichtextstylesheet} which manages style definitions | |
d2d0adc7 | 293 | (\helpref{wxRichTextParagraphStyleDefinition}{wxrichtextparagraphstyledefinition}, \helpref{wxRichTextListStyleDefinition}{wxrichtextliststyledefinition} and \helpref{wxRichTextCharacterStyleDefinition}{wxrichtextcharacterstyledefinition}). |
4f88b483 JS |
294 | Once you have added definitions to a style sheet and associated it with a wxRichTextCtrl, |
295 | you can apply a named definition to a range of text. The classes \helpref{wxRichTextStyleComboCtrl}{wxrichtextstylecomboctrl}\rtfsp | |
296 | and \helpref{wxRichTextStyleListBox}{wxrichtextstylelistbox} can be used to present the user with a list | |
297 | of styles in a sheet, and apply them to the selected text. | |
298 | ||
299 | You can reapply a style sheet to the contents of the control, by calling \helpref{wxRichTextCtrl::ApplyStyleSheet}{wxrichtextctrlapplystylesheet}. | |
300 | This is useful if the style definitions have changed, and you want the content to reflect this. | |
301 | It relies on the fact that when you apply a named style, the style definition name is recorded in the | |
302 | content. So ApplyStyleSheet works by finding the paragraph attributes with style names and re-applying the definition's | |
d2d0adc7 | 303 | attributes to the paragraph. Currently, this works with paragraph and list style definitions only. |
4f88b483 JS |
304 | |
305 | \subsection{wxRichTextCtrl dialogs}\label{wxrichtextctrldialogs} | |
306 | ||
307 | wxRichTextCtrl comes with standard dialogs to make it easier to implement | |
308 | text editing functionality. | |
309 | ||
310 | \helpref{wxRichTextFormattingDialog}{wxrichtextformattingdialog} can be used | |
311 | for character or paragraph formatting, or a combination of both. It's a wxPropertySheetDialog | |
312 | with the following available tabs: Font, Indents \& Spacing, Tabs, Bullets, and Style. | |
313 | You can select which pages will be shown by supplying flags to the dialog constructor. | |
314 | In a character formatting dialog, typically only the Font page will be shown. | |
315 | In a paragraph formatting dialog, you'll show the Indents \& Spacing, Tabs and Bullets | |
316 | pages. The Style tab is useful when editing a style definition. | |
317 | ||
318 | You can customize this dialog by providing your own wxRichTextFormattingDialogFactory | |
319 | object, which tells the formatting dialog how many pages are supported, what their identifiers | |
320 | are, and how to creates the pages. | |
321 | ||
322 | \helpref{wxSymbolPickerDialog}{wxsymbolpickerdialog} lets the user insert a symbol from | |
323 | a specified font. It has no wxRichTextCtrl dependencies besides being included in | |
324 | the rich text library. | |
27b12131 JS |
325 | |
326 | \subsection{How wxRichTextCtrl is implemented} | |
327 | ||
328 | Data representation is handled by wxRichTextBuffer, and a wxRichTextCtrl | |
329 | always has one such buffer. | |
330 | ||
331 | The content is represented by a hierarchy of objects, all derived from | |
332 | wxRichTextObject. An object might be an image, a fragment of text, a paragraph, | |
333 | or a whole buffer. Objects store a wxRichTextAttr containing style information; | |
334 | although it contains both paragraph formatting and character style, the | |
335 | paragraph style information is ignored by children of a paragraph (only | |
336 | character style is relevant to these objects). | |
337 | ||
338 | The top of the hierarchy is the buffer, a kind of wxRichTextParagraphLayoutBox. | |
4f88b483 JS |
339 | containing further wxRichTextParagraph objects, each of which can include text, |
340 | images and potentially other types of object. | |
27b12131 JS |
341 | |
342 | Each object maintains a range (start and end position) measured | |
343 | from the start of the main parent box. | |
344 | ||
345 | When Layout is called on an object, it is given a size which the object | |
346 | must limit itself to, or one or more flexible directions (vertical | |
62a268cc | 347 | or horizontal). So, for example, a centred paragraph is given the page |
27b12131 JS |
348 | width to play with (minus any margins), but can extend indefinitely |
349 | in the vertical direction. The implementation of Layout caches the calculated | |
350 | size and position. | |
351 | ||
352 | When the buffer is modified, a range is invalidated (marked as requiring | |
353 | layout), so that only the minimum amount of layout is performed. | |
354 | ||
355 | A paragraph of pure text with the same style contains just one further | |
356 | object, a wxRichTextPlainText object. When styling is applied to part of | |
357 | this object, the object is decomposed into separate objects, one object | |
358 | for each different character style. So each object within a paragraph always has | |
359 | just one wxRichTextAttr object to denote its character style. Of course, this can | |
360 | lead to fragmentation after a lot of edit operations, potentially leading | |
361 | to several objects with the same style where just one would do. So | |
362 | a Defragment function is called when updating the control's display, to ensure that | |
363 | the minimum number of objects is used. | |
364 | ||
27b12131 JS |
365 | \subsection{wxRichTextCtrl roadmap} |
366 | ||
367 | \wxheading{Bugs} | |
368 | ||
369 | This is an incomplete list of bugs. | |
370 | ||
4f88b483 | 371 | \begin{itemize}\itemsep=0pt |
27b12131 JS |
372 | \item Moving the caret up at the beginning of a line sometimes incorrectly positions the |
373 | caret. | |
4f88b483 JS |
374 | \item As the selection is expanded, the text jumps slightly due to kerning differences between |
375 | drawing a single text string versus drawing several fragments separately. This could | |
376 | be improved by using wxDC::GetPartialTextExtents to calculate exactly where the separate fragments | |
4aeaf419 | 377 | should be drawn. Note that this problem also applies to separation of text fragments due to difference in their attributes. |
27b12131 JS |
378 | \end{itemize} |
379 | ||
380 | \wxheading{Features} | |
5f35b46a | 381 | |
27b12131 | 382 | This is a list of some of the features that have yet to be implemented. Help with them will be appreciated. |
5f35b46a | 383 | |
4f88b483 | 384 | \begin{itemize}\itemsep=0pt |
27b12131 | 385 | \item RTF input and output |
4aeaf419 JS |
386 | \item Conversion from HTML |
387 | \item Open Office input and output | |
27b12131 JS |
388 | \item Floating images, with content wrapping around them |
389 | \item A ruler control | |
390 | \item Standard editing toolbars | |
27b12131 | 391 | \item Tables |
96202eaa JS |
392 | \item Bitmap bullets |
393 | \item Borders | |
27b12131 | 394 | \item Text frames |
4aeaf419 | 395 | \item Justified text, in print/preview at least |
27b12131 | 396 | \end{itemize} |
5f35b46a | 397 | |
27b12131 JS |
398 | There are also things that could be done to take advantage of the underlying text capabilities of the platform; |
399 | higher-level text formatting APIs are available on some platforms, such as Mac OS X, and some of translation from | |
400 | high level to low level wxDC API is unnecessary. However this would require additions to the wxWidgets API. | |
62a268cc | 401 |