File: clMarkdownRenderer.cpp

package info (click to toggle)
codelite 17.0.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 136,204 kB
  • sloc: cpp: 491,547; ansic: 280,393; php: 10,259; sh: 8,930; lisp: 7,664; vhdl: 6,518; python: 6,020; lex: 4,920; yacc: 3,123; perl: 2,385; javascript: 1,715; cs: 1,193; xml: 1,110; makefile: 804; cobol: 741; sql: 709; ruby: 620; f90: 566; ada: 534; asm: 464; fortran: 350; objc: 289; tcl: 258; java: 157; erlang: 61; pascal: 51; ml: 49; awk: 44; haskell: 36
file content (160 lines) | stat: -rw-r--r-- 5,072 bytes parent folder | download | duplicates (2)
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);
}