mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-22 11:18:44 +00:00
Closed beta 10019008: Some more ripple animations added.
This commit is contained in:
parent
cdef9fa14f
commit
07689476a6
@ -53,6 +53,11 @@ lightButtonBgRipple: #c9e4f6;
|
||||
lightButtonFg: #2b99d5;
|
||||
lightButtonFgOver: lightButtonFg;
|
||||
|
||||
attentionButtonFg: #d14e4e;
|
||||
attentionButtonFgOver: #d14e4e;
|
||||
attentionButtonBgOver: #fcdfde;
|
||||
attentionButtonBgRipple: #f4c3c2;
|
||||
|
||||
menuBg: windowBg;
|
||||
menuBgOver: windowBgOver;
|
||||
menuBgRipple: windowBgRipple;
|
||||
@ -99,11 +104,6 @@ boxBlockTitleAdditionalFg: #808080;
|
||||
boxBlockTitleCloseFg: cancelIconFg;
|
||||
boxBlockTitleCloseFgOver: cancelIconFgOver;
|
||||
|
||||
attentionBoxButtonFg: #d14e4e;
|
||||
attentionBoxButtonFgOver: #d14e4e;
|
||||
attentionBoxButtonBgOver: #fcdfde;
|
||||
attentionBoxButtonBgRipple: #f4c3c2;
|
||||
|
||||
membersAboutLimitFg: windowSubTextFgOver;
|
||||
|
||||
contactsBg: windowBg;
|
||||
@ -228,6 +228,7 @@ mediaviewFileExtFg: activeButtonFg;
|
||||
|
||||
mediaviewMenuBg: #383838;
|
||||
mediaviewMenuBgOver: #505050;
|
||||
mediaviewMenuBgRipple: #676767;
|
||||
mediaviewMenuFg: #ffffff;
|
||||
|
||||
mediaviewBg: #222222eb;
|
||||
|
@ -49,6 +49,10 @@ lightButtonBgOver: #e3f1fa;
|
||||
lightButtonBgRipple: #c9e4f6;
|
||||
lightButtonFg: #2b99d5;
|
||||
lightButtonFgOver: lightButtonFg;
|
||||
attentionButtonFg: #d14e4e;
|
||||
attentionButtonFgOver: #d14e4e;
|
||||
attentionButtonBgOver: #fcdfde;
|
||||
attentionButtonBgRipple: #f4c3c2;
|
||||
menuBg: windowBg;
|
||||
menuBgOver: windowBgOver;
|
||||
menuBgRipple: windowBgRipple;
|
||||
@ -84,10 +88,6 @@ boxBlockTitleFg: boxTitleFg;
|
||||
boxBlockTitleAdditionalFg: #808080;
|
||||
boxBlockTitleCloseFg: cancelIconFg;
|
||||
boxBlockTitleCloseFgOver: cancelIconFgOver;
|
||||
attentionBoxButtonFg: #d14e4e;
|
||||
attentionBoxButtonFgOver: #d14e4e;
|
||||
attentionBoxButtonBgOver: #fcdfde;
|
||||
attentionBoxButtonBgRipple: #f4c3c2;
|
||||
membersAboutLimitFg: windowSubTextFgOver;
|
||||
contactsBg: windowBg;
|
||||
contactsBgOver: windowBgOver;
|
||||
@ -189,6 +189,7 @@ mediaviewFileBlueCornerFg: #599dcf;
|
||||
mediaviewFileExtFg: activeButtonFg;
|
||||
mediaviewMenuBg: #383838;
|
||||
mediaviewMenuBgOver: #505050;
|
||||
mediaviewMenuBgRipple: #676767;
|
||||
mediaviewMenuFg: #ffffff;
|
||||
mediaviewBg: #222222eb;
|
||||
mediaviewVideoBg: #000000;
|
||||
|
@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,10,19,7
|
||||
PRODUCTVERSION 0,10,19,7
|
||||
FILEVERSION 0,10,19,8
|
||||
PRODUCTVERSION 0,10,19,8
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -51,10 +51,10 @@ BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileVersion", "0.10.19.7"
|
||||
VALUE "FileVersion", "0.10.19.8"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "0.10.19.7"
|
||||
VALUE "ProductVersion", "0.10.19.8"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,10,19,7
|
||||
PRODUCTVERSION 0,10,19,7
|
||||
FILEVERSION 0,10,19,8
|
||||
PRODUCTVERSION 0,10,19,8
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -43,10 +43,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram Messenger LLP"
|
||||
VALUE "FileDescription", "Telegram Updater"
|
||||
VALUE "FileVersion", "0.10.19.7"
|
||||
VALUE "FileVersion", "0.10.19.8"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "0.10.19.7"
|
||||
VALUE "ProductVersion", "0.10.19.8"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class Radiobutton;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/lambda_wrap.h"
|
||||
|
||||
class BackgroundBox : public ItemListBox {
|
||||
|
@ -37,7 +37,6 @@ defaultBoxButton: RoundButton {
|
||||
padding: margins(0px, 0px, 0px, 0px);
|
||||
|
||||
textTop: 8px;
|
||||
downTextTop: 8px;
|
||||
|
||||
font: boxButtonFont;
|
||||
|
||||
@ -51,12 +50,12 @@ cancelBoxButton: RoundButton(defaultBoxButton) {
|
||||
}
|
||||
|
||||
attentionBoxButton: RoundButton(defaultBoxButton) {
|
||||
textFg: attentionBoxButtonFg;
|
||||
textFgOver: attentionBoxButtonFgOver;
|
||||
textBgOver: attentionBoxButtonBgOver;
|
||||
textFg: attentionButtonFg;
|
||||
textFgOver: attentionButtonFgOver;
|
||||
textBgOver: attentionButtonBgOver;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: attentionBoxButtonBgRipple;
|
||||
color: attentionButtonBgRipple;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,12 +197,21 @@ contactUserIcon: icon {{ "add_contact_user", #999999 }};
|
||||
contactPhoneIcon: icon {{ "add_contact_phone", #999999 }};
|
||||
contactIconTop: 10px;
|
||||
|
||||
contactsAdd: IconButton {
|
||||
contactsAddIconAbove: icon {{ "contacts_add", activeButtonFg, point(18px, 18px) }};
|
||||
contactsAdd: TwoIconButton {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
|
||||
icon: contactsAddIcon;
|
||||
iconOver: contactsAddIconOver;
|
||||
iconBelow: contactsAddIconBelow;
|
||||
iconBelowOver: contactsAddIconBelowOver;
|
||||
iconAbove: contactsAddIconAbove;
|
||||
iconAboveOver: contactsAddIconAbove;
|
||||
|
||||
rippleAreaPosition: point(5px, 5px);
|
||||
rippleAreaSize: 42px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: activeButtonBgRipple;
|
||||
}
|
||||
}
|
||||
contactsAddPosition: point(14px, 8px);
|
||||
|
||||
@ -289,9 +297,7 @@ contactsMultiSelect: MultiSelect {
|
||||
|
||||
icon: boxSearchCancelIcon;
|
||||
iconOver: boxSearchCancelIconOver;
|
||||
|
||||
iconPosition: point(8px, 18px);
|
||||
iconPositionDown: point(8px, 18px);
|
||||
}
|
||||
fieldCancelSkip: 34px;
|
||||
}
|
||||
@ -370,9 +376,7 @@ sessionTerminate: IconButton {
|
||||
|
||||
icon: simpleCloseIcon;
|
||||
iconOver: simpleCloseIconOver;
|
||||
|
||||
iconPosition: point(3px, 3px);
|
||||
iconPositionDown: point(3px, 4px);
|
||||
}
|
||||
sessionTerminateAllButton: LinkButton(boxLinkButton) {
|
||||
color: #d15948;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/single_timer.h"
|
||||
#include "ui/effects/round_image_checkbox.h"
|
||||
#include "boxes/members_box.h"
|
||||
@ -93,7 +93,7 @@ private:
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<Ui::WidgetSlideWrap<Ui::MultiSelect>> _select;
|
||||
ChildWidget<Ui::IconButton> _add = { nullptr };
|
||||
ChildWidget<MembersAddButton> _add = { nullptr };
|
||||
|
||||
ChildWidget<Ui::RoundButton> _next;
|
||||
ChildWidget<Ui::RoundButton> _cancel;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/observer.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
class EmojiBox : public AbstractBox {
|
||||
Q_OBJECT
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class Radiobutton;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
|
@ -30,8 +30,36 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "observer_peer.h"
|
||||
|
||||
|
||||
MembersAddButton::MembersAddButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
|
||||
, _st(st) {
|
||||
resize(_st.width, _st.height);
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
void MembersAddButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto over = (_state & StateOver);
|
||||
auto down = (_state & StateDown);
|
||||
|
||||
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
|
||||
((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width());
|
||||
}
|
||||
|
||||
QImage MembersAddButton::prepareRippleMask() const {
|
||||
return Ui::RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
}
|
||||
|
||||
QPoint MembersAddButton::prepareRippleStartPosition() const {
|
||||
return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
|
||||
}
|
||||
|
||||
MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox(st::boxScroll)
|
||||
, _inner(this, channel, filter) {
|
||||
ItemListBox::init(_inner);
|
||||
|
@ -20,9 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/single_timer.h"
|
||||
#include "ui/effects/round_image_checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
|
||||
class ContactsBox;
|
||||
class ConfirmBox;
|
||||
@ -33,6 +34,21 @@ enum class MembersFilter {
|
||||
};
|
||||
using MembersAlreadyIn = OrderedSet<UserData*>;
|
||||
|
||||
class MembersAddButton : public Ui::RippleButton {
|
||||
public:
|
||||
MembersAddButton(QWidget *parent, const style::TwoIconButton &st);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
private:
|
||||
const style::TwoIconButton &_st;
|
||||
|
||||
};
|
||||
|
||||
class MembersBox : public ItemListBox {
|
||||
Q_OBJECT
|
||||
|
||||
@ -54,7 +70,7 @@ private:
|
||||
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<Ui::IconButton> _add = { nullptr };
|
||||
ChildWidget<MembersAddButton> _add = { nullptr };
|
||||
|
||||
ContactsBox *_addBox = nullptr;
|
||||
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class InputField;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "localimageloader.h"
|
||||
|
||||
namespace Ui {
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class Radiobutton;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/single_timer.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/lambda_wrap.h"
|
||||
#include "core/observer.h"
|
||||
#include "core/vector_of_moveable.h"
|
||||
|
@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "styles/style_stickers.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -563,6 +564,7 @@ void StickersBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
|
||||
_a_shifting.step();
|
||||
|
||||
auto ms = getms();
|
||||
p.fillRect(r, st::boxBg);
|
||||
p.setClipRect(r);
|
||||
|
||||
@ -591,19 +593,26 @@ void StickersBox::Inner::paintEvent(QPaintEvent *e) {
|
||||
p.translate(0, from * _rowHeight);
|
||||
for (int32 i = from; i < to; ++i) {
|
||||
if (i != _above) {
|
||||
paintRow(p, i);
|
||||
paintRow(p, i, ms);
|
||||
}
|
||||
p.translate(0, _rowHeight);
|
||||
}
|
||||
if (from <= _above && _above < to) {
|
||||
p.translate(0, (_above - to) * _rowHeight);
|
||||
paintRow(p, _above);
|
||||
paintRow(p, _above, ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::paintRow(Painter &p, int32 index) {
|
||||
const StickerSetRow *s(_rows.at(index));
|
||||
QRect StickersBox::Inner::relativeAddButtonRect() const {
|
||||
int addw = st::stickersAddSize.width();
|
||||
int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw;
|
||||
int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersAddSize.height()) / 2;
|
||||
return QRect(addx, addy, addw, st::stickersAddSize.height());
|
||||
}
|
||||
|
||||
void StickersBox::Inner::paintRow(Painter &p, int32 index, uint64 ms) {
|
||||
auto s = _rows.at(index);
|
||||
|
||||
int32 xadd = 0, yadd = s->yadd.current();
|
||||
if (xadd || yadd) p.translate(xadd, yadd);
|
||||
@ -639,17 +648,23 @@ void StickersBox::Inner::paintRow(Painter &p, int32 index) {
|
||||
int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (addw + st::stickersFeaturedInstalled.width()) / 2);
|
||||
int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2;
|
||||
st::stickersFeaturedInstalled.paint(p, QPoint(checkx, checky), width());
|
||||
if (s->ripple) {
|
||||
s->ripple.reset();
|
||||
}
|
||||
} else {
|
||||
int addw = st::stickersAddSize.width();
|
||||
int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw;
|
||||
int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersAddSize.height()) / 2;
|
||||
QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height()));
|
||||
auto relativeAdd = relativeAddButtonRect();
|
||||
auto add = myrtlrect(relativeAdd);
|
||||
|
||||
auto &textBg = (_actionSel == index) ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg;
|
||||
auto &textBg = (_actionSel == index || _actionDown == index) ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg;
|
||||
App::roundRect(p, add, textBg, ImageRoundRadius::Small);
|
||||
int iconx = addx + (st::stickersAddSize.width() - st::stickersAddIcon.width()) / 2;
|
||||
int icony = addy + (st::stickersAddSize.height() - st::stickersAddIcon.height()) / 2;
|
||||
icony += (_actionSel == index && _actionDown == index) ? (st::defaultActiveButton.downTextTop - st::defaultActiveButton.textTop) : 0;
|
||||
if (s->ripple) {
|
||||
s->ripple->paint(p, relativeAdd.x(), relativeAdd.y(), width(), ms);
|
||||
if (s->ripple->empty()) {
|
||||
s->ripple.reset();
|
||||
}
|
||||
}
|
||||
int iconx = relativeAdd.x() + (st::stickersAddSize.width() - st::stickersAddIcon.width()) / 2;
|
||||
int icony = relativeAdd.y() + (st::stickersAddSize.height() - st::stickersAddIcon.height()) / 2;
|
||||
st::stickersAddIcon.paint(p, QPoint(iconx, icony), width());
|
||||
}
|
||||
|
||||
@ -696,7 +711,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
|
||||
_pressed = _selected;
|
||||
if (_actionSel >= 0) {
|
||||
_actionDown = _actionSel;
|
||||
setActionDown(_actionSel);
|
||||
update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
|
||||
} else if (_selected >= 0 && _section == Section::Installed && !_rows.at(_selected)->recent) {
|
||||
_above = _dragging = _started = _selected;
|
||||
@ -704,6 +719,33 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::setActionDown(int newActionDown) {
|
||||
if (_actionDown == newActionDown) {
|
||||
return;
|
||||
}
|
||||
if (_actionDown >= 0 && _actionDown < _rows.size()) {
|
||||
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
|
||||
auto set = _rows[_actionDown];
|
||||
if (set->ripple) {
|
||||
set->ripple->lastStop();
|
||||
}
|
||||
}
|
||||
_actionDown = newActionDown;
|
||||
if (_actionDown >= 0 && _actionDown < _rows.size()) {
|
||||
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
|
||||
auto set = _rows[_actionDown];
|
||||
if (!set->ripple) {
|
||||
auto mask = Ui::RippleAnimation::roundRectMask(st::stickersAddSize, st::buttonRadius);
|
||||
set->ripple = MakeShared<Ui::RippleAnimation>(st::defaultActiveButton.ripple, std_::move(mask), [this, index = _actionDown] {
|
||||
update(0, _itemsTop + index * _rowHeight, width(), _rowHeight);
|
||||
});
|
||||
}
|
||||
auto relativeAdd = relativeAddButtonRect();
|
||||
auto add = myrtlrect(relativeAdd);
|
||||
set->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(add.x(), _itemsTop + _actionDown * _rowHeight + add.y()));
|
||||
}
|
||||
}
|
||||
|
||||
void StickersBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (_saving) return;
|
||||
_mouse = e->globalPos();
|
||||
@ -762,10 +804,8 @@ void StickersBox::Inner::onUpdateSelected() {
|
||||
} else if (_rows.at(selected)->installed && !_rows.at(selected)->disabled) {
|
||||
actionSel = -1;
|
||||
} else {
|
||||
int addw = st::stickersAddSize.width();
|
||||
int addx = width() - st::contactsPadding.right() - st::contactsCheckPosition.x() - addw;
|
||||
int addy = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersAddSize.height()) / 2;
|
||||
QRect add(myrtlrect(addx, addy, addw, st::stickersAddSize.height()));
|
||||
auto relativeAdd = relativeAddButtonRect();
|
||||
auto add = myrtlrect(relativeAdd);
|
||||
actionSel = add.contains(local.x(), local.y() - _itemsTop - selected * _rowHeight) ? selected : -1;
|
||||
}
|
||||
} else if (_hasFeaturedButton && QRect(0, st::membersPadding.top(), width(), _buttonHeight).contains(local)) {
|
||||
@ -878,10 +918,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_actionDown >= 0) {
|
||||
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
|
||||
_actionDown = -1;
|
||||
}
|
||||
setActionDown(-1);
|
||||
}
|
||||
|
||||
void StickersBox::Inner::leaveEvent(QEvent *e) {
|
||||
|
@ -20,13 +20,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace Ui {
|
||||
class PlainShadow;
|
||||
class RoundButton;
|
||||
class RippleAnimation;
|
||||
} // namespace Ui
|
||||
|
||||
class StickersBox : public ItemListBox, public RPCSender {
|
||||
@ -150,11 +151,13 @@ private slots:
|
||||
void onImageLoaded();
|
||||
|
||||
private:
|
||||
void setActionDown(int newActionDown);
|
||||
void setup();
|
||||
QRect relativeAddButtonRect() const;
|
||||
void paintButton(Painter &p, int y, bool selected, const QString &text, int badgeCounter) const;
|
||||
|
||||
void step_shifting(uint64 ms, bool timer);
|
||||
void paintRow(Painter &p, int32 index);
|
||||
void paintRow(Painter &p, int32 index, uint64 ms);
|
||||
void clear();
|
||||
void setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
@ -192,6 +195,7 @@ private:
|
||||
bool installed, official, unread, disabled, recent;
|
||||
int32 pixw, pixh;
|
||||
anim::ivalue yadd;
|
||||
QSharedPointer<Ui::RippleAnimation> ripple;
|
||||
};
|
||||
using StickerSetRows = QList<StickerSetRow*>;
|
||||
|
||||
@ -236,5 +240,6 @@ private:
|
||||
|
||||
Ui::RectShadow _aboveShadow;
|
||||
|
||||
int32 _scrollbar = 0;
|
||||
int _scrollbar = 0;
|
||||
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
#include "core/vector_of_moveable.h"
|
||||
|
||||
class ConfirmBox;
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
#include "boxes/abstractbox.h"
|
||||
|
||||
namespace Ui {
|
||||
class UsernameInput;
|
||||
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "core/utils.h"
|
||||
|
||||
#define BETA_VERSION_MACRO (10019007ULL)
|
||||
#define BETA_VERSION_MACRO (10019008ULL)
|
||||
|
||||
constexpr int AppVersion = 10020;
|
||||
constexpr str_const AppVersionStr = "0.10.20";
|
||||
|
@ -84,7 +84,6 @@ dialogsMenuToggle: IconButton {
|
||||
icon: icon {{ "dialogs_menu", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_menu", dialogsMenuIconFgOver }};
|
||||
iconPosition: point(10px, 10px);
|
||||
iconPositionDown: point(10px, 10px);
|
||||
|
||||
rippleAreaPosition: point(0px, 0px);
|
||||
rippleAreaSize: 40px;
|
||||
@ -112,18 +111,14 @@ dialogsFilter: FlatInput(defaultFlatInput) {
|
||||
dialogsCancelSearchInPeer: IconButton(dialogsMenuToggle) {
|
||||
icon: icon {{ "dialogs_cancel_search", dialogsMenuIconFg }};
|
||||
iconOver: icon {{ "dialogs_cancel_search", dialogsMenuIconFgOver }};
|
||||
|
||||
iconPosition: point(11px, 11px);
|
||||
iconPositionDown: point(11px, 11px);
|
||||
}
|
||||
dialogsCancelSearch: IconButton(dialogsCancelSearchInPeer) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
iconPosition: point(7px, 7px);
|
||||
iconPositionDown: point(7px, 7px);
|
||||
|
||||
rippleAreaSize: 0px;
|
||||
ripple: emptyRippleAnimation;
|
||||
}
|
||||
|
||||
dialogsChatTypeSkip: 22px;
|
||||
@ -177,8 +172,6 @@ dialogsUpdateButton: FlatButton {
|
||||
height: 46px;
|
||||
|
||||
textTop: 14px;
|
||||
overTextTop: 14px;
|
||||
downTextTop: 15px;
|
||||
|
||||
font: semiboldFont;
|
||||
overFont: semiboldFont;
|
||||
@ -197,8 +190,6 @@ dialogsForwardCancel: IconButton {
|
||||
|
||||
icon: dialogsForwardCancelIcon;
|
||||
iconOver: dialogsForwardCancelIcon;
|
||||
|
||||
iconPosition: point(12px, 11px);
|
||||
iconPositionDown: point(12px, 11px);
|
||||
}
|
||||
dialogsForwardFont: semiboldFont;
|
||||
|
@ -22,14 +22,6 @@ using "basic.style";
|
||||
using "dialogs/dialogs.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
BotKeyboardButton {
|
||||
margin: pixels;
|
||||
padding: pixels;
|
||||
height: pixels;
|
||||
textTop: pixels;
|
||||
downTextTop: pixels;
|
||||
}
|
||||
|
||||
historyScroll: FlatScroll(defaultFlatScroll) {
|
||||
barColor: #89a0b47a;
|
||||
bgColor: #89a0b44c;
|
||||
@ -47,13 +39,28 @@ historyScroll: FlatScroll(defaultFlatScroll) {
|
||||
bottomsh: -1px;
|
||||
}
|
||||
|
||||
historyPaddingBottom: 10px;
|
||||
historyPaddingBottom: 8px;
|
||||
|
||||
historyToDownPosition: point(12px, 10px);
|
||||
historyToDownArrow: icon {
|
||||
{ "history_down_arrow", #b9b9b9, point(17px, 23px) },
|
||||
};
|
||||
historyToDownAbove: icon {{ "history_down_arrow", #b9b9b9, point(17px, 23px) }};
|
||||
historyToDownAboveOver: icon {{ "history_down_arrow", #a3a3a3, point(17px, 23px) }};
|
||||
historyToDownPaddingTop: 10px;
|
||||
historyToDown: TwoIconButton {
|
||||
width: 52px;
|
||||
height: 62px;
|
||||
|
||||
iconBelow: historyToDownBelow;
|
||||
iconBelowOver: historyToDownBelowOver;
|
||||
iconAbove: historyToDownAbove;
|
||||
iconAboveOver: historyToDownAboveOver;
|
||||
iconPosition: point(0px, historyToDownPaddingTop);
|
||||
|
||||
rippleAreaPosition: point(5px, 15px);
|
||||
rippleAreaSize: 42px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgRipple;
|
||||
}
|
||||
}
|
||||
historyToDownBadgeFont: semiboldFont;
|
||||
historyToDownBadgeSize: 22px;
|
||||
|
||||
@ -196,8 +203,6 @@ historyComposeButton: FlatButton {
|
||||
height: 46px;
|
||||
|
||||
textTop: 14px;
|
||||
overTextTop: 14px;
|
||||
downTextTop: 14px;
|
||||
|
||||
font: semiboldFont;
|
||||
overFont: semiboldFont;
|
||||
@ -217,9 +222,7 @@ historySend: IconButton {
|
||||
|
||||
icon: icon {{ "send_control_send", historySendIconFg }};
|
||||
iconOver: icon {{ "send_control_send", historySendIconFgOver }};
|
||||
|
||||
iconPosition: point(11px, 11px);
|
||||
iconPositionDown: point(11px, 11px);
|
||||
}
|
||||
historyEditSaveIcon: icon {{ "send_control_save", historySendIconFg, point(3px, 7px) }};
|
||||
historyEditSaveIconOver: icon {{ "send_control_save", historySendIconFgOver, point(3px, 7px) }};
|
||||
@ -242,11 +245,9 @@ historyAttachPhotoIconOver: icon {{ "media_type_photo", historyComposeIconFgOver
|
||||
historyAttachEmoji: IconButton(historyAttach) {
|
||||
icon: icon {{ "send_control_emoji", historyComposeIconFg }};
|
||||
iconOver: icon {{ "send_control_emoji", historyComposeIconFgOver }};
|
||||
|
||||
iconPosition: point(15px, 15px);
|
||||
iconPositionDown: point(15px, 15px);
|
||||
|
||||
rippleAreaSize: 0px;
|
||||
ripple: emptyRippleAnimation;
|
||||
}
|
||||
historyEmojiCircle: size(20px, 20px);
|
||||
historyEmojiCirclePeriod: 1500;
|
||||
@ -263,9 +264,7 @@ historyBotKeyboardShow: IconButton(historySend) {
|
||||
historyBotKeyboardHide: IconButton(historySend) {
|
||||
icon: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFg }};
|
||||
iconOver: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFgOver }};
|
||||
|
||||
iconPosition: point(11px, 16px);
|
||||
iconPositionDown: point(11px, 16px);
|
||||
}
|
||||
historyBotCommandStart: IconButton(historySend) {
|
||||
icon: icon {{ "send_control_bot_command", historyComposeIconFg }};
|
||||
@ -319,9 +318,7 @@ historyReplyCancel: IconButton {
|
||||
|
||||
icon: historyReplyCancelIcon;
|
||||
iconOver: historyReplyCancelIconOver;
|
||||
|
||||
iconPosition: point(-1px, -1px);
|
||||
iconPositionDown: point(-1px, -1px);
|
||||
|
||||
rippleAreaPosition: point(4px, 4px);
|
||||
rippleAreaSize: 40px;
|
||||
@ -349,8 +346,6 @@ reportSpamHide: FlatButton {
|
||||
height: 46px;
|
||||
|
||||
textTop: 15px;
|
||||
overTextTop: 15px;
|
||||
downTextTop: 16px;
|
||||
|
||||
font: font(fsize);
|
||||
overFont: font(fsize underline);
|
||||
@ -361,7 +356,7 @@ reportSpamFg: #000000;
|
||||
|
||||
msgBotKbDuration: 200;
|
||||
msgBotKbFont: semiboldFont;
|
||||
msgBotKbOverBg: #ffffff1a;
|
||||
msgBotKbOverBg: #ffffff20;
|
||||
msgBotKbIconPadding: 2px;
|
||||
msgBotKbUrlIcon: icon {{ "inline_button_url", #ffffff }};
|
||||
msgBotKbSwitchPmIcon: icon {{ "inline_button_switch", #ffffff }};
|
||||
@ -370,28 +365,30 @@ msgBotKbButton: BotKeyboardButton {
|
||||
padding: 10px;
|
||||
height: 36px;
|
||||
textTop: 8px;
|
||||
downTextTop: 9px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: #00000020;
|
||||
}
|
||||
}
|
||||
|
||||
botKbDuration: 200;
|
||||
botKbBg: #edf1f5;
|
||||
botKbOverBg: #d8e2ec;
|
||||
botKbDownBg: #d8e2ec;
|
||||
botKbColor: #4b565f;
|
||||
botKbBg: menuBgOver;
|
||||
botKbOverBg: menuBgOver;
|
||||
botKbDownBg: menuBgRipple;
|
||||
botKbColor: windowBoldFgOver;
|
||||
botKbFont: font(15px semibold);
|
||||
botKbButton: BotKeyboardButton {
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
height: 38px;
|
||||
textTop: 9px;
|
||||
downTextTop: 9px;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
botKbTinyButton: BotKeyboardButton {
|
||||
margin: 4px;
|
||||
padding: 3px;
|
||||
height: 25px;
|
||||
textTop: 2px;
|
||||
downTextTop: 2px;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
botKbScroll: FlatScroll(defaultSolidScroll) {
|
||||
deltax: 3px;
|
||||
|
@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "media/media_clip_reader.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "fileuploader.h"
|
||||
|
||||
namespace {
|
||||
@ -221,7 +222,7 @@ int ReplyKeyboard::naturalHeight() const {
|
||||
return (_rows.size() - 1) * _st->buttonSkip() + _rows.size() * _st->buttonHeight();
|
||||
}
|
||||
|
||||
void ReplyKeyboard::paint(Painter &p, int outerWidth, const QRect &clip) const {
|
||||
void ReplyKeyboard::paint(Painter &p, int outerWidth, const QRect &clip, uint64 ms) const {
|
||||
t_assert(_st != nullptr);
|
||||
t_assert(_width > 0);
|
||||
|
||||
@ -235,7 +236,7 @@ void ReplyKeyboard::paint(Painter &p, int outerWidth, const QRect &clip) const {
|
||||
// just ignore the buttons that didn't layout well
|
||||
if (rect.x() + rect.width() > _width) break;
|
||||
|
||||
_st->paintButton(p, outerWidth, button);
|
||||
_st->paintButton(p, outerWidth, button, ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,6 +252,7 @@ ClickHandlerPtr ReplyKeyboard::getState(int x, int y) const {
|
||||
if (rect.x() + rect.width() > _width) break;
|
||||
|
||||
if (rect.contains(x, y)) {
|
||||
_savedCoords = QPoint(x, y);
|
||||
return button.link;
|
||||
}
|
||||
}
|
||||
@ -261,34 +263,63 @@ ClickHandlerPtr ReplyKeyboard::getState(int x, int y) const {
|
||||
void ReplyKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
|
||||
if (!p) return;
|
||||
|
||||
bool startAnimation = false;
|
||||
_savedActive = active ? p : ClickHandlerPtr();
|
||||
auto coords = findButtonCoordsByClickHandler(p);
|
||||
if (coords.i >= 0 && _savedPressed != p) {
|
||||
startAnimation(coords.i, coords.j, active ? 1 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReplyKeyboard::ButtonCoords ReplyKeyboard::findButtonCoordsByClickHandler(const ClickHandlerPtr &p) {
|
||||
for (int i = 0, rows = _rows.size(); i != rows; ++i) {
|
||||
auto &row = _rows.at(i);
|
||||
auto &row = _rows[i];
|
||||
for (int j = 0, cols = row.size(); j != cols; ++j) {
|
||||
if (row.at(j).link == p) {
|
||||
bool startAnimation = _animations.isEmpty();
|
||||
if (row[j].link == p) {
|
||||
return { i, j };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { -1, -1 };
|
||||
}
|
||||
|
||||
int indexForAnimation = i * MatrixRowShift + j + 1;
|
||||
if (!active) {
|
||||
indexForAnimation = -indexForAnimation;
|
||||
}
|
||||
void ReplyKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||
if (!p) return;
|
||||
|
||||
_animations.remove(-indexForAnimation);
|
||||
if (!_animations.contains(indexForAnimation)) {
|
||||
_animations.insert(indexForAnimation, getms());
|
||||
}
|
||||
|
||||
if (startAnimation && !_a_selected.animating()) {
|
||||
_a_selected.start();
|
||||
}
|
||||
return;
|
||||
_savedPressed = pressed ? p : ClickHandlerPtr();
|
||||
auto coords = findButtonCoordsByClickHandler(p);
|
||||
if (coords.i >= 0) {
|
||||
auto &button = _rows[coords.i][coords.j];
|
||||
if (pressed) {
|
||||
if (!button.ripple) {
|
||||
auto mask = Ui::RippleAnimation::roundRectMask(button.rect.size(), _st->buttonRadius());
|
||||
button.ripple = MakeShared<Ui::RippleAnimation>(_st->_st->ripple, std_::move(mask), [this] { _st->repaint(_item); });
|
||||
}
|
||||
button.ripple->add(_savedCoords - button.rect.topLeft());
|
||||
} else {
|
||||
if (button.ripple) {
|
||||
button.ripple->lastStop();
|
||||
}
|
||||
if (_savedActive != p) {
|
||||
startAnimation(coords.i, coords.j, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReplyKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
|
||||
_st->repaint(_item);
|
||||
void ReplyKeyboard::startAnimation(int i, int j, int direction) {
|
||||
auto notStarted = _animations.isEmpty();
|
||||
|
||||
int indexForAnimation = (i * MatrixRowShift + j + 1) * direction;
|
||||
|
||||
_animations.remove(-indexForAnimation);
|
||||
if (!_animations.contains(indexForAnimation)) {
|
||||
_animations.insert(indexForAnimation, getms());
|
||||
}
|
||||
|
||||
if (notStarted && !_a_selected.animating()) {
|
||||
_a_selected.start();
|
||||
}
|
||||
}
|
||||
|
||||
void ReplyKeyboard::step_selected(uint64 ms, bool timer) {
|
||||
@ -330,11 +361,15 @@ int ReplyKeyboard::Style::buttonHeight() const {
|
||||
return _st->height;
|
||||
}
|
||||
|
||||
void ReplyKeyboard::Style::paintButton(Painter &p, int outerWidth, const ReplyKeyboard::Button &button) const {
|
||||
void ReplyKeyboard::Style::paintButton(Painter &p, int outerWidth, const ReplyKeyboard::Button &button, uint64 ms) const {
|
||||
const QRect &rect = button.rect;
|
||||
bool pressed = ClickHandler::showAsPressed(button.link);
|
||||
|
||||
paintButtonBg(p, rect, pressed, button.howMuchOver);
|
||||
paintButtonBg(p, rect, button.howMuchOver);
|
||||
if (button.ripple) {
|
||||
button.ripple->paint(p, rect.x(), rect.y(), outerWidth, ms);
|
||||
if (button.ripple->empty()) {
|
||||
button.ripple.reset();
|
||||
}
|
||||
}
|
||||
paintButtonIcon(p, rect, outerWidth, button.type);
|
||||
if (button.type == HistoryMessageReplyMarkup::Button::Type::Callback
|
||||
|| button.type == HistoryMessageReplyMarkup::Button::Type::Game) {
|
||||
@ -353,8 +388,7 @@ void ReplyKeyboard::Style::paintButton(Painter &p, int outerWidth, const ReplyKe
|
||||
tx += (tw - st::botKbFont->elidew) / 2;
|
||||
tw = st::botKbFont->elidew;
|
||||
}
|
||||
int textTop = rect.y() + (pressed ? _st->downTextTop : _st->textTop);
|
||||
button.text.drawElided(p, tx, textTop + ((rect.height() - _st->height) / 2), tw, 1, style::al_top);
|
||||
button.text.drawElided(p, tx, rect.y() + _st->textTop + ((rect.height() - _st->height) / 2), tw, 1, style::al_top);
|
||||
}
|
||||
|
||||
void HistoryMessageReplyMarkup::createFromButtonRows(const QVector<MTPKeyboardButtonRow> &v) {
|
||||
|
@ -22,8 +22,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "core/runtime_composer.h"
|
||||
|
||||
namespace Ui {
|
||||
class RippleAnimation;
|
||||
} // namespace Ui
|
||||
|
||||
namespace style {
|
||||
struct BotKeyboardButton;
|
||||
struct RippleAnimation;
|
||||
} // namespace style
|
||||
|
||||
class HistoryElement {
|
||||
@ -294,13 +299,14 @@ public:
|
||||
int buttonSkip() const;
|
||||
int buttonPadding() const;
|
||||
int buttonHeight() const;
|
||||
virtual int buttonRadius() const = 0;
|
||||
|
||||
virtual void repaint(const HistoryItem *item) const = 0;
|
||||
virtual ~Style() {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void paintButtonBg(Painter &p, const QRect &rect, bool pressed, float64 howMuchOver) const = 0;
|
||||
virtual void paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const = 0;
|
||||
virtual void paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const = 0;
|
||||
virtual void paintButtonLoading(Painter &p, const QRect &rect) const = 0;
|
||||
virtual int minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const = 0;
|
||||
@ -308,7 +314,7 @@ public:
|
||||
private:
|
||||
const style::BotKeyboardButton *_st;
|
||||
|
||||
void paintButton(Painter &p, int outerWidth, const ReplyKeyboard::Button &button) const;
|
||||
void paintButton(Painter &p, int outerWidth, const ReplyKeyboard::Button &button, uint64 ms) const;
|
||||
friend class ReplyKeyboard;
|
||||
|
||||
};
|
||||
@ -326,7 +332,7 @@ public:
|
||||
int naturalWidth() const;
|
||||
int naturalHeight() const;
|
||||
|
||||
void paint(Painter &p, int outerWidth, const QRect &clip) const;
|
||||
void paint(Painter &p, int outerWidth, const QRect &clip, uint64 ms) const;
|
||||
ClickHandlerPtr getState(int x, int y) const;
|
||||
|
||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active);
|
||||
@ -336,8 +342,7 @@ public:
|
||||
void updateMessageId();
|
||||
|
||||
private:
|
||||
const HistoryItem *_item;
|
||||
int _width = 0;
|
||||
void startAnimation(int i, int j, int direction);
|
||||
|
||||
friend class Style;
|
||||
using ReplyMarkupClickHandlerPtr = QSharedPointer<ReplyMarkupClickHandler>;
|
||||
@ -348,17 +353,33 @@ private:
|
||||
float64 howMuchOver = 0.;
|
||||
HistoryMessageReplyMarkup::Button::Type type;
|
||||
ReplyMarkupClickHandlerPtr link;
|
||||
mutable QSharedPointer<Ui::RippleAnimation> ripple;
|
||||
};
|
||||
using ButtonRow = QVector<Button>;
|
||||
using ButtonRows = QVector<ButtonRow>;
|
||||
ButtonRows _rows;
|
||||
|
||||
struct ButtonCoords {
|
||||
int i, j;
|
||||
};
|
||||
ButtonCoords findButtonCoordsByClickHandler(const ClickHandlerPtr &p);
|
||||
|
||||
using Animations = QMap<int, uint64>;
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
|
||||
const HistoryItem *_item;
|
||||
int _width = 0;
|
||||
|
||||
ButtonRows _rows;
|
||||
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
StylePtr _st;
|
||||
|
||||
ClickHandlerPtr _savedPressed;
|
||||
ClickHandlerPtr _savedActive;
|
||||
mutable QPoint _savedCoords;
|
||||
|
||||
};
|
||||
|
||||
// any HistoryItem can have this Interface for
|
||||
|
@ -310,11 +310,12 @@ void HistoryMessage::KeyboardStyle::repaint(const HistoryItem *item) const {
|
||||
Ui::repaintHistoryItem(item);
|
||||
}
|
||||
|
||||
void HistoryMessage::KeyboardStyle::paintButtonBg(Painter &p, const QRect &rect, bool down, float64 howMuchOver) const {
|
||||
int HistoryMessage::KeyboardStyle::buttonRadius() const {
|
||||
return st::dateRadius;
|
||||
}
|
||||
|
||||
void HistoryMessage::KeyboardStyle::paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const {
|
||||
App::roundRect(p, rect, st::msgServiceBg, StickerCorners);
|
||||
if (down) {
|
||||
howMuchOver = 1.;
|
||||
}
|
||||
if (howMuchOver > 0) {
|
||||
auto o = p.opacity();
|
||||
p.setOpacity(o * howMuchOver);
|
||||
@ -1278,7 +1279,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||
height -= h;
|
||||
int top = height + st::msgBotKbButton.margin - marginBottom();
|
||||
p.translate(left, top);
|
||||
keyboard->paint(p, width, r.translated(-left, -top));
|
||||
keyboard->paint(p, width, r.translated(-left, -top), ms);
|
||||
p.translate(-left, -top);
|
||||
}
|
||||
|
||||
|
@ -208,12 +208,14 @@ private:
|
||||
public:
|
||||
using ReplyKeyboard::Style::Style;
|
||||
|
||||
int buttonRadius() const override;
|
||||
|
||||
void startPaint(Painter &p) const override;
|
||||
style::font textFont() const override;
|
||||
void repaint(const HistoryItem *item) const override;
|
||||
|
||||
protected:
|
||||
void paintButtonBg(Painter &p, const QRect &rect, bool down, float64 howMuchOver) const override;
|
||||
void paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const override;
|
||||
void paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
void paintButtonLoading(Painter &p, const QRect &rect) const override;
|
||||
int minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
|
@ -2437,7 +2437,7 @@ void BotKeyboard::paintEvent(QPaintEvent *e) {
|
||||
if (_impl) {
|
||||
int x = rtl() ? st::botKbScroll.width : _st->margin;
|
||||
p.translate(x, st::botKbScroll.deltat);
|
||||
_impl->paint(p, width(), clip.translated(-x, -st::botKbScroll.deltat));
|
||||
_impl->paint(p, width(), clip.translated(-x, -st::botKbScroll.deltat), getms());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2454,17 +2454,12 @@ void BotKeyboard::Style::repaint(const HistoryItem *item) const {
|
||||
_parent->update();
|
||||
}
|
||||
|
||||
void BotKeyboard::Style::paintButtonBg(Painter &p, const QRect &rect, bool down, float64 howMuchOver) const {
|
||||
if (down) {
|
||||
App::roundRect(p, rect, st::botKbDownBg, BotKeyboardDownCorners);
|
||||
} else {
|
||||
App::roundRect(p, rect, st::botKbBg, BotKeyboardCorners);
|
||||
if (howMuchOver > 0) {
|
||||
p.setOpacity(howMuchOver);
|
||||
App::roundRect(p, rect, st::botKbOverBg, BotKeyboardOverCorners);
|
||||
p.setOpacity(1);
|
||||
}
|
||||
}
|
||||
int BotKeyboard::Style::buttonRadius() const {
|
||||
return st::buttonRadius;
|
||||
}
|
||||
|
||||
void BotKeyboard::Style::paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const {
|
||||
App::roundRect(p, rect, st::botKbBg, BotKeyboardCorners);
|
||||
}
|
||||
|
||||
void BotKeyboard::Style::paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const {
|
||||
@ -3018,7 +3013,7 @@ TextWithTags::Tags textTagsFromEntities(const EntitiesInText &entities) {
|
||||
HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||
, _fieldBarCancel(this, st::historyReplyCancel)
|
||||
, _scroll(this, st::historyScroll, false)
|
||||
, _historyToEnd(this)
|
||||
, _historyToEnd(this, st::historyToDown)
|
||||
, _fieldAutocomplete(this)
|
||||
, _reportSpamPanel(this)
|
||||
, _send(this, st::historySend)
|
||||
|
@ -427,12 +427,14 @@ private:
|
||||
Style(BotKeyboard *parent, const style::BotKeyboardButton &st) : ReplyKeyboard::Style(st), _parent(parent) {
|
||||
}
|
||||
|
||||
int buttonRadius() const override;
|
||||
|
||||
void startPaint(Painter &p) const override;
|
||||
style::font textFont() const override;
|
||||
void repaint(const HistoryItem *item) const override;
|
||||
|
||||
protected:
|
||||
void paintButtonBg(Painter &p, const QRect &rect, bool down, float64 howMuchOver) const override;
|
||||
void paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const override;
|
||||
void paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
void paintButtonLoading(Painter &p, const QRect &rect) const override;
|
||||
int minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
|
@ -83,7 +83,6 @@ introNextButton: RoundButton(defaultActiveButton) {
|
||||
height: 56px;
|
||||
|
||||
textTop: 16px;
|
||||
downTextTop: 17px;
|
||||
|
||||
font: font(17px);
|
||||
}
|
||||
@ -147,8 +146,6 @@ introBackButton: IconButton {
|
||||
{ size(40px, 40px), #eeeeee },
|
||||
{ "title_back", #969696, point(12px, 12px) },
|
||||
};
|
||||
|
||||
iconPosition: point(0px, 0px);
|
||||
iconPositionDown: point(0px, 0px);
|
||||
}
|
||||
introBackPosition: point(32px, 32px);
|
||||
|
@ -76,7 +76,6 @@ mediaPlayerRepeatButton: IconButton {
|
||||
{ "player_repeat", mediaPlayerActiveFg, point(9px, 11px) }
|
||||
};
|
||||
iconPosition: point(0px, 0px);
|
||||
iconPositionDown: point(0px, 0px);
|
||||
}
|
||||
mediaPlayerRepeatDisabledIcon: icon {
|
||||
{ "player_repeat", #c8c8c8, point(9px, 11px)}
|
||||
@ -103,7 +102,6 @@ mediaPlayerVolumeToggle: IconButton {
|
||||
|
||||
icon: mediaPlayerVolumeIcon0;
|
||||
iconPosition: point(8px, 11px);
|
||||
iconPositionDown: point(8px, 11px);
|
||||
}
|
||||
mediaPlayerVolumeMargin: 10px;
|
||||
mediaPlayerVolumeSize: size(27px, 100px);
|
||||
|
@ -51,9 +51,7 @@ mediaviewPlayButton: IconButton {
|
||||
|
||||
icon: icon {{ "media_play", #c7c7c7, point(3px, 0px) }};
|
||||
iconOver: icon {{ "media_play", #ffffff, point(3px, 0px) }};
|
||||
|
||||
iconPosition: point(3px, 1px);
|
||||
iconPositionDown: point(3px, 1px);
|
||||
|
||||
duration: mediaviewOverDuration;
|
||||
}
|
||||
@ -67,7 +65,6 @@ mediaviewFullScreenButton: IconButton(mediaviewPlayButton) {
|
||||
icon: icon {{ "media_fullscreen_to", #c7c7c7, point(0px, 0px) }};
|
||||
iconOver: icon {{ "media_fullscreen_to", #ffffff, point(0px, 0px) }};
|
||||
iconPosition: point(0px, 1px);
|
||||
iconPositionDown: point(0px, 1px);
|
||||
}
|
||||
mediaviewFullScreenOutIcon: icon {{ "media_fullscreen_from", #c7c7c7, point(0px, 0px) }};
|
||||
mediaviewFullScreenOutIconOver: icon {{ "media_fullscreen_from", #ffffff, point(0px, 0px) }};
|
||||
@ -136,6 +133,10 @@ mediaviewMenu: Menu(defaultMenu) {
|
||||
itemFgShortcutDisabled: mediaviewMenuFg;
|
||||
|
||||
separatorFg: mediaviewMenuFg;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: mediaviewMenuBgRipple;
|
||||
}
|
||||
}
|
||||
mediaviewMenuShadow: Shadow(defaultEmptyShadow) {
|
||||
fallback: mediaviewMenuBg;
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "styles/style_profile.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/report_box.h"
|
||||
#include "mainwidget.h"
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "styles/style_profile.h"
|
||||
#include "mtproto/file_download.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "profile/profile_settings_widget.h"
|
||||
|
||||
#include "styles/style_profile.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/contactsbox.h"
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "styles/style_profile.h"
|
||||
#include "observer_peer.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "mainwidget.h"
|
||||
#include "lang.h"
|
||||
|
||||
|
@ -76,7 +76,6 @@ settingsEditButton: IconButton {
|
||||
|
||||
icon: icon {{ "settings_edit_name", #b7b7b7 }};
|
||||
iconPosition: point(3px, 9px);
|
||||
iconPositionDown: point(3px, 10px);
|
||||
}
|
||||
|
||||
settingsBlocksTop: 7px;
|
||||
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "styles/style_stickers.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/stickersetbox.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
@ -1003,13 +1004,13 @@ void StickerPanInner::paintStickers(Painter &p, const QRect &r) {
|
||||
tocol = StickerPanPerRow - tocol;
|
||||
}
|
||||
|
||||
int y, tilly = 0;
|
||||
|
||||
auto tilly = 0;
|
||||
auto ms = getms();
|
||||
auto &sets = shownSets();
|
||||
if (_section == Section::Featured) {
|
||||
tilly += st::emojiPanHeader;
|
||||
for (int c = 0, l = sets.size(); c < l; ++c) {
|
||||
y = tilly;
|
||||
auto y = tilly;
|
||||
auto &set = sets[c];
|
||||
tilly = y + featuredRowHeight();
|
||||
if (r.top() >= tilly) continue;
|
||||
@ -1020,14 +1021,19 @@ void StickerPanInner::paintStickers(Painter &p, const QRect &r) {
|
||||
int widthForTitle = featuredContentWidth() - (st::emojiPanHeaderLeft - st::buttonRadius);
|
||||
if (featuredHasAddButton(c)) {
|
||||
auto add = featuredAddRect(c);
|
||||
auto selected = (_selectedFeaturedSetAdd == c);
|
||||
auto selected = (_selectedFeaturedSetAdd == c) || (_pressedFeaturedSetAdd == c);
|
||||
auto &textBg = selected ? st::stickersTrendingAdd.textBgOver : st::stickersTrendingAdd.textBg;
|
||||
auto textTop = (selected && _selectedFeaturedSetAdd == _pressedFeaturedSetAdd) ? st::stickersTrendingAdd.downTextTop : st::stickersTrendingAdd.textTop;
|
||||
|
||||
App::roundRect(p, myrtlrect(add), textBg, ImageRoundRadius::Small);
|
||||
if (set.ripple) {
|
||||
set.ripple->paint(p, add.x(), add.y(), width(), ms);
|
||||
if (set.ripple->empty()) {
|
||||
set.ripple.reset();
|
||||
}
|
||||
}
|
||||
p.setFont(st::stickersTrendingAdd.font);
|
||||
p.setPen(selected ? st::stickersTrendingAdd.textFgOver : st::stickersTrendingAdd.textFg);
|
||||
p.drawTextLeft(add.x() - (st::stickersTrendingAdd.width / 2), add.y() + textTop, width(), _addText, _addWidth);
|
||||
p.drawTextLeft(add.x() - (st::stickersTrendingAdd.width / 2), add.y() + st::stickersTrendingAdd.textTop, width(), _addText, _addWidth);
|
||||
|
||||
widthForTitle -= add.width() - (st::stickersTrendingAdd.width / 2);
|
||||
} else {
|
||||
@ -1075,10 +1081,10 @@ void StickerPanInner::paintStickers(Painter &p, const QRect &r) {
|
||||
}
|
||||
} else {
|
||||
for (int c = 0, l = sets.size(); c < l; ++c) {
|
||||
y = tilly;
|
||||
auto y = tilly;
|
||||
auto &set = sets[c];
|
||||
int32 size = set.pack.size();
|
||||
int32 rows = (size / StickerPanPerRow) + ((size % StickerPanPerRow) ? 1 : 0);
|
||||
auto size = set.pack.size();
|
||||
auto rows = (size / StickerPanPerRow) + ((size % StickerPanPerRow) ? 1 : 0);
|
||||
tilly = y + st::emojiPanHeader + (rows * st::stickerPanSize.height());
|
||||
if (r.y() >= tilly) continue;
|
||||
|
||||
@ -1175,25 +1181,45 @@ void StickerPanInner::mousePressEvent(QMouseEvent *e) {
|
||||
|
||||
_pressed = _selected;
|
||||
_pressedFeaturedSet = _selectedFeaturedSet;
|
||||
_pressedFeaturedSetAdd = _selectedFeaturedSetAdd;
|
||||
setPressedFeaturedSetAdd(_selectedFeaturedSetAdd);
|
||||
ClickHandler::pressed();
|
||||
_previewTimer.start(QApplication::startDragTime());
|
||||
}
|
||||
|
||||
void StickerPanInner::setPressedFeaturedSetAdd(int newPressedFeaturedSetAdd) {
|
||||
if (_pressedFeaturedSetAdd >= 0 && _pressedFeaturedSetAdd < _featuredSets.size()) {
|
||||
auto &set = _featuredSets[_pressedFeaturedSetAdd];
|
||||
if (set.ripple) {
|
||||
set.ripple->lastStop();
|
||||
}
|
||||
}
|
||||
_pressedFeaturedSetAdd = newPressedFeaturedSetAdd;
|
||||
if (_pressedFeaturedSetAdd >= 0 && _pressedFeaturedSetAdd < _featuredSets.size()) {
|
||||
auto &set = _featuredSets[_pressedFeaturedSetAdd];
|
||||
if (!set.ripple) {
|
||||
auto maskSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height);
|
||||
auto mask = Ui::RippleAnimation::roundRectMask(maskSize, st::buttonRadius);
|
||||
set.ripple = MakeShared<Ui::RippleAnimation>(st::stickersTrendingAdd.ripple, std_::move(mask), [this, index = _pressedFeaturedSetAdd] {
|
||||
update(myrtlrect(featuredAddRect(index)));
|
||||
});
|
||||
}
|
||||
auto rect = myrtlrect(featuredAddRect(_pressedFeaturedSetAdd));
|
||||
set.ripple->add(mapFromGlobal(QCursor::pos()) - rect.topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_previewTimer.stop();
|
||||
|
||||
auto pressed = _pressed;
|
||||
_pressed = -1;
|
||||
auto pressedFeaturedSet = _pressedFeaturedSet;
|
||||
_pressedFeaturedSet = -1;
|
||||
auto pressed = base::take(_pressed, -1);
|
||||
auto pressedFeaturedSet = base::take(_pressedFeaturedSet, -1);
|
||||
auto pressedFeaturedSetAdd = _pressedFeaturedSetAdd;
|
||||
if (_pressedFeaturedSetAdd != _selectedFeaturedSetAdd) {
|
||||
setPressedFeaturedSetAdd(-1);
|
||||
if (pressedFeaturedSetAdd != _selectedFeaturedSetAdd) {
|
||||
update();
|
||||
}
|
||||
_pressedFeaturedSetAdd = -1;
|
||||
|
||||
ClickHandlerPtr activated = ClickHandler::unpressed();
|
||||
auto activated = ClickHandler::unpressed();
|
||||
|
||||
if (_previewShown) {
|
||||
_previewShown = false;
|
||||
@ -1360,7 +1386,8 @@ void StickerPanInner::clearSelection(bool fast) {
|
||||
}
|
||||
_selected = _pressed = -1;
|
||||
_selectedFeaturedSet = _pressedFeaturedSet = -1;
|
||||
_selectedFeaturedSetAdd = _pressedFeaturedSetAdd = -1;
|
||||
_selectedFeaturedSetAdd = -1;
|
||||
setPressedFeaturedSetAdd(-1);
|
||||
_a_selected.stop();
|
||||
update();
|
||||
} else {
|
||||
|
@ -37,6 +37,7 @@ class ScrollArea;
|
||||
class IconButton;
|
||||
class LinkButton;
|
||||
class RoundButton;
|
||||
class RippleAnimation;
|
||||
} // namesapce Ui
|
||||
|
||||
namespace internal {
|
||||
@ -307,6 +308,8 @@ private:
|
||||
static constexpr bool kRefreshIconsScrollAnimation = true;
|
||||
static constexpr bool kRefreshIconsNoAnimation = false;
|
||||
|
||||
void setPressedFeaturedSetAdd(int newPressedFeaturedSetAdd);
|
||||
|
||||
struct Set {
|
||||
Set(uint64 id, MTPDstickerSet::Flags flags, const QString &title, int32 hoversSize, const StickerPack &pack = StickerPack()) : id(id), flags(flags), title(title), hovers(hoversSize, 0), pack(pack) {
|
||||
}
|
||||
@ -315,6 +318,7 @@ private:
|
||||
QString title;
|
||||
QVector<float64> hovers;
|
||||
StickerPack pack;
|
||||
QSharedPointer<Ui::RippleAnimation> ripple;
|
||||
};
|
||||
using Sets = QList<Set>;
|
||||
Sets &shownSets() {
|
||||
|
@ -27,7 +27,6 @@ switchPmButton: RoundButton(defaultBoxButton) {
|
||||
width: 320px;
|
||||
height: 34px;
|
||||
textTop: 7px;
|
||||
downTextTop: 8px;
|
||||
}
|
||||
|
||||
stickersTrendingHeader: 45px;
|
||||
@ -45,7 +44,6 @@ stickersTrendingAdd: RoundButton(defaultActiveButton) {
|
||||
width: -17px;
|
||||
height: 26px;
|
||||
textTop: 4px;
|
||||
downTextTop: 5px;
|
||||
}
|
||||
|
||||
stickerEmojiSkip: 5px;
|
||||
@ -113,7 +111,6 @@ emojiCategory: IconButton {
|
||||
height: 46px;
|
||||
|
||||
iconPosition: point(11px, 12px);
|
||||
iconPositionDown: point(11px, 12px);
|
||||
}
|
||||
emojiCategoryRecent: IconButton(emojiCategory) { icon: emojiRecent; }
|
||||
emojiCategoryPeople: IconButton(emojiCategory) { icon: emojiPeople; }
|
||||
@ -174,7 +171,5 @@ hashtagClose: IconButton {
|
||||
|
||||
icon: simpleCloseIcon;
|
||||
iconOver: simpleCloseIconOver;
|
||||
|
||||
iconPosition: point(10px, 10px);
|
||||
iconPositionDown: point(10px, 11px);
|
||||
}
|
||||
|
@ -23,46 +23,43 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "styles/style_history.h"
|
||||
#include "dialogs/dialogs_layout.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
HistoryDownButton::HistoryDownButton(QWidget *parent) : AbstractButton(parent)
|
||||
HistoryDownButton::HistoryDownButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
|
||||
, _st(st)
|
||||
//, a_arrowOpacity(st::historyAttachEmoji.opacity, st::historyAttachEmoji.opacity)
|
||||
, _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
|
||||
resize(_st.width, _st.height);
|
||||
setCursor(style::cur_pointer);
|
||||
|
||||
int iconWidth = st::historyToDown.width();
|
||||
int iconHeight = st::historyToDown.height();
|
||||
int retina = cIntRetinaFactor();
|
||||
resize(iconWidth, st::historyToDownPaddingTop + iconHeight);
|
||||
|
||||
QImage cache(iconWidth * retina, iconHeight * retina, QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(cRetinaFactor());
|
||||
{
|
||||
Painter p(&cache);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(0, 0, iconWidth, iconHeight, Qt::transparent);
|
||||
st::historyToDown.paint(p, QPoint(0, 0), st::historyToDown.width());
|
||||
}
|
||||
_cache = App::pixmapFromImageInPlace(std_::move(cache));
|
||||
_cache.setDevicePixelRatio(cRetinaFactor());
|
||||
|
||||
hide();
|
||||
}
|
||||
|
||||
QImage HistoryDownButton::prepareRippleMask() const {
|
||||
return Ui::RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
}
|
||||
|
||||
QPoint HistoryDownButton::prepareRippleStartPosition() const {
|
||||
return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
|
||||
}
|
||||
|
||||
void HistoryDownButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
if (_a_show.animating(getms())) {
|
||||
p.setOpacity(_a_show.current());
|
||||
p.drawPixmap(0, st::historyToDownPaddingTop, _cache);
|
||||
} else if (!_shown) {
|
||||
hide();
|
||||
auto ms = getms();
|
||||
auto opacity = _a_show.current(ms, _shown ? 1. : 0.);
|
||||
if (opacity == 0.) {
|
||||
if (!_shown) hide();
|
||||
return;
|
||||
} else {
|
||||
st::historyToDown.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
|
||||
}
|
||||
st::historyToDownArrow.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
|
||||
p.setOpacity(opacity);
|
||||
auto over = (_state & StateOver);
|
||||
auto down = (_state & StateDown);
|
||||
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
|
||||
((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width());
|
||||
if (_unreadCount > 0) {
|
||||
auto unreadString = QString::number(_unreadCount);
|
||||
if (unreadString.size() > 4) {
|
||||
@ -78,18 +75,6 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryDownButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
//a_arrowOpacity.start((_state & (StateOver | StateDown)) ? st::historyAttachEmoji.overOpacity : st::historyAttachEmoji.opacity);
|
||||
|
||||
if (source == StateChangeSource::ByUser || source == StateChangeSource::ByPress) {
|
||||
_a_arrowOver.stop();
|
||||
a_arrowOpacity.finish();
|
||||
update();
|
||||
} else {
|
||||
_a_arrowOver.start();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryDownButton::setUnreadCount(int unreadCount) {
|
||||
_unreadCount = unreadCount;
|
||||
update();
|
||||
@ -152,7 +137,7 @@ void EmojiButton::paintEvent(QPaintEvent *e) {
|
||||
|
||||
auto over = (_state & StateOver);
|
||||
auto icon = &(over ? _st.iconOver : _st.icon);
|
||||
icon->paint(p, (_state & StateDown) ? _st.iconPositionDown : _st.iconPosition, width());
|
||||
icon->paint(p, _st.iconPosition, width());
|
||||
|
||||
p.setOpacity(1.);
|
||||
p.setPen(QPen(over ? st::historyEmojiCircleFgOver : st::historyEmojiCircleFg, st::historyEmojiCircleLine));
|
||||
|
@ -20,14 +20,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class HistoryDownButton : public AbstractButton {
|
||||
class HistoryDownButton : public RippleButton {
|
||||
public:
|
||||
HistoryDownButton(QWidget *parent);
|
||||
HistoryDownButton(QWidget *parent, const style::TwoIconButton &st);
|
||||
|
||||
void setUnreadCount(int unreadCount);
|
||||
int unreadCount() const {
|
||||
@ -44,13 +44,15 @@ public:
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
private:
|
||||
void toggleAnimated();
|
||||
void step_arrowOver(float64 ms, bool timer);
|
||||
|
||||
QPixmap _cache;
|
||||
const style::TwoIconButton &_st;
|
||||
|
||||
bool _shown = false;
|
||||
|
||||
anim::fvalue a_arrowOpacity;
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "ui/buttons/left_outline_button.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
LeftOutlineButton::LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st) : AbstractButton(parent)
|
||||
, _text(text)
|
||||
, _fullText(text)
|
||||
, _textWidth(st.font->width(_text))
|
||||
, _fullTextWidth(_textWidth)
|
||||
, _st(st) {
|
||||
resizeToWidth(_textWidth + _st.padding.left() + _st.padding.right());
|
||||
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
void LeftOutlineButton::setText(const QString &text) {
|
||||
_text = text;
|
||||
_fullText = text;
|
||||
_fullTextWidth = _textWidth = _st.font->width(_text);
|
||||
resizeToWidth(width());
|
||||
update();
|
||||
}
|
||||
|
||||
int LeftOutlineButton::resizeGetHeight(int newWidth) {
|
||||
int availableWidth = qMax(newWidth - _st.padding.left() - _st.padding.right(), 1);
|
||||
if ((availableWidth < _fullTextWidth) || (_textWidth < availableWidth)) {
|
||||
_text = _st.font->elided(_fullText, availableWidth);
|
||||
_textWidth = _st.font->width(_text);
|
||||
}
|
||||
return _st.padding.top() + _st.font->height + _st.padding.bottom();
|
||||
}
|
||||
|
||||
void LeftOutlineButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
bool over = (_state & StateOver);
|
||||
if (width() > _st.outlineWidth) {
|
||||
p.fillRect(rtlrect(0, 0, _st.outlineWidth, height(), width()), over ? _st.outlineFgOver : _st.outlineFg);
|
||||
p.fillRect(rtlrect(_st.outlineWidth, 0, width() - _st.outlineWidth, height(), width()), over ? _st.textBgOver : _st.textBg);
|
||||
}
|
||||
p.setFont(_st.font);
|
||||
p.setPen(over ? _st.textFgOver : _st.textFg);
|
||||
p.drawTextLeft(_st.padding.left(), _st.padding.top(), width(), _text, _textWidth);
|
||||
}
|
||||
|
||||
void LeftOutlineButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
}
|
||||
|
||||
} // namespace Ui
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/abstract_button.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class LeftOutlineButton : public AbstractButton {
|
||||
public:
|
||||
LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st = st::defaultLeftOutlineButton);
|
||||
|
||||
void setText(const QString &text);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
QString _text, _fullText;
|
||||
int _textWidth, _fullTextWidth;
|
||||
|
||||
const style::OutlineButton &_st;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
@ -190,6 +190,35 @@ void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, uint64 ms
|
||||
clearFinished();
|
||||
}
|
||||
|
||||
QImage RippleAnimation::maskByDrawer(QSize size, bool filled, base::lambda_unique<void(QPainter &p)> drawer) {
|
||||
auto result = QImage(size * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
result.fill(filled ? QColor(255, 255, 255) : Qt::transparent);
|
||||
if (drawer) {
|
||||
Painter p(&result);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(255, 255, 255));
|
||||
drawer(p);
|
||||
}
|
||||
return std_::move(result);
|
||||
}
|
||||
|
||||
QImage RippleAnimation::rectMask(QSize size) {
|
||||
return maskByDrawer(size, true, base::lambda_unique<void(QPainter&)>());
|
||||
}
|
||||
|
||||
QImage RippleAnimation::roundRectMask(QSize size, int radius) {
|
||||
return maskByDrawer(size, false, [size, radius](QPainter &p) {
|
||||
p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius);
|
||||
});
|
||||
}
|
||||
|
||||
QImage RippleAnimation::ellipseMask(QSize size) {
|
||||
return maskByDrawer(size, false, [size](QPainter &p) {
|
||||
p.drawEllipse(0, 0, size.width(), size.height());
|
||||
});
|
||||
}
|
||||
|
||||
void RippleAnimation::clearFinished() {
|
||||
while (!_ripples.isEmpty() && _ripples.front()->finished()) {
|
||||
delete base::take(_ripples.front());
|
||||
|
@ -45,6 +45,11 @@ public:
|
||||
return _ripples.isEmpty();
|
||||
}
|
||||
|
||||
static QImage maskByDrawer(QSize size, bool filled, base::lambda_unique<void(QPainter &p)> drawer);
|
||||
static QImage rectMask(QSize size);
|
||||
static QImage roundRectMask(QSize size, int radius);
|
||||
static QImage ellipseMask(QSize size);
|
||||
|
||||
~RippleAnimation() {
|
||||
clear();
|
||||
}
|
||||
|
@ -25,7 +25,111 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
namespace Ui {
|
||||
|
||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st) : AbstractButton(parent)
|
||||
LinkButton::LinkButton(QWidget *parent, const QString &text, const style::LinkButton &st) : AbstractButton(parent)
|
||||
, _text(text)
|
||||
, _textWidth(st.font->width(_text))
|
||||
, _st(st) {
|
||||
resize(_textWidth, _st.font->height);
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
int LinkButton::naturalWidth() const {
|
||||
return _textWidth;
|
||||
}
|
||||
|
||||
void LinkButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
auto &font = ((_state & StateOver) ? _st.overFont : _st.font);
|
||||
auto &pen = ((_state & StateDown) ? _st.downColor : ((_state & StateOver) ? _st.overColor : _st.color));
|
||||
p.setFont(font);
|
||||
p.setPen(pen);
|
||||
if (_textWidth > width()) {
|
||||
p.drawText(0, font->ascent, font->elided(_text, width()));
|
||||
} else {
|
||||
p.drawText(0, font->ascent, _text);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkButton::setText(const QString &text) {
|
||||
_text = text;
|
||||
_textWidth = _st.font->width(_text);
|
||||
resize(_textWidth, _st.font->height);
|
||||
update();
|
||||
}
|
||||
|
||||
void LinkButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
}
|
||||
|
||||
RippleButton::RippleButton(QWidget *parent, const style::RippleAnimation &st) : AbstractButton(parent)
|
||||
, _st(st) {
|
||||
}
|
||||
|
||||
void RippleButton::setForceRippled(bool rippled, SetForceRippledWay way) {
|
||||
if (_forceRippled != rippled) {
|
||||
_forceRippled = rippled;
|
||||
if (_forceRippled) {
|
||||
ensureRipple();
|
||||
if (_ripple->empty()) {
|
||||
_ripple->addFading();
|
||||
} else {
|
||||
_ripple->lastUnstop();
|
||||
}
|
||||
} else if (_ripple) {
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
if (way == SetForceRippledWay::SkipAnimation && _ripple) {
|
||||
_ripple->lastFinish();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void RippleButton::paintRipple(QPainter &p, int x, int y, uint64 ms) {
|
||||
if (_ripple) {
|
||||
_ripple->paint(p, x, y, width(), ms);
|
||||
if (_ripple->empty()) {
|
||||
_ripple.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RippleButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
|
||||
auto wasDown = (oldState & StateDown);
|
||||
auto down = (_state & StateDown);
|
||||
if (!_st.showDuration || down == wasDown || _forceRippled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (down && (source == StateChangeSource::ByPress)) {
|
||||
// Start a ripple only from mouse press.
|
||||
ensureRipple();
|
||||
_ripple->add(prepareRippleStartPosition());
|
||||
} else if (!down && _ripple) {
|
||||
// Finish ripple anyway.
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
|
||||
void RippleButton::ensureRipple() {
|
||||
if (!_ripple) {
|
||||
_ripple = std_::make_unique<RippleAnimation>(_st, prepareRippleMask(), [this] { update(); });
|
||||
}
|
||||
}
|
||||
|
||||
QImage RippleButton::prepareRippleMask() const {
|
||||
return RippleAnimation::rectMask(size());
|
||||
}
|
||||
|
||||
QPoint RippleButton::prepareRippleStartPosition() const {
|
||||
return mapFromGlobal(QCursor::pos());
|
||||
}
|
||||
|
||||
RippleButton::~RippleButton() = default;
|
||||
|
||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st) : RippleButton(parent, st.ripple)
|
||||
, _text(text)
|
||||
, _st(st)
|
||||
, a_over(0)
|
||||
@ -81,6 +185,8 @@ void FlatButton::step_appearance(float64 ms, bool timer) {
|
||||
}
|
||||
|
||||
void FlatButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
RippleButton::onStateChanged(oldState, source);
|
||||
|
||||
a_over.start((_state & StateOver) ? 1. : 0.);
|
||||
if (source == StateChangeSource::ByUser || source == StateChangeSource::ByPress) {
|
||||
_a_appearance.stop();
|
||||
@ -89,27 +195,6 @@ void FlatButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
} else {
|
||||
_a_appearance.start();
|
||||
}
|
||||
|
||||
handleRipples(oldState & StateDown, (source == StateChangeSource::ByPress));
|
||||
}
|
||||
|
||||
void FlatButton::handleRipples(bool wasDown, bool wasPress) {
|
||||
auto down = static_cast<bool>(_state & StateDown);
|
||||
if (!_st.ripple.showDuration || down == wasDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (down && wasPress) {
|
||||
// Start a ripple only from mouse press.
|
||||
if (!_ripple) {
|
||||
_ripple = std_::make_unique<Ui::RippleAnimation>(_st.ripple, prepareRippleMask(), [this] { update(); });
|
||||
}
|
||||
auto clickPosition = mapFromGlobal(QCursor::pos());
|
||||
_ripple->add(clickPosition);
|
||||
} else if (!down && _ripple) {
|
||||
// Finish ripple anyway.
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
|
||||
void FlatButton::paintEvent(QPaintEvent *e) {
|
||||
@ -121,69 +206,17 @@ void FlatButton::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(r, anim::brush(_st.bgColor, _st.overBgColor, a_over.current()));
|
||||
|
||||
auto ms = getms();
|
||||
if (_ripple) {
|
||||
_ripple->paint(p, 0, 0, width(), ms);
|
||||
if (_ripple->empty()) {
|
||||
_ripple.reset();
|
||||
}
|
||||
}
|
||||
paintRipple(p, 0, 0, ms);
|
||||
|
||||
p.setFont((_state & StateOver) ? _st.overFont : _st.font);
|
||||
p.setRenderHint(QPainter::TextAntialiasing);
|
||||
p.setPen(anim::pen(_st.color, _st.overColor, a_over.current()));
|
||||
|
||||
auto top = (_state & StateDown) ? _st.downTextTop : ((_state & StateOver) ? _st.overTextTop : _st.textTop);
|
||||
r.setTop(top);
|
||||
|
||||
r.setTop(_st.textTop);
|
||||
p.drawText(r, _text, style::al_top);
|
||||
}
|
||||
|
||||
QImage FlatButton::prepareRippleMask() const {
|
||||
auto result = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
result.fill(QColor(255, 255, 255));
|
||||
return std_::move(result);
|
||||
}
|
||||
|
||||
FlatButton::~FlatButton() = default;
|
||||
|
||||
LinkButton::LinkButton(QWidget *parent, const QString &text, const style::LinkButton &st) : AbstractButton(parent)
|
||||
, _text(text)
|
||||
, _textWidth(st.font->width(_text))
|
||||
, _st(st) {
|
||||
resize(_textWidth, _st.font->height);
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
int LinkButton::naturalWidth() const {
|
||||
return _textWidth;
|
||||
}
|
||||
|
||||
void LinkButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
auto &font = ((_state & StateOver) ? _st.overFont : _st.font);
|
||||
auto &pen = ((_state & StateDown) ? _st.downColor : ((_state & StateOver) ? _st.overColor : _st.color));
|
||||
p.setFont(font);
|
||||
p.setPen(pen);
|
||||
if (_textWidth > width()) {
|
||||
p.drawText(0, font->ascent, font->elided(_text, width()));
|
||||
} else {
|
||||
p.drawText(0, font->ascent, _text);
|
||||
}
|
||||
}
|
||||
|
||||
void LinkButton::setText(const QString &text) {
|
||||
_text = text;
|
||||
_textWidth = _st.font->width(_text);
|
||||
resize(_textWidth, _st.font->height);
|
||||
update();
|
||||
}
|
||||
|
||||
void LinkButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
}
|
||||
|
||||
RoundButton::RoundButton(QWidget *parent, const QString &text, const style::RoundButton &st) : AbstractButton(parent)
|
||||
RoundButton::RoundButton(QWidget *parent, const QString &text, const style::RoundButton &st) : RippleButton(parent, st.ripple)
|
||||
, _fullText(text)
|
||||
, _st(st) {
|
||||
setCursor(style::cur_pointer);
|
||||
@ -264,20 +297,14 @@ void RoundButton::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
|
||||
auto ms = getms();
|
||||
if (_ripple) {
|
||||
_ripple->paint(p, rounded.x(), rounded.y(), width(), ms);
|
||||
if (_ripple->empty()) {
|
||||
_ripple.reset();
|
||||
}
|
||||
}
|
||||
paintRipple(p, rounded.x(), rounded.y(), ms);
|
||||
|
||||
p.setFont(_st.font);
|
||||
int textLeft = _st.padding.left() + ((width() - innerWidth - _st.padding.left() - _st.padding.right()) / 2);
|
||||
if (_fullWidthOverride < 0) {
|
||||
textLeft = -_fullWidthOverride / 2;
|
||||
}
|
||||
int textTopDelta = (_state & StateDown) ? (_st.downTextTop - _st.textTop) : 0;
|
||||
int textTop = _st.padding.top() + _st.textTop + textTopDelta;
|
||||
int textTop = _st.padding.top() + _st.textTop;
|
||||
if (!_text.isEmpty()) {
|
||||
p.setPen((over || down) ? _st.textFgOver : _st.textFg);
|
||||
p.drawTextLeft(textLeft, textTop, width(), _text);
|
||||
@ -287,32 +314,7 @@ void RoundButton::paintEvent(QPaintEvent *e) {
|
||||
p.setPen((over || down) ? _st.secondaryTextFgOver : _st.secondaryTextFg);
|
||||
p.drawTextLeft(textLeft, textTop, width(), _secondaryText);
|
||||
}
|
||||
_st.icon.paint(p, QPoint(_st.padding.left(), _st.padding.right() + textTopDelta), width());
|
||||
}
|
||||
|
||||
void RoundButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
|
||||
handleRipples(oldState & StateDown, (source == StateChangeSource::ByPress));
|
||||
}
|
||||
|
||||
void RoundButton::handleRipples(bool wasDown, bool wasPress) {
|
||||
auto down = static_cast<bool>(_state & StateDown);
|
||||
if (!_st.ripple.showDuration || down == wasDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (down && wasPress) {
|
||||
// Start a ripple only from mouse press.
|
||||
if (!_ripple) {
|
||||
_ripple = std_::make_unique<Ui::RippleAnimation>(_st.ripple, prepareRippleMask(), [this] { update(); });
|
||||
}
|
||||
auto clickPosition = mapFromGlobal(QCursor::pos()) - QPoint(_st.padding.left(), _st.padding.top());
|
||||
_ripple->add(clickPosition);
|
||||
} else if (!down && _ripple) {
|
||||
// Finish ripple anyway.
|
||||
_ripple->lastStop();
|
||||
}
|
||||
_st.icon.paint(p, QPoint(_st.padding.left(), _st.padding.right()), width());
|
||||
}
|
||||
|
||||
QImage RoundButton::prepareRippleMask() const {
|
||||
@ -321,22 +323,14 @@ QImage RoundButton::prepareRippleMask() const {
|
||||
if (_fullWidthOverride < 0) {
|
||||
rounded = QRect(0, rounded.top(), innerWidth - _fullWidthOverride, rounded.height());
|
||||
}
|
||||
|
||||
auto result = QImage(rounded.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&result);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(255, 255, 255));
|
||||
p.drawRoundedRect(rounded.translated(-rounded.topLeft()), st::buttonRadius, st::buttonRadius);
|
||||
}
|
||||
return std_::move(result);
|
||||
return RippleAnimation::roundRectMask(rounded.size(), st::buttonRadius);
|
||||
}
|
||||
|
||||
RoundButton::~RoundButton() = default;
|
||||
QPoint RoundButton::prepareRippleStartPosition() const {
|
||||
return mapFromGlobal(QCursor::pos()) - QPoint(_st.padding.left(), _st.padding.top());
|
||||
}
|
||||
|
||||
IconButton::IconButton(QWidget *parent, const style::IconButton &st) : AbstractButton(parent)
|
||||
IconButton::IconButton(QWidget *parent, const style::IconButton &st) : RippleButton(parent, st.ripple)
|
||||
, _st(st) {
|
||||
resize(_st.width, _st.height);
|
||||
setCursor(style::cur_pointer);
|
||||
@ -348,40 +342,15 @@ void IconButton::setIcon(const style::icon *icon, const style::icon *iconOver) {
|
||||
update();
|
||||
}
|
||||
|
||||
void IconButton::setActiveState(bool activeState, SetStateWay way) {
|
||||
if (_activeState != activeState) {
|
||||
_activeState = activeState;
|
||||
if (_activeState) {
|
||||
ensureRipple();
|
||||
if (_ripple->empty()) {
|
||||
_ripple->addFading();
|
||||
} else {
|
||||
_ripple->lastUnstop();
|
||||
}
|
||||
} else if (_ripple) {
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
if (way == SetStateWay::SkipAnimation && _ripple) {
|
||||
_ripple->lastFinish();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void IconButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
|
||||
if (_ripple) {
|
||||
_ripple->paint(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), width(), ms);
|
||||
if (_ripple->empty()) {
|
||||
_ripple.reset();
|
||||
}
|
||||
}
|
||||
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
|
||||
|
||||
auto down = (_state & StateDown);
|
||||
auto overIconOpacity = (down || _activeState) ? 1. : _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
|
||||
auto overIconOpacity = (down || forceRippled()) ? 1. : _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
|
||||
auto overIcon = [this] {
|
||||
if (_iconOverrideOver) {
|
||||
return _iconOverrideOver;
|
||||
@ -399,7 +368,7 @@ void IconButton::paintEvent(QPaintEvent *e) {
|
||||
return &_st.icon;
|
||||
};
|
||||
auto icon = (overIconOpacity == 1.) ? overIcon() : justIcon();
|
||||
auto position = (_state & StateDown) ? _st.iconPositionDown : _st.iconPosition;
|
||||
auto position = _st.iconPosition;
|
||||
if (position.x() < 0) {
|
||||
position.setX((width() - icon->width()) / 2);
|
||||
}
|
||||
@ -417,6 +386,8 @@ void IconButton::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
|
||||
void IconButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
RippleButton::onStateChanged(oldState, source);
|
||||
|
||||
auto over = (_state & StateOver);
|
||||
if (over != (oldState & StateOver)) {
|
||||
if (_st.duration) {
|
||||
@ -427,54 +398,56 @@ void IconButton::onStateChanged(int oldState, StateChangeSource source) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
handleRipples(oldState & StateDown, (source == StateChangeSource::ByPress));
|
||||
}
|
||||
|
||||
void IconButton::handleRipples(bool wasDown, bool wasPress) {
|
||||
auto down = static_cast<bool>(_state & StateDown);
|
||||
if (!_st.ripple.showDuration || _st.rippleAreaSize <= 0 || down == wasDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (down && wasPress && !_activeState) {
|
||||
// Start a ripple only from mouse press.
|
||||
ensureRipple();
|
||||
auto clickPosition = mapFromGlobal(QCursor::pos());
|
||||
auto rippleCenter = QRect(_st.rippleAreaPosition, QSize(_st.rippleAreaSize, _st.rippleAreaSize)).center();
|
||||
auto clickRadiusSquare = style::point::dotProduct(clickPosition - rippleCenter, clickPosition - rippleCenter);
|
||||
auto startRadius = 0;
|
||||
if (clickRadiusSquare * 4 > _st.rippleAreaSize * _st.rippleAreaSize) {
|
||||
startRadius = sqrt(clickRadiusSquare) - (_st.rippleAreaSize / 2);
|
||||
}
|
||||
_ripple->add(clickPosition - _st.rippleAreaPosition, startRadius);
|
||||
} else if (!down && _ripple && !_activeState) {
|
||||
// Finish ripple anyway.
|
||||
_ripple->lastStop();
|
||||
}
|
||||
}
|
||||
|
||||
void IconButton::ensureRipple() {
|
||||
if (!_ripple) {
|
||||
_ripple = std_::make_unique<Ui::RippleAnimation>(_st.ripple, prepareRippleMask(), [this] { update(); });
|
||||
}
|
||||
QPoint IconButton::prepareRippleStartPosition() const {
|
||||
return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
|
||||
}
|
||||
|
||||
QImage IconButton::prepareRippleMask() const {
|
||||
auto size = _st.rippleAreaSize * cIntRetinaFactor();
|
||||
auto result = QImage(size, size, QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&result);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(255, 255, 255));
|
||||
p.drawEllipse(0, 0, _st.rippleAreaSize, _st.rippleAreaSize);
|
||||
}
|
||||
return std_::move(result);
|
||||
return RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
}
|
||||
|
||||
IconButton::~IconButton() = default;
|
||||
LeftOutlineButton::LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st) : RippleButton(parent, st.ripple)
|
||||
, _text(text)
|
||||
, _fullText(text)
|
||||
, _textWidth(st.font->width(_text))
|
||||
, _fullTextWidth(_textWidth)
|
||||
, _st(st) {
|
||||
resizeToWidth(_textWidth + _st.padding.left() + _st.padding.right());
|
||||
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
void LeftOutlineButton::setText(const QString &text) {
|
||||
_text = text;
|
||||
_fullText = text;
|
||||
_fullTextWidth = _textWidth = _st.font->width(_text);
|
||||
resizeToWidth(width());
|
||||
update();
|
||||
}
|
||||
|
||||
int LeftOutlineButton::resizeGetHeight(int newWidth) {
|
||||
int availableWidth = qMax(newWidth - _st.padding.left() - _st.padding.right(), 1);
|
||||
if ((availableWidth < _fullTextWidth) || (_textWidth < availableWidth)) {
|
||||
_text = _st.font->elided(_fullText, availableWidth);
|
||||
_textWidth = _st.font->width(_text);
|
||||
}
|
||||
return _st.padding.top() + _st.font->height + _st.padding.bottom();
|
||||
}
|
||||
|
||||
void LeftOutlineButton::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
bool over = (_state & StateOver), down = (_state & StateDown);
|
||||
if (width() > _st.outlineWidth) {
|
||||
p.fillRect(rtlrect(_st.outlineWidth, 0, width() - _st.outlineWidth, height(), width()), (over || down) ? _st.textBgOver : _st.textBg);
|
||||
paintRipple(p, 0, 0, getms());
|
||||
p.fillRect(rtlrect(0, 0, _st.outlineWidth, height(), width()), (over || down) ? _st.outlineFgOver : _st.outlineFg);
|
||||
}
|
||||
p.setFont(_st.font);
|
||||
p.setPen((over || down) ? _st.textFgOver : _st.textFg);
|
||||
p.drawTextLeft(_st.padding.left(), _st.padding.top(), width(), _text, _textWidth);
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
@ -27,44 +27,6 @@ namespace Ui {
|
||||
|
||||
class RippleAnimation;
|
||||
|
||||
class FlatButton : public AbstractButton {
|
||||
public:
|
||||
FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st);
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void setOpacity(float64 o);
|
||||
float64 opacity() const;
|
||||
|
||||
void setText(const QString &text);
|
||||
void setWidth(int32 w);
|
||||
|
||||
int32 textWidth() const;
|
||||
|
||||
~FlatButton();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
|
||||
private:
|
||||
QImage prepareRippleMask() const;
|
||||
void handleRipples(bool wasDown, bool wasPress);
|
||||
|
||||
QString _text, _textForAutoSize;
|
||||
int _width;
|
||||
|
||||
const style::FlatButton &_st;
|
||||
|
||||
anim::fvalue a_over;
|
||||
Animation _a_appearance;
|
||||
|
||||
float64 _opacity = 1.;
|
||||
|
||||
std_::unique_ptr<RippleAnimation> _ripple;
|
||||
|
||||
};
|
||||
|
||||
class LinkButton : public AbstractButton {
|
||||
public:
|
||||
LinkButton(QWidget *parent, const QString &text, const style::LinkButton &st = st::defaultLinkButton);
|
||||
@ -85,7 +47,73 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class RoundButton : public AbstractButton {
|
||||
class RippleButton : public AbstractButton {
|
||||
public:
|
||||
RippleButton(QWidget *parent, const style::RippleAnimation &st);
|
||||
|
||||
// Displays full ripple circle constantly.
|
||||
enum class SetForceRippledWay {
|
||||
Default,
|
||||
SkipAnimation,
|
||||
};
|
||||
void setForceRippled(bool rippled, SetForceRippledWay way = SetForceRippledWay::Default);
|
||||
bool forceRippled() const {
|
||||
return _forceRippled;
|
||||
}
|
||||
|
||||
~RippleButton();
|
||||
|
||||
protected:
|
||||
void paintRipple(QPainter &p, int x, int y, uint64 ms);
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
|
||||
virtual QImage prepareRippleMask() const;
|
||||
virtual QPoint prepareRippleStartPosition() const;
|
||||
|
||||
private:
|
||||
void ensureRipple();
|
||||
void handleRipples(bool wasDown, bool wasPress);
|
||||
|
||||
const style::RippleAnimation &_st;
|
||||
std_::unique_ptr<RippleAnimation> _ripple;
|
||||
bool _forceRippled = false;
|
||||
|
||||
};
|
||||
|
||||
class FlatButton : public RippleButton {
|
||||
public:
|
||||
FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st);
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
void setText(const QString &text);
|
||||
void setWidth(int32 w);
|
||||
|
||||
int32 textWidth() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
|
||||
private:
|
||||
void setOpacity(float64 o);
|
||||
float64 opacity() const;
|
||||
|
||||
QString _text, _textForAutoSize;
|
||||
int _width;
|
||||
|
||||
const style::FlatButton &_st;
|
||||
|
||||
anim::fvalue a_over;
|
||||
Animation _a_appearance;
|
||||
|
||||
float64 _opacity = 1.;
|
||||
|
||||
};
|
||||
|
||||
class RoundButton : public RippleButton {
|
||||
public:
|
||||
RoundButton(QWidget *parent, const QString &text, const style::RoundButton &st);
|
||||
|
||||
@ -102,17 +130,13 @@ public:
|
||||
};
|
||||
void setTextTransform(TextTransform transform);
|
||||
|
||||
~RoundButton();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
private:
|
||||
QImage prepareRippleMask() const;
|
||||
void handleRipples(bool wasDown, bool wasPress);
|
||||
|
||||
void updateText();
|
||||
void resizeToText();
|
||||
|
||||
@ -128,44 +152,48 @@ private:
|
||||
|
||||
TextTransform _transform = TextTransform::ToUpper;
|
||||
|
||||
std_::unique_ptr<RippleAnimation> _ripple;
|
||||
|
||||
};
|
||||
|
||||
class IconButton : public AbstractButton {
|
||||
class IconButton : public RippleButton {
|
||||
public:
|
||||
IconButton(QWidget *parent, const style::IconButton &st);
|
||||
|
||||
// Pass nullptr to restore the default icon.
|
||||
void setIcon(const style::icon *icon, const style::icon *iconOver = nullptr);
|
||||
|
||||
// Displays full ripple circle constantly.
|
||||
enum class SetStateWay {
|
||||
Default,
|
||||
SkipAnimation,
|
||||
};
|
||||
void setActiveState(bool activeState, SetStateWay way = SetStateWay::Default);
|
||||
|
||||
~IconButton();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
void onStateChanged(int oldState, StateChangeSource source) override;
|
||||
|
||||
private:
|
||||
void ensureRipple();
|
||||
QImage prepareRippleMask() const;
|
||||
void handleRipples(bool wasDown, bool wasPress);
|
||||
QImage prepareRippleMask() const override;
|
||||
QPoint prepareRippleStartPosition() const override;
|
||||
|
||||
private:
|
||||
const style::IconButton &_st;
|
||||
const style::icon *_iconOverride = nullptr;
|
||||
const style::icon *_iconOverrideOver = nullptr;
|
||||
|
||||
FloatAnimation _a_over;
|
||||
|
||||
std_::unique_ptr<RippleAnimation> _ripple;
|
||||
bool _activeState = false;
|
||||
};
|
||||
|
||||
class LeftOutlineButton : public RippleButton {
|
||||
public:
|
||||
LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st = st::defaultLeftOutlineButton);
|
||||
|
||||
void setText(const QString &text);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
QString _text, _fullText;
|
||||
int _textWidth, _fullTextWidth;
|
||||
|
||||
const style::OutlineButton &_st;
|
||||
|
||||
};
|
||||
|
||||
|
@ -58,6 +58,7 @@ void DropdownMenu::init() {
|
||||
_menu->setKeyPressDelegate([this](int key) { return handleKeyPress(key); });
|
||||
_menu->setMouseMoveDelegate([this](QPoint globalPosition) { handleMouseMove(globalPosition); });
|
||||
_menu->setMousePressDelegate([this](QPoint globalPosition) { handleMousePress(globalPosition); });
|
||||
_menu->setMouseReleaseDelegate([this](QPoint globalPosition) { handleMouseRelease(globalPosition); });
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
@ -176,6 +177,14 @@ void DropdownMenu::handleMousePress(QPoint globalPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
void DropdownMenu::handleMouseRelease(QPoint globalPosition) {
|
||||
if (_parent) {
|
||||
_parent->forwardMouseRelease(globalPosition);
|
||||
} else {
|
||||
hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void DropdownMenu::focusOutEvent(QFocusEvent *e) {
|
||||
hideMenu();
|
||||
}
|
||||
|
@ -88,6 +88,10 @@ private:
|
||||
_menu->handleMousePress(globalPosition);
|
||||
}
|
||||
void handleMousePress(QPoint globalPosition);
|
||||
void forwardMouseRelease(QPoint globalPosition) {
|
||||
_menu->handleMouseRelease(globalPosition);
|
||||
}
|
||||
void handleMouseRelease(QPoint globalPosition);
|
||||
|
||||
using SubmenuPointer = QPointer<DropdownMenu>;
|
||||
bool popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source);
|
||||
|
@ -18,6 +18,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "stdafx.h"
|
||||
#include "ui/widgets/menu.h"
|
||||
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
Menu::Menu(QWidget *parent, const style::Menu &st) : TWidget(parent)
|
||||
@ -150,6 +152,7 @@ void Menu::actionChanged() {
|
||||
void Menu::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto ms = getms();
|
||||
auto clip = e->rect();
|
||||
|
||||
auto topskip = QRect(0, 0, width(), _st.skip);
|
||||
@ -172,8 +175,15 @@ void Menu::paintEvent(QPaintEvent *e) {
|
||||
p.fillRect(0, 0, width(), actionHeight, _st.itemBg);
|
||||
p.fillRect(_st.separatorPadding.left(), _st.separatorPadding.top(), width() - _st.separatorPadding.left() - _st.separatorPadding.right(), _st.separatorWidth, _st.separatorFg);
|
||||
} else {
|
||||
auto enabled = action->isEnabled(), selected = (i == _selected && enabled);
|
||||
auto enabled = action->isEnabled();
|
||||
auto selected = ((i == _selected || i == _pressed) && enabled);
|
||||
p.fillRect(0, 0, width(), actionHeight, selected ? _st.itemBgOver : _st.itemBg);
|
||||
if (data.ripple) {
|
||||
data.ripple->paint(p, 0, 0, width(), ms);
|
||||
if (data.ripple->empty()) {
|
||||
data.ripple.reset();
|
||||
}
|
||||
}
|
||||
if (auto icon = (selected ? data.iconOver : data.icon)) {
|
||||
icon->paint(p, _st.itemIconPosition, width());
|
||||
}
|
||||
@ -207,9 +217,29 @@ void Menu::itemPressed(TriggeredSource source) {
|
||||
return;
|
||||
}
|
||||
if (_selected >= 0 && _selected < _actions.size() && _actions[_selected]->isEnabled()) {
|
||||
if (_triggeredCallback) {
|
||||
auto actionTop = _st.skip + itemTop(_selected);
|
||||
_triggeredCallback(_actions[_selected], actionTop, source);
|
||||
_pressed = _selected;
|
||||
if (source == TriggeredSource::Mouse) {
|
||||
if (!_actionsData[_pressed].ripple) {
|
||||
auto mask = RippleAnimation::rectMask(QSize(width(), _itemHeight));
|
||||
_actionsData[_pressed].ripple = MakeShared<RippleAnimation>(_st.ripple, std_::move(mask), [this, selected = _pressed] {
|
||||
updateItem(selected);
|
||||
});
|
||||
}
|
||||
_actionsData[_pressed].ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, itemTop(_pressed)));
|
||||
} else {
|
||||
itemReleased(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::itemReleased(TriggeredSource source) {
|
||||
auto pressed = base::take(_pressed, -1);
|
||||
if (pressed >= 0 && pressed < _actions.size()) {
|
||||
if (source == TriggeredSource::Mouse && _actionsData[pressed].ripple) {
|
||||
_actionsData[pressed].ripple->lastStop();
|
||||
}
|
||||
if (pressed == _selected && _triggeredCallback) {
|
||||
_triggeredCallback(_actions[_selected], itemTop(_selected), source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,9 +320,8 @@ void Menu::setSelected(int selected) {
|
||||
_selected = selected;
|
||||
updateSelectedItem();
|
||||
if (_activatedCallback) {
|
||||
auto actionTop = _st.skip + itemTop(_selected);
|
||||
auto source = _mouseSelection ? TriggeredSource::Mouse : TriggeredSource::Keyboard;
|
||||
_activatedCallback((_selected >= 0) ? _actions[_selected] : nullptr, actionTop, source);
|
||||
_activatedCallback((_selected >= 0) ? _actions[_selected] : nullptr, itemTop(_selected), source);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,19 +330,23 @@ int Menu::itemTop(int index) {
|
||||
if (index > _actions.size()) {
|
||||
index = _actions.size();
|
||||
}
|
||||
int top = 0;
|
||||
int top = _st.skip;
|
||||
for (int i = 0; i < index; ++i) {
|
||||
top += _actions.at(i)->isSeparator() ? _separatorHeight : _itemHeight;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
void Menu::updateSelectedItem() {
|
||||
if (_selected >= 0) {
|
||||
update(0, _st.skip + itemTop(_selected), width(), _actions.at(_selected)->isSeparator() ? _separatorHeight : _itemHeight);
|
||||
void Menu::updateItem(int index) {
|
||||
if (index >= 0 && index < _actions.size()) {
|
||||
update(0, itemTop(index), width(), _actions[index]->isSeparator() ? _separatorHeight : _itemHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::updateSelectedItem() {
|
||||
updateItem(_selected);
|
||||
}
|
||||
|
||||
void Menu::mouseMoveEvent(QMouseEvent *e) {
|
||||
handleMouseMove(e->globalPos());
|
||||
}
|
||||
@ -336,6 +369,10 @@ void Menu::mousePressEvent(QMouseEvent *e) {
|
||||
handleMousePress(e->globalPos());
|
||||
}
|
||||
|
||||
void Menu::mouseReleaseEvent(QMouseEvent *e) {
|
||||
handleMouseRelease(e->globalPos());
|
||||
}
|
||||
|
||||
void Menu::handleMousePress(QPoint globalPosition) {
|
||||
handleMouseMove(globalPosition);
|
||||
if (rect().contains(mapFromGlobal(globalPosition))) {
|
||||
@ -345,4 +382,12 @@ void Menu::handleMousePress(QPoint globalPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::handleMouseRelease(QPoint globalPosition) {
|
||||
handleMouseMove(globalPosition);
|
||||
itemReleased(TriggeredSource::Mouse);
|
||||
if (!rect().contains(mapFromGlobal(globalPosition)) && _mouseReleaseDelegate) {
|
||||
_mouseReleaseDelegate(globalPosition);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
@ -24,6 +24,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class RippleAnimation;
|
||||
|
||||
class Menu : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@ -76,11 +78,17 @@ public:
|
||||
}
|
||||
void handleMousePress(QPoint globalPosition);
|
||||
|
||||
void setMouseReleaseDelegate(base::lambda_unique<void(QPoint globalPosition)> delegate) {
|
||||
_mouseReleaseDelegate = std_::move(delegate);
|
||||
}
|
||||
void handleMouseRelease(QPoint globalPosition);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
|
||||
@ -99,8 +107,10 @@ private:
|
||||
void clearMouseSelection();
|
||||
|
||||
int itemTop(int index);
|
||||
void updateItem(int index);
|
||||
void updateSelectedItem();
|
||||
void itemPressed(TriggeredSource source);
|
||||
void itemReleased(TriggeredSource source);
|
||||
|
||||
const style::Menu &_st;
|
||||
|
||||
@ -110,6 +120,7 @@ private:
|
||||
base::lambda_unique<bool(int key)> _keyPressDelegate;
|
||||
base::lambda_unique<void(QPoint globalPosition)> _mouseMoveDelegate;
|
||||
base::lambda_unique<void(QPoint globalPosition)> _mousePressDelegate;
|
||||
base::lambda_unique<void(QPoint globalPosition)> _mouseReleaseDelegate;
|
||||
|
||||
struct ActionData {
|
||||
bool hasSubmenu = false;
|
||||
@ -117,6 +128,7 @@ private:
|
||||
QString shortcut;
|
||||
const style::icon *icon = nullptr;
|
||||
const style::icon *iconOver = nullptr;
|
||||
QSharedPointer<RippleAnimation> ripple;
|
||||
};
|
||||
using ActionsData = QList<ActionData>;
|
||||
|
||||
@ -129,6 +141,7 @@ private:
|
||||
bool _mouseSelection = false;
|
||||
|
||||
int _selected = -1;
|
||||
int _pressed = -1;
|
||||
bool _childShown = false;
|
||||
|
||||
};
|
||||
|
@ -55,6 +55,7 @@ void PopupMenu::init() {
|
||||
_menu->setKeyPressDelegate([this](int key) { return handleKeyPress(key); });
|
||||
_menu->setMouseMoveDelegate([this](QPoint globalPosition) { handleMouseMove(globalPosition); });
|
||||
_menu->setMousePressDelegate([this](QPoint globalPosition) { handleMousePress(globalPosition); });
|
||||
_menu->setMouseReleaseDelegate([this](QPoint globalPosition) { handleMouseRelease(globalPosition); });
|
||||
|
||||
handleCompositingUpdate();
|
||||
|
||||
@ -224,6 +225,14 @@ void PopupMenu::handleMousePress(QPoint globalPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
void PopupMenu::handleMouseRelease(QPoint globalPosition) {
|
||||
if (_parent) {
|
||||
_parent->forwardMouseRelease(globalPosition);
|
||||
} else {
|
||||
hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void PopupMenu::focusOutEvent(QFocusEvent *e) {
|
||||
hideMenu();
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ private:
|
||||
_menu->handleMousePress(globalPosition);
|
||||
}
|
||||
void handleMousePress(QPoint globalPosition);
|
||||
void forwardMouseRelease(QPoint globalPosition) {
|
||||
_menu->handleMouseRelease(globalPosition);
|
||||
}
|
||||
void handleMouseRelease(QPoint globalPosition);
|
||||
|
||||
using SubmenuPointer = QPointer<PopupMenu>;
|
||||
bool popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source);
|
||||
|
@ -61,8 +61,6 @@ FlatButton {
|
||||
height: pixels;
|
||||
|
||||
textTop: pixels;
|
||||
overTextTop: pixels;
|
||||
downTextTop: pixels;
|
||||
|
||||
font: font;
|
||||
overFont: font;
|
||||
@ -87,7 +85,6 @@ RoundButton {
|
||||
padding: margins;
|
||||
|
||||
textTop: pixels;
|
||||
downTextTop: pixels;
|
||||
|
||||
icon: icon;
|
||||
|
||||
@ -272,6 +269,8 @@ OutlineButton {
|
||||
|
||||
font: font;
|
||||
padding: margins;
|
||||
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
||||
IconButton {
|
||||
@ -280,9 +279,7 @@ IconButton {
|
||||
|
||||
icon: icon;
|
||||
iconOver: icon;
|
||||
|
||||
iconPosition: point;
|
||||
iconPositionDown: point;
|
||||
|
||||
duration: int;
|
||||
|
||||
@ -394,6 +391,8 @@ Menu {
|
||||
|
||||
widthMin: pixels;
|
||||
widthMax: pixels;
|
||||
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
||||
PanelAnimation {
|
||||
@ -487,7 +486,6 @@ defaultActiveButton: RoundButton {
|
||||
padding: margins(0px, 0px, 0px, 0px);
|
||||
|
||||
textTop: 8px;
|
||||
downTextTop: 8px;
|
||||
|
||||
font: semiboldFont;
|
||||
|
||||
@ -589,14 +587,22 @@ defaultLeftOutlineButton: OutlineButton {
|
||||
|
||||
font: normalFont;
|
||||
padding: margins(11px, 5px, 11px, 5px);
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: lightButtonBgRipple;
|
||||
}
|
||||
}
|
||||
attentionLeftOutlineButton: OutlineButton(defaultLeftOutlineButton) {
|
||||
outlineFgOver: attentionBoxButtonFg;
|
||||
outlineFgOver: attentionButtonFg;
|
||||
|
||||
textBgOver: attentionBoxButtonBgOver;
|
||||
textBgOver: attentionButtonBgOver;
|
||||
|
||||
textFg: attentionBoxButtonFg;
|
||||
textFgOver: attentionBoxButtonFg;
|
||||
textFg: attentionButtonFg;
|
||||
textFgOver: attentionButtonFg;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: attentionButtonBgRipple;
|
||||
}
|
||||
}
|
||||
|
||||
defaultInputArea: InputArea {
|
||||
@ -697,7 +703,6 @@ defaultRadiobutton: Radiobutton {
|
||||
|
||||
defaultIconButton: IconButton {
|
||||
iconPosition: point(-1px, -1px);
|
||||
iconPositionDown: point(-1px, -1px);
|
||||
}
|
||||
|
||||
widgetSlideDuration: 200;
|
||||
@ -756,8 +761,8 @@ defaultMenu: Menu {
|
||||
itemFg: windowFg;
|
||||
itemFgOver: windowFgOver;
|
||||
itemFgDisabled: #cccccc;
|
||||
itemFgShortcut: #999999;
|
||||
itemFgShortcutOver: #7c99b2;
|
||||
itemFgShortcut: windowSubTextFg;
|
||||
itemFgShortcutOver: windowSubTextFgOver;
|
||||
itemFgShortcutDisabled: #cccccc;
|
||||
itemIconPosition: point(0px, 0px);
|
||||
itemPadding: margins(17px, 8px, 17px, 7px);
|
||||
@ -771,6 +776,8 @@ defaultMenu: Menu {
|
||||
|
||||
widthMin: 180px;
|
||||
widthMax: 300px;
|
||||
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
defaultPopupMenu: PopupMenu {
|
||||
shadow: defaultRoundShadow;
|
||||
@ -801,18 +808,42 @@ defaultDropdownMenu: DropdownMenu {
|
||||
menu: defaultMenu;
|
||||
}
|
||||
|
||||
historyToDown: icon {
|
||||
historyToDownBelow: icon {
|
||||
{ "history_down_shadow", #00000040 },
|
||||
{ "history_down_circle", #ffffff, point(4px, 4px) },
|
||||
{ "history_down_circle", windowBg, point(4px, 4px) },
|
||||
};
|
||||
historyToDownBelowOver: icon {
|
||||
{ "history_down_shadow", #00000040 },
|
||||
{ "history_down_circle", windowBgOver, point(4px, 4px) },
|
||||
};
|
||||
contactsAddIconBelow: icon {
|
||||
{ "history_down_shadow", #00000040 },
|
||||
{ "history_down_circle", activeButtonBg, point(4px, 4px) },
|
||||
};
|
||||
contactsAddIconBelowOver: icon {
|
||||
{ "history_down_shadow", #00000040 },
|
||||
{ "history_down_circle", activeButtonBgOver, point(4px, 4px) },
|
||||
};
|
||||
|
||||
contactsAddIcon: icon {
|
||||
{ "history_down_shadow", #00000020 },
|
||||
{ "history_down_circle", activeButtonBg, point(4px, 4px) },
|
||||
{ "contacts_add", activeButtonFg, point(18px, 18px) },
|
||||
};
|
||||
contactsAddIconOver: icon {
|
||||
{ "history_down_shadow", #00000020 },
|
||||
{ "history_down_circle", activeButtonBgOver, point(4px, 4px) },
|
||||
{ "contacts_add", activeButtonFg, point(18px, 18px) },
|
||||
};
|
||||
BotKeyboardButton {
|
||||
margin: pixels;
|
||||
padding: pixels;
|
||||
height: pixels;
|
||||
textTop: pixels;
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
||||
TwoIconButton {
|
||||
width: pixels;
|
||||
height: pixels;
|
||||
|
||||
iconBelow: icon;
|
||||
iconAbove: icon;
|
||||
iconBelowOver: icon;
|
||||
iconAboveOver: icon;
|
||||
iconPosition: point;
|
||||
|
||||
rippleAreaPosition: point;
|
||||
rippleAreaSize: pixels;
|
||||
ripple: RippleAnimation;
|
||||
}
|
||||
|
@ -56,10 +56,10 @@ TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w)
|
||||
subscribe(w->searchInPeerChanged(), [this](PeerData *peer) {
|
||||
_searchInPeer = peer;
|
||||
auto historyPeer = App::main() ? App::main()->historyPeer() : nullptr;
|
||||
_search->setActiveState(historyPeer && historyPeer == _searchInPeer);
|
||||
_search->setForceRippled(historyPeer && historyPeer == _searchInPeer);
|
||||
});
|
||||
subscribe(w->historyPeerChanged(), [this](PeerData *peer) {
|
||||
_search->setActiveState(peer && peer == _searchInPeer, Ui::IconButton::SetStateWay::SkipAnimation);
|
||||
_search->setForceRippled(peer && peer == _searchInPeer, Ui::IconButton::SetForceRippledWay::SkipAnimation);
|
||||
update();
|
||||
});
|
||||
|
||||
@ -115,17 +115,17 @@ void TopBarWidget::showMenu() {
|
||||
data->menu->deleteLater();
|
||||
if (data->that && _menu == data->menu) {
|
||||
_menu = nullptr;
|
||||
_menuToggle->setActiveState(false);
|
||||
_menuToggle->setForceRippled(false);
|
||||
}
|
||||
});
|
||||
_menu->setShowStartCallback([this, data] {
|
||||
if (data->that && _menu == data->menu) {
|
||||
_menuToggle->setActiveState(true);
|
||||
_menuToggle->setForceRippled(true);
|
||||
}
|
||||
});
|
||||
_menu->setHideStartCallback([this, data] {
|
||||
if (data->that && _menu == data->menu) {
|
||||
_menuToggle->setActiveState(false);
|
||||
_menuToggle->setForceRippled(false);
|
||||
}
|
||||
});
|
||||
_menuToggle->installEventFilter(_menu);
|
||||
|
@ -47,7 +47,6 @@ notifyClose: IconButton {
|
||||
iconOver: simpleCloseIconOver;
|
||||
|
||||
iconPosition: point(10px, 10px);
|
||||
iconPositionDown: point(10px, 11px);
|
||||
}
|
||||
notifyItemTop: 12px;
|
||||
notifyTextLeft: 12px;
|
||||
@ -77,7 +76,6 @@ notifySendReply: IconButton {
|
||||
|
||||
icon: icon {{ "notification_send", lightButtonFg, point(3px, 9px) }};
|
||||
iconPosition: point(0px, 0px);
|
||||
iconPositionDown: point(0px, 1px);
|
||||
}
|
||||
|
||||
titleUnreadCounterTop: 5px;
|
||||
@ -96,6 +94,8 @@ mainMenuCoverNameTop: 88px;
|
||||
mainMenuCoverStatusTop: 106px;
|
||||
mainMenuSkip: 13px;
|
||||
mainMenu: Menu(defaultMenu) {
|
||||
itemFg: windowBoldFg;
|
||||
itemFgOver: windowBoldFgOver;
|
||||
itemFont: semiboldFont;
|
||||
itemIconPosition: point(28px, 11px);
|
||||
itemPadding: margins(76px, 14px, 28px, 14px);
|
||||
@ -144,9 +144,7 @@ titleButtonMinimize: IconButton {
|
||||
{ size(24px, 21px), titleButtonBgOver },
|
||||
{ "title_button_minimize", titleButtonFgOver, point(4px, 4px) },
|
||||
};
|
||||
|
||||
iconPosition: point(0px, 0px);
|
||||
iconPositionDown: point(0px, 0px);
|
||||
}
|
||||
titleButtonMaximize: IconButton(titleButtonMinimize) {
|
||||
icon: icon {{ "title_button_maximize", titleButtonFg, point(4px, 4px) }};
|
||||
@ -195,7 +193,6 @@ topBarButton: RoundButton {
|
||||
padding: margins(0px, 14px, 12px, 12px);
|
||||
|
||||
textTop: 6px;
|
||||
downTextTop: 6px;
|
||||
|
||||
font: font(fsize);
|
||||
|
||||
@ -212,9 +209,7 @@ topBarSearch: IconButton {
|
||||
|
||||
icon: icon {{ "title_search", menuIconFg }};
|
||||
iconOver: icon {{ "title_search", menuIconFgOver }};
|
||||
|
||||
iconPosition: point(15px, 18px);
|
||||
iconPositionDown: point(15px, 18px);
|
||||
|
||||
rippleAreaPosition: point(4px, 7px);
|
||||
rippleAreaSize: 40px;
|
||||
@ -225,9 +220,7 @@ topBarSearch: IconButton {
|
||||
topBarMenuToggle: IconButton(topBarSearch) {
|
||||
icon: icon {{ "title_menu_dots", menuIconFg }};
|
||||
iconOver: icon {{ "title_menu_dots", menuIconFgOver }};
|
||||
|
||||
iconPosition: point(16px, 17px);
|
||||
iconPositionDown: point(16px, 17px);
|
||||
|
||||
rippleAreaPosition: point(0px, 7px);
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ void MainMenu::checkSelf() {
|
||||
_userpicButton->setClickedCallback([] {
|
||||
App::wnd()->showSettings();
|
||||
});
|
||||
_userpicButton->show();
|
||||
updateControlsGeometry();
|
||||
if (_showFinished) {
|
||||
_userpicButton->showFinished();
|
||||
|
@ -3,4 +3,4 @@ AppVersionStrMajor 0.10
|
||||
AppVersionStrSmall 0.10.20
|
||||
AppVersionStr 0.10.20
|
||||
AlphaChannel 0
|
||||
BetaVersion 10019007
|
||||
BetaVersion 10019008
|
||||
|
@ -452,8 +452,6 @@
|
||||
'<(src_loc)/stickers/stickers.h',
|
||||
'<(src_loc)/ui/buttons/history_down_button.cpp',
|
||||
'<(src_loc)/ui/buttons/history_down_button.h',
|
||||
'<(src_loc)/ui/buttons/left_outline_button.cpp',
|
||||
'<(src_loc)/ui/buttons/left_outline_button.h',
|
||||
'<(src_loc)/ui/buttons/peer_avatar_button.cpp',
|
||||
'<(src_loc)/ui/buttons/peer_avatar_button.h',
|
||||
'<(src_loc)/ui/effects/panel_animation.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user