summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-10-08 23:52:23 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-10-08 23:52:23 +0200
commitc4d2ec875dfce9c29adab0ec85e4317277b5509d (patch)
tree24a8e3cb996769f3fcf2e96faea8d88365be3269 /src
parentSwitch to manual polishing of event delegates (diff)
downloadnheko-c4d2ec875dfce9c29adab0ec85e4317277b5509d.tar.xz
Fixup reply and state event rendering
Diffstat (limited to 'src')
-rw-r--r--src/timeline/EventDelegateChooser.cpp120
-rw-r--r--src/timeline/EventDelegateChooser.h96
2 files changed, 156 insertions, 60 deletions
diff --git a/src/timeline/EventDelegateChooser.cpp b/src/timeline/EventDelegateChooser.cpp
index 0060907d..a8629b3e 100644
--- a/src/timeline/EventDelegateChooser.cpp
+++ b/src/timeline/EventDelegateChooser.cpp
@@ -97,6 +97,7 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
         return;
 
     item->setParentItem(&chooser);
+    item->setParent(&chooser);
 
     auto roleNames = chooser.room_->roleNames();
     QHash<QByteArray, int> nameToRole;
@@ -106,8 +107,6 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
 
     QHash<int, int> roleToPropIdx;
     std::vector<QModelRoleData> roles;
-    bool isReplyNeeded = false;
-
     // Workaround for https://bugreports.qt.io/browse/QTBUG-98846
     QHash<QString, RequiredPropertyKey> requiredProperties;
     for (const auto &[propKey, prop] :
@@ -124,10 +123,7 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
         if (!prop.isRequired() && !requiredProperties.contains(prop.name()))
             continue;
 
-        if (prop.name() == std::string_view("isReply")) {
-            isReplyNeeded = true;
-            roleToPropIdx.insert(-1, i);
-        } else if (auto role = nameToRole.find(prop.name()); role != nameToRole.end()) {
+        if (auto role = nameToRole.find(prop.name()); role != nameToRole.end()) {
             roleToPropIdx.insert(*role, i);
             roles.emplace_back(*role);
 
@@ -141,6 +137,11 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
     chooser.room_->multiData(currentId, forReply ? chooser.eventId_ : QString(), roles);
 
     Qt::beginPropertyUpdateGroup();
+    auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+      qmlAttachedPropertiesObject<EventDelegateChooser>(obj));
+    Q_ASSERT(attached != nullptr);
+    attached->setIsReply(this->forReply);
+
     for (const auto &role : roles) {
         const auto &roleName = roleNames[role.role()];
         // nhlog::ui()->critical("Setting role {}, {} to {}",
@@ -155,22 +156,25 @@ EventDelegateChooser::DelegateIncubator::setInitialState(QObject *obj)
             QQmlIncubatorPrivate::get(this)->requiredProperties()->remove(*req);
     }
 
-    if (isReplyNeeded) {
-        const auto roleName = QByteArray("isReply");
-        // nhlog::ui()->critical("Setting role {} to {}", roleName.toStdString(), forReply);
-
-        // nhlog::ui()->critical("Setting {}", mo->property(roleToPropIdx[-1]).name());
-        mo->property(roleToPropIdx[-1]).write(obj, forReply);
-
-        if (const auto &req = requiredProperties.find(roleName); req != requiredProperties.end())
-            QQmlIncubatorPrivate::get(this)->requiredProperties()->remove(*req);
-    }
     Qt::endPropertyUpdateGroup();
 
     // setInitialProperties(rolesToSet);
 
     auto update =
       [this, obj, roleToPropIdx = std::move(roleToPropIdx)](const QList<int> &changedRoles) {
+          if (changedRoles.empty() || changedRoles.contains(TimelineModel::Roles::Type)) {
+              int type = chooser.room_
+                           ->dataById(currentId,
+                                      TimelineModel::Roles::Type,
+                                      forReply ? chooser.eventId_ : QString())
+                           .toInt();
+              if (type != oldType) {
+                  nhlog::ui()->debug("Type changed!");
+                  reset(currentId);
+                  return;
+              }
+          }
+
           std::vector<QModelRoleData> rolesToRequest;
 
           if (changedRoles.empty()) {
@@ -233,6 +237,7 @@ EventDelegateChooser::DelegateIncubator::reset(QString id)
       chooser.room_
         ->dataById(id, TimelineModel::Roles::Type, forReply ? chooser.eventId_ : QString())
         .toInt();
+    this->oldType = role;
 
     for (const auto choice : qAsConst(chooser.choices_)) {
         const auto &choiceValue = choice->roleValues();
@@ -293,41 +298,58 @@ EventDelegateChooser::updatePolish()
 
     nhlog::ui()->critical("POLISHING {}", (void *)this);
 
-    if (mainChild) {
-        auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
-          qmlAttachedPropertiesObject<EventDelegateChooser>(mainChild));
-        Q_ASSERT(attached != nullptr);
-
-        // in theory we could also reset the width, but that doesn't seem to work nicely for text
-        // areas because of how they cache it.
-        mainChild->setWidth(maxWidth_);
-        mainChild->ensurePolished();
-        auto width = mainChild->implicitWidth();
-
-        if (width > maxWidth_ || attached->fillWidth())
-            width = maxWidth_;
-
-        nhlog::ui()->debug(
-          "Made event delegate width: {}, {}", width, mainChild->metaObject()->className());
-        mainChild->setWidth(width);
-        mainChild->ensurePolished();
-    }
-
-    if (replyChild) {
-        auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
-          qmlAttachedPropertiesObject<EventDelegateChooser>(replyChild));
-        Q_ASSERT(attached != nullptr);
+    auto layoutItem = [this](QQuickItem *item, int inset) {
+        if (item) {
+            auto attached = qobject_cast<EventDelegateChooserAttachedType *>(
+              qmlAttachedPropertiesObject<EventDelegateChooser>(item));
+            Q_ASSERT(attached != nullptr);
+
+            int maxWidth = maxWidth_ - inset;
+
+            // in theory we could also reset the width, but that doesn't seem to work nicely for
+            // text areas because of how they cache it.
+            if (attached->maxWidth() > 0)
+                item->setWidth(attached->maxWidth());
+            else
+                item->setWidth(maxWidth);
+            item->ensurePolished();
+            auto width = item->implicitWidth();
+
+            if (width < 1 || width > maxWidth)
+                width = maxWidth;
+
+            if (attached->maxWidth() > 0 && width > attached->maxWidth())
+                width = attached->maxWidth();
+
+            if (attached->keepAspectRatio()) {
+                auto height = width * attached->aspectRatio();
+                if (attached->maxHeight() && height > attached->maxHeight()) {
+                    height = attached->maxHeight();
+                    width  = height / attached->aspectRatio();
+                }
+
+                item->setHeight(height);
+            }
 
-        // in theory we could also reset the width, but that doesn't seem to work nicely for text
-        // areas because of how they cache it.
-        replyChild->setWidth(maxWidth_);
-        replyChild->ensurePolished();
-        auto width = replyChild->implicitWidth();
+            nhlog::ui()->debug(
+              "Made event delegate width: {}, {}", width, item->metaObject()->className());
+            item->setWidth(width);
+            item->ensurePolished();
+        }
+    };
 
-        if (width > maxWidth_ || attached->fillWidth())
-            width = maxWidth_;
+    layoutItem(mainChild, mainInset_);
+    layoutItem(replyChild, replyInset_);
+}
 
-        replyChild->setWidth(width);
-        replyChild->ensurePolished();
+void
+EventDelegateChooserAttachedType::polishChooser()
+{
+    auto p = parent();
+    if (p) {
+        auto chooser = qobject_cast<EventDelegateChooser *>(p->parent());
+        if (chooser) {
+            chooser->polish();
+        }
     }
 }
diff --git a/src/timeline/EventDelegateChooser.h b/src/timeline/EventDelegateChooser.h
index ff67ccd8..ce79444a 100644
--- a/src/timeline/EventDelegateChooser.h
+++ b/src/timeline/EventDelegateChooser.h
@@ -17,27 +17,78 @@
 class EventDelegateChooserAttachedType : public QObject
 {
     Q_OBJECT
-    Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged)
+    Q_PROPERTY(bool keepAspectRatio READ keepAspectRatio WRITE setKeepAspectRatio NOTIFY
+                 keepAspectRatioChanged)
+    Q_PROPERTY(double aspectRatio READ aspectRatio WRITE setAspectRatio NOTIFY aspectRatioChanged)
+    Q_PROPERTY(int maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
+    Q_PROPERTY(int maxHeight READ maxHeight WRITE setMaxHeight NOTIFY maxHeightChanged)
+    Q_PROPERTY(bool isReply READ isReply WRITE setIsReply NOTIFY isReplyChanged)
+
     QML_ANONYMOUS
 public:
     EventDelegateChooserAttachedType(QObject *parent)
       : QObject(parent)
     {
     }
-    bool fillWidth() const { return fillWidth_; }
-    void setFillWidth(bool fill)
+
+    bool keepAspectRatio() const { return keepAspectRatio_; }
+    void setKeepAspectRatio(bool fill)
+    {
+        if (fill != keepAspectRatio_) {
+            keepAspectRatio_ = fill;
+            emit keepAspectRatioChanged();
+            polishChooser();
+        }
+    }
+
+    double aspectRatio() const { return aspectRatio_; }
+    void setAspectRatio(double fill)
     {
-        fillWidth_ = fill;
-        emit fillWidthChanged();
+        aspectRatio_ = fill;
+        emit aspectRatioChanged();
+        polishChooser();
     }
+
+    int maxWidth() const { return maxWidth_; }
+    void setMaxWidth(int fill)
+    {
+        maxWidth_ = fill;
+        emit maxWidthChanged();
+        polishChooser();
+    }
+
+    int maxHeight() const { return maxHeight_; }
+    void setMaxHeight(int fill)
+    {
+        maxHeight_ = fill;
+        emit maxHeightChanged();
+    }
+
+    bool isReply() const { return isReply_; }
+    void setIsReply(bool fill)
+    {
+        if (fill != isReply_) {
+            isReply_ = fill;
+            emit isReplyChanged();
+            polishChooser();
+        }
+    }
+
 signals:
-    void fillWidthChanged();
+    void keepAspectRatioChanged();
+    void aspectRatioChanged();
+    void maxWidthChanged();
+    void maxHeightChanged();
+    void isReplyChanged();
 
 private:
-    bool fillWidth_ = false, keepAspectRatio = false;
-    double aspectRatio = 1.;
-    int maxWidth       = -1;
-    int maxHeight      = -1;
+    void polishChooser();
+
+    double aspectRatio_ = 1.;
+    int maxWidth_       = -1;
+    int maxHeight_        = -1;
+    bool keepAspectRatio_ = false;
+    bool isReply_         = false;
 };
 
 class EventDelegateChoice : public QObject
@@ -84,6 +135,8 @@ class EventDelegateChooser : public QQuickItem
     Q_PROPERTY(TimelineModel *room READ room WRITE setRoom NOTIFY roomChanged REQUIRED FINAL)
     Q_PROPERTY(bool sameWidth READ sameWidth WRITE setSameWidth NOTIFY sameWidthChanged)
     Q_PROPERTY(int maxWidth READ maxWidth WRITE setMaxWidth NOTIFY maxWidthChanged)
+    Q_PROPERTY(int replyInset READ replyInset WRITE setReplyInset NOTIFY replyInsetChanged)
+    Q_PROPERTY(int mainInset READ mainInset WRITE setMainInset NOTIFY mainInsetChanged)
 
 public:
     QQmlListProperty<EventDelegateChoice> choices();
@@ -103,7 +156,7 @@ public:
         sameWidth_ = width;
         emit sameWidthChanged();
     }
-    bool maxWidth() const { return maxWidth_; }
+    int maxWidth() const { return maxWidth_; }
     void setMaxWidth(int width)
     {
         maxWidth_ = width;
@@ -111,6 +164,22 @@ public:
         polish();
     }
 
+    int replyInset() const { return replyInset_; }
+    void setReplyInset(int width)
+    {
+        replyInset_ = width;
+        emit replyInsetChanged();
+        polish();
+    }
+
+    int mainInset() const { return mainInset_; }
+    void setMainInset(int width)
+    {
+        mainInset_ = width;
+        emit mainInsetChanged();
+        polish();
+    }
+
     void setRoom(TimelineModel *m)
     {
         if (m != room_) {
@@ -161,6 +230,8 @@ signals:
     void replyToChanged();
     void sameWidthChanged();
     void maxWidthChanged();
+    void replyInsetChanged();
+    void mainInsetChanged();
 
 private:
     struct DelegateIncubator final : public QQmlIncubator
@@ -183,6 +254,7 @@ private:
         QString instantiatedId;
         int instantiatedRole = -1;
         QAbstractItemModel *instantiatedModel = nullptr;
+        int oldType                           = -1;
     };
 
     QVariant roleValue_;
@@ -194,6 +266,8 @@ private:
     QString replyId;
     bool sameWidth_ = false;
     int maxWidth_   = 400;
+    int replyInset_ = 0;
+    int mainInset_  = 0;
 
     static void appendChoice(QQmlListProperty<EventDelegateChoice> *, EventDelegateChoice *);
     static qsizetype choiceCount(QQmlListProperty<EventDelegateChoice> *);