void paintUnreadBadge(Painter &p, const QRect &rect, const UnreadBadgeStyle &st) { t_assert(rect.height() == st.size); int index = (st.muted ? 0x03 : 0x00) + (st.active ? 0x02 : (st.selected ? 0x01 : 0x00)); int size = st.size, sizehalf = size / 2; unreadBadgeStyle.createIfNull(); auto badgeData = unreadBadgeStyle->sizes; if (st.sizeId > 0) { t_assert(st.sizeId < UnreadBadgeSizesCount); badgeData = &unreadBadgeStyle->sizes[st.sizeId]; } auto bg = unreadBadgeStyle->bg[index]; if (badgeData->left[index].isNull()) { int imgsize = size * cIntRetinaFactor(), imgsizehalf = sizehalf * cIntRetinaFactor(); createCircleMask(badgeData, size); badgeData->left[index] = App::pixmapFromImageInPlace(colorizeCircleHalf(badgeData, imgsize, imgsizehalf, 0, bg)); badgeData->right[index] = App::pixmapFromImageInPlace(colorizeCircleHalf(badgeData, imgsize, imgsizehalf, imgsize - imgsizehalf, bg)); } int bar = rect.width() - 2 * sizehalf; p.drawPixmap(rect.x(), rect.y(), badgeData->left[index]); if (bar) { p.fillRect(rect.x() + sizehalf, rect.y(), bar, rect.height(), bg); } p.drawPixmap(rect.x() + sizehalf + bar, rect.y(), badgeData->right[index]); }
bool FadeAnimation::paint(Painter &p) { if (_cache.isNull()) return false; const auto cache = _cache; auto opacity = _animation.value(_visible ? 1. : 0.); p.setOpacity(opacity); if (_scale < 1.) { PainterHighQualityEnabler hq(p); auto targetRect = QRect( (1 - kWideScale) / 2 * _size.width(), (1 - kWideScale) / 2 * _size.height(), kWideScale * _size.width(), kWideScale * _size.height()); auto scale = opacity + (1. - opacity) * _scale; auto shownWidth = anim::interpolate( (1 - kWideScale) / 2 * _size.width(), 0, scale); auto shownHeight = anim::interpolate( (1 - kWideScale) / 2 * _size.height(), 0, scale); auto margins = QMargins( shownWidth, shownHeight, shownWidth, shownHeight); p.drawPixmap(targetRect.marginsAdded(margins), cache); } else { p.drawPixmap(0, 0, cache); } return true; }
void SlideAnimation::paintFrame(Painter &p, int x, int y, int outerWidth) { auto dt = _animation.value(1.); if (!animating()) return; auto easeOut = anim::easeOutCirc(1., dt); auto easeIn = anim::easeInCirc(1., dt); auto arrivingAlpha = easeIn; auto departingAlpha = 1. - easeOut; auto leftCoord = (_slideLeft ? anim::interpolate(-_leftSnapshotWidth, 0, easeOut) : anim::interpolate(0, -_leftSnapshotWidth, easeIn)); auto leftAlpha = (_slideLeft ? arrivingAlpha : departingAlpha); auto rightCoord = (_slideLeft ? anim::interpolate(0, _rightSnapshotWidth, easeIn) : anim::interpolate(_rightSnapshotWidth, 0, easeOut)); auto rightAlpha = (_slideLeft ? departingAlpha : arrivingAlpha); if (_overflowHidden) { auto leftWidth = (_leftSnapshotWidth + leftCoord); if (leftWidth > 0) { p.setOpacity(leftAlpha); p.drawPixmap(x, y, leftWidth, _leftSnapshotHeight, _leftSnapshot, (_leftSnapshot.width() - leftWidth * cIntRetinaFactor()), 0, leftWidth * cIntRetinaFactor(), _leftSnapshot.height()); } auto rightWidth = _rightSnapshotWidth - rightCoord; if (rightWidth > 0) { p.setOpacity(rightAlpha); p.drawPixmap(x + rightCoord, y, _rightSnapshot, 0, 0, rightWidth * cIntRetinaFactor(), _rightSnapshot.height()); } } else { p.setOpacity(leftAlpha); p.drawPixmap(x + leftCoord, y, _leftSnapshot); p.setOpacity(rightAlpha); p.drawPixmap(x + rightCoord, y, _rightSnapshot); } }
void PeerData::paintUserpicSquare(Painter &p, int x, int y, int size) const { if (auto userpic = currentUserpic()) { p.drawPixmap(x, y, userpic->pix(size, size)); } else { _userpicEmpty->paintSquare(p, x, y, x + size + x, size); } }
void PeerData::paintUserpicRounded(Painter &p, int x, int y, int size) const { if (auto userpic = currentUserpic()) { p.drawPixmap(x, y, userpic->pixRounded(size, size, ImageRoundRadius::Small)); } else { _userpicEmpty->paintRounded(p, x, y, x + size + x, size); } }
bool MultiSelect::Inner::Item::paintCached(Painter &p, int x, int y, int outerWidth) { PainterHighQualityEnabler hq(p); auto opacity = _visibility.current(_hiding ? 0. : 1.); auto scale = opacity + _st.minScale * (1. - opacity); auto height = opacity * _cache.height() / _cache.devicePixelRatio(); auto width = opacity * _cache.width() / _cache.devicePixelRatio(); p.setOpacity(opacity); p.drawPixmap(rtlrect(x + (_width - width) / 2., y + (_st.height - height) / 2., width, height, outerWidth), _cache); p.setOpacity(1.); return true; }
void HistoryPhoto::drawGrouped( Painter &p, const QRect &clip, TextSelection selection, crl::time ms, const QRect &geometry, RectParts corners, not_null<uint64*> cacheKey, not_null<QPixmap*> cache) const { _data->automaticLoad(_realParent->fullId(), _parent->data()); validateGroupedCache(geometry, corners, cacheKey, cache); const auto selected = (selection == FullSelection); const auto loaded = _data->loaded(); const auto displayLoading = _data->displayLoading(); const auto bubble = _parent->hasBubble(); if (displayLoading) { ensureAnimation(); if (!_animation->radial.animating()) { _animation->radial.start(_data->progress()); } } const auto radial = isRadialAnimation(); if (!bubble) { // App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } p.drawPixmap(geometry.topLeft(), *cache); if (selected) { const auto roundRadius = ImageRoundRadius::Large; App::complexOverlayRect(p, geometry, roundRadius, corners); } const auto displayState = radial || (!loaded && !_data->loading()) || _data->waitingForAlbum(); if (displayState) { const auto radialOpacity = radial ? _animation->radial.opacity() : 1.; const auto backOpacity = (loaded && !_data->uploading()) ? radialOpacity : 1.; const auto radialSize = st::historyGroupRadialSize; const auto inner = QRect( geometry.x() + (geometry.width() - radialSize) / 2, geometry.y() + (geometry.height() - radialSize) / 2, radialSize, radialSize); p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgDateImgBgSelected); } else if (isThumbAnimation()) { auto over = _animation->a_thumbOver.value(1.); p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, over)); } else { auto over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); } p.setOpacity(backOpacity * p.opacity()); { PainterHighQualityEnabler hq(p); p.drawEllipse(inner); } const auto icon = [&]() -> const style::icon* { if (_data->waitingForAlbum()) { return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting); } else if (radial || _data->loading()) { if (_data->uploading() || _data->large()->location().valid()) { return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel); } return nullptr; } return &(selected ? st::historyFileThumbDownloadSelected : st::historyFileThumbDownload); }(); const auto previous = [&]() -> const style::icon* { if (_data->waitingForAlbum()) { return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel); } return nullptr; }(); p.setOpacity(backOpacity); if (icon) { if (previous && radialOpacity > 0. && radialOpacity < 1.) { PaintInterpolatedIcon(p, *icon, *previous, radialOpacity, inner); } else { icon->paintInCenter(p, inner); } } p.setOpacity(1); if (radial) { const auto line = st::historyGroupRadialLine; const auto rinner = inner.marginsRemoved({ line, line, line, line }); const auto color = selected ? st::historyFileThumbRadialFgSelected : st::historyFileThumbRadialFg; _animation->radial.draw(p, rinner, line, color); } } }
void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_realParent->fullId(), _parent->data()); auto selected = (selection == FullSelection); auto loaded = _data->loaded(); auto displayLoading = _data->displayLoading(); auto inWebPage = (_parent->media() != this); auto paintx = 0, painty = 0, paintw = width(), painth = height(); auto bubble = _parent->hasBubble(); auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right(); if (displayLoading) { ensureAnimation(); if (!_animation->radial.animating()) { _animation->radial.start(_data->progress()); } } const auto radial = isRadialAnimation(); auto rthumb = rtlrect(paintx, painty, paintw, painth, width()); if (_serviceWidth > 0) { const auto pix = [&] { if (loaded) { return _data->large()->pixCircled(_realParent->fullId(), _pixw, _pixh); } else if (_data->thumbnail()->loaded()) { return _data->thumbnail()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh); } else if (_data->thumbnailSmall()->loaded()) { return _data->thumbnailSmall()->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh); } else if (const auto blurred = _data->thumbnailInline()) { return blurred->pixBlurredCircled(_realParent->fullId(), _pixw, _pixh); } else { return QPixmap(); } }(); p.drawPixmap(rthumb.topLeft(), pix); } else { if (bubble) { if (!_caption.isEmpty()) { painth -= st::mediaCaptionSkip + _caption.countHeight(captionw); if (isBubbleBottom()) { painth -= st::msgPadding.bottom(); } rthumb = rtlrect(paintx, painty, paintw, painth, width()); } } else { App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } auto inWebPage = (_parent->media() != this); auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None) | ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None)); const auto pix = [&] { if (loaded) { return _data->large()->pixSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners); } else if (_data->thumbnail()->loaded()) { return _data->thumbnail()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners); } else if (_data->thumbnailSmall()->loaded()) { return _data->thumbnailSmall()->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners); } else if (const auto blurred = _data->thumbnailInline()) { return blurred->pixBlurredSingle(_realParent->fullId(), _pixw, _pixh, paintw, painth, roundRadius, roundCorners); } else { return QPixmap(); } }(); p.drawPixmap(rthumb.topLeft(), pix); if (selected) { App::complexOverlayRect(p, rthumb, roundRadius, roundCorners); } } if (radial || (!loaded && !_data->loading())) { const auto radialOpacity = (radial && loaded && !_data->uploading()) ? _animation->radial.opacity() : 1.; QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgDateImgBgSelected); } else if (isThumbAnimation()) { auto over = _animation->a_thumbOver.value(1.); p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, over)); } else { auto over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); } p.setOpacity(radialOpacity * p.opacity()); { PainterHighQualityEnabler hq(p); p.drawEllipse(inner); } p.setOpacity(radialOpacity); auto icon = [&]() -> const style::icon* { if (radial || _data->loading()) { if (_data->uploading() || _data->large()->location().valid()) { return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel); } return nullptr; } return &(selected ? st::historyFileThumbDownloadSelected : st::historyFileThumbDownload); }(); if (icon) { icon->paintInCenter(p, inner); } p.setOpacity(1); if (radial) { QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::historyFileThumbRadialFgSelected : st::historyFileThumbRadialFg); } } // date if (!_caption.isEmpty()) { auto outbg = _parent->hasOutLayout(); p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg)); _caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); } else if (!inWebPage) { auto fullRight = paintx + paintw; auto fullBottom = painty + painth; if (needInfoDisplay()) { _parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayType::Image); } if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); _parent->drawRightAction(p, fastShareLeft, fastShareTop, 2 * paintx + paintw); } } }
void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const { if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_realParent->fullId(), _parent->data()); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); bool selected = (selection == FullSelection); auto paintx = 0, painty = 0, paintw = width(), painth = height(); bool bubble = _parent->hasBubble(); int captionw = paintw - st::msgPadding.left() - st::msgPadding.right(); if (displayLoading) { ensureAnimation(); if (!_animation->radial.animating()) { _animation->radial.start(_data->progress()); } } updateStatusText(); bool radial = isRadialAnimation(ms); if (bubble) { if (!_caption.isEmpty()) { painth -= st::mediaCaptionSkip + _caption.countHeight(captionw); if (isBubbleBottom()) { painth -= st::msgPadding.bottom(); } } } else { App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners); } auto inWebPage = (_parent->media() != this); auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None) | ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None)); QRect rthumb(rtlrect(paintx, painty, paintw, painth, width())); const auto good = _data->goodThumbnail(); if (good && good->loaded()) { p.drawPixmap(rthumb.topLeft(), good->pixSingle({}, _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); } else { if (good) { good->load({}); } p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners)); } if (selected) { App::complexOverlayRect(p, rthumb, roundRadius, roundCorners); } QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); p.setPen(Qt::NoPen); if (selected) { p.setBrush(st::msgDateImgBgSelected); } else if (isThumbAnimation(ms)) { auto over = _animation->a_thumbOver.current(); p.setBrush(anim::brush(st::msgDateImgBg, st::msgDateImgBgOver, over)); } else { bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); } { PainterHighQualityEnabler hq(p); p.drawEllipse(inner); } if (!selected && _animation) { p.setOpacity(1); } auto icon = ([this, radial, selected, loaded]() -> const style::icon * { if (loaded && !radial) { return &(selected ? st::historyFileThumbPlaySelected : st::historyFileThumbPlay); } else if (radial || _data->loading()) { if (_parent->data()->id > 0 || _data->uploading()) { return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel); } return nullptr; } return &(selected ? st::historyFileThumbDownloadSelected : st::historyFileThumbDownload); })(); if (icon) { icon->paintInCenter(p, inner); } if (radial) { QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::historyFileThumbRadialFgSelected : st::historyFileThumbRadialFg); } auto statusX = paintx + st::msgDateImgDelta + st::msgDateImgPadding.x(), statusY = painty + st::msgDateImgDelta + st::msgDateImgPadding.y(); auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); auto statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); App::roundRect(p, rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, width()), selected ? st::msgDateImgBgSelected : st::msgDateImgBg, selected ? DateSelectedCorners : DateCorners); p.setFont(st::normalFont); p.setPen(st::msgDateImgFg); p.drawTextLeft(statusX, statusY, width(), _statusText, statusW - 2 * st::msgDateImgPadding.x()); // date if (!_caption.isEmpty()) { auto outbg = _parent->hasOutLayout(); p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg)); _caption.draw(p, st::msgPadding.left(), painty + painth + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); } else if (_parent->media() == this) { auto fullRight = paintx + paintw, fullBottom = painty + painth; _parent->drawInfo(p, fullRight, fullBottom, 2 * paintx + paintw, selected, InfoDisplayType::Image); if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); _parent->drawRightAction(p, fastShareLeft, fastShareTop, 2 * paintx + paintw); } } }