tdesktop/Telegram/SourceFiles/ui/controls/send_button.cpp

266 lines
7.3 KiB
C++
Raw Normal View History

2020-10-13 10:00:35 +00:00
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/controls/send_button.h"
#include "ui/effects/ripple_animation.h"
#include "styles/style_chat.h"
namespace Ui {
namespace {
constexpr int kWideScale = 5;
} // namespace
SendButton::SendButton(QWidget *parent)
: RippleButton(parent, st::historyReplyCancel.ripple) {
resize(st::historySendSize);
}
void SendButton::setType(Type type) {
Expects(isSlowmode() || type != Type::Slowmode);
if (isSlowmode() && type != Type::Slowmode) {
_afterSlowmodeType = type;
return;
}
if (_type != type) {
_contentFrom = grabContent();
_type = type;
_a_typeChanged.stop();
_contentTo = grabContent();
_a_typeChanged.start(
[=] { update(); },
0.,
1.,
st::historyRecordVoiceDuration);
setPointerCursor(_type != Type::Slowmode);
update();
}
if (_type != Type::Record) {
_recordActive = false;
_a_recordActive.stop();
}
}
void SendButton::setRecordActive(bool recordActive) {
if (_recordActive != recordActive) {
_recordActive = recordActive;
_a_recordActive.start(
[=] { recordAnimationCallback(); },
_recordActive ? 0. : 1.,
_recordActive ? 1. : 0,
st::historyRecordVoiceDuration);
update();
}
}
void SendButton::setSlowmodeDelay(int seconds) {
Expects(seconds >= 0 && seconds < kSlowmodeDelayLimit);
if (_slowmodeDelay == seconds) {
return;
}
_slowmodeDelay = seconds;
_slowmodeDelayText = isSlowmode()
? u"%1:%2"_q.arg(seconds / 60).arg(seconds % 60, 2, 10, QChar('0'))
: QString();
setType(isSlowmode() ? Type::Slowmode : _afterSlowmodeType);
update();
}
void SendButton::finishAnimating() {
_a_typeChanged.stop();
_a_recordActive.stop();
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 over = (isDown() || isOver());
auto changed = _a_typeChanged.value(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);
return;
}
switch (_type) {
case Type::Record: paintRecord(p, over); break;
case Type::Save: paintSave(p, over); break;
case Type::Cancel: paintCancel(p, over); break;
case Type::Send: paintSend(p, over); break;
case Type::Schedule: paintSchedule(p, over); break;
case Type::Slowmode: paintSlowmode(p); break;
}
}
void SendButton::paintRecord(Painter &p, bool over) {
auto recordActive = recordActiveRatio();
if (!isDisabled()) {
auto rippleColor = anim::color(st::historyAttachEmoji.ripple.color, st::historyRecordVoiceRippleBgActive, recordActive);
paintRipple(p, (width() - st::historyAttachEmoji.rippleAreaSize) / 2, st::historyAttachEmoji.rippleAreaPosition.y(), &rippleColor);
}
auto fastIcon = [&] {
if (isDisabled()) {
return &st::historyRecordVoice;
} else if (recordActive == 1.) {
return &st::historyRecordVoiceActive;
} else if (over) {
return &st::historyRecordVoiceOver;
}
return &st::historyRecordVoice;
};
fastIcon()->paintInCenter(p, rect());
if (!isDisabled() && recordActive > 0. && recordActive < 1.) {
p.setOpacity(recordActive);
st::historyRecordVoiceActive.paintInCenter(p, rect());
p.setOpacity(1.);
}
}
void SendButton::paintSave(Painter &p, bool over) {
const auto &saveIcon = over
? st::historyEditSaveIconOver
: st::historyEditSaveIcon;
saveIcon.paint(p, st::historySendIconPosition, width());
}
void SendButton::paintCancel(Painter &p, bool over) {
paintRipple(p, (width() - st::historyAttachEmoji.rippleAreaSize) / 2, st::historyAttachEmoji.rippleAreaPosition.y());
const auto &cancelIcon = over
? st::historyReplyCancelIconOver
: st::historyReplyCancelIcon;
cancelIcon.paintInCenter(p, rect());
}
void SendButton::paintSend(Painter &p, bool over) {
const auto &sendIcon = over
? st::historySendIconOver
: st::historySendIcon;
if (isDisabled()) {
const auto color = st::historyRecordVoiceFg->c;
sendIcon.paint(p, st::historySendIconPosition, width(), color);
} else {
sendIcon.paint(p, st::historySendIconPosition, width());
}
}
void SendButton::paintSchedule(Painter &p, bool over) {
{
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(over ? st::historySendIconFgOver : st::historySendIconFg);
p.drawEllipse(
st::historyScheduleIconPosition.x(),
st::historyScheduleIconPosition.y(),
st::historyScheduleIcon.width(),
st::historyScheduleIcon.height());
}
st::historyScheduleIcon.paint(
p,
st::historyScheduleIconPosition,
width());
}
void SendButton::paintSlowmode(Painter &p) {
p.setFont(st::normalFont);
p.setPen(st::windowSubTextFg);
p.drawText(
rect().marginsRemoved(st::historySlowmodeCounterMargins),
_slowmodeDelayText,
style::al_center);
}
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);
}
}
}
}
bool SendButton::isSlowmode() const {
return (_slowmodeDelay > 0);
}
QPixmap SendButton::grabContent() {
auto result = QImage(
kWideScale * size() * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(style::DevicePixelRatio());
result.fill(Qt::transparent);
{
Painter p(&result);
p.drawPixmap(
(kWideScale - 1) / 2 * width(),
(kWideScale - 1) / 2 * height(),
GrabWidget(this));
}
return Ui::PixmapFromImage(std::move(result));
}
QImage SendButton::prepareRippleMask() const {
auto size = (_type == Type::Record)
? st::historyAttachEmoji.rippleAreaSize
: st::historyReplyCancel.rippleAreaSize;
return 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