aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix (xq) Queißner <git@mq32.de>2020-06-06 22:23:20 +0200
committerFelix (xq) Queißner <git@mq32.de>2020-06-06 22:23:20 +0200
commitd9e105e6e0accf5def8681334341069117cab213 (patch)
tree68764c76f67326aaa3f731ce70726e821c00e11a
parent87d787bc2c50eb00c6b86957efaa71e07f9acc07 (diff)
downloadkristall-d9e105e6e0accf5def8681334341069117cab213.tar.gz
Navigation via outline is now possible. Sexy!
-rw-r--r--README.md5
-rw-r--r--browsertab.cpp6
-rw-r--r--browsertab.hpp2
-rw-r--r--documentoutlinemodel.cpp38
-rw-r--r--documentoutlinemodel.hpp10
-rw-r--r--geminirenderer.cpp33
-rw-r--r--mainwindow.cpp12
-rw-r--r--mainwindow.hpp2
8 files changed, 87 insertions, 21 deletions
diff --git a/README.md b/README.md
index b49cd6b..9b359b6 100644
--- a/README.md
+++ b/README.md
@@ -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;