Fully working textview, removing render area files
parent
b93c5bc31f
commit
90b3cbbb48
|
@ -6,7 +6,7 @@ About::About()
|
|||
devs.push_back("Melroy van den Berg <melroy@melroy.org>");
|
||||
logo.set("../../misc/browser_logo_small.png");
|
||||
|
||||
set_name("DBrowser");
|
||||
set_program_name("DWeb Browser");
|
||||
set_version("0.1.0");
|
||||
set_comments("The fastest decentralized & distributed Browser on planet Earth.");
|
||||
set_logo(logo.get_pixbuf());
|
||||
|
@ -15,6 +15,7 @@ About::About()
|
|||
set_authors(devs);
|
||||
set_artists(devs);
|
||||
set_license_type(Gtk::License::LICENSE_MIT_X11);
|
||||
set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
|
||||
|
||||
show_all_children();
|
||||
}
|
||||
|
|
69
src/draw.cc
69
src/draw.cc
|
@ -55,6 +55,10 @@ Draw::Draw()
|
|||
heading3.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading4.set_size(fontSize * PANGO_SCALE_LARGE);
|
||||
heading4.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading5.set_size(fontSize * PANGO_SCALE_MEDIUM);
|
||||
heading5.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading6.set_size(fontSize * PANGO_SCALE_MEDIUM);
|
||||
heading6.set_weight(Pango::WEIGHT_BOLD);
|
||||
}
|
||||
|
||||
void Draw::showMessage(const std::string &message, const std::string &detailed_info)
|
||||
|
@ -124,6 +128,11 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Last list level new line
|
||||
if (listLevel == 1)
|
||||
{
|
||||
addText("\n");
|
||||
}
|
||||
listLevel--;
|
||||
}
|
||||
if (listLevel == 0)
|
||||
|
@ -137,7 +146,8 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
{
|
||||
if (entering)
|
||||
{
|
||||
// TODO: Indent for each list level
|
||||
// Add tab
|
||||
addText(" ");
|
||||
if (listType == cmark_list_type::CMARK_BULLET_LIST)
|
||||
{
|
||||
bulletListLevel++;
|
||||
|
@ -200,24 +210,13 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
|
||||
case CMARK_NODE_THEMATIC_BREAK:
|
||||
{
|
||||
/*
|
||||
TODO: Can we draw a line in textview?
|
||||
line.margin_end_x = 20;
|
||||
line.height = 0.2;
|
||||
line.hex_color = "2e2e2e";
|
||||
line.cap = Cairo::LineCap::LINE_CAP_ROUND;
|
||||
cr->set_line_cap(line.cap);
|
||||
cr->set_source_rgb(r, g, b);
|
||||
cr->set_line_width(line.height);
|
||||
cr->move_to(line.start_x, line.start_y);
|
||||
cr->line_to(endX, line.end_y);
|
||||
cr->stroke();
|
||||
*/
|
||||
addText("\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015");
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
if (listLevel == 0) {
|
||||
if (listLevel == 0)
|
||||
{
|
||||
// Add new line, but not when listing is enabled
|
||||
addText("\n");
|
||||
}
|
||||
|
@ -236,7 +235,7 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
std::string text = cmark_node_get_literal(node);
|
||||
if (bulletListLevel > 0)
|
||||
{
|
||||
text.insert(0, "\u2022 ");
|
||||
text.insert(0, std::string(bulletListLevel, '\u0009') + "\u2022 ");
|
||||
}
|
||||
else if (orderedListLevel > 0)
|
||||
{
|
||||
|
@ -249,7 +248,7 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
{
|
||||
number = std::to_string(orderedListCounters[orderedListLevel]) + ". ";
|
||||
}
|
||||
text.insert(0, number);
|
||||
text.insert(0, std::string(orderedListLevel, '\u0009') + number);
|
||||
}
|
||||
|
||||
if (headingLevel > 0)
|
||||
|
@ -268,8 +267,14 @@ void Draw::processNode(cmark_node *node, cmark_event_type ev_type)
|
|||
case 4:
|
||||
addHeading4(text);
|
||||
break;
|
||||
case 5:
|
||||
addHeading5(text);
|
||||
break;
|
||||
case 6:
|
||||
addHeading6(text);
|
||||
break;
|
||||
default:
|
||||
addHeading4(text); // fallback
|
||||
addHeading5(text); // fallback
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -361,6 +366,16 @@ void Draw::addHeading4(const std::string &text)
|
|||
addMarkupText("\n<span font_desc=\"" + heading4.to_string() + "\">" + text + "</span>\n");
|
||||
}
|
||||
|
||||
void Draw::addHeading5(const std::string &text)
|
||||
{
|
||||
addMarkupText("\n<span font_desc=\"" + heading5.to_string() + "\">" + text + "</span>\n");
|
||||
}
|
||||
|
||||
void Draw::addHeading6(const std::string &text)
|
||||
{
|
||||
addMarkupText("\n<span foreground=\"gray\" font_desc=\"" + heading6.to_string() + "\">" + text + "</span>\n");
|
||||
}
|
||||
|
||||
void Draw::addBold(const std::string &text)
|
||||
{
|
||||
addMarkupText("<span font_desc=\"" + bold.to_string() + "\">" + text + "</span>");
|
||||
|
@ -391,6 +406,9 @@ void Draw::clear()
|
|||
gdk_threads_add_idle((GSourceFunc)clearIdle, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text on Idle Call function
|
||||
*/
|
||||
gboolean Draw::addTextIdle(struct DispatchData *data)
|
||||
{
|
||||
GtkTextIter end_iter;
|
||||
|
@ -400,6 +418,9 @@ gboolean Draw::addTextIdle(struct DispatchData *data)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Text on Idle Call function
|
||||
*/
|
||||
gboolean Draw::clearIdle(GtkTextBuffer *textBuffer)
|
||||
{
|
||||
GtkTextIter start_iter, end_iter;
|
||||
|
@ -427,15 +448,3 @@ std::string const Draw::intToRoman(int num)
|
|||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string to seperate RGB values
|
||||
*/
|
||||
void Draw::hexToRGB(const std::string &hex, double &r, double &g, double &b)
|
||||
{
|
||||
unsigned int intR, intG, intB;
|
||||
sscanf(hex.c_str(), "%02x%02x%02x", &intR, &intG, &intB);
|
||||
r = intR / 255.0;
|
||||
g = intG / 255.0;
|
||||
b = intB / 255.0;
|
||||
}
|
|
@ -23,6 +23,8 @@ private:
|
|||
void addHeading2(const std::string &text);
|
||||
void addHeading3(const std::string &text);
|
||||
void addHeading4(const std::string &text);
|
||||
void addHeading5(const std::string &text);
|
||||
void addHeading6(const std::string &text);
|
||||
void addItalic(const std::string &text);
|
||||
void addBold(const std::string &text);
|
||||
void addBoldItalic(const std::string &text);
|
||||
|
@ -32,7 +34,6 @@ private:
|
|||
static gboolean addTextIdle(struct DispatchData *data);
|
||||
static gboolean clearIdle(GtkTextBuffer *textBuffer);
|
||||
std::string const intToRoman(int num);
|
||||
void hexToRGB(const std::string& hex, double &r, double &g, double &b);
|
||||
|
||||
int fontSize;
|
||||
std::string fontFamily;
|
||||
|
@ -53,6 +54,8 @@ private:
|
|||
Pango::FontDescription heading2;
|
||||
Pango::FontDescription heading3;
|
||||
Pango::FontDescription heading4;
|
||||
Pango::FontDescription heading5;
|
||||
Pango::FontDescription heading6;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -16,7 +16,7 @@ MainWindow::MainWindow()
|
|||
finalRequestPath(""),
|
||||
currentContent("")
|
||||
{
|
||||
set_title("DBrowser");
|
||||
set_title("DWeb Browser");
|
||||
set_default_size(1000, 800);
|
||||
set_position(Gtk::WIN_POS_CENTER);
|
||||
|
||||
|
|
|
@ -1,528 +0,0 @@
|
|||
#include "render-area.h"
|
||||
#include "node.h"
|
||||
|
||||
#include <gtkmm/widget.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#define PANGO_SCALE_XXX_LARGE ((double)1.98)
|
||||
|
||||
RenderArea::RenderArea()
|
||||
: currentX(0),
|
||||
currentY(0),
|
||||
sceneMarginX(25),
|
||||
sceneMarginY(15),
|
||||
currentXList(sceneMarginX),
|
||||
headingLevel(0),
|
||||
listLevel(0),
|
||||
wordSpacing(4), // spacing may depend on the font
|
||||
highestWidth(0),
|
||||
highestHeight(0),
|
||||
paragraphMargin(5),
|
||||
headingMargin(10),
|
||||
listMargin(5),
|
||||
horizontalLineMargin(2),
|
||||
listXOffset(20),
|
||||
isBold(false),
|
||||
isItalic(false),
|
||||
bulletListLevel(0),
|
||||
orderedListLevel(0),
|
||||
isOrderedList(false),
|
||||
fontSize(10),
|
||||
fontFamily("Ubuntu"),
|
||||
pageWidth(0),
|
||||
pageHeight(0)
|
||||
{
|
||||
// Default size
|
||||
set_size_request(200, 400);
|
||||
createPangoContexts();
|
||||
}
|
||||
|
||||
RenderArea::~RenderArea()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderArea::createPangoContexts()
|
||||
{
|
||||
defaultFont.set_family(fontFamily);
|
||||
defaultFont.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_MEDIUM);
|
||||
|
||||
boldFont.set_family(fontFamily);
|
||||
boldFont.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_MEDIUM);
|
||||
boldFont.set_weight(Pango::WEIGHT_BOLD);
|
||||
|
||||
italicFont.set_family(fontFamily);
|
||||
italicFont.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_MEDIUM);
|
||||
italicFont.set_style(Pango::Style::STYLE_ITALIC);
|
||||
|
||||
boldItalicFont.set_family(fontFamily);
|
||||
boldItalicFont.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_MEDIUM);
|
||||
boldItalicFont.set_weight(Pango::WEIGHT_BOLD);
|
||||
boldItalicFont.set_style(Pango::Style::STYLE_ITALIC);
|
||||
|
||||
heading1Font.set_family(fontFamily);
|
||||
heading1Font.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_XXX_LARGE);
|
||||
heading1Font.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading2Font.set_family(fontFamily);
|
||||
heading2Font.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_XX_LARGE);
|
||||
heading2Font.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading3Font.set_family(fontFamily);
|
||||
heading3Font.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_X_LARGE);
|
||||
heading3Font.set_weight(Pango::WEIGHT_BOLD);
|
||||
heading4Font.set_family(fontFamily);
|
||||
heading4Font.set_size(fontSize * PANGO_SCALE * PANGO_SCALE_LARGE);
|
||||
heading4Font.set_weight(Pango::WEIGHT_BOLD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean-up render area fields
|
||||
*/
|
||||
void RenderArea::clear()
|
||||
{
|
||||
m_textList.clear();
|
||||
m_lines.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process AST document and eventually render to screen (drawing area)
|
||||
*/
|
||||
void RenderArea::processDocument(cmark_node *root_node)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
/*typedef std::chrono::high_resolution_clock Time;
|
||||
typedef std::chrono::milliseconds ms;
|
||||
typedef std::chrono::duration<float> fsec;
|
||||
auto t0 = Time::now();*/
|
||||
|
||||
// Loop over AST nodes
|
||||
cmark_event_type ev_type;
|
||||
cmark_iter *iter = cmark_iter_new(root_node);
|
||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||
cmark_node *cur = cmark_iter_get_node(iter);
|
||||
processNode(cur, ev_type);
|
||||
}
|
||||
|
||||
/*auto t1 = Time::now();
|
||||
fsec fs = t1 - t0;
|
||||
ms d = std::chrono::duration_cast<ms>(fs);
|
||||
std::cout << fs.count() << "s\n";
|
||||
std::cout << d.count() << "ms\n";*/
|
||||
|
||||
// Change drawing area
|
||||
set_size_request(pageWidth, pageHeight);
|
||||
this->redraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a message on screen
|
||||
* \param message Message to be displayed
|
||||
*/
|
||||
void RenderArea::showMessage(const std::string &message, const std::string &detailed_info)
|
||||
{
|
||||
this->clear();
|
||||
|
||||
auto layout = create_pango_layout(message);
|
||||
layout->set_font_description(heading1Font);
|
||||
text_struct textStruct;
|
||||
textStruct.x = 40;
|
||||
textStruct.y = 20;
|
||||
textStruct.layout = layout;
|
||||
m_textList.push_back(textStruct);
|
||||
|
||||
if (!detailed_info.empty()) {
|
||||
auto detail_layout = create_pango_layout(detailed_info);
|
||||
detail_layout->set_font_description(defaultFont);
|
||||
text_struct textStructDetail;
|
||||
textStructDetail.x = 40;
|
||||
textStructDetail.y = 70;
|
||||
textStructDetail.layout = detail_layout;
|
||||
m_textList.push_back(textStructDetail);
|
||||
}
|
||||
|
||||
set_size_request(800, 800);
|
||||
|
||||
this->redraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show start page
|
||||
*/
|
||||
void RenderArea::showStartPage()
|
||||
{
|
||||
this->clear();
|
||||
|
||||
auto layout = create_pango_layout("Welcome to the Decentralized Web (DWeb)");
|
||||
layout->set_font_description(heading1Font);
|
||||
text_struct textStruct;
|
||||
textStruct.x = 40;
|
||||
textStruct.y = 20;
|
||||
textStruct.layout = layout;
|
||||
m_textList.push_back(textStruct);
|
||||
|
||||
auto detail_layout = create_pango_layout("For the test example, go to: ipfs://QmQzhn6hEfbYdCfwzYFsSt3eWpubVKA1dNqsgUwci5vHwq");
|
||||
detail_layout->set_font_description(defaultFont);
|
||||
text_struct textStructDetail;
|
||||
textStructDetail.x = 40;
|
||||
textStructDetail.y = 70;
|
||||
textStructDetail.layout = detail_layout;
|
||||
m_textList.push_back(textStructDetail);
|
||||
|
||||
set_size_request(700, 800);
|
||||
|
||||
this->redraw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the drawing locations and parse each node in the AST
|
||||
*/
|
||||
void RenderArea::processNode(cmark_node *node, cmark_event_type ev_type)
|
||||
{
|
||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||
|
||||
switch (node->type) {
|
||||
case CMARK_NODE_DOCUMENT:
|
||||
if (entering) {
|
||||
// Reset on start
|
||||
currentX = sceneMarginX;
|
||||
currentY = sceneMarginY;
|
||||
headingLevel = 0;
|
||||
bulletListLevel = 0;
|
||||
listLevel = 0;
|
||||
highestHeight = 0;
|
||||
highestWidth = 0;
|
||||
pageWidth = 0;
|
||||
pageHeight = 0;
|
||||
} else {
|
||||
// Document end, set page width & height
|
||||
pageWidth = highestWidth;
|
||||
pageHeight = currentY + sceneMarginY;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_BLOCK_QUOTE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LIST: {
|
||||
cmark_list_type listType = node->as.list.list_type;
|
||||
|
||||
if (entering) {
|
||||
if (listLevel == 0) {
|
||||
currentY += listMargin; // First level Y margin
|
||||
}
|
||||
listLevel++;
|
||||
} else {
|
||||
if (listLevel == 1) {
|
||||
currentY += listMargin; // First level Y margin
|
||||
}
|
||||
listLevel--;
|
||||
}
|
||||
if (listLevel == 0) {
|
||||
// Reset X to be safe
|
||||
currentX = sceneMarginX;
|
||||
currentXList = currentX;
|
||||
// Reset bullet/ordered levels
|
||||
bulletListLevel = 0;
|
||||
orderedListLevel = 0;
|
||||
isOrderedList = false;
|
||||
} else if (listLevel > 0) {
|
||||
if (entering) {
|
||||
currentXList += listXOffset;
|
||||
if (listType == cmark_list_type::CMARK_BULLET_LIST) {
|
||||
bulletListLevel++;
|
||||
} else if(listType == cmark_list_type::CMARK_ORDERED_LIST) {
|
||||
orderedListLevel++;
|
||||
// Create the counter (and reset to zero)
|
||||
orderedListCounters[orderedListLevel] = 0;
|
||||
}
|
||||
} else {
|
||||
currentXList -= listXOffset;
|
||||
if (listType == cmark_list_type::CMARK_BULLET_LIST) {
|
||||
bulletListLevel--;
|
||||
} else if(listType == cmark_list_type::CMARK_ORDERED_LIST) {
|
||||
orderedListLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
isOrderedList = (orderedListLevel > 0) && (bulletListLevel <= 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_ITEM:
|
||||
// Line break for list items
|
||||
currentY += highestHeight;
|
||||
// Reset heighest high (Y-axis)
|
||||
highestHeight = 0;
|
||||
// Set new node item to the correct X position
|
||||
currentX = currentXList;
|
||||
|
||||
if (entering && isOrderedList) {
|
||||
// Increasement ordered list counter
|
||||
orderedListCounters[orderedListLevel]++;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HEADING:
|
||||
if (entering) {
|
||||
headingLevel = node->as.heading.level;
|
||||
} else {
|
||||
headingLevel = 0; // reset
|
||||
}
|
||||
// Move to left again
|
||||
currentX = sceneMarginX;
|
||||
// New heading
|
||||
currentY += highestHeight + headingMargin;
|
||||
|
||||
// Reset heighest high (Y-axis)
|
||||
highestHeight = 0;
|
||||
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE_BLOCK:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML_BLOCK:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CUSTOM_BLOCK:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_THEMATIC_BREAK: {
|
||||
currentY += horizontalLineMargin;
|
||||
line_struct line;
|
||||
line.start_x = 20;
|
||||
line.start_y = currentY;
|
||||
line.end_x = -1; // auto-size width
|
||||
line.end_y = currentY;
|
||||
line.margin_end_x = 20;
|
||||
line.height = 0.2;
|
||||
line.hex_color = "2e2e2e";
|
||||
line.cap = Cairo::LineCap::LINE_CAP_ROUND;
|
||||
m_lines.push_back(line);
|
||||
currentY += horizontalLineMargin;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_PARAGRAPH:
|
||||
// Skip paragraph if listing is enabled
|
||||
if (listLevel == 0) {
|
||||
// Move to left again
|
||||
currentX = sceneMarginX;
|
||||
// New paragraph
|
||||
currentY += highestHeight + paragraphMargin;
|
||||
|
||||
// Reset heighest high (Y-axis)
|
||||
highestHeight = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_TEXT: {
|
||||
// Instead of creating seperate pango layouts we may want to use Pango attributes,
|
||||
// for changing parts of the text. Which is most likely be faster.
|
||||
// https://developer.gnome.org/pango/stable/pango-Text-Attributes.html
|
||||
// Pango is using a simple parser for parsing (X)HTML:
|
||||
// https://developer.gnome.org/glib/stable/glib-Simple-XML-Subset-Parser.html
|
||||
// We can use simular parse functions and using their own 'OpenTag' struct containing a list of Pango attributes:
|
||||
// https://gitlab.gnome.org/GNOME/pango/-/blob/master/pango/pango-markup.c#L515
|
||||
|
||||
// For some reason Pango::Layout:create objects doesn't show up in cairo content
|
||||
std::string text = cmark_node_get_literal(node);
|
||||
if (bulletListLevel > 0) {
|
||||
text.insert(0, "\u2022 ");
|
||||
} else if(orderedListLevel > 0) {
|
||||
std::string number;
|
||||
if (orderedListLevel % 2 == 0) {
|
||||
number = intToRoman(orderedListCounters[orderedListLevel]) + " ";
|
||||
} else {
|
||||
number = std::to_string(orderedListCounters[orderedListLevel]) + ". ";
|
||||
}
|
||||
text.insert(0, number);
|
||||
}
|
||||
|
||||
auto layout = create_pango_layout(text);
|
||||
|
||||
if (headingLevel > 0) {
|
||||
switch (headingLevel)
|
||||
{
|
||||
case 1:
|
||||
layout->set_font_description(heading1Font);
|
||||
break;
|
||||
case 2:
|
||||
layout->set_font_description(heading2Font);
|
||||
break;
|
||||
case 3:
|
||||
layout->set_font_description(heading3Font);
|
||||
break;
|
||||
case 4:
|
||||
layout->set_font_description(heading4Font);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (isBold && isItalic) {
|
||||
layout->set_font_description(boldItalicFont);
|
||||
} else if (isBold) {
|
||||
layout->set_font_description(boldFont);
|
||||
} else if (isItalic) {
|
||||
layout->set_font_description(italicFont);
|
||||
} else {
|
||||
layout->set_font_description(defaultFont);
|
||||
}
|
||||
//layout->set_width(100);
|
||||
int textWidth;
|
||||
int textHeight;
|
||||
layout->get_pixel_size(textWidth, textHeight);
|
||||
|
||||
// Add text to list
|
||||
text_struct textStruct;
|
||||
textStruct.x = currentX;
|
||||
textStruct.y = currentY;
|
||||
textStruct.layout = layout;
|
||||
m_textList.push_back(textStruct);
|
||||
|
||||
// Increase X with text width
|
||||
currentX += textWidth;
|
||||
|
||||
if (textHeight > highestHeight) {
|
||||
highestHeight = textHeight;
|
||||
}
|
||||
if (currentX > highestWidth) {
|
||||
highestWidth = currentX;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINEBREAK:
|
||||
// Move to left again
|
||||
currentX = sceneMarginX;
|
||||
// Line break (no soft break)
|
||||
currentY += highestHeight;
|
||||
|
||||
// Reset heighest high (Y-axis)
|
||||
highestHeight = 0;
|
||||
break;
|
||||
|
||||
case CMARK_NODE_SOFTBREAK:
|
||||
// ignore
|
||||
// Only insert a space between the words
|
||||
currentX += wordSpacing;
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CODE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_HTML_INLINE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_CUSTOM_INLINE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_STRONG:
|
||||
isBold = entering;
|
||||
break;
|
||||
|
||||
case CMARK_NODE_EMPH:
|
||||
isItalic = entering;
|
||||
break;
|
||||
|
||||
case CMARK_NODE_LINK:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_IMAGE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_FOOTNOTE_REFERENCE:
|
||||
break;
|
||||
|
||||
case CMARK_NODE_FOOTNOTE_DEFINITION:
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force redraw
|
||||
*/
|
||||
void RenderArea::redraw()
|
||||
{
|
||||
queue_draw_area(0, 0, get_allocation().get_width(), get_allocation().get_height());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrided method of GTK DrawingArea
|
||||
*/
|
||||
bool RenderArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
|
||||
{
|
||||
Gtk::Allocation allocation = get_allocation();
|
||||
// Total drawing area size
|
||||
const int width = allocation.get_width();
|
||||
const int height = allocation.get_height();
|
||||
|
||||
// White background
|
||||
cr->set_source_rgb(1.0, 1.0, 1.0);
|
||||
cr->rectangle(0, 0, width, height);
|
||||
cr->fill();
|
||||
|
||||
// Set to black for text
|
||||
cr->set_source_rgb(0.0, 0.0, 0.0);
|
||||
|
||||
// Draw text
|
||||
std::list<text_struct>::iterator textIt;
|
||||
for(textIt = m_textList.begin(); textIt != m_textList.end(); ++textIt) {
|
||||
auto text = (*textIt);
|
||||
cr->move_to(text.x, text.y);
|
||||
text.layout->show_in_cairo_context(cr);
|
||||
}
|
||||
|
||||
// Draw lines
|
||||
std::list<line_struct>::iterator lineIt;
|
||||
for(lineIt = m_lines.begin(); lineIt != m_lines.end(); ++lineIt) {
|
||||
auto line = (*lineIt);
|
||||
double r, g, b;
|
||||
hexToRGB(line.hex_color, r, g, b);
|
||||
int endX = line.end_x;
|
||||
if (line.end_x == -1)
|
||||
endX = width - line.margin_end_x;
|
||||
cr->set_line_cap(line.cap);
|
||||
cr->set_source_rgb(r, g, b);
|
||||
cr->set_line_width(line.height);
|
||||
cr->move_to(line.start_x, line.start_y);
|
||||
cr->line_to(endX, line.end_y);
|
||||
cr->stroke();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert number to roman number
|
||||
*/
|
||||
std::string const RenderArea::intToRoman(int num)
|
||||
{
|
||||
static const int values[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
|
||||
static const std::string numerals[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" };
|
||||
std::string res;
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
while (num >= values[i]) {
|
||||
num -= values[i];
|
||||
res += numerals[i];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string to seperate RGB values
|
||||
*/
|
||||
void RenderArea::hexToRGB(const std::string& hex, double &r, double &g, double &b)
|
||||
{
|
||||
unsigned int intR, intG, intB;
|
||||
sscanf(hex.c_str(), "%02x%02x%02x", &intR, &intG, &intB);
|
||||
r = intR / 255.0;
|
||||
g = intG / 255.0;
|
||||
b = intB / 255.0;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
#ifndef RENDER_AREA_H
|
||||
#define RENDER_AREA_H
|
||||
|
||||
#include <gtkmm/drawingarea.h>
|
||||
#include <pangomm/layout.h>
|
||||
#include <cmark-gfm.h>
|
||||
|
||||
struct text_struct {
|
||||
int x;
|
||||
int y;
|
||||
Glib::RefPtr<Pango::Layout> layout;
|
||||
};
|
||||
|
||||
struct line_struct {
|
||||
int start_x;
|
||||
int start_y;
|
||||
int end_x; // -1 means auto-size
|
||||
int end_y;
|
||||
int margin_end_x;
|
||||
double height;
|
||||
std::string hex_color;
|
||||
Cairo::LineCap cap;
|
||||
};
|
||||
|
||||
class RenderArea : public Gtk::DrawingArea
|
||||
{
|
||||
public:
|
||||
RenderArea();
|
||||
virtual ~RenderArea();
|
||||
|
||||
void processDocument(cmark_node *root_node);
|
||||
void showMessage(const std::string &message, const std::string &detailed_info = "");
|
||||
void showStartPage();
|
||||
|
||||
protected:
|
||||
std::list<text_struct> m_textList;
|
||||
std::list<line_struct> m_lines;
|
||||
|
||||
// Override default signal handler:
|
||||
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
|
||||
|
||||
private:
|
||||
int currentX;
|
||||
int currentY;
|
||||
int sceneMarginX;
|
||||
int sceneMarginY;
|
||||
int currentXList;
|
||||
int headingLevel;
|
||||
int listLevel;
|
||||
int wordSpacing;
|
||||
int highestWidth;
|
||||
int highestHeight;
|
||||
int paragraphMargin;
|
||||
int headingMargin;
|
||||
int listMargin;
|
||||
int horizontalLineMargin;
|
||||
int listXOffset;
|
||||
bool isBold;
|
||||
bool isItalic;
|
||||
int bulletListLevel;
|
||||
int orderedListLevel;
|
||||
bool isOrderedList;
|
||||
std::map<int,int> orderedListCounters;
|
||||
int fontSize;
|
||||
std::string fontFamily;
|
||||
int pageWidth;
|
||||
int pageHeight;
|
||||
|
||||
Pango::FontDescription defaultFont;
|
||||
Pango::FontDescription boldFont;
|
||||
Pango::FontDescription italicFont;
|
||||
Pango::FontDescription boldItalicFont;
|
||||
Pango::FontDescription heading1Font;
|
||||
Pango::FontDescription heading2Font;
|
||||
Pango::FontDescription heading3Font;
|
||||
Pango::FontDescription heading4Font;
|
||||
|
||||
void createPangoContexts();
|
||||
void clear();
|
||||
void processNode(cmark_node *node, cmark_event_type ev_type);
|
||||
void redraw();
|
||||
std::string const intToRoman(int num);
|
||||
void hexToRGB(const std::string& hex, double &r, double &g, double &b);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue