checkbox.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  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 "ui/widgets/buttons.h"
  9. #include "ui/effects/animations.h"
  10. #include "ui/text/text.h"
  11. #include "styles/style_widgets.h"
  12. class QPainter;
  13. class Painter;
  14. namespace Ui {
  15. class AbstractCheckView {
  16. public:
  17. AbstractCheckView(int duration, bool checked, Fn<void()> updateCallback);
  18. void setChecked(bool checked, anim::type animated);
  19. void finishAnimating();
  20. void setUpdateCallback(Fn<void()> updateCallback);
  21. bool checked() const {
  22. return _checked;
  23. }
  24. void update();
  25. float64 currentAnimationValue();
  26. bool animating() const;
  27. auto checkedChanges() const {
  28. return _checks.events();
  29. }
  30. auto checkedValue() const {
  31. return _checks.events_starting_with(checked());
  32. }
  33. virtual QSize getSize() const = 0;
  34. virtual void paint(QPainter &p, int left, int top, int outerWidth) = 0;
  35. virtual QImage prepareRippleMask() const = 0;
  36. virtual bool checkRippleStartPosition(QPoint position) const = 0;
  37. virtual ~AbstractCheckView() = default;
  38. private:
  39. virtual void checkedChangedHook(anim::type animated) {
  40. }
  41. int _duration = 0;
  42. bool _checked = false;
  43. Fn<void()> _updateCallback;
  44. Ui::Animations::Simple _toggleAnimation;
  45. rpl::event_stream<bool> _checks;
  46. };
  47. class CheckView : public AbstractCheckView {
  48. public:
  49. CheckView(
  50. const style::Check &st,
  51. bool checked,
  52. Fn<void()> updateCallback = nullptr);
  53. void setStyle(const style::Check &st);
  54. QSize getSize() const override;
  55. void paint(QPainter &p, int left, int top, int outerWidth) override;
  56. QImage prepareRippleMask() const override;
  57. bool checkRippleStartPosition(QPoint position) const override;
  58. void setUntoggledOverride(
  59. std::optional<QColor> untoggledOverride);
  60. [[nodiscard]] static Fn<void()> PrepareNonToggledError(
  61. not_null<CheckView*> view,
  62. rpl::lifetime &lifetime);
  63. private:
  64. QSize rippleSize() const;
  65. not_null<const style::Check*> _st;
  66. std::optional<QColor> _untoggledOverride;
  67. };
  68. class RadioView : public AbstractCheckView {
  69. public:
  70. RadioView(
  71. const style::Radio &st,
  72. bool checked,
  73. Fn<void()> updateCallback = nullptr);
  74. void setStyle(const style::Radio &st);
  75. void setToggledOverride(std::optional<QColor> toggledOverride);
  76. void setUntoggledOverride(std::optional<QColor> untoggledOverride);
  77. QSize getSize() const override;
  78. void paint(QPainter &p, int left, int top, int outerWidth) override;
  79. QImage prepareRippleMask() const override;
  80. bool checkRippleStartPosition(QPoint position) const override;
  81. private:
  82. QSize rippleSize() const;
  83. not_null<const style::Radio*> _st;
  84. std::optional<QColor> _toggledOverride;
  85. std::optional<QColor> _untoggledOverride;
  86. };
  87. class ToggleView : public AbstractCheckView {
  88. public:
  89. ToggleView(
  90. const style::Toggle &st,
  91. bool checked,
  92. Fn<void()> updateCallback = nullptr);
  93. void setStyle(const style::Toggle &st);
  94. QSize getSize() const override;
  95. void paint(QPainter &p, int left, int top, int outerWidth) override;
  96. QImage prepareRippleMask() const override;
  97. bool checkRippleStartPosition(QPoint position) const override;
  98. void setLocked(bool locked);
  99. private:
  100. void paintXV(QPainter &p, int left, int top, int outerWidth, float64 toggled, const QBrush &brush);
  101. QSize rippleSize() const;
  102. not_null<const style::Toggle*> _st;
  103. bool _locked = false;
  104. };
  105. class Checkbox : public RippleButton, public ClickHandlerHost {
  106. public:
  107. Checkbox(
  108. QWidget *parent,
  109. const QString &text,
  110. bool checked = false,
  111. const style::Checkbox &st = st::defaultCheckbox,
  112. const style::Check &checkSt = st::defaultCheck);
  113. Checkbox(
  114. QWidget *parent,
  115. const TextWithEntities &text,
  116. bool checked = false,
  117. const style::Checkbox &st = st::defaultCheckbox,
  118. const style::Check &checkSt = st::defaultCheck);
  119. Checkbox(
  120. QWidget *parent,
  121. const QString &text,
  122. bool checked,
  123. const style::Checkbox &st,
  124. const style::Toggle &toggleSt);
  125. Checkbox(
  126. QWidget *parent,
  127. rpl::producer<QString> &&text,
  128. bool checked = false,
  129. const style::Checkbox &st = st::defaultCheckbox,
  130. const style::Check &checkSt = st::defaultCheck);
  131. Checkbox(
  132. QWidget *parent,
  133. rpl::producer<QString> &&text,
  134. bool checked,
  135. const style::Checkbox &st,
  136. const style::Toggle &toggleSt);
  137. Checkbox(
  138. QWidget *parent,
  139. const QString &text,
  140. const style::Checkbox &st,
  141. std::unique_ptr<AbstractCheckView> check);
  142. Checkbox(
  143. QWidget *parent,
  144. rpl::producer<TextWithEntities> &&text,
  145. const style::Checkbox &st,
  146. std::unique_ptr<AbstractCheckView> check);
  147. void setText(const QString &text, bool rich = false);
  148. void setCheckAlignment(style::align alignment);
  149. void setAllowTextLines(int lines = 0);
  150. void setTextBreakEverywhere(bool allow = true);
  151. void setLink(uint16 index, const ClickHandlerPtr &lnk);
  152. void setLinksTrusted();
  153. using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
  154. void setClickHandlerFilter(ClickHandlerFilter &&filter);
  155. [[nodiscard]] bool checked() const;
  156. [[nodiscard]] rpl::producer<bool> checkedChanges() const;
  157. [[nodiscard]] rpl::producer<bool> checkedValue() const;
  158. enum class NotifyAboutChange {
  159. Notify,
  160. DontNotify,
  161. };
  162. void setChecked(
  163. bool checked,
  164. NotifyAboutChange notify = NotifyAboutChange::Notify);
  165. void finishAnimating();
  166. [[nodiscard]] QMargins getMargins() const override {
  167. return _st.margin;
  168. }
  169. [[nodiscard]] int naturalWidth() const override;
  170. void updateCheck() {
  171. rtlupdate(checkRect());
  172. }
  173. [[nodiscard]] QRect checkRect() const;
  174. [[nodiscard]] not_null<AbstractCheckView*> checkView() const {
  175. return _check.get();
  176. }
  177. protected:
  178. void paintEvent(QPaintEvent *e) override;
  179. void mousePressEvent(QMouseEvent *e) override;
  180. void mouseMoveEvent(QMouseEvent *e) override;
  181. void mouseReleaseEvent(QMouseEvent *e) override;
  182. void leaveEventHook(QEvent *e) override;
  183. void onStateChanged(State was, StateChangeSource source) override;
  184. int resizeGetHeight(int newWidth) override;
  185. QImage prepareRippleMask() const override;
  186. QPoint prepareRippleStartPosition() const override;
  187. virtual void handlePress();
  188. private:
  189. void resizeToText();
  190. QPixmap grabCheckCache() const;
  191. int countTextMinWidth() const;
  192. Text::StateResult getTextState(const QPoint &m) const;
  193. const style::Checkbox &_st;
  194. std::unique_ptr<AbstractCheckView> _check;
  195. rpl::event_stream<bool> _checkedChanges;
  196. ClickHandlerPtr _activatingHandler;
  197. QPixmap _checkCache;
  198. ClickHandlerFilter _clickHandlerFilter;
  199. style::align _checkAlignment = style::al_left;
  200. Text::String _text;
  201. int _allowTextLines = 1;
  202. bool _textBreakEverywhere = false;
  203. };
  204. class Radiobutton;
  205. class RadiobuttonGroup
  206. : public std::enable_shared_from_this<RadiobuttonGroup> {
  207. public:
  208. RadiobuttonGroup() = default;
  209. RadiobuttonGroup(int value) : _value(value), _hasValue(true) {
  210. }
  211. void setChangedCallback(Fn<void(int value)> callback) {
  212. _changedCallback = std::move(callback);
  213. }
  214. [[nodiscard]] rpl::producer<int> changes() const {
  215. return _changes.events();
  216. }
  217. [[nodiscard]] rpl::producer<int> value() const {
  218. return hasValue()
  219. ? _changes.events_starting_with_copy(_value)
  220. : changes();
  221. }
  222. [[nodiscard]] bool hasValue() const {
  223. return _hasValue;
  224. }
  225. [[nodiscard]] int current() const {
  226. return _value;
  227. }
  228. void setValue(int value);
  229. private:
  230. friend class Radiobutton;
  231. void registerButton(Radiobutton *button);
  232. void unregisterButton(Radiobutton *button);
  233. int _value = 0;
  234. bool _hasValue = false;
  235. Fn<void(int value)> _changedCallback;
  236. rpl::event_stream<int> _changes;
  237. std::vector<Radiobutton*> _buttons;
  238. };
  239. class Radiobutton : public Checkbox {
  240. public:
  241. Radiobutton(
  242. QWidget *parent,
  243. const std::shared_ptr<RadiobuttonGroup> &group,
  244. int value,
  245. const QString &text,
  246. const style::Checkbox &st = st::defaultCheckbox,
  247. const style::Radio &radioSt = st::defaultRadio);
  248. Radiobutton(
  249. QWidget *parent,
  250. const std::shared_ptr<RadiobuttonGroup> &group,
  251. int value,
  252. const QString &text,
  253. const style::Checkbox &st,
  254. std::unique_ptr<AbstractCheckView> check);
  255. ~Radiobutton();
  256. protected:
  257. void handlePress() override;
  258. private:
  259. // Hide the names from Checkbox.
  260. bool checked() const;
  261. void checkedChanges() const;
  262. void checkedValue() const;
  263. void setChecked(bool checked, NotifyAboutChange notify);
  264. Checkbox *checkbox() {
  265. return this;
  266. }
  267. const Checkbox *checkbox() const {
  268. return this;
  269. }
  270. friend class RadiobuttonGroup;
  271. void handleNewGroupValue(int value);
  272. std::shared_ptr<RadiobuttonGroup> _group;
  273. int _value = 0;
  274. };
  275. template <typename Enum>
  276. class Radioenum;
  277. template <typename Enum>
  278. class RadioenumGroup : public RadiobuttonGroup {
  279. using Parent = RadiobuttonGroup;
  280. [[nodiscard]] static Enum Cast(int value) {
  281. return static_cast<Enum>(value);
  282. }
  283. public:
  284. RadioenumGroup() = default;
  285. RadioenumGroup(Enum value) : Parent(static_cast<int>(value)) {
  286. }
  287. template <typename Callback>
  288. void setChangedCallback(Callback &&callback) {
  289. Parent::setChangedCallback([copy = std::move(callback)](int value) {
  290. copy(Cast(value));
  291. });
  292. }
  293. [[nodiscard]] rpl::producer<Enum> changes() const {
  294. return Parent::changes() | rpl::map(Cast);
  295. }
  296. [[nodiscard]] rpl::producer<Enum> value() const {
  297. return Parent::value() | rpl::map(Cast);
  298. }
  299. [[nodiscard]] Enum current() const {
  300. return Cast(Parent::current());
  301. }
  302. void setValue(Enum value) {
  303. Parent::setValue(static_cast<int>(value));
  304. }
  305. private:
  306. template <typename OtherEnum>
  307. friend class Radioenum;
  308. };
  309. template <typename Enum>
  310. class Radioenum : public Radiobutton {
  311. public:
  312. Radioenum(
  313. QWidget *parent,
  314. const std::shared_ptr<RadioenumGroup<Enum>> &group,
  315. Enum value,
  316. const QString &text,
  317. const style::Checkbox &st = st::defaultCheckbox)
  318. : Radiobutton(
  319. parent,
  320. group->shared_from_this(),
  321. static_cast<int>(value),
  322. text,
  323. st) {
  324. }
  325. Radioenum(
  326. QWidget *parent,
  327. const std::shared_ptr<RadioenumGroup<Enum>> &group,
  328. Enum value,
  329. const QString &text,
  330. const style::Checkbox &st,
  331. std::unique_ptr<AbstractCheckView> check)
  332. : Radiobutton(
  333. parent,
  334. group->shared_from_this(),
  335. static_cast<int>(value),
  336. text,
  337. st,
  338. std::move(check)) {
  339. }
  340. };
  341. } // namespace Ui