summary refs log tree commit diff
path: root/src/ui/MxcAnimatedImage.h
blob: 2e5ae4f7d28d1b61c27a1123ca4d80ee416b769a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <QBuffer>
#include <QMovie>
#include <QObject>
#include <QQuickItem>

class TimelineModel;

// This is an AnimatedImage, that can draw encrypted images
class MxcAnimatedImage : public QQuickItem
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
    Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
    Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged)
    Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
    Q_PROPERTY(bool play READ play WRITE setPlay NOTIFY playChanged)
public:
    MxcAnimatedImage(QQuickItem *parent = nullptr)
      : QQuickItem(parent)
    {
        connect(this, &MxcAnimatedImage::eventIdChanged, &MxcAnimatedImage::startDownload);
        connect(this, &MxcAnimatedImage::roomChanged, &MxcAnimatedImage::startDownload);
        connect(&movie, &QMovie::frameChanged, this, &MxcAnimatedImage::newFrame);
        setFlag(QQuickItem::ItemHasContents);
        setFlag(QQuickItem::ItemObservesViewport);
        // setAcceptHoverEvents(true);
    }

    bool animatable() const { return animatable_; }
    bool loaded() const { return buffer.size() > 0; }
    bool play() const { return play_; }
    QString eventId() const { return eventId_; }
    TimelineModel *room() const { return room_; }
    void setEventId(QString newEventId)
    {
        if (eventId_ != newEventId) {
            eventId_ = newEventId;
            emit eventIdChanged();
        }
    }
    void setRoom(TimelineModel *room)
    {
        if (room_ != room) {
            room_ = room;
            emit roomChanged();
        }
    }
    void setPlay(bool newPlay)
    {
        if (play_ != newPlay) {
            play_ = newPlay;
            if (movie.frameCount() > 1)
                movie.setPaused(!play_);
            else {
                movie.jumpToFrame(0);
                movie.setPaused(true);
            }
            emit playChanged();
        }
    }

    void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
    QSGNode *updatePaintNode(QSGNode *oldNode,
                             QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;

signals:
    void roomChanged();
    void eventIdChanged();
    void animatableChanged();
    void loadedChanged();
    void playChanged();

private slots:
    void startDownload();
    void newFrame(int frame)
    {
        currentFrame = frame;
        imageDirty   = true;
        if (!clipRect().isEmpty())
            update();
    }

private:
    TimelineModel *room_ = nullptr;
    QString eventId_;
    QString filename_;
    bool animatable_ = false;
    QBuffer buffer;
    QMovie movie;
    int currentFrame = 0;
    bool imageDirty  = true;
    bool play_       = true;
};