Simple menu

master
Melroy van den Berg 2020-12-01 00:43:52 +01:00
parent 2a4c0af69a
commit 0f0e37e02d
9 changed files with 96 additions and 341 deletions

View File

@ -34,6 +34,8 @@ set(SOURCES
main.cc
mainwindow.cc
mainwindow.h
menu.cc
menu.h
md-parser.cc
md-parser.h
render-area.cc

View File

@ -4,10 +4,8 @@
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
auto app = Gtk::Application::create(argc, argv, "org.melroy.browser");
MainWindow window;
//Shows the window and returns when it is closed.
return app->run(window);
}

View File

@ -3,6 +3,7 @@
#include <chrono>
#include <iostream>
#include <gtkmm/menuitem.h>
#ifdef LEGACY_CXX
#include <experimental/filesystem>
namespace n_fs = ::std::experimental::filesystem;
@ -11,17 +12,22 @@ namespace n_fs = ::std::experimental::filesystem;
namespace n_fs = ::std::filesystem;
#endif
MainWindow::MainWindow()
MainWindow::MainWindow() : m_vbox(Gtk::ORIENTATION_VERTICAL, 0)
{
set_title("Browser");
set_default_size(1000, 800);
set_position(Gtk::WIN_POS_CENTER_ALWAYS);
add(m_scrolledWindow);
// Connect signals
m_menu.quit.connect(sigc::mem_fun(this, &MainWindow::hide)); /*!< hide main window and therefor closes the app */
m_vbox.pack_start(m_menu, false, false, 0);
m_scrolledWindow.add(m_renderArea);
m_scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
m_vbox.pack_end(m_scrolledWindow, true, true, 0);
add(m_vbox);
show_all_children();
// Setup parser

View File

@ -2,8 +2,11 @@
#define MAINWINDOW_H
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/menubar.h>
#include <gtkmm/scrolledwindow.h>
#include "render-area.h"
#include "menu.h"
class Parser;
@ -19,6 +22,8 @@ protected:
void on_button_clicked(Glib::ustring data);
// Child widgets
Menu m_menu;
Gtk::Box m_vbox;
Gtk::ScrolledWindow m_scrolledWindow;
RenderArea m_renderArea;
private:

45
src/menu.cc Normal file
View File

@ -0,0 +1,45 @@
#include "menu.h"
Menu::Menu()
: m_file("_File", true),
m_view("_View", true),
m_help("_Help", true)
{
// File submenu
auto exit_menuitem = createMenuItem("Exit");
exit_menuitem->signal_activate().connect(quit);
// View submenu
auto source_code_menuitem = createMenuItem("View source");
source_code_menuitem->signal_activate().connect(source_code);
// Help submenu
auto about_menuitem = createMenuItem("About");
about_menuitem->signal_activate().connect(show_about);
// Add items to sub-menus
m_file_submenu.append(*exit_menuitem);
m_view_submenu.append(*source_code_menuitem);
m_help_submenu.append(*about_menuitem);
// Add sub-menus to menus
m_file.set_submenu(m_file_submenu);
m_view.set_submenu(m_view_submenu);
m_help.set_submenu(m_help_submenu);
// Add menus to menu bar
append(m_file);
append(m_view);
append(m_help);
}
Menu::~Menu() {
}
/**
* \brief Helper method for creating a menu with an image
* \return GTKWidget menu item pointer
*/
Gtk::MenuItem* Menu::createMenuItem(const Glib::ustring& label_text) {
Gtk::MenuItem* item = Gtk::manage(new Gtk::MenuItem(label_text));
return item;
}

34
src/menu.h Normal file
View File

@ -0,0 +1,34 @@
#include <signal.h>
#include <gtkmm/menubar.h>
#include <gtkmm/menu.h>
#include <gtkmm/menuitem.h>
#include <gtkmm/separatormenuitem.h>
/**
* \class Menu
* \brief The top main-menu
*/
class Menu: public Gtk::MenuBar
{
public:
sigc::signal<void> source_code;
sigc::signal<void> quit;
sigc::signal<void> show_about;
Menu();
virtual ~Menu();
Gtk::Menu* GetMachineMenu();
protected:
// Child widgets
Gtk::MenuItem m_file;
Gtk::MenuItem m_view;
Gtk::MenuItem m_help;
Gtk::Menu m_file_submenu; /*!< File sub menu */
Gtk::Menu m_view_submenu; /*!< Help sub menu */
Gtk::Menu m_help_submenu; /*!< Help sub menu */
Gtk::SeparatorMenuItem m_separator1;
private:
Gtk::MenuItem* createMenuItem(const Glib::ustring& label_text);
};

View File

@ -1,278 +0,0 @@
#include "qt-renderer.h"
#include "scene.h"
#include "cmark-gfm.h"
#include <chrono>
#include <iostream>
#include <node.h>
#include <QFont>
#include <QGraphicsTextItem>
#include <QGraphicsRectItem>
#include <QGraphicsSimpleTextItem>
#include <QPainter>
QtRenderer::QtRenderer():
scene(NULL),
defaultFontSize(12),
sceneMarginX(3.0),
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),
paragraphHeightOffset(5.0),
headingHeightOffset(10.0),
listXOffset(15.0),
bulletWithTemp(0.0) {
font = new QFont();
font->setPixelSize(defaultFontSize);
font->setFamily(fontFamilty);
}
QtRenderer::~QtRenderer()
{
delete font;
}
void QtRenderer::setScene(Scene* scene)
{
this->scene = scene;
}
/**
* Render the whole document to scene/screen
*/
void QtRenderer::renderDocument(cmark_node *root, int width)
{
cmark_event_type ev_type;
cmark_iter *iter = cmark_iter_new(root);
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
cmark_node *cur = cmark_iter_get_node(iter);
renderNode(cur, ev_type);
}
}
/**
* Calculates the locations, render and paint the content/objects
* to a QGraphicsScene
*/
void QtRenderer::renderNode(cmark_node *node, cmark_event_type ev_type)
{
bool entering = (ev_type == CMARK_EVENT_ENTER);
switch (node->type) {
case CMARK_NODE_DOCUMENT:
if (entering) {
currentX = sceneMarginX;
currentY = sceneMarginY;
}
break;
case CMARK_NODE_BLOCK_QUOTE:
break;
case CMARK_NODE_LIST:
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:
// 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:
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:
break;
case CMARK_NODE_HTML_BLOCK:
break;
case CMARK_NODE_CUSTOM_BLOCK:
break;
case CMARK_NODE_THEMATIC_BREAK:
break;
case CMARK_NODE_PARAGRAPH:
// 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: {
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:
// 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:
// 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:
bold = entering;
break;
case CMARK_NODE_EMPH:
italic = 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;
}
}
QRectF const QtRenderer::drawText(const QString& text)
{
typedef std::chrono::high_resolution_clock Time;
typedef std::chrono::milliseconds ms;
typedef std::chrono::duration<float> fsec;
auto t0 = Time::now();
// 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(text);
font->setBold(bold);
font->setItalic(italic);
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;
}
}
textItem->setFont(*font);
textItem->setPos(currentX, currentY);
scene->addItem(textItem);
if (headingLevel > 0) {
font->setPixelSize(defaultFontSize);
}
auto t1 = Time::now();
fsec fs = t1 - t0;
ms d = std::chrono::duration_cast<ms>(fs);
std::cout << "Draw Text: " << d.count() << " ms . Content: " << text.toStdString().c_str() << std::endl;
return textItem->boundingRect();
}
QRectF const QtRenderer::drawBullet()
{
QGraphicsSimpleTextItem *bullet = new QGraphicsSimpleTextItem("\u2022");
bullet->setFont(*font);
bullet->setPos(currentX, currentY);
scene->addItem(bullet);
return bullet->boundingRect();
}

View File

@ -1,56 +0,0 @@
#ifndef QT_RENDER_H
#define QT_RENDER_H
#include <cmark-gfm.h>
#include <render.h>
#include <QtGlobal>
#include <QString>
#include "renderer-interface.h"
class Scene;
class QRectF;
class QFont;
/**
* \class QtRenderer Class will use Qt to render AST object to a QGraphicsScene
*/
class QtRenderer : public RendererI
{
public:
explicit QtRenderer();
~QtRenderer();
void setScene(Scene *scene) override;
void setUnknownYet() override {}; // No implementation
void renderDocument(cmark_node *root, int width = 0) override;
private:
Scene *scene;
QFont *font;
int defaultFontSize;
qreal sceneMarginX;
qreal sceneMarginY;
bool bold;
bool italic;
int headingLevel;
int listLevel;
qreal currentX;
qreal currentY;
QString fontFamilty;
qreal wordSpacing;
qreal heighestHigh;
qreal paragraphHeightOffset;
qreal headingHeightOffset;
qreal listXOffset;
qreal bulletWithTemp;
// Copy contructor (not used/non-copyable)
QtRenderer(const QtRenderer& _);
// Copy assignment (not used/not assignable)
QtRenderer& operator=(const QtRenderer& _);
void renderNode(cmark_node *node, cmark_event_type ev_type);
QRectF const drawText(const QString& text);
QRectF const drawBullet();
};
#endif

View File

@ -1,3 +1,2 @@
missingIncludeSystem
missingInclude:lib/*
unusedFunction:src/*