diff --git a/.vscode/settings.json b/.vscode/settings.json index 92c33e8..6eb879f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,6 +66,7 @@ "variant": "cpp", "bit": "cpp", "qsizepolicy": "cpp", - "qgraphicsscene": "cpp" + "qgraphicsscene": "cpp", + "qstring": "cpp" } } \ No newline at end of file diff --git a/src/mainwindow.cc b/src/mainwindow.cc index c33c816..e1ff52e 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -35,7 +35,7 @@ MainWindow::MainWindow() scene = new Scene(this); view = new QGraphicsView(scene); //view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - view->setAlignment(Qt::Alignment::enum_type::AlignLeft); + view->setAlignment(Qt::Alignment::enum_type::AlignTop|Qt::Alignment::enum_type::AlignLeft); layout->addWidget(view); // We will not use TextEdit, it does only support HTML (and markdown, but we don't want to use the built-in parser). diff --git a/src/md-parser.cc b/src/md-parser.cc index 5632a70..ffbfc93 100644 --- a/src/md-parser.cc +++ b/src/md-parser.cc @@ -58,14 +58,6 @@ std::string const Parser::renderHTML(cmark_node *node) return output; } -std::string const Parser::renderMyLayout(cmark_node *node) -{ - char *tmp = renderLayout(node, options, 0, NULL); - std::string output = std::string(tmp); - free(tmp); - return output; -} - /** * This is a function that will make enabling extensions easier */ @@ -74,109 +66,3 @@ void Parser::addMarkdownExtension(cmark_parser *parser, const char *extName) { if ( ext ) cmark_parser_attach_syntax_extension(parser, ext); } - -char *Parser::renderLayout(cmark_node *root, int options, int width, cmark_llist *extensions) -{ - return cmark_render(cmark_node_mem(root), root, options, width, outc, renderNode); -} - -int Parser::renderNode(cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) -{ - bool entering = (ev_type == CMARK_EVENT_ENTER); - - switch (node->type) { - case CMARK_NODE_DOCUMENT: - printf("Document\n"); - break; - - case CMARK_NODE_BLOCK_QUOTE: - break; - - case CMARK_NODE_LIST: - printf("List\n"); - break; - - case CMARK_NODE_ITEM: - printf("Item\n"); - break; - - case CMARK_NODE_HEADING: - printf("Heading\n"); - break; - - case CMARK_NODE_CODE_BLOCK: - break; - - case CMARK_NODE_HTML_BLOCK: - break; - - case CMARK_NODE_CUSTOM_BLOCK: - break; - - case CMARK_NODE_THEMATIC_BREAK: - break; - - case CMARK_NODE_PARAGRAPH: - printf("Paragraph\n"); - break; - - case CMARK_NODE_TEXT: - printf("Text\n"); - - // False = no wrap, we didn't specify a width - OUT(cmark_node_get_literal(node), false, NORMAL); - break; - - case CMARK_NODE_LINEBREAK: - break; - - case CMARK_NODE_SOFTBREAK: - break; - - case CMARK_NODE_CODE: - break; - - case CMARK_NODE_HTML_INLINE: - break; - - case CMARK_NODE_CUSTOM_INLINE: - break; - - case CMARK_NODE_STRONG: - printf("Bold\n"); - if (entering) { - LIT("[b]"); - } else { - LIT("[/b]"); - } - break; - - case CMARK_NODE_EMPH: - printf("Italic\n"); - if (entering) { - LIT("_"); - } else { - LIT("_"); - } - 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; - } - - return 1; -} - diff --git a/src/md-parser.h b/src/md-parser.h index 0f04f1b..09051b4 100644 --- a/src/md-parser.h +++ b/src/md-parser.h @@ -14,14 +14,10 @@ public: Parser(); cmark_node * parseFile(const std::string &filePath); std::string const renderHTML(cmark_node *node); - std::string const renderMyLayout(cmark_node *node); private: int options; void addMarkdownExtension(cmark_parser *parser, const char *extName); - char * renderLayout(cmark_node *root, int options, int width, cmark_llist *extensions); - static int renderNode(cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options); }; #endif diff --git a/src/md-render.cc b/src/md-render.cc index 1168796..c8cba64 100644 --- a/src/md-render.cc +++ b/src/md-render.cc @@ -15,10 +15,17 @@ Renderer::Renderer(Scene* scene) : sceneMarginY(3.0), bold(false), italic(false), + headingLevel(0), + listLevel(0), currentX(0.0), currentY(0.0), + fontFamilty("Open Sans"), + wordSpacing(4.0), // spacing may depend on the font heighestHigh(0.0), - paragraphOffsetHeight(5.0) { + paragraphHeightOffset(5.0), + headingHeightOffset(10.0), + listXOffset(15.0), + bulletWithTemp(0.0) { } /** @@ -44,7 +51,6 @@ void Renderer::renderNode(cmark_node *node, cmark_event_type ev_type) switch (node->type) { case CMARK_NODE_DOCUMENT: - printf("Document\n"); if (entering) { currentX = sceneMarginX; currentY = sceneMarginY; @@ -55,15 +61,56 @@ void Renderer::renderNode(cmark_node *node, cmark_event_type ev_type) break; case CMARK_NODE_LIST: - printf("List\n"); + if (entering) { + listLevel++; + } else { + listLevel--; + if (listLevel < 0) + listLevel = 0; + } + + if (listLevel == 0) { + // Reset X to be safe + currentX = sceneMarginX; + } else if (listLevel > 0) { + if (entering) { + currentX += listXOffset; + } else { + currentX -= listXOffset; + } + } break; case CMARK_NODE_ITEM: - printf("Item\n"); + // Line break for list items + currentY += heighestHigh; + // Reset heighest high (Y-axis) + heighestHigh = 0; + + // Add bullet before text items + if (entering) { + const QRectF rec = drawBullet(); + bulletWithTemp = rec.width() + 2.0; // + offset + currentX += bulletWithTemp; + } else { + currentX -= bulletWithTemp; + } break; case CMARK_NODE_HEADING: - printf("Heading\n"); + if (entering) { + headingLevel = node->as.heading.level; + } else { + headingLevel = 0; // reset + } + // Move to left again + currentX = sceneMarginX; + // New heading + currentY += heighestHigh + headingHeightOffset; + + // Reset heighest high (Y-axis) + heighestHigh = 0; + break; case CMARK_NODE_CODE_BLOCK: @@ -79,31 +126,46 @@ void Renderer::renderNode(cmark_node *node, cmark_event_type ev_type) break; case CMARK_NODE_PARAGRAPH: - printf("Paragraph\n"); - // Move to left again - currentX = sceneMarginX; - // New paragraph - currentY += heighestHigh + paragraphOffsetHeight; - - // Reset heighest high (Y-axis) - heighestHigh = 0; + printf("p\n"); + + // Skip paragraph if listing is enabled + if (listLevel == 0) { + // Move to left again + currentX = sceneMarginX; + // New paragraph + currentY += heighestHigh + paragraphHeightOffset; + + // Reset heighest high (Y-axis) + heighestHigh = 0; + } break; case CMARK_NODE_TEXT: { - printf("Text\n"); - const QRectF rec = drawText(cmark_node_get_literal(node), bold, italic); - currentX += rec.width(); + printf("text\n"); + const QRectF rec = drawText(cmark_node_get_literal(node)); + // Skip paragraph if listing is enabled + if (listLevel == 0) { + currentX += rec.width(); + } if (rec.height() > heighestHigh) heighestHigh = rec.height(); } break; case CMARK_NODE_LINEBREAK: - printf("Line break\n"); + // Move to left again + currentX = sceneMarginX; + // Line break (no soft break) + currentY += heighestHigh; + + // Reset heighest high (Y-axis) + heighestHigh = 0; break; case CMARK_NODE_SOFTBREAK: - printf("Soft-Line break\n"); + // ignore + // Only insert a space between the words + currentX += wordSpacing; break; case CMARK_NODE_CODE: @@ -116,12 +178,10 @@ void Renderer::renderNode(cmark_node *node, cmark_event_type ev_type) break; case CMARK_NODE_STRONG: - printf("Bold\n"); bold = entering; break; case CMARK_NODE_EMPH: - printf("Italic\n"); italic = entering; break; @@ -142,27 +202,55 @@ void Renderer::renderNode(cmark_node *node, cmark_event_type ev_type) } } -QRectF const Renderer::drawText(const std::string& text, bool bold, bool italic) +QRectF const Renderer::drawText(const QString& text) { // We can still extend the QGraphicsSimpleTextItem class (or QAbstractGraphicsShapeItem) and override paint method. // Or just use QPainter with a paint device (like QWidgets), to have maximal control. - QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(QString::fromStdString(text)); + QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(text); QFont font; if (bold) font.setBold(true); if (italic) font.setItalic(true); - font.setFamily("Open Sans"); // Arial + + if (headingLevel > 0) { + font.setBold(true); + switch(headingLevel) { + case 1: + font.setPixelSize(24); + break; + case 2: + font.setPixelSize(20); + break; + case 3: + font.setPixelSize(16); + break; + case 4: + font.setPixelSize(14); + break; + case 5: + font.setPixelSize(12); + break; + default: + break; + } + } + + font.setFamily(fontFamilty); textItem->setFont(font); textItem->setPos(currentX, currentY); scene->addItem(textItem); - if (false) { - // For debugging only - QGraphicsRectItem* box = new QGraphicsRectItem(textItem->boundingRect()); - box->setPos(currentX, currentY); - scene->addItem(box); - } - return textItem->boundingRect(); +} + +QRectF const Renderer::drawBullet() +{ + QGraphicsSimpleTextItem *bullet = new QGraphicsSimpleTextItem("\u2022"); + QFont font; + font.setFamily(fontFamilty); + bullet->setFont(font); + bullet->setPos(currentX, currentY); + scene->addItem(bullet); + return bullet->boundingRect(); } \ No newline at end of file diff --git a/src/md-render.h b/src/md-render.h index b4159ba..89edbda 100644 --- a/src/md-render.h +++ b/src/md-render.h @@ -1,10 +1,10 @@ #ifndef MD_RENDER_H #define MD_RENDER_H -#include #include #include #include +#include class Scene; class QRectF; @@ -24,12 +24,21 @@ private: qreal sceneMarginY; bool bold; bool italic; + int headingLevel; + int listLevel; qreal currentX; qreal currentY; + QString fontFamilty; + qreal wordSpacing; qreal heighestHigh; - qreal paragraphOffsetHeight; + qreal paragraphHeightOffset; + qreal headingHeightOffset; + qreal listXOffset; + + qreal bulletWithTemp; void renderNode(cmark_node *node, cmark_event_type ev_type); - QRectF const drawText(const std::string& text, bool bold = false, bool italic = false); + QRectF const drawText(const QString& text); + QRectF const drawBullet(); }; #endif diff --git a/src/scene.cc b/src/scene.cc index ad168d8..bc42b0e 100644 --- a/src/scene.cc +++ b/src/scene.cc @@ -3,5 +3,5 @@ Scene::Scene(QObject *parent) : QGraphicsScene(parent) { - setSceneRect(QRectF(0, 0, 200, 180)); + setSceneRect(QRectF(0, 0, 300, 300)); } \ No newline at end of file diff --git a/test.md b/test.md index e2ae47f..3ad2951 100644 --- a/test.md +++ b/test.md @@ -1,3 +1,19 @@ Hello *World*, What a **happy** day! +blabla. +test -New paragraph/line. \ No newline at end of file +# Heading 1 + +## Heading 2 + +***New*** paragraph. +New line. + +* list 1 +* list 2 +* list 3 + * list 3.1 + * list 3.2 +* list 4 + +Normal text. \ No newline at end of file