NOTE : This is not a general purpose HTML/CSS renderer, only the specified tags/properties below are targeted
Implementation of Rich Text Rendering for ImGui (ASCII text only) akin to Qt support for it. Use it as follows:
// Do not cache anything
std::string rtf = "<blink>This is blinking</blink>"
"<marquee>This is moving...</marquee>"
"<meter value='3' max='10'></meter>"
"<s><q>Quotation </q><cite>Citation</cite></s>"
"<br>Powered by: <a href='https://https://github.com/ajax-crypto/ImRichText'>ImRichText</a>"
"<ul style='font-size: 36px;'><li>item</li><li>item</li></ul>";
// Create rich text with cacehable drawables
auto id = ImRichText::CreateRichText("2<sup>2</sup> equals 4 <hr style=\"height: 4px; color: sienna;\"/>"
"<p style=\"color: rgb(150, 0, 0);\">Paragraph <b>bold <i>italics</i> bold2 </b></p>"
"<h1 style=\"color: darkblue;\">Heading	</h1>"
"<span style='background: teal; color: white;'>White on Teal</span><br/>"
"<mark>This is highlighted! <small>This is small...</small></mark>");
auto config = ImRichText::GetDefaultConfig({ -1.f, -1.f }, 24.f, 1.5f);
config->Scale = 2.f;
config->ListItemBullet = ImRichText::BulletType::Arrow;
ImRichText::PushConfig(*config);
while (<event-loop>)
{
if (ImGui::Begin(...))
{
// ... other widgets
ImRichText::GetCurrentConfig()->DefaultBgColor = ImColor{ 255, 255, 255 };
ImRichText::Show(rtf.data(), rtf.data() + rtf.size());
ImRichText::GetCurrentConfig()->DefaultBgColor = ImColor{ 200, 200, 200 };
ImRichText::Show(id);
// ... other widgets
}
}
Just include the .h and .cpp files in your project. (You will need a C++17 compiler)
The following subset of HTML tags/CSS properties are supported:
Tags | Description | Implementation Status |
---|---|---|
span | A region of text with certain style properties | Yes |
p | Start a paragraph in new line (paragraph indent can be specified in RenderConfig::ParagraphStop ) |
Yes |
font | Specify size, family, weight, style for a block of text | Yes |
sup/sub | Superscript/Subscript | Yes1 |
hr | Horizontal line | Yes |
h1...h6 | Header (bold) text with a line underneath | Yes |
ul | Un-numbered list (with bullets) | Yes |
ol | Numbered list (with nested numberings i.e. 1.2.3) | Yes |
li | List Item | Yes |
br | Line Break | Yes |
b/strong | Bold block of text | Yes |
i/em/cite | Italics block of text | Yes |
mark | Highlight current block of text | Yes |
small | Reduce font size to 80% of current block | Yes |
q | Wrap text inside quotation mark | Yes |
u | Underline current block of text | Yes2 |
a | Make current block of text a hyperlink (handle click events) | Yes3 |
abbr | Mark current block as an abbreviation, title attribute contains tooltip |
Yes |
s/del | Draw a horizontal line through the text content | Yes |
blink | Make current block of text blink | Yes |
marquee | Make current block of text scroll horizontally | Yes |
meter | Create a progress bar inline | Yes |
blockquote | Blockquote as in HTML | Under progress |
pre | Preformatted text with monospaced font | Under progress |
code | Use monospace font for this block of text | Under progress |
Property Name(s) | Value/Example |
---|---|
background/background-color/color | rgb(r, g, b) /rgba(r, g, b, a) /hsl(h, s, l) /linear-gradient(color-stops) 4 CSS color name |
padding/padding-top/etc. | px /em units |
font-size | pt /px /em (absolute) / % (of parent font size) / xx-small , x-small , medium , large , etc. |
font-family | name of font family |
font-weight | value between 0-800 or light /normal /bold |
font-style | italics/oblique |
height/width | px /em |
list-style-type | (Only for list items) circle /disk /square /custom 5 |
border/border-top/etc. | 2px solid gray 6 |
border-radius | px /em |
text-overflow | Under progress |
In order to handle rich text as specified above, fonts need to be managed i.e. different family, weights, sizes, etc.
The library internally uses default fonts (for Windows Segoe UI family for proportional and Consolas for monospace).
However, user can provide their own font provider through RenderConfig::GetFont
function pointer.
- Word wrapping support
- Maybe add
<center>
and<font>
tags? (These are deprecated in HTML5) - Add support for
margin
- Add support for line style (solid, dotted, dashed) for
border
- Implement support for vertical/horizontal text alignment including baseline alignment (May need to use FreeType backend)
- Integration example with Clay layout library
- Roman numerals for numbered lists
- Radial gradient fills for backgrounds
- Tables (
<table>
,<tr>
,<th>
,<td>
tags)
- Use a library (roll your own?) to lookup font(s) based on requirements i.e. fuzzy match on family, etc.
- Internationalization support by integrating Harfbuzz (Unicode Bidir algo)
- Add ways to remove C++ standard library dependencies
- Text effects like "glow", "shadow", etc.
- Build scripts like cmake, build2, make, etc. This library is intended to be used by simply copying the .h/.cpp files.
- Full-fledged support for CSS3 styling with layout
- Support alternate syntax i.e. Markdown, Restructured Text, MathML, etc.
The library depends on ImGui and C++17 standard library. It can be compiled using any C++17 compiler.
In order to customize certain behavior at build-time, the following macros can be used
Macro name | Functionality | Default Value |
---|---|---|
IM_RICHTEXT_MAXDEPTH |
Maximum depth of nested blocks/tags in Rich Text | 32 |
IM_RICHTEXT_MAX_LISTDEPTH |
Maximum depth of nested lists | 16 |
IM_RICHTEXT_MAX_LISTITEM |
Maxmimum number of list items at a specific depth | 128 |
IM_RICHTEXT_MAXTABSTOP |
Maxmimum number of nested <p> /paragraphs |
32 |
IM_RICHTEXT_ENABLE_PARSER_LOGS |
Enable printing parsing + layout logs in console in debug builds | Not defined |
IM_RICHTEXT_BLINK_ANIMATION_INTERVAL |
Specify blink animation interval | 500ms |
IM_RICHTEXT_MARQUEE_ANIMATION_INTERVAL |
Specify interval (1/FPS ) for marquee animation |
18ms |
IM_RICHTEXT_MAX_COLORSTOPS |
Specify maximum color stops in gradients | 8 |
When _DEBUG
macro is defined, if a console is present, error messages will be printed along
with the parsing state i.e. entering/exiting tags. Custom properties or unknonw tags are ignored, but reported.
Since it is work in progress, no contributions are accepted at the moment. Once I stabilize and create a release, contributions will be accepted! In the meantime, feel free to browse the source...
The current implementation intentionally forgoes the creation of any form of AST (Abstract Syntax Tree) or a well-defined phase of tokenization for lexical analysis. In order to keep the codebase simple and not ending up creating a HTML/CSS engine, the scope the arbitrarily cutdown. The algorithm simply breaks down the rich text specified into lines, and each line into segments. Each segment is defined as multiple blocks of text containing the same style i.e. background/foreground/font properties, etc. A "block of text" is simply a run of glyphs without any "space"/"blank" characters in between. Once rich text is broken down to lines, it is rendered in two phases i.e. first the background is drawn i.e. blockquote background can span multiple lines. After that, the foreground i.e. text is drawn (with background/foreground colors).
Footnotes
-
Nested subscript/superscript is untested at the moment ↩
-
Underline text due to
<u>
tag is not baseline-underlined, but underlined beneath the whole text ↩ -
Set
RenderConfig::HandleHyperlink
function pointer to handle hyperlinks clicked ↩ -
Only axis aligned gradients are support as
background
property ↩ -
Custom bullets are also possible, set
RenderConfig::DrawBullet
function pointer andlist-style-type
property tocustom
↩ -
Border line type is parsed but not used for rendering ↩