|
wxMaxima
|
Character formatting (bold, italic, superscript, ...) of the text in a text cell (GH #492). More...
#include <cstdint>#include <cstddef>#include <vector>#include <wx/string.h>Go to the source code of this file.
Data Structures | |
| struct | TextFormat::Run |
| A stretch of text whose characters all have the same format. More... | |
Enumerations | |
| enum | : Format { None = 0 , Bold = 1 , Italic = 2 , Underline = 4 , Strikethrough = 8 , TextFormat::Superscript = 16 , TextFormat::Subscript = 32 } |
Functions | |
| constexpr std::size_t | TextFormat::FontIndex (Format format) |
| A number below FontVariants that tells the fonts the WidthAffecting flags ask for apart. | |
| constexpr Format | TextFormat::WithFlag (Format format, Format flag) |
| The format that results from switching flag on in format. | |
| bool | TextFormat::IsPlain (const Formats &formats) |
| Does this formatting vector describe plain text? | |
| Format | TextFormat::At (const Formats &formats, std::size_t pos) |
| The format of character pos, None past the end (or for plain text). | |
| Format | TextFormat::FormatForInsertionAt (const wxString &text, const Formats &formats, std::size_t pos) |
| The format a character typed at pos gets. | |
| Formats | TextFormat::Reconcile (const wxString &oldText, const Formats &oldFormats, const wxString &newText, bool hasPending=false, std::size_t pendingPos=0, Format pendingFormat=None) |
| The formatting of newText, given that it came from oldText by editing. | |
| std::vector< Run > | TextFormat::Runs (const wxString &text, const Formats &formats, std::size_t start, std::size_t end) |
| Splits [start, end) of text into runs of equally formatted characters. | |
| wxString | TextFormat::LineAttributes (const wxString &text, const Formats &formats, std::size_t lineStart, std::size_t lineEnd) |
| The attributes that store the formatting of [lineStart, lineEnd) of text. | |
| void | TextFormat::ReadLine (const wxXmlNode *line, wxString &text, Formats &formats, wxString *unknownAttributes=nullptr) |
Append the text and formatting of a <line> element. | |
| void | TextFormat::ReadHTML (const wxString &html, wxString &text, Formats &formats) |
| The text and formatting of an HTML fragment other programs put on the clipboard. | |
| std::vector< std::pair< std::size_t, std::size_t > > | TextFormat::ParseRanges (const wxString &ranges) |
| Parse a range list like "0-4,10-12" (half-open, in code points). | |
| std::size_t | TextFormat::CodePointsBefore (const wxString &text, std::size_t start, std::size_t index) |
| How many Unicode code points text[0, index) holds - which differs from index where wxString stores UTF-16 (MS Windows) and the text contains a character outside the Basic Multilingual Plane. | |
| std::size_t | TextFormat::IndexOfCodePoint (const wxString &text, std::size_t start, std::size_t codePoints) |
| The wxString index of the codePoints'th code point after start. | |
Variables | |
| constexpr Format | TextFormat::WidthAffecting = Bold | Italic | Superscript | Subscript |
| The flags that change a character's width, and therefore the font it is measured and drawn with. Underline and strikethrough are lines drawn on top. | |
| constexpr std::size_t | TextFormat::FontVariants = 16 |
| How many different fonts the WidthAffecting flags can ask for. | |
| constexpr Format | TextFormat::VerticalPosition = Superscript | Subscript |
| The flags that move a character up or down. A character is never both. | |
Character formatting (bold, italic, superscript, ...) of the text in a text cell (GH #492).
Everything here is a pure function of strings and vectors, needing neither a cell nor a GUI, so that it can be tested on its own.
The model: one Format per character of the cell's text, stored in a vector indexed exactly like the wxString it describes. An empty vector means "no formatting at all", which is what every cell that never had any carries, so plain cells pay nothing.
How it is saved: .wxmx stores a text cell as one <line> element per line. Formatting goes into attributes of those elements, one per format, each a list of half-open ranges counted in Unicode code points from the start of the line:
<line bold="0-4,10-12" italic="6-9">Bold, italic and bold</line>
This is not a pretty format, but it is the one older wxMaxima versions can read: they take the element's text and never look at its attributes, so they show the text unformatted instead of losing any of it. Inline tags (<b>, <i>, ...) would have been nicer, but an older version reading <line>a <b>b</b> c</line> keeps only the "a ".
ReadLine() nevertheless understands such inline tags too, so a future version can switch to them: <b>/ <strong>,<i>/ <em>,<u>, <s>/ <strike>/ <del>,<sup> and<sub> set the matching format, and any other tag is read as if it weren't there - its text is kept, only the formatting it stands for is lost.
| anonymous enum : Format |
| Format TextFormat::FormatForInsertionAt | ( | const wxString & | text, |
| const Formats & | formats, | ||
| std::size_t | pos | ||
| ) |
The format a character typed at pos gets.
The one of the character before it, as in any word processor (typing at the end of a bold word continues it in bold) - unless there is none on the same line, in which case the character after it decides.
| wxString TextFormat::LineAttributes | ( | const wxString & | text, |
| const Formats & | formats, | ||
| std::size_t | lineStart, | ||
| std::size_t | lineEnd | ||
| ) |
The attributes that store the formatting of [lineStart, lineEnd) of text.
bold="0-4" italic="2-3" (with a leading space), or an empty one if that line is plain. | std::vector< std::pair< std::size_t, std::size_t > > TextFormat::ParseRanges | ( | const wxString & | ranges | ) |
Parse a range list like "0-4,10-12" (half-open, in code points).
Malformed entries are skipped. Exposed for the tests.
| void TextFormat::ReadHTML | ( | const wxString & | html, |
| wxString & | text, | ||
| Formats & | formats | ||
| ) |
The text and formatting of an HTML fragment other programs put on the clipboard.
Lenient, as clipboard HTML is rarely well-formed XML: unclosed <br>, <meta> or <p>, entities like , a Windows CF_HTML header. Reads what is inside <body>, or else between the <!--StartFragment–> and <!--EndFragment–> markers, if there are any. Understands the elements FlagForTag() knows and the CSS a <span> or any other element carries in its style attribute (font-weight, font-style, text-decoration, vertical-align), which is how Google Docs and Word mark their formatting - including switching a format off again, as Google Docs wraps a whole copy in <b style="font-weight:normal">. Whitespace collapses as a browser collapses it; <br> and the end of a paragraph, heading, list item, table row or <div> make a line break; <script>, <style> and <head> are skipped.
| formats | Receives one format per character of text. |
| void TextFormat::ReadLine | ( | const wxXmlNode * | line, |
| wxString & | text, | ||
| Formats & | formats, | ||
| wxString * | unknownAttributes = nullptr |
||
| ) |
Append the text and formatting of a <line> element.
| line | The <line> element. |
| text | The line's text is appended to it. |
| formats | Receives one format per appended character. Resized to match text first, so it may be passed empty. |
| unknownAttributes | If not null, receives every attribute of line this version doesn't understand, serialized as name="value", so a newer version's formatting survives being opened and saved by this one. |
| Formats TextFormat::Reconcile | ( | const wxString & | oldText, |
| const Formats & | oldFormats, | ||
| const wxString & | newText, | ||
| bool | hasPending = false, |
||
| std::size_t | pendingPos = 0, |
||
| Format | pendingFormat = None |
||
| ) |
The formatting of newText, given that it came from oldText by editing.
Finds which characters of newText already existed in oldText and lets them keep their format; characters that are new take the format of the character(s) they replaced, or else of the one before them (as in any word processor, typing at the end of a bold word continues it in bold).
One contiguous edit - typing, deleting, pasting, replacing a selection - is mapped exactly via the common prefix and suffix. Several separate edits at once (a "replace all", indenting several lines) are mapped by a longest-common-subsequence diff of the part that changed, which is bounded in size; past that bound the changed part keeps its formats by position.
| pendingPos,pendingFormat | If hasPending and the edit was a pure insertion at pendingPos, the inserted characters get pendingFormat: that is what pressing "bold" with nothing selected and then typing does. |
| std::vector< Run > TextFormat::Runs | ( | const wxString & | text, |
| const Formats & | formats, | ||
| std::size_t | start, | ||
| std::size_t | end | ||
| ) |
Splits [start, end) of text into runs of equally formatted characters.
For the formats of other programs (RTF, HTML), which switch formatting on and off around runs of text rather than storing one format per character. A hard line break ('
') is always a run of its own and never formatted, so a run never spans two paragraphs: RTF and HTML both end a paragraph in a way that doesn't nest in a formatting group.