// 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 namespace Ui { namespace { constexpr auto kMaxLabelLines = 3; } // namespace SideBarButton::SideBarButton( not_null 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