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