mirror of https://github.com/procxx/kepka.git
Optimized dropdown animation. Dropdown animation for EmojiPan done.
This commit is contained in:
parent
78f55c10e9
commit
48eb72a9c2
|
@ -2732,40 +2732,74 @@ namespace {
|
|||
}
|
||||
return ::cornersMaskSmall;
|
||||
}
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, const CornersPixmaps &c, const style::color *sh) {
|
||||
int32 cw = c.p[0]->width() / cIntRetinaFactor(), ch = c.p[0]->height() / cIntRetinaFactor();
|
||||
if (w < 2 * cw || h < 2 * ch) return;
|
||||
if (w > 2 * cw) {
|
||||
p.fillRect(QRect(x + cw, y, w - 2 * cw, ch), bg->b);
|
||||
p.fillRect(QRect(x + cw, y + h - ch, w - 2 * cw, ch), bg->b);
|
||||
if (sh) p.fillRect(QRect(x + cw, y + h, w - 2 * cw, st::msgShadow), (*sh)->b);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, const CornersPixmaps &corner, const style::color *shadow, RectParts parts) {
|
||||
auto cornerWidth = corner.p[0]->width() / cIntRetinaFactor();
|
||||
auto cornerHeight = corner.p[0]->height() / cIntRetinaFactor();
|
||||
if (w < 2 * cornerWidth || h < 2 * cornerHeight) return;
|
||||
if (w > 2 * cornerWidth) {
|
||||
if (parts & RectPart::Top) {
|
||||
p.fillRect(x + cornerWidth, y, w - 2 * cornerWidth, cornerHeight, bg);
|
||||
}
|
||||
if (parts & RectPart::Bottom) {
|
||||
p.fillRect(x + cornerWidth, y + h - cornerHeight, w - 2 * cornerWidth, cornerHeight, bg);
|
||||
if (shadow) {
|
||||
p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, *shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (h > 2 * ch) {
|
||||
p.fillRect(QRect(x, y + ch, w, h - 2 * ch), bg->b);
|
||||
if (h > 2 * cornerHeight) {
|
||||
if ((parts & RectPart::NoTopBottom) == qFlags(RectPart::NoTopBottom)) {
|
||||
p.fillRect(x, y + cornerHeight, w, h - 2 * cornerHeight, bg);
|
||||
} else {
|
||||
if (parts & RectPart::Left) {
|
||||
p.fillRect(x, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg);
|
||||
}
|
||||
if ((parts & RectPart::Center) && w > 2 * cornerWidth) {
|
||||
p.fillRect(x + cornerWidth, y + cornerHeight, w - 2 * cornerWidth, h - 2 * cornerHeight, bg);
|
||||
}
|
||||
if (parts & RectPart::Right) {
|
||||
p.fillRect(x + w - cornerWidth, y + cornerHeight, cornerWidth, h - 2 * cornerHeight, bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parts & RectPart::TopLeft) {
|
||||
p.drawPixmap(x, y, *corner.p[0]);
|
||||
}
|
||||
if (parts & RectPart::TopRight) {
|
||||
p.drawPixmap(x + w - cornerWidth, y, *corner.p[1]);
|
||||
}
|
||||
if (parts & RectPart::BottomLeft) {
|
||||
p.drawPixmap(x, y + h - cornerHeight, *corner.p[2]);
|
||||
}
|
||||
if (parts & RectPart::BottomRight) {
|
||||
p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight, *corner.p[3]);
|
||||
}
|
||||
p.drawPixmap(QPoint(x, y), *c.p[0]);
|
||||
p.drawPixmap(QPoint(x + w - cw, y), *c.p[1]);
|
||||
p.drawPixmap(QPoint(x, y + h - ch), *c.p[2]);
|
||||
p.drawPixmap(QPoint(x + w - cw, y + h - ch), *c.p[3]);
|
||||
}
|
||||
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh) {
|
||||
roundRect(p, x, y, w, h, bg, ::corners[index], sh);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *shadow, RectParts parts) {
|
||||
roundRect(p, x, y, w, h, bg, ::corners[index], shadow, parts);
|
||||
}
|
||||
|
||||
void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index) {
|
||||
const CornersPixmaps &c = ::corners[index];
|
||||
int32 cw = c.p[0]->width() / cIntRetinaFactor(), ch = c.p[0]->height() / cIntRetinaFactor();
|
||||
p.fillRect(x + cw, y + h, w - 2 * cw, st::msgShadow, sh->b);
|
||||
p.fillRect(x, y + h - ch, cw, st::msgShadow, sh->b);
|
||||
p.fillRect(x + w - cw, y + h - ch, cw, st::msgShadow, sh->b);
|
||||
p.drawPixmap(x, y + h - ch + st::msgShadow, *c.p[2]);
|
||||
p.drawPixmap(x + w - cw, y + h - ch + st::msgShadow, *c.p[3]);
|
||||
void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &shadow, RoundCorners index, RectParts parts) {
|
||||
auto &corner = ::corners[index];
|
||||
auto cornerWidth = corner.p[0]->width() / cIntRetinaFactor();
|
||||
auto cornerHeight = corner.p[0]->height() / cIntRetinaFactor();
|
||||
if (parts & RectPart::Bottom) {
|
||||
p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, shadow);
|
||||
}
|
||||
if (parts & RectPart::BottomLeft) {
|
||||
p.fillRect(x, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow);
|
||||
p.drawPixmap(x, y + h - cornerHeight + st::msgShadow, *corner.p[2]);
|
||||
}
|
||||
if (parts & RectPart::BottomRight) {
|
||||
p.fillRect(x + w - cornerWidth, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow);
|
||||
p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight + st::msgShadow, *corner.p[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, ImageRoundRadius radius) {
|
||||
uint32 colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) | ((uint32(bg->c.red()) & 0xFF) << 16) | ((uint32(bg->c.green()) & 0xFF) << 8) | ((uint32(bg->c.blue()) & 0xFF) << 24);
|
||||
CornersMap::const_iterator i = cornersMap.find(colorKey);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, ImageRoundRadius radius, RectParts parts) {
|
||||
auto colorKey = ((uint32(bg->c.alpha()) & 0xFF) << 24) | ((uint32(bg->c.red()) & 0xFF) << 16) | ((uint32(bg->c.green()) & 0xFF) << 8) | ((uint32(bg->c.blue()) & 0xFF) << 24);
|
||||
auto i = cornersMap.find(colorKey);
|
||||
if (i == cornersMap.cend()) {
|
||||
QImage images[4];
|
||||
switch (radius) {
|
||||
|
@ -2781,7 +2815,7 @@ namespace {
|
|||
}
|
||||
i = cornersMap.insert(colorKey, pixmaps);
|
||||
}
|
||||
roundRect(p, x, y, w, h, bg, i.value(), 0);
|
||||
roundRect(p, x, y, w, h, bg, i.value(), nullptr, parts);
|
||||
}
|
||||
|
||||
WallPapers gServerBackgrounds;
|
||||
|
|
|
@ -279,18 +279,39 @@ namespace App {
|
|||
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY
|
||||
void setProxySettings(QTcpSocket &socket);
|
||||
|
||||
enum class RectPart {
|
||||
TopLeft = 0x001,
|
||||
Top = 0x002,
|
||||
TopRight = 0x004,
|
||||
Left = 0x008,
|
||||
Center = 0x010,
|
||||
Right = 0x020,
|
||||
BottomLeft = 0x040,
|
||||
Bottom = 0x080,
|
||||
BottomRight = 0x100,
|
||||
TopFull = 0x007,
|
||||
LeftFull = 0x049,
|
||||
RightFull = 0x124,
|
||||
BottomFull = 0x1c0,
|
||||
NoTopBottom = 0x038,
|
||||
NoLeftRight = 0x092,
|
||||
Full = 0x1ff,
|
||||
};
|
||||
Q_DECLARE_FLAGS(RectParts, RectPart);
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(RectParts);
|
||||
|
||||
QImage **cornersMask(ImageRoundRadius radius);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *sh = 0);
|
||||
inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *sh = 0) {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, sh);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full);
|
||||
inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts);
|
||||
}
|
||||
void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &sh, RoundCorners index);
|
||||
inline void roundShadow(Painter &p, const QRect &rect, const style::color &sh, RoundCorners index) {
|
||||
return roundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), sh, index);
|
||||
void roundShadow(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &shadow, RoundCorners index, RectParts parts = RectPart::Full);
|
||||
inline void roundShadow(Painter &p, const QRect &rect, const style::color &shadow, RoundCorners index, RectParts parts = RectPart::Full) {
|
||||
return roundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, index, parts);
|
||||
}
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, ImageRoundRadius radius);
|
||||
inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, ImageRoundRadius radius) {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius);
|
||||
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, ImageRoundRadius radius, RectParts parts = RectPart::Full);
|
||||
inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, ImageRoundRadius radius, RectParts parts = RectPart::Full) {
|
||||
return roundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);
|
||||
}
|
||||
|
||||
struct WallPaper {
|
||||
|
|
|
@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include <QtCore/QReadWriteLock>
|
||||
|
||||
#include "core/build_config.h"
|
||||
#include "core/stl_subset.h"
|
||||
#include "core/ordered_set.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// thanks Chromium
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define OS_MAC 1
|
||||
#elif defined(__linux__) // __APPLE__
|
||||
#define OS_LINUX 1
|
||||
#elif defined(_WIN32) // __APPLE__ || __linux__
|
||||
#define OS_WIN 1
|
||||
#else // __APPLE__ || __linux__ || _WIN32
|
||||
#error Please add support for your platform in core/build_config.h
|
||||
#endif // else for __APPLE__ || __linux__ || _WIN32
|
||||
|
||||
// For access to standard POSIXish features, use OS_POSIX instead of a
|
||||
// more specific macro.
|
||||
#if defined(OS_MAC) || defined(OS_LINUX)
|
||||
#define OS_POSIX 1
|
||||
#endif // OS_MAC || OS_LINUX
|
||||
|
||||
// Compiler detection.
|
||||
#if defined(__clang__)
|
||||
#define COMPILER_CLANG 1
|
||||
#elif defined(__GNUC__) // __clang__
|
||||
#define COMPILER_GCC 1
|
||||
#elif defined(_MSC_VER) // __clang__ || __GNUC__
|
||||
#define COMPILER_MSVC 1
|
||||
#else // _MSC_VER || __clang__ || __GNUC__
|
||||
#error Please add support for your compiler in core/build_config.h
|
||||
#endif // else for _MSC_VER || __clang__ || __GNUC__
|
||||
|
||||
// Processor architecture detection.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define ARCH_CPU_X86_FAMILY 1
|
||||
#define ARCH_CPU_X86_64 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define ARCH_CPU_X86_FAMILY 1
|
||||
#define ARCH_CPU_X86 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#else
|
||||
#error Please add support for your architecture in core/build_config.h
|
||||
#endif
|
||||
|
||||
#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define FORCE_INLINE inline
|
||||
#endif
|
||||
|
||||
#include <climits>
|
||||
static_assert(CHAR_BIT == 8, "Not supported char size.");
|
|
@ -208,7 +208,8 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
|
|||
auto frame = frameToShow();
|
||||
t_assert(frame != nullptr);
|
||||
|
||||
if (ms) {
|
||||
auto shouldBePaused = !ms;
|
||||
if (!shouldBePaused) {
|
||||
frame->displayed.storeRelease(1);
|
||||
if (_autoPausedGif.loadAcquire()) {
|
||||
_autoPausedGif.storeRelease(0);
|
||||
|
@ -218,10 +219,10 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
frame->displayed.storeRelease(-1); // displayed, but should be paused
|
||||
frame->displayed.storeRelease(-1);
|
||||
}
|
||||
|
||||
int32 factor(cIntRetinaFactor());
|
||||
auto factor = cIntRetinaFactor();
|
||||
if (frame->pix.width() == outerw * factor && frame->pix.height() == outerh * factor) {
|
||||
moveToNextShow();
|
||||
return frame->pix;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "ui/twidget.h"
|
||||
#include "ui/effects/rect_shadow.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/effects/panel_animation.h"
|
||||
|
||||
namespace InlineBots {
|
||||
namespace Layout {
|
||||
|
@ -60,7 +61,6 @@ class EmojiColorPicker : public TWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiColorPicker();
|
||||
|
||||
void showEmoji(uint32 code);
|
||||
|
@ -345,6 +345,7 @@ private:
|
|||
void appendSet(Sets &to, uint64 setId, AppendSkip skip);
|
||||
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
int stickersLeft() const;
|
||||
QRect stickerRect(int tab, int sel);
|
||||
|
||||
int32 _maxHeight;
|
||||
|
@ -510,8 +511,6 @@ public:
|
|||
return _hiding || _hideTimer.isActive();
|
||||
}
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_slide(float64 ms, bool timer);
|
||||
void step_icons(uint64 ms, bool timer);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
|
@ -535,13 +534,12 @@ public:
|
|||
bool ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return s_inner.inlineResultsShown();
|
||||
}
|
||||
|
||||
void showAnimated();
|
||||
void setOrigin(Ui::PanelAnimation::Origin origin);
|
||||
void showAnimated(Ui::PanelAnimation::Origin origin);
|
||||
void hideAnimated();
|
||||
|
||||
~EmojiPan();
|
||||
|
||||
public slots:
|
||||
void refreshStickers();
|
||||
|
||||
|
@ -549,8 +547,6 @@ private slots:
|
|||
void hideByTimerOrLeave();
|
||||
void refreshSavedGifs();
|
||||
|
||||
void hideFinish();
|
||||
|
||||
void onWndActiveChanged();
|
||||
|
||||
void onScrollEmoji();
|
||||
|
@ -581,6 +577,33 @@ signals:
|
|||
void updateStickers();
|
||||
|
||||
private:
|
||||
void paintContent(Painter &p);
|
||||
void performSwitch();
|
||||
|
||||
style::margins innerPadding() const;
|
||||
|
||||
// Rounded rect which has shadow around it.
|
||||
QRect innerRect() const;
|
||||
|
||||
// Inner rect with removed st::buttonRadius from top and bottom.
|
||||
// This one is allowed to be not rounded.
|
||||
QRect horizontalRect() const;
|
||||
|
||||
// Inner rect with removed st::buttonRadius from left and right.
|
||||
// This one is allowed to be not rounded.
|
||||
QRect verticalRect() const;
|
||||
|
||||
QImage grabForPanelAnimation();
|
||||
void startShowAnimation();
|
||||
void startOpacityAnimation(bool hiding);
|
||||
void prepareCache();
|
||||
|
||||
class Container;
|
||||
void opacityAnimationCallback();
|
||||
|
||||
void hideFinished();
|
||||
void showStarted();
|
||||
|
||||
bool preventAutoHide() const;
|
||||
void installSetDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installSetFail(uint64 setId, const RPCError &error);
|
||||
|
@ -599,7 +622,6 @@ private:
|
|||
void updateContentHeight();
|
||||
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child);
|
||||
void prepareShowHideCache();
|
||||
|
||||
void updateSelected();
|
||||
void updateIcons();
|
||||
|
@ -614,15 +636,20 @@ private:
|
|||
bool _horizontal = false;
|
||||
|
||||
int32 _width, _height, _bottom;
|
||||
|
||||
Ui::PanelAnimation::Origin _origin = Ui::PanelAnimation::Origin::BottomRight;
|
||||
std_::unique_ptr<Ui::PanelAnimation> _showAnimation;
|
||||
FloatAnimation _a_show;
|
||||
|
||||
bool _hiding = false;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity = { 0. };
|
||||
Animation _a_appearance;
|
||||
|
||||
FloatAnimation _a_opacity;
|
||||
QTimer _hideTimer;
|
||||
bool _inPanelGrab = false;
|
||||
|
||||
Ui::RectShadow _shadow;
|
||||
class SlideAnimation;
|
||||
std_::unique_ptr<SlideAnimation> _slideAnimation;
|
||||
FloatAnimation _a_slide;
|
||||
|
||||
ChildWidget<Ui::IconButton> _recent;
|
||||
ChildWidget<Ui::IconButton> _people;
|
||||
|
@ -651,12 +678,8 @@ private:
|
|||
anim::ivalue _iconSelX = { 0, 0 };
|
||||
uint64 _iconsStartAnim = 0;
|
||||
|
||||
bool _stickersShown = false;
|
||||
bool _emojiShown = true;
|
||||
bool _shownFromInlineQuery = false;
|
||||
QPixmap _fromCache, _toCache;
|
||||
anim::ivalue a_fromCoord, a_toCoord;
|
||||
anim::fvalue a_fromAlpha, a_toAlpha;
|
||||
Animation _a_slide;
|
||||
|
||||
ScrollArea e_scroll;
|
||||
internal::EmojiPanInner e_inner;
|
||||
|
|
|
@ -117,12 +117,18 @@ emojiCategoryTravel: IconButton(emojiCategory) { icon: emojiTravel; }
|
|||
emojiCategoryObjects: IconButton(emojiCategory) { icon: emojiObjects; }
|
||||
emojiCategorySymbols: IconButton(emojiCategory) { icon: emojiSymbols; }
|
||||
|
||||
emojiPanAnimation: PanelAnimation(defaultPanelAnimation) {
|
||||
fadeBg: emojiPanBg;
|
||||
}
|
||||
emojiPanPadding: 12px;
|
||||
emojiPanSize: size(45px, 41px);
|
||||
emojiPanWidth: 345px;
|
||||
emojiPanMaxHeight: 366px;
|
||||
emojiPanShowDuration: 200;
|
||||
emojiPanDuration: 200;
|
||||
emojiPanHover: #f0f4f7;
|
||||
emojiPanSlideDuration: 200;
|
||||
emojiPanSlideDelta: 0; // between hide start and show start
|
||||
|
||||
emojiPanHeader: 42px;
|
||||
emojiPanHeaderFont: semiboldFont;
|
||||
|
|
|
@ -213,7 +213,110 @@ void startManager();
|
|||
void stopManager();
|
||||
void registerClipManager(Media::Clip::Manager *manager);
|
||||
|
||||
inline uint64 shifted(uint32 components) {
|
||||
FORCE_INLINE int interpolate(int a, int b, float64 b_ratio) {
|
||||
return qRound(a + float64(b - a) * b_ratio);
|
||||
}
|
||||
|
||||
#ifdef ARCH_CPU_32_BITS
|
||||
#define SHIFTED_USE_32BIT
|
||||
#endif // ARCH_CPU_32_BITS
|
||||
|
||||
#ifdef SHIFTED_USE_32BIT
|
||||
|
||||
using ShiftedMultiplier = uint32;
|
||||
|
||||
struct Shifted {
|
||||
Shifted() = default;
|
||||
Shifted(uint32 low, uint32 high) : low(low), high(high) {
|
||||
}
|
||||
uint32 low = 0;
|
||||
uint32 high = 0;
|
||||
};
|
||||
|
||||
FORCE_INLINE Shifted operator+(Shifted a, Shifted b) {
|
||||
return Shifted(a.low + b.low, a.high + b.high);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted operator*(Shifted shifted, ShiftedMultiplier multiplier) {
|
||||
return Shifted(shifted.low * multiplier, shifted.high * multiplier);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted operator*(ShiftedMultiplier multiplier, Shifted shifted) {
|
||||
return Shifted(shifted.low * multiplier, shifted.high * multiplier);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted shifted(uint32 components) {
|
||||
return Shifted(
|
||||
(components & 0x000000FFU) | ((components & 0x0000FF00U) << 8),
|
||||
((components & 0x00FF0000U) >> 16) | ((components & 0xFF000000U) >> 8));
|
||||
}
|
||||
|
||||
FORCE_INLINE uint32 unshifted(Shifted components) {
|
||||
return ((components.low & 0x0000FF00U) >> 8)
|
||||
| ((components.low & 0xFF000000U) >> 16)
|
||||
| ((components.high & 0x0000FF00U) << 8)
|
||||
| (components.high & 0xFF000000U);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted reshifted(Shifted components) {
|
||||
return Shifted((components.low >> 8) & 0x00FF00FFU, (components.high >> 8) & 0x00FF00FFU);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted shifted(QColor color) {
|
||||
// Make it premultiplied.
|
||||
auto alpha = static_cast<uint32>((color.alpha() & 0xFF) + 1);
|
||||
auto components = Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
|
||||
static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(255) << 16));
|
||||
return reshifted(components * alpha);
|
||||
}
|
||||
|
||||
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
||||
return (components.high & 0x00FF0000U) >> 16;
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted non_premultiplied(QColor color) {
|
||||
return Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
|
||||
static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(color.alpha() & 0xFF) << 16));
|
||||
}
|
||||
|
||||
FORCE_INLINE QColor color(QColor a, QColor b, float64 b_ratio) {
|
||||
auto bOpacity = snap(interpolate(0, 255, b_ratio), 0, 255) + 1;
|
||||
auto aOpacity = (256 - bOpacity);
|
||||
auto components = (non_premultiplied(a) * aOpacity + non_premultiplied(b) * bOpacity);
|
||||
return {
|
||||
static_cast<int>((components.high >> 8) & 0xFF),
|
||||
static_cast<int>((components.low >> 24) & 0xFF),
|
||||
static_cast<int>((components.low >> 8) & 0xFF),
|
||||
static_cast<int>((components.high >> 24) & 0xFF),
|
||||
};
|
||||
}
|
||||
|
||||
#else // SHIFTED_USE_32BIT
|
||||
|
||||
using ShiftedMultiplier = uint64;
|
||||
|
||||
struct Shifted {
|
||||
Shifted() = default;
|
||||
Shifted(uint32 value) : value(value) {
|
||||
}
|
||||
Shifted(uint64 value) : value(value) {
|
||||
}
|
||||
uint64 value = 0;
|
||||
};
|
||||
|
||||
FORCE_INLINE Shifted operator+(Shifted a, Shifted b) {
|
||||
return Shifted(a.value + b.value);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted operator*(Shifted shifted, ShiftedMultiplier multiplier) {
|
||||
return Shifted(shifted.value * multiplier);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted operator*(ShiftedMultiplier multiplier, Shifted shifted) {
|
||||
return Shifted(shifted.value * multiplier);
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted shifted(uint32 components) {
|
||||
auto wide = static_cast<uint64>(components);
|
||||
return (wide & 0x00000000000000FFULL)
|
||||
| ((wide & 0x000000000000FF00ULL) << 8)
|
||||
|
@ -221,82 +324,93 @@ inline uint64 shifted(uint32 components) {
|
|||
| ((wide & 0x00000000FF000000ULL) << 24);
|
||||
}
|
||||
|
||||
inline uint32 unshifted(uint64 components) {
|
||||
return static_cast<uint32>((components & 0x000000000000FF00ULL) >> 8)
|
||||
| static_cast<uint32>((components & 0x00000000FF000000ULL) >> 16)
|
||||
| static_cast<uint32>((components & 0x0000FF0000000000ULL) >> 24)
|
||||
| static_cast<uint32>((components & 0xFF00000000000000ULL) >> 32);
|
||||
FORCE_INLINE uint32 unshifted(Shifted components) {
|
||||
return static_cast<uint32>((components.value & 0x000000000000FF00ULL) >> 8)
|
||||
| static_cast<uint32>((components.value & 0x00000000FF000000ULL) >> 16)
|
||||
| static_cast<uint32>((components.value & 0x0000FF0000000000ULL) >> 24)
|
||||
| static_cast<uint32>((components.value & 0xFF00000000000000ULL) >> 32);
|
||||
}
|
||||
|
||||
inline uint64 reshifted(uint64 components) {
|
||||
return (components >> 8) & 0x00FF00FF00FF00FFULL;
|
||||
FORCE_INLINE Shifted reshifted(Shifted components) {
|
||||
return (components.value >> 8) & 0x00FF00FF00FF00FFULL;
|
||||
}
|
||||
|
||||
inline int interpolate(int a, int b, float64 b_ratio) {
|
||||
return qRound(a + float64(b - a) * b_ratio);
|
||||
FORCE_INLINE Shifted shifted(QColor color) {
|
||||
// Make it premultiplied.
|
||||
auto alpha = static_cast<uint64>((color.alpha() & 0xFF) + 1);
|
||||
auto components = static_cast<uint64>(color.blue() & 0xFF)
|
||||
| (static_cast<uint64>(color.green() & 0xFF) << 16)
|
||||
| (static_cast<uint64>(color.red() & 0xFF) << 32)
|
||||
| (static_cast<uint64>(255) << 48);
|
||||
return reshifted(components * alpha);
|
||||
}
|
||||
|
||||
inline QColor color(QColor a, QColor b, float64 b_ratio) {
|
||||
FORCE_INLINE uint32 getAlpha(Shifted components) {
|
||||
return (components.value & 0x00FF000000000000ULL) >> 48;
|
||||
}
|
||||
|
||||
FORCE_INLINE Shifted non_premultiplied(QColor color) {
|
||||
return static_cast<uint64>(color.blue() & 0xFF)
|
||||
| (static_cast<uint64>(color.green() & 0xFF) << 16)
|
||||
| (static_cast<uint64>(color.red() & 0xFF) << 32)
|
||||
| (static_cast<uint64>(color.alpha() & 0xFF) << 48);
|
||||
}
|
||||
|
||||
FORCE_INLINE QColor color(QColor a, QColor b, float64 b_ratio) {
|
||||
auto bOpacity = snap(interpolate(0, 255, b_ratio), 0, 255) + 1;
|
||||
auto aOpacity = (256 - bOpacity);
|
||||
auto bBits = static_cast<uint64>(b.alpha() & 0xFF)
|
||||
| (static_cast<uint64>(b.red() & 0xFF) << 16)
|
||||
| (static_cast<uint64>(b.green() & 0xFF) << 32)
|
||||
| (static_cast<uint64>(b.blue() & 0xFF) << 48);
|
||||
auto aBits = static_cast<uint64>(a.alpha() & 0xFF)
|
||||
| (static_cast<uint64>(a.red() & 0xFF) << 16)
|
||||
| (static_cast<uint64>(a.green() & 0xFF) << 32)
|
||||
| (static_cast<uint64>(a.blue() & 0xFF) << 48);
|
||||
auto resultBits = (aBits * aOpacity + bBits * bOpacity) >> 8;
|
||||
auto components = (non_premultiplied(a) * aOpacity + non_premultiplied(b) * bOpacity);
|
||||
return {
|
||||
static_cast<int>((resultBits >> 16) & 0xFF),
|
||||
static_cast<int>((resultBits >> 32) & 0xFF),
|
||||
static_cast<int>((resultBits >> 48) & 0xFF),
|
||||
static_cast<int>(resultBits & 0xFF),
|
||||
static_cast<int>((components.value >> 40) & 0xFF),
|
||||
static_cast<int>((components.value >> 24) & 0xFF),
|
||||
static_cast<int>((components.value >> 8) & 0xFF),
|
||||
static_cast<int>((components.value >> 56) & 0xFF),
|
||||
};
|
||||
}
|
||||
|
||||
inline QColor color(const style::color &a, QColor b, float64 b_ratio) {
|
||||
#endif // SHIFTED_USE_32BIT
|
||||
|
||||
FORCE_INLINE QColor color(const style::color &a, QColor b, float64 b_ratio) {
|
||||
return color(a->c, b, b_ratio);
|
||||
}
|
||||
|
||||
inline QColor color(QColor a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QColor color(QColor a, const style::color &b, float64 b_ratio) {
|
||||
return color(a, b->c, b_ratio);
|
||||
}
|
||||
|
||||
inline QColor color(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QColor color(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
return color(a->c, b->c, b_ratio);
|
||||
}
|
||||
|
||||
inline QPen pen(QColor a, QColor b, float64 b_ratio) {
|
||||
FORCE_INLINE QPen pen(QColor a, QColor b, float64 b_ratio) {
|
||||
return color(a, b, b_ratio);
|
||||
}
|
||||
|
||||
inline QPen pen(const style::color &a, QColor b, float64 b_ratio) {
|
||||
FORCE_INLINE QPen pen(const style::color &a, QColor b, float64 b_ratio) {
|
||||
return (b_ratio > 0) ? pen(a->c, b, b_ratio) : a;
|
||||
}
|
||||
|
||||
inline QPen pen(QColor a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QPen pen(QColor a, const style::color &b, float64 b_ratio) {
|
||||
return (b_ratio < 1) ? pen(a, b->c, b_ratio) : b;
|
||||
}
|
||||
|
||||
inline QPen pen(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QPen pen(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
return (b_ratio > 0) ? ((b_ratio < 1) ? pen(a->c, b->c, b_ratio) : b) : a;
|
||||
}
|
||||
|
||||
inline QBrush brush(QColor a, QColor b, float64 b_ratio) {
|
||||
FORCE_INLINE QBrush brush(QColor a, QColor b, float64 b_ratio) {
|
||||
return color(a, b, b_ratio);
|
||||
}
|
||||
|
||||
inline QBrush brush(const style::color &a, QColor b, float64 b_ratio) {
|
||||
FORCE_INLINE QBrush brush(const style::color &a, QColor b, float64 b_ratio) {
|
||||
return (b_ratio > 0) ? brush(a->c, b, b_ratio) : a;
|
||||
}
|
||||
|
||||
inline QBrush brush(QColor a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QBrush brush(QColor a, const style::color &b, float64 b_ratio) {
|
||||
return (b_ratio < 1) ? brush(a, b->c, b_ratio) : b;
|
||||
}
|
||||
|
||||
inline QBrush brush(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
FORCE_INLINE QBrush brush(const style::color &a, const style::color &b, float64 b_ratio) {
|
||||
return (b_ratio > 0) ? ((b_ratio < 1) ? brush(a->c, b->c, b_ratio) : b) : a;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,64 +23,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
namespace Ui {
|
||||
|
||||
void PanelAnimation::setFinalImage(QImage &&finalImage, QRect inner) {
|
||||
void RoundShadowAnimation::start(int frameWidth, int frameHeight, float64 devicePixelRatio) {
|
||||
t_assert(!started());
|
||||
_finalImage = std_::move(finalImage).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
t_assert(!_finalImage.isNull());
|
||||
_finalWidth = _finalImage.width();
|
||||
_finalHeight = _finalImage.height();
|
||||
_finalInnerLeft = inner.x();
|
||||
_finalInnerTop = inner.y();
|
||||
_finalInnerWidth = inner.width();
|
||||
_finalInnerHeight = inner.height();
|
||||
_finalInnerRight = _finalInnerLeft + _finalInnerWidth;
|
||||
_finalInnerBottom = _finalInnerTop + _finalInnerHeight;
|
||||
t_assert(QRect(0, 0, _finalWidth, _finalHeight).contains(inner));
|
||||
|
||||
setStartWidth();
|
||||
setStartHeight();
|
||||
setStartAlpha();
|
||||
setStartFadeTop();
|
||||
createFadeMask();
|
||||
setWidthDuration();
|
||||
setHeightDuration();
|
||||
setAlphaDuration();
|
||||
setShadow();
|
||||
|
||||
auto checkCorner = [this, inner](Corner &corner) {
|
||||
if (!corner.valid()) return;
|
||||
if ((_startWidth >= 0 && _startWidth < _finalWidth)
|
||||
|| (_startHeight >= 0 && _startHeight < _finalHeight)) {
|
||||
t_assert(corner.width <= inner.width());
|
||||
t_assert(corner.height <= inner.height());
|
||||
}
|
||||
};
|
||||
checkCorner(_topLeft);
|
||||
checkCorner(_topRight);
|
||||
checkCorner(_bottomLeft);
|
||||
checkCorner(_bottomRight);
|
||||
_finalInts = reinterpret_cast<const uint32*>(_finalImage.constBits());
|
||||
_finalIntsPerLine = (_finalImage.bytesPerLine() >> 2);
|
||||
_finalIntsPerLineAdded = _finalIntsPerLine - _finalWidth;
|
||||
t_assert(_finalImage.depth() == static_cast<int>(sizeof(uint32) << 3));
|
||||
t_assert(_finalImage.bytesPerLine() == (_finalIntsPerLine << 2));
|
||||
t_assert(_finalIntsPerLineAdded >= 0);
|
||||
_frameWidth = frameWidth;
|
||||
_frameHeight = frameHeight;
|
||||
_frame = QImage(_frameWidth, _frameHeight, QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(devicePixelRatio);
|
||||
_frameIntsPerLine = (_frame.bytesPerLine() >> 2);
|
||||
_frameInts = reinterpret_cast<uint32*>(_frame.bits());
|
||||
_frameIntsPerLineAdded = _frameIntsPerLine - _frameWidth;
|
||||
t_assert(_frame.depth() == static_cast<int>(sizeof(uint32) << 3));
|
||||
t_assert(_frame.bytesPerLine() == (_frameIntsPerLine << 2));
|
||||
t_assert(_frameIntsPerLineAdded >= 0);
|
||||
}
|
||||
|
||||
void PanelAnimation::setShadow() {
|
||||
if (_skipShadow) return;
|
||||
|
||||
_shadow.extend = _st.shadow.extend * cIntRetinaFactor();
|
||||
_shadow.left = cloneImage(_st.shadow.left);
|
||||
void RoundShadowAnimation::setShadow(const style::Shadow &st) {
|
||||
_shadow.extend = st.extend * cIntRetinaFactor();
|
||||
_shadow.left = cloneImage(st.left);
|
||||
if (_shadow.valid()) {
|
||||
_shadow.topLeft = cloneImage(_st.shadow.topLeft);
|
||||
_shadow.top = cloneImage(_st.shadow.top);
|
||||
_shadow.topRight = cloneImage(_st.shadow.topRight);
|
||||
_shadow.right = cloneImage(_st.shadow.right);
|
||||
_shadow.bottomRight = cloneImage(_st.shadow.bottomRight);
|
||||
_shadow.bottom = cloneImage(_st.shadow.bottom);
|
||||
_shadow.bottomLeft = cloneImage(_st.shadow.bottomLeft);
|
||||
_shadow.topLeft = cloneImage(st.topLeft);
|
||||
_shadow.top = cloneImage(st.top);
|
||||
_shadow.topRight = cloneImage(st.topRight);
|
||||
_shadow.right = cloneImage(st.right);
|
||||
_shadow.bottomRight = cloneImage(st.bottomRight);
|
||||
_shadow.bottom = cloneImage(st.bottom);
|
||||
_shadow.bottomLeft = cloneImage(st.bottomLeft);
|
||||
t_assert(!_shadow.topLeft.isNull()
|
||||
&& !_shadow.top.isNull()
|
||||
&& !_shadow.topRight.isNull()
|
||||
|
@ -99,6 +66,214 @@ void PanelAnimation::setShadow() {
|
|||
}
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::setCornerMasks(QImage &&topLeft, QImage &&topRight, QImage &&bottomLeft, QImage &&bottomRight) {
|
||||
setCornerMask(_topLeft, std_::move(topLeft));
|
||||
setCornerMask(_topRight, std_::move(topRight));
|
||||
setCornerMask(_bottomLeft, std_::move(bottomLeft));
|
||||
setCornerMask(_bottomRight, std_::move(bottomRight));
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::setCornerMask(Corner &corner, QImage &&image) {
|
||||
t_assert(!started());
|
||||
corner.image = std_::move(image);
|
||||
if (corner.valid()) {
|
||||
corner.width = corner.image.width();
|
||||
corner.height = corner.image.height();
|
||||
corner.bytes = corner.image.constBits();
|
||||
corner.bytesPerPixel = (corner.image.depth() >> 3);
|
||||
corner.bytesPerLineAdded = corner.image.bytesPerLine() - corner.width * corner.bytesPerPixel;
|
||||
t_assert(corner.image.depth() == (corner.bytesPerPixel << 3));
|
||||
t_assert(corner.bytesPerLineAdded >= 0);
|
||||
} else {
|
||||
corner.width = corner.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QImage RoundShadowAnimation::cloneImage(const style::icon &source) {
|
||||
if (source.empty()) return QImage();
|
||||
|
||||
auto result = QImage(source.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&result);
|
||||
source.paint(p, 0, 0, source.width());
|
||||
}
|
||||
return std_::move(result);
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::paintCorner(Corner &corner, int left, int top) {
|
||||
auto mask = corner.bytes;
|
||||
auto bytesPerPixel = corner.bytesPerPixel;
|
||||
auto bytesPerLineAdded = corner.bytesPerLineAdded;
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - corner.width;
|
||||
for (auto y = 0; y != corner.height; ++y) {
|
||||
for (auto x = 0; x != corner.width; ++x) {
|
||||
auto alpha = static_cast<uint32>(*mask) + 1;
|
||||
*frameInts = anim::unshifted(anim::shifted(*frameInts) * alpha);
|
||||
++frameInts;
|
||||
mask += bytesPerPixel;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
mask += bytesPerLineAdded;
|
||||
}
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::paintShadow(int left, int top, int right, int bottom) {
|
||||
paintShadowCorner(left, top, _shadow.topLeft);
|
||||
paintShadowCorner(right - _shadow.topRight.width(), top, _shadow.topRight);
|
||||
paintShadowCorner(right - _shadow.bottomRight.width(), bottom - _shadow.bottomRight.height(), _shadow.bottomRight);
|
||||
paintShadowCorner(left, bottom - _shadow.bottomLeft.height(), _shadow.bottomLeft);
|
||||
paintShadowVertical(left, top + _shadow.topLeft.height(), bottom - _shadow.bottomLeft.height(), _shadow.left);
|
||||
paintShadowVertical(right - _shadow.right.width(), top + _shadow.topRight.height(), bottom - _shadow.bottomRight.height(), _shadow.right);
|
||||
paintShadowHorizontal(left + _shadow.topLeft.width(), right - _shadow.topRight.width(), top, _shadow.top);
|
||||
paintShadowHorizontal(left + _shadow.bottomLeft.width(), right - _shadow.bottomRight.width(), bottom - _shadow.bottom.height(), _shadow.bottom);
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::paintShadowCorner(int left, int top, const QImage &image) {
|
||||
auto imageWidth = image.width();
|
||||
auto imageHeight = image.height();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
auto imageIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
auto imageIntsPerLineAdded = imageIntsPerLine - imageWidth;
|
||||
if (left < 0) {
|
||||
auto shift = -base::take(left);
|
||||
imageWidth -= shift;
|
||||
imageInts += shift;
|
||||
}
|
||||
if (top < 0) {
|
||||
auto shift = -base::take(top);
|
||||
imageHeight -= shift;
|
||||
imageInts += shift * imageIntsPerLine;
|
||||
}
|
||||
if (left + imageWidth > _frameWidth) {
|
||||
imageWidth = _frameWidth - left;
|
||||
}
|
||||
if (top + imageHeight > _frameHeight) {
|
||||
imageHeight = _frameHeight - top;
|
||||
}
|
||||
if (imageWidth < 0 || imageHeight < 0) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - imageWidth;
|
||||
for (auto y = 0; y != imageHeight; ++y) {
|
||||
for (auto x = 0; x != imageWidth; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = qMax(_frameAlpha - int(source >> 24), 0);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + anim::shifted(*imageInts) * shadowAlpha);
|
||||
++frameInts;
|
||||
++imageInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts += imageIntsPerLineAdded;
|
||||
}
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::paintShadowVertical(int left, int top, int bottom, const QImage &image) {
|
||||
auto imageWidth = image.width();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
if (left < 0) {
|
||||
auto shift = -base::take(left);
|
||||
imageWidth -= shift;
|
||||
imageInts += shift;
|
||||
}
|
||||
if (top < 0) top = 0;
|
||||
accumulate_min(bottom, _frameHeight);
|
||||
accumulate_min(imageWidth, _frameWidth - left);
|
||||
if (imageWidth < 0 || bottom <= top) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - imageWidth;
|
||||
for (auto y = top; y != bottom; ++y) {
|
||||
for (auto x = 0; x != imageWidth; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = _frameAlpha - (source >> 24);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + anim::shifted(*imageInts) * shadowAlpha);
|
||||
++frameInts;
|
||||
++imageInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts -= imageWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void RoundShadowAnimation::paintShadowHorizontal(int left, int right, int top, const QImage &image) {
|
||||
auto imageHeight = image.height();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
auto imageIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
if (top < 0) {
|
||||
auto shift = -base::take(top);
|
||||
imageHeight -= shift;
|
||||
imageInts += shift * imageIntsPerLine;
|
||||
}
|
||||
if (left < 0) left = 0;
|
||||
accumulate_min(right, _frameWidth);
|
||||
accumulate_min(imageHeight, _frameHeight - top);
|
||||
if (imageHeight < 0 || right <= left) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - (right - left);
|
||||
for (auto y = 0; y != imageHeight; ++y) {
|
||||
auto imagePattern = anim::shifted(*imageInts);
|
||||
for (auto x = left; x != right; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = _frameAlpha - (source >> 24);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + imagePattern * shadowAlpha);
|
||||
++frameInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts += imageIntsPerLine;
|
||||
}
|
||||
}
|
||||
|
||||
void PanelAnimation::setFinalImage(QImage &&finalImage, QRect inner) {
|
||||
t_assert(!started());
|
||||
_finalImage = QPixmap::fromImage(std_::move(finalImage).convertToFormat(QImage::Format_ARGB32_Premultiplied), Qt::ColorOnly);
|
||||
|
||||
t_assert(!_finalImage.isNull());
|
||||
_finalWidth = _finalImage.width();
|
||||
_finalHeight = _finalImage.height();
|
||||
t_assert(!(_finalWidth % cIntRetinaFactor()));
|
||||
t_assert(!(_finalHeight % cIntRetinaFactor()));
|
||||
_finalInnerLeft = inner.x();
|
||||
_finalInnerTop = inner.y();
|
||||
_finalInnerWidth = inner.width();
|
||||
_finalInnerHeight = inner.height();
|
||||
t_assert(!(_finalInnerLeft % cIntRetinaFactor()));
|
||||
t_assert(!(_finalInnerTop % cIntRetinaFactor()));
|
||||
t_assert(!(_finalInnerWidth % cIntRetinaFactor()));
|
||||
t_assert(!(_finalInnerHeight % cIntRetinaFactor()));
|
||||
_finalInnerRight = _finalInnerLeft + _finalInnerWidth;
|
||||
_finalInnerBottom = _finalInnerTop + _finalInnerHeight;
|
||||
t_assert(QRect(0, 0, _finalWidth, _finalHeight).contains(inner));
|
||||
|
||||
setStartWidth();
|
||||
setStartHeight();
|
||||
setStartAlpha();
|
||||
setStartFadeTop();
|
||||
createFadeMask();
|
||||
setWidthDuration();
|
||||
setHeightDuration();
|
||||
setAlphaDuration();
|
||||
if (!_skipShadow) {
|
||||
setShadow(_st.shadow);
|
||||
}
|
||||
|
||||
auto checkCorner = [this, inner](Corner &corner) {
|
||||
if (!corner.valid()) return;
|
||||
if ((_startWidth >= 0 && _startWidth < _finalWidth)
|
||||
|| (_startHeight >= 0 && _startHeight < _finalHeight)) {
|
||||
t_assert(corner.width <= inner.width());
|
||||
t_assert(corner.height <= inner.height());
|
||||
}
|
||||
};
|
||||
checkCorner(_topLeft);
|
||||
checkCorner(_topRight);
|
||||
checkCorner(_bottomLeft);
|
||||
checkCorner(_bottomRight);
|
||||
}
|
||||
|
||||
void PanelAnimation::setStartWidth() {
|
||||
_startWidth = qRound(_st.startWidth * _finalInnerWidth);
|
||||
if (_startWidth >= 0) t_assert(_startWidth <= _finalInnerWidth);
|
||||
|
@ -120,30 +295,30 @@ void PanelAnimation::setStartFadeTop() {
|
|||
|
||||
void PanelAnimation::createFadeMask() {
|
||||
auto resultHeight = qRound(_finalImage.height() * _st.fadeHeight);
|
||||
if (auto remove = (resultHeight % cIntRetinaFactor())) {
|
||||
resultHeight -= remove;
|
||||
}
|
||||
auto finalAlpha = qRound(_st.fadeOpacity * 255);
|
||||
t_assert(finalAlpha >= 0 && finalAlpha < 256);
|
||||
auto result = QImage(1, resultHeight, QImage::Format_ARGB32_Premultiplied);
|
||||
auto result = QImage(cIntRetinaFactor(), resultHeight, QImage::Format_ARGB32_Premultiplied);
|
||||
auto ints = reinterpret_cast<uint32*>(result.bits());
|
||||
auto intsPerLine = (result.bytesPerLine() >> 2);
|
||||
auto intsPerLineAdded = (result.bytesPerLine() >> 2) - cIntRetinaFactor();
|
||||
auto up = (_origin == PanelAnimation::Origin::BottomLeft || _origin == PanelAnimation::Origin::BottomRight);
|
||||
auto from = up ? resultHeight : 0, to = resultHeight - from, delta = up ? -1 : 1;
|
||||
auto fadeFirstAlpha = up ? (finalAlpha + 1) : 1;
|
||||
auto fadeLastAlpha = up ? 1 : (finalAlpha + 1);
|
||||
_fadeFirst = QBrush(QColor(_st.fadeBg->c.red(), _st.fadeBg->c.green(), _st.fadeBg->c.blue(), (_st.fadeBg->c.alpha() * fadeFirstAlpha) >> 8));
|
||||
_fadeLast = QBrush(QColor(_st.fadeBg->c.red(), _st.fadeBg->c.green(), _st.fadeBg->c.blue(), (_st.fadeBg->c.alpha() * fadeLastAlpha) >> 8));
|
||||
for (auto y = from; y != to; y += delta) {
|
||||
auto alpha = static_cast<uint32>(finalAlpha * y) / resultHeight;
|
||||
*ints = (0xFFU << 24) | (alpha << 16) | (alpha << 8) | alpha;
|
||||
ints += intsPerLine;
|
||||
auto value = (0xFFU << 24) | (alpha << 16) | (alpha << 8) | alpha;
|
||||
for (auto x = 0; x != cIntRetinaFactor(); ++x) {
|
||||
*ints++ = value;
|
||||
}
|
||||
ints += intsPerLineAdded;
|
||||
}
|
||||
_fadeMask = style::colorizeImage(result, _st.fadeBg);
|
||||
_fadeMask = QPixmap::fromImage(style::colorizeImage(result, _st.fadeBg), Qt::ColorOnly);
|
||||
_fadeHeight = _fadeMask.height();
|
||||
_fadeInts = reinterpret_cast<const uint32*>(_fadeMask.constBits());
|
||||
_fadeIntsPerLine = (_fadeMask.bytesPerLine() >> 2);
|
||||
t_assert(_fadeMask.bytesPerLine() == (_fadeIntsPerLine << 2));
|
||||
}
|
||||
|
||||
void PanelAnimation::setCornerMasks(QImage &&topLeft, QImage &&topRight, QImage &&bottomLeft, QImage &&bottomRight) {
|
||||
setCornerMask(_topLeft, std_::move(topLeft));
|
||||
setCornerMask(_topRight, std_::move(topRight));
|
||||
setCornerMask(_bottomLeft, std_::move(bottomLeft));
|
||||
setCornerMask(_bottomRight, std_::move(bottomRight));
|
||||
}
|
||||
|
||||
void PanelAnimation::setSkipShadow(bool skipShadow) {
|
||||
|
@ -151,41 +326,6 @@ void PanelAnimation::setSkipShadow(bool skipShadow) {
|
|||
_skipShadow = skipShadow;
|
||||
}
|
||||
|
||||
void PanelAnimation::setCornerMask(Corner &corner, QImage &&image) {
|
||||
t_assert(!started());
|
||||
corner.image = std_::move(image);
|
||||
if (corner.valid()) {
|
||||
corner.width = corner.image.width();
|
||||
corner.height = corner.image.height();
|
||||
corner.bytes = corner.image.constBits();
|
||||
corner.bytesPerPixel = (corner.image.depth() >> 3);
|
||||
corner.bytesPerLineAdded = corner.image.bytesPerLine() - corner.width * corner.bytesPerPixel;
|
||||
t_assert(corner.image.depth() == (corner.bytesPerPixel << 3));
|
||||
t_assert(corner.bytesPerLineAdded >= 0);
|
||||
if (_startWidth >= 0) t_assert(corner.width <= _startWidth);
|
||||
if (_startHeight >= 0) t_assert(corner.height <= _startHeight);
|
||||
if (!_finalImage.isNull()) {
|
||||
t_assert(corner.width <= _finalInnerWidth);
|
||||
t_assert(corner.height <= _finalInnerHeight);
|
||||
}
|
||||
} else {
|
||||
corner.width = corner.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QImage PanelAnimation::cloneImage(const style::icon &source) {
|
||||
if (source.empty()) return QImage();
|
||||
|
||||
auto result = QImage(source.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&result);
|
||||
source.paint(p, 0, 0, source.width());
|
||||
}
|
||||
return std_::move(result);
|
||||
}
|
||||
|
||||
void PanelAnimation::setWidthDuration() {
|
||||
_widthDuration = _st.widthDuration;
|
||||
t_assert(_widthDuration >= 0.);
|
||||
|
@ -207,35 +347,46 @@ void PanelAnimation::setAlphaDuration() {
|
|||
}
|
||||
|
||||
void PanelAnimation::start() {
|
||||
t_assert(!started());
|
||||
t_assert(!_finalImage.isNull());
|
||||
_frame = QImage(_finalWidth, _finalHeight, QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(_finalImage.devicePixelRatio());
|
||||
_frameIntsPerLine = (_frame.bytesPerLine() >> 2);
|
||||
_frameInts = reinterpret_cast<uint32*>(_frame.bits());
|
||||
_frameIntsPerLineAdded = _frameIntsPerLine - _finalWidth;
|
||||
t_assert(_frame.depth() == static_cast<int>(sizeof(uint32) << 3));
|
||||
t_assert(_frame.bytesPerLine() == (_frameIntsPerLine << 2));
|
||||
t_assert(_frameIntsPerLineAdded >= 0);
|
||||
RoundShadowAnimation::start(_finalWidth, _finalHeight, _finalImage.devicePixelRatio());
|
||||
auto checkCorner = [this](const Corner &corner) {
|
||||
if (!corner.valid()) return;
|
||||
if (_startWidth >= 0) t_assert(corner.width <= _startWidth);
|
||||
if (_startHeight >= 0) t_assert(corner.height <= _startHeight);
|
||||
t_assert(corner.width <= _finalInnerWidth);
|
||||
t_assert(corner.height <= _finalInnerHeight);
|
||||
};
|
||||
checkCorner(_topLeft);
|
||||
checkCorner(_topRight);
|
||||
checkCorner(_bottomLeft);
|
||||
checkCorner(_bottomRight);
|
||||
}
|
||||
|
||||
const QImage &PanelAnimation::getFrame(float64 dt, float64 opacity) {
|
||||
void PanelAnimation::paintFrame(QPainter &p, int x, int y, int outerWidth, float64 dt, float64 opacity) {
|
||||
t_assert(started());
|
||||
t_assert(dt >= 0.);
|
||||
|
||||
auto &transition = anim::easeOutCirc;
|
||||
constexpr auto finalAlpha = 256;
|
||||
auto alpha = (dt >= _alphaDuration) ? finalAlpha : anim::interpolate(_startAlpha + 1, finalAlpha, transition(1., dt / _alphaDuration));
|
||||
_frameAlpha = anim::interpolate(0, alpha, opacity);
|
||||
if (dt < _alphaDuration) opacity *= transition(1., dt / _alphaDuration);
|
||||
_frameAlpha = anim::interpolate(1, 256, opacity);
|
||||
|
||||
auto frameWidth = (_startWidth < 0 || dt >= _widthDuration) ? _finalInnerWidth : anim::interpolate(_startWidth, _finalInnerWidth, transition(1., dt / _widthDuration));
|
||||
auto frameHeight = (_startHeight < 0 || dt >= _heightDuration) ? _finalInnerHeight : anim::interpolate(_startHeight, _finalInnerHeight, transition(1., dt / _heightDuration));
|
||||
if (auto decrease = (frameWidth % cIntRetinaFactor())) {
|
||||
frameWidth -= decrease;
|
||||
}
|
||||
if (auto decrease = (frameHeight % cIntRetinaFactor())) {
|
||||
frameHeight -= decrease;
|
||||
}
|
||||
auto frameLeft = (_origin == Origin::TopLeft || _origin == Origin::BottomLeft) ? _finalInnerLeft : (_finalInnerRight - frameWidth);
|
||||
auto frameTop = (_origin == Origin::TopLeft || _origin == Origin::TopRight) ? _finalInnerTop : (_finalInnerBottom - frameHeight);
|
||||
auto frameRight = frameLeft + frameWidth;
|
||||
auto frameBottom = frameTop + frameHeight;
|
||||
|
||||
auto fadeTop = (_fadeHeight > 0) ? snap(anim::interpolate(_startFadeTop, _finalInnerHeight, transition(1., dt)), 0, frameHeight) : frameHeight;
|
||||
if (auto decrease = (fadeTop % cIntRetinaFactor())) {
|
||||
fadeTop -= decrease;
|
||||
}
|
||||
auto fadeBottom = (fadeTop < frameHeight) ? qMin(fadeTop + _fadeHeight, frameHeight) : frameHeight;
|
||||
auto fadeSkipLines = 0;
|
||||
if (_origin == Origin::BottomLeft || _origin == Origin::BottomRight) {
|
||||
|
@ -247,97 +398,97 @@ const QImage &PanelAnimation::getFrame(float64 dt, float64 opacity) {
|
|||
fadeTop += frameTop;
|
||||
fadeBottom += frameTop;
|
||||
|
||||
auto finalInts = _finalInts + frameLeft + frameTop * _finalIntsPerLine;
|
||||
if (opacity < 1.) {
|
||||
_frame.fill(Qt::transparent);
|
||||
}
|
||||
{
|
||||
Painter p(&_frame);
|
||||
p.setOpacity(opacity);
|
||||
auto painterFrameLeft = frameLeft / cIntRetinaFactor();
|
||||
auto painterFrameTop = frameTop / cIntRetinaFactor();
|
||||
auto painterFadeBottom = fadeBottom / cIntRetinaFactor();
|
||||
p.drawPixmap(painterFrameLeft, painterFrameTop, _finalImage, frameLeft, frameTop, frameWidth, frameHeight);
|
||||
if (_fadeHeight) {
|
||||
if (frameTop != fadeTop) {
|
||||
p.fillRect(painterFrameLeft, painterFrameTop, frameWidth, fadeTop - frameTop, _fadeFirst);
|
||||
}
|
||||
if (fadeTop != fadeBottom) {
|
||||
auto painterFadeTop = fadeTop / cIntRetinaFactor();
|
||||
auto painterFrameWidth = frameWidth / cIntRetinaFactor();
|
||||
auto painterFrameHeight = frameHeight / cIntRetinaFactor();
|
||||
p.drawPixmap(painterFrameLeft, painterFadeTop, painterFrameWidth, painterFadeBottom - painterFadeTop, _fadeMask, 0, fadeSkipLines, cIntRetinaFactor(), fadeBottom - fadeTop);
|
||||
}
|
||||
if (fadeBottom != frameBottom) {
|
||||
p.fillRect(painterFrameLeft, painterFadeBottom, frameWidth, frameBottom - fadeBottom, _fadeLast);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto frameInts = _frameInts + frameLeft + frameTop * _frameIntsPerLine;
|
||||
auto finalIntsPerLineAdd = (_finalWidth - frameWidth) + _finalIntsPerLineAdded;
|
||||
auto frameIntsPerLineAdd = (_finalWidth - frameWidth) + _frameIntsPerLineAdded;
|
||||
|
||||
// Draw frameWidth x fadeTop with fade first color.
|
||||
auto fadeInts = _fadeInts + fadeSkipLines * _fadeIntsPerLine;
|
||||
auto fadeWithMasterAlpha = [this](uint32 fade) {
|
||||
auto fadeAlphaAddition = (256 - (fade >> 24));
|
||||
auto fadePattern = anim::shifted(fade);
|
||||
return [this, fadeAlphaAddition, fadePattern](uint32 source) {
|
||||
auto sourceAlpha = (source >> 24) + 1;
|
||||
auto sourcePattern = anim::shifted(source);
|
||||
auto mixedPattern = anim::reshifted(fadePattern * sourceAlpha + sourcePattern * fadeAlphaAddition);
|
||||
return anim::unshifted(mixedPattern * _frameAlpha);
|
||||
};
|
||||
};
|
||||
if (frameTop != fadeTop) {
|
||||
// Take the fade components from the first line of the fade mask.
|
||||
auto withMasterAlpha = fadeWithMasterAlpha(_fadeInts ? *_fadeInts : 0);
|
||||
for (auto y = frameTop; y != fadeTop; ++y) {
|
||||
for (auto x = frameLeft; x != frameRight; ++x) {
|
||||
*frameInts++ = withMasterAlpha(*finalInts++);
|
||||
}
|
||||
finalInts += finalIntsPerLineAdd;
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw frameWidth x (fadeBottom - fadeTop) with fade gradient.
|
||||
for (auto y = fadeTop; y != fadeBottom; ++y) {
|
||||
auto withMasterAlpha = fadeWithMasterAlpha(*fadeInts);
|
||||
for (auto x = frameLeft; x != frameRight; ++x) {
|
||||
*frameInts++ = withMasterAlpha(*finalInts++);
|
||||
}
|
||||
finalInts += finalIntsPerLineAdd;
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
fadeInts += _fadeIntsPerLine;
|
||||
}
|
||||
|
||||
// Draw frameWidth x (frameBottom - fadeBottom) with fade final color.
|
||||
if (fadeBottom != frameBottom) {
|
||||
// Take the fade components from the last line of the fade mask.
|
||||
auto withMasterAlpha = fadeWithMasterAlpha(*(fadeInts - _fadeIntsPerLine));
|
||||
for (auto y = fadeBottom; y != frameBottom; ++y) {
|
||||
for (auto x = frameLeft; x != frameRight; ++x) {
|
||||
*frameInts++ = withMasterAlpha(*finalInts++);
|
||||
}
|
||||
finalInts += finalIntsPerLineAdd;
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw corners
|
||||
auto innerLeft = qMax(_finalInnerLeft, frameLeft);
|
||||
auto innerTop = qMax(_finalInnerTop, frameTop);
|
||||
auto innerRight = qMin(_finalInnerRight, frameRight);
|
||||
auto innerBottom = qMin(_finalInnerBottom, frameBottom);
|
||||
if (innerLeft != _finalInnerLeft || innerTop != _finalInnerTop) {
|
||||
paintCorner(_topLeft, innerLeft, innerTop);
|
||||
}
|
||||
if (innerRight != _finalInnerRight || innerTop != _finalInnerTop) {
|
||||
paintCorner(_topRight, innerRight - _topRight.width, innerTop);
|
||||
}
|
||||
if (innerLeft != _finalInnerLeft || innerBottom != _finalInnerBottom) {
|
||||
paintCorner(_bottomLeft, innerLeft, innerBottom - _bottomLeft.height);
|
||||
}
|
||||
if (innerRight != _finalInnerRight || innerBottom != _finalInnerBottom) {
|
||||
paintCorner(_bottomRight, innerRight - _bottomRight.width, innerBottom - _bottomRight.height);
|
||||
}
|
||||
paintCorner(_topLeft, frameLeft, frameTop);
|
||||
paintCorner(_topRight, frameRight - _topRight.width, frameTop);
|
||||
paintCorner(_bottomLeft, frameLeft, frameBottom - _bottomLeft.height);
|
||||
paintCorner(_bottomRight, frameRight - _bottomRight.width, frameBottom - _bottomRight.height);
|
||||
|
||||
// Fill the rest with transparent
|
||||
if (frameTop) {
|
||||
memset(_frameInts, 0, _frameIntsPerLine * frameTop * sizeof(uint32));
|
||||
// Draw shadow upon the transparent
|
||||
auto outerLeft = frameLeft;
|
||||
auto outerTop = frameTop;
|
||||
auto outerRight = frameRight;
|
||||
auto outerBottom = frameBottom;
|
||||
if (_shadow.valid()) {
|
||||
outerLeft -= _shadow.extend.left();
|
||||
outerTop -= _shadow.extend.top();
|
||||
outerRight += _shadow.extend.right();
|
||||
outerBottom += _shadow.extend.bottom();
|
||||
}
|
||||
auto widthLeft = (_finalWidth - frameRight);
|
||||
if (frameLeft || widthLeft) {
|
||||
auto frameInts = _frameInts + frameTop * _frameIntsPerLine;
|
||||
for (auto y = frameTop; y != frameBottom; ++y) {
|
||||
memset(frameInts, 0, frameLeft * sizeof(uint32));
|
||||
memset(frameInts + frameLeft + frameWidth, 0, widthLeft * sizeof(uint32));
|
||||
frameInts += _frameIntsPerLine;
|
||||
if (cIntRetinaFactor() > 1) {
|
||||
if (auto skipLeft = (outerLeft % cIntRetinaFactor())) {
|
||||
outerLeft -= skipLeft;
|
||||
}
|
||||
if (auto skipTop = (outerTop % cIntRetinaFactor())) {
|
||||
outerTop -= skipTop;
|
||||
}
|
||||
if (auto skipRight = (outerRight % cIntRetinaFactor())) {
|
||||
outerRight += (cIntRetinaFactor() - skipRight);
|
||||
}
|
||||
if (auto skipBottom = (outerBottom % cIntRetinaFactor())) {
|
||||
outerBottom += (cIntRetinaFactor() - skipBottom);
|
||||
}
|
||||
}
|
||||
if (auto heightLeft = (_finalHeight - frameBottom)) {
|
||||
memset(_frameInts + frameBottom * _frameIntsPerLine, 0, _frameIntsPerLine * heightLeft * sizeof(uint32));
|
||||
|
||||
if (opacity == 1.) {
|
||||
// Fill above the frame top with transparent.
|
||||
auto fillTopInts = (_frameInts + outerTop * _frameIntsPerLine + outerLeft);
|
||||
auto fillWidth = (outerRight - outerLeft) * sizeof(uint32);
|
||||
for (auto fillTop = frameTop - outerTop; fillTop != 0; --fillTop) {
|
||||
memset(fillTopInts, 0, fillWidth);
|
||||
fillTopInts += _frameIntsPerLine;
|
||||
}
|
||||
|
||||
// Fill to the left and to the right of the frame with transparent.
|
||||
auto fillLeft = (frameLeft - outerLeft) * sizeof(uint32);
|
||||
auto fillRight = (outerRight - frameRight) * sizeof(uint32);
|
||||
if (fillLeft || fillRight) {
|
||||
auto fillInts = _frameInts + frameTop * _frameIntsPerLine;
|
||||
for (auto y = frameTop; y != frameBottom; ++y) {
|
||||
memset(fillInts + outerLeft, 0, fillLeft);
|
||||
memset(fillInts + frameRight, 0, fillRight);
|
||||
fillInts += _frameIntsPerLine;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill below the frame bottom with transparent.
|
||||
auto fillBottomInts = (_frameInts + frameBottom * _frameIntsPerLine + outerLeft);
|
||||
for (auto fillBottom = outerBottom - frameBottom; fillBottom != 0; --fillBottom) {
|
||||
memset(fillBottomInts, 0, fillWidth);
|
||||
fillBottomInts += _frameIntsPerLine;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw shadow
|
||||
if (_shadow.valid()) {
|
||||
paintShadow(innerLeft, innerTop, innerRight, innerBottom);
|
||||
paintShadow(outerLeft, outerTop, outerRight, outerBottom);
|
||||
}
|
||||
|
||||
// Debug
|
||||
|
@ -353,140 +504,7 @@ const QImage &PanelAnimation::getFrame(float64 dt, float64 opacity) {
|
|||
// frameInts += _frameIntsPerLineAdded;
|
||||
//}
|
||||
|
||||
return _frame;
|
||||
}
|
||||
|
||||
void PanelAnimation::paintCorner(Corner &corner, int left, int top) {
|
||||
auto mask = corner.bytes;
|
||||
auto bytesPerPixel = corner.bytesPerPixel;
|
||||
auto bytesPerLineAdded = corner.bytesPerLineAdded;
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - corner.width;
|
||||
for (auto y = 0; y != corner.height; ++y) {
|
||||
for (auto x = 0; x != corner.width; ++x) {
|
||||
auto alpha = static_cast<uint32>(*mask) + 1;
|
||||
*frameInts = anim::unshifted(anim::shifted(*frameInts) * alpha);
|
||||
++frameInts;
|
||||
mask += bytesPerPixel;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
mask += bytesPerLineAdded;
|
||||
}
|
||||
}
|
||||
|
||||
void PanelAnimation::paintShadow(int left, int top, int right, int bottom) {
|
||||
left -= _shadow.extend.left();
|
||||
top -= _shadow.extend.top();
|
||||
right += _shadow.extend.right();
|
||||
bottom += _shadow.extend.bottom();
|
||||
paintShadowCorner(left, top, _shadow.topLeft);
|
||||
paintShadowCorner(right - _shadow.topRight.width(), top, _shadow.topRight);
|
||||
paintShadowCorner(right - _shadow.bottomRight.width(), bottom - _shadow.bottomRight.height(), _shadow.bottomRight);
|
||||
paintShadowCorner(left, bottom - _shadow.bottomLeft.height(), _shadow.bottomLeft);
|
||||
paintShadowVertical(left, top + _shadow.topLeft.height(), bottom - _shadow.bottomLeft.height(), _shadow.left);
|
||||
paintShadowVertical(right - _shadow.right.width(), top + _shadow.topRight.height(), bottom - _shadow.bottomRight.height(), _shadow.right);
|
||||
paintShadowHorizontal(left + _shadow.topLeft.width(), right - _shadow.topRight.width(), top, _shadow.top);
|
||||
paintShadowHorizontal(left + _shadow.bottomLeft.width(), right - _shadow.bottomRight.width(), bottom - _shadow.bottom.height(), _shadow.bottom);
|
||||
}
|
||||
|
||||
void PanelAnimation::paintShadowCorner(int left, int top, const QImage &image) {
|
||||
auto imageWidth = image.width();
|
||||
auto imageHeight = image.height();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
auto imageIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
auto imageIntsPerLineAdded = imageIntsPerLine - imageWidth;
|
||||
if (left < 0) {
|
||||
auto shift = -base::take(left);
|
||||
imageWidth -= shift;
|
||||
imageInts += shift;
|
||||
}
|
||||
if (top < 0) {
|
||||
auto shift = -base::take(top);
|
||||
imageHeight -= shift;
|
||||
imageInts += shift * imageIntsPerLine;
|
||||
}
|
||||
if (left + imageWidth > _finalWidth) {
|
||||
imageWidth = _finalWidth - left;
|
||||
}
|
||||
if (top + imageHeight > _finalHeight) {
|
||||
imageHeight = _finalHeight - top;
|
||||
}
|
||||
if (imageWidth < 0 || imageHeight < 0) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - imageWidth;
|
||||
for (auto y = 0; y != imageHeight; ++y) {
|
||||
for (auto x = 0; x != imageWidth; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = _frameAlpha - (source >> 24);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + anim::shifted(*imageInts) * shadowAlpha);
|
||||
++frameInts;
|
||||
++imageInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts += imageIntsPerLineAdded;
|
||||
}
|
||||
}
|
||||
|
||||
void PanelAnimation::paintShadowVertical(int left, int top, int bottom, const QImage &image) {
|
||||
auto imageWidth = image.width();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
if (left < 0) {
|
||||
auto shift = -base::take(left);
|
||||
imageWidth -= shift;
|
||||
imageInts += shift;
|
||||
}
|
||||
if (top < 0) top = 0;
|
||||
if (bottom > _finalHeight) bottom = _finalHeight;
|
||||
if (left + imageWidth > _finalWidth) {
|
||||
imageWidth = _finalWidth - left;
|
||||
}
|
||||
if (imageWidth < 0 || bottom <= top) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - imageWidth;
|
||||
for (auto y = top; y != bottom; ++y) {
|
||||
for (auto x = 0; x != imageWidth; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = _frameAlpha - (source >> 24);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + anim::shifted(*imageInts) * shadowAlpha);
|
||||
++frameInts;
|
||||
++imageInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts -= imageWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void PanelAnimation::paintShadowHorizontal(int left, int right, int top, const QImage &image) {
|
||||
auto imageHeight = image.height();
|
||||
auto imageInts = reinterpret_cast<const uint32*>(image.constBits());
|
||||
auto imageIntsPerLine = (image.bytesPerLine() >> 2);
|
||||
if (top < 0) {
|
||||
auto shift = -base::take(top);
|
||||
imageHeight -= shift;
|
||||
imageInts += shift * imageIntsPerLine;
|
||||
}
|
||||
if (left < 0) left = 0;
|
||||
if (right > _finalWidth) right = _finalWidth;
|
||||
if (top + imageHeight > _finalHeight) {
|
||||
imageHeight = _finalHeight - top;
|
||||
}
|
||||
if (imageHeight < 0 || right <= left) return;
|
||||
|
||||
auto frameInts = _frameInts + top * _frameIntsPerLine + left;
|
||||
auto frameIntsPerLineAdd = _frameIntsPerLine - (right - left);
|
||||
for (auto y = 0; y != imageHeight; ++y) {
|
||||
auto imagePattern = anim::shifted(*imageInts);
|
||||
for (auto x = left; x != right; ++x) {
|
||||
auto source = *frameInts;
|
||||
auto shadowAlpha = _frameAlpha - (source >> 24);
|
||||
*frameInts = anim::unshifted(anim::shifted(source) * 256 + imagePattern * shadowAlpha);
|
||||
++frameInts;
|
||||
}
|
||||
frameInts += frameIntsPerLineAdd;
|
||||
imageInts += imageIntsPerLine;
|
||||
}
|
||||
p.drawImage(rtlpoint(x + (outerLeft / cIntRetinaFactor()), y + (outerTop / cIntRetinaFactor()), outerWidth), _frame, QRect(outerLeft, outerTop, outerRight - outerLeft, outerBottom - outerTop));
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -24,34 +24,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
namespace Ui {
|
||||
|
||||
class PanelAnimation {
|
||||
class RoundShadowAnimation {
|
||||
public:
|
||||
enum class Origin {
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
};
|
||||
PanelAnimation(const style::PanelAnimation &st, Origin origin) : _st(st), _origin(origin) {
|
||||
}
|
||||
|
||||
void setFinalImage(QImage &&finalImage, QRect inner);
|
||||
void setCornerMasks(QImage &&topLeft, QImage &&topRight, QImage &&bottomLeft, QImage &&bottomRight);
|
||||
void setSkipShadow(bool skipShadow);
|
||||
|
||||
void start();
|
||||
const QImage &getFrame(float64 dt, float64 opacity);
|
||||
|
||||
private:
|
||||
void setStartWidth();
|
||||
void setStartHeight();
|
||||
void setStartAlpha();
|
||||
void setStartFadeTop();
|
||||
void createFadeMask();
|
||||
void setWidthDuration();
|
||||
void setHeightDuration();
|
||||
void setAlphaDuration();
|
||||
void setShadow();
|
||||
protected:
|
||||
void start(int frameWidth, int frameHeight, float64 devicePixelRatio);
|
||||
void setShadow(const style::Shadow &st);
|
||||
|
||||
bool started() const {
|
||||
return !_frame.isNull();
|
||||
|
@ -86,13 +65,54 @@ private:
|
|||
void paintShadowVertical(int left, int top, int bottom, const QImage &image);
|
||||
void paintShadowHorizontal(int left, int right, int top, const QImage &image);
|
||||
|
||||
Shadow _shadow;
|
||||
|
||||
Corner _topLeft;
|
||||
Corner _topRight;
|
||||
Corner _bottomLeft;
|
||||
Corner _bottomRight;
|
||||
|
||||
QImage _frame;
|
||||
uint32 *_frameInts = nullptr;
|
||||
int _frameWidth = 0;
|
||||
int _frameHeight = 0;
|
||||
int _frameAlpha = 0; // recounted each getFrame()
|
||||
int _frameIntsPerLine = 0;
|
||||
int _frameIntsPerLineAdded = 0;
|
||||
|
||||
};
|
||||
|
||||
class PanelAnimation : public RoundShadowAnimation {
|
||||
public:
|
||||
enum class Origin {
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
};
|
||||
PanelAnimation(const style::PanelAnimation &st, Origin origin) : _st(st), _origin(origin) {
|
||||
}
|
||||
|
||||
void setFinalImage(QImage &&finalImage, QRect inner);
|
||||
void setSkipShadow(bool skipShadow);
|
||||
|
||||
void start();
|
||||
void paintFrame(QPainter &p, int x, int y, int outerWidth, float64 dt, float64 opacity);
|
||||
|
||||
private:
|
||||
void setStartWidth();
|
||||
void setStartHeight();
|
||||
void setStartAlpha();
|
||||
void setStartFadeTop();
|
||||
void createFadeMask();
|
||||
void setWidthDuration();
|
||||
void setHeightDuration();
|
||||
void setAlphaDuration();
|
||||
|
||||
const style::PanelAnimation &_st;
|
||||
Origin _origin = Origin::TopLeft;
|
||||
|
||||
QImage _finalImage;
|
||||
const uint32 *_finalInts = nullptr;
|
||||
int _finalIntsPerLine = 0;
|
||||
int _finalIntsPerLineAdded = 0;
|
||||
QPixmap _finalImage;
|
||||
int _finalWidth = 0;
|
||||
int _finalHeight = 0;
|
||||
int _finalInnerLeft = 0;
|
||||
|
@ -102,33 +122,20 @@ private:
|
|||
int _finalInnerWidth = 0;
|
||||
int _finalInnerHeight = 0;
|
||||
|
||||
Shadow _shadow;
|
||||
bool _skipShadow = false;
|
||||
int _startWidth = -1;
|
||||
int _startHeight = -1;
|
||||
int _startAlpha = 0;
|
||||
|
||||
int _startFadeTop = 0;
|
||||
QImage _fadeMask;
|
||||
QPixmap _fadeMask;
|
||||
int _fadeHeight = 0;
|
||||
const uint32 *_fadeInts = nullptr;
|
||||
int _fadeIntsPerLine = 0;
|
||||
|
||||
Corner _topLeft;
|
||||
Corner _topRight;
|
||||
Corner _bottomLeft;
|
||||
Corner _bottomRight;
|
||||
QBrush _fadeFirst, _fadeLast;
|
||||
|
||||
float64 _widthDuration = 1.;
|
||||
float64 _heightDuration = 1.;
|
||||
float64 _alphaDuration = 1.;
|
||||
|
||||
QImage _frame;
|
||||
uint32 *_frameInts = nullptr;
|
||||
int _frameAlpha = 0; // recounted each getFrame()
|
||||
int _frameIntsPerLine = 0;
|
||||
int _frameIntsPerLineAdded = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -85,15 +85,7 @@ void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect
|
|||
auto height = srcRect.height();
|
||||
t_assert(outResult && outResult->rect().contains(QRect(dstPoint, srcRect.size())));
|
||||
|
||||
auto initialAlpha = c.alpha() + 1;
|
||||
auto red = (c.red() * initialAlpha) >> 8;
|
||||
auto green = (c.green() * initialAlpha) >> 8;
|
||||
auto blue = (c.blue() * initialAlpha) >> 8;
|
||||
auto alpha = (255 * initialAlpha) >> 8;
|
||||
auto pattern = static_cast<uint64>(blue)
|
||||
| (static_cast<uint64>(green) << 16)
|
||||
| (static_cast<uint64>(red) << 32)
|
||||
| (static_cast<uint64>(alpha) << 48);
|
||||
auto pattern = anim::shifted(c);
|
||||
|
||||
auto resultBytesPerPixel = (src.depth() >> 3);
|
||||
auto resultIntsPerPixel = 1;
|
||||
|
|
|
@ -110,7 +110,7 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
|||
auto ms = getms();
|
||||
if (_a_show.animating(ms)) {
|
||||
if (auto opacity = _a_opacity.current(ms, _hiding ? 0. : 1.)) {
|
||||
p.drawImage(0, 0, _showAnimation->getFrame(_a_show.current(1.), opacity));
|
||||
_showAnimation->paintFrame(p, 0, 0, width(), _a_show.current(1.), opacity);
|
||||
}
|
||||
} else if (_a_opacity.animating(ms)) {
|
||||
p.setOpacity(_a_opacity.current(0.));
|
||||
|
@ -118,10 +118,11 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
|||
} else if (_hiding || isHidden()) {
|
||||
hideFinished();
|
||||
} else if (_showAnimation) {
|
||||
p.drawImage(0, 0, _showAnimation->getFrame(1., 1.));
|
||||
_showAnimation->paintFrame(p, 0, 0, width(), 1., 1.);
|
||||
_showAnimation.reset();
|
||||
showChildren();
|
||||
} else {
|
||||
if (!_cache.isNull()) _cache = QPixmap();
|
||||
auto inner = rect().marginsRemoved(_st.padding);
|
||||
Shadow::paint(p, inner, width(), _st.shadow);
|
||||
App::roundRect(p, inner, _st.bg, ImageRoundRadius::Small);
|
||||
|
@ -207,6 +208,9 @@ void InnerDropdown::prepareCache() {
|
|||
_cache = myGrab(this);
|
||||
_showAnimation = base::take(showAnimationData);
|
||||
_a_show = base::take(showAnimation);
|
||||
if (_a_show.animating()) {
|
||||
hideChildren();
|
||||
}
|
||||
}
|
||||
|
||||
void InnerDropdown::startOpacityAnimation(bool hiding) {
|
||||
|
@ -270,7 +274,7 @@ void InnerDropdown::opacityAnimationCallback() {
|
|||
if (_hiding) {
|
||||
_hiding = false;
|
||||
hideFinished();
|
||||
} else {
|
||||
} else if (!_a_show.animating()) {
|
||||
showChildren();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ void PopupMenu::paintEvent(QPaintEvent *e) {
|
|||
auto ms = getms();
|
||||
if (_a_show.animating(ms)) {
|
||||
if (auto opacity = _a_opacity.current(ms, _hiding ? 0. : 1.)) {
|
||||
p.drawImage(0, 0, _showAnimation->getFrame(_a_show.current(1.), opacity));
|
||||
_showAnimation->paintFrame(p, 0, 0, width(), _a_show.current(1.), opacity);
|
||||
}
|
||||
} else if (_a_opacity.animating(ms)) {
|
||||
p.setOpacity(_a_opacity.current(0.));
|
||||
|
@ -117,7 +117,7 @@ void PopupMenu::paintEvent(QPaintEvent *e) {
|
|||
} else if (_hiding || isHidden()) {
|
||||
hideFinished();
|
||||
} else if (_showAnimation) {
|
||||
p.drawImage(0, 0, _showAnimation->getFrame(1., 1.));
|
||||
_showAnimation->paintFrame(p, 0, 0, width(), 1., 1.);
|
||||
_showAnimation.reset();
|
||||
showChildren();
|
||||
} else {
|
||||
|
|
|
@ -201,6 +201,7 @@
|
|||
'<(src_loc)/boxes/stickers_box.h',
|
||||
'<(src_loc)/boxes/usernamebox.cpp',
|
||||
'<(src_loc)/boxes/usernamebox.h',
|
||||
'<(src_loc)/core/build_config.h',
|
||||
'<(src_loc)/core/basic_types.h',
|
||||
'<(src_loc)/core/click_handler.cpp',
|
||||
'<(src_loc)/core/click_handler.h',
|
||||
|
|
Loading…
Reference in New Issue