TextState HistoryPhoto::textState(QPoint point, StateRequest request) const { auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; } auto paintx = 0, painty = 0, paintw = width(), painth = height(); auto bubble = _parent->hasBubble(); if (bubble && !_caption.isEmpty()) { const auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right(); painth -= _caption.countHeight(captionw); if (isBubbleBottom()) { painth -= st::msgPadding.bottom(); } if (QRect(st::msgPadding.left(), painth, captionw, height() - painth).contains(point)) { result = TextState(_parent, _caption.getState( point - QPoint(st::msgPadding.left(), painth), captionw, request.forText())); return result; } painth -= st::mediaCaptionSkip; } if (QRect(paintx, painty, paintw, painth).contains(point)) { if (_data->uploading()) { result.link = _cancell; } else if (_data->loaded()) { result.link = _openl; } else if (_data->loading()) { if (_data->large()->location().valid()) { result.link = _cancell; } } else { result.link = _savel; } } if (_caption.isEmpty() && _parent->media() == this) { auto fullRight = paintx + paintw; auto fullBottom = painty + painth; if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { result.cursor = CursorState::Date; } if (!bubble && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) { result.link = _parent->rightActionLink(); } } } return result; }
HistoryView::TextState HistoryGroupedMedia::textState( QPoint point, StateRequest request) const { auto result = getPartState(point, request); if (!result.link && !_caption.isEmpty()) { const auto captionw = width() - st::msgPadding.left() - st::msgPadding.right(); const auto captiony = height() - (isBubbleBottom() ? st::msgPadding.bottom() : 0) - _caption.countHeight(captionw); if (QRect(st::msgPadding.left(), captiony, captionw, height() - captiony).contains(point)) { return TextState(_parent->data(), _caption.getState( point - QPoint(st::msgPadding.left(), captiony), captionw, request.forText())); } } else if (_parent->media() == this) { auto fullRight = width(); auto fullBottom = height(); if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayType::Image)) { result.cursor = CursorState::Date; } if (!_parent->hasBubble() && _parent->displayRightAction()) { auto fastShareLeft = (fullRight + st::historyFastShareLeft); auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize); if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) { result.link = _parent->rightActionLink(); } } } return result; }
TextState HistoryGroupedMedia::getPartState( QPoint point, StateRequest request) const { for (const auto &part : _parts) { if (part.geometry.contains(point)) { auto result = part.content->getStateGrouped( part.geometry, point, request); result.itemId = part.item->fullId(); return result; } } return TextState(_parent->data()); }
TextState HistoryVideo::getStateGrouped( const QRect &geometry, QPoint point, StateRequest request) const { if (!geometry.contains(point)) { return {}; } return TextState(_parent, _data->uploading() ? _cancell : _data->loaded() ? _openl : _data->loading() ? _cancell : _savel); }
TextState HistoryPhoto::getStateGrouped( const QRect &geometry, QPoint point, StateRequest request) const { if (!geometry.contains(point)) { return {}; } return TextState(_parent, _data->uploading() ? _cancell : _data->loaded() ? _openl : _data->loading() ? (_data->large()->location().valid() ? _cancell : nullptr) : _savel); }
TextState HistoryGame::textState(QPoint point, StateRequest request) const { auto result = TextState(_parent); if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) { return result; } auto paintw = width(), painth = height(); QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins()); auto padding = inBubblePadding(); auto tshift = padding.top(); auto bshift = padding.bottom(); if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->width() + _parent->skipBlockWidth() > paintw + bubble.left() + bubble.right()) { bshift += bottomInfoPadding(); } paintw -= padding.left() + padding.right(); auto inThumb = false; auto symbolAdd = 0; auto lineHeight = unitedLineHeight(); if (_titleLines) { if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { Text::StateRequestElided titleRequest = request.forText(); titleRequest.lines = _titleLines; result = TextState(_parent, _title.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), titleRequest)); } else if (point.y() >= tshift + _titleLines * lineHeight) { symbolAdd += _title.length(); } tshift += _titleLines * lineHeight; } if (_descriptionLines) { if (point.y() >= tshift && point.y() < tshift + _descriptionLines * lineHeight) { Text::StateRequestElided descriptionRequest = request.forText(); descriptionRequest.lines = _descriptionLines; result = TextState(_parent, _description.getStateElidedLeft( point - QPoint(padding.left(), tshift), paintw, width(), descriptionRequest)); } else if (point.y() >= tshift + _descriptionLines * lineHeight) { symbolAdd += _description.length(); } tshift += _descriptionLines * lineHeight; } if (inThumb) { if (!_parent->data()->isLogEntry()) { result.link = _openl; } } else if (_attach) { auto attachAtTop = !_titleLines && !_descriptionLines; if (!attachAtTop) tshift += st::mediaInBubbleSkip; auto attachLeft = padding.left() - bubble.left(); auto attachTop = tshift - bubble.top(); if (rtl()) attachLeft = width() - attachLeft - _attach->width(); if (QRect(attachLeft, tshift, _attach->width(), height() - tshift - bshift).contains(point)) { if (_attach->isReadyForOpen()) { if (!_parent->data()->isLogEntry()) { result.link = _openl; } } else { result = _attach->textState(point - QPoint(attachLeft, attachTop), request); } } } result.symbol += symbolAdd; return result; }
static void draw_text(HDC _hDC, const text_info& _Desc, const char* _Text, RECT* _pActual) { argb_channels fg, bg, sh; fg.argb = _Desc.argb_foreground; bg.argb = _Desc.argb_background; sh.argb = _Desc.argb_shadow; if (!fg.a) { if (!bg.a) oThrow(std::errc::invalid_argument, ""); fg.r = bg.r; fg.g = bg.g; fg.b = bg.b; } UINT uFormat = DT_WORDBREAK; switch ((int)_Desc.alignment % 3) { case 0: uFormat |= DT_LEFT; break; case 1: uFormat |= DT_CENTER; break; case 2: uFormat |= DT_RIGHT; break; } switch ((int)_Desc.alignment / 3) { case 0: uFormat |= DT_TOP; break; case 1: uFormat |= DT_VCENTER; break; case 2: uFormat |= DT_BOTTOM; break; } bool forcedSingleLine = !_Desc.single_line && ((uFormat & DT_BOTTOM) || (uFormat & DT_VCENTER)); if (forcedSingleLine || _Desc.single_line) { if (forcedSingleLine) oTraceOnce("GDI doesn't support multi-line, vertically aligned text. See DrawText docs for more details. http://msdn.microsoft.com/en-us/library/ms901121.aspx"); uFormat &=~ DT_WORDBREAK; uFormat |= DT_SINGLELINE; } if (_pActual) uFormat |= DT_CALCRECT; RECT rect = oWinRectWH(_Desc.position, _Desc.size); if (!_pActual) _pActual = ▭ else { _pActual->top = 0; _pActual->left = 0; _pActual->right = 1; _pActual->bottom = 1; } if (sh.a && any(_Desc.shadow_offset != int2(0,0))) { // If the background is opaque, cast an opaque shadow auto sh_rgb = RGB(sh.r,sh.g,sh.b); scoped_text_color ShadowState(_hDC, sh_rgb, sh_rgb, bg.a); RECT rShadow = *_pActual; OffsetRect(&rShadow, _Desc.shadow_offset.x, _Desc.shadow_offset.y); DrawTextA(_hDC, _Text, -1, &rShadow, uFormat); } scoped_text_color TextState(_hDC, RGB(fg.r,fg.g,fg.b), RGB(bg.r,bg.g,bg.b), bg.a); DrawTextA(_hDC, _Text, -1, _pActual, uFormat); }