|
|
|
@@ -7,7 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
|
*/
|
|
|
|
|
#include "editor/color_picker.h"
|
|
|
|
|
|
|
|
|
|
#include "base/basic_types.h"
|
|
|
|
|
#include "ui/painter.h"
|
|
|
|
|
#include "ui/rect.h"
|
|
|
|
|
#include "ui/rp_widget.h"
|
|
|
|
|
#include "styles/style_editor.h"
|
|
|
|
|
|
|
|
|
@@ -17,8 +19,10 @@ namespace Editor {
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
constexpr auto kPrecision = 1000;
|
|
|
|
|
constexpr auto kMinBrushSize = 0.1f;
|
|
|
|
|
constexpr auto kMinBrushSize = 0.1;
|
|
|
|
|
constexpr auto kMouseSkip = 1.4;
|
|
|
|
|
constexpr auto kMinBrushWidth = 1.;
|
|
|
|
|
constexpr auto kMaxBrushWidth = 25.;
|
|
|
|
|
|
|
|
|
|
constexpr auto kMinInnerHeight = 0.2;
|
|
|
|
|
constexpr auto kMaxInnerHeight = 0.8;
|
|
|
|
@@ -69,11 +73,11 @@ QBrush GradientBrush(const QPoint &p, const QGradientStops &stops) {
|
|
|
|
|
return QBrush(std::move(gradient));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float RatioPrecise(float a) {
|
|
|
|
|
return int(a * kPrecision) / float(kPrecision);
|
|
|
|
|
float64 RatioPrecise(float64 a) {
|
|
|
|
|
return int(a * kPrecision) / float64(kPrecision);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float64 InterpolateF(float a, float b, float64 b_ratio) {
|
|
|
|
|
inline float64 InterpolateF(float64 a, float64 b, float64 b_ratio) {
|
|
|
|
|
return a + float64(b - a) * b_ratio;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -86,11 +90,14 @@ inline float64 InterpolationRatio(int from, int to, int result) {
|
|
|
|
|
ColorPicker::ColorPicker(
|
|
|
|
|
not_null<Ui::RpWidget*> parent,
|
|
|
|
|
const Brush &savedBrush)
|
|
|
|
|
: _circleColor(Qt::white)
|
|
|
|
|
: _parent(parent)
|
|
|
|
|
, _circleColor(Qt::white)
|
|
|
|
|
, _width(st::photoEditorColorPickerWidth)
|
|
|
|
|
, _lineHeight(st::photoEditorColorPickerLineHeight)
|
|
|
|
|
, _colorLine(base::make_unique_q<Ui::RpWidget>(parent))
|
|
|
|
|
, _canvasForCircle(base::make_unique_q<Ui::RpWidget>(parent))
|
|
|
|
|
, _sizeControlHoverArea(std::in_place, parent)
|
|
|
|
|
, _sizeControl(std::in_place, parent)
|
|
|
|
|
, _gradientStops(Colors())
|
|
|
|
|
, _outlinedStop(FindOutlinedStop(_circleColor, _gradientStops, _width))
|
|
|
|
|
, _gradientBrush(
|
|
|
|
@@ -107,10 +114,19 @@ ColorPicker::ColorPicker(
|
|
|
|
|
_canvasForCircle->resize(
|
|
|
|
|
_width + circleHeight(kMax),
|
|
|
|
|
st::photoEditorColorPickerCanvasHeight);
|
|
|
|
|
_sizeControl->resize(
|
|
|
|
|
st::photoEditorBrushSizeControlHitPadding * 2
|
|
|
|
|
+ st::photoEditorBrushSizeControlExpandShift
|
|
|
|
|
+ st::photoEditorBrushSizeControlExpandedTopWidth,
|
|
|
|
|
st::photoEditorBrushSizeControlHeight);
|
|
|
|
|
_sizeControlHoverArea->setMouseTracking(true);
|
|
|
|
|
_sizeControl->setMouseTracking(true);
|
|
|
|
|
|
|
|
|
|
_canvasForCircle->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
|
|
|
|
|
|
|
|
_down.pos = QPoint(colorToPosition(savedBrush.color), 0);
|
|
|
|
|
updateSizeControlPositionFromRatio();
|
|
|
|
|
moveSizeControl(_parent->size());
|
|
|
|
|
|
|
|
|
|
_colorLine->paintRequest(
|
|
|
|
|
) | rpl::on_next([=] {
|
|
|
|
@@ -130,6 +146,27 @@ ColorPicker::ColorPicker(
|
|
|
|
|
paintCircle(p);
|
|
|
|
|
}, _canvasForCircle->lifetime());
|
|
|
|
|
|
|
|
|
|
_sizeControl->paintOn([=](QPainter &p) {
|
|
|
|
|
paintSizeControl(p);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_parent->sizeValue(
|
|
|
|
|
) | rpl::on_next([=](const QSize &size) {
|
|
|
|
|
moveSizeControl(size);
|
|
|
|
|
}, _sizeControl->lifetime());
|
|
|
|
|
|
|
|
|
|
_sizeControlHoverArea->events(
|
|
|
|
|
) | rpl::on_next([=](not_null<QEvent*> event) {
|
|
|
|
|
const auto type = event->type();
|
|
|
|
|
if (type == QEvent::Enter) {
|
|
|
|
|
_sizeHoverAreaHovered = true;
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
} else if (type == QEvent::Leave) {
|
|
|
|
|
_sizeHoverAreaHovered = false;
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
}
|
|
|
|
|
}, _sizeControlHoverArea->lifetime());
|
|
|
|
|
|
|
|
|
|
_colorLine->events(
|
|
|
|
|
) | rpl::on_next([=](not_null<QEvent*> event) {
|
|
|
|
|
const auto type = event->type();
|
|
|
|
@@ -162,7 +199,68 @@ ColorPicker::ColorPicker(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_canvasForCircle->update();
|
|
|
|
|
_sizeControl->update();
|
|
|
|
|
}, _colorLine->lifetime());
|
|
|
|
|
|
|
|
|
|
_sizeControl->events(
|
|
|
|
|
) | rpl::on_next([=](not_null<QEvent*> event) {
|
|
|
|
|
const auto type = event->type();
|
|
|
|
|
if (type == QEvent::Enter) {
|
|
|
|
|
_sizeControlHovered = true;
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
return;
|
|
|
|
|
} else if (type == QEvent::Leave) {
|
|
|
|
|
_sizeControlHovered = false;
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto isPress = (type == QEvent::MouseButtonPress)
|
|
|
|
|
|| (type == QEvent::MouseButtonDblClick);
|
|
|
|
|
const auto isMove = (type == QEvent::MouseMove);
|
|
|
|
|
const auto isRelease = (type == QEvent::MouseButtonRelease);
|
|
|
|
|
if (!isPress && !isMove && !isRelease) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto e = static_cast<QMouseEvent*>(event.get());
|
|
|
|
|
if (isPress) {
|
|
|
|
|
if (e->button() != Qt::LeftButton) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto progress = _sizeControlAnimation.value(
|
|
|
|
|
_sizeControlExpanded ? 1. : 0.);
|
|
|
|
|
const auto inHandle = sizeControlHandleRect(progress).contains(
|
|
|
|
|
e->pos());
|
|
|
|
|
const auto inControl = sizeControlHitRect(progress).contains(
|
|
|
|
|
e->pos());
|
|
|
|
|
if (!inHandle && !inControl) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_sizeDown.pressed = true;
|
|
|
|
|
updateSizeControlMousePosition(e->pos().y());
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
_canvasForCircle->update();
|
|
|
|
|
_sizeControl->update();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!_sizeDown.pressed) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (isMove) {
|
|
|
|
|
updateSizeControlMousePosition(e->pos().y());
|
|
|
|
|
_canvasForCircle->update();
|
|
|
|
|
_sizeControl->update();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (isRelease && (e->button() == Qt::LeftButton)) {
|
|
|
|
|
updateSizeControlMousePosition(e->pos().y());
|
|
|
|
|
_sizeDown.pressed = false;
|
|
|
|
|
updateSizeControlExpanded();
|
|
|
|
|
_saveBrushRequests.fire_copy(_brush);
|
|
|
|
|
_canvasForCircle->update();
|
|
|
|
|
_sizeControl->update();
|
|
|
|
|
}
|
|
|
|
|
}, _sizeControl->lifetime());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::updateMousePosition(const QPoint &pos, float64 progress) {
|
|
|
|
@@ -185,9 +283,10 @@ void ColorPicker::updateMousePosition(const QPoint &pos, float64 progress) {
|
|
|
|
|
// Don't change the brush size when we are on the color line.
|
|
|
|
|
if (mappedY <= to) {
|
|
|
|
|
_brush.sizeRatio = std::clamp(
|
|
|
|
|
float(1. - InterpolationRatio(from, to, _down.pos.y())),
|
|
|
|
|
float64(1. - InterpolationRatio(from, to, _down.pos.y())),
|
|
|
|
|
kMinBrushSize,
|
|
|
|
|
1.f);
|
|
|
|
|
1.);
|
|
|
|
|
updateSizeControlPositionFromRatio();
|
|
|
|
|
}
|
|
|
|
|
_brush.color = positionToColor(_down.pos.x());
|
|
|
|
|
}
|
|
|
|
@@ -204,6 +303,11 @@ void ColorPicker::moveLine(const QPoint &position) {
|
|
|
|
|
- _canvasForCircle->height());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::setCanvasRect(const QRect &rect) {
|
|
|
|
|
_canvasRect = rect;
|
|
|
|
|
moveSizeControl(_parent->size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QColor ColorPicker::positionToColor(int x) const {
|
|
|
|
|
const auto from = 0;
|
|
|
|
|
const auto to = _width;
|
|
|
|
@@ -263,12 +367,29 @@ void ColorPicker::paintCircle(QPainter &p) {
|
|
|
|
|
p.drawEllipse(innerRect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::paintSizeControl(QPainter &p) {
|
|
|
|
|
auto hq = PainterHighQualityEnabler(p);
|
|
|
|
|
|
|
|
|
|
const auto progress = _sizeControlAnimation.value(_sizeControlExpanded
|
|
|
|
|
? 1.
|
|
|
|
|
: 0.);
|
|
|
|
|
const auto path = sizeControlShapePath(progress);
|
|
|
|
|
|
|
|
|
|
p.setPen(Qt::NoPen);
|
|
|
|
|
p.setBrush(QColor(255, 255, 255, anim::interpolate(96, 176, progress)));
|
|
|
|
|
p.drawPath(path);
|
|
|
|
|
|
|
|
|
|
const auto handleRect = sizeControlHandleRect(progress);
|
|
|
|
|
p.setBrush(QColor(255, 255, 255, 244));
|
|
|
|
|
p.drawEllipse(handleRect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::paintOutline(QPainter &p, const QRectF &rect) {
|
|
|
|
|
const auto &s = _outlinedStop;
|
|
|
|
|
if (!s.stopPos) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto draw = [&](float opacity) {
|
|
|
|
|
const auto draw = [&](float64 opacity) {
|
|
|
|
|
p.save();
|
|
|
|
|
p.setOpacity(opacity);
|
|
|
|
|
p.setPen(Qt::lightGray);
|
|
|
|
@@ -302,8 +423,17 @@ int ColorPicker::circleHeight(float64 progress) const {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::setVisible(bool visible) {
|
|
|
|
|
if (!visible) {
|
|
|
|
|
_sizeDown.pressed = false;
|
|
|
|
|
_sizeHoverAreaHovered = false;
|
|
|
|
|
_sizeControlHovered = false;
|
|
|
|
|
_sizeControlExpanded = false;
|
|
|
|
|
_sizeControlAnimation.stop();
|
|
|
|
|
}
|
|
|
|
|
_colorLine->setVisible(visible);
|
|
|
|
|
_canvasForCircle->setVisible(visible);
|
|
|
|
|
_sizeControlHoverArea->setVisible(visible);
|
|
|
|
|
_sizeControl->setVisible(visible);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rpl::producer<Brush> ColorPicker::saveBrushRequests() const {
|
|
|
|
@@ -322,7 +452,201 @@ int ColorPicker::colorToPosition(const QColor &color) const {
|
|
|
|
|
|
|
|
|
|
bool ColorPicker::preventHandleKeyPress() const {
|
|
|
|
|
return _canvasForCircle->isVisible()
|
|
|
|
|
&& (_circleAnimation.animating() || _down.pressed);
|
|
|
|
|
&& (_circleAnimation.animating()
|
|
|
|
|
|| _sizeControlAnimation.animating()
|
|
|
|
|
|| _down.pressed
|
|
|
|
|
|| _sizeDown.pressed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::moveSizeControl(const QSize &size) {
|
|
|
|
|
if (size.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto areaWidth = std::min(
|
|
|
|
|
size.width(),
|
|
|
|
|
st::photoEditorBrushSizeControlHitPadding);
|
|
|
|
|
const auto areaTop = (_canvasRect.height() > 0)
|
|
|
|
|
? _canvasRect.y()
|
|
|
|
|
: (size.height() - _sizeControl->height()) / 2;
|
|
|
|
|
const auto areaHeight = (_canvasRect.height() > 0)
|
|
|
|
|
? _canvasRect.height()
|
|
|
|
|
: _sizeControl->height();
|
|
|
|
|
_sizeControlHoverArea->setGeometry(
|
|
|
|
|
0,
|
|
|
|
|
std::clamp(areaTop, 0, std::max(0, size.height() - areaHeight)),
|
|
|
|
|
areaWidth,
|
|
|
|
|
std::min(areaHeight, size.height()));
|
|
|
|
|
|
|
|
|
|
const auto collapsedCenterX = sizeControlCurrentCenterX(0.);
|
|
|
|
|
const auto collapsedLeft = collapsedCenterX
|
|
|
|
|
- (float64(st::photoEditorBrushSizeControlCollapsedWidth) / 2.);
|
|
|
|
|
const auto y = (_canvasRect.height() > 0)
|
|
|
|
|
? (rect::center(_canvasRect).y() - _sizeControl->height() / 2)
|
|
|
|
|
: ((size.height() - _sizeControl->height()) / 2);
|
|
|
|
|
const auto diff = size.height() - _sizeControl->height();
|
|
|
|
|
_sizeControl->move(
|
|
|
|
|
-int(base::SafeRound(collapsedLeft)),
|
|
|
|
|
std::clamp(y, 0, std::max(0, diff)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::updateSizeControlExpanded() {
|
|
|
|
|
const auto expanded = _sizeDown.pressed
|
|
|
|
|
|| _sizeHoverAreaHovered
|
|
|
|
|
|| _sizeControlHovered;
|
|
|
|
|
if (_sizeControlExpanded == expanded
|
|
|
|
|
&& !_sizeControlAnimation.animating()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_sizeControlExpanded = expanded;
|
|
|
|
|
const auto from = _sizeControlAnimation.value(expanded ? 0. : 1.);
|
|
|
|
|
const auto to = expanded ? 1. : 0.;
|
|
|
|
|
_sizeControlAnimation.stop();
|
|
|
|
|
_sizeControlAnimation.start(
|
|
|
|
|
[=] { _sizeControl->update(); },
|
|
|
|
|
from,
|
|
|
|
|
to,
|
|
|
|
|
kCircleDuration * std::abs(to - from),
|
|
|
|
|
anim::easeOutCirc);
|
|
|
|
|
_sizeControl->update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::updateSizeControlMousePosition(int y) {
|
|
|
|
|
_sizeDown.y = std::clamp(y, sizeControlTop(), sizeControlBottom());
|
|
|
|
|
_brush.sizeRatio = sizeControlRatioFromY(_sizeDown.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorPicker::updateSizeControlPositionFromRatio() {
|
|
|
|
|
_sizeDown.y = sizeControlYFromRatio(_brush.sizeRatio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ColorPicker::sizeControlShapeTop() const {
|
|
|
|
|
return st::photoEditorBrushSizeControlHitPadding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ColorPicker::sizeControlShapeBottom() const {
|
|
|
|
|
return _sizeControl->height() - st::photoEditorBrushSizeControlHitPadding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ColorPicker::sizeControlTop() const {
|
|
|
|
|
return sizeControlShapeTop()
|
|
|
|
|
+ (st::photoEditorBrushSizeControlExpandedTopWidth / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ColorPicker::sizeControlBottom() const {
|
|
|
|
|
return sizeControlShapeBottom()
|
|
|
|
|
- (st::photoEditorBrushSizeControlExpandedBottomWidth / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float64 ColorPicker::sizeControlRatioFromY(int y) const {
|
|
|
|
|
const auto top = sizeControlTop();
|
|
|
|
|
const auto bottom = sizeControlBottom();
|
|
|
|
|
if (bottom <= top) {
|
|
|
|
|
return 1.;
|
|
|
|
|
}
|
|
|
|
|
return std::clamp(
|
|
|
|
|
float64(1. - InterpolationRatio(top, bottom, y)),
|
|
|
|
|
kMinBrushSize,
|
|
|
|
|
1.);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ColorPicker::sizeControlYFromRatio(float64 ratio) const {
|
|
|
|
|
const auto top = sizeControlTop();
|
|
|
|
|
const auto bottom = sizeControlBottom();
|
|
|
|
|
if (bottom <= top) {
|
|
|
|
|
return top;
|
|
|
|
|
}
|
|
|
|
|
const auto normalized = std::clamp(
|
|
|
|
|
(ratio - kMinBrushSize) / (1. - kMinBrushSize),
|
|
|
|
|
0.,
|
|
|
|
|
1.);
|
|
|
|
|
return std::clamp(
|
|
|
|
|
anim::interpolate(bottom, top, normalized),
|
|
|
|
|
top,
|
|
|
|
|
bottom);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRectF ColorPicker::sizeControlHandleRect(float64 progress) const {
|
|
|
|
|
const auto handleSize = sizeControlHandleSize();
|
|
|
|
|
const auto centerX = sizeControlCurrentCenterX(progress);
|
|
|
|
|
return QRectF(
|
|
|
|
|
centerX - handleSize / 2.,
|
|
|
|
|
_sizeDown.y - handleSize / 2.,
|
|
|
|
|
handleSize,
|
|
|
|
|
handleSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRectF ColorPicker::sizeControlHitRect(float64 progress) const {
|
|
|
|
|
const auto collapsed = st::photoEditorBrushSizeControlCollapsedWidth;
|
|
|
|
|
const auto width = float64(anim::interpolate(
|
|
|
|
|
collapsed,
|
|
|
|
|
st::photoEditorBrushSizeControlExpandedTopWidth,
|
|
|
|
|
progress));
|
|
|
|
|
const auto centerX = sizeControlCurrentCenterX(progress);
|
|
|
|
|
const auto top = float64(sizeControlShapeTop());
|
|
|
|
|
const auto bottom = float64(sizeControlShapeBottom());
|
|
|
|
|
return QRectF(
|
|
|
|
|
centerX - width / 2.,
|
|
|
|
|
top,
|
|
|
|
|
width,
|
|
|
|
|
bottom - top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QPainterPath ColorPicker::sizeControlShapePath(float64 progress) const {
|
|
|
|
|
const auto collapsed = st::photoEditorBrushSizeControlCollapsedWidth;
|
|
|
|
|
const auto topWidth = float64(anim::interpolate(
|
|
|
|
|
collapsed,
|
|
|
|
|
st::photoEditorBrushSizeControlExpandedTopWidth,
|
|
|
|
|
progress));
|
|
|
|
|
const auto topInset = st::photoEditorBrushSizeControlTopInset;
|
|
|
|
|
const auto adjustedTopWidth = std::max(
|
|
|
|
|
0.,
|
|
|
|
|
topWidth - float64(topInset * 2));
|
|
|
|
|
const auto bottomWidth = float64(anim::interpolate(
|
|
|
|
|
collapsed,
|
|
|
|
|
st::photoEditorBrushSizeControlExpandedBottomWidth,
|
|
|
|
|
progress));
|
|
|
|
|
const auto centerX = sizeControlCurrentCenterX(progress);
|
|
|
|
|
const auto top = float64(sizeControlShapeTop()) + topInset;
|
|
|
|
|
const auto bottom = float64(sizeControlShapeBottom());
|
|
|
|
|
const auto topRadius = adjustedTopWidth / 2.;
|
|
|
|
|
const auto bottomRadius = bottomWidth / 2.;
|
|
|
|
|
|
|
|
|
|
auto path = QPainterPath();
|
|
|
|
|
const auto topRect = QRectF(
|
|
|
|
|
centerX - topRadius,
|
|
|
|
|
top,
|
|
|
|
|
adjustedTopWidth,
|
|
|
|
|
adjustedTopWidth);
|
|
|
|
|
const auto bottomRect = QRectF(
|
|
|
|
|
centerX - bottomRadius,
|
|
|
|
|
bottom - bottomWidth,
|
|
|
|
|
bottomWidth,
|
|
|
|
|
bottomWidth);
|
|
|
|
|
path.moveTo(centerX - topRadius, top + topRadius);
|
|
|
|
|
path.arcTo(topRect, 180., -180.);
|
|
|
|
|
path.lineTo(centerX + bottomRadius, bottom - bottomRadius);
|
|
|
|
|
path.arcTo(bottomRect, 0., -180.);
|
|
|
|
|
path.lineTo(centerX - topRadius, top + topRadius);
|
|
|
|
|
path.closeSubpath();
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float64 ColorPicker::sizeControlCurrentCenterX(float64 progress) const {
|
|
|
|
|
const auto from = float64(st::photoEditorBrushSizeControlCollapsedWidth)
|
|
|
|
|
/ 2.;
|
|
|
|
|
const auto to = float64(st::photoEditorBrushSizeControlExpandShift)
|
|
|
|
|
+ float64(st::photoEditorBrushSizeControlExpandedTopWidth) / 2.;
|
|
|
|
|
return float64(st::photoEditorBrushSizeControlHitPadding)
|
|
|
|
|
+ InterpolateF(from, to, progress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float64 ColorPicker::sizeControlHandleSize() const {
|
|
|
|
|
const auto width = kMinBrushWidth
|
|
|
|
|
+ (kMaxBrushWidth - kMinBrushWidth) * _brush.sizeRatio;
|
|
|
|
|
return std::clamp(
|
|
|
|
|
width,
|
|
|
|
|
float64(st::photoEditorBrushSizeControlExpandedBottomWidth),
|
|
|
|
|
float64(st::photoEditorBrushSizeControlExpandedTopWidth));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Editor
|
|
|
|
|