aboutsummaryrefslogtreecommitdiff
path: root/ui.qt/source
diff options
context:
space:
mode:
Diffstat (limited to 'ui.qt/source')
-rw-r--r--ui.qt/source/document.cpp144
-rw-r--r--ui.qt/source/document.hpp68
-rw-r--r--ui.qt/source/fwd.hpp3
-rw-r--r--ui.qt/source/main.cpp6
-rw-r--r--ui.qt/source/qml/Document.qml164
-rw-r--r--ui.qt/source/qml/MainWindow.qml11
-rw-r--r--ui.qt/source/qml/Navigator.qml36
7 files changed, 342 insertions, 90 deletions
diff --git a/ui.qt/source/document.cpp b/ui.qt/source/document.cpp
index b418b0d..377913b 100644
--- a/ui.qt/source/document.cpp
+++ b/ui.qt/source/document.cpp
@@ -1,35 +1,29 @@
#include "document.hpp"
-#include <QMetaType>
+#include <QBrush>
+#include <QColor>
+#include <QTextCursor>
#include <QVariant>
-DocumentBlock::DocumentBlock(QObject* parent)
+DocumentHandler::DocumentHandler(QObject* parent)
: QObject{ parent }
{
}
-DocumentModel* DocumentBlock::getModel() const
-{
- return mModel;
-}
-
-void DocumentBlock::setModel(DocumentModel* newModel)
-{
- mModel = newModel;
-}
-
-QQuickTextDocument* DocumentBlock::getDoc() const
+QQuickTextDocument* DocumentHandler::getDoc() const
{
return mDoc;
}
-void DocumentBlock::setDoc(QQuickTextDocument* newDoc)
+void DocumentHandler::setDoc(QQuickTextDocument* newDoc)
{
if (mDoc != newDoc) {
- if (mDoc) {
- disconnect(mDoc->textDocument(), nullptr, this, nullptr);
- }
+ auto oldDoc = mDoc;
mDoc = newDoc;
+
+ if (oldDoc) {
+ disconnect(oldDoc->textDocument(), nullptr, this, nullptr);
+ }
if (newDoc) {
connect(newDoc->textDocument(), &QTextDocument::modificationChanged, this, [&]() {
// TODO add a timer to wait for 1 second before updating?
@@ -37,42 +31,122 @@ void DocumentBlock::setDoc(QQuickTextDocument* newDoc)
emit modificationChanged();
});
}
- emit docChanged();
+
+ emit docChanged(oldDoc);
}
}
-const QDateTime& DocumentBlock::getModifyTime() const
+const QDateTime& DocumentHandler::getModifyTime() const
{
return mModifyTime;
}
-void DocumentModel::appendBlock(DocumentBlock* block)
+int DocumentHandler::getCursorPos() const
+{
+ return mCursorPos;
+}
+
+void DocumentHandler::setCursorPos(int newCursorPos)
{
- mBlocks.push_back(block);
+ if (mCursorPos == newCursorPos) {
+ return;
+ }
+ mCursorPos = newCursorPos;
+ emit cursorPosChanged();
}
-int DocumentModel::rowCount(const QModelIndex& parent) const
+int DocumentHandler::getSelectionBegin() const
{
- return mBlocks.size();
+ return mSelectionBegin;
}
-QVariant DocumentModel::data(const QModelIndex& index, int role) const
+void DocumentHandler::setSelectionBegin(int newSelectionBegin)
{
- if (index.row() < 0 || index.row() >= mBlocks.size()) {
- return QVariant();
+ if (mSelectionBegin == newSelectionBegin) {
+ return;
}
+ mSelectionBegin = newSelectionBegin;
+ emit selectionBeginChanged();
+}
- switch (role) {
- case Qt::DisplayRole: return QVariant::fromValue(mBlocks[index.row()]);
- case ModifyTimeRole: return mBlocks[index.row()]->getModifyTime();
- default: return QVariant();
+int DocumentHandler::getSelectionEnd() const
+{
+ return mSelectionEnd;
+}
+
+void DocumentHandler::setSelectionEnd(int newSelectionEnd)
+{
+ if (mSelectionEnd == newSelectionEnd) {
+ return;
}
+ mSelectionEnd = newSelectionEnd;
+ emit selectionEndChanged();
}
-QHash<int, QByteArray> DocumentModel::roleNames() const
+QFont DocumentHandler::getActiveFont() const
{
- QHash<int, QByteArray> roles;
- roles[Qt::DisplayRole] = "display",
- roles[ModifyTimeRole] = "modifyTime";
- return roles;
+ auto cursor = makeTextCursor();
+ if (cursor.isNull()) {
+ return mDoc->textDocument()->defaultFont();
+ }
+ auto format = cursor.charFormat();
+ return format.font();
+}
+
+void DocumentHandler::setActiveFont(const QFont& font)
+{
+ auto cursor = makeTextCursor();
+ if (!cursor.isNull() && cursor.charFormat().font() == font) {
+ return;
+ }
+
+ QTextCharFormat format;
+ format.setFont(font);
+ mergeFormatOnWordOrSelection(format);
+
+ emit activeFontChanged();
+}
+
+QColor DocumentHandler::getActiveTextColor() const
+{
+ auto cursor = makeTextCursor();
+ if (cursor.isNull()) {
+ return QColor(Qt::black);
+ }
+ QTextCharFormat format = cursor.charFormat();
+ return format.foreground().color();
+}
+
+void DocumentHandler::setActiveTextColor(const QColor& color)
+{
+ QTextCharFormat format;
+ format.setForeground(QBrush(color));
+ mergeFormatOnWordOrSelection(format);
+ emit activeTextColorChanged();
+}
+
+QTextCursor DocumentHandler::makeTextCursor() const
+{
+ auto doc = mDoc->textDocument();
+ if (!doc) {
+ return QTextCursor();
+ }
+
+ QTextCursor cursor(doc);
+ if (mSelectionBegin != mSelectionEnd) {
+ cursor.setPosition(mSelectionBegin);
+ cursor.setPosition(mSelectionEnd, QTextCursor::KeepAnchor);
+ } else {
+ cursor.setPosition(mCursorPos);
+ }
+ return cursor;
+}
+
+void DocumentHandler::mergeFormatOnWordOrSelection(const QTextCharFormat& format)
+{
+ auto cursor = makeTextCursor();
+ if (!cursor.hasSelection()) {
+ cursor.select(QTextCursor::WordUnderCursor);
+ }
+ cursor.mergeCharFormat(format);
}
diff --git a/ui.qt/source/document.hpp b/ui.qt/source/document.hpp
index ba11e26..5ef1bba 100644
--- a/ui.qt/source/document.hpp
+++ b/ui.qt/source/document.hpp
@@ -6,57 +6,67 @@
#include <QDateTime>
#include <QObject>
#include <QQuickTextDocument>
+#include <QTextCharFormat>
-class DocumentBlock : public QObject
+// To be instanciated in QML as the logic backend to some TextArea
+class DocumentHandler : public QObject
{
Q_OBJECT
QML_ELEMENT
- Q_PROPERTY(QQuickTextDocument* textDocument READ getDoc WRITE setDoc NOTIFY docChanged)
+ Q_PROPERTY(QQuickTextDocument* document READ getDoc WRITE setDoc NOTIFY docChanged)
+ Q_PROPERTY(QDateTime modifyTime READ getModifyTime NOTIFY modificationChanged)
+
+ Q_PROPERTY(int cursorPos READ getCursorPos WRITE setCursorPos NOTIFY cursorPosChanged)
+ Q_PROPERTY(int selectionBegin READ getSelectionBegin WRITE setSelectionBegin NOTIFY selectionBeginChanged)
+ Q_PROPERTY(int selectionEnd READ getSelectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged)
+
+ Q_PROPERTY(QFont activeFont READ getActiveFont WRITE setActiveFont NOTIFY activeFontChanged)
+ Q_PROPERTY(QColor activeTextColor READ getActiveTextColor WRITE setActiveTextColor NOTIFY activeTextColorChanged)
private:
- DocumentModel* mModel;
QQuickTextDocument* mDoc = nullptr;
QDateTime mModifyTime;
-public:
- explicit DocumentBlock(QObject* parent = nullptr);
+ int mCursorPos;
+ int mSelectionBegin;
+ int mSelectionEnd;
- DocumentModel* getModel() const;
- void setModel(DocumentModel* newModel);
+public:
+ explicit DocumentHandler(QObject* parent = nullptr);
QQuickTextDocument* getDoc() const;
void setDoc(QQuickTextDocument* newDoc);
const QDateTime& getModifyTime() const;
-signals:
- void docChanged();
- void modificationChanged();
-};
+ int getCursorPos() const;
+ void setCursorPos(int newCursorPos);
-class DocumentModel : public QAbstractItemModel
-{
- Q_OBJECT
- QML_ELEMENT
+ int getSelectionBegin() const;
+ void setSelectionBegin(int newSelectionBegin);
-private:
- std::vector<DocumentBlock*> mBlocks;
+ int getSelectionEnd() const;
+ void setSelectionEnd(int newSelectionEnd);
-public:
- enum DocumentRoles {
- ModifyTimeRole = Qt::UserRole + 1,
- };
+ QFont getActiveFont() const;
+ void setActiveFont(const QFont& font);
- DocumentModel(QObject* parent = nullptr);
+ QColor getActiveTextColor() const;
+ void setActiveTextColor(const QColor& color);
- void appendBlock(DocumentBlock* block);
- // TODO
- // void moveBlock()
+signals:
+ void docChanged(QQuickTextDocument* oldDoc);
+ void modificationChanged(); // Redirected from the currently bound document
+
+ void cursorPosChanged();
+ void selectionBeginChanged();
+ void selectionEndChanged();
- int rowCount(const QModelIndex& parent = QModelIndex()) const override;
- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+ void activeFontChanged();
+ void activeTextColorChanged();
-protected:
- QHash<int, QByteArray> roleNames() const override;
+private:
+ QTextCursor makeTextCursor() const;
+ void mergeFormatOnWordOrSelection(const QTextCharFormat& format);
};
diff --git a/ui.qt/source/fwd.hpp b/ui.qt/source/fwd.hpp
index 7f98627..7a24ded 100644
--- a/ui.qt/source/fwd.hpp
+++ b/ui.qt/source/fwd.hpp
@@ -1,8 +1,7 @@
#pragma once
// document.hpp
-class DocumentBlock;
-class DocumentModel;
+class DocumentHandler;
// keyword.hpp
class Keyword;
diff --git a/ui.qt/source/main.cpp b/ui.qt/source/main.cpp
index e92863f..fab148c 100644
--- a/ui.qt/source/main.cpp
+++ b/ui.qt/source/main.cpp
@@ -1,13 +1,13 @@
-#include <QGuiApplication>
+#include <QApplication>
#include <QLocale>
#include <QQmlApplicationEngine>
#include <QTranslator>
int main(int argc, char *argv[])
{
- QGuiApplication app(argc, argv);
+ QApplication app(argc, argv);
- QTranslator translator;
+ QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString& locale : uiLanguages) {
const QString baseName = "EpistmoolUI_" + QLocale(locale).name();
diff --git a/ui.qt/source/qml/Document.qml b/ui.qt/source/qml/Document.qml
index e62b731..a3d4075 100644
--- a/ui.qt/source/qml/Document.qml
+++ b/ui.qt/source/qml/Document.qml
@@ -1,39 +1,163 @@
import QtCore
import QtQuick
import QtQuick.Controls
+import QtQuick.Dialogs
+import Qt.labs.platform as Platform
import EpistmoolUI
Item {
- DocumentModel {
- id: documentModel
+ Action {
+ id: boldAction
+ shortcut: StandardKey.Bold
+ onTriggered: docHandler.bold = !docHandler.bold
}
- ScrollView {
- id: scrollView
+ Action {
+ id: italicAction
+ shortcut: StandardKey.Italic
+ onTriggered: docHandler.italic = !docHandler.italic
+ }
+
+ Action {
+ id: underlineAction
+ shortcut: StandardKey.Underline
+ onTriggered: docHandler.underline = !docHandler.underline
+ }
+
+ Action {
+ id: strikeoutAction
+ shortcut: "Ctrl+Shift+X"
+ onTriggered: docHandler.strikeout = !docHandler.strikeout
+ }
- ListView {
- id: listView
- model: documentModel
- anchors.fill: parent
+ Platform.ColorDialog {
+ id: colorDialog
+ currentColor: "black"
+ }
+
+ Item {
+ id: toolbar
+ width: parent.width
+ height: childrenRect.height
+
+ Row {
+ id: toolbarLeft
+ layoutDirection: Qt.LeftToRight
+
+ ToolButton {
+ id: boldButton
+ text: "B"
+ font.bold: true
+ focusPolicy: Qt.TabFocus
+ checkable: true
+ checked: docHandler.bold
+ action: boldAction
+ }
+ ToolButton {
+ id: italicButton
+ text: "I"
+ font.italic: true
+ focusPolicy: Qt.TabFocus
+ checkable: true
+ checked: docHandler.italic
+ action: italicAction
+ }
+ ToolButton {
+ id: underlineButton
+ text: "U"
+ font.underline: true
+ focusPolicy: Qt.TabFocus
+ checkable: true
+ checked: docHandler.underline
+ action: underlineAction
+ }
+ ToolButton {
+ id: strikeoutButton
+ text: "S"
+ font.strikeout: true
+ focusPolicy: Qt.TabFocus
+ checkable: true
+ checked: docHandler.strikeout
+ action: strikeoutAction
+ }
+ ToolButton {
+ id: textColorButton
+ text: "\uF1FC" // icon-brush
+ font.family: "fontello"
+ focusPolicy: Qt.TabFocus
+ onClicked: colorDialog.open()
- delegate: Item {
- required property DocumentBlock documentBlock
- required property date modifyTime
+ Rectangle {
+ width: aFontMetrics.width + 3
+ height: 2
+ color: docHandler.activeTextColor
+ parent: textColorButton.contentItem
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.baseline: parent.baseline
+ anchors.baselineOffset: 6
- Component.onCompleted: {
- documentBlock.textDocument = textArea.textDocument
+ TextMetrics {
+ id: aFontMetrics
+ font: textColorButton.font
+ text: textColorButton.text
+ }
}
+ }
+ }
+
+ Row {
+ id: toolbarRight
+ layoutDirection: Qt.RightToLeft
+ height: parent.height
+ anchors.left: toolbarLeft.right
+ anchors.right: parent.right
+
+ Label {
+ text: docHandler.modifyTime.toLocaleTimeString()
- TextArea {
- id: textArea
- textFormat: Qt.RichText
- wrapMode: TextArea.Wrap
- focus: true
- selectByMouse: true
- persistentSelection: true
+ ToolTip.visible: ma.containsMouse
+ ToolTip.text: docHandler.modifyTime.toLocaleString()
+
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ hoverEnabled: true
}
}
}
}
+
+ DocumentHandler {
+ id: docHandler
+ document: textArea.textDocument
+
+ // Binding for current editing state of the TextArea
+ cursorPos: textArea.cursorPosition
+ selectionBegin: textArea.selectionStart
+ selectionEnd: textArea.selectionEnd
+
+ property alias family: docHandler.activeFont.family
+ property alias bold: docHandler.activeFont.bold
+ property alias italic: docHandler.activeFont.italic
+ property alias underline: docHandler.activeFont.underline
+ property alias strikeout: docHandler.activeFont.strikeout
+ property alias size: docHandler.activeFont.pointSize
+ }
+
+ ScrollView {
+ id: scrollView
+ width: parent.width
+ anchors.top: toolbar.bottom
+ anchors.bottom: parent.bottom
+
+ TextArea {
+ id: textArea
+ textFormat: Qt.RichText
+ wrapMode: TextArea.Wrap
+ focus: true
+ selectByMouse: true
+ persistentSelection: true
+ }
+ }
}
diff --git a/ui.qt/source/qml/MainWindow.qml b/ui.qt/source/qml/MainWindow.qml
index 905f0e8..d81fb4f 100644
--- a/ui.qt/source/qml/MainWindow.qml
+++ b/ui.qt/source/qml/MainWindow.qml
@@ -6,7 +6,16 @@ Window {
visible: true
title: qsTr("Hello World")
+ Navigator {
+ id: navigator
+ width: childrenRect.width
+ height: parent.height
+ }
+
Document {
- id: doc
+ id: document
+ height: parent.height
+ anchors.left: navigator.right
+ anchors.right: parent.right
}
}
diff --git a/ui.qt/source/qml/Navigator.qml b/ui.qt/source/qml/Navigator.qml
new file mode 100644
index 0000000..40c66e4
--- /dev/null
+++ b/ui.qt/source/qml/Navigator.qml
@@ -0,0 +1,36 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ ColumnLayout {
+ spacing: 0
+
+ Button {
+ contentItem: Label {
+ text: qsTr("Settings")
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Layout.fillWidth: true
+ }
+
+ Button {
+ contentItem: Label {
+ text: qsTr("Keyword")
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Layout.fillWidth: true
+ }
+
+ Button {
+ contentItem: Label {
+ text: qsTr("Knowledge Fragments")
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Layout.fillWidth: true
+ }
+ }
+}