1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "ui/effects/animations.h" 11 #include "base/timer.h" 12 #include "base/weak_ptr.h" 13 14 namespace style { 15 class palette; 16 struct colorizer; 17 } // namespace style 18 19 namespace Ui { 20 21 class ChatStyle; 22 struct ChatPaintContext; 23 struct BubblePattern; 24 25 struct ChatThemeBackground { 26 QImage prepared; 27 QImage preparedForTiled; 28 QImage gradientForFill; 29 std::optional<QColor> colorForFill; 30 std::vector<QColor> colors; 31 float64 patternOpacity = 1.; 32 int gradientRotation = 0; 33 bool isPattern = false; 34 bool tile = false; 35 waitingForNegativePatternChatThemeBackground36 [[nodiscard]] bool waitingForNegativePattern() const { 37 return isPattern && prepared.isNull() && (patternOpacity < 0.); 38 } 39 }; 40 41 bool operator==(const ChatThemeBackground &a, const ChatThemeBackground &b); 42 bool operator!=(const ChatThemeBackground &a, const ChatThemeBackground &b); 43 44 struct ChatThemeBackgroundData { 45 QString path; 46 QByteArray bytes; 47 bool gzipSvg = false; 48 std::vector<QColor> colors; 49 bool isPattern = false; 50 float64 patternOpacity = 0.; 51 bool isBlurred = false; 52 bool generateGradient = false; 53 int gradientRotation = 0; 54 }; 55 56 struct ChatThemeBubblesData { 57 std::vector<QColor> colors; 58 std::optional<QColor> accent; 59 }; 60 61 struct CacheBackgroundRequest { 62 ChatThemeBackground background; 63 QSize area; 64 int gradientRotationAdd = 0; 65 float64 gradientProgress = 1.; 66 67 explicit operator bool() const { 68 return !background.prepared.isNull() 69 || !background.gradientForFill.isNull(); 70 } 71 }; 72 73 bool operator==( 74 const CacheBackgroundRequest &a, 75 const CacheBackgroundRequest &b); 76 bool operator!=( 77 const CacheBackgroundRequest &a, 78 const CacheBackgroundRequest &b); 79 80 struct CacheBackgroundResult { 81 QImage image; 82 QImage gradient; 83 QSize area; 84 int x = 0; 85 int y = 0; 86 bool waitingForNegativePattern = false; 87 }; 88 89 struct CachedBackground { 90 CachedBackground() = default; 91 CachedBackground(CacheBackgroundResult &&result); 92 93 QPixmap pixmap; 94 QSize area; 95 int x = 0; 96 int y = 0; 97 bool waitingForNegativePattern = false; 98 }; 99 100 struct BackgroundState { 101 CachedBackground was; 102 CachedBackground now; 103 float64 shown = 1.; 104 }; 105 106 struct ChatThemeKey { 107 uint64 id = 0; 108 bool dark = false; 109 110 explicit operator bool() const { 111 return (id != 0); 112 } 113 }; 114 115 inline bool operator<(ChatThemeKey a, ChatThemeKey b) { 116 return (a.id < b.id) || ((a.id == b.id) && (a.dark < b.dark)); 117 } 118 inline bool operator>(ChatThemeKey a, ChatThemeKey b) { 119 return (b < a); 120 } 121 inline bool operator<=(ChatThemeKey a, ChatThemeKey b) { 122 return !(b < a); 123 } 124 inline bool operator>=(ChatThemeKey a, ChatThemeKey b) { 125 return !(a < b); 126 } 127 inline bool operator==(ChatThemeKey a, ChatThemeKey b) { 128 return (a.id == b.id) && (a.dark == b.dark); 129 } 130 inline bool operator!=(ChatThemeKey a, ChatThemeKey b) { 131 return !(a == b); 132 } 133 134 struct ChatThemeDescriptor { 135 ChatThemeKey key; 136 Fn<void(style::palette&)> preparePalette; 137 ChatThemeBackgroundData backgroundData; 138 ChatThemeBubblesData bubblesData; 139 bool basedOnDark = false; 140 }; 141 142 class ChatTheme final : public base::has_weak_ptr { 143 public: 144 ChatTheme(); 145 146 // Expected to be invoked on a background thread. Invokes callbacks there. 147 ChatTheme(ChatThemeDescriptor &&descriptor); 148 149 ~ChatTheme(); 150 151 [[nodiscard]] ChatThemeKey key() const; palette()152 [[nodiscard]] const style::palette *palette() const { 153 return _palette.get(); 154 } 155 156 void setBackground(ChatThemeBackground &&background); 157 void updateBackgroundImageFrom(ChatThemeBackground &&background); background()158 [[nodiscard]] const ChatThemeBackground &background() const { 159 return _mutableBackground; 160 } 161 162 void setBubblesBackground(QImage image); bubblesBackgroundPattern()163 [[nodiscard]] const BubblePattern *bubblesBackgroundPattern() const { 164 return _bubblesBackgroundPattern.get(); 165 } 166 167 [[nodiscard]] ChatPaintContext preparePaintContext( 168 not_null<const ChatStyle*> st, 169 QRect viewport, 170 QRect clip); 171 [[nodiscard]] const BackgroundState &backgroundState(QSize area); 172 void clearBackgroundState(); 173 [[nodiscard]] rpl::producer<> repaintBackgroundRequests() const; 174 void rotateComplexGradientBackground(); 175 176 private: 177 void cacheBackground(); 178 void cacheBackgroundNow(); 179 void cacheBackgroundAsync( 180 const CacheBackgroundRequest &request, 181 Fn<void(CacheBackgroundResult&&)> done = nullptr); 182 void setCachedBackground(CacheBackgroundResult &&cached); 183 [[nodiscard]] CacheBackgroundRequest cacheBackgroundRequest( 184 QSize area, 185 int addRotation = 0) const; 186 [[nodiscard]] bool readyForBackgroundRotation() const; 187 void generateNextBackgroundRotation(); 188 189 void cacheBubbles(); 190 void cacheBubblesNow(); 191 void cacheBubblesAsync( 192 const CacheBackgroundRequest &request); 193 [[nodiscard]] CacheBackgroundRequest cacheBubblesRequest( 194 QSize area) const; 195 196 [[nodiscard]] style::colorizer bubblesAccentColorizer( 197 const QColor &accent) const; 198 void adjustPalette(const ChatThemeDescriptor &descriptor); 199 void set(const style::color &my, const QColor &color); 200 void adjust(const style::color &my, const QColor &by); 201 void adjust(const style::color &my, const style::colorizer &by); 202 203 ChatThemeKey _key; 204 std::unique_ptr<style::palette> _palette; 205 ChatThemeBackground _mutableBackground; 206 BackgroundState _backgroundState; 207 Animations::Simple _backgroundFade; 208 CacheBackgroundRequest _backgroundCachingRequest; 209 CacheBackgroundResult _backgroundNext; 210 QSize _cacheBackgroundArea; 211 crl::time _lastBackgroundAreaChangeTime = 0; 212 std::optional<base::Timer> _cacheBackgroundTimer; 213 214 CachedBackground _bubblesBackground; 215 QImage _bubblesBackgroundPrepared; 216 CacheBackgroundRequest _bubblesCachingRequest; 217 QSize _cacheBubblesArea; 218 crl::time _lastBubblesAreaChangeTime = 0; 219 std::optional<base::Timer> _cacheBubblesTimer; 220 std::unique_ptr<BubblePattern> _bubblesBackgroundPattern; 221 222 rpl::event_stream<> _repaintBackgroundRequests; 223 224 rpl::lifetime _lifetime; 225 226 }; 227 228 struct ChatBackgroundRects { 229 QRect from; 230 QRect to; 231 }; 232 [[nodiscard]] ChatBackgroundRects ComputeChatBackgroundRects( 233 QSize fillSize, 234 QSize imageSize); 235 236 [[nodiscard]] QColor CountAverageColor(const QImage &image); 237 [[nodiscard]] QColor CountAverageColor(const std::vector<QColor> &colors); 238 [[nodiscard]] bool IsPatternInverted( 239 const std::vector<QColor> &background, 240 float64 patternOpacity); 241 [[nodiscard]] QColor ThemeAdjustedColor(QColor original, QColor background); 242 [[nodiscard]] QImage PreprocessBackgroundImage(QImage image); 243 [[nodiscard]] std::optional<QColor> CalculateImageMonoColor( 244 const QImage &image); 245 [[nodiscard]] QImage PrepareImageForTiled(const QImage &prepared); 246 247 [[nodiscard]] QImage ReadBackgroundImage( 248 const QString &path, 249 const QByteArray &content, 250 bool gzipSvg); 251 [[nodiscard]] QImage GenerateBackgroundImage( 252 QSize size, 253 const std::vector<QColor> &bg, 254 int gradientRotation, 255 float64 patternOpacity = 1., 256 Fn<void(QPainter&,bool)> drawPattern = nullptr); 257 [[nodiscard]] QImage InvertPatternImage(QImage pattern); 258 [[nodiscard]] QImage PreparePatternImage( 259 QImage pattern, 260 const std::vector<QColor> &bg, 261 int gradientRotation, 262 float64 patternOpacity); 263 [[nodiscard]] QImage PrepareBlurredBackground(QImage image); 264 [[nodiscard]] QImage GenerateDitheredGradient( 265 const std::vector<QColor> &colors, 266 int rotation); 267 [[nodiscard]] ChatThemeBackground PrepareBackgroundImage( 268 const ChatThemeBackgroundData &data); 269 270 } // namespace Ui 271