chat_theme.h 7.1 KB

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