Added saving of color and size of brush from photo editor to settings.

This commit is contained in:
23rd 2021-02-17 03:01:19 +03:00
parent dc7f440902
commit e322733e20
5 changed files with 104 additions and 25 deletions

View File

@ -113,7 +113,8 @@ QByteArray Settings::serialize() const {
+ sizeof(qint64) + sizeof(qint64)
+ sizeof(qint32) * 2 + sizeof(qint32) * 2
+ Serialize::bytearraySize(windowPosition) + Serialize::bytearraySize(windowPosition)
+ sizeof(qint32); + sizeof(qint32)
+ Serialize::bytearraySize(_photoEditorBrush);
for (const auto &[id, rating] : recentEmojiPreloadData) { for (const auto &[id, rating] : recentEmojiPreloadData) {
size += Serialize::stringSize(id) + sizeof(quint16); size += Serialize::stringSize(id) + sizeof(quint16);
} }
@ -216,7 +217,8 @@ QByteArray Settings::serialize() const {
<< qint32(_workMode.current()) << qint32(_workMode.current())
<< proxy << proxy
<< qint32(_hiddenGroupCallTooltips.value()) << qint32(_hiddenGroupCallTooltips.value())
<< qint32(_disableOpenGL ? 1 : 0); << qint32(_disableOpenGL ? 1 : 0)
<< _photoEditorBrush;
} }
return result; return result;
} }
@ -297,6 +299,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 workMode = static_cast<qint32>(_workMode.current()); qint32 workMode = static_cast<qint32>(_workMode.current());
QByteArray proxy; QByteArray proxy;
qint32 hiddenGroupCallTooltips = qint32(_hiddenGroupCallTooltips.value()); qint32 hiddenGroupCallTooltips = qint32(_hiddenGroupCallTooltips.value());
QByteArray photoEditorBrush = _photoEditorBrush;
stream >> themesAccentColors; stream >> themesAccentColors;
if (!stream.atEnd()) { if (!stream.atEnd()) {
@ -444,6 +447,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) { if (!stream.atEnd()) {
stream >> disableOpenGL; stream >> disableOpenGL;
} }
if (!stream.atEnd()) {
stream >> photoEditorBrush;
}
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("App Error: " LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()")); "Bad data for Core::Settings::constructFromSerialized()"));
@ -573,6 +579,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
? Tooltip::Microphone ? Tooltip::Microphone
: Tooltip(0)); : Tooltip(0));
}(); }();
_photoEditorBrush = photoEditorBrush;
} }
QString Settings::getSoundPath(const QString &key) const { QString Settings::getSoundPath(const QString &key) const {

View File

@ -434,6 +434,13 @@ public:
_videoPipGeometry = geometry; _videoPipGeometry = geometry;
} }
[[nodiscard]] QByteArray photoEditorBrush() const {
return _photoEditorBrush;
}
void setPhotoEditorBrush(QByteArray brush) {
_photoEditorBrush = brush;
}
[[nodiscard]] float64 rememberedSongVolume() const { [[nodiscard]] float64 rememberedSongVolume() const {
return _rememberedSongVolume; return _rememberedSongVolume;
} }
@ -696,6 +703,8 @@ private:
bool _rememberedSoundNotifyFromTray = false; bool _rememberedSoundNotifyFromTray = false;
bool _rememberedFlashBounceNotifyFromTray = false; bool _rememberedFlashBounceNotifyFromTray = false;
QByteArray _photoEditorBrush;
}; };
} // namespace Core } // namespace Core

View File

@ -17,7 +17,7 @@ namespace Editor {
namespace { namespace {
constexpr auto kPrecision = 1000; constexpr auto kPrecision = 1000;
constexpr auto kMinBrushSize = 0.1; constexpr auto kMinBrushSize = 0.1f;
constexpr auto kMouseSkip = 1.4; constexpr auto kMouseSkip = 1.4;
constexpr auto kMinInnerHeight = 0.2; constexpr auto kMinInnerHeight = 0.2;
@ -83,7 +83,9 @@ inline float64 InterpolationRatio(int from, int to, int result) {
} // namespace } // namespace
ColorPicker::ColorPicker(not_null<Ui::RpWidget*> parent) ColorPicker::ColorPicker(
not_null<Ui::RpWidget*> parent,
const Brush &savedBrush)
: _circleColor(Qt::white) : _circleColor(Qt::white)
, _width(st::photoEditorColorPickerWidth) , _width(st::photoEditorColorPickerWidth)
, _lineHeight(st::photoEditorColorPickerLineHeight) , _lineHeight(st::photoEditorColorPickerLineHeight)
@ -93,7 +95,14 @@ ColorPicker::ColorPicker(not_null<Ui::RpWidget*> parent)
, _outlinedStop(FindOutlinedStop(_circleColor, _gradientStops, _width)) , _outlinedStop(FindOutlinedStop(_circleColor, _gradientStops, _width))
, _gradientBrush( , _gradientBrush(
GradientBrush(QPoint(_width, _lineHeight / 2), _gradientStops)) GradientBrush(QPoint(_width, _lineHeight / 2), _gradientStops))
, _brush(Brush{ .sizeRatio = kMinBrushSize, .color = QColor() }) { , _brush(Brush{
.sizeRatio = (savedBrush.sizeRatio
? savedBrush.sizeRatio
: kMinBrushSize),
.color = (savedBrush.color.isValid()
? savedBrush.color
: _gradientStops.front().second),
}) {
_colorLine->resize(_width, _lineHeight); _colorLine->resize(_width, _lineHeight);
_canvasForCircle->resize( _canvasForCircle->resize(
_width + circleHeight(kMax), _width + circleHeight(kMax),
@ -101,6 +110,8 @@ ColorPicker::ColorPicker(not_null<Ui::RpWidget*> parent)
_canvasForCircle->setAttribute(Qt::WA_TransparentForMouseEvents); _canvasForCircle->setAttribute(Qt::WA_TransparentForMouseEvents);
_down.pos = QPoint(colorToPosition(savedBrush.color), 0);
_colorLine->paintRequest( _colorLine->paintRequest(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
Painter p(_colorLine); Painter p(_colorLine);
@ -146,6 +157,9 @@ ColorPicker::ColorPicker(not_null<Ui::RpWidget*> parent)
} }
const auto e = static_cast<QMouseEvent*>(event.get()); const auto e = static_cast<QMouseEvent*>(event.get());
updateMousePosition(e->pos(), progress); updateMousePosition(e->pos(), progress);
if (isRelease) {
_saveBrushRequests.fire_copy(_brush);
}
_canvasForCircle->update(); _canvasForCircle->update();
}, _colorLine->lifetime()); }, _colorLine->lifetime());
@ -168,18 +182,14 @@ void ColorPicker::updateMousePosition(const QPoint &pos, float64 progress) {
const auto from = 0; const auto from = 0;
const auto to = bottom - skip; const auto to = bottom - skip;
const auto size = (mappedY > to) // Don't change the brush size when we are on the color line.
? _brush.current().sizeRatio // Don't change value. if (mappedY <= to) {
: std::clamp( _brush.sizeRatio = std::clamp(
1. - InterpolationRatio(from, to, _down.pos.y()), float(1. - InterpolationRatio(from, to, _down.pos.y())),
kMinBrushSize, kMinBrushSize,
1.); 1.f);
const auto color = positionToColor(_down.pos.x()); }
_brush.color = positionToColor(_down.pos.x());
_brush = Brush{
.sizeRatio = float(size),
.color = color,
};
} }
void ColorPicker::moveLine(const QPoint &position) { void ColorPicker::moveLine(const QPoint &position) {
@ -239,9 +249,9 @@ void ColorPicker::paintCircle(Painter &p) {
const auto innerH = InterpolateF( const auto innerH = InterpolateF(
h * kMinInnerHeight, h * kMinInnerHeight,
h * kMaxInnerHeight, h * kMaxInnerHeight,
_brush.current().sizeRatio); _brush.sizeRatio);
p.setBrush(_brush.current().color); p.setBrush(_brush.color);
const auto innerRect = QRectF( const auto innerRect = QRectF(
r.x() + (r.width() - innerH) / 2., r.x() + (r.width() - innerH) / 2.,
@ -297,8 +307,18 @@ void ColorPicker::setVisible(bool visible) {
_canvasForCircle->setVisible(visible); _canvasForCircle->setVisible(visible);
} }
rpl::producer<Brush> ColorPicker::brushValue() const { rpl::producer<Brush> ColorPicker::saveBrushRequests() const {
return _brush.value(); return _saveBrushRequests.events();
}
int ColorPicker::colorToPosition(const QColor &color) const {
const auto step = 1. / kPrecision;
for (auto i = 0.; i <= 1.; i += step) {
if (positionToColor(i * _width) == color) {
return i * _width;
}
}
return 0;
} }
} // namespace Editor } // namespace Editor

View File

@ -25,17 +25,18 @@ public:
std::optional<int> nextStopPos = std::nullopt; std::optional<int> nextStopPos = std::nullopt;
}; };
ColorPicker(not_null<Ui::RpWidget*> parent); ColorPicker(not_null<Ui::RpWidget*> parent, const Brush &savedBrush);
void moveLine(const QPoint &position); void moveLine(const QPoint &position);
void setVisible(bool visible); void setVisible(bool visible);
rpl::producer<Brush> brushValue() const; rpl::producer<Brush> saveBrushRequests() const;
private: private:
void paintCircle(Painter &p); void paintCircle(Painter &p);
void paintOutline(Painter &p, const QRectF &rect); void paintOutline(Painter &p, const QRectF &rect);
QColor positionToColor(int x) const; QColor positionToColor(int x) const;
int colorToPosition(const QColor &color) const;
int circleHeight(float64 progress = 0.) const; int circleHeight(float64 progress = 0.) const;
void updateMousePosition(const QPoint &pos, float64 progress); void updateMousePosition(const QPoint &pos, float64 progress);
@ -54,10 +55,12 @@ private:
QPoint pos; QPoint pos;
bool pressed = false; bool pressed = false;
} _down; } _down;
rpl::variable<Brush> _brush; Brush _brush;
Ui::Animations::Simple _circleAnimation; Ui::Animations::Simple _circleAnimation;
rpl::event_stream<Brush> _saveBrushRequests;
}; };
} // namespace Editor } // namespace Editor

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "editor/photo_editor.h" #include "editor/photo_editor.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "editor/color_picker.h" #include "editor/color_picker.h"
#include "editor/photo_editor_content.h" #include "editor/photo_editor_content.h"
#include "editor/photo_editor_controls.h" #include "editor/photo_editor_controls.h"
@ -14,6 +16,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_editor.h" #include "styles/style_editor.h"
namespace Editor { namespace Editor {
namespace {
constexpr auto kPrecision = 100000;
[[nodiscard]] QByteArray Serialize(const Brush &brush) {
auto result = QByteArray();
auto stream = QDataStream(&result, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_3);
stream << qint32(brush.sizeRatio * kPrecision) << brush.color;
stream.device()->close();
return result;
}
[[nodiscard]] Brush Deserialize(const QByteArray &data) {
auto stream = QDataStream(data);
auto result = Brush();
auto size = qint32(0);
stream >> size >> result.color;
result.sizeRatio = size / float(kPrecision);
return (stream.status() != QDataStream::Ok)
? Brush()
: result;
}
} // namespace
PhotoEditor::PhotoEditor( PhotoEditor::PhotoEditor(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
@ -28,7 +56,10 @@ PhotoEditor::PhotoEditor(
_modifications, _modifications,
_undoController)) _undoController))
, _controls(base::make_unique_q<PhotoEditorControls>(this, _undoController)) , _controls(base::make_unique_q<PhotoEditorControls>(this, _undoController))
, _colorPicker(std::make_unique<ColorPicker>(this)) { , _colorPicker(std::make_unique<ColorPicker>(
this,
Deserialize(Core::App().settings().photoEditorBrush()))) {
sizeValue( sizeValue(
) | rpl::start_with_next([=](const QSize &size) { ) | rpl::start_with_next([=](const QSize &size) {
if (size.isEmpty()) { if (size.isEmpty()) {
@ -97,9 +128,18 @@ PhotoEditor::PhotoEditor(
} }
}, lifetime()); }, lifetime());
_colorPicker->brushValue( rpl::single(
Deserialize(Core::App().settings().photoEditorBrush())
) | rpl::then(
_colorPicker->saveBrushRequests()
) | rpl::start_with_next([=](const Brush &brush) { ) | rpl::start_with_next([=](const Brush &brush) {
_content->applyBrush(brush); _content->applyBrush(brush);
const auto serialized = Serialize(brush);
if (Core::App().settings().photoEditorBrush() != serialized) {
Core::App().settings().setPhotoEditorBrush(serialized);
Core::App().saveSettingsDelayed();
}
}, lifetime()); }, lifetime());
} }