labels.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "base/timer.h"
  9. #include "base/unique_qptr.h"
  10. #include "ui/rp_widget.h"
  11. #include "ui/wrap/padding_wrap.h"
  12. #include "ui/text/text.h"
  13. #include "ui/click_handler.h"
  14. #include "ui/widgets/box_content_divider.h"
  15. #include "styles/style_widgets.h"
  16. class QTouchEvent;
  17. namespace Ui {
  18. class PopupMenu;
  19. class BoxContentDivider;
  20. class CrossFadeAnimation {
  21. public:
  22. struct Data {
  23. QImage full;
  24. std::vector<int> lineWidths;
  25. QPoint position;
  26. style::align align;
  27. style::font font;
  28. style::margins margin;
  29. int lineHeight = 0;
  30. int lineAddTop = 0;
  31. };
  32. CrossFadeAnimation(style::color bg, Data &&from, Data &&to);
  33. struct Part {
  34. QPixmap snapshot;
  35. QPoint position;
  36. };
  37. void addLine(Part was, Part now);
  38. void paintFrame(QPainter &p, float64 dt);
  39. void paintFrame(
  40. QPainter &p,
  41. float64 positionReady,
  42. float64 alphaWas,
  43. float64 alphaNow);
  44. private:
  45. struct Line {
  46. Line(Part was, Part now) : was(std::move(was)), now(std::move(now)) {
  47. }
  48. Part was;
  49. Part now;
  50. };
  51. void paintLine(
  52. QPainter &p,
  53. const Line &line,
  54. float64 positionReady,
  55. float64 alphaWas,
  56. float64 alphaNow);
  57. style::color _bg;
  58. QList<Line> _lines;
  59. };
  60. class LabelSimple : public RpWidget {
  61. public:
  62. LabelSimple(
  63. QWidget *parent,
  64. const style::LabelSimple &st = st::defaultLabelSimple,
  65. const QString &value = QString());
  66. // This method also resizes the label.
  67. void setText(const QString &newText, bool *outTextChanged = nullptr);
  68. protected:
  69. void paintEvent(QPaintEvent *e) override;
  70. private:
  71. QString _fullText;
  72. int _fullTextWidth;
  73. QString _text;
  74. int _textWidth;
  75. const style::LabelSimple &_st;
  76. };
  77. class FlatLabel : public RpWidget, public ClickHandlerHost {
  78. public:
  79. FlatLabel(
  80. QWidget *parent,
  81. const style::FlatLabel &st = st::defaultFlatLabel,
  82. const style::PopupMenu &stMenu = st::defaultPopupMenu);
  83. FlatLabel(
  84. QWidget *parent,
  85. const QString &text,
  86. const style::FlatLabel &st = st::defaultFlatLabel,
  87. const style::PopupMenu &stMenu = st::defaultPopupMenu);
  88. FlatLabel(
  89. QWidget *parent,
  90. rpl::producer<QString> &&text,
  91. const style::FlatLabel &st = st::defaultFlatLabel,
  92. const style::PopupMenu &stMenu = st::defaultPopupMenu);
  93. FlatLabel(
  94. QWidget *parent,
  95. rpl::producer<TextWithEntities> &&text,
  96. const style::FlatLabel &st = st::defaultFlatLabel,
  97. const style::PopupMenu &stMenu = st::defaultPopupMenu,
  98. const Text::MarkedContext &context = {});
  99. [[nodiscard]] const style::FlatLabel &st() const {
  100. return _st;
  101. }
  102. void setOpacity(float64 o);
  103. void setTextColorOverride(std::optional<QColor> color);
  104. void setText(const QString &text);
  105. void setMarkedText(
  106. const TextWithEntities &textWithEntities,
  107. Text::MarkedContext context = {});
  108. void setSelectable(bool selectable);
  109. void setDoubleClickSelectsParagraph(bool doubleClickSelectsParagraph);
  110. void setContextCopyText(const QString &copyText);
  111. void setBreakEverywhere(bool breakEverywhere);
  112. void setTryMakeSimilarLines(bool tryMakeSimilarLines);
  113. enum class WhichAnimationsPaused {
  114. None,
  115. CustomEmoji,
  116. Spoiler,
  117. All,
  118. };
  119. void setAnimationsPausedCallback(Fn<WhichAnimationsPaused()> callback) {
  120. _animationsPausedCallback = std::move(callback);
  121. }
  122. [[nodiscard]] int textMaxWidth() const;
  123. int naturalWidth() const override;
  124. QMargins getMargins() const override;
  125. void setLink(uint16 index, const ClickHandlerPtr &lnk);
  126. void setLinksTrusted();
  127. using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
  128. void setClickHandlerFilter(ClickHandlerFilter &&filter);
  129. void overrideLinkClickHandler(Fn<void()> handler);
  130. void overrideLinkClickHandler(Fn<void(QString url)> handler);
  131. struct ContextMenuRequest {
  132. not_null<PopupMenu*> menu;
  133. ClickHandlerPtr link;
  134. TextSelection selection;
  135. bool uponSelection = false;
  136. bool fullSelection = false;
  137. };
  138. void setContextMenuHook(Fn<void(ContextMenuRequest)> hook);
  139. void fillContextMenu(ContextMenuRequest request);
  140. // ClickHandlerHost interface
  141. void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
  142. void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
  143. [[nodiscard]] CrossFadeAnimation::Data crossFadeData(
  144. style::color bg,
  145. QPoint basePosition = QPoint());
  146. static std::unique_ptr<CrossFadeAnimation> CrossFade(
  147. not_null<FlatLabel*> from,
  148. not_null<FlatLabel*> to,
  149. style::color bg,
  150. QPoint fromPosition = QPoint(),
  151. QPoint toPosition = QPoint());
  152. protected:
  153. void paintEvent(QPaintEvent *e) override;
  154. void mouseMoveEvent(QMouseEvent *e) override;
  155. void mousePressEvent(QMouseEvent *e) override;
  156. void mouseReleaseEvent(QMouseEvent *e) override;
  157. void mouseDoubleClickEvent(QMouseEvent *e) override;
  158. void enterEventHook(QEnterEvent *e) override;
  159. void leaveEventHook(QEvent *e) override;
  160. void focusOutEvent(QFocusEvent *e) override;
  161. void focusInEvent(QFocusEvent *e) override;
  162. void keyPressEvent(QKeyEvent *e) override;
  163. void contextMenuEvent(QContextMenuEvent *e) override;
  164. bool eventHook(QEvent *e) override; // calls touchEvent when necessary
  165. void touchEvent(QTouchEvent *e);
  166. int resizeGetHeight(int newWidth) override;
  167. void copySelectedText();
  168. void copyContextText();
  169. void touchSelect();
  170. void executeDrag();
  171. private:
  172. void init();
  173. void textUpdated();
  174. Text::StateResult dragActionUpdate();
  175. Text::StateResult dragActionStart(const QPoint &p, Qt::MouseButton button);
  176. Text::StateResult dragActionFinish(const QPoint &p, Qt::MouseButton button);
  177. void updateHover(const Text::StateResult &state);
  178. Text::StateResult getTextState(const QPoint &m) const;
  179. void refreshCursor(bool uponSymbol);
  180. int countTextWidth() const;
  181. int countTextHeight(int textWidth);
  182. void refreshSize();
  183. enum class ContextMenuReason {
  184. FromEvent,
  185. FromTouch,
  186. };
  187. void showContextMenu(QContextMenuEvent *e, ContextMenuReason reason);
  188. Text::String _text;
  189. const style::FlatLabel &_st;
  190. const style::PopupMenu &_stMenu;
  191. std::optional<QColor> _textColorOverride;
  192. float64 _opacity = 1.;
  193. int _allowedWidth = 0;
  194. int _textWidth = 0;
  195. int _fullTextHeight = 0;
  196. bool _breakEverywhere = false;
  197. bool _tryMakeSimilarLines = false;
  198. style::cursor _cursor = style::cur_default;
  199. bool _selectable = false;
  200. TextSelection _selection, _savedSelection;
  201. TextSelectType _selectionType = TextSelectType::Letters;
  202. bool _doubleClickSelectsParagraph = false;
  203. enum DragAction {
  204. NoDrag = 0x00,
  205. PrepareDrag = 0x01,
  206. Dragging = 0x02,
  207. Selecting = 0x04,
  208. };
  209. DragAction _dragAction = NoDrag;
  210. QPoint _dragStartPosition;
  211. uint16 _dragSymbol = 0;
  212. bool _dragWasInactive = false;
  213. QPoint _lastMousePos;
  214. QPoint _trippleClickPoint;
  215. base::Timer _trippleClickTimer;
  216. base::unique_qptr<PopupMenu> _contextMenu;
  217. Fn<void(ContextMenuRequest)> _contextMenuHook;
  218. QString _contextCopyText;
  219. ClickHandlerFilter _clickHandlerFilter;
  220. Fn<WhichAnimationsPaused()> _animationsPausedCallback;
  221. // text selection and context menu by touch support (at least Windows Surface tablets)
  222. bool _touchSelect = false;
  223. bool _touchInProgress = false;
  224. QPoint _touchStart, _touchPrevPos, _touchPos;
  225. base::Timer _touchSelectTimer;
  226. };
  227. class DividerLabel : public PaddingWrap<> {
  228. public:
  229. DividerLabel(
  230. QWidget *parent,
  231. object_ptr<RpWidget> &&child,
  232. const style::margins &padding,
  233. RectParts parts = RectPart::Top | RectPart::Bottom);
  234. int naturalWidth() const override;
  235. protected:
  236. void resizeEvent(QResizeEvent *e) override;
  237. private:
  238. object_ptr<BoxContentDivider> _background;
  239. };
  240. } // namespace Ui