morpheus

A Matrix client written in Go-QT
git clone git://archive.git.mtrnord.blog/Nordgedanken/morpheus.git
Log | Files | Refs | README | LICENSE

commit 6b6847e4405bbf63abd40c8678918b61d1312d8c
parent 1f5feffcb7ff5bd07504db5c59437509e596fbab
Author: MTRNord <mtrnord1@gmail.com>
Date:   Sat, 14 Oct 2017 00:51:02 +0200

Fix Scrollbar in timeline, fill all fields of a message, generate kind of generic avatars (not finished yet), add linter (lots to do), cleanup a bit of code

Signed-off-by: MTRNord <mtrnord1@gmail.com>

Diffstat:
Delements.go | 36------------------------------------
Melements/messageList.go | 52+++++++++++++++++++++++++++++++++++++---------------
Melements/moc.cpp | 6+++---
Melements/moc.go | 21+++++++++++++--------
Melements/moc.h | 2+-
Melements/moc_moc.h | 15++++++++-------
Alinter.json | 22++++++++++++++++++++++
Mmatrix/ownUser.go | 113++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mqml/ui/chat.ui | 15++++++++++++---
Mqml/ui/message.ui | 283++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Muis.go | 37++++++++++++++++---------------------
11 files changed, 370 insertions(+), 232 deletions(-)

