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