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