1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#include "clMarkdownRenderer.hpp"
#include "ColoursAndFontsManager.h"
#include "clSystemSettings.h"
#include "drawingutils.h"
#include "file_logger.h"
#include "mdparser.hpp"
#include "wx/settings.h"
namespace
{
struct DCFontLocker {
wxDC& m_dc;
wxFont m_old_font;
DCFontLocker(wxDC& dc)
: m_dc(dc)
, m_old_font(dc.GetFont())
{
}
~DCFontLocker() { m_dc.SetFont(m_old_font); }
};
} // namespace
void clMarkdownRenderer::UpdateFont(wxDC& dc, const mdparser::Style& style)
{
// we always use code font, so we dont change it
wxFont f = dc.GetFont();
double point_size = f.GetPointSize();
switch(style.font_size) {
case mdparser::Style::FONTSIZE_H1:
point_size += 4; // it will receive a different colour
break;
case mdparser::Style::FONTSIZE_H2:
point_size += 4;
break;
case mdparser::Style::FONTSIZE_H3:
point_size += 2;
break;
default:
break;
}
f.SetPointSize(point_size);
f.SetWeight(style.font_weight == mdparser::Style::FONTWEIGHT_BOLD ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL);
f.SetStyle(style.font_style == mdparser::Style::FONTSTYLE_ITALIC ? wxFONTSTYLE_ITALIC : wxFONTSTYLE_NORMAL);
f.SetStrikethrough(style.font_strikethrough);
dc.SetFont(f);
}
clMarkdownRenderer::clMarkdownRenderer() {}
clMarkdownRenderer::~clMarkdownRenderer() {}
wxSize clMarkdownRenderer::Render(wxWindow* win, wxDC& dc, const wxString& text, const wxRect& rect)
{
return DoRender(win, dc, text, rect, true);
}
wxSize clMarkdownRenderer::DoRender(wxWindow* win, wxDC& dc, const wxString& text, const wxRect& rect, bool do_draw)
{
wxUnusedVar(win);
constexpr int X_MARGIN = 5;
constexpr int Y_MARGIN = 5;
int xx = rect.GetTopLeft().x + X_MARGIN;
int yy = rect.GetTopLeft().y + Y_MARGIN;
wxFont default_font = ColoursAndFontsManager::Get().GetFixedFont(true);
dc.SetFont(default_font);
// clear the area
wxColour pen_colour = clSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW);
wxColour bg_colour = clSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
bool is_dark = DrawingUtils::IsDark(bg_colour); //.GetLuminance() < 128;
if(do_draw) {
wxRect bgRect = rect;
#ifdef __WXMAC__
bgRect.Inflate(1);
#endif
dc.SetPen(pen_colour);
dc.SetBrush(bg_colour);
dc.DrawRectangle(bgRect);
}
int height = X_MARGIN;
int width = Y_MARGIN;
int line_height = wxNOT_FOUND;
auto on_write = [&](const wxString& buffer, const mdparser::Style& style, bool is_eol) {
DCFontLocker font_locker(dc);
if(style.is_horizontal_rule()) {
wxSize text_size = dc.GetTextExtent("Tp");
yy += text_size.GetHeight() / 2;
if(do_draw) {
dc.DrawLine(xx, yy, rect.GetRight() - X_MARGIN, yy);
}
xx = X_MARGIN;
yy += text_size.GetHeight() / 2;
height += text_size.GetHeight();
} else {
UpdateFont(dc, style);
wxSize text_size = dc.GetTextExtent(buffer);
// even if text is empty, we still need to have a valid line height
// so use a dummy "Tp" text for this purpose
line_height = dc.GetTextExtent("Tp").GetHeight();
wxColour code_bg_colour = bg_colour.ChangeLightness(is_dark ? 110 : 150);
wxColour text_colour = clSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
if(style.is_code()) {
text_colour = is_dark ? wxColour("#cc99ff") : wxColour("#cc0000");
} else if(style.has_flag(mdparser::T_H1)) {
text_colour = is_dark ? wxColour("#ff9999") : wxColour("#3399cc");
}
if(do_draw) {
if(style.is_code()) {
wxRect code_rect = wxRect({ xx, yy }, text_size);
dc.SetPen(code_bg_colour);
dc.SetBrush(code_bg_colour);
dc.DrawRoundedRectangle(code_rect, 1.0);
} else if(style.is_codeblock()) {
// colour the entire row
wxRect code_rect = wxRect(0, yy, rect.GetWidth(), line_height);
code_rect.Deflate(1, 0);
dc.SetPen(code_bg_colour);
dc.SetBrush(code_bg_colour);
dc.DrawRectangle(code_rect);
}
dc.SetTextForeground(text_colour);
dc.DrawText(buffer, xx, yy);
}
xx += text_size.GetWidth();
if(is_eol) {
width = wxMax(xx, width);
xx = X_MARGIN;
yy += line_height;
height = yy;
}
}
};
mdparser::Parser parser;
parser.parse(text, on_write);
width = wxMax(width, xx);
height += line_height;
return { width, height };
}
wxSize clMarkdownRenderer::GetSize(wxWindow* win, wxDC& dc, const wxString& text)
{
return DoRender(win, dc, text, {}, false);
}
|