diff --git a/elements.go b/elements.go @@ -1,36 +0,0 @@ -package main - -import ( - "github.com/rhinoman/go-commonmark" - "github.com/therecipe/qt/core" - "github.com/therecipe/qt/gui" - "github.com/therecipe/qt/uitools" - "github.com/therecipe/qt/widgets" -) - -func AddMessage(body string, avatar *gui.QPixmap) *widgets.QWidget { - var widget = widgets.NewQWidget(nil, 0) - - var loader = uitools.NewQUiLoader(nil) - var file = core.NewQFile2(":/qml/ui/message.ui") - - file.Open(core.QIODevice__ReadOnly) - var messageWidget = loader.Load(file, widget) - file.Close() - - var layout = widgets.NewQHBoxLayout() - layout.AddWidget(messageWidget, 1, core.Qt__AlignTop|core.Qt__AlignLeft) - widget.SetLayout(layout) - layout.SetSpacing(0) - layout.SetContentsMargins(0, 0, 0, 0) - - avatarLogo := widgets.NewQLabelFromPointer(widget.FindChild("avatar", core.Qt__FindChildrenRecursively).Pointer()) - messageContent := widgets.NewQLabelFromPointer(widget.FindChild("messageContent", core.Qt__FindChildrenRecursively).Pointer()) - - mardownMessage := commonmark.Md2Html(body, 0) - - messageContent.SetText(mardownMessage) - avatarLogo.SetPixmap(avatar) - - return widget -} diff --git a/elements/messageList.go b/elements/messageList.go @@ -1,30 +1,46 @@ package elements import ( + "github.com/Nordgedanken/Morpheus/matrix" + "github.com/matrix-org/gomatrix" + "github.com/rhinoman/go-commonmark" "github.com/therecipe/qt/core" - "github.com/therecipe/qt/gui" "github.com/therecipe/qt/uitools" "github.com/therecipe/qt/widgets" ) +//////////////////////////////////////////////////// +// // +// // +// // +// // +// DON'T TOUCH I HAVE NO IDEA WHY THIS EVEN WORKS // +// // +// // +// // +//////////////////////////////////////////////////// + type QVBoxLayoutWithTriggerSlot struct { widgets.QVBoxLayout - _ func(messageBody string) `slot:"TriggerMessage"` + _ func(messageBody, sender string) `slot:"TriggerMessage"` } -func NewMessageList() (messageView *widgets.QWidget, messageViewLayout *QVBoxLayoutWithTriggerSlot) { - messageView = widgets.NewQWidget(nil, 0) - +func NewMessageList(scrollArea *widgets.QScrollArea, messageView *widgets.QWidget) (messageViewLayout *QVBoxLayoutWithTriggerSlot) { messageViewLayout = NewQVBoxLayoutWithTriggerSlot2(messageView) messageViewLayout.SetSpacing(0) messageViewLayout.SetContentsMargins(0, 0, 0, 0) + messageView.SetContentsMargins(0, 0, 0, 0) + scrollArea.SetWidget(messageView) + scrollArea.Widget().SetLayout(messageViewLayout) return } -func (messageViewLayout *QVBoxLayoutWithTriggerSlot) NewMessage(messageBody string, widthScrollArea *widgets.QScrollArea, chatWidget *widgets.QWidget) { +func (messageViewLayout *QVBoxLayoutWithTriggerSlot) NewMessage(body string, cli *gomatrix.Client, sender string, scrollArea *widgets.QScrollArea) { + avatar := matrix.GetUserAvatar(cli, sender) + var widget = widgets.NewQWidget(nil, 0) var loader = uitools.NewQUiLoader(nil) @@ -35,23 +51,29 @@ func (messageViewLayout *QVBoxLayoutWithTriggerSlot) NewMessage(messageBody stri file.Close() messageWidget := widgets.NewQWidgetFromPointer(widget.FindChild("message", core.Qt__FindChildrenRecursively).Pointer()) - message := widgets.NewQLabelFromPointer(widget.FindChild("messageContent", core.Qt__FindChildrenRecursively).Pointer()) + avatarLogo := widgets.NewQLabelFromPointer(widget.FindChild("avatar", core.Qt__FindChildrenRecursively).Pointer()) + messageContent := widgets.NewQLabelFromPointer(widget.FindChild("messageContent", core.Qt__FindChildrenRecursively).Pointer()) + senderContent := widgets.NewQLabelFromPointer(widget.FindChild("sender", core.Qt__FindChildrenRecursively).Pointer()) - chatWidget.ConnectResizeEvent(func(event *gui.QResizeEvent) { - messageWidget.SetMinimumSize2(widthScrollArea.Size().Width(), wrapperWidget.Size().Height()) - message.SetMinimumWidth(widthScrollArea.Size().Width()) - }) + markdownMessage := commonmark.Md2Html(body, 0) - message.SetText(messageBody) - message.SetMinimumWidth(widthScrollArea.Size().Width()) + messageContent.SetText(markdownMessage) - messageWidget.SetMinimumSize2(widthScrollArea.Size().Width(), wrapperWidget.Size().Height()) + senderDisplayNameResp, _ := cli.GetDisplayName(sender) + senderDisplayName := senderDisplayNameResp.DisplayName + senderContent.SetText(senderDisplayName) + avatarLogo.SetPixmap(avatar) + + messageContent.SetMinimumWidth(messageContent.LineWidth()) + + messageWidget.SetMinimumWidth(messageContent.LineWidth() + 100) messageWidget.Resize(wrapperWidget.Size()) messageViewLayout.SetSpacing(0) + messageViewLayout.SetContentsMargins(0, 0, 0, 0) - messageViewLayout.AddLayout(messageWidget.Layout(), 1) messageViewLayout.AddWidget(messageWidget, 0, core.Qt__AlignBottom) + scrollArea.Widget().SetLayout(messageViewLayout) return } diff --git a/elements/moc.cpp b/elements/moc.cpp @@ -66,7 +66,7 @@ public: QWidget * widget() { return static_cast<QWidget*>(callbackQVBoxLayoutWithTriggerSlot_Widget(this)); }; signals: public slots: - void TriggerMessage(QString messageBody) { QByteArray t59bf16 = messageBody.toUtf8(); Moc_PackedString messageBodyPacked = { const_cast<char*>(t59bf16.prepend("WHITESPACE").constData()+10), t59bf16.size()-10 };callbackQVBoxLayoutWithTriggerSlot_TriggerMessage(this, messageBodyPacked); }; + void TriggerMessage(QString messageBody, QString sender) { QByteArray t59bf16 = messageBody.toUtf8(); Moc_PackedString messageBodyPacked = { const_cast<char*>(t59bf16.prepend("WHITESPACE").constData()+10), t59bf16.size()-10 };QByteArray tacc6a3 = sender.toUtf8(); Moc_PackedString senderPacked = { const_cast<char*>(tacc6a3.prepend("WHITESPACE").constData()+10), tacc6a3.size()-10 };callbackQVBoxLayoutWithTriggerSlot_TriggerMessage(this, messageBodyPacked, senderPacked); }; private: }; @@ -76,9 +76,9 @@ Q_DECLARE_METATYPE(QVBoxLayoutWithTriggerSlot*) void QVBoxLayoutWithTriggerSlot_QVBoxLayoutWithTriggerSlot_QRegisterMetaTypes() { } -void QVBoxLayoutWithTriggerSlot_TriggerMessage(void* ptr, struct Moc_PackedString messageBody) +void QVBoxLayoutWithTriggerSlot_TriggerMessage(void* ptr, struct Moc_PackedString messageBody, struct Moc_PackedString sender) { - QMetaObject::invokeMethod(static_cast<QVBoxLayoutWithTriggerSlot*>(ptr), "TriggerMessage", Q_ARG(QString, QString::fromUtf8(messageBody.data, messageBody.len))); + QMetaObject::invokeMethod(static_cast<QVBoxLayoutWithTriggerSlot*>(ptr), "TriggerMessage", Q_ARG(QString, QString::fromUtf8(messageBody.data, messageBody.len)), Q_ARG(QString, QString::fromUtf8(sender.data, sender.len))); } int QVBoxLayoutWithTriggerSlot_QVBoxLayoutWithTriggerSlot_QRegisterMetaType() diff --git a/elements/moc.go b/elements/moc.go @@ -78,20 +78,20 @@ func callbackQVBoxLayoutWithTriggerSlot_Constructor(ptr unsafe.Pointer) { } //export callbackQVBoxLayoutWithTriggerSlot_TriggerMessage -func callbackQVBoxLayoutWithTriggerSlot_TriggerMessage(ptr unsafe.Pointer, messageBody C.struct_Moc_PackedString) { +func callbackQVBoxLayoutWithTriggerSlot_TriggerMessage(ptr unsafe.Pointer, messageBody C.struct_Moc_PackedString, sender C.struct_Moc_PackedString) { if signal := qt.GetSignal(ptr, "TriggerMessage"); signal != nil { - signal.(func(string))(cGoUnpackString(messageBody)) + signal.(func(string, string))(cGoUnpackString(messageBody), cGoUnpackString(sender)) } } -func (ptr *QVBoxLayoutWithTriggerSlot) ConnectTriggerMessage(f func(messageBody string)) { +func (ptr *QVBoxLayoutWithTriggerSlot) ConnectTriggerMessage(f func(messageBody string, sender string)) { if ptr.Pointer() != nil { if signal := qt.LendSignal(ptr.Pointer(), "TriggerMessage"); signal != nil { - qt.ConnectSignal(ptr.Pointer(), "TriggerMessage", func(messageBody string) { - signal.(func(string))(messageBody) - f(messageBody) + qt.ConnectSignal(ptr.Pointer(), "TriggerMessage", func(messageBody string, sender string) { + signal.(func(string, string))(messageBody, sender) + f(messageBody, sender) }) } else { qt.ConnectSignal(ptr.Pointer(), "TriggerMessage", f) @@ -106,14 +106,19 @@ func (ptr *QVBoxLayoutWithTriggerSlot) DisconnectTriggerMessage() { } } -func (ptr *QVBoxLayoutWithTriggerSlot) TriggerMessage(messageBody string) { +func (ptr *QVBoxLayoutWithTriggerSlot) TriggerMessage(messageBody string, sender string) { if ptr.Pointer() != nil { var messageBodyC *C.char if messageBody != "" { messageBodyC = C.CString(messageBody) defer C.free(unsafe.Pointer(messageBodyC)) } - C.QVBoxLayoutWithTriggerSlot_TriggerMessage(ptr.Pointer(), C.struct_Moc_PackedString{data: messageBodyC, len: C.longlong(len(messageBody))}) + var senderC *C.char + if sender != "" { + senderC = C.CString(sender) + defer C.free(unsafe.Pointer(senderC)) + } + C.QVBoxLayoutWithTriggerSlot_TriggerMessage(ptr.Pointer(), C.struct_Moc_PackedString{data: messageBodyC, len: C.longlong(len(messageBody))}, C.struct_Moc_PackedString{data: senderC, len: C.longlong(len(sender))}) } } diff --git a/elements/moc.h b/elements/moc.h @@ -15,7 +15,7 @@ extern "C" { struct Moc_PackedString { char* data; long long len; }; struct Moc_PackedList { void* data; long long len; }; -void QVBoxLayoutWithTriggerSlot_TriggerMessage(void* ptr, struct Moc_PackedString messageBody); +void QVBoxLayoutWithTriggerSlot_TriggerMessage(void* ptr, struct Moc_PackedString messageBody, struct Moc_PackedString sender); int QVBoxLayoutWithTriggerSlot_QVBoxLayoutWithTriggerSlot_QRegisterMetaType(); int QVBoxLayoutWithTriggerSlot_QVBoxLayoutWithTriggerSlot_QRegisterMetaType2(char* typeName); int QVBoxLayoutWithTriggerSlot_QVBoxLayoutWithTriggerSlot_QmlRegisterType(); diff --git a/elements/moc_moc.h b/elements/moc_moc.h @@ -20,8 +20,8 @@ QT_BEGIN_MOC_NAMESPACE QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED struct qt_meta_stringdata_QVBoxLayoutWithTriggerSlot_t { - QByteArrayData data[4]; - char stringdata0[55]; + QByteArrayData data[5]; + char stringdata0[62]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ @@ -33,11 +33,12 @@ static const qt_meta_stringdata_QVBoxLayoutWithTriggerSlot_t qt_meta_stringdata_ QT_MOC_LITERAL(0, 0, 26), // "QVBoxLayoutWithTriggerSlot" QT_MOC_LITERAL(1, 27, 14), // "TriggerMessage" QT_MOC_LITERAL(2, 42, 0), // "" -QT_MOC_LITERAL(3, 43, 11) // "messageBody" +QT_MOC_LITERAL(3, 43, 11), // "messageBody" +QT_MOC_LITERAL(4, 55, 6) // "sender" }, "QVBoxLayoutWithTriggerSlot\0TriggerMessage\0" - "\0messageBody" + "\0messageBody\0sender" }; #undef QT_MOC_LITERAL @@ -55,10 +56,10 @@ static const uint qt_meta_data_QVBoxLayoutWithTriggerSlot[] = { 0, // signalCount // slots: name, argc, parameters, tag, flags - 1, 1, 19, 2, 0x0a /* Public */, + 1, 2, 19, 2, 0x0a /* Public */, // slots: parameters - QMetaType::Void, QMetaType::QString, 3, + QMetaType::Void, QMetaType::QString, QMetaType::QString, 3, 4, 0 // eod }; @@ -69,7 +70,7 @@ void QVBoxLayoutWithTriggerSlot::qt_static_metacall(QObject *_o, QMetaObject::Ca QVBoxLayoutWithTriggerSlot *_t = static_cast<QVBoxLayoutWithTriggerSlot *>(_o); Q_UNUSED(_t) switch (_id) { - case 0: _t->TriggerMessage((*reinterpret_cast< QString(*)>(_a[1]))); break; + case 0: _t->TriggerMessage((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break; default: ; } } diff --git a/linter.json b/linter.json @@ -0,0 +1,21 @@ +{ + "Vendor": false, + "Cyclo": 12, + "Deadline": "5m", + "Enable": [ + "vetshadow", + "deadcode", + "gocyclo", + "golint", + "varcheck", + "structcheck", + "ineffassign", + "gas", + "misspell", + "unparam", + "errcheck", + "vet", + "megacheck", + "goconst" + ] +} +\ No newline at end of file diff --git a/matrix/ownUser.go b/matrix/ownUser.go @@ -14,7 +14,10 @@ import ( "image" "image/color" "image/draw" + _ "image/gif" + _ "image/jpeg" "image/png" + "math/rand" ) var localLog *log.Logger @@ -47,6 +50,18 @@ func (c *circle) At(x, y int) color.Color { return color.Alpha{0} } +func generateGenericImages(displayname string) string { + // Create an 100 x 100 image + img := image.NewRGBA(image.Rect(0, 0, 100, 100)) + + // Draw a red dot at (2, 3) + img.Set(50, 50, color.RGBA{uint8(rand.Intn(200)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255}) + + buf := new(bytes.Buffer) + png.Encode(buf, img) + return string(buf.Bytes()) +} + // getOwnUserAvatar returns a *gui.QPixmap of an UserAvatar func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { // Init local vars @@ -77,9 +92,9 @@ func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { // If avatarURL is not empty (aka. has a avatar set) download it at the size of 100x100. Else make the data string empty if avatarURL != "" { hsURL := cli.HomeserverURL.String() - avatarURL_splits := strings.Split(strings.Replace(avatarURL, "mxc://", "", -1), "/") + avatarURLSplits := strings.Split(strings.Replace(avatarURL, "mxc://", "", -1), "/") - urlPath := hsURL + "/_matrix/media/r0/thumbnail/" + avatarURL_splits[0] + "/" + avatarURL_splits[1] + "?width=100&height=100" + urlPath := hsURL + "/_matrix/media/r0/thumbnail/" + avatarURLSplits[0] + "/" + avatarURLSplits[1] + "?width=100&height=100" data, err := cli.MakeRequest("GET", urlPath, nil, nil) if err != nil { @@ -88,7 +103,9 @@ func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { IMGdata = string(data[:]) } else { //TODO Generate default image (Step: AfterUI) - IMGdata = "0" + DisplayNameResp, _ := cli.GetOwnDisplayName() + DisplayName := DisplayNameResp.DisplayName + IMGdata = generateGenericImages(DisplayName) } // Update cache @@ -97,7 +114,91 @@ func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { return nil }) if DBerr != nil { - localLog.Fatalln(DBerr) + localLog.Fatalln("DB ERROR: ", DBerr) + } + } else { + IMGdata = avatarData + } + + r := bytes.NewReader([]byte(IMGdata)) + srcIMG, _, err := image.Decode(r) + if err != nil { + localLog.Println("Decoder error: ", err) + } + + // Convert avatarimage to QPixmap for usage in QT + canvas := image.NewRGBA(srcIMG.Bounds()) + cx := srcIMG.Bounds().Min.X + srcIMG.Bounds().Dx()/2 + cy := srcIMG.Bounds().Min.Y + srcIMG.Bounds().Dy()/2 + draw.DrawMask(canvas, canvas.Bounds(), srcIMG, image.ZP, &circle{image.Point{cx, cy}, 110}, image.ZP, draw.Over) + avatar := gui.NewQPixmap() + buf := new(bytes.Buffer) + Converr := png.Encode(buf, canvas) + if Converr != nil { + localLog.Println("Converting error: ", Converr) + } + + str := fmt.Sprintf("%s", buf) + avatar.LoadFromData(str, uint(len(str)), "", 0) + return avatar +} + +// getOwnUserAvatar returns a *gui.QPixmap of an UserAvatar +func GetUserAvatar(cli *gomatrix.Client, mxid string) *gui.QPixmap { + // Init local vars + var avatarData string + var IMGdata string + + // Get cache + db.View(func(tx *buntdb.Tx) error { + QueryErr := tx.AscendKeys("user:"+mxid+":avatarData100x100", + func(key, value string) bool { + avatarData = value + return true + }) + if QueryErr != nil { + return QueryErr + } + return nil + }) + + //If cache is empty do a ServerQuery + if avatarData == "" { + // Get avatarURL + urlPath := cli.BuildURL("profile", mxid, "avatar_url") + s := struct { + AvatarURL string `json:"avatar_url"` + }{} + + cli.MakeRequest("GET", urlPath, nil, &s) + avatarURL := s.AvatarURL + + // If avatarURL is not empty (aka. has a avatar set) download it at the size of 100x100. Else make the data string empty + if avatarURL != "" { + hsURL := cli.HomeserverURL.String() + avatarURLSplits := strings.Split(strings.Replace(avatarURL, "mxc://", "", -1), "/") + + urlPath := hsURL + "/_matrix/media/r0/thumbnail/" + avatarURLSplits[0] + "/" + avatarURLSplits[1] + "?width=100&height=100" + + data, err := cli.MakeRequest("GET", urlPath, nil, nil) + if err != nil { + localLog.Println(err) + } + IMGdata = string(data[:]) + } else { + //TODO Generate default image (Step: AfterUI) + DisplayNameResp, _ := cli.GetOwnDisplayName() + DisplayName := DisplayNameResp.DisplayName + IMGdata = generateGenericImages(DisplayName) + } + + // Update cache + DBerr := db.Update(func(tx *buntdb.Tx) error { + tx.Set("user:"+mxid+":avatarData100x100", IMGdata, nil) + return nil + }) + if DBerr != nil { + localLog.Fatalln("DB ERROR: ", DBerr) } } else { IMGdata = avatarData @@ -106,7 +207,7 @@ func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { r := bytes.NewReader([]byte(IMGdata)) srcIMG, _, err := image.Decode(r) if err != nil { - localLog.Println(err) + localLog.Println("Decoder error: ", err) } // Convert avatarimage to QPixmap for usage in QT @@ -118,7 +219,7 @@ func GetOwnUserAvatar(cli *gomatrix.Client) *gui.QPixmap { buf := new(bytes.Buffer) Converr := png.Encode(buf, canvas) if Converr != nil { - localLog.Println(Converr) + localLog.Println("Converting error: ", Converr) } str := fmt.Sprintf("%s", buf) diff --git a/qml/ui/chat.ui b/qml/ui/chat.ui @@ -807,10 +807,16 @@ border-radius: 2px;</string> <item> <layout class="QVBoxLayout" name="messageAreaLayout"> <property name="spacing"> - <number>21</number> + <number>9</number> </property> <item> <widget class="QScrollArea" name="messageScroll"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="minimumSize"> <size> <width>901</width> @@ -823,6 +829,9 @@ border-radius: 2px;</string> <property name="widgetResizable"> <bool>true</bool> </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> <widget class="QWidget" name="messagesScrollAreaContent"> <property name="geometry"> <rect> @@ -860,13 +869,13 @@ border-radius: 2px;</string> <number>9</number> </property> <property name="topMargin"> - <number>0</number> + <number>9</number> </property> <property name="rightMargin"> <number>9</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>9</number> </property> <property name="spacing"> <number>0</number> diff --git a/qml/ui/message.ui b/qml/ui/message.ui @@ -16,142 +16,161 @@ <property name="styleSheet"> <string notr="true">background-color:transparent;</string> </property> - <widget class="QWidget" name="widget" native="true"> - <property name="geometry"> - <rect> - <x>107</x> - <y>4</y> - <width>437</width> - <height>77</height> - </rect> + <layout class="QFormLayout" name="formLayout"> + <property name="horizontalSpacing"> + <number>0</number> </property> - <widget class="QLabel" name="messageContent"> - <property name="geometry"> - <rect> - <x>0</x> - <y>27</y> - <width>437</width> - <height>54</height> - </rect> - </property> - <property name="font"> - <font> - <family>Arial</family> - <pointsize>12</pointsize> - <stylestrategy>PreferAntialias</stylestrategy> - </font> - </property> - <property name="styleSheet"> - <string notr="true">background-color: rgb(242, 244, 248); -border: 0; -border-radius:5px;</string> - </property> - <property name="text"> - <string>Test</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="margin"> - <number>4</number> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - </widget> - <widget class="QLabel" name="Sender"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>437</width> - <height>21</height> - </rect> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="text"> - <string>MTRNord</string> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - </widget> - </widget> - <widget class="QWidget" name="widget_2" native="true"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>84</width> - <height>84</height> - </rect> + <property name="verticalSpacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <property name="topMargin"> + <number>0</number> </property> - <layout class="QGridLayout" name="gridLayout"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QWidget" name="widget_3" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="widget_2" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> </property> - <widget class="QLabel" name="avatar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>84</width> - <height>84</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - <property name="pixmap"> - <pixmap>../../../../../../../Downloads/avatar512.png</pixmap> - </property> - <property name="scaledContents"> - <bool>true</bool> - </property> - </widget> - </widget> - </item> - </layout> - </widget> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="widget_3" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>84</width> + <height>84</height> + </size> + </property> + <widget class="QLabel" name="avatar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>84</width> + <height>84</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap>../../../../../../../Downloads/avatar512.png</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QWidget" name="widget" native="true"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="sender"> + <property name="font"> + <font> + <pointsize>12</pointsize> + </font> + </property> + <property name="text"> + <string>MTRNord</string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="messageContent"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <family>Arial</family> + <pointsize>12</pointsize> + <stylestrategy>PreferAntialias</stylestrategy> + </font> + </property> + <property name="styleSheet"> + <string notr="true">background-color: rgb(242, 244, 248); +border: 0; +border-radius:5px;</string> + </property> + <property name="text"> + <string>Test</string> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> </widget> <resources/> <connections/> diff --git a/uis.go b/uis.go @@ -171,6 +171,7 @@ func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client) *widgets.QWi chatWidget.SetGeometry2(0, 0, window.Size().Width(), window.Size().Height()) messageScrollArea := widgets.NewQScrollAreaFromPointer(widget.FindChild("messageScroll", core.Qt__FindChildrenRecursively).Pointer()) + messagesScrollAreaContent := widgets.NewQWidgetFromPointer(widget.FindChild("messagesScrollAreaContent", core.Qt__FindChildrenRecursively).Pointer()) mainWidget.SetWindowTitle("Morpheus - MatrixHQ") var layout = widgets.NewQHBoxLayout() @@ -180,11 +181,21 @@ func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client) *widgets.QWi layout.SetContentsMargins(0, 0, 0, 0) window.ConnectResizeEvent(func(event *gui.QResizeEvent) { + mainWidget.SetMinimumSize2(1, 1) + widget.SetMinimumSize2(1, 1) + chatWidget.SetMinimumSize2(1, 1) + widget.Resize(event.Size()) mainWidget.Resize(event.Size()) chatWidget.Resize(event.Size()) }) + messageScrollArea.ConnectResizeEvent(func(event *gui.QResizeEvent) { + messageScrollArea.SetMinimumSize2(1, 1) + + messageScrollArea.Resize(event.Size()) + }) + //Set Avatar avatarLogo := widgets.NewQLabelFromPointer(widget.FindChild("UserAvatar", core.Qt__FindChildrenRecursively).Pointer()) avatarLogo.SetPixmap(matrix.GetOwnUserAvatar(cli)) @@ -237,29 +248,14 @@ func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client) *widgets.QWi syncer.Store = customStore // Init Message View - messageView, messageListLayout := elements.NewMessageList() + messageListLayout := elements.NewMessageList(messageScrollArea, messagesScrollAreaContent) - messageListLayout.ConnectTriggerMessage(func(messageBody string) { - localLog.Println("messageTriggered:", messageBody) - chatWidgetSize := chatWidget.Size() - widgetSize := widget.Size() - mainWidgetSize := mainWidget.Size() - - messageListLayout.NewMessage(messageBody, messageScrollArea, chatWidget) - - chatWidget.Resize(chatWidgetSize) - widget.Resize(widgetSize) - mainWidget.Resize(mainWidgetSize) + messageListLayout.ConnectTriggerMessage(func(messageBody, sender string) { + messageListLayout.NewMessage(messageBody, cli, sender, messageScrollArea) }) - - messageScrollArea.SetLayout(messageListLayout) + messageScrollArea.SetWidgetResizable(true) messageScrollArea.SetHorizontalScrollBarPolicy(core.Qt__ScrollBarAlwaysOff) - messageScrollArea.SetVerticalScrollBarPolicy(core.Qt__ScrollBarAsNeeded) messageScrollArea.SetContentsMargins(0, 0, 0, 0) - messageView.AdjustSize() - messageView.SetContentsMargins(0, 0, 0, 0) - messageScrollArea.SetWidget(messageView) - messageScrollArea.SetWidgetResizable(false) syncer.OnEventType("m.room.message", func(ev *gomatrix.Event) { msg, _ := ev.Body() @@ -268,8 +264,7 @@ func NewMainUI(windowWidth, windowHeight int, cli *gomatrix.Client) *widgets.QWi id := ev.ID timestamp := ev.Timestamp matrix.CacheMessageEvents(id, sender, room, msg, timestamp, db) - localLog.Println("message:", msg) - messageListLayout.TriggerMessage(msg) + messageListLayout.TriggerMessage(msg, sender) }) // Start Non-blocking sync