summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2019-11-08 14:39:45 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2019-11-23 20:06:15 +0100
commit2bfb885b4739dae46a35cfc5b1c62767b3900da9 (patch)
tree753fa8ae89671057adea30cb0e0cc53c0a4c0cf0
parentMake replies format nicer (diff)
downloadnheko-2bfb885b4739dae46a35cfc5b1c62767b3900da9.tar.xz
optionally use QQuickWidget and replace ColorOverlay -> colorImageProvider
-rw-r--r--CMakeLists.txt4
-rw-r--r--resources/qml/EncryptionIndicator.qml8
-rw-r--r--resources/qml/ImageButton.qml9
-rw-r--r--resources/qml/StatusIndicator.qml15
-rw-r--r--resources/qml/TimelineRow.qml4
-rw-r--r--resources/qml/TimelineView.qml238
-rw-r--r--src/ColorImageProvider.cpp30
-rw-r--r--src/ColorImageProvider.h11
-rw-r--r--src/timeline2/DelegateChooser.cpp1
-rw-r--r--src/timeline2/TimelineModel.cpp2
-rw-r--r--src/timeline2/TimelineViewManager.cpp14
-rw-r--r--src/timeline2/TimelineViewManager.h7
12 files changed, 194 insertions, 149 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ae9a5e46..a7cddc50 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,7 +69,7 @@ include(LMDB)
 #
 # Discover Qt dependencies.
 #
-find_package(Qt5 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia Qml QuickControls2 REQUIRED)
+find_package(Qt5 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia Qml QuickControls2 QuickWidgets REQUIRED)
 find_package(Qt5QuickCompiler)
 find_package(Qt5DBus)
 
