399 lines
18 KiB
C
399 lines
18 KiB
C
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Name: richtextctrl
|
||
|
// Purpose: topic overview
|
||
|
// Author: wxWidgets team
|
||
|
// RCS-ID: $Id$
|
||
|
// Licence: wxWindows license
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
/*!
|
||
|
|
||
|
@page richtextctrl_overview wxRichTextCtrl overview
|
||
|
|
||
|
@b Major classes: #wxRichTextCtrl, #wxRichTextBuffer, #wxRichTextEvent
|
||
|
@b Helper classes: #wxTextAttr, #wxRichTextRange
|
||
|
@b File handler classes: #wxRichTextFileHandler, #wxRichTextHTMLHandler,
|
||
|
#wxRichTextXMLHandler
|
||
|
@b Style classes: #wxRichTextCharacterStyleDefinition,
|
||
|
#wxRichTextParagraphStyleDefinition,
|
||
|
#wxRichTextListStyleDefinition,
|
||
|
#wxRichTextStyleSheet
|
||
|
@b Additional controls: #wxRichTextStyleComboCtrl,
|
||
|
#wxRichTextStyleListBox,
|
||
|
#wxRichTextStyleListCtrl
|
||
|
@b Printing classes: #wxRichTextPrinting,
|
||
|
#wxRichTextPrintout,
|
||
|
#wxRichTextHeaderFooterData
|
||
|
@b Dialog classes: #wxRichTextStyleOrganiserDialog,
|
||
|
#wxRichTextFormattingDialog,
|
||
|
#wxSymbolPickerDialog
|
||
|
wxRichTextCtrl provides a generic implementation of a rich text editor that can handle different character
|
||
|
styles, paragraph formatting, and images. It's aimed at editing 'natural' language text - if you need an editor
|
||
|
that supports code editing, wxStyledTextCtrl is a better choice.
|
||
|
Despite its name, it cannot currently read or write RTF (rich text format) files. Instead, it
|
||
|
uses its own XML format, and can also read and write plain text. In future we expect to provide
|
||
|
RTF file capabilities. Custom file formats can be supported by creating additional
|
||
|
file handlers and registering them with the control.
|
||
|
wxRichTextCtrl is largely compatible with the wxTextCtrl API, but extends it where necessary.
|
||
|
The control can be used where the native rich text capabilities of wxTextCtrl are not
|
||
|
adequate (this is particularly @true on Windows) and where more direct access to
|
||
|
the content representation is required. It is difficult and inefficient to read
|
||
|
the style information in a wxTextCtrl, whereas this information is readily
|
||
|
available in wxRichTextCtrl. Since it's written in pure wxWidgets, any customizations
|
||
|
you make to wxRichTextCtrl will be reflected on all platforms.
|
||
|
wxRichTextCtrl supports basic printing via the easy-to-use #wxRichTextPrinting class.
|
||
|
Creating applications with simple word processing features is simplified with the inclusion of
|
||
|
#wxRichTextFormattingDialog, a tabbed dialog allowing
|
||
|
interactive tailoring of paragraph and character styling. Also provided is the multi-purpose dialog
|
||
|
#wxRichTextStyleOrganiserDialog that can be used for
|
||
|
managing style definitions, browsing styles and applying them, or selecting list styles with
|
||
|
a renumber option.
|
||
|
There are a few disadvantages to using wxRichTextCtrl. It is not native,
|
||
|
so does not behave exactly as a native wxTextCtrl, although common editing conventions
|
||
|
are followed. Users may miss the built-in spelling correction on Mac OS X, or any
|
||
|
special character input that may be provided by the native control. It would also
|
||
|
be a poor choice if intended users rely on screen readers that would be not work well
|
||
|
with non-native text input implementation. You might mitigate this by providing
|
||
|
the choice between wxTextCtrl and wxRichTextCtrl, with fewer features in the
|
||
|
former case.
|
||
|
A good way to understand wxRichTextCtrl's capabilities is to compile and run the
|
||
|
sample, @c samples/richtext, and browse the code. The following screenshot shows the sample in action:
|
||
|
|
||
|
@b Example
|
||
|
The following code is taken from the sample, and adds text and styles to a rich text control programmatically.
|
||
|
|
||
|
|
||
|
@code
|
||
|
wxRichTextCtrl* richTextCtrl = new wxRichTextCtrl(splitter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxBORDER_NONE|wxWANTS_CHARS);
|
||
|
|
||
|
wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
|
||
|
wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
|
||
|
wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
|
||
|
|
||
|
wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
|
||
|
|
||
|
m_richTextCtrl-SetFont(font);
|
||
|
|
||
|
wxRichTextCtrl& r = richTextCtrl;
|
||
|
|
||
|
r.BeginSuppressUndo();
|
||
|
|
||
|
r.BeginParagraphSpacing(0, 20);
|
||
|
|
||
|
r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
|
||
|
r.BeginBold();
|
||
|
|
||
|
r.BeginFontSize(14);
|
||
|
r.WriteText(wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images"));
|
||
|
r.EndFontSize();
|
||
|
r.Newline();
|
||
|
|
||
|
r.BeginItalic();
|
||
|
r.WriteText(wxT("by Julian Smart"));
|
||
|
r.EndItalic();
|
||
|
|
||
|
r.EndBold();
|
||
|
|
||
|
r.Newline();
|
||
|
r.WriteImage(wxBitmap(zebra_xpm));
|
||
|
|
||
|
r.EndAlignment();
|
||
|
|
||
|
r.Newline();
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("What can you do with this thing? "));
|
||
|
r.WriteImage(wxBitmap(smiley_xpm));
|
||
|
r.WriteText(wxT(" Well, you can change text "));
|
||
|
|
||
|
r.BeginTextColour(wxColour(255, 0, 0));
|
||
|
r.WriteText(wxT("colour, like this red bit."));
|
||
|
r.EndTextColour();
|
||
|
|
||
|
r.BeginTextColour(wxColour(0, 0, 255));
|
||
|
r.WriteText(wxT(" And this blue bit."));
|
||
|
r.EndTextColour();
|
||
|
|
||
|
r.WriteText(wxT(" Naturally you can make things "));
|
||
|
r.BeginBold();
|
||
|
r.WriteText(wxT("bold "));
|
||
|
r.EndBold();
|
||
|
r.BeginItalic();
|
||
|
r.WriteText(wxT("or italic "));
|
||
|
r.EndItalic();
|
||
|
r.BeginUnderline();
|
||
|
r.WriteText(wxT("or underlined."));
|
||
|
r.EndUnderline();
|
||
|
|
||
|
r.BeginFontSize(14);
|
||
|
r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
|
||
|
r.EndFontSize();
|
||
|
|
||
|
r.WriteText(wxT(" Next we'll show an indented paragraph."));
|
||
|
|
||
|
r.BeginLeftIndent(60);
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("Indented paragraph."));
|
||
|
r.EndLeftIndent();
|
||
|
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));
|
||
|
|
||
|
r.BeginLeftIndent(100, -40);
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter."));
|
||
|
r.EndLeftIndent();
|
||
|
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));
|
||
|
|
||
|
r.BeginNumberedBullet(1, 100, 60);
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later."));
|
||
|
r.EndNumberedBullet();
|
||
|
|
||
|
r.BeginNumberedBullet(2, 100, 60);
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("This is my second item."));
|
||
|
r.EndNumberedBullet();
|
||
|
|
||
|
r.Newline();
|
||
|
|
||
|
r.WriteText(wxT("The following paragraph is right-indented:"));
|
||
|
|
||
|
r.BeginRightIndent(200);
|
||
|
r.Newline();
|
||
|
|
||
|
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."));
|
||
|
r.EndRightIndent();
|
||
|
|
||
|
r.Newline();
|
||
|
|
||
|
wxArrayInt tabs;
|
||
|
tabs.Add(400);
|
||
|
tabs.Add(600);
|
||
|
tabs.Add(800);
|
||
|
tabs.Add(1000);
|
||
|
wxTextAttr attr;
|
||
|
attr.SetFlags(wxTEXT_ATTR_TABS);
|
||
|
attr.SetTabs(tabs);
|
||
|
r.SetDefaultStyle(attr);
|
||
|
|
||
|
r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));
|
||
|
|
||
|
r.Newline();
|
||
|
r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));
|
||
|
|
||
|
r.BeginSymbolBullet(wxT('*'), 100, 60);
|
||
|
r.Newline();
|
||
|
r.WriteText(wxT("Compatibility with wxTextCtrl API"));
|
||
|
r.EndSymbolBullet();
|
||
|
|
||
|
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!"));
|
||
|
|
||
|
r.EndSuppressUndo();
|
||
|
@endcode
|
||
|
|
||
|
|
||
|
@ref topic19_overview
|
||
|
@ref richtextctrldialogs_overview
|
||
|
@ref topic22_overview
|
||
|
@ref topic23_overview
|
||
|
|
||
|
|
||
|
@section topic19 Programming with wxRichTextCtrl
|
||
|
|
||
|
|
||
|
@section topic20 Starting to use wxRichTextCtrl
|
||
|
|
||
|
You need to include @c wx/richtext/richtextctrl.h in your source, and link
|
||
|
with the appropriate wxWidgets library with @c richtext suffix. Put the rich text
|
||
|
library first in your link line to avoid unresolved symbols.
|
||
|
Then you can create a wxRichTextCtrl, with the wxWANT_CHARS style if you want tabs to
|
||
|
be processed by the control rather than being used for navigation between controls.
|
||
|
|
||
|
@section topic21 wxRichTextCtrl and styles
|
||
|
|
||
|
Styling attributes are represented by #wxTextAttr.
|
||
|
When setting a style, the flags of the attribute object determine which
|
||
|
attributes are applied. When querying a style, the passed flags are ignored
|
||
|
except (optionally) to determine whether attributes should be retrieved from
|
||
|
character content or from the paragraph object.
|
||
|
wxRichTextCtrl takes a layered approach to styles, so that different parts of
|
||
|
the content may be responsible for contributing different attributes to the final
|
||
|
style you see on the screen.
|
||
|
There are four main notions of style within a control:
|
||
|
|
||
|
|
||
|
@b Basic style: the fundamental style of a control, onto which any other
|
||
|
styles are layered. It provides default attributes, and changing the basic style
|
||
|
may immediately change the look of the content depending on what other styles
|
||
|
the content uses. Calling wxRichTextCtrl::SetFont changes the font for the basic style.
|
||
|
The basic style is set with wxRichTextCtrl::SetBasicStyle.
|
||
|
@b Paragraph style: each paragraph has attributes that are set independently
|
||
|
from other paragraphs and independently from the content within the paragraph.
|
||
|
Normally, these attributes are paragraph-related, such as alignment and indentation,
|
||
|
but it is possible to set character attributes too.
|
||
|
The paragraph style can be set independently of its content by passing wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
|
||
|
to wxRichTextCtrl::SetStyleEx.
|
||
|
@b Character style: characters within each paragraph can have attributes.
|
||
|
A single character, or a run of characters, can have a particular set of attributes.
|
||
|
The character style can be with wxRichTextCtrl::SetStyle or
|
||
|
wxRichTextCtrl::SetStyleEx.
|
||
|
@b Default style: this is the 'current' style that determines the
|
||
|
style of content that is subsequently typed, pasted or programmatically inserted.
|
||
|
The default style is set with wxRichTextCtrl::SetDefaultStyle.
|
||
|
|
||
|
|
||
|
What you see on the screen is the dynamically @e combined style, found by merging
|
||
|
the first three of the above style types (the fourth is only a guide for future content
|
||
|
insertion and therefore does not affect the currently displayed content).
|
||
|
To make all this more concrete, here are examples of where you might set these different
|
||
|
styles:
|
||
|
|
||
|
|
||
|
You might set the @b basic style to have a Times Roman font in 12 point,
|
||
|
left-aligned, with two millimetres of spacing after each paragraph.
|
||
|
You might set the @b paragraph style (for one particular paragraph) to
|
||
|
be centred.
|
||
|
You might set the @b character style of one particular word to bold.
|
||
|
You might set the @b default style to be underlined, for subsequent
|
||
|
inserted text.
|
||
|
|
||
|
|
||
|
Naturally you can do any of these things either using your own UI, or programmatically.
|
||
|
The basic wxTextCtrl doesn't make the same distinctions as wxRichTextCtrl regarding
|
||
|
attribute storage. So we need finer control when setting and retrieving
|
||
|
attributes. wxRichTextCtrl::SetStyleEx takes a @e flags parameter:
|
||
|
|
||
|
|
||
|
wxRICHTEXT_SETSTYLE_OPTIMIZE specifies that the style should be changed only if
|
||
|
the combined attributes are different from the attributes for the current object. This is important when
|
||
|
applying styling that has been edited by the user, because he has just edited the @e combined (visible)
|
||
|
style, and wxRichTextCtrl wants to leave unchanged attributes associated with their original objects
|
||
|
instead of applying them to both paragraph and content objects.
|
||
|
wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY specifies that only paragraph objects within the given range
|
||
|
should take on the attributes.
|
||
|
wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY specifies that only content objects (text or images) within the given range
|
||
|
should take on the attributes.
|
||
|
wxRICHTEXT_SETSTYLE_WITH_UNDO specifies that the operation should be undoable.
|
||
|
|
||
|
|
||
|
It's great to be able to change arbitrary attributes in a wxRichTextCtrl, but
|
||
|
it can be unwieldy for the user or programmer to set attributes separately. Word processors have collections
|
||
|
of styles that you can tailor or use as-is, and this means that you can set a heading with one click
|
||
|
instead of marking text in bold, specifying a large font size, and applying a certain
|
||
|
paragraph spacing and alignment for every such heading. Similarly,
|
||
|
wxWidgets provides a class called #wxRichTextStyleSheet which manages style definitions
|
||
|
(#wxRichTextParagraphStyleDefinition, #wxRichTextListStyleDefinition and #wxRichTextCharacterStyleDefinition).
|
||
|
Once you have added definitions to a style sheet and associated it with a wxRichTextCtrl,
|
||
|
you can apply a named definition to a range of text. The classes #wxRichTextStyleComboCtrl
|
||
|
and #wxRichTextStyleListBox can be used to present the user with a list
|
||
|
of styles in a sheet, and apply them to the selected text.
|
||
|
You can reapply a style sheet to the contents of the control, by calling wxRichTextCtrl::ApplyStyleSheet.
|
||
|
This is useful if the style definitions have changed, and you want the content to reflect this.
|
||
|
It relies on the fact that when you apply a named style, the style definition name is recorded in the
|
||
|
content. So ApplyStyleSheet works by finding the paragraph attributes with style names and re-applying the definition's
|
||
|
attributes to the paragraph. Currently, this works with paragraph and list style definitions only.
|
||
|
|
||
|
@section wxrichtextctrldialogs wxRichTextCtrl dialogs
|
||
|
|
||
|
wxRichTextCtrl comes with standard dialogs to make it easier to implement
|
||
|
text editing functionality.
|
||
|
#wxRichTextFormattingDialog can be used
|
||
|
for character or paragraph formatting, or a combination of both. It's a wxPropertySheetDialog
|
||
|
with the following available tabs: Font, Indents Spacing, Tabs, Bullets, Style, and List Style.
|
||
|
You can select which pages will be shown by supplying flags to the dialog constructor.
|
||
|
In a character formatting dialog, typically only the Font page will be shown.
|
||
|
In a paragraph formatting dialog, you'll show the Indents Spacing, Tabs and Bullets
|
||
|
pages. The Style tab is useful when editing a style definition.
|
||
|
You can customize this dialog by providing your own wxRichTextFormattingDialogFactory
|
||
|
object, which tells the formatting dialog how many pages are supported, what their identifiers
|
||
|
are, and how to creates the pages.
|
||
|
#wxRichTextStyleOrganiserDialog is a multi-purpose dialog
|
||
|
that can be used for managing style definitions, browsing styles and applying them, or selecting list styles with
|
||
|
a renumber option. See the sample for usage - it is used for the "Manage Styles" and "Bullets and Numbering"
|
||
|
menu commands.
|
||
|
#wxSymbolPickerDialog lets the user insert a symbol from
|
||
|
a specified font. It has no wxRichTextCtrl dependencies besides being included in
|
||
|
the rich text library.
|
||
|
|
||
|
@section topic22 How wxRichTextCtrl is implemented
|
||
|
|
||
|
Data representation is handled by wxRichTextBuffer, and a wxRichTextCtrl
|
||
|
always has one such buffer.
|
||
|
The content is represented by a hierarchy of objects, all derived from
|
||
|
wxRichTextObject. An object might be an image, a fragment of text, a paragraph,
|
||
|
or a whole buffer. Objects store a wxTextAttr containing style information;
|
||
|
a paragraph object can contain both paragraph and character information, but
|
||
|
content objects such as text can only store character information. The final
|
||
|
style displayed in the control or in a printout is a combination of base
|
||
|
style, paragraph style and content (character) style.
|
||
|
The top of the hierarchy is the buffer, a kind of wxRichTextParagraphLayoutBox.
|
||
|
containing further wxRichTextParagraph objects, each of which can include text,
|
||
|
images and potentially other types of object.
|
||
|
Each object maintains a range (start and end position) measured
|
||
|
from the start of the main parent object.
|
||
|
When Layout is called on an object, it is given a size which the object
|
||
|
must limit itself to, or one or more flexible directions (vertical
|
||
|
or horizontal). So, for example, a centred paragraph is given the page
|
||
|
width to play with (minus any margins), but can extend indefinitely
|
||
|
in the vertical direction. The implementation of Layout caches the calculated
|
||
|
size and position.
|
||
|
When the buffer is modified, a range is invalidated (marked as requiring
|
||
|
layout), so that only the minimum amount of layout is performed.
|
||
|
A paragraph of pure text with the same style contains just one further
|
||
|
object, a wxRichTextPlainText object. When styling is applied to part of
|
||
|
this object, the object is decomposed into separate objects, one object
|
||
|
for each different character style. So each object within a paragraph always has
|
||
|
just one wxTextAttr object to denote its character style. Of course, this can
|
||
|
lead to fragmentation after a lot of edit operations, potentially leading
|
||
|
to several objects with the same style where just one would do. So
|
||
|
a Defragment function is called when updating the control's display, to ensure that
|
||
|
the minimum number of objects is used.
|
||
|
|
||
|
@section topic23 wxRichTextCtrl roadmap
|
||
|
|
||
|
@b Bugs
|
||
|
This is an incomplete list of bugs.
|
||
|
|
||
|
|
||
|
Moving the caret up at the beginning of a line sometimes incorrectly positions the
|
||
|
caret.
|
||
|
As the selection is expanded, the text jumps slightly due to kerning differences between
|
||
|
drawing a single text string versus drawing several fragments separately. This could
|
||
|
be improved by using wxDC::GetPartialTextExtents to calculate exactly where the separate fragments
|
||
|
should be drawn. Note that this problem also applies to separation of text fragments due to difference in their attributes.
|
||
|
|
||
|
|
||
|
@b Features
|
||
|
This is a list of some of the features that have yet to be implemented. Help with them will be appreciated.
|
||
|
|
||
|
|
||
|
RTF input and output
|
||
|
Conversion from HTML
|
||
|
Open Office input and output
|
||
|
Floating images, with content wrapping around them
|
||
|
A ruler control
|
||
|
Standard editing toolbars
|
||
|
Tables
|
||
|
Bitmap bullets
|
||
|
Borders
|
||
|
Text frames
|
||
|
Justified text, in print/preview at least
|
||
|
|
||
|
|
||
|
There are also things that could be done to take advantage of the underlying text capabilities of the platform;
|
||
|
higher-level text formatting APIs are available on some platforms, such as Mac OS X, and some of translation from
|
||
|
high level to low level wxDC API is unnecessary. However this would require additions to the wxWidgets API.
|
||
|
|
||
|
*/
|
||
|
|
||
|
|