diff options
| author | Felix (xq) Queißner <git@mq32.de> | 2020-06-06 22:23:20 +0200 |
|---|---|---|
| committer | Felix (xq) Queißner <git@mq32.de> | 2020-06-06 22:23:20 +0200 |
| commit | d9e105e6e0accf5def8681334341069117cab213 (patch) | |
| tree | 68764c76f67326aaa3f731ce70726e821c00e11a | |
| parent | 87d787bc2c50eb00c6b86957efaa71e07f9acc07 (diff) | |
| download | kristall-d9e105e6e0accf5def8681334341069117cab213.tar.gz | |
Navigation via outline is now possible. Sexy!
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | browsertab.cpp | 6 | ||||
| -rw-r--r-- | browsertab.hpp | 2 | ||||
| -rw-r--r-- | documentoutlinemodel.cpp | 38 | ||||
| -rw-r--r-- | documentoutlinemodel.hpp | 10 | ||||
| -rw-r--r-- | geminirenderer.cpp | 33 | ||||
| -rw-r--r-- | mainwindow.cpp | 12 | ||||
| -rw-r--r-- | mainwindow.hpp | 2 |
8 files changed, 87 insertions, 21 deletions
@@ -17,7 +17,7 @@ A high-quality visual cross-platform gemini browser. - [Special link highlighting for different targets](https://mq32.de/public/92f3ec7a64833d01f1ed001d15c8db4158e5d3c2.png) - Color Themes - Custom color theme - - Automatic light/dark theme based on the host name + - [Automatic light/dark theme based on the host name](https://mq32.de/public/kristall-01.mp4) - Navigation history - Crossplatform supports - Linux @@ -68,5 +68,4 @@ Notes for OpenBSD: - [ ] Add auto-generated "favicons" - [ ] Check if the site follows this guideline: `#<ICON> Title` where `<ICON>` is a unicode emoji - [ ] Opt-In: Regularly check for `domain/favicon.ico` -- [ ] Theming - - [ ] Fix default theme when not found. + diff --git a/browsertab.cpp b/browsertab.cpp index 6543c86..e81dc39 100644 --- a/browsertab.cpp +++ b/browsertab.cpp @@ -104,6 +104,12 @@ void BrowserTab::navOneForward() navigateBack(history.oneForward(current_history_index)); } +void BrowserTab::scrollToAnchor(QString const & anchor) +{ + qDebug() << "scroll to anchor" << anchor; + this->ui->text_browser->scrollToAnchor(anchor); +} + void BrowserTab::on_menu_button_clicked() { QMenu menu; diff --git a/browsertab.hpp b/browsertab.hpp index 7e05995..44e47b7 100644 --- a/browsertab.hpp +++ b/browsertab.hpp @@ -39,6 +39,8 @@ public: void navOneForward(); + void scrollToAnchor(QString const & anchor); + signals: void titleChanged(QString const & title); void locationChanged(QUrl const & url); diff --git a/documentoutlinemodel.cpp b/documentoutlinemodel.cpp index 47ff3b5..5978f33 100644 --- a/documentoutlinemodel.cpp +++ b/documentoutlinemodel.cpp @@ -21,39 +21,39 @@ void DocumentOutlineModel::beginBuild() beginResetModel(); root = Node { nullptr, - "<ROOT>", + "<ROOT>", "", 0, 0, QList<Node> { }, }; } -void DocumentOutlineModel::appendH1(const QString &title) +void DocumentOutlineModel::appendH1(const QString &title, QString const & anchor) { root.children.append(Node { &root, - title, + title, anchor, 1, 0, QList<Node> { }, }); } -void DocumentOutlineModel::appendH2(const QString &title) +void DocumentOutlineModel::appendH2(const QString &title, QString const & anchor) { auto & parent = ensureLevel1(); parent.children.append(Node { &parent, - title, + title, anchor, 2, parent.children.size() - 1, QList<Node> { }, }); } -void DocumentOutlineModel::appendH3(const QString &title) +void DocumentOutlineModel::appendH3(const QString &title, QString const & anchor) { auto & parent = ensureLevel2(); parent.children.append(Node { &parent, - title, + title, anchor, 3, parent.children.size() - 1, QList<Node> { }, }); @@ -79,6 +79,26 @@ void DocumentOutlineModel::endBuild() endResetModel(); } +QString DocumentOutlineModel::getTitle(const QModelIndex &index) const +{ + if(not index.isValid()) + return ""; + + Node const *childItem = static_cast<Node const *>(index.internalPointer()); + + return childItem->title; +} + +QString DocumentOutlineModel::getAnchor(const QModelIndex &index) const +{ + if(not index.isValid()) + return ""; + + Node const *childItem = static_cast<Node const *>(index.internalPointer()); + + return childItem->anchor; +} + QModelIndex DocumentOutlineModel::index(int row, int column, const QModelIndex &parent) const { if (not hasIndex(row, column, parent)) @@ -155,7 +175,7 @@ DocumentOutlineModel::Node & DocumentOutlineModel::ensureLevel1() if(root.children.size() == 0) { root.children.append(Node { &root, - "<missing layer>", + "<missing layer>", "", 1, 0, QList<Node> { }, }); @@ -170,7 +190,7 @@ DocumentOutlineModel::Node & DocumentOutlineModel::ensureLevel2() if(parent.children.size() == 0) { root.children.append(Node { &parent, - "<missing layer>", + "<missing layer>", "", 2, 0, QList<Node> { }, }); diff --git a/documentoutlinemodel.hpp b/documentoutlinemodel.hpp index 52e5f48..0476892 100644 --- a/documentoutlinemodel.hpp +++ b/documentoutlinemodel.hpp @@ -15,14 +15,17 @@ public: void beginBuild(); - void appendH1(QString const & title); + void appendH1(QString const & title, QString const & anchor); - void appendH2(QString const & title); + void appendH2(QString const & title, QString const & anchor); - void appendH3(QString const & title); + void appendH3(QString const & title, QString const & anchor); void endBuild(); + QString getTitle(QModelIndex const & index) const; + QString getAnchor(QModelIndex const & index) const; + public: QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; @@ -39,6 +42,7 @@ private: { Node * parent; QString title; + QString anchor; int depth = 0; int index = 0; QList<Node> children; diff --git a/geminirenderer.cpp b/geminirenderer.cpp index 51565e2..811a946 100644 --- a/geminirenderer.cpp +++ b/geminirenderer.cpp @@ -235,6 +235,12 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(const QByteArray &input, outline.beginBuild(); + int anchor_id = 0; + + auto unique_anchor_name = [&]() -> QString { + return QString("auto-title-%1").arg(++anchor_id); + }; + QList<QByteArray> lines = input.split('\n'); for (auto const &line : lines) { @@ -283,22 +289,37 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(const QByteArray &input, { auto heading = trim_whitespace(line.mid(3)); - cursor.insertText(heading + "\n", standard_h3); - outline.appendH3(heading); + auto id = unique_anchor_name(); + auto fmt = standard_h3; + fmt.setAnchor(true); + fmt.setAnchorNames(QStringList { id }); + + cursor.insertText(heading + "\n", fmt); + outline.appendH3(heading, id); } else if (line.startsWith("##")) { auto heading = trim_whitespace(line.mid(2)); - cursor.insertText(heading + "\n", standard_h2); - outline.appendH2(heading); + auto id = unique_anchor_name(); + auto fmt = standard_h2; + fmt.setAnchor(true); + fmt.setAnchorNames(QStringList { id }); + + cursor.insertText(heading + "\n", fmt); + outline.appendH2(heading, id); } else if (line.startsWith("#")) { auto heading = trim_whitespace(line.mid(1)); - cursor.insertText(heading + "\n", standard_h1); - outline.appendH1(heading); + auto id = unique_anchor_name(); + auto fmt = standard_h1; + fmt.setAnchor(true); + fmt.setAnchorNames(QStringList { id }); + + cursor.insertText(heading + "\n", fmt); + outline.appendH1(heading, id); } else if (line.startsWith("=>")) { diff --git a/mainwindow.cpp b/mainwindow.cpp index 3682891..4b8d692 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -183,3 +183,15 @@ void MainWindow::on_nav_forward() tab->navOneForward(); } } + +void MainWindow::on_outline_view_clicked(const QModelIndex &index) +{ + BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget()); + if(tab != nullptr) { + + auto anchor = tab->outline.getAnchor(index); + if(not anchor.isEmpty()) { + tab->scrollToAnchor(anchor); + } + } +} diff --git a/mainwindow.hpp b/mainwindow.hpp index 648f643..dd901e3 100644 --- a/mainwindow.hpp +++ b/mainwindow.hpp @@ -56,6 +56,8 @@ private slots: void on_nav_forward(); + void on_outline_view_clicked(const QModelIndex &index); + public: QSettings settings; GeminiStyle current_style; |
