| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // 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 "base/flat_map.h"
- #include "ui/effects/animation_value.h"
- #include <QtGui/QLinearGradient>
- #include <QtGui/QRadialGradient>
- namespace anim {
- [[nodiscard]] QColor gradient_color_at(
- const QGradientStops &stops,
- float64 ratio);
- [[nodiscard]] QColor gradient_color_at(
- const QGradient &gradient,
- float64 ratio);
- struct gradient_colors {
- explicit gradient_colors(QColor color) {
- stops.push_back({ 0., color });
- stops.push_back({ 1., color });
- }
- explicit gradient_colors(std::vector<QColor> colors) {
- if (colors.size() == 1) {
- gradient_colors(colors.front());
- return;
- }
- const auto last = float(colors.size() - 1);
- for (auto i = 0; i < colors.size(); i++) {
- stops.push_back({ i / last, std::move(colors[i]) });
- }
- }
- explicit gradient_colors(QGradientStops colors)
- : stops(std::move(colors)) {
- }
- QGradientStops stops;
- };
- namespace details {
- template <typename T, typename Derived>
- class gradients {
- public:
- gradients() = default;
- gradients(base::flat_map<T, std::vector<QColor>> colors) {
- Expects(!colors.empty());
- for (const auto &[key, value] : colors) {
- auto c = gradient_colors(std::move(value));
- _gradients.emplace(key, gradient_with_stops(std::move(c.stops)));
- }
- }
- gradients(base::flat_map<T, gradient_colors> colors) {
- Expects(!colors.empty());
- for (const auto &[key, c] : colors) {
- _gradients.emplace(key, gradient_with_stops(std::move(c.stops)));
- }
- }
- QGradient gradient(T state1, T state2, float64 b_ratio) const {
- Expects(!_gradients.empty());
- if (b_ratio == 0.) {
- return _gradients.find(state1)->second;
- } else if (b_ratio == 1.) {
- return _gradients.find(state2)->second;
- }
- auto gradient = empty_gradient();
- const auto gradient1 = _gradients.find(state1);
- const auto gradient2 = _gradients.find(state2);
- Assert(gradient1 != end(_gradients));
- Assert(gradient2 != end(_gradients));
- const auto stopsFrom = gradient1->second.stops();
- const auto stopsTo = gradient2->second.stops();
- if ((stopsFrom.size() == stopsTo.size())
- && ranges::equal(
- stopsFrom,
- stopsTo,
- ranges::equal_to(),
- &QGradientStop::first,
- &QGradientStop::first)) {
- const auto size = stopsFrom.size();
- const auto &p = b_ratio;
- for (auto i = 0; i < size; i++) {
- auto c = color(stopsFrom[i].second, stopsTo[i].second, p);
- gradient.setColorAt(stopsTo[i].first, std::move(c));
- }
- return gradient;
- }
- const auto invert = (stopsFrom.size() > stopsTo.size());
- if (invert) {
- b_ratio = 1. - b_ratio;
- }
- const auto &stops1 = invert ? stopsTo : stopsFrom;
- const auto &stops2 = invert ? stopsFrom : stopsTo;
- const auto size1 = stops1.size();
- const auto size2 = stops2.size();
- for (auto i = 0; i < size1; i++) {
- const auto point1 = stops1[i].first;
- const auto previousPoint1 = i ? stops1[i - 1].first : -1.;
- for (auto n = 0; n < size2; n++) {
- const auto point2 = stops2[n].first;
- if ((point2 <= previousPoint1) || (point2 > point1)) {
- continue;
- }
- const auto color2 = stops2[n].second;
- QColor result;
- if (point2 < point1) {
- const auto pointRatio2 = (point2 - previousPoint1)
- / (point1 - previousPoint1);
- const auto color1 = color(
- stops1[i - 1].second,
- stops1[i].second,
- pointRatio2);
- result = color(color1, color2, b_ratio);
- } else {
- // point2 == point1
- result = color(stops1[i].second, color2, b_ratio);
- }
- gradient.setColorAt(point2, std::move(result));
- }
- }
- return gradient;
- }
- protected:
- void cache_gradients() {
- auto copy = std::move(_gradients);
- for (const auto &[key, value] : copy) {
- _gradients.emplace(key, gradient_with_stops(value.stops()));
- }
- }
- private:
- QGradient empty_gradient() const {
- return static_cast<const Derived*>(this)->empty_gradient();
- }
- QGradient gradient_with_stops(QGradientStops stops) const {
- auto gradient = empty_gradient();
- gradient.setStops(std::move(stops));
- return gradient;
- }
- base::flat_map<T, QGradient> _gradients;
- };
- } // namespace details
- template <typename T>
- class linear_gradients final
- : public details::gradients<T, linear_gradients<T>> {
- using parent = details::gradients<T, linear_gradients<T>>;
- public:
- linear_gradients() = default;
- linear_gradients(
- base::flat_map<T, std::vector<QColor>> colors,
- QPointF point1,
- QPointF point2)
- : parent(std::move(colors)) {
- set_points(point1, point2);
- }
- linear_gradients(
- base::flat_map<T, gradient_colors> colors,
- QPointF point1,
- QPointF point2)
- : parent(std::move(colors)) {
- set_points(point1, point2);
- }
- void set_points(QPointF point1, QPointF point2) {
- if (_point1 == point1 && _point2 == point2) {
- return;
- }
- _point1 = point1;
- _point2 = point2;
- parent::cache_gradients();
- }
- private:
- friend class details::gradients<T, linear_gradients<T>>;
- QGradient empty_gradient() const {
- return QLinearGradient(_point1, _point2);
- }
- QPointF _point1;
- QPointF _point2;
- };
- template <typename T>
- class radial_gradients final
- : public details::gradients<T, radial_gradients<T>> {
- using parent = details::gradients<T, radial_gradients<T>>;
- public:
- radial_gradients() = default;
- radial_gradients(
- base::flat_map<T, std::vector<QColor>> colors,
- QPointF center,
- float radius)
- : parent(std::move(colors)) {
- set_points(center, radius);
- }
- radial_gradients(
- base::flat_map<T, gradient_colors> colors,
- QPointF center,
- float radius)
- : parent(std::move(colors)) {
- set_points(center, radius);
- }
- void set_points(QPointF center, float radius) {
- if (_center == center && _radius == radius) {
- return;
- }
- _center = center;
- _radius = radius;
- parent::cache_gradients();
- }
- private:
- friend class details::gradients<T, radial_gradients<T>>;
- QGradient empty_gradient() const {
- return QRadialGradient(_center, _radius);
- }
- QPointF _center;
- float _radius = 0.;
- };
- } // namespace anim
|