mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Generalize Checkbox layout.
Now any Checkbox can have Check, Radio or Toggle layout. Radiobutton is now a subclass of Checkbox with default Radio layout.
This commit is contained in:
parent
0ecef54e2b
commit
21d2f6a44f
18 changed files with 408 additions and 350 deletions
|
@ -630,7 +630,7 @@ ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : TWidget(parent)
|
|||
void ContactsBox::Inner::init() {
|
||||
subscribe(AuthSession::CurrentDownloaderTaskFinished(), [this] { update(); });
|
||||
connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
|
||||
connect(_allAdmins, SIGNAL(changed()), this, SLOT(onAllAdminsChanged()));
|
||||
subscribe(_allAdmins->checkedChanged, [this](bool checked) { onAllAdminsChanged(); });
|
||||
|
||||
_rowsTop = st::contactsMarginTop;
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
|
|
@ -196,9 +196,9 @@ void EditAdminBox::prepare() {
|
|||
}
|
||||
auto checked = (prepareRights.c_channelAdminRights().vflags.v & flags) != 0;
|
||||
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::defaultBoxCheckbox));
|
||||
connect(control, &Ui::Checkbox::changed, this, [this, control] {
|
||||
applyDependencies(control);
|
||||
}, Qt::QueuedConnection);
|
||||
subscribe(control->checkedChanged, [this, control](bool checked) {
|
||||
InvokeQueued(this, [this, control] { applyDependencies(control); });
|
||||
});
|
||||
_checkboxes.emplace(flags, control);
|
||||
};
|
||||
if (channel()->isMegagroup()) {
|
||||
|
@ -221,7 +221,7 @@ void EditAdminBox::prepare() {
|
|||
if (addAdmins != _checkboxes.end()) {
|
||||
_aboutAddAdmins = addControl(object_ptr<Ui::FlatLabel>(this, st::boxLabel));
|
||||
t_assert(addAdmins != _checkboxes.end());
|
||||
connect(addAdmins->second, &Ui::Checkbox::changed, this, [this] {
|
||||
subscribe(addAdmins->second->checkedChanged, [this](bool checked) {
|
||||
refreshAboutAddAdminsText();
|
||||
});
|
||||
refreshAboutAddAdminsText();
|
||||
|
@ -298,9 +298,9 @@ void EditRestrictedBox::prepare() {
|
|||
auto addCheckbox = [this, &prepareRights](Flags flags, const QString &text) {
|
||||
auto checked = (prepareRights.c_channelBannedRights().vflags.v & flags) == 0;
|
||||
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::defaultBoxCheckbox));
|
||||
connect(control, &Ui::Checkbox::changed, this, [this, control] {
|
||||
applyDependencies(control);
|
||||
}, Qt::QueuedConnection);
|
||||
subscribe(control->checkedChanged, [this, control](bool checked) {
|
||||
InvokeQueued(this, [this, control] { applyDependencies(control); });
|
||||
});
|
||||
_checkboxes.emplace(flags, control);
|
||||
};
|
||||
addCheckbox(Flag::f_view_messages, lang(lng_rights_chat_read));
|
||||
|
|
|
@ -244,7 +244,7 @@ void SendFilesBox::prepare() {
|
|||
auto compressed = (_compressConfirm == CompressConfirm::Auto) ? cCompressPastedImage() : (_compressConfirm == CompressConfirm::Yes);
|
||||
auto text = lng_send_images_compress(lt_count, _files.size());
|
||||
_compressed.create(this, text, compressed, st::defaultBoxCheckbox);
|
||||
connect(_compressed, SIGNAL(changed()), this, SLOT(onCompressedChange()));
|
||||
subscribe(_compressed->checkedChanged, [this](bool checked) { onCompressedChange(); });
|
||||
}
|
||||
if (_caption) {
|
||||
_caption->setMaxLength(MaxPhotoCaption);
|
||||
|
|
|
@ -30,11 +30,13 @@ namespace {
|
|||
|
||||
class UserCheckbox : public Ui::RippleButton {
|
||||
public:
|
||||
UserCheckbox(QWidget *parent, gsl::not_null<UserData*> user, bool checked, base::lambda<void()> changedCallback);
|
||||
UserCheckbox(QWidget *parent, gsl::not_null<UserData*> user, bool checked);
|
||||
|
||||
bool checked() const {
|
||||
return _checked;
|
||||
return _check->checked();
|
||||
}
|
||||
base::Observable<bool> checkedChanged;
|
||||
|
||||
enum class NotifyAboutChange {
|
||||
Notify,
|
||||
DontNotify,
|
||||
|
@ -57,24 +59,20 @@ protected:
|
|||
|
||||
private:
|
||||
const style::Checkbox &_st;
|
||||
std::unique_ptr<Ui::AbstractCheckView> _check;
|
||||
|
||||
QRect _checkRect;
|
||||
|
||||
bool _checked = false;
|
||||
Animation _a_checked;
|
||||
|
||||
gsl::not_null<UserData*> _user;
|
||||
base::lambda<void()> _changedCallback;
|
||||
QString _statusText;
|
||||
bool _statusOnline = false;
|
||||
|
||||
};
|
||||
|
||||
UserCheckbox::UserCheckbox(QWidget *parent, gsl::not_null<UserData*> user, bool checked, base::lambda<void()> changedCallback) : Ui::RippleButton(parent, st::defaultBoxCheckbox.ripple)
|
||||
UserCheckbox::UserCheckbox(QWidget *parent, gsl::not_null<UserData*> user, bool checked) : Ui::RippleButton(parent, st::defaultBoxCheckbox.ripple)
|
||||
, _st(st::adminLogFilterUserCheckbox)
|
||||
, _checked(checked)
|
||||
, _user(user)
|
||||
, _changedCallback(std::move(changedCallback)) {
|
||||
, _check(std::make_unique<Ui::CheckView>(st::defaultCheck, checked, [this] { rtlupdate(_checkRect); }))
|
||||
, _user(user) {
|
||||
setCursor(style::cur_pointer);
|
||||
setClickedCallback([this] {
|
||||
if (isDisabled()) return;
|
||||
|
@ -83,15 +81,15 @@ UserCheckbox::UserCheckbox(QWidget *parent, gsl::not_null<UserData*> user, bool
|
|||
auto now = unixtime();
|
||||
_statusText = App::onlineText(_user, now);
|
||||
_statusOnline = App::onlineColorUse(_user, now);
|
||||
_checkRect = myrtlrect(_st.margin.left(), (st::contactsPhotoSize - _st.diameter) / 2, _st.diameter, _st.diameter);
|
||||
auto checkSize = _check->getSize();
|
||||
_checkRect = { QPoint(_st.margin.left(), (st::contactsPhotoSize - checkSize.height()) / 2), checkSize };
|
||||
}
|
||||
|
||||
void UserCheckbox::setChecked(bool checked, NotifyAboutChange notify) {
|
||||
if (_checked != checked) {
|
||||
_checked = checked;
|
||||
_a_checked.start([this] { update(_checkRect); }, _checked ? 0. : 1., _checked ? 1. : 0., _st.duration);
|
||||
if (notify == NotifyAboutChange::Notify && _changedCallback) {
|
||||
_changedCallback();
|
||||
if (_check->checked() != checked) {
|
||||
_check->setCheckedAnimated(checked);
|
||||
if (notify == NotifyAboutChange::Notify) {
|
||||
checkedChanged.notify(checked, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,25 +98,15 @@ void UserCheckbox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto active = _a_checked.current(ms, _checked ? 1. : 0.);
|
||||
auto active = _check->currentAnimationValue(ms);
|
||||
auto color = anim::color(_st.rippleBg, _st.rippleBgActive, active);
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y() + (_checkRect.y() - st::defaultBoxCheckbox.margin.top()), ms, &color);
|
||||
|
||||
if (_checkRect.intersects(e->rect())) {
|
||||
auto pen = anim::pen(_st.checkFg, _st.checkFgActive, active);
|
||||
pen.setWidth(_st.thickness);
|
||||
p.setPen(pen);
|
||||
p.setBrush(anim::brush(_st.checkBg, anim::color(_st.checkFg, _st.checkFgActive, active), active));
|
||||
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawRoundedRect(QRectF(_checkRect).marginsRemoved(QMarginsF(_st.thickness / 2., _st.thickness / 2., _st.thickness / 2., _st.thickness / 2.)), st::buttonRadius - (_st.thickness / 2.), st::buttonRadius - (_st.thickness / 2.));
|
||||
}
|
||||
|
||||
if (active > 0) {
|
||||
_st.checkIcon.paint(p, _checkRect.topLeft(), width());
|
||||
}
|
||||
auto realCheckRect = myrtlrect(_checkRect);
|
||||
if (realCheckRect.intersects(e->rect())) {
|
||||
_check->paint(p, _checkRect.left(), _checkRect.top(), width());
|
||||
}
|
||||
if (realCheckRect.contains(e->rect())) return;
|
||||
|
||||
auto userpicLeft = _checkRect.x() + _checkRect.width() + st::adminLogFilterUserpicLeft;
|
||||
auto userpicTop = 0;
|
||||
|
@ -138,7 +126,7 @@ void UserCheckbox::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
void UserCheckbox::finishAnimations() {
|
||||
_a_checked.finish();
|
||||
_check->finishAnimation();
|
||||
}
|
||||
|
||||
int UserCheckbox::resizeGetHeight(int newWidth) {
|
||||
|
@ -159,7 +147,7 @@ QPoint UserCheckbox::prepareRippleStartPosition() const {
|
|||
|
||||
} // namespace
|
||||
|
||||
class FilterBox::Inner : public TWidget {
|
||||
class FilterBox::Inner : public TWidget, private base::Subscriber {
|
||||
public:
|
||||
Inner(QWidget *parent, gsl::not_null<ChannelData*> channel, const std::vector<gsl::not_null<UserData*>> &admins, const FilterValue &filter, base::lambda<void()> changedCallback);
|
||||
|
||||
|
@ -223,7 +211,7 @@ void FilterBox::Inner::createControls(const std::vector<gsl::not_null<UserData*>
|
|||
void FilterBox::Inner::createAllActionsCheckbox(const FilterValue &filter) {
|
||||
auto checked = (filter.flags == 0);
|
||||
_allFlags = addRow(object_ptr<Ui::Checkbox>(this, lang(lng_admin_log_filter_all_actions), checked, st::adminLogFilterCheckbox), st::adminLogFilterCheckbox.margin.top());
|
||||
connect(_allFlags, &Ui::Checkbox::changed, this, [this] {
|
||||
subscribe(_allFlags->checkedChanged, [this](bool checked) {
|
||||
if (!std::exchange(_restoringInvariant, true)) {
|
||||
auto allChecked = _allFlags->checked();
|
||||
for_const (auto &&checkbox, _filterFlags) {
|
||||
|
@ -244,7 +232,7 @@ void FilterBox::Inner::createActionsCheckboxes(const FilterValue &filter) {
|
|||
auto checked = (filter.flags == 0) || (filter.flags & flag);
|
||||
auto checkbox = addRow(object_ptr<Ui::Checkbox>(this, std::move(text), checked, st::defaultBoxCheckbox), st::adminLogFilterLittleSkip);
|
||||
_filterFlags.insert(flag, checkbox);
|
||||
connect(checkbox, &Ui::Checkbox::changed, this, [this] {
|
||||
subscribe(checkbox->checkedChanged, [this](bool checked) {
|
||||
if (!std::exchange(_restoringInvariant, true)) {
|
||||
auto allChecked = true;
|
||||
for_const (auto &&checkbox, _filterFlags) {
|
||||
|
@ -278,8 +266,8 @@ void FilterBox::Inner::createActionsCheckboxes(const FilterValue &filter) {
|
|||
|
||||
void FilterBox::Inner::createAllUsersCheckbox(const FilterValue &filter) {
|
||||
_allUsers = addRow(object_ptr<Ui::Checkbox>(this, lang(lng_admin_log_filter_all_admins), filter.allUsers, st::adminLogFilterCheckbox), st::adminLogFilterSkip);
|
||||
connect(_allUsers, &Ui::Checkbox::changed, this, [this] {
|
||||
if (_allUsers->checked() && !std::exchange(_restoringInvariant, true)) {
|
||||
subscribe(_allUsers->checkedChanged, [this](bool checked) {
|
||||
if (checked && !std::exchange(_restoringInvariant, true)) {
|
||||
for_const (auto &&checkbox, _admins) {
|
||||
checkbox->setChecked(true);
|
||||
}
|
||||
|
@ -294,7 +282,8 @@ void FilterBox::Inner::createAllUsersCheckbox(const FilterValue &filter) {
|
|||
void FilterBox::Inner::createAdminsCheckboxes(const std::vector<gsl::not_null<UserData*>> &admins, const FilterValue &filter) {
|
||||
for (auto user : admins) {
|
||||
auto checked = filter.allUsers || base::contains(filter.admins, user);
|
||||
auto checkbox = addRow(object_ptr<UserCheckbox>(this, user, checked, [this] {
|
||||
auto checkbox = addRow(object_ptr<UserCheckbox>(this, user, checked), st::adminLogFilterLittleSkip);
|
||||
subscribe(checkbox->checkedChanged, [this](bool checked) {
|
||||
if (!std::exchange(_restoringInvariant, true)) {
|
||||
auto allChecked = true;
|
||||
for_const (auto &&checkbox, _admins) {
|
||||
|
@ -311,7 +300,7 @@ void FilterBox::Inner::createAdminsCheckboxes(const std::vector<gsl::not_null<Us
|
|||
_changedCallback();
|
||||
}
|
||||
}
|
||||
}), st::adminLogFilterLittleSkip);
|
||||
});
|
||||
_admins.insert(user, checkbox);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -858,9 +858,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
|||
}
|
||||
}
|
||||
if (selected || context->selecting) {
|
||||
QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter));
|
||||
QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheck.diameter), rthumb.height() - st::defaultCheck.diameter), QSize(st::defaultCheck.diameter, st::defaultCheck.diameter));
|
||||
p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck);
|
||||
st::defaultCheckbox.checkIcon.paint(p, QPoint(rthumb.width() - st::defaultCheckbox.diameter, rthumb.y() + rthumb.height() - st::defaultCheckbox.diameter), _width);
|
||||
st::defaultCheck.icon.paint(p, QPoint(rthumb.width() - st::defaultCheck.diameter, rthumb.y() + rthumb.height() - st::defaultCheck.diameter), _width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
|
|||
|
||||
SettingsWidget::SettingsWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_settings_section))
|
||||
, _enableNotifications(this, lang(lng_profile_enable_notifications), true, st::defaultCheckbox) {
|
||||
connect(_enableNotifications, SIGNAL(changed()), this, SLOT(onNotificationsChange()));
|
||||
subscribe(_enableNotifications->checkedChanged, [this](bool checked) { onNotificationsChange(); });
|
||||
|
||||
Notify::PeerUpdate::Flags observeEvents = UpdateFlag::NotificationsEnabled;
|
||||
if (auto chat = peer->asChat()) {
|
||||
|
|
|
@ -222,8 +222,8 @@ void BackgroundWidget::createControls() {
|
|||
connect(_background, SIGNAL(editTheme()), this, SLOT(onEditTheme()));
|
||||
connect(_background, SIGNAL(useDefault()), this, SLOT(onUseDefaultTheme()));
|
||||
|
||||
addChildRow(_tile, margin, lang(lng_settings_bg_tile), SLOT(onTile()), Window::Theme::Background()->tile());
|
||||
addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), SLOT(onAdaptive()), Global::AdaptiveForWide());
|
||||
addChildRow(_tile, margin, lang(lng_settings_bg_tile), [this](bool) { onTile(); }, Window::Theme::Background()->tile());
|
||||
addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), [this](bool) { onAdaptive(); }, Global::AdaptiveForWide());
|
||||
if (Global::AdaptiveChatLayout() != Adaptive::ChatLayout::Wide) {
|
||||
_adaptive->hideFast();
|
||||
}
|
||||
|
|
|
@ -85,9 +85,9 @@ void BlockWidget::rowHeightUpdated() {
|
|||
}
|
||||
}
|
||||
|
||||
void BlockWidget::createChildRow(object_ptr<Ui::Checkbox> &child, style::margins &margin, const QString &text, const char *slot, bool checked) {
|
||||
void BlockWidget::createChildRow(object_ptr<Ui::Checkbox> &child, style::margins &margin, const QString &text, base::lambda<void(bool checked)> callback, bool checked) {
|
||||
child.create(this, text, checked, st::defaultBoxCheckbox);
|
||||
connect(child, SIGNAL(changed()), this, slot);
|
||||
subscribe(child->checkedChanged, std::move(callback));
|
||||
}
|
||||
|
||||
void BlockWidget::createChildRow(object_ptr<Ui::LinkButton> &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st) {
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
margin.setRight(margin.right() - padding.right());
|
||||
margin.setBottom(margin.bottom() - padding.bottom());
|
||||
}
|
||||
void createChildRow(object_ptr<Ui::Checkbox> &child, style::margins &margin, const QString &text, const char *slot, bool checked);
|
||||
void createChildRow(object_ptr<Ui::Checkbox> &child, style::margins &margin, const QString &text, base::lambda<void(bool checked)> callback, bool checked);
|
||||
void createChildRow(object_ptr<Ui::LinkButton> &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st = st::boxLinkButton);
|
||||
|
||||
template <typename Enum>
|
||||
|
|
|
@ -154,7 +154,7 @@ void ChatSettingsWidget::createControls() {
|
|||
style::margins marginSub(0, 0, 0, st::settingsSubSkip);
|
||||
style::margins slidedPadding(0, marginSub.bottom() / 2, 0, marginSub.bottom() - (marginSub.bottom() / 2));
|
||||
|
||||
addChildRow(_replaceEmoji, marginSub, lang(lng_settings_replace_emojis), SLOT(onReplaceEmoji()), cReplaceEmojis());
|
||||
addChildRow(_replaceEmoji, marginSub, lang(lng_settings_replace_emojis), [this](bool) { onReplaceEmoji(); }, cReplaceEmojis());
|
||||
style::margins marginList(st::defaultBoxCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
|
||||
addChildRow(_viewList, marginList, slidedPadding, lang(lng_settings_view_emojis), SLOT(onViewList()), st::defaultLinkButton);
|
||||
if (!cReplaceEmojis()) {
|
||||
|
@ -166,7 +166,7 @@ void ChatSettingsWidget::createControls() {
|
|||
#else // OS_WIN_STORE
|
||||
auto pathMargin = marginSkip;
|
||||
#endif // OS_WIN_STORE
|
||||
addChildRow(_dontAskDownloadPath, pathMargin, lang(lng_download_path_dont_ask), SLOT(onDontAskDownloadPath()), !Global::AskDownloadPath());
|
||||
addChildRow(_dontAskDownloadPath, pathMargin, lang(lng_download_path_dont_ask), [this](bool) { onDontAskDownloadPath(); }, !Global::AskDownloadPath());
|
||||
|
||||
#ifndef OS_WIN_STORE
|
||||
style::margins marginPath(st::defaultBoxCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
|
||||
|
|
|
@ -175,7 +175,7 @@ void GeneralWidget::refreshControls() {
|
|||
style::margins slidedPadding(0, marginSmall.bottom() / 2, 0, marginSmall.bottom() - (marginSmall.bottom() / 2));
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
addChildRow(_updateAutomatically, marginSub, lang(lng_settings_update_automatically), SLOT(onUpdateAutomatically()), cAutoUpdate());
|
||||
addChildRow(_updateAutomatically, marginSub, lang(lng_settings_update_automatically), [this](bool) { onUpdateAutomatically(); }, cAutoUpdate());
|
||||
style::margins marginLink(st::defaultBoxCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
|
||||
addChildRow(_updateRow, marginLink, slidedPadding);
|
||||
connect(_updateRow->entity(), SIGNAL(restart()), this, SLOT(onRestart()));
|
||||
|
@ -186,20 +186,20 @@ void GeneralWidget::refreshControls() {
|
|||
|
||||
if (cPlatform() == dbipWindows || cSupportTray()) {
|
||||
auto workMode = Global::WorkMode().value();
|
||||
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onEnableTrayIcon()), (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray));
|
||||
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), [this](bool) { onEnableTrayIcon(); }, (workMode == dbiwmTrayOnly || workMode == dbiwmWindowAndTray));
|
||||
if (cPlatform() == dbipWindows) {
|
||||
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray));
|
||||
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), [this](bool) { onEnableTaskbarIcon(); }, (workMode == dbiwmWindowOnly || workMode == dbiwmWindowAndTray));
|
||||
|
||||
#ifndef OS_WIN_STORE
|
||||
addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart());
|
||||
addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), SLOT(onStartMinimized()), (cStartMinimized() && !Global::LocalPasscode()));
|
||||
addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), [this](bool) { onAutoStart(); }, cAutoStart());
|
||||
addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), [this](bool) { onStartMinimized(); }, (cStartMinimized() && !Global::LocalPasscode()));
|
||||
subscribe(Global::RefLocalPasscodeChanged(), [this] {
|
||||
_startMinimized->entity()->setChecked(cStartMinimized() && !Global::LocalPasscode());
|
||||
});
|
||||
if (!cAutoStart()) {
|
||||
_startMinimized->hideFast();
|
||||
}
|
||||
addChildRow(_addInSendTo, marginSmall, lang(lng_settings_add_sendto), SLOT(onAddInSendTo()), cSendToMenu());
|
||||
addChildRow(_addInSendTo, marginSmall, lang(lng_settings_add_sendto), [this](bool) { onAddInSendTo(); }, cSendToMenu());
|
||||
#endif // OS_WIN_STORE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,9 +56,9 @@ NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : Bloc
|
|||
void NotificationsWidget::createControls() {
|
||||
style::margins margin(0, 0, 0, st::settingsSkip);
|
||||
style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2));
|
||||
addChildRow(_desktopNotifications, margin, lang(lng_settings_desktop_notify), SLOT(onDesktopNotifications()), Global::DesktopNotify());
|
||||
addChildRow(_showSenderName, margin, slidedPadding, lang(lng_settings_show_name), SLOT(onShowSenderName()), Global::NotifyView() <= dbinvShowName);
|
||||
addChildRow(_showMessagePreview, margin, slidedPadding, lang(lng_settings_show_preview), SLOT(onShowMessagePreview()), Global::NotifyView() <= dbinvShowPreview);
|
||||
addChildRow(_desktopNotifications, margin, lang(lng_settings_desktop_notify), [this](bool) { onDesktopNotifications(); }, Global::DesktopNotify());
|
||||
addChildRow(_showSenderName, margin, slidedPadding, lang(lng_settings_show_name), [this](bool) { onShowSenderName(); }, Global::NotifyView() <= dbinvShowName);
|
||||
addChildRow(_showMessagePreview, margin, slidedPadding, lang(lng_settings_show_preview), [this](bool) { onShowMessagePreview(); }, Global::NotifyView() <= dbinvShowPreview);
|
||||
if (!_showSenderName->entity()->checked()) {
|
||||
_showMessagePreview->hideFast();
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ void NotificationsWidget::createControls() {
|
|||
_showSenderName->hideFast();
|
||||
_showMessagePreview->hideFast();
|
||||
}
|
||||
addChildRow(_playSound, margin, lang(lng_settings_sound_notify), SLOT(onPlaySound()), Global::SoundNotify());
|
||||
addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), SLOT(onIncludeMuted()), Global::IncludeMuted());
|
||||
addChildRow(_playSound, margin, lang(lng_settings_sound_notify), [this](bool) { onPlaySound(); }, Global::SoundNotify());
|
||||
addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), [this](bool) { onIncludeMuted(); }, Global::IncludeMuted());
|
||||
|
||||
if (cPlatform() != dbipMac) {
|
||||
createNotificationsControls();
|
||||
|
@ -87,7 +87,7 @@ void NotificationsWidget::createNotificationsControls() {
|
|||
#endif // Q_OS_WIN || Q_OS_LINUX64 || Q_OS_LINUX32
|
||||
}
|
||||
if (!nativeNotificationsLabel.isEmpty()) {
|
||||
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, SLOT(onNativeNotifications()), Global::NativeNotifications());
|
||||
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, [this](bool) { onNativeNotifications(); }, Global::NativeNotifications());
|
||||
}
|
||||
addChildRow(_advanced, margin, slidedPadding, lang(lng_settings_advanced_notifications), SLOT(onAdvanced()));
|
||||
if (!nativeNotificationsLabel.isEmpty() && Global::NativeNotifications()) {
|
||||
|
|
|
@ -52,7 +52,7 @@ ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent,
|
|||
void ScaleWidget::createControls() {
|
||||
style::margins margin(0, 0, 0, st::settingsSmallSkip);
|
||||
|
||||
addChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), SLOT(onAutoChanged()), (cConfigScale() == dbisAuto));
|
||||
addChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), [this](bool) { onAutoChanged(); }, (cConfigScale() == dbisAuto));
|
||||
addChildRow(_scale, style::margins(0, 0, 0, 0));
|
||||
|
||||
_scale->addSection(scaleLabel(dbisOne));
|
||||
|
|
|
@ -28,12 +28,18 @@ inline QPoint rtlpoint(int x, int y, int outerw) {
|
|||
inline QPoint rtlpoint(const QPoint &p, int outerw) {
|
||||
return rtl() ? QPoint(outerw - p.x(), p.y()) : p;
|
||||
}
|
||||
inline QPointF rtlpoint(const QPointF &p, int outerw) {
|
||||
return rtl() ? QPointF(outerw - p.x(), p.y()) : p;
|
||||
}
|
||||
inline QRect rtlrect(int x, int y, int w, int h, int outerw) {
|
||||
return QRect(rtl() ? (outerw - x - w) : x, y, w, h);
|
||||
}
|
||||
inline QRect rtlrect(const QRect &r, int outerw) {
|
||||
return rtl() ? QRect(outerw - r.x() - r.width(), r.y(), r.width(), r.height()) : r;
|
||||
}
|
||||
inline QRectF rtlrect(const QRectF &r, int outerw) {
|
||||
return rtl() ? QRectF(outerw - r.x() - r.width(), r.y(), r.width(), r.height()) : r;
|
||||
}
|
||||
inline QRect centerrect(const QRect &inRect, const QRect &rect) {
|
||||
return QRect(inRect.x() + (inRect.width() - rect.width()) / 2, inRect.y() + (inRect.height() - rect.height()) / 2, rect.width(), rect.height());
|
||||
}
|
||||
|
|
|
@ -35,14 +35,158 @@ TextParseOptions _checkboxOptions = {
|
|||
|
||||
} // namespace
|
||||
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st) : RippleButton(parent, st.ripple)
|
||||
AbstractCheckView::AbstractCheckView(int duration, bool checked, base::lambda<void()> updateCallback)
|
||||
: _duration(duration)
|
||||
, _checked(checked)
|
||||
, _updateCallback(std::move(updateCallback)) {
|
||||
}
|
||||
|
||||
void AbstractCheckView::setCheckedFast(bool checked) {
|
||||
_checked = checked;
|
||||
finishAnimation();
|
||||
if (_updateCallback) {
|
||||
_updateCallback();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCheckView::setUpdateCallback(base::lambda<void()> updateCallback) {
|
||||
_updateCallback = std::move(updateCallback);
|
||||
if (_toggleAnimation.animating()) {
|
||||
_toggleAnimation.setUpdateCallback(_updateCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCheckView::setCheckedAnimated(bool checked) {
|
||||
if (_checked != checked) {
|
||||
_checked = checked;
|
||||
_toggleAnimation.start(_updateCallback, _checked ? 0. : 1., _checked ? 1. : 0., _duration);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCheckView::finishAnimation() {
|
||||
_toggleAnimation.finish();
|
||||
}
|
||||
|
||||
float64 AbstractCheckView::currentAnimationValue(TimeMs ms) {
|
||||
return ms ? _toggleAnimation.current(ms, _checked ? 1. : 0.) : _toggleAnimation.current(_checked ? 1. : 0.);
|
||||
}
|
||||
|
||||
ToggleView::ToggleView(const style::Toggle &st, bool checked, base::lambda<void()> updateCallback) : AbstractCheckView(st.duration, checked, std::move(updateCallback))
|
||||
, _st(&st) {
|
||||
}
|
||||
|
||||
QSize ToggleView::getSize() {
|
||||
return QSize(_st->diameter + _st->width, _st->diameter);
|
||||
}
|
||||
|
||||
void ToggleView::setStyle(const style::Toggle &st) {
|
||||
_st = &st;
|
||||
}
|
||||
|
||||
void ToggleView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
auto toggled = currentAnimationValue(ms);
|
||||
auto fullWidth = _st->diameter + _st->width;
|
||||
auto innerDiameter = _st->diameter - 2 * _st->shift;
|
||||
auto innerRadius = float64(innerDiameter) / 2.;
|
||||
auto bgRect = rtlrect(left + _st->shift, top + _st->shift, fullWidth - 2 * _st->shift, innerDiameter, outerWidth);
|
||||
auto fgRect = rtlrect(left + anim::interpolate(0, fullWidth - _st->diameter, toggled), top, _st->diameter, _st->diameter, outerWidth);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(anim::brush(_st->untoggledFg, _st->toggledFg, toggled));
|
||||
p.drawRoundedRect(bgRect, innerRadius, innerRadius);
|
||||
|
||||
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled);
|
||||
pen.setWidth(_st->border);
|
||||
p.setPen(pen);
|
||||
p.setBrush(anim::brush(_st->untoggledBg, _st->toggledBg, toggled));
|
||||
p.drawEllipse(fgRect);
|
||||
}
|
||||
|
||||
CheckView::CheckView(const style::Check &st, bool checked, base::lambda<void()> updateCallback) : AbstractCheckView(st.duration, checked, std::move(updateCallback))
|
||||
, _st(&st) {
|
||||
}
|
||||
|
||||
QSize CheckView::getSize() {
|
||||
return QSize(_st->diameter, _st->diameter);
|
||||
}
|
||||
|
||||
void CheckView::setStyle(const style::Check &st) {
|
||||
_st = &st;
|
||||
}
|
||||
|
||||
void CheckView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) {
|
||||
auto toggled = currentAnimationValue(ms);
|
||||
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled);
|
||||
pen.setWidth(_st->thickness);
|
||||
p.setPen(pen);
|
||||
p.setBrush(anim::brush(_st->bg, anim::color(_st->untoggledFg, _st->toggledFg, toggled), toggled));
|
||||
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawRoundedRect(rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(_st->thickness / 2., _st->thickness / 2., _st->thickness / 2., _st->thickness / 2.)), outerWidth), st::buttonRadius - (_st->thickness / 2.), st::buttonRadius - (_st->thickness / 2.));
|
||||
}
|
||||
|
||||
if (toggled > 0) {
|
||||
_st->icon.paint(p, QPoint(left, top), outerWidth);
|
||||
}
|
||||
}
|
||||
|
||||
RadioView::RadioView(const style::Radio &st, bool checked, base::lambda<void()> updateCallback) : AbstractCheckView(st.duration, checked, std::move(updateCallback))
|
||||
, _st(&st) {
|
||||
}
|
||||
|
||||
QSize RadioView::getSize() {
|
||||
return QSize(_st->diameter, _st->diameter);
|
||||
}
|
||||
|
||||
void RadioView::setStyle(const style::Radio &st) {
|
||||
_st = &st;
|
||||
}
|
||||
|
||||
void RadioView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
auto toggled = currentAnimationValue(ms);
|
||||
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled);
|
||||
pen.setWidth(_st->thickness);
|
||||
p.setPen(pen);
|
||||
p.setBrush(_st->bg);
|
||||
//int32 skip = qCeil(_st->thickness / 2.);
|
||||
//p.drawEllipse(_checkRect.marginsRemoved(QMargins(skip, skip, skip, skip)));
|
||||
p.drawEllipse(rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(_st->thickness / 2., _st->thickness / 2., _st->thickness / 2., _st->thickness / 2.)), outerWidth));
|
||||
|
||||
if (toggled > 0) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(anim::brush(_st->untoggledFg, _st->toggledFg, toggled));
|
||||
|
||||
auto skip0 = _st->diameter / 2., skip1 = _st->skip / 10., checkSkip = skip0 * (1. - toggled) + skip1 * toggled;
|
||||
p.drawEllipse(rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(checkSkip, checkSkip, checkSkip, checkSkip)), outerWidth));
|
||||
//int32 fskip = qFloor(checkSkip), cskip = qCeil(checkSkip);
|
||||
//if (2 * fskip < _checkRect.width()) {
|
||||
// if (fskip != cskip) {
|
||||
// p.setOpacity(float64(cskip) - checkSkip);
|
||||
// p.drawEllipse(_checkRect.marginsRemoved(QMargins(fskip, fskip, fskip, fskip)));
|
||||
// p.setOpacity(1.);
|
||||
// }
|
||||
// if (2 * cskip < _checkRect.width()) {
|
||||
// p.drawEllipse(_checkRect.marginsRemoved(QMargins(cskip, cskip, cskip, cskip)));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st, const style::Check &checkSt) : Checkbox(parent, text, st, std::make_unique<CheckView>(checkSt, checked, [this] { updateCheck(); })) {
|
||||
}
|
||||
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st, const style::Toggle &toggleSt) : Checkbox(parent, text, st, std::make_unique<ToggleView>(toggleSt, checked, [this] { updateCheck(); })) {
|
||||
}
|
||||
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, const style::Checkbox &st, std::unique_ptr<AbstractCheckView> check) : RippleButton(parent, st.ripple)
|
||||
, _st(st)
|
||||
, _text(_st.style, text, _checkboxOptions)
|
||||
, _checked(checked) {
|
||||
, _check(std::move(check))
|
||||
, _text(_st.style, text, _checkboxOptions) {
|
||||
resizeToText();
|
||||
|
||||
connect(this, SIGNAL(clicked()), this, SLOT(onClicked()));
|
||||
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
|
@ -53,7 +197,7 @@ void Checkbox::setText(const QString &text) {
|
|||
}
|
||||
|
||||
bool Checkbox::checked() const {
|
||||
return _checked;
|
||||
return _check->checked();
|
||||
}
|
||||
|
||||
void Checkbox::resizeToText() {
|
||||
|
@ -62,21 +206,20 @@ void Checkbox::resizeToText() {
|
|||
} else {
|
||||
resizeToWidth(_st.width);
|
||||
}
|
||||
_checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter);
|
||||
_checkRect = { QPoint(_st.margin.left(), _st.margin.top()), _check->getSize() };
|
||||
}
|
||||
|
||||
void Checkbox::setChecked(bool checked, NotifyAboutChange notify) {
|
||||
if (_checked != checked) {
|
||||
_checked = checked;
|
||||
_a_checked.start([this] { update(_checkRect); }, _checked ? 0. : 1., _checked ? 1. : 0., _st.duration);
|
||||
if (_check->checked() != checked) {
|
||||
_check->setCheckedAnimated(checked);
|
||||
if (notify == NotifyAboutChange::Notify) {
|
||||
emit changed();
|
||||
checkedChanged.notify(checked, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Checkbox::finishAnimations() {
|
||||
_a_checked.finish();
|
||||
_check->finishAnimation();
|
||||
}
|
||||
|
||||
int Checkbox::naturalWidth() const {
|
||||
|
@ -87,38 +230,22 @@ void Checkbox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto active = _a_checked.current(ms, _checked ? 1. : 0.);
|
||||
auto active = _check->currentAnimationValue(ms);
|
||||
auto color = anim::color(_st.rippleBg, _st.rippleBgActive, active);
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms, &color);
|
||||
|
||||
if (_checkRect.intersects(e->rect())) {
|
||||
auto pen = anim::pen(_st.checkFg, _st.checkFgActive, active);
|
||||
pen.setWidth(_st.thickness);
|
||||
p.setPen(pen);
|
||||
p.setBrush(anim::brush(_st.checkBg, anim::color(_st.checkFg, _st.checkFgActive, active), active));
|
||||
|
||||
{
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawRoundedRect(QRectF(_checkRect).marginsRemoved(QMarginsF(_st.thickness / 2., _st.thickness / 2., _st.thickness / 2., _st.thickness / 2.)), st::buttonRadius - (_st.thickness / 2.), st::buttonRadius - (_st.thickness / 2.));
|
||||
}
|
||||
|
||||
if (active > 0) {
|
||||
_st.checkIcon.paint(p, QPoint(_st.margin.left(), _st.margin.top()), width());
|
||||
}
|
||||
auto realCheckRect = myrtlrect(_checkRect);
|
||||
if (realCheckRect.intersects(e->rect())) {
|
||||
_check->paint(p, _checkRect.left(), _checkRect.top(), width());
|
||||
}
|
||||
if (_checkRect.contains(e->rect())) return;
|
||||
if (realCheckRect.contains(e->rect())) return;
|
||||
|
||||
auto textWidth = qMax(width() - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1);
|
||||
auto textWidth = qMax(width() - (_st.textPosition.x() + (_st.textPosition.x() - _check->getSize().width())), 1);
|
||||
|
||||
p.setPen(_st.textFg);
|
||||
_text.drawLeftElided(p, _st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), textWidth, width());
|
||||
}
|
||||
|
||||
void Checkbox::onClicked() {
|
||||
if (isDisabled()) return;
|
||||
setChecked(!checked());
|
||||
}
|
||||
|
||||
void Checkbox::onStateChanged(State was, StateChangeSource source) {
|
||||
RippleButton::onStateChanged(was, source);
|
||||
|
||||
|
@ -127,6 +254,13 @@ void Checkbox::onStateChanged(State was, StateChangeSource source) {
|
|||
} else if (!isDisabled() && (was & StateFlag::Disabled)) {
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
auto now = state();
|
||||
if (!isDisabled() && (was & StateFlag::Over) && (now & StateFlag::Over)) {
|
||||
if ((was & StateFlag::Down) && !(now & StateFlag::Down)) {
|
||||
setChecked(!checked());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Checkbox::resizeGetHeight(int newWidth) {
|
||||
|
@ -159,88 +293,26 @@ void RadiobuttonGroup::setValue(int value) {
|
|||
}
|
||||
}
|
||||
|
||||
Radiobutton::Radiobutton(QWidget *parent, const std::shared_ptr<RadiobuttonGroup> &group, int value, const QString &text, const style::Checkbox &st) : RippleButton(parent, st.ripple)
|
||||
Radiobutton::Radiobutton(QWidget *parent, const std::shared_ptr<RadiobuttonGroup> &group, int value, const QString &text, const style::Checkbox &st, const style::Radio &radioSt) : Checkbox(parent, text, st, std::make_unique<RadioView>(radioSt, (group->hasValue() && group->value() == value), [this] { updateCheck(); }))
|
||||
, _group(group)
|
||||
, _value(value)
|
||||
, _st(st)
|
||||
, _text(_st.style, text, _checkboxOptions)
|
||||
, _checked(_group->hasValue() && _group->value() == _value) {
|
||||
, _value(value) {
|
||||
_group->registerButton(this);
|
||||
|
||||
if (_st.width <= 0) {
|
||||
resizeToWidth(_text.maxWidth() - _st.width);
|
||||
} else {
|
||||
resizeToWidth(_st.width);
|
||||
}
|
||||
_checkRect = myrtlrect(_st.margin.left(), _st.margin.top(), _st.diameter, _st.diameter);
|
||||
subscribe(checkbox()->checkedChanged, [this](bool checked) {
|
||||
if (checked) {
|
||||
_group->setValue(_value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Radiobutton::handleNewGroupValue(int value) {
|
||||
auto checked = (value == _value);
|
||||
if (_checked != checked) {
|
||||
_checked = checked;
|
||||
_a_checked.start([this] { update(_checkRect); }, _checked ? 0. : 1., _checked ? 1. : 0., _st.duration);
|
||||
if (checkbox()->checked() != checked) {
|
||||
checkbox()->setChecked(checked, Ui::Checkbox::NotifyAboutChange::DontNotify);
|
||||
}
|
||||
}
|
||||
|
||||
int Radiobutton::naturalWidth() const {
|
||||
return _st.textPosition.x() + _text.maxWidth();
|
||||
}
|
||||
|
||||
void Radiobutton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto active = _a_checked.current(ms, _checked ? 1. : 0.);
|
||||
auto color = anim::color(_st.rippleBg, _st.rippleBgActive, active);
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms, &color);
|
||||
|
||||
if (_checkRect.intersects(e->rect())) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
auto pen = anim::pen(_st.checkFg, _st.checkFgActive, active);
|
||||
pen.setWidth(_st.thickness);
|
||||
p.setPen(pen);
|
||||
p.setBrush(_st.checkBg);
|
||||
//int32 skip = qCeil(_st.thickness / 2.);
|
||||
//p.drawEllipse(_checkRect.marginsRemoved(QMargins(skip, skip, skip, skip)));
|
||||
p.drawEllipse(QRectF(_checkRect).marginsRemoved(QMarginsF(_st.thickness / 2., _st.thickness / 2., _st.thickness / 2., _st.thickness / 2.)));
|
||||
|
||||
if (active > 0) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(anim::brush(_st.checkFg, _st.checkFgActive, active));
|
||||
|
||||
auto skip0 = _checkRect.width() / 2., skip1 = _st.radioSkip / 10., checkSkip = skip0 * (1. - active) + skip1 * active;
|
||||
p.drawEllipse(QRectF(_checkRect).marginsRemoved(QMarginsF(checkSkip, checkSkip, checkSkip, checkSkip)));
|
||||
//int32 fskip = qFloor(checkSkip), cskip = qCeil(checkSkip);
|
||||
//if (2 * fskip < _checkRect.width()) {
|
||||
// if (fskip != cskip) {
|
||||
// p.setOpacity(float64(cskip) - checkSkip);
|
||||
// p.drawEllipse(_checkRect.marginsRemoved(QMargins(fskip, fskip, fskip, fskip)));
|
||||
// p.setOpacity(1.);
|
||||
// }
|
||||
// if (2 * cskip < _checkRect.width()) {
|
||||
// p.drawEllipse(_checkRect.marginsRemoved(QMargins(cskip, cskip, cskip, cskip)));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (_checkRect.contains(e->rect())) return;
|
||||
|
||||
auto textWidth = qMax(width() - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1);
|
||||
|
||||
p.setPen(_st.textFg);
|
||||
_text.drawLeftElided(p, _st.margin.left() + _st.textPosition.x(), _st.margin.top() + _st.textPosition.y(), textWidth, width());
|
||||
}
|
||||
|
||||
void Radiobutton::onStateChanged(State was, StateChangeSource source) {
|
||||
RippleButton::onStateChanged(was, source);
|
||||
|
||||
if (isDisabled() && !(was & StateFlag::Disabled)) {
|
||||
setCursor(style::cur_default);
|
||||
} else if (!isDisabled() && (was & StateFlag::Disabled)) {
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
Checkbox::onStateChanged(was, source);
|
||||
|
||||
auto now = state();
|
||||
if (!isDisabled() && (was & StateFlag::Over) && (now & StateFlag::Over)) {
|
||||
|
@ -250,80 +322,8 @@ void Radiobutton::onStateChanged(State was, StateChangeSource source) {
|
|||
}
|
||||
}
|
||||
|
||||
int Radiobutton::resizeGetHeight(int newWidth) {
|
||||
return _st.height;
|
||||
}
|
||||
|
||||
QImage Radiobutton::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
}
|
||||
|
||||
QPoint Radiobutton::prepareRippleStartPosition() const {
|
||||
auto position = mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
|
||||
if (QRect(0, 0, _st.rippleAreaSize, _st.rippleAreaSize).contains(position)) {
|
||||
return position;
|
||||
}
|
||||
return disabledRippleStartPosition();
|
||||
}
|
||||
|
||||
Radiobutton::~Radiobutton() {
|
||||
_group->unregisterButton(this);
|
||||
}
|
||||
|
||||
ToggleView::ToggleView(const style::Toggle &st, bool toggled, base::lambda<void()> updateCallback)
|
||||
: _st(&st)
|
||||
, _toggled(toggled)
|
||||
, _updateCallback(std::move(updateCallback)) {
|
||||
}
|
||||
|
||||
void ToggleView::setStyle(const style::Toggle &st) {
|
||||
_st = &st;
|
||||
}
|
||||
|
||||
void ToggleView::setToggledFast(bool toggled) {
|
||||
_toggled = toggled;
|
||||
finishAnimation();
|
||||
if (_updateCallback) {
|
||||
_updateCallback();
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleView::setUpdateCallback(base::lambda<void()> updateCallback) {
|
||||
_updateCallback = std::move(updateCallback);
|
||||
if (_toggleAnimation.animating()) {
|
||||
_toggleAnimation.setUpdateCallback(_updateCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleView::setToggledAnimated(bool toggled) {
|
||||
if (_toggled != toggled) {
|
||||
_toggled = toggled;
|
||||
_toggleAnimation.start(_updateCallback, _toggled ? 0. : 1., _toggled ? 1. : 0., _st->duration);
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleView::finishAnimation() {
|
||||
_toggleAnimation.finish();
|
||||
}
|
||||
|
||||
void ToggleView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
auto toggled = _toggleAnimation.current(ms, _toggled ? 1. : 0.);
|
||||
auto fullWidth = _st->diameter + _st->width;
|
||||
auto innerDiameter = _st->diameter - 2 * _st->shift;
|
||||
auto innerRadius = float64(innerDiameter) / 2.;
|
||||
auto bgRect = rtlrect(left + _st->shift, top + _st->shift, fullWidth - 2 * _st->shift, innerDiameter, outerWidth);
|
||||
auto fgRect = rtlrect(left + anim::interpolate(0, fullWidth - _st->diameter, toggled), top, _st->diameter, _st->diameter, outerWidth);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(anim::brush(_st->untoggledFg, _st->toggledFg, toggled));
|
||||
p.drawRoundedRect(bgRect, innerRadius, innerRadius);
|
||||
|
||||
auto pen = anim::pen(_st->untoggledFg, _st->toggledFg, toggled);
|
||||
pen.setWidth(_st->border);
|
||||
p.setPen(pen);
|
||||
p.setBrush(anim::brush(_st->untoggledBg, _st->toggledBg, toggled));
|
||||
p.drawEllipse(fgRect);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -25,11 +25,87 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
|
||||
namespace Ui {
|
||||
|
||||
class Checkbox : public RippleButton {
|
||||
Q_OBJECT
|
||||
|
||||
class AbstractCheckView {
|
||||
public:
|
||||
Checkbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox);
|
||||
AbstractCheckView(int duration, bool checked, base::lambda<void()> updateCallback);
|
||||
|
||||
void setCheckedFast(bool checked);
|
||||
void setCheckedAnimated(bool checked);
|
||||
void finishAnimation();
|
||||
void setUpdateCallback(base::lambda<void()> updateCallback);
|
||||
bool checked() const {
|
||||
return _checked;
|
||||
}
|
||||
float64 currentAnimationValue(TimeMs ms);
|
||||
|
||||
virtual QSize getSize() = 0;
|
||||
|
||||
// Zero instead of ms value means that animation was already updated for this time.
|
||||
// It can be passed to currentAnimationValue() safely.
|
||||
virtual void paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) = 0;
|
||||
|
||||
void paint(Painter &p, int left, int top, int outerWidth) {
|
||||
// Pass zero in ms if the animation was already updated for this time.
|
||||
paint(p, left, top, outerWidth, 0);
|
||||
}
|
||||
|
||||
virtual ~AbstractCheckView() = default;
|
||||
|
||||
private:
|
||||
int _duration = 0;
|
||||
bool _checked = false;
|
||||
base::lambda<void()> _updateCallback;
|
||||
Animation _toggleAnimation;
|
||||
|
||||
};
|
||||
|
||||
class CheckView : public AbstractCheckView {
|
||||
public:
|
||||
CheckView(const style::Check &st, bool checked, base::lambda<void()> updateCallback);
|
||||
|
||||
void setStyle(const style::Check &st);
|
||||
|
||||
QSize getSize() override;
|
||||
void paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) override;
|
||||
|
||||
private:
|
||||
gsl::not_null<const style::Check*> _st;
|
||||
|
||||
};
|
||||
|
||||
class RadioView : public AbstractCheckView {
|
||||
public:
|
||||
RadioView(const style::Radio &st, bool checked, base::lambda<void()> updateCallback);
|
||||
|
||||
void setStyle(const style::Radio &st);
|
||||
|
||||
QSize getSize() override;
|
||||
void paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) override;
|
||||
|
||||
private:
|
||||
gsl::not_null<const style::Radio*> _st;
|
||||
|
||||
};
|
||||
|
||||
class ToggleView : public AbstractCheckView {
|
||||
public:
|
||||
ToggleView(const style::Toggle &st, bool checked, base::lambda<void()> updateCallback);
|
||||
|
||||
void setStyle(const style::Toggle &st);
|
||||
|
||||
QSize getSize() override;
|
||||
void paint(Painter &p, int left, int top, int outerWidth, TimeMs ms) override;
|
||||
|
||||
private:
|
||||
gsl::not_null<const style::Toggle*> _st;
|
||||
|
||||
};
|
||||
|
||||
class Checkbox : public RippleButton {
|
||||
public:
|
||||
Checkbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox, const style::Check &checkSt = st::defaultCheck);
|
||||
Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st, const style::Toggle &toggleSt);
|
||||
Checkbox(QWidget *parent, const QString &text, const style::Checkbox &st, std::unique_ptr<AbstractCheckView> check);
|
||||
|
||||
void setText(const QString &text);
|
||||
|
||||
|
@ -39,6 +115,7 @@ public:
|
|||
DontNotify,
|
||||
};
|
||||
void setChecked(bool checked, NotifyAboutChange notify = NotifyAboutChange::Notify);
|
||||
base::Observable<bool> checkedChanged;
|
||||
|
||||
void finishAnimations();
|
||||
|
||||
|
@ -56,23 +133,19 @@ protected:
|
|||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
public slots:
|
||||
void onClicked();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
void updateCheck() {
|
||||
rtlupdate(_checkRect);
|
||||
}
|
||||
|
||||
private:
|
||||
void resizeToText();
|
||||
|
||||
const style::Checkbox &_st;
|
||||
std::unique_ptr<AbstractCheckView> _check;
|
||||
|
||||
Text _text;
|
||||
QRect _checkRect;
|
||||
|
||||
bool _checked;
|
||||
Animation _a_checked;
|
||||
|
||||
};
|
||||
|
||||
class Radiobutton;
|
||||
|
@ -113,41 +186,32 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class Radiobutton : public RippleButton {
|
||||
class Radiobutton : public Checkbox, private base::Subscriber {
|
||||
public:
|
||||
Radiobutton(QWidget *parent, const std::shared_ptr<RadiobuttonGroup> &group, int value, const QString &text, const style::Checkbox &st = st::defaultCheckbox);
|
||||
|
||||
QMargins getMargins() const override {
|
||||
return _st.margin;
|
||||
}
|
||||
int naturalWidth() const override;
|
||||
|
||||
Radiobutton(QWidget *parent, const std::shared_ptr<RadiobuttonGroup> &group, int value, const QString &text, const style::Checkbox &st = st::defaultCheckbox, const style::Radio &radioSt = st::defaultRadio);
|
||||
~Radiobutton();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(State was, StateChangeSource source) override;
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
private:
|
||||
// Hide the names from Checkbox.
|
||||
bool checked() const;
|
||||
void setChecked(bool checked, NotifyAboutChange notify);
|
||||
void checkedChanged();
|
||||
Checkbox *checkbox() {
|
||||
return this;
|
||||
}
|
||||
const Checkbox *checkbox() const {
|
||||
return this;
|
||||
}
|
||||
|
||||
friend class RadiobuttonGroup;
|
||||
void handleNewGroupValue(int value);
|
||||
|
||||
std::shared_ptr<RadiobuttonGroup> _group;
|
||||
int _value = 0;
|
||||
|
||||
const style::Checkbox &_st;
|
||||
|
||||
Text _text;
|
||||
QRect _checkRect;
|
||||
|
||||
bool _checked = false;
|
||||
Animation _a_checked;
|
||||
|
||||
};
|
||||
|
||||
template <typename Enum>
|
||||
|
@ -194,24 +258,4 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class ToggleView {
|
||||
public:
|
||||
ToggleView(const style::Toggle &st, bool toggled, base::lambda<void()> updateCallback);
|
||||
|
||||
void setToggledFast(bool toggled);
|
||||
void setToggledAnimated(bool toggled);
|
||||
void finishAnimation();
|
||||
void setStyle(const style::Toggle &st);
|
||||
void setUpdateCallback(base::lambda<void()> updateCallback);
|
||||
|
||||
void paint(Painter &p, int left, int top, int outerWidth, TimeMs ms);
|
||||
|
||||
private:
|
||||
gsl::not_null<const style::Toggle*> _st;
|
||||
bool _toggled = false;
|
||||
base::lambda<void()> _updateCallback;
|
||||
Animation _toggleAnimation;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -140,13 +140,13 @@ int Menu::processAction(QAction *action, int index, int width) {
|
|||
}
|
||||
if (action->isCheckable()) {
|
||||
auto updateCallback = [this, index] { updateItem(index); };
|
||||
goodw += _st.itemPadding.left() + _st.itemToggle.diameter + _st.itemToggle.width - _st.itemToggleShift;
|
||||
if (data.toggle) {
|
||||
data.toggle->setUpdateCallback(updateCallback);
|
||||
data.toggle->setToggledAnimated(action->isChecked());
|
||||
data.toggle->setCheckedAnimated(action->isChecked());
|
||||
} else {
|
||||
data.toggle = std::make_unique<ToggleView>(_st.itemToggle, action->isChecked(), updateCallback);
|
||||
}
|
||||
goodw += _st.itemPadding.left() + data.toggle->getSize().width() - _st.itemToggleShift;
|
||||
} else {
|
||||
data.toggle.reset();
|
||||
}
|
||||
|
@ -231,8 +231,8 @@ void Menu::paintEvent(QPaintEvent *e) {
|
|||
p.setPen(selected ? _st.itemFgShortcutOver : (enabled ? _st.itemFgShortcut : _st.itemFgShortcutDisabled));
|
||||
p.drawTextRight(_st.itemPadding.right(), _st.itemPadding.top(), width(), data.shortcut);
|
||||
} else if (data.toggle) {
|
||||
auto toggleSize = _st.itemToggle.diameter + _st.itemToggle.width;
|
||||
data.toggle->paint(p, width() - _st.itemPadding.right() - toggleSize + _st.itemToggleShift, (_itemHeight - _st.itemToggle.diameter) / 2, width(), ms);
|
||||
auto toggleSize = data.toggle->getSize();
|
||||
data.toggle->paint(p, width() - _st.itemPadding.right() - toggleSize.width() + _st.itemToggleShift, (_itemHeight - toggleSize.height()) / 2, width(), ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,25 +92,48 @@ RoundButton {
|
|||
ripple: RippleAnimation;
|
||||
}
|
||||
|
||||
Toggle {
|
||||
toggledBg: color;
|
||||
toggledFg: color;
|
||||
untoggledBg: color;
|
||||
untoggledFg: color;
|
||||
duration: int;
|
||||
border: pixels;
|
||||
shift: pixels;
|
||||
diameter: pixels;
|
||||
width: pixels;
|
||||
}
|
||||
|
||||
Check {
|
||||
bg: color;
|
||||
untoggledFg: color;
|
||||
toggledFg: color;
|
||||
diameter: pixels;
|
||||
thickness: pixels;
|
||||
icon: icon;
|
||||
duration: int;
|
||||
}
|
||||
|
||||
Radio {
|
||||
bg: color;
|
||||
untoggledFg: color;
|
||||
toggledFg: color;
|
||||
diameter: pixels;
|
||||
thickness: pixels;
|
||||
skip: pixels;
|
||||
duration: int;
|
||||
}
|
||||
|
||||
Checkbox {
|
||||
textFg: color;
|
||||
|
||||
checkBg: color;
|
||||
checkFg: color;
|
||||
checkFgActive: color;
|
||||
|
||||
width: pixels;
|
||||
height: pixels;
|
||||
margin: margins;
|
||||
|
||||
textPosition: point;
|
||||
diameter: pixels;
|
||||
thickness: pixels;
|
||||
radioSkip: pixels;
|
||||
checkIcon: icon;
|
||||
|
||||
style: TextStyle;
|
||||
duration: int;
|
||||
|
||||
rippleAreaPosition: point;
|
||||
rippleAreaSize: pixels;
|
||||
|
@ -360,18 +383,6 @@ CallButton {
|
|||
outerBg: color;
|
||||
}
|
||||
|
||||
Toggle {
|
||||
toggledBg: color;
|
||||
toggledFg: color;
|
||||
untoggledBg: color;
|
||||
untoggledFg: color;
|
||||
duration: int;
|
||||
border: pixels;
|
||||
shift: pixels;
|
||||
diameter: pixels;
|
||||
width: pixels;
|
||||
}
|
||||
|
||||
Menu {
|
||||
skip: pixels;
|
||||
|
||||
|
@ -660,25 +671,45 @@ defaultInputField: InputField {
|
|||
|
||||
defaultCheckboxIcon: icon {{ "default_checkbox_check", windowFgActive, point(4px, 7px) }};
|
||||
|
||||
defaultCheck: Check {
|
||||
bg: transparent;
|
||||
untoggledFg: checkboxFg;
|
||||
toggledFg: windowBgActive;
|
||||
diameter: 22px;
|
||||
thickness: 2px;
|
||||
icon: defaultCheckboxIcon;
|
||||
duration: 120;
|
||||
}
|
||||
defaultRadio: Radio {
|
||||
bg: transparent;
|
||||
untoggledFg: checkboxFg;
|
||||
toggledFg: windowBgActive;
|
||||
diameter: 22px;
|
||||
thickness: 2px;
|
||||
skip: 65px; // * 0.1
|
||||
duration: 120;
|
||||
}
|
||||
defaultToggle: Toggle {
|
||||
toggledBg: windowBg;
|
||||
toggledFg: windowBgActive;
|
||||
untoggledBg: windowBg;
|
||||
untoggledFg: checkboxFg;
|
||||
duration: 120;
|
||||
border: 2px;
|
||||
shift: 1px;
|
||||
diameter: 20px;
|
||||
width: 16px;
|
||||
}
|
||||
defaultCheckbox: Checkbox {
|
||||
textFg: windowFg;
|
||||
|
||||
checkBg: transparent;
|
||||
checkFg: checkboxFg;
|
||||
checkFgActive: windowBgActive;
|
||||
|
||||
width: -44px;
|
||||
height: 22px;
|
||||
margin: margins(8px, 8px, 8px, 8px);
|
||||
|
||||
textPosition: point(32px, 2px);
|
||||
diameter: 22px;
|
||||
thickness: 2px;
|
||||
checkIcon: defaultCheckboxIcon;
|
||||
radioSkip: 65px; // * 0.1
|
||||
|
||||
style: defaultTextStyle;
|
||||
duration: 120;
|
||||
|
||||
rippleAreaSize: 38px;
|
||||
rippleAreaPosition: point(0px, 0px);
|
||||
|
@ -781,18 +812,6 @@ defaultRoundCheckbox: RoundCheckbox {
|
|||
duration: 150;
|
||||
}
|
||||
|
||||
defaultToggle: Toggle {
|
||||
toggledBg: windowBg;
|
||||
toggledFg: windowBgActive;
|
||||
untoggledBg: windowBg;
|
||||
untoggledFg: checkboxFg;
|
||||
duration: 200;
|
||||
border: 2px;
|
||||
shift: 1px;
|
||||
diameter: 20px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
defaultMenuArrow: icon {{ "dropdown_submenu_arrow", menuSubmenuArrowFg }};
|
||||
defaultMenuToggle: Toggle(defaultToggle) {
|
||||
untoggledFg: menuIconFg;
|
||||
|
|
Loading…
Add table
Reference in a new issue