@@ -234,6 +234,7 @@ set(SRC_FILES
     src/MainWindow.cpp
     src/MatrixClient.cpp
     src/MxcImageProvider.cpp
+    src/ColorImageProvider.cpp
     src/QuickSwitcher.cpp
     src/Olm.cpp
     src/RegisterPage.cpp
@@ -414,6 +415,7 @@ set(COMMON_LIBS
     Qt5::Multimedia
     Qt5::Qml
     Qt5::QuickControls2
+    Qt5::QuickWidgets
     nlohmann_json::nlohmann_json)
 
 if(APPVEYOR_BUILD)
diff --git a/resources/qml/EncryptionIndicator.qml b/resources/qml/EncryptionIndicator.qml
index 0d0e86cf..2cd9161b 100644
--- a/resources/qml/EncryptionIndicator.qml
+++ b/resources/qml/EncryptionIndicator.qml
@@ -1,6 +1,5 @@
 import QtQuick 2.5
 import QtQuick.Controls 2.1
-import QtGraphicalEffects 1.0
 import com.github.nheko 1.0
 
 Rectangle {
@@ -19,12 +18,7 @@ Rectangle {
 	Image {
 		id: stateImg
 		anchors.fill: parent
-		source: "qrc:/icons/icons/ui/lock.png"
-	}
-	ColorOverlay {
-		anchors.fill: stateImg
-		source: stateImg
-		color: colors.buttonText
+		source: "image://colorimage/:/icons/icons/ui/lock.png?"+colors.buttonText
 	}
 }
 
diff --git a/resources/qml/ImageButton.qml b/resources/qml/ImageButton.qml
index dda9865b..dc576e18 100644
--- a/resources/qml/ImageButton.qml
+++ b/resources/qml/ImageButton.qml
@@ -1,9 +1,8 @@
 import QtQuick 2.3
 import QtQuick.Controls 2.3
-import QtGraphicalEffects 1.0
 
 Button {
-	property alias image: buttonImg.source
+	property string image: undefined
 
 	id: button
 
@@ -17,11 +16,7 @@ Button {
 		id: buttonImg
 		// Workaround, can't get icon.source working for now...
 		anchors.fill: parent
-	}
-	ColorOverlay {
-		anchors.fill: buttonImg
-		source: buttonImg
-		color: button.hovered ? colors.highlight : colors.buttonText
+		source: "image://colorimage/" + image + "?" + (button.hovered ? colors.highlight : colors.buttonText)
 	}
 
 	MouseArea
diff --git a/resources/qml/StatusIndicator.qml b/resources/qml/StatusIndicator.qml
index 9f8d2cae..2ed59a17 100644
--- a/resources/qml/StatusIndicator.qml
+++ b/resources/qml/StatusIndicator.qml
@@ -1,6 +1,5 @@
 import QtQuick 2.5
 import QtQuick.Controls 2.1
-import QtGraphicalEffects 1.0
 import com.github.nheko 1.0
 
 Rectangle {
@@ -28,18 +27,12 @@ Rectangle {
 		// Workaround, can't get icon.source working for now...
 		anchors.fill: parent
 		source: switch (indicator.state) {
-			case MtxEvent.Failed: return "qrc:/icons/icons/ui/remove-symbol.png"
-			case MtxEvent.Sent: return "qrc:/icons/icons/ui/clock.png"
-			case MtxEvent.Received: return "qrc:/icons/icons/ui/checkmark.png"
-			case MtxEvent.Read: return "qrc:/icons/icons/ui/double-tick-indicator.png"
+			case MtxEvent.Failed: return "image://colorimage/:/icons/icons/ui/remove-symbol.png?" + colors.buttonText
+			case MtxEvent.Sent: return "image://colorimage/:/icons/icons/ui/clock.png?" + colors.buttonText
+			case MtxEvent.Received: return "image://colorimage/:/icons/icons/ui/checkmark.png?" + colors.buttonText
+			case MtxEvent.Read: return "image://colorimage/:/icons/icons/ui/double-tick-indicator.png?" + colors.buttonText
 			default: return ""
 		}
 	}
-	ColorOverlay {
-		anchors.fill: stateImg
-		source: stateImg
-		color: colors.buttonText
-		visible: stateImg.source != ""
-	}
 }
 
diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index 8f9090e3..63a84701 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -50,7 +50,7 @@ RowLayout {
 		Layout.preferredHeight: 16
 		id: replyButton
 
-		image: "qrc:/icons/icons/ui/mail-reply.png"
+		image: ":/icons/icons/ui/mail-reply.png"
 		ToolTip {
 			visible: replyButton.hovered
 			text: qsTr("Reply")
@@ -64,7 +64,7 @@ RowLayout {
 		Layout.preferredHeight: 16
 		id: optionsButton
 
-		image: "qrc:/icons/icons/ui/vertical-ellipsis.png"
+		image: ":/icons/icons/ui/vertical-ellipsis.png"
 		ToolTip {
 			visible: optionsButton.hovered
 			text: qsTr("Options")
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index c2f6f9b9..b25b3a7c 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -8,151 +8,151 @@ import com.github.nheko 1.0
 
 import "./delegates"
 
-Rectangle {
-	anchors.fill: parent
-
+Item {
 	property var colors: currentActivePalette
 	property var systemInactive: SystemPalette { colorGroup: SystemPalette.Disabled }
 	property var inactiveColors: currentInactivePalette ? currentInactivePalette : systemInactive
 	property int avatarSize: 40
 
-	color: colors.window
-
-	Text {
-		visible: !timelineManager.timeline
-		anchors.centerIn: parent
-		text: qsTr("No room open")
-		font.pointSize: 24
-		color: colors.windowText
-	}
+	Rectangle {
+		anchors.fill: parent
+		color: colors.window
+
+		Text {
+			visible: !timelineManager.timeline
+			anchors.centerIn: parent
+			text: qsTr("No room open")
+			font.pointSize: 24
+			color: colors.windowText
+		}
 
-	ListView {
-		id: chat
+		ListView {
+			id: chat
 
-		cacheBuffer: 2000
+			cacheBuffer: 2000
 
-		visible: timelineManager.timeline != null
-		anchors.fill: parent
+			visible: timelineManager.timeline != null
+			anchors.fill: parent
 
-		anchors.leftMargin: 4
-		anchors.rightMargin: scrollbar.width
+			anchors.leftMargin: 4
+			anchors.rightMargin: scrollbar.width
 
-		model: timelineManager.timeline
+			model: timelineManager.timeline
 
-		onModelChanged: {
-			if (model) {
-				currentIndex = model.currentIndex
-				if (model.currentIndex == count - 1) {
-					positionViewAtEnd()
-				} else {
-					positionViewAtIndex(model.currentIndex, ListView.End)
-				}
+			onModelChanged: {
+				if (model) {
+					currentIndex = model.currentIndex
+					if (model.currentIndex == count - 1) {
+						positionViewAtEnd()
+					} else {
+						positionViewAtIndex(model.currentIndex, ListView.End)
+					}
 
-				if (contentHeight < height) {
-					model.fetchHistory();
+					//if (contentHeight < height) {
+					//	model.fetchHistory();
+					//}
 				}
 			}
-		}
 
-		ScrollBar.vertical: ScrollBar {
-			id: scrollbar
-			anchors.top: parent.top
-			anchors.left: parent.right
-			anchors.bottom: parent.bottom
-			onPressedChanged: if (!pressed) chat.updatePosition()
-		}
-
-		property bool atBottom: false
-		onCountChanged: {
-			if (atBottom && Window.active) {
-				var newIndex = count - 1 // last index
-				positionViewAtEnd()
-				currentIndex = newIndex
-				model.currentIndex = newIndex
+			ScrollBar.vertical: ScrollBar {
+				id: scrollbar
+				anchors.top: parent.top
+				anchors.left: parent.right
+				anchors.bottom: parent.bottom
+				onPressedChanged: if (!pressed) chat.updatePosition()
 			}
 
-			if (contentHeight < height && model) {
-				model.fetchHistory();
-			}
-		}
+			property bool atBottom: false
+			onCountChanged: {
+				if (atBottom) {
+					var newIndex = count - 1 // last index
+					positionViewAtEnd()
+					currentIndex = newIndex
+					model.currentIndex = newIndex
+				}
 
-		onAtYBeginningChanged: if (atYBeginning) model.fetchHistory()
-
-		function updatePosition() {
-			for (var y = chat.contentY + chat.height; y > chat.height; y -= 5) {
-				var i = chat.itemAt(100, y);
-				if (!i) continue;
-				if (!i.isFullyVisible()) continue;
-				chat.model.currentIndex = i.getIndex();
-				chat.currentIndex = i.getIndex()
-				atBottom = i.getIndex() == count - 1;
-				console.log("bottom:" + atBottom)
-				break;
+				if (contentHeight < height && model) {
+					model.fetchHistory();
+				}
 			}
-		}
-		onMovementEnded: updatePosition()
 
-		spacing: 4
-		delegate: TimelineRow {
-			function isFullyVisible() {
-				return height > 1 && (y - chat.contentY - 1) + height < chat.height
-			}
-			function getIndex() {
-				return index;
+			onAtYBeginningChanged: if (atYBeginning) model.fetchHistory()
+
+			function updatePosition() {
+				for (var y = chat.contentY + chat.height; y > chat.height; y -= 9) {
+					var i = chat.itemAt(100, y);
+					if (!i) continue;
+					if (!i.isFullyVisible()) continue;
+					chat.model.currentIndex = i.getIndex();
+					chat.currentIndex = i.getIndex()
+					atBottom = i.getIndex() == count - 1;
+					break;
+				}
 			}
-		}
+			onMovementEnded: updatePosition()
 
-		section {
-			property: "section"
-			delegate: Column {
-				topPadding: 4
-				bottomPadding: 4
-				spacing: 8
-
-				width: parent.width
-				height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8
-
-				Label {
-					id: dateBubble
-					anchors.horizontalCenter: parent.horizontalCenter
-					visible: section.includes(" ")
-					text: chat.model.formatDateSeparator(new Date(Number(section.split(" ")[1])))
-					color: colors.windowText
-
-					height: contentHeight * 1.2
-					width: contentWidth * 1.2
-					horizontalAlignment: Text.AlignHCenter
-					background: Rectangle {
-						radius: parent.height / 2
-						color: colors.dark
-					}
+			spacing: 4
+			delegate: TimelineRow {
+				function isFullyVisible() {
+					return height > 1 && (y - chat.contentY - 1) + height < chat.height
 				}
-				Row {
-					height: userName.height
-					spacing: 4
-					Avatar {
-						width: avatarSize
-						height: avatarSize
-						url: chat.model.avatarUrl(section.split(" ")[0]).replace("mxc://", "image://MxcImage/")
-						displayName: chat.model.displayName(section.split(" ")[0])
-
-						MouseArea {
-							anchors.fill: parent
-							onClicked: chat.model.openUserProfile(section.split(" ")[0])
-							cursorShape: Qt.PointingHandCursor
+				function getIndex() {
+					return index;
+				}
+			}
+
+			section {
+				property: "section"
+				delegate: Column {
+					topPadding: 4
+					bottomPadding: 4
+					spacing: 8
+
+					width: parent.width
+					height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8
+
+					Label {
+						id: dateBubble
+						anchors.horizontalCenter: parent.horizontalCenter
+						visible: section.includes(" ")
+						text: chat.model.formatDateSeparator(new Date(Number(section.split(" ")[1])))
+						color: colors.windowText
+
+						height: contentHeight * 1.2
+						width: contentWidth * 1.2
+						horizontalAlignment: Text.AlignHCenter
+						background: Rectangle {
+							radius: parent.height / 2
+							color: colors.dark
 						}
 					}
+					Row {
+						height: userName.height
+						spacing: 4
+						Avatar {
+							width: avatarSize
+							height: avatarSize
+							url: chat.model.avatarUrl(section.split(" ")[0]).replace("mxc://", "image://MxcImage/")
+							displayName: chat.model.displayName(section.split(" ")[0])
+
+							MouseArea {
+								anchors.fill: parent
+								onClicked: chat.model.openUserProfile(section.split(" ")[0])
+								cursorShape: Qt.PointingHandCursor
+							}
+						}
 
-					Text { 
-						id: userName
-						text: chat.model.escapeEmoji(chat.model.displayName(section.split(" ")[0]))
-						color: chat.model.userColor(section.split(" ")[0], colors.window)
-						textFormat: Text.RichText
-
-						MouseArea {
-							anchors.fill: parent
-							onClicked: chat.model.openUserProfile(section.split(" ")[0])
-							cursorShape: Qt.PointingHandCursor
+						Text { 
+							id: userName
+							text: chat.model.escapeEmoji(chat.model.displayName(section.split(" ")[0]))
+							color: chat.model.userColor(section.split(" ")[0], colors.window)
+							textFormat: Text.RichText
+
+							MouseArea {
+								anchors.fill: parent
+								onClicked: chat.model.openUserProfile(section.split(" ")[0])
+								cursorShape: Qt.PointingHandCursor
+							}
 						}
 					}
 				}
diff --git a/src/ColorImageProvider.cpp b/src/ColorImageProvider.cpp
new file mode 100644
index 00000000..92e4732b
--- /dev/null
+++ b/src/ColorImageProvider.cpp
@@ -0,0 +1,30 @@
+#include "ColorImageProvider.h"
+
+#include "Logging.h"
+#include <QPainter>
+
+QPixmap
+ColorImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &)
+{
+        auto args = id.split('?');
+
+        nhlog::ui()->info("Loading {}, source is {}", id.toStdString(), args[0].toStdString());
+
+        QPixmap source(args[0]);
+
+        if (size)
+                *size = QSize(source.width(), source.height());
+
+        if (args.size() < 2)
+                return source;
+
+        QColor color(args[1]);
+
+        QPixmap colorized = source;
+        QPainter painter(&colorized);
+        painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+        painter.fillRect(colorized.rect(), color);
+        painter.end();
+
+        return colorized;
+}
diff --git a/src/ColorImageProvider.h b/src/ColorImageProvider.h
new file mode 100644
index 00000000..21f36c12
--- /dev/null
+++ b/src/ColorImageProvider.h
@@ -0,0 +1,11 @@
+#include <QQuickImageProvider>
+
+class ColorImageProvider : public QQuickImageProvider
+{
+public:
+        ColorImageProvider()
+          : QQuickImageProvider(QQuickImageProvider::Pixmap)
+        {}
+
+        QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
+};
diff --git a/src/timeline2/DelegateChooser.cpp b/src/timeline2/DelegateChooser.cpp
index 6aeea69b..632a2a64 100644
--- a/src/timeline2/DelegateChooser.cpp
+++ b/src/timeline2/DelegateChooser.cpp
@@ -119,7 +119,6 @@ DelegateChooser::DelegateIncubator::statusChanged(QQmlIncubator::Status status)
                 chooser.child = dynamic_cast<QQuickItem *>(object());
                 if (chooser.child == nullptr) {
                         nhlog::ui()->error("Delegate has to be derived of Item!");
-                        delete chooser.child;
                         return;
                 }
 
diff --git a/src/timeline2/TimelineModel.cpp b/src/timeline2/TimelineModel.cpp
index b2b6f803..ab7d3d47 100644
--- a/src/timeline2/TimelineModel.cpp
+++ b/src/timeline2/TimelineModel.cpp
@@ -844,7 +844,7 @@ TimelineModel::replyAction(QString id)
                   return related_;
           },
           event);
-        related.type = mtx::events::getMessageType(boost::apply_visitor(
+        related.type        = mtx::events::getMessageType(boost::apply_visitor(
           [](const auto &e) -> std::string { return eventMsgType(e); }, event));
         related.quoted_body = boost::apply_visitor(
           [](const auto &e) -> QString { return eventFormattedBody(e); }, event);
diff --git a/src/timeline2/TimelineViewManager.cpp b/src/timeline2/TimelineViewManager.cpp
index a054bc78..d733ad90 100644
--- a/src/timeline2/TimelineViewManager.cpp
+++ b/src/timeline2/TimelineViewManager.cpp
@@ -8,6 +8,7 @@
 #include <QStandardPaths>
 
 #include "ChatPage.h"
+#include "ColorImageProvider.h"
 #include "DelegateChooser.h"
 #include "Logging.h"
 #include "MxcImageProvider.h"
@@ -51,6 +52,7 @@ TimelineViewManager::updateColorPalette()
 
 TimelineViewManager::TimelineViewManager(QWidget *parent)
   : imgProvider(new MxcImageProvider())
+  , colorImgProvider(new ColorImageProvider())
 {
         qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
                                          "com.github.nheko",
@@ -61,12 +63,24 @@ TimelineViewManager::TimelineViewManager(QWidget *parent)
         qmlRegisterType<DelegateChoice>("com.github.nheko", 1, 0, "DelegateChoice");
         qmlRegisterType<DelegateChooser>("com.github.nheko", 1, 0, "DelegateChooser");
 
+#ifdef USE_QUICK_VIEW
         view      = new QQuickView();
         container = QWidget::createWindowContainer(view, parent);
+#else
+        view      = new QQuickWidget(parent);
+        container = view;
+        view->setResizeMode(QQuickWidget::SizeRootObjectToView);
+        container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+        connect(view, &QQuickWidget::statusChanged, this, [](QQuickWidget::Status status) {
+                nhlog::ui()->debug("Status changed to {}", status);
+        });
+#endif
         container->setMinimumSize(200, 200);
         view->rootContext()->setContextProperty("timelineManager", this);
         updateColorPalette();
         view->engine()->addImageProvider("MxcImage", imgProvider);
+        view->engine()->addImageProvider("colorimage", colorImgProvider);
         view->setSource(QUrl("qrc:///qml/TimelineView.qml"));
 
         connect(dynamic_cast<ChatPage *>(parent),
diff --git a/src/timeline2/TimelineViewManager.h b/src/timeline2/TimelineViewManager.h
index b14e78ff..691c8ddb 100644
--- a/src/timeline2/TimelineViewManager.h
+++ b/src/timeline2/TimelineViewManager.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <QQuickView>
+#include <QQuickWidget>
 #include <QSharedPointer>
 #include <QWidget>
 
@@ -16,6 +17,7 @@
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 
 class MxcImageProvider;
+class ColorImageProvider;
 
 class TimelineViewManager : public QObject
 {
@@ -99,10 +101,15 @@ public slots:
                                uint64_t dsize);
 
 private:
+#ifdef USE_QUICK_VIEW
         QQuickView *view;
+#else
+        QQuickWidget *view;
+#endif
         QWidget *container;
         TimelineModel *timeline_ = nullptr;
         MxcImageProvider *imgProvider;
+        ColorImageProvider *colorImgProvider;
 
         QHash<QString, QSharedPointer<TimelineModel>> models;
 };