diff --git a/ui/widgets/buttons.cpp b/ui/widgets/buttons.cpp index 905efe7..7d7a0c3 100644 --- a/ui/widgets/buttons.cpp +++ b/ui/widgets/buttons.cpp @@ -6,12 +6,15 @@ // #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/effects/ripple_animation.h" #include "ui/effects/cross_animation.h" #include "ui/effects/numbers_animation.h" #include "ui/image/image_prepare.h" #include "ui/painter.h" +#include + namespace Ui { LinkButton::LinkButton( @@ -628,4 +631,142 @@ QImage CrossButton::prepareRippleMask() const { return RippleAnimation::ellipseMask(QSize(_st.cross.size, _st.cross.size)); } +SettingsButton::SettingsButton( + QWidget *parent, + rpl::producer &&text) +: SettingsButton(parent, std::move(text), st::defaultSettingsButton) { +} + +SettingsButton::SettingsButton( + QWidget *parent, + rpl::producer &&text, + const style::SettingsButton &st) +: RippleButton(parent, st.ripple) +, _st(st) { + std::move( + text + ) | rpl::start_with_next([this](QString &&value) { + setText(std::move(value)); + }, lifetime()); +} + +SettingsButton *SettingsButton::toggleOn(rpl::producer &&toggled) { + Expects(_toggle == nullptr); + _toggle = std::make_unique( + isOver() ? _st.toggleOver : _st.toggle, + false, + [this] { rtlupdate(toggleRect()); }); + addClickHandler([this] { + _toggle->setChecked(!_toggle->checked(), anim::type::normal); + }); + std::move( + toggled + ) | rpl::start_with_next([this](bool toggled) { + _toggle->setChecked(toggled, anim::type::normal); + }, lifetime()); + _toggle->finishAnimating(); + return this; +} + +bool SettingsButton::toggled() const { + return _toggle ? _toggle->checked() : false; +} + +rpl::producer SettingsButton::toggledChanges() const { + if (_toggle) { + return _toggle->checkedChanges(); + } + return nullptr; +} + +rpl::producer SettingsButton::toggledValue() const { + if (_toggle) { + return _toggle->checkedValue(); + } + return nullptr; +} + +void SettingsButton::setColorOverride(std::optional textColorOverride) { + _textColorOverride = textColorOverride; + update(); +} + +void SettingsButton::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto paintOver = (isOver() || isDown()) && !isDisabled(); + p.fillRect(e->rect(), paintOver ? _st.textBgOver : _st.textBg); + + paintRipple(p, 0, 0); + + auto outerw = width(); + p.setFont(_st.font); + p.setPen(_textColorOverride + ? QPen(*_textColorOverride) + : paintOver + ? _st.textFgOver + : _st.textFg); + p.drawTextLeft( + _st.padding.left(), + _st.padding.top(), + outerw, + _text, + _textWidth); + + if (_toggle) { + auto rect = toggleRect(); + _toggle->paint(p, rect.left(), rect.top(), outerw); + } +} + +QRect SettingsButton::toggleRect() const { + Expects(_toggle != nullptr); + + auto size = _toggle->getSize(); + auto left = width() - _st.toggleSkip - size.width(); + auto top = (height() - size.height()) / 2; + return { QPoint(left, top), size }; +} + +int SettingsButton::resizeGetHeight(int newWidth) { + updateVisibleText(newWidth); + return _st.padding.top() + _st.height + _st.padding.bottom(); +} + +void SettingsButton::onStateChanged( + State was, + StateChangeSource source) { + if (!isDisabled() || !isDown()) { + RippleButton::onStateChanged(was, source); + } + if (_toggle) { + _toggle->setStyle(isOver() ? _st.toggleOver : _st.toggle); + } + setPointerCursor(!isDisabled()); +} + +void SettingsButton::setText(QString &&text) { + _original = std::move(text); + _originalWidth = _st.font->width(_original); + updateVisibleText(width()); +} + +void SettingsButton::updateVisibleText(int newWidth) { + auto availableWidth = newWidth + - _st.padding.left() + - _st.padding.right(); + if (_toggle) { + availableWidth -= (width() - toggleRect().x()); + } + accumulate_max(availableWidth, 0); + if (availableWidth < _originalWidth) { + _text = _st.font->elided(_original, availableWidth); + _textWidth = _st.font->width(_text); + } else { + _text = _original; + _textWidth = _originalWidth; + } + update(); +} + } // namespace Ui diff --git a/ui/widgets/buttons.h b/ui/widgets/buttons.h index 4cfffc4..e010c70 100644 --- a/ui/widgets/buttons.h +++ b/ui/widgets/buttons.h @@ -17,6 +17,7 @@ namespace Ui { class RippleAnimation; class NumbersAnimation; +class ToggleView; class LinkButton : public AbstractButton { public: @@ -230,4 +231,44 @@ private: }; +class SettingsButton : public Ui::RippleButton { +public: + SettingsButton( + QWidget *parent, + rpl::producer &&text); + SettingsButton( + QWidget *parent, + rpl::producer &&text, + const style::SettingsButton &st); + + SettingsButton *toggleOn(rpl::producer &&toggled); + bool toggled() const; + rpl::producer toggledChanges() const; + rpl::producer toggledValue() const; + + void setColorOverride(std::optional textColorOverride); + +protected: + int resizeGetHeight(int newWidth) override; + void onStateChanged( + State was, + StateChangeSource source) override; + + void paintEvent(QPaintEvent *e) override; + +private: + void setText(QString &&text); + QRect toggleRect() const; + void updateVisibleText(int newWidth); + + const style::SettingsButton &_st; + QString _original; + QString _text; + int _originalWidth = 0; + int _textWidth = 0; + std::unique_ptr _toggle; + std::optional _textColorOverride; + +}; + } // namespace Ui diff --git a/ui/widgets/widgets.style b/ui/widgets/widgets.style index 8b24e36..a463c50 100644 --- a/ui/widgets/widgets.style +++ b/ui/widgets/widgets.style @@ -485,7 +485,7 @@ ImportantTooltip { duration: int; } -InfoProfileButton { +SettingsButton { textFg: color; textFgOver: color; textBg: color; @@ -503,8 +503,8 @@ InfoProfileButton { ripple: RippleAnimation; } -InfoProfileCountButton { - button: InfoProfileButton; +SettingsCountButton { + button: SettingsButton; icon: icon; iconPosition: point; label: FlatLabel; @@ -1183,6 +1183,30 @@ backButton: IconButton(defaultIconButton) { } } +defaultSettingsToggle: Toggle(defaultToggle) { + untoggledFg: menuIconFg; +} +defaultSettingsToggleOver: Toggle(defaultSettingsToggle) { + untoggledFg: menuIconFgOver; +} +defaultSettingsButton: SettingsButton { + textFg: windowBoldFg; + textFgOver: windowBoldFgOver; + textBg: windowBg; + textBgOver: windowBgOver; + + font: boxTextFont; + + height: 20px; + padding: margins(22px, 10px, 22px, 8px); + + toggle: defaultSettingsToggle; + toggleOver: defaultSettingsToggleOver; + toggleSkip: 23px; + + ripple: defaultRippleAnimation; +} + // Windows specific title windowTitleButton: IconButton {