Added saving of color and size of brush from photo editor to settings.
This commit is contained in:
parent
dc7f440902
commit
e322733e20
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue