Added initial implementation of Linear Blobs.
This commit is contained in:
parent
15ea9197cc
commit
cffbdc7c58
6 changed files with 406 additions and 3 deletions
|
|
@ -71,8 +71,12 @@ PRIVATE
|
||||||
ui/layers/layer_widget.h
|
ui/layers/layer_widget.h
|
||||||
ui/paint/blob.cpp
|
ui/paint/blob.cpp
|
||||||
ui/paint/blob.h
|
ui/paint/blob.h
|
||||||
|
ui/paint/blob_linear.cpp
|
||||||
|
ui/paint/blob_linear.h
|
||||||
ui/paint/blobs.cpp
|
ui/paint/blobs.cpp
|
||||||
ui/paint/blobs.h
|
ui/paint/blobs.h
|
||||||
|
ui/paint/blobs_linear.cpp
|
||||||
|
ui/paint/blobs_linear.h
|
||||||
ui/platform/linux/ui_window_linux.cpp
|
ui/platform/linux/ui_window_linux.cpp
|
||||||
ui/platform/linux/ui_window_linux.h
|
ui/platform/linux/ui_window_linux.h
|
||||||
ui/platform/linux/ui_utility_linux.cpp
|
ui/platform/linux/ui_utility_linux.cpp
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,6 @@ public:
|
||||||
void update(float level, float speedScale);
|
void update(float level, float speedScale);
|
||||||
void generateBlob();
|
void generateBlob();
|
||||||
|
|
||||||
void setMinRadius(float value);
|
|
||||||
void setMaxRadius(float value);
|
|
||||||
|
|
||||||
void setRadiuses(Radiuses values);
|
void setRadiuses(Radiuses values);
|
||||||
Radiuses radiuses() const;
|
Radiuses radiuses() const;
|
||||||
|
|
||||||
|
|
|
||||||
153
ui/paint/blob_linear.cpp
Normal file
153
ui/paint/blob_linear.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#include "ui/paint/blob_linear.h"
|
||||||
|
|
||||||
|
#include "base/openssl_help.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
|
|
||||||
|
#include <QtGui/QPainterPath>
|
||||||
|
#include <QtCore/QtMath>
|
||||||
|
|
||||||
|
namespace Ui::Paint {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kMaxSpeed = 8.2;
|
||||||
|
constexpr auto kMinSpeed = 0.8;
|
||||||
|
|
||||||
|
float64 RandomAdditional() {
|
||||||
|
return (openssl::RandomValue<int>() % 100 / 100.);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
LinearBlobBezier::LinearBlobBezier(
|
||||||
|
int n,
|
||||||
|
float minScale,
|
||||||
|
float minSpeed,
|
||||||
|
float maxSpeed)
|
||||||
|
: _segmentsCount(n)
|
||||||
|
, _minSpeed(minSpeed ? minSpeed : kMinSpeed)
|
||||||
|
, _maxSpeed(maxSpeed ? maxSpeed : kMaxSpeed)
|
||||||
|
, _pen(Qt::NoBrush, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
|
||||||
|
, _segments(n + 1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobBezier::paint(
|
||||||
|
Painter &p,
|
||||||
|
const QBrush &brush,
|
||||||
|
const QRect &rect,
|
||||||
|
float pinnedTop,
|
||||||
|
float progressToPinned) {
|
||||||
|
auto path = QPainterPath();
|
||||||
|
auto m = QMatrix();
|
||||||
|
|
||||||
|
const auto left = rect.x();
|
||||||
|
const auto top = rect.y();
|
||||||
|
const auto right = rect.x() + rect.width();
|
||||||
|
const auto bottom = rect.y() + rect.height();
|
||||||
|
|
||||||
|
// path.moveTo(right, bottom);
|
||||||
|
// path.lineTo(left, bottom);
|
||||||
|
path.moveTo(right, top);
|
||||||
|
path.lineTo(left, top);
|
||||||
|
|
||||||
|
const auto &n = _segmentsCount;
|
||||||
|
|
||||||
|
p.save();
|
||||||
|
|
||||||
|
for (auto i = 0; i <= n; i++) {
|
||||||
|
const auto &segment = _segments[i];
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
const auto progress = segment.progress;
|
||||||
|
const auto r1 = segment.radius * (1. - progress)
|
||||||
|
+ segment.radiusNext * progress;
|
||||||
|
const auto y = (bottom + r1);// * progressToPinned
|
||||||
|
// const auto y = (top - r1) * progressToPinned
|
||||||
|
// + pinnedTop * (1. - progressToPinned);
|
||||||
|
path.lineTo(left, y);
|
||||||
|
} else {
|
||||||
|
const auto &prevSegment = _segments[i - 1];
|
||||||
|
const auto progress = prevSegment.progress;
|
||||||
|
const auto r1 = prevSegment.radius * (1. - progress)
|
||||||
|
+ prevSegment.radiusNext * progress;
|
||||||
|
|
||||||
|
const auto progressNext = segment.progress;
|
||||||
|
const auto r2 = segment.radius * (1. - progressNext)
|
||||||
|
+ segment.radiusNext * progressNext;
|
||||||
|
|
||||||
|
const auto x1 = (right - left) / n * (i - 1);
|
||||||
|
const auto x2 = (right - left) / n * i;
|
||||||
|
const auto cx = x1 + (x2 - x1) / 2;
|
||||||
|
|
||||||
|
const auto y1 = (bottom + r1);// * progressToPinned
|
||||||
|
// const auto y1 = (top - r1) * progressToPinned
|
||||||
|
// + pinnedTop * (1. - progressToPinned);
|
||||||
|
const auto y2 = (bottom + r2);// * progressToPinned
|
||||||
|
// const auto y2 = (top - r2) * progressToPinned
|
||||||
|
// + pinnedTop * (1. - progressToPinned);
|
||||||
|
path.cubicTo(
|
||||||
|
QPointF(cx, y1),
|
||||||
|
QPointF(cx, y2),
|
||||||
|
QPointF(x2, y2)
|
||||||
|
);
|
||||||
|
if (i == n) {
|
||||||
|
path.lineTo(right, top);
|
||||||
|
// path.lineTo(right, bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
|
||||||
|
p.setPen(_pen);
|
||||||
|
p.fillPath(path, brush);
|
||||||
|
p.drawPath(path);
|
||||||
|
|
||||||
|
p.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobBezier::generateBlob() {
|
||||||
|
for (auto i = 0; i < _segmentsCount; i++) {
|
||||||
|
auto &segment = _segments[i];
|
||||||
|
generateBlob(segment.radius, i);
|
||||||
|
generateBlob(segment.radiusNext, i);
|
||||||
|
segment.progress = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobBezier::generateBlob(float &radius, int i) {
|
||||||
|
const auto radDiff = _radiuses.max - _radiuses.min;
|
||||||
|
|
||||||
|
radius = _radiuses.min + std::abs(RandomAdditional()) * radDiff;
|
||||||
|
_segments[i].speed = 0.017 + 0.003 * std::abs(RandomAdditional());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobBezier::update(float level, float speedScale) {
|
||||||
|
_scale = level;
|
||||||
|
for (auto i = 0; i < _segmentsCount; i++) {
|
||||||
|
auto &segment = _segments[i];
|
||||||
|
segment.progress += (segment.speed * _minSpeed)
|
||||||
|
+ level * segment.speed * _maxSpeed * speedScale;
|
||||||
|
if (segment.progress >= 1) {
|
||||||
|
segment.progress = 0.;
|
||||||
|
segment.radius = segment.radiusNext;
|
||||||
|
generateBlob(segment.radiusNext, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobBezier::setRadiuses(Radiuses values) {
|
||||||
|
_radiuses = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearBlobBezier::Radiuses LinearBlobBezier::radiuses() const {
|
||||||
|
return _radiuses;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui::Paint
|
||||||
67
ui/paint/blob_linear.h
Normal file
67
ui/paint/blob_linear.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Painter;
|
||||||
|
|
||||||
|
namespace Ui::Paint {
|
||||||
|
|
||||||
|
class LinearBlobBezier final {
|
||||||
|
public:
|
||||||
|
struct Radiuses {
|
||||||
|
float min = 0.;
|
||||||
|
float max = 0.;
|
||||||
|
|
||||||
|
inline bool operator==(const Radiuses &other) const {
|
||||||
|
return (min == other.min) && (max == other.max);
|
||||||
|
}
|
||||||
|
inline bool operator!=(const Radiuses &other) const {
|
||||||
|
return !(min == other.min) && (max == other.max);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LinearBlobBezier(
|
||||||
|
int n,
|
||||||
|
float minScale,
|
||||||
|
float minSpeed = 0,
|
||||||
|
float maxSpeed = 0);
|
||||||
|
|
||||||
|
void paint(
|
||||||
|
Painter &p,
|
||||||
|
const QBrush &brush,
|
||||||
|
const QRect &rect,
|
||||||
|
float pinnedTop,
|
||||||
|
float progressToPinned);
|
||||||
|
void update(float level, float speedScale);
|
||||||
|
void generateBlob();
|
||||||
|
|
||||||
|
void setRadiuses(Radiuses values);
|
||||||
|
Radiuses radiuses() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Segment {
|
||||||
|
float radius = 0.;
|
||||||
|
float radiusNext = 0.;
|
||||||
|
float progress = 0.;
|
||||||
|
float speed = 0.;
|
||||||
|
};
|
||||||
|
|
||||||
|
void generateBlob(float &radius, int i);
|
||||||
|
|
||||||
|
const int _segmentsCount;
|
||||||
|
const float _minSpeed;
|
||||||
|
const float _maxSpeed;
|
||||||
|
const QPen _pen;
|
||||||
|
|
||||||
|
std::vector<Segment> _segments;
|
||||||
|
|
||||||
|
float64 _scale = 0;
|
||||||
|
Radiuses _radiuses;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui::Paint
|
||||||
113
ui/paint/blobs_linear.cpp
Normal file
113
ui/paint/blobs_linear.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#include "ui/paint/blobs_linear.h"
|
||||||
|
|
||||||
|
#include "ui/painter.h"
|
||||||
|
|
||||||
|
namespace Ui::Paint {
|
||||||
|
|
||||||
|
LinearBlobs::LinearBlobs(
|
||||||
|
std::vector<BlobData> blobDatas,
|
||||||
|
float levelDuration,
|
||||||
|
float levelDuration2,
|
||||||
|
float maxLevel)
|
||||||
|
: _maxLevel(maxLevel)
|
||||||
|
, _blobDatas(std::move(blobDatas))
|
||||||
|
, _levelValue(levelDuration)
|
||||||
|
, _levelValue2(levelDuration2) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobs::init() {
|
||||||
|
for (const auto &data : _blobDatas) {
|
||||||
|
auto blob = Paint::LinearBlobBezier(
|
||||||
|
data.segmentsCount,
|
||||||
|
data.minScale);
|
||||||
|
blob.setRadiuses({ 0, data.minRadius });
|
||||||
|
blob.generateBlob();
|
||||||
|
_blobs.push_back(std::move(blob));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float LinearBlobs::maxRadius() const {
|
||||||
|
const auto maxOfRadiuses = [](const BlobData data) {
|
||||||
|
return std::max(data.maxRadius, data.minRadius);
|
||||||
|
};
|
||||||
|
const auto max = *ranges::max_element(
|
||||||
|
_blobDatas,
|
||||||
|
std::less<>(),
|
||||||
|
maxOfRadiuses);
|
||||||
|
return maxOfRadiuses(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LinearBlobs::size() const {
|
||||||
|
return _blobs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobs::setRadiusesAt(
|
||||||
|
rpl::producer<LinearBlobBezier::Radiuses> &&radiuses,
|
||||||
|
int index) {
|
||||||
|
Expects(index >= 0 && index < size());
|
||||||
|
std::move(
|
||||||
|
radiuses
|
||||||
|
) | rpl::start_with_next([=](LinearBlobBezier::Radiuses r) {
|
||||||
|
_blobs[index].setRadiuses(std::move(r));
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearBlobBezier::Radiuses LinearBlobs::radiusesAt(int index) {
|
||||||
|
Expects(index >= 0 && index < size());
|
||||||
|
return _blobs[index].radiuses();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobs::setLevel(float value) {
|
||||||
|
const auto to = std::min(_maxLevel, value) / _maxLevel;
|
||||||
|
_levelValue.start(to);
|
||||||
|
_levelValue2.start(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobs::paint(
|
||||||
|
Painter &p,
|
||||||
|
const QBrush &brush,
|
||||||
|
const QRect &rect,
|
||||||
|
float pinnedTop,
|
||||||
|
float progressToPinned) {
|
||||||
|
const auto opacity = p.opacity();
|
||||||
|
for (auto i = 0; i < _blobs.size(); i++) {
|
||||||
|
auto r = rect;
|
||||||
|
r.setTop(r.top() - _blobDatas[i].topOffset * _levelValue2.current());
|
||||||
|
|
||||||
|
_blobs[i].update(_levelValue.current(), _blobDatas[i].speedScale);
|
||||||
|
const auto alpha = _blobDatas[i].alpha;
|
||||||
|
if (alpha != 1.) {
|
||||||
|
p.setOpacity(opacity * alpha);
|
||||||
|
}
|
||||||
|
_blobs[i].paint(p, brush, r, pinnedTop, progressToPinned);
|
||||||
|
if (alpha != 1.) {
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinearBlobs::updateLevel(crl::time dt) {
|
||||||
|
const auto d = (dt > 20) ? 17 : dt;
|
||||||
|
_levelValue.update(d);
|
||||||
|
_levelValue2.update(d);
|
||||||
|
|
||||||
|
for (auto i = 0; i < _blobs.size(); i++) {
|
||||||
|
const auto &data = _blobDatas[i];
|
||||||
|
_blobs[i].setRadiuses({
|
||||||
|
0,
|
||||||
|
data.minRadius + data.maxRadius * (float)currentLevel() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 LinearBlobs::currentLevel() const {
|
||||||
|
return _levelValue.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui::Paint
|
||||||
69
ui/paint/blobs_linear.h
Normal file
69
ui/paint/blobs_linear.h
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/animation_value.h"
|
||||||
|
#include "ui/paint/blob_linear.h"
|
||||||
|
|
||||||
|
class Painter;
|
||||||
|
|
||||||
|
namespace Ui::Paint {
|
||||||
|
|
||||||
|
class LinearBlobs final {
|
||||||
|
public:
|
||||||
|
struct BlobData {
|
||||||
|
int segmentsCount = 0;
|
||||||
|
float minScale = 0;
|
||||||
|
float minRadius = 0;
|
||||||
|
float maxRadius = 0;
|
||||||
|
float speedScale = 0;
|
||||||
|
float alpha = 0;
|
||||||
|
int topOffset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
LinearBlobs(
|
||||||
|
std::vector<BlobData> blobDatas,
|
||||||
|
float levelDuration,
|
||||||
|
float levelDuration2,
|
||||||
|
float maxLevel);
|
||||||
|
|
||||||
|
void setRadiusesAt(
|
||||||
|
rpl::producer<LinearBlobBezier::Radiuses> &&radiuses,
|
||||||
|
int index);
|
||||||
|
LinearBlobBezier::Radiuses radiusesAt(int index);
|
||||||
|
|
||||||
|
void setLevel(float value);
|
||||||
|
void paint(
|
||||||
|
Painter &p,
|
||||||
|
const QBrush &brush,
|
||||||
|
const QRect &rect,
|
||||||
|
float pinnedTop,
|
||||||
|
float progressToPinned);
|
||||||
|
void updateLevel(crl::time dt);
|
||||||
|
|
||||||
|
[[nodiscard]] float maxRadius() const;
|
||||||
|
[[nodiscard]] int size() const;
|
||||||
|
[[nodiscard]] float64 currentLevel() const;
|
||||||
|
|
||||||
|
static constexpr auto kHideBlobsDuration = 2000;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
const float _maxLevel;
|
||||||
|
|
||||||
|
std::vector<BlobData> _blobDatas;
|
||||||
|
std::vector<LinearBlobBezier> _blobs;
|
||||||
|
|
||||||
|
anim::continuous_value _levelValue;
|
||||||
|
anim::continuous_value _levelValue2;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui::Paint
|
||||||
Loading…
Add table
Reference in a new issue