Add customized rounded ripple mask generators.
This commit is contained in:
parent
2c2a7887e6
commit
89ae115a87
7 changed files with 120 additions and 37 deletions
|
|
@ -18,7 +18,7 @@ namespace {
|
|||
const auto s = QSize(
|
||||
st::boxRadius * 2 + st.extend.left(),
|
||||
st::boxRadius * 2 + st.extend.right());
|
||||
const auto mask = Ui::RippleAnimation::maskByDrawer(s, false, [&](
|
||||
const auto mask = Ui::RippleAnimation::MaskByDrawer(s, false, [&](
|
||||
QPainter &p) {
|
||||
p.drawRoundedRect(QRect(QPoint(), s), st::boxRadius, st::boxRadius);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,15 +9,27 @@
|
|||
#include "ui/effects/animations.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/image/image_prepare.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class RippleAnimation::Ripple {
|
||||
public:
|
||||
Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn<void()> update);
|
||||
Ripple(const style::RippleAnimation &st, const QPixmap &mask, Fn<void()> update);
|
||||
Ripple(
|
||||
const style::RippleAnimation &st,
|
||||
QPoint origin,
|
||||
int startRadius,
|
||||
const QPixmap &mask,
|
||||
Fn<void()> update);
|
||||
Ripple(
|
||||
const style::RippleAnimation &st,
|
||||
const QPixmap &mask,
|
||||
Fn<void()> update);
|
||||
|
||||
void paint(QPainter &p, const QPixmap &mask, const QColor *colorOverride);
|
||||
void paint(
|
||||
QPainter &p,
|
||||
const QPixmap &mask,
|
||||
const QColor *colorOverride);
|
||||
|
||||
void stop();
|
||||
void unstop();
|
||||
|
|
@ -43,7 +55,12 @@ private:
|
|||
|
||||
};
|
||||
|
||||
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn<void()> update)
|
||||
RippleAnimation::Ripple::Ripple(
|
||||
const style::RippleAnimation &st,
|
||||
QPoint origin,
|
||||
int startRadius,
|
||||
const QPixmap &mask,
|
||||
Fn<void()> update)
|
||||
: _st(st)
|
||||
, _update(update)
|
||||
, _origin(origin)
|
||||
|
|
@ -59,7 +76,9 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin,
|
|||
{ 0, _frame.height() / pixelRatio },
|
||||
};
|
||||
for (auto point : points) {
|
||||
accumulate_max(_radiusTo, style::point::dotProduct(_origin - point, _origin - point));
|
||||
accumulate_max(
|
||||
_radiusTo,
|
||||
style::point::dotProduct(_origin - point, _origin - point));
|
||||
}
|
||||
_radiusTo = qRound(sqrt(_radiusTo));
|
||||
|
||||
|
|
@ -79,7 +98,10 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap
|
|||
_hide.start(_update, 0., 1., _st.hideDuration);
|
||||
}
|
||||
|
||||
void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QColor *colorOverride) {
|
||||
void RippleAnimation::Ripple::paint(
|
||||
QPainter &p,
|
||||
const QPixmap &mask,
|
||||
const QColor *colorOverride) {
|
||||
auto opacity = _hide.value(_hiding ? 0. : 1.);
|
||||
if (opacity == 0.) {
|
||||
return;
|
||||
|
|
@ -92,9 +114,11 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, const QCol
|
|||
Assert(!std::isnan(diff));
|
||||
const auto mult = diff * shown;
|
||||
Assert(!std::isnan(mult));
|
||||
const auto interpolated = _radiusFrom + mult;//anim::interpolateF(_radiusFrom, _radiusTo, shown);
|
||||
const auto interpolated = _radiusFrom + mult;
|
||||
//anim::interpolateF(_radiusFrom, _radiusTo, shown);
|
||||
Assert(!std::isnan(interpolated));
|
||||
auto radius = int(base::SafeRound(interpolated));//anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.));
|
||||
auto radius = int(base::SafeRound(interpolated));
|
||||
//anim::interpolate(_radiusFrom, _radiusTo, _show.value(1.));
|
||||
_frame.fill(Qt::transparent);
|
||||
{
|
||||
QPainter p(&_frame);
|
||||
|
|
@ -151,7 +175,10 @@ void RippleAnimation::Ripple::clearCache() {
|
|||
_cache = QPixmap();
|
||||
}
|
||||
|
||||
RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn<void()> callback)
|
||||
RippleAnimation::RippleAnimation(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
Fn<void()> callback)
|
||||
: _st(st)
|
||||
, _mask(PixmapFromImage(std::move(mask)))
|
||||
, _update(callback) {
|
||||
|
|
@ -160,7 +187,8 @@ RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask,
|
|||
|
||||
void RippleAnimation::add(QPoint origin, int startRadius) {
|
||||
lastStop();
|
||||
_ripples.push_back(std::make_unique<Ripple>(_st, origin, startRadius, _mask, _update));
|
||||
_ripples.push_back(
|
||||
std::make_unique<Ripple>(_st, origin, startRadius, _mask, _update));
|
||||
}
|
||||
|
||||
void RippleAnimation::addFading() {
|
||||
|
|
@ -195,7 +223,12 @@ void RippleAnimation::forceRepaint() {
|
|||
}
|
||||
}
|
||||
|
||||
void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, const QColor *colorOverride) {
|
||||
void RippleAnimation::paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth,
|
||||
const QColor *colorOverride) {
|
||||
if (_ripples.empty()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -211,8 +244,13 @@ void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, const QCo
|
|||
clearFinished();
|
||||
}
|
||||
|
||||
QImage RippleAnimation::maskByDrawer(QSize size, bool filled, Fn<void(QPainter &p)> drawer) {
|
||||
auto result = QImage(size * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied);
|
||||
QImage RippleAnimation::MaskByDrawer(
|
||||
QSize size,
|
||||
bool filled,
|
||||
Fn<void(QPainter &p)> drawer) {
|
||||
auto result = QImage(
|
||||
size * style::DevicePixelRatio(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
result.fill(filled ? QColor(255, 255, 255) : Qt::transparent);
|
||||
if (drawer) {
|
||||
|
|
@ -226,18 +264,46 @@ QImage RippleAnimation::maskByDrawer(QSize size, bool filled, Fn<void(QPainter &
|
|||
return result;
|
||||
}
|
||||
|
||||
QImage RippleAnimation::rectMask(QSize size) {
|
||||
return maskByDrawer(size, true, Fn<void(QPainter&)>());
|
||||
QImage RippleAnimation::RectMask(QSize size) {
|
||||
return MaskByDrawer(size, true, nullptr);
|
||||
}
|
||||
|
||||
QImage RippleAnimation::roundRectMask(QSize size, int radius) {
|
||||
return maskByDrawer(size, false, [size, radius](QPainter &p) {
|
||||
QImage RippleAnimation::RoundRectMask(QSize size, int radius) {
|
||||
return MaskByDrawer(size, false, [&](QPainter &p) {
|
||||
p.drawRoundedRect(0, 0, size.width(), size.height(), radius, radius);
|
||||
});
|
||||
}
|
||||
|
||||
QImage RippleAnimation::ellipseMask(QSize size) {
|
||||
return maskByDrawer(size, false, [size](QPainter &p) {
|
||||
QImage RippleAnimation::RoundRectMask(
|
||||
QSize size,
|
||||
Images::CornersMaskRef corners) {
|
||||
return MaskByDrawer(size, true, [&](QPainter &p) {
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto corner = [&](int index, bool right, bool bottom) {
|
||||
if (const auto image = corners.p[index]) {
|
||||
if (!image->isNull()) {
|
||||
const auto width = image->width() / ratio;
|
||||
const auto height = image->height() / ratio;
|
||||
p.drawImage(
|
||||
QRect(
|
||||
right ? (size.width() - width) : 0,
|
||||
bottom ? (size.height() - height) : 0,
|
||||
width,
|
||||
height),
|
||||
*image);
|
||||
}
|
||||
}
|
||||
};
|
||||
corner(0, false, false);
|
||||
corner(1, true, false);
|
||||
corner(2, false, true);
|
||||
corner(3, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
QImage RippleAnimation::EllipseMask(QSize size) {
|
||||
return MaskByDrawer(size, false, [&](QPainter &p) {
|
||||
p.drawEllipse(0, 0, size.width(), size.height());
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,20 @@
|
|||
|
||||
#include <deque>
|
||||
|
||||
namespace Images {
|
||||
struct CornersMaskRef;
|
||||
} // namespace Images
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class RippleAnimation {
|
||||
public:
|
||||
// White upon transparent mask, like colorizeImage(black-white-mask, white).
|
||||
RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn<void()> update);
|
||||
// White upon transparent mask,
|
||||
// like colorizeImage(black-white-mask, white).
|
||||
RippleAnimation(
|
||||
const style::RippleAnimation &st,
|
||||
QImage mask,
|
||||
Fn<void()> update);
|
||||
|
||||
void add(QPoint origin, int startRadius = 0);
|
||||
void addFading();
|
||||
|
|
@ -24,16 +32,25 @@ public:
|
|||
void lastFinish();
|
||||
void forceRepaint();
|
||||
|
||||
void paint(QPainter &p, int x, int y, int outerWidth, const QColor *colorOverride = nullptr);
|
||||
void paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
int outerWidth,
|
||||
const QColor *colorOverride = nullptr);
|
||||
|
||||
bool empty() const {
|
||||
return _ripples.empty();
|
||||
}
|
||||
|
||||
static QImage maskByDrawer(QSize size, bool filled, Fn<void(QPainter &p)> drawer);
|
||||
static QImage rectMask(QSize size);
|
||||
static QImage roundRectMask(QSize size, int radius);
|
||||
static QImage ellipseMask(QSize size);
|
||||
static QImage MaskByDrawer(
|
||||
QSize size,
|
||||
bool filled,
|
||||
Fn<void(QPainter &p)> drawer);
|
||||
static QImage RectMask(QSize size);
|
||||
static QImage RoundRectMask(QSize size, int radius);
|
||||
static QImage RoundRectMask(QSize size, Images::CornersMaskRef corners);
|
||||
static QImage EllipseMask(QSize size);
|
||||
|
||||
~RippleAnimation();
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ void RippleButton::ensureRipple() {
|
|||
}
|
||||
|
||||
QImage RippleButton::prepareRippleMask() const {
|
||||
return RippleAnimation::rectMask(size());
|
||||
return RippleAnimation::RectMask(size());
|
||||
}
|
||||
|
||||
QPoint RippleButton::prepareRippleStartPosition() const {
|
||||
|
|
@ -449,7 +449,7 @@ QImage RoundButton::prepareRippleMask() const {
|
|||
if (_fullWidthOverride < 0) {
|
||||
rounded = QRect(0, rounded.top(), innerWidth - _fullWidthOverride, rounded.height());
|
||||
}
|
||||
return RippleAnimation::roundRectMask(
|
||||
return RippleAnimation::RoundRectMask(
|
||||
rounded.size(),
|
||||
(_fullRadius
|
||||
? (rounded.height() / 2)
|
||||
|
|
@ -551,7 +551,7 @@ QPoint IconButton::prepareRippleStartPosition() const {
|
|||
}
|
||||
|
||||
QImage IconButton::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
return RippleAnimation::EllipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
|
||||
}
|
||||
|
||||
CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : RippleButton(parent, st.ripple)
|
||||
|
|
@ -684,7 +684,7 @@ QPoint CrossButton::prepareRippleStartPosition() const {
|
|||
}
|
||||
|
||||
QImage CrossButton::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(QSize(_st.cross.size, _st.cross.size));
|
||||
return RippleAnimation::EllipseMask(QSize(_st.cross.size, _st.cross.size));
|
||||
}
|
||||
|
||||
SettingsButton::SettingsButton(
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ CallButton::CallButton(
|
|||
void CallButton::init() {
|
||||
resize(_stFrom->button.width, _stFrom->button.height);
|
||||
|
||||
_bgMask = RippleAnimation::ellipseMask(QSize(_stFrom->bgSize, _stFrom->bgSize));
|
||||
_bgMask = RippleAnimation::EllipseMask(QSize(_stFrom->bgSize, _stFrom->bgSize));
|
||||
_bgFrom = Ui::PixmapFromImage(style::colorizeImage(_bgMask, _stFrom->bg));
|
||||
if (_stTo) {
|
||||
Assert(_stFrom->button.width == _stTo->button.width);
|
||||
|
|
@ -242,7 +242,7 @@ QPoint CallButton::prepareRippleStartPosition() const {
|
|||
}
|
||||
|
||||
QImage CallButton::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(QSize(_stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize));
|
||||
return RippleAnimation::EllipseMask(QSize(_stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ QSize ToggleView::rippleSize() const {
|
|||
|
||||
QImage ToggleView::prepareRippleMask() const {
|
||||
auto size = rippleSize();
|
||||
return RippleAnimation::roundRectMask(size, size.height() / 2);
|
||||
return RippleAnimation::RoundRectMask(size, size.height() / 2);
|
||||
}
|
||||
|
||||
bool ToggleView::checkRippleStartPosition(QPoint position) const {
|
||||
|
|
@ -277,7 +277,7 @@ QSize CheckView::rippleSize() const {
|
|||
}
|
||||
|
||||
QImage CheckView::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(rippleSize());
|
||||
return RippleAnimation::EllipseMask(rippleSize());
|
||||
}
|
||||
|
||||
bool CheckView::checkRippleStartPosition(QPoint position) const {
|
||||
|
|
@ -356,7 +356,7 @@ QSize RadioView::rippleSize() const {
|
|||
}
|
||||
|
||||
QImage RadioView::prepareRippleMask() const {
|
||||
return RippleAnimation::ellipseMask(rippleSize());
|
||||
return RippleAnimation::EllipseMask(rippleSize());
|
||||
}
|
||||
|
||||
bool RadioView::checkRippleStartPosition(QPoint position) const {
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ QPoint Action::prepareRippleStartPosition() const {
|
|||
}
|
||||
|
||||
QImage Action::prepareRippleMask() const {
|
||||
return Ui::RippleAnimation::rectMask(size());
|
||||
return Ui::RippleAnimation::RectMask(size());
|
||||
}
|
||||
|
||||
int Action::contentHeight() const {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue