mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
[img-editor] Added corner rounding level picker for sticker creation.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 21 21">
|
||||
<g fill="none" fill-rule="evenodd" stroke="white" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" transform="translate(2 2)">
|
||||
<path d="m.5 4.5c0-2.209139 1.79086-4 4-4"/>
|
||||
<path d="m16.5 4.5c0-2.209139-1.79086-4-4-4"/>
|
||||
<path d="m16.5 12.5c0 2.209139-1.79086 4-4 4"/>
|
||||
<path d="m.5 12.5c0 2.209139 1.79086 4 4 4"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 426 B |
@@ -7222,6 +7222,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_photo_editor_crop_square" = "Square";
|
||||
"lng_photo_editor_crop_free" = "Free";
|
||||
|
||||
"lng_photo_editor_corners_about" = "Choose how rounded the sticker corners should look.";
|
||||
"lng_photo_editor_corners_large" = "Large";
|
||||
"lng_photo_editor_corners_medium" = "Medium";
|
||||
"lng_photo_editor_corners_small" = "Small";
|
||||
"lng_photo_editor_corners_none" = "None";
|
||||
|
||||
"lng_voice_speed_slow" = "Slow";
|
||||
"lng_voice_speed_normal" = "Normal";
|
||||
"lng_voice_speed_medium" = "Medium";
|
||||
|
||||
@@ -95,6 +95,20 @@ photoEditorCropRatioButton: IconButton(photoEditorRotateButton) {
|
||||
}
|
||||
photoEditorCropRatioIconActive: icon {{ "photo_editor/ratio-23x23", photoEditorButtonIconFgActive, point(0px, 1px) }};
|
||||
|
||||
photoEditorCornersButton: IconButton(photoEditorRotateButton) {
|
||||
icon: icon {{ "photo_editor/corners-23x23", photoEditorButtonIconFg, point(0px, 1px) }};
|
||||
iconOver: icon {{ "photo_editor/corners-23x23", photoEditorButtonIconFgOver, point(0px, 1px) }};
|
||||
}
|
||||
photoEditorCornersIconActive: icon {{ "photo_editor/corners-23x23", photoEditorButtonIconFgActive, point(0px, 1px) }};
|
||||
|
||||
photoEditorCornersMenuAboutLabel: FlatLabel(defaultFlatLabel) {
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(11px);
|
||||
}
|
||||
minWidth: 136px;
|
||||
}
|
||||
photoEditorCornersMenuAboutPosition: point(12px, 4px);
|
||||
|
||||
photoEditorCropRatioMenu: PopupMenu(popupMenuWithIcons) {
|
||||
menu: Menu(menuWithIcons) {
|
||||
widthMin: 108px;
|
||||
|
||||
@@ -82,7 +82,8 @@ Crop::Crop(
|
||||
: QRectF(QPoint(), _imageSize))
|
||||
, _angle(modifications.angle)
|
||||
, _flipped(modifications.flipped)
|
||||
, _keepAspectRatio(_data.keepAspectRatio) {
|
||||
, _keepAspectRatio(_data.keepAspectRatio)
|
||||
, _cornersLevel(modifications.cornersLevel) {
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
@@ -158,9 +159,15 @@ QPainterPath Crop::cropPath() const {
|
||||
if (_data.cropType == EditorData::CropType::Ellipse) {
|
||||
result.addEllipse(_cropPaint);
|
||||
} else if (_data.cropType == EditorData::CropType::RoundedRect) {
|
||||
const auto radius = std::min(_cropPaint.width(), _cropPaint.height())
|
||||
* Ui::ForumUserpicRadiusMultiplier();
|
||||
const auto multiplier = RoundedCornersMultiplier(_cornersLevel);
|
||||
if (multiplier <= 0.) {
|
||||
result.addRect(_cropPaint);
|
||||
} else {
|
||||
const auto radius = std::min(
|
||||
_cropPaint.width(),
|
||||
_cropPaint.height()) * multiplier;
|
||||
result.addRoundedRect(_cropPaint, radius, radius);
|
||||
}
|
||||
} else {
|
||||
result.addRect(_cropPaint);
|
||||
}
|
||||
@@ -565,6 +572,17 @@ void Crop::setAspectRatio(float64 ratio) {
|
||||
update();
|
||||
}
|
||||
|
||||
void Crop::setCornersLevel(RoundedCornersLevel level) {
|
||||
if (_cornersLevel == level) {
|
||||
return;
|
||||
}
|
||||
_cornersLevel = level;
|
||||
_painterPath.clear();
|
||||
_painterPath.addRect(_innerRect);
|
||||
_painterPath.addPath(cropPath());
|
||||
update();
|
||||
}
|
||||
|
||||
QRect Crop::saveCropRect() {
|
||||
const auto savedCrop = _cropOriginal.toRect();
|
||||
return (!savedCrop.topLeft().isNull() || (savedCrop.size() != _imageSize))
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
[[nodiscard]] QRect saveCropRect();
|
||||
[[nodiscard]] style::margins cropMargins() const;
|
||||
void setAspectRatio(float64 ratio);
|
||||
void setCornersLevel(RoundedCornersLevel level);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
@@ -99,6 +100,8 @@ private:
|
||||
|
||||
bool _keepAspectRatio = false;
|
||||
|
||||
RoundedCornersLevel _cornersLevel = RoundedCornersLevel::Large;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Editor
|
||||
|
||||
@@ -295,6 +295,12 @@ PhotoEditor::PhotoEditor(
|
||||
_content->applyAspectRatio(ratio);
|
||||
}, lifetime());
|
||||
|
||||
_controls->cornersLevelChanges(
|
||||
) | rpl::on_next([=](RoundedCornersLevel level) {
|
||||
_modifications.cornersLevel = level;
|
||||
_content->applyModifications(_modifications);
|
||||
}, lifetime());
|
||||
|
||||
_controls->paintModeRequests(
|
||||
) | rpl::on_next([=] {
|
||||
_mode = PhotoEditorMode{
|
||||
|
||||
@@ -14,10 +14,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
namespace Editor {
|
||||
namespace {
|
||||
|
||||
void ApplyShapeMask(QImage &image, EditorData::CropType type) {
|
||||
void ApplyShapeMask(
|
||||
QImage &image,
|
||||
EditorData::CropType type,
|
||||
RoundedCornersLevel cornersLevel) {
|
||||
if (type == EditorData::CropType::Rect) {
|
||||
return;
|
||||
}
|
||||
const auto multiplier = (type == EditorData::CropType::RoundedRect)
|
||||
? RoundedCornersMultiplier(cornersLevel)
|
||||
: Ui::ForumUserpicRadiusMultiplier();
|
||||
if (type == EditorData::CropType::RoundedRect && multiplier <= 0.) {
|
||||
return;
|
||||
}
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
@@ -33,7 +42,7 @@ void ApplyShapeMask(QImage &image, EditorData::CropType type) {
|
||||
p.drawEllipse(rect);
|
||||
} else {
|
||||
const auto radius = std::min(rect.width(), rect.height())
|
||||
* Ui::ForumUserpicRadiusMultiplier();
|
||||
* multiplier;
|
||||
p.drawRoundedRect(rect, radius, radius);
|
||||
}
|
||||
}
|
||||
@@ -44,6 +53,16 @@ void ApplyShapeMask(QImage &image, EditorData::CropType type) {
|
||||
|
||||
} // namespace
|
||||
|
||||
float64 RoundedCornersMultiplier(RoundedCornersLevel level) {
|
||||
switch (level) {
|
||||
case RoundedCornersLevel::Large: return Ui::ForumUserpicRadiusMultiplier();
|
||||
case RoundedCornersLevel::Medium: return 0.2;
|
||||
case RoundedCornersLevel::Small: return 0.12;
|
||||
case RoundedCornersLevel::None: return 0.;
|
||||
}
|
||||
Unexpected("Unknown RoundedCornersLevel in RoundedCornersMultiplier.");
|
||||
}
|
||||
|
||||
QImage ImageModified(QImage image, const PhotoModifications &mods) {
|
||||
Expects(!image.isNull());
|
||||
|
||||
@@ -64,7 +83,7 @@ QImage ImageModified(QImage image, const PhotoModifications &mods) {
|
||||
auto cropped = mods.crop.isValid()
|
||||
? image.copy(mods.crop)
|
||||
: image;
|
||||
ApplyShapeMask(cropped, mods.cropType);
|
||||
ApplyShapeMask(cropped, mods.cropType, mods.cornersLevel);
|
||||
QTransform transform;
|
||||
if (mods.flipped) {
|
||||
transform.scale(-1, 1);
|
||||
|
||||
@@ -11,6 +11,15 @@ namespace Editor {
|
||||
|
||||
class Scene;
|
||||
|
||||
enum class RoundedCornersLevel {
|
||||
Large,
|
||||
Medium,
|
||||
Small,
|
||||
None,
|
||||
};
|
||||
|
||||
[[nodiscard]] float64 RoundedCornersMultiplier(RoundedCornersLevel level);
|
||||
|
||||
struct EditorData {
|
||||
enum class CropType {
|
||||
Rect,
|
||||
@@ -31,6 +40,7 @@ struct PhotoModifications {
|
||||
bool flipped = false;
|
||||
QRect crop;
|
||||
EditorData::CropType cropType = EditorData::CropType::Rect;
|
||||
RoundedCornersLevel cornersLevel = RoundedCornersLevel::Large;
|
||||
std::shared_ptr<Scene> paint = nullptr;
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
@@ -96,6 +96,7 @@ PhotoEditorContent::PhotoEditorContent(
|
||||
geometry + _crop->cropMargins(),
|
||||
mods.angle,
|
||||
mods.flipped, imageSizeF);
|
||||
_crop->setCornersLevel(mods.cornersLevel);
|
||||
_paint->applyTransform(geometry, mods.angle, mods.flipped);
|
||||
|
||||
_innerRect = geometry;
|
||||
|
||||
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/image/image_prepare.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/menu/menu_multiline_action.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "ui/painter.h"
|
||||
@@ -276,6 +277,11 @@ PhotoEditorControls::PhotoEditorControls(
|
||||
: base::make_unique_q<Ui::IconButton>(
|
||||
_transformButtons,
|
||||
st::photoEditorCropRatioButton))
|
||||
, _cornersButton((data.cropType == EditorData::CropType::RoundedRect)
|
||||
? base::make_unique_q<Ui::IconButton>(
|
||||
_transformButtons,
|
||||
st::photoEditorCornersButton)
|
||||
: nullptr)
|
||||
, _transformDone(base::make_unique_q<EdgeButton>(
|
||||
_transformButtons,
|
||||
(data.confirm.isEmpty() ? tr::lng_box_done(tr::now) : data.confirm),
|
||||
@@ -516,6 +522,69 @@ PhotoEditorControls::PhotoEditorControls(
|
||||
});
|
||||
}
|
||||
|
||||
_currentCornersLevel = modifications.cornersLevel;
|
||||
if (_cornersButton) {
|
||||
const auto updateIcon = [=] {
|
||||
const auto active = (_currentCornersLevel
|
||||
!= RoundedCornersLevel::Large);
|
||||
const auto icon = active
|
||||
? &st::photoEditorCornersIconActive
|
||||
: nullptr;
|
||||
_cornersButton->setIconOverride(icon, icon);
|
||||
};
|
||||
updateIcon();
|
||||
_cornersButton->setClickedCallback([=] {
|
||||
_cornersMenu = base::make_unique_q<Ui::PopupMenu>(
|
||||
_cornersButton.get(),
|
||||
st::photoEditorCropRatioMenu);
|
||||
_cornersMenu->setForcedOrigin(
|
||||
Ui::PanelAnimation::Origin::BottomRight);
|
||||
auto about = base::make_unique_q<Ui::Menu::MultilineAction>(
|
||||
_cornersMenu->menu(),
|
||||
_cornersMenu->menu()->st(),
|
||||
st::photoEditorCornersMenuAboutLabel,
|
||||
st::photoEditorCornersMenuAboutPosition,
|
||||
TextWithEntities{
|
||||
tr::lng_photo_editor_corners_about(tr::now),
|
||||
});
|
||||
_cornersMenu->addAction(std::move(about));
|
||||
_cornersMenu->addSeparator();
|
||||
const auto check = &st::mediaPlayerMenuCheck;
|
||||
const auto add = [&](
|
||||
const QString &text,
|
||||
RoundedCornersLevel level) {
|
||||
const auto selected = (_currentCornersLevel == level);
|
||||
_cornersMenu->addAction(
|
||||
text,
|
||||
[=] {
|
||||
if (_currentCornersLevel == level) {
|
||||
return;
|
||||
}
|
||||
_currentCornersLevel = level;
|
||||
updateIcon();
|
||||
_cornersLevelChanges.fire_copy(level);
|
||||
},
|
||||
selected ? check : nullptr);
|
||||
};
|
||||
add(
|
||||
tr::lng_photo_editor_corners_large(tr::now),
|
||||
RoundedCornersLevel::Large);
|
||||
add(
|
||||
tr::lng_photo_editor_corners_medium(tr::now),
|
||||
RoundedCornersLevel::Medium);
|
||||
add(
|
||||
tr::lng_photo_editor_corners_small(tr::now),
|
||||
RoundedCornersLevel::Small);
|
||||
add(
|
||||
tr::lng_photo_editor_corners_none(tr::now),
|
||||
RoundedCornersLevel::None);
|
||||
const auto button = _cornersButton.get();
|
||||
const auto bottomRight = button->mapToGlobal(
|
||||
QPoint(button->width(), 0));
|
||||
_cornersMenu->popup(bottomRight);
|
||||
});
|
||||
}
|
||||
|
||||
updateInputMask();
|
||||
|
||||
}
|
||||
@@ -564,6 +633,11 @@ rpl::producer<float64> PhotoEditorControls::aspectRatioChanges() const {
|
||||
return _aspectRatioChanges.events();
|
||||
}
|
||||
|
||||
auto PhotoEditorControls::cornersLevelChanges() const
|
||||
-> rpl::producer<RoundedCornersLevel> {
|
||||
return _cornersLevelChanges.events();
|
||||
}
|
||||
|
||||
int PhotoEditorControls::bottomButtonsTop() const {
|
||||
return height()
|
||||
- st::photoEditorControlsBottomSkip
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
[[nodiscard]] rpl::producer<QPoint> colorLinePositionValue() const;
|
||||
[[nodiscard]] rpl::producer<bool> colorLineShownValue() const;
|
||||
[[nodiscard]] rpl::producer<float64> aspectRatioChanges() const;
|
||||
[[nodiscard]] auto cornersLevelChanges() const
|
||||
-> rpl::producer<RoundedCornersLevel>;
|
||||
|
||||
[[nodiscard]] bool animating() const;
|
||||
|
||||
@@ -77,6 +79,7 @@ private:
|
||||
const base::unique_qptr<Ui::IconButton> _rotateButton;
|
||||
const base::unique_qptr<Ui::IconButton> _paintModeButton;
|
||||
const base::unique_qptr<Ui::IconButton> _cropRatioButton;
|
||||
const base::unique_qptr<Ui::IconButton> _cornersButton;
|
||||
const base::unique_qptr<EdgeButton> _transformDone;
|
||||
|
||||
const base::unique_qptr<EdgeButton> _paintCancel;
|
||||
@@ -88,7 +91,9 @@ private:
|
||||
const base::unique_qptr<EdgeButton> _paintDone;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _ratioMenu;
|
||||
base::unique_qptr<Ui::PopupMenu> _cornersMenu;
|
||||
float64 _currentRatio = 0.;
|
||||
RoundedCornersLevel _currentCornersLevel = RoundedCornersLevel::Large;
|
||||
|
||||
bool _flipped = false;
|
||||
|
||||
@@ -97,6 +102,7 @@ private:
|
||||
rpl::variable<PhotoEditorMode> _mode;
|
||||
rpl::event_stream<not_null<QKeyEvent*>> _keyPresses;
|
||||
rpl::event_stream<float64> _aspectRatioChanges;
|
||||
rpl::event_stream<RoundedCornersLevel> _cornersLevelChanges;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user