185 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // This file is part of Desktop App Toolkit,
 | |
| // a set of libraries for developing nice desktop applications.
 | |
| //
 | |
| // For license and copyright information please follow this link:
 | |
| // https://github.com/desktop-app/legal/blob/master/LEGAL
 | |
| //
 | |
| #include "ui/widgets/side_bar_button.h"
 | |
| 
 | |
| #include "ui/effects/ripple_animation.h"
 | |
| 
 | |
| #include <QtGui/QtEvents>
 | |
| 
 | |
| namespace Ui {
 | |
| namespace {
 | |
| 
 | |
| constexpr auto kMaxLabelLines = 3;
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| SideBarButton::SideBarButton(
 | |
| 	not_null<QWidget*> parent,
 | |
| 	const QString &title,
 | |
| 	const style::SideBarButton &st)
 | |
| : RippleButton(parent, st.ripple)
 | |
| , _st(st)
 | |
| , _text(_st.minTextWidth) {
 | |
| 	_text.setText(_st.style, title);
 | |
| 	setAttribute(Qt::WA_OpaquePaintEvent);
 | |
| 
 | |
| 	style::PaletteChanged(
 | |
| 	) | rpl::start_with_next([=] {
 | |
| 		_iconCache = _iconCacheActive = QImage();
 | |
| 		update();
 | |
| 	}, lifetime());
 | |
| }
 | |
| 
 | |
| void SideBarButton::setActive(bool active) {
 | |
| 	if (_active == active) {
 | |
| 		return;
 | |
| 	}
 | |
| 	_active = active;
 | |
| 	update();
 | |
| }
 | |
| 
 | |
| void SideBarButton::setBadge(const QString &badge, bool muted) {
 | |
| 	if (_badge.toString() == badge && _badgeMuted == muted) {
 | |
| 		return;
 | |
| 	}
 | |
| 	_badge.setText(_st.badgeStyle, badge);
 | |
| 	_badgeMuted = muted;
 | |
| 	const auto width = badge.isEmpty()
 | |
| 		? 0
 | |
| 		: std::max(_st.badgeHeight, _badge.maxWidth() + 2 * _st.badgeSkip);
 | |
| 	if (_iconCacheBadgeWidth != width) {
 | |
| 		_iconCacheBadgeWidth = width;
 | |
| 		_iconCache = _iconCacheActive = QImage();
 | |
| 	}
 | |
| 	update();
 | |
| }
 | |
| 
 | |
| void SideBarButton::setIconOverride(
 | |
| 		const style::icon *iconOverride,
 | |
| 		const style::icon *iconOverrideActive) {
 | |
| 	_iconOverride = iconOverride;
 | |
| 	_iconOverrideActive = iconOverrideActive;
 | |
| 	update();
 | |
| }
 | |
| 
 | |
| int SideBarButton::resizeGetHeight(int newWidth) {
 | |
| 	auto result = _st.minHeight;
 | |
| 	const auto text = std::min(
 | |
| 		_text.countHeight(newWidth - _st.textSkip * 2),
 | |
| 		_st.style.font->height * kMaxLabelLines);
 | |
| 	const auto add = text - _st.style.font->height;
 | |
| 	return result + std::max(add, 0);
 | |
| }
 | |
| 
 | |
| void SideBarButton::paintEvent(QPaintEvent *e) {
 | |
| 	auto p = Painter(this);
 | |
| 	const auto clip = e->rect();
 | |
| 
 | |
| 	p.fillRect(clip, _active ? _st.textBgActive : _st.textBg);
 | |
| 
 | |
| 	RippleButton::paintRipple(p, 0, 0);
 | |
| 
 | |
| 	const auto &icon = computeIcon();
 | |
| 	const auto x = (_st.iconPosition.x() < 0)
 | |
| 		? (width() - icon.width()) / 2
 | |
| 		: _st.iconPosition.x();
 | |
| 	const auto y = (_st.iconPosition.y() < 0)
 | |
| 		? (height() - icon.height()) / 2
 | |
| 		: _st.iconPosition.y();
 | |
| 	if (_iconCacheBadgeWidth) {
 | |
| 		validateIconCache();
 | |
| 		p.drawImage(x, y, _active ? _iconCacheActive : _iconCache);
 | |
| 	} else {
 | |
| 		icon.paint(p, x, y, width());
 | |
| 	}
 | |
| 	p.setPen(_active ? _st.textFgActive : _st.textFg);
 | |
| 	_text.drawElided(
 | |
| 		p,
 | |
| 		_st.textSkip,
 | |
| 		_st.textTop,
 | |
| 		(width() - 2 * _st.textSkip),
 | |
| 		kMaxLabelLines,
 | |
| 		style::al_top);
 | |
| 
 | |
| 	if (_iconCacheBadgeWidth) {
 | |
| 		const auto desiredLeft = width() / 2 + _st.badgePosition.x();
 | |
| 		const auto x = std::min(
 | |
| 			desiredLeft,
 | |
| 			width() - _iconCacheBadgeWidth - st::defaultScrollArea.width);
 | |
| 		const auto y = _st.badgePosition.y();
 | |
| 
 | |
| 		auto hq = PainterHighQualityEnabler(p);
 | |
| 		p.setPen(Qt::NoPen);
 | |
| 		p.setBrush((_badgeMuted && !_active)
 | |
| 			? _st.badgeBgMuted
 | |
| 			: _st.badgeBg);
 | |
| 		const auto r = _st.badgeHeight / 2;
 | |
| 		p.drawRoundedRect(x, y, _iconCacheBadgeWidth, _st.badgeHeight, r, r);
 | |
| 
 | |
| 		p.setPen(_st.badgeFg);
 | |
| 		_badge.draw(
 | |
| 			p,
 | |
| 			x + (_iconCacheBadgeWidth - _badge.maxWidth()) / 2,
 | |
| 			y + (_st.badgeHeight - _st.badgeStyle.font->height) / 2,
 | |
| 			width());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const style::icon &SideBarButton::computeIcon() const {
 | |
| 	return _active
 | |
| 		? (_iconOverrideActive
 | |
| 			? *_iconOverrideActive
 | |
| 			: !_st.iconActive.empty()
 | |
| 			? _st.iconActive
 | |
| 			: _iconOverride
 | |
| 			? *_iconOverride
 | |
| 			: _st.icon)
 | |
| 		: _iconOverride
 | |
| 		? *_iconOverride
 | |
| 		: _st.icon;
 | |
| }
 | |
| 
 | |
| void SideBarButton::validateIconCache() {
 | |
| 	Expects(_st.iconPosition.x() < 0);
 | |
| 
 | |
| 	if (!(_active ? _iconCacheActive : _iconCache).isNull()) {
 | |
| 		return;
 | |
| 	}
 | |
| 	const auto &icon = computeIcon();
 | |
| 	auto image = QImage(
 | |
| 		icon.size() * style::DevicePixelRatio(),
 | |
| 		QImage::Format_ARGB32_Premultiplied);
 | |
| 	image.setDevicePixelRatio(style::DevicePixelRatio());
 | |
| 	image.fill(Qt::transparent);
 | |
| 	{
 | |
| 		auto p = QPainter(&image);
 | |
| 		icon.paint(p, 0, 0, icon.width());
 | |
| 		p.setCompositionMode(QPainter::CompositionMode_Source);
 | |
| 		p.setBrush(Qt::transparent);
 | |
| 		auto pen = QPen(Qt::transparent);
 | |
| 		pen.setWidth(2 * _st.badgeStroke);
 | |
| 		p.setPen(pen);
 | |
| 		auto hq = PainterHighQualityEnabler(p);
 | |
| 		const auto desiredLeft = (icon.width() / 2) + _st.badgePosition.x();
 | |
| 		const auto x = std::min(
 | |
| 			desiredLeft,
 | |
| 			(width()
 | |
| 				- _iconCacheBadgeWidth
 | |
| 				- st::defaultScrollArea.width
 | |
| 				- (width() / 2)
 | |
| 				+ (icon.width() / 2)));
 | |
| 		const auto top = (_st.iconPosition.y() >= 0)
 | |
| 			? _st.iconPosition.y()
 | |
| 			: (height() - icon.height()) / 2;
 | |
| 		const auto y = _st.badgePosition.y() - top;
 | |
| 		const auto r = _st.badgeHeight / 2.;
 | |
| 		p.drawRoundedRect(x, y, _iconCacheBadgeWidth, _st.badgeHeight, r, r);
 | |
| 	}
 | |
| 	(_active ? _iconCacheActive : _iconCache) = std::move(image);
 | |
| }
 | |
| 
 | |
| } // namespace Ui
 | 
