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