-
-
Notifications
You must be signed in to change notification settings - Fork 441
/
MessageLayoutContainer.hpp
135 lines (112 loc) · 3.91 KB
/
MessageLayoutContainer.hpp
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#pragma once
#include <QPoint>
#include <QRect>
#include <memory>
#include <vector>
#include "common/Common.hpp"
#include "common/FlagsEnum.hpp"
#include "messages/Selection.hpp"
#include "messages/layouts/MessageLayoutElement.hpp"
class QPainter;
namespace chatterino {
enum class MessageFlag : int64_t;
enum class FirstWord { Neutral, RTL, LTR };
using MessageFlags = FlagsEnum<MessageFlag>;
struct Margin {
int top;
int right;
int bottom;
int left;
Margin()
: Margin(0)
{
}
Margin(int value)
: Margin(value, value, value, value)
{
}
Margin(int _top, int _right, int _bottom, int _left)
: top(_top)
, right(_right)
, bottom(_bottom)
, left(_left)
{
}
};
struct MessageLayoutContainer {
MessageLayoutContainer() = default;
FirstWord first = FirstWord::Neutral;
bool containsRTL = false;
int getHeight() const;
int getWidth() const;
float getScale() const;
// methods
void begin(int width_, float scale_, MessageFlags flags_);
void end();
void clear();
bool canAddElements();
void addElement(MessageLayoutElement *element);
void addElementNoLineBreak(MessageLayoutElement *element);
void breakLine();
bool atStartOfLine();
bool fitsInLine(int width_);
// this method is called when a message has an RTL word
// we need to reorder the words to be shown properly
// however we don't we to reorder non-text elements like badges, timestamps, username
// firstTextIndex is the index of the first text element that we need to start the reordering from
void reorderRTL(int firstTextIndex);
MessageLayoutElement *getElementAt(QPoint point);
// painting
void paintElements(QPainter &painter);
void paintAnimatedElements(QPainter &painter, int yOffset);
void paintSelection(QPainter &painter, int messageIndex,
Selection &selection, int yOffset);
// selection
int getSelectionIndex(QPoint point);
int getLastCharacterIndex() const;
int getFirstMessageCharacterIndex() const;
void addSelectionText(QString &str, int from, int to, CopyMode copymode);
bool isCollapsed();
private:
struct Line {
int startIndex;
int endIndex;
int startCharIndex;
int endCharIndex;
QRect rect;
};
// helpers
/*
_addElement is called at two stages. first stage is the normal one where we want to add message layout elements to the container.
If we detect an RTL word in the message, reorderRTL will be called, which is the second stage, where we call _addElement
again for each layout element, but in the correct order this time, without adding the elemnt to the this->element_ vector.
Due to compact emote logic, we need the previous element to check if we should change the spacing or not.
in stage one, this is simply elements_.back(), but in stage 2 that's not the case due to the reordering, and we need to pass the
index of the reordered previous element.
In stage one we don't need that and we pass -2 to indicate stage one (i.e. adding mode)
In stage two, we pass -1 for the first element, and the index of the oredered privous element for the rest.
*/
void _addElement(MessageLayoutElement *element, bool forceAdd = false,
int prevIndex = -2);
bool canCollapse();
const Margin margin = {4, 8, 4, 8};
// variables
float scale_ = 1.f;
int width_ = 0;
MessageFlags flags_{};
int line_ = 0;
int height_ = 0;
int currentX_ = 0;
int currentY_ = 0;
int charIndex_ = 0;
size_t lineStart_ = 0;
int lineHeight_ = 0;
int spaceWidth_ = 4;
int textLineHeight_ = 0;
int dotdotdotWidth_ = 0;
bool canAddMessages_ = true;
bool isCollapsed_ = false;
std::vector<std::unique_ptr<MessageLayoutElement>> elements_;
std::vector<Line> lines_;
};
} // namespace chatterino