2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Closed beta 10020005: Added several buttons animations.

This commit is contained in:
John Preston
2016-12-27 02:46:36 +04:00
parent ef927c8465
commit 38e6a0ae7e
19 changed files with 445 additions and 227 deletions

View File

@@ -54,6 +54,13 @@ public:
_clickedCallback = std_::move(callback);
}
void setVisible(bool visible) override {
TWidget::setVisible(visible);
if (!visible) {
clearState();
}
}
protected:
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;

View File

@@ -26,6 +26,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/effects/ripple_animation.h"
namespace Ui {
namespace {
constexpr int kWideScale = 5;
} // namespace
HistoryDownButton::HistoryDownButton(QWidget *parent, const style::TwoIconButton &st) : RippleButton(parent, st.ripple)
, _st(st) {
@@ -141,4 +146,147 @@ QImage EmojiButton::prepareRippleMask() const {
return RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
}
SendButton::SendButton(QWidget *parent) : RippleButton(parent, st::historyReplyCancel.ripple) {
resize(st::historySendSize);
}
void SendButton::setType(Type type) {
if (_type != type) {
_contentFrom = grabContent();
_type = type;
_a_typeChanged.finish();
_contentTo = grabContent();
_a_typeChanged.start([this] { update(); }, 0., 1., st::historyRecordVoiceDuration);
update();
}
if (_type != Type::Record) {
_recordActive = false;
_a_recordActive.finish();
}
}
void SendButton::setRecordActive(bool recordActive) {
if (_recordActive != recordActive) {
_recordActive = recordActive;
_a_recordActive.start([this] { recordAnimationCallback(); }, _recordActive ? 0. : 1., _recordActive ? 1. : 0, st::historyRecordVoiceDuration);
update();
}
}
void SendButton::finishAnimation() {
_a_typeChanged.finish();
_a_recordActive.finish();
update();
}
void SendButton::mouseMoveEvent(QMouseEvent *e) {
AbstractButton::mouseMoveEvent(e);
if (_recording) {
if (_recordUpdateCallback) {
_recordUpdateCallback(e->globalPos());
}
}
}
void SendButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = getms();
auto over = (isDown() || isOver());
auto changed = _a_typeChanged.current(ms, 1.);
if (changed < 1.) {
PainterHighQualityEnabler hq(p);
p.setOpacity(1. - changed);
auto targetRect = QRect((1 - kWideScale) / 2 * width(), (1 - kWideScale) / 2 * height(), kWideScale * width(), kWideScale * height());
auto hiddenWidth = anim::interpolate(0, (1 - kWideScale) / 2 * width(), changed);
auto hiddenHeight = anim::interpolate(0, (1 - kWideScale) / 2 * height(), changed);
p.drawPixmap(targetRect.marginsAdded(QMargins(hiddenWidth, hiddenHeight, hiddenWidth, hiddenHeight)), _contentFrom);
p.setOpacity(changed);
auto shownWidth = anim::interpolate((1 - kWideScale) / 2 * width(), 0, changed);
auto shownHeight = anim::interpolate((1 - kWideScale) / 2 * height(), 0, changed);
p.drawPixmap(targetRect.marginsAdded(QMargins(shownWidth, shownHeight, shownWidth, shownHeight)), _contentTo);
} else if (_type == Type::Record) {
auto recordActive = recordActiveRatio();
auto rippleColor = anim::color(st::historyAttachEmoji.ripple.color, st::historyRecordVoiceRippleBgActive, recordActive);
paintRipple(p, (width() - st::historyAttachEmoji.rippleAreaSize) / 2, st::historyAttachEmoji.rippleAreaPosition.y(), ms, &rippleColor);
auto fastIcon = [recordActive, over, this] {
if (recordActive == 1.) {
return &st::historyRecordVoiceActive;
} else if (over) {
return &st::historyRecordVoiceOver;
}
return &st::historyRecordVoice;
};
fastIcon()->paintInCenter(p, rect());
if (recordActive > 0. && recordActive < 1.) {
p.setOpacity(recordActive);
st::historyRecordVoiceActive.paintInCenter(p, rect());
p.setOpacity(1.);
}
} else if (_type == Type::Save) {
auto &saveIcon = over ? st::historyEditSaveIconOver : st::historyEditSaveIcon;
saveIcon.paint(p, st::historySendIconPosition, width());
} else if (_type == Type::Cancel) {
paintRipple(p, (width() - st::historyAttachEmoji.rippleAreaSize) / 2, st::historyAttachEmoji.rippleAreaPosition.y(), ms);
auto &cancelIcon = over ? st::historyReplyCancelIconOver : st::historyReplyCancelIcon;
cancelIcon.paintInCenter(p, rect());
} else {
auto &sendIcon = over ? st::historySendIconOver : st::historySendIcon;
sendIcon.paint(p, st::historySendIconPosition, width());
}
}
void SendButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
auto down = (state() & StateFlag::Down);
if ((was & StateFlag::Down) != down) {
if (down) {
if (_type == Type::Record) {
_recording = true;
if (_recordStartCallback) {
_recordStartCallback();
}
}
} else if (_recording) {
_recording = false;
if (_recordStopCallback) {
_recordStopCallback(_recordActive);
}
}
}
}
QPixmap SendButton::grabContent() {
auto result = QImage(kWideScale * size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(cRetinaFactor());
result.fill(Qt::transparent);
{
Painter p(&result);
p.drawPixmap((kWideScale - 1) / 2 * width(), (kWideScale - 1) / 2 * height(), myGrab(this));
}
return App::pixmapFromImageInPlace(std_::move(result));
}
QImage SendButton::prepareRippleMask() const {
auto size = (_type == Type::Record) ? st::historyAttachEmoji.rippleAreaSize : st::historyReplyCancel.rippleAreaSize;
return Ui::RippleAnimation::ellipseMask(QSize(size, size));
}
QPoint SendButton::prepareRippleStartPosition() const {
auto real = mapFromGlobal(QCursor::pos());
auto size = (_type == Type::Record) ? st::historyAttachEmoji.rippleAreaSize : st::historyReplyCancel.rippleAreaSize;
auto y = (_type == Type::Record) ? st::historyAttachEmoji.rippleAreaPosition.y() : (height() - st::historyReplyCancel.rippleAreaSize) / 2;
return real - QPoint((width() - size) / 2, y);
}
void SendButton::recordAnimationCallback() {
update();
if (_recordAnimationCallback) {
_recordAnimationCallback();
}
}
} // namespace Ui

View File

@@ -75,4 +75,65 @@ private:
};
class SendButton : public RippleButton {
public:
SendButton(QWidget *parent);
enum class Type {
Send,
Save,
Record,
Cancel,
};
Type type() const {
return _type;
}
void setType(Type state);
void setRecordActive(bool recordActive);
void finishAnimation();
void setRecordStartCallback(base::lambda<void()> &&callback) {
_recordStartCallback = std_::move(callback);
}
void setRecordUpdateCallback(base::lambda<void(QPoint globalPos)> &&callback) {
_recordUpdateCallback = std_::move(callback);
}
void setRecordStopCallback(base::lambda<void(bool active)> &&callback) {
_recordStopCallback = std_::move(callback);
}
void setRecordAnimationCallback(base::lambda<void()> &&callback) {
_recordAnimationCallback = std_::move(callback);
}
float64 recordActiveRatio() {
return _a_recordActive.current(getms(), _recordActive ? 1. : 0.);
}
protected:
void mouseMoveEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void onStateChanged(State was, StateChangeSource source) override;
QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override;
private:
void recordAnimationCallback();
QPixmap grabContent();
Type _type = Type::Send;
bool _recordActive = false;
QPixmap _contentFrom, _contentTo;
Animation _a_typeChanged;
Animation _a_recordActive;
bool _recording = false;
base::lambda<void()> _recordStartCallback;
base::lambda<void(bool active)> _recordStopCallback;
base::lambda<void(QPoint globalPos)> _recordUpdateCallback;
base::lambda<void()> _recordAnimationCallback;
};
} // namespace Ui

View File

@@ -131,6 +131,10 @@ QPoint RippleButton::prepareRippleStartPosition() const {
return mapFromGlobal(QCursor::pos());
}
void RippleButton::resetRipples() {
_ripple.reset();
}
RippleButton::~RippleButton() = default;
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::FlatButton &st) : RippleButton(parent, st.ripple)
@@ -189,7 +193,6 @@ void FlatButton::paintEvent(QPaintEvent *e) {
RoundButton::RoundButton(QWidget *parent, const QString &text, const style::RoundButton &st) : RippleButton(parent, st.ripple)
, _fullText(text)
, _st(st) {
setCursor(style::cur_pointer);
updateText();
}
@@ -308,7 +311,6 @@ QPoint RoundButton::prepareRippleStartPosition() const {
IconButton::IconButton(QWidget *parent, const style::IconButton &st) : RippleButton(parent, st.ripple)
, _st(st) {
resize(_st.width, _st.height);
setCursor(style::cur_pointer);
}
void IconButton::setIconOverride(const style::icon *iconOverride, const style::icon *iconOverOverride) {

View File

@@ -75,6 +75,7 @@ protected:
QPoint disabledRippleStartPosition() const {
return QPoint(-0x3FFFFFFF, -0x3FFFFFFF);
}
void resetRipples();
private:
void ensureRipple();