1 | /* |
---|---|
2 | SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org> |
3 | SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch> |
4 | SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "katerenderrange.h" |
10 | |
11 | #include <KColorUtils> |
12 | |
13 | void mergeAttributes(KTextEditor::Attribute::Ptr base, KTextEditor::Attribute::Ptr add) |
14 | { |
15 | if (!add) { |
16 | return; |
17 | } |
18 | |
19 | bool hadBg = base->hasProperty(propertyId: KTextEditor::Attribute::BackgroundBrush); |
20 | bool hasBg = add->hasProperty(propertyId: KTextEditor::Attribute::BackgroundBrush); |
21 | |
22 | bool hadFg = base->hasProperty(propertyId: KTextEditor::Attribute::ForegroundBrush); |
23 | bool hasFg = add->hasProperty(propertyId: KTextEditor::Attribute::ForegroundBrush); |
24 | |
25 | if (((!hadBg || !hasBg) && (!hadFg || !hasFg))) { |
26 | // Nothing to blend |
27 | *base += *add; |
28 | return; |
29 | } |
30 | |
31 | // We eventually have to blend |
32 | |
33 | QBrush baseBgBrush; |
34 | QBrush baseFgBrush; |
35 | |
36 | if (hadBg) { |
37 | baseBgBrush = base->background(); |
38 | } |
39 | |
40 | if (hadFg) { |
41 | baseFgBrush = base->foreground(); |
42 | } |
43 | |
44 | *base += *add; |
45 | |
46 | if (hadBg && hasBg) { |
47 | QBrush bg = add->background(); |
48 | if (!bg.isOpaque()) { |
49 | QColor mixWithColor = bg.color(); |
50 | mixWithColor.setAlpha(255); |
51 | bg.setColor(KColorUtils::mix(c1: baseBgBrush.color(), c2: mixWithColor, bias: bg.color().alphaF())); |
52 | base->setBackground(bg); |
53 | } |
54 | } |
55 | if (hadFg && hasFg) { |
56 | QBrush fg = add->foreground(); |
57 | if (!fg.isOpaque()) { |
58 | QColor mixWithColor = fg.color(); |
59 | mixWithColor.setAlpha(255); |
60 | fg.setColor(KColorUtils::mix(c1: baseFgBrush.color(), c2: mixWithColor, bias: fg.color().alphaF())); |
61 | base->setForeground(fg); |
62 | } |
63 | } |
64 | } |
65 | |
66 | void NormalRenderRange::addRange(KTextEditor::Range range, KTextEditor::Attribute::Ptr attribute) |
67 | { |
68 | m_ranges.emplace_back(args&: range, args: std::move(attribute)); |
69 | } |
70 | |
71 | KTextEditor::Cursor NormalRenderRange::nextBoundary() const |
72 | { |
73 | return m_nextBoundary; |
74 | } |
75 | |
76 | bool NormalRenderRange::advanceTo(const KTextEditor::Cursor pos) |
77 | { |
78 | size_t index = m_currentRange; |
79 | while (index < m_ranges.size()) { |
80 | const auto &p = m_ranges[index]; |
81 | const auto &r = p.first; |
82 | if (r.end() <= pos) { |
83 | ++index; |
84 | } else { |
85 | bool ret = index != m_currentRange; |
86 | m_currentRange = index; |
87 | |
88 | if (r.start() > pos) { |
89 | m_nextBoundary = r.start(); |
90 | } else { |
91 | m_nextBoundary = r.end(); |
92 | } |
93 | if (r.contains(cursor: pos)) { |
94 | m_currentAttribute = p.second; |
95 | } else { |
96 | m_currentAttribute.reset(); |
97 | } |
98 | |
99 | return ret; |
100 | } |
101 | } |
102 | |
103 | m_nextBoundary = KTextEditor::Cursor(INT_MAX, INT_MAX); |
104 | m_currentAttribute.reset(); |
105 | return false; |
106 | } |
107 | |
108 | KTextEditor::Attribute::Ptr NormalRenderRange::currentAttribute() const |
109 | { |
110 | return m_currentAttribute; |
111 | } |
112 | |
113 | KTextEditor::Cursor RenderRangeVector::nextBoundary() const |
114 | { |
115 | KTextEditor::Cursor ret = m_currentPos; |
116 | bool first = true; |
117 | for (auto &r : m_ranges) { |
118 | if (first) { |
119 | ret = r.nextBoundary(); |
120 | first = false; |
121 | |
122 | } else { |
123 | KTextEditor::Cursor nb = r.nextBoundary(); |
124 | if (ret > nb) { |
125 | ret = nb; |
126 | } |
127 | } |
128 | } |
129 | return ret; |
130 | } |
131 | |
132 | NormalRenderRange &RenderRangeVector::pushNewRange() |
133 | { |
134 | m_ranges.push_back(x: NormalRenderRange()); |
135 | return m_ranges.back(); |
136 | } |
137 | |
138 | void RenderRangeVector::advanceTo(const KTextEditor::Cursor pos) |
139 | { |
140 | for (auto &r : m_ranges) { |
141 | r.advanceTo(pos); |
142 | } |
143 | } |
144 | |
145 | bool RenderRangeVector::hasAttribute() const |
146 | { |
147 | for (auto &r : m_ranges) { |
148 | if (r.currentAttribute()) { |
149 | return true; |
150 | } |
151 | } |
152 | |
153 | return false; |
154 | } |
155 | |
156 | KTextEditor::Attribute::Ptr RenderRangeVector::generateAttribute() const |
157 | { |
158 | KTextEditor::Attribute::Ptr a; |
159 | bool ownsAttribute = false; |
160 | |
161 | for (auto &r : m_ranges) { |
162 | if (KTextEditor::Attribute::Ptr a2 = r.currentAttribute()) { |
163 | if (!a) { |
164 | a = a2; |
165 | } else { |
166 | if (!ownsAttribute) { |
167 | // Make an own copy of the attribute.. |
168 | ownsAttribute = true; |
169 | a = new KTextEditor::Attribute(*a); |
170 | } |
171 | mergeAttributes(base: a, add: a2); |
172 | } |
173 | } |
174 | } |
175 | |
176 | return a; |
177 | } |
178 |