Added masked shadow corners for special layers.
This commit is contained in:
parent
549edbe5c7
commit
b9a702f6e0
6 changed files with 172 additions and 28 deletions
|
|
@ -227,6 +227,8 @@ PRIVATE
|
||||||
ui/abstract_button.h
|
ui/abstract_button.h
|
||||||
ui/basic_click_handlers.cpp
|
ui/basic_click_handlers.cpp
|
||||||
ui/basic_click_handlers.h
|
ui/basic_click_handlers.h
|
||||||
|
ui/cached_special_layer_shadow_corners.cpp
|
||||||
|
ui/cached_special_layer_shadow_corners.h
|
||||||
ui/click_handler.cpp
|
ui/click_handler.cpp
|
||||||
ui/click_handler.h
|
ui/click_handler.h
|
||||||
ui/delayed_activation.cpp
|
ui/delayed_activation.cpp
|
||||||
|
|
|
||||||
71
ui/cached_special_layer_shadow_corners.cpp
Normal file
71
ui/cached_special_layer_shadow_corners.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
#include "ui/cached_special_layer_shadow_corners.h"
|
||||||
|
|
||||||
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "styles/style_layers.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] std::array<QImage, 4> PrepareSpecialLayerShadowCorners() {
|
||||||
|
const auto &st = st::boxRoundShadow;
|
||||||
|
|
||||||
|
const auto s = QSize(
|
||||||
|
st::boxRadius * 2 + st.extend.left(),
|
||||||
|
st::boxRadius * 2 + st.extend.right());
|
||||||
|
const auto mask = Ui::RippleAnimation::maskByDrawer(s, false, [&](
|
||||||
|
QPainter &p) {
|
||||||
|
p.drawRoundedRect(QRect(QPoint(), s), st::boxRadius, st::boxRadius);
|
||||||
|
});
|
||||||
|
struct Corner {
|
||||||
|
const style::icon &icon;
|
||||||
|
QPoint factor;
|
||||||
|
};
|
||||||
|
const auto corners = std::vector<Corner>{
|
||||||
|
Corner{ st.topLeft, QPoint(1, 1) },
|
||||||
|
Corner{ st.bottomLeft, QPoint(1, 0) },
|
||||||
|
Corner{ st.topRight, QPoint(0, 1) },
|
||||||
|
Corner{ st.bottomRight, QPoint(0, 0) },
|
||||||
|
};
|
||||||
|
const auto processCorner = [&](int i) {
|
||||||
|
const auto &corner = corners[i];
|
||||||
|
auto result = QImage(
|
||||||
|
corner.icon.size() * style::DevicePixelRatio(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
result.fill(Qt::transparent);
|
||||||
|
|
||||||
|
{
|
||||||
|
QPainter p(&result);
|
||||||
|
corner.icon.paint(p, 0, 0, corner.icon.width());
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
|
||||||
|
p.drawImage(
|
||||||
|
corner.icon.width() * corner.factor.x()
|
||||||
|
- mask.width() / style::DevicePixelRatio() / 2,
|
||||||
|
corner.icon.height() * corner.factor.y()
|
||||||
|
- mask.height() / style::DevicePixelRatio() / 2,
|
||||||
|
mask);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
return std::array<QImage, 4>{ {
|
||||||
|
processCorner(0),
|
||||||
|
processCorner(1),
|
||||||
|
processCorner(2),
|
||||||
|
processCorner(3),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const std::array<QImage, 4> &SpecialLayerShadowCorners() {
|
||||||
|
static const auto custom = PrepareSpecialLayerShadowCorners();
|
||||||
|
return custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
13
ui/cached_special_layer_shadow_corners.h
Normal file
13
ui/cached_special_layer_shadow_corners.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<QImage, 4> &SpecialLayerShadowCorners();
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
#include "ui/layers/layer_widget.h"
|
#include "ui/layers/layer_widget.h"
|
||||||
|
|
||||||
|
#include "ui/cached_special_layer_shadow_corners.h"
|
||||||
#include "ui/layers/box_layer_widget.h"
|
#include "ui/layers/box_layer_widget.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
|
|
@ -21,7 +22,7 @@ namespace Ui {
|
||||||
|
|
||||||
class LayerStackWidget::BackgroundWidget : public TWidget {
|
class LayerStackWidget::BackgroundWidget : public TWidget {
|
||||||
public:
|
public:
|
||||||
explicit BackgroundWidget(QWidget *parent);
|
using TWidget::TWidget;
|
||||||
|
|
||||||
void setDoneCallback(Fn<void()> callback) {
|
void setDoneCallback(Fn<void()> callback) {
|
||||||
_doneCallback = std::move(callback);
|
_doneCallback = std::move(callback);
|
||||||
|
|
@ -63,7 +64,6 @@ private:
|
||||||
int _mainMenuCacheWidth = 0;
|
int _mainMenuCacheWidth = 0;
|
||||||
QPixmap _specialLayerCache;
|
QPixmap _specialLayerCache;
|
||||||
QPixmap _layerCache;
|
QPixmap _layerCache;
|
||||||
RoundRect _roundRect;
|
|
||||||
|
|
||||||
Fn<void()> _doneCallback;
|
Fn<void()> _doneCallback;
|
||||||
|
|
||||||
|
|
@ -84,11 +84,6 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LayerStackWidget::BackgroundWidget::BackgroundWidget(QWidget *parent)
|
|
||||||
: TWidget(parent)
|
|
||||||
, _roundRect(st::boxRadius, st::boxBg) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayerStackWidget::BackgroundWidget::setCacheImages(
|
void LayerStackWidget::BackgroundWidget::setCacheImages(
|
||||||
QPixmap &&bodyCache,
|
QPixmap &&bodyCache,
|
||||||
QPixmap &&mainMenuCache,
|
QPixmap &&mainMenuCache,
|
||||||
|
|
@ -262,15 +257,9 @@ void LayerStackWidget::BackgroundWidget::paintEvent(QPaintEvent *e) {
|
||||||
if (topCorners || bottomCorners) {
|
if (topCorners || bottomCorners) {
|
||||||
p.setClipRegion(QRegion(rect()) - specialLayerBox.marginsRemoved(QMargins(st::boxRadius, 0, st::boxRadius, 0)) - specialLayerBox.marginsRemoved(QMargins(0, st::boxRadius, 0, st::boxRadius)));
|
p.setClipRegion(QRegion(rect()) - specialLayerBox.marginsRemoved(QMargins(st::boxRadius, 0, st::boxRadius, 0)) - specialLayerBox.marginsRemoved(QMargins(0, st::boxRadius, 0, st::boxRadius)));
|
||||||
}
|
}
|
||||||
Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, sides);
|
Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, sides, Ui::SpecialLayerShadowCorners());
|
||||||
|
|
||||||
if (topCorners || bottomCorners) {
|
if (topCorners || bottomCorners) {
|
||||||
// In case of painting the shadow above the special layer we get
|
|
||||||
// glitches in the corners, so we need to paint the corners once more.
|
|
||||||
p.setClipping(false);
|
p.setClipping(false);
|
||||||
auto parts = (topCorners ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
|
|
||||||
| (bottomCorners ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None);
|
|
||||||
_roundRect.paint(p, specialLayerBox, parts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,42 @@
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
PlainShadow::PlainShadow(QWidget *parent)
|
struct CustomShadowCorners {
|
||||||
: PlainShadow(parent, st::shadowFg) {
|
struct Image {
|
||||||
|
public:
|
||||||
|
Image(const QImage &image)
|
||||||
|
: _image(image) {
|
||||||
}
|
}
|
||||||
|
void paint(QPainter &p, int x, int y, int outerw) const {
|
||||||
PlainShadow::PlainShadow(QWidget *parent, style::color color)
|
p.drawImage(x, y, _image);
|
||||||
: RpWidget(parent)
|
|
||||||
, _color(color) {
|
|
||||||
resize(st::lineWidth, st::lineWidth);
|
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool empty() const {
|
||||||
void PlainShadow::paintEvent(QPaintEvent *e) {
|
return _image.isNull();
|
||||||
QPainter(this).fillRect(e->rect(), _color);
|
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] int width() const {
|
||||||
|
return _image.width() / style::DevicePixelRatio();
|
||||||
|
}
|
||||||
|
[[nodiscard]] int height() const {
|
||||||
|
return _image.height() / style::DevicePixelRatio();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const QImage &_image;
|
||||||
|
};
|
||||||
|
const style::icon &left;
|
||||||
|
Image topLeft;
|
||||||
|
const style::icon ⊤
|
||||||
|
Image topRight;
|
||||||
|
const style::icon &right;
|
||||||
|
Image bottomRight;
|
||||||
|
const style::icon ⊥
|
||||||
|
Image bottomLeft;
|
||||||
|
const style::margins &extend;
|
||||||
|
};
|
||||||
|
|
||||||
void Shadow::paint(QPainter &p, const QRect &box, int outerWidth, const style::Shadow &st, RectParts sides) {
|
template <typename Shadow>
|
||||||
|
void ShadowPaint(QPainter &p, const QRect &box, int outerWidth, const Shadow &st, RectParts sides) {
|
||||||
auto left = (sides & RectPart::Left);
|
auto left = (sides & RectPart::Left);
|
||||||
auto top = (sides & RectPart::Top);
|
auto top = (sides & RectPart::Top);
|
||||||
auto right = (sides & RectPart::Right);
|
auto right = (sides & RectPart::Right);
|
||||||
|
|
@ -84,6 +104,47 @@ void Shadow::paint(QPainter &p, const QRect &box, int outerWidth, const style::S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
PlainShadow::PlainShadow(QWidget *parent)
|
||||||
|
: PlainShadow(parent, st::shadowFg) {
|
||||||
|
}
|
||||||
|
|
||||||
|
PlainShadow::PlainShadow(QWidget *parent, style::color color)
|
||||||
|
: RpWidget(parent)
|
||||||
|
, _color(color) {
|
||||||
|
resize(st::lineWidth, st::lineWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlainShadow::paintEvent(QPaintEvent *e) {
|
||||||
|
QPainter(this).fillRect(e->rect(), _color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shadow::paint(QPainter &p, const QRect &box, int outerWidth, const style::Shadow &st, RectParts sides) {
|
||||||
|
ShadowPaint<style::Shadow>(p, box, outerWidth, st, std::move(sides));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shadow::paint(
|
||||||
|
QPainter &p,
|
||||||
|
const QRect &box,
|
||||||
|
int outerWidth,
|
||||||
|
const style::Shadow &st,
|
||||||
|
RectParts sides,
|
||||||
|
const std::array<QImage, 4> &corners) {
|
||||||
|
const auto shadow = CustomShadowCorners{
|
||||||
|
.left = st.left,
|
||||||
|
.topLeft = CustomShadowCorners::Image(corners[0]),
|
||||||
|
.top = st.top,
|
||||||
|
.topRight = CustomShadowCorners::Image(corners[2]),
|
||||||
|
.right = st.right,
|
||||||
|
.bottomRight = CustomShadowCorners::Image(corners[3]),
|
||||||
|
.bottom = st.bottom,
|
||||||
|
.bottomLeft = CustomShadowCorners::Image(corners[1]),
|
||||||
|
.extend = st.extend,
|
||||||
|
};
|
||||||
|
ShadowPaint<CustomShadowCorners>(p, box, outerWidth, shadow, std::move(sides));
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap Shadow::grab(
|
QPixmap Shadow::grab(
|
||||||
not_null<TWidget*> target,
|
not_null<TWidget*> target,
|
||||||
const style::Shadow &shadow,
|
const style::Shadow &shadow,
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ public:
|
||||||
const style::Shadow &st,
|
const style::Shadow &st,
|
||||||
RectParts sides = RectPart::AllSides);
|
RectParts sides = RectPart::AllSides);
|
||||||
|
|
||||||
|
static void paint(
|
||||||
|
QPainter &p,
|
||||||
|
const QRect &box,
|
||||||
|
int outerWidth,
|
||||||
|
const style::Shadow &st,
|
||||||
|
RectParts sides,
|
||||||
|
const std::array<QImage, 4> &corners);
|
||||||
|
|
||||||
static QPixmap grab(
|
static QPixmap grab(
|
||||||
not_null<TWidget*> target,
|
not_null<TWidget*> target,
|
||||||
const style::Shadow &shadow,
|
const style::Shadow &shadow,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue