diff --git a/Telegram/SourceFiles/boxes/create_poll_box.cpp b/Telegram/SourceFiles/boxes/create_poll_box.cpp index 55256a3dba..8d096fda17 100644 --- a/Telegram/SourceFiles/boxes/create_poll_box.cpp +++ b/Telegram/SourceFiles/boxes/create_poll_box.cpp @@ -2251,6 +2251,13 @@ object_ptr CreatePollBox::setupContent() { }, remove); return; + } else if (document) { + HistoryView::ShowPollDocumentPreview( + _controller, + document, + [=] { chooseDocument(media); }, + remove); + return; } state->mediaMenu = base::make_unique_q( button, diff --git a/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp b/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp index cbee7efed8..70be64578f 100644 --- a/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp +++ b/Telegram/SourceFiles/history/view/history_view_reaction_preview.cpp @@ -35,6 +35,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { +void SetupOverlayHideOnEscape( + not_null clickable, + Fn hideAll) { + clickable->setClickedCallback(hideAll); + base::install_event_filter(QCoreApplication::instance(), [=]( + not_null e) { + if (e->type() == QEvent::KeyPress + && clickable->window()->isActiveWindow()) { + const auto k = static_cast(e.get()); + if (k->key() == Qt::Key_Escape) { + hideAll(); + return base::EventFilterResult::Cancel; + } + } + return base::EventFilterResult::Continue; + }, clickable->lifetime()); +} + struct PreviewOverlayState { base::unique_qptr mediaPreview; base::unique_qptr clickable; @@ -80,19 +98,7 @@ template st::defaultToggle.duration, [=] { state->clear(); }); }; - state->clickable->setClickedCallback(hideAll); - base::install_event_filter(QCoreApplication::instance(), [=]( - not_null e) { - if (e->type() == QEvent::KeyPress - && state->clickable->window()->isActiveWindow()) { - const auto k = static_cast(e.get()); - if (k->key() == Qt::Key_Escape) { - hideAll(); - return base::EventFilterResult::Cancel; - } - } - return base::EventFilterResult::Continue; - }, state->clickable->lifetime()); + SetupOverlayHideOnEscape(state->clickable.get(), hideAll); state->mediaPreview->showPreview(origin, media); state->clickable->show(); const auto clickableRaw = state->clickable.get(); @@ -284,4 +290,74 @@ bool ShowReactionPreview( return true; } +void ShowWidgetPreview( + not_null controller, + Fn)> setupContent, + Fn)> fillMenu) { + struct State { + base::unique_qptr preview; + base::unique_qptr clickable; + base::unique_qptr menu; + }; + const auto state = std::make_shared(); + const auto mainwidget = controller->widget()->bodyWidget(); + + state->preview = base::make_unique_q(mainwidget); + const auto previewRaw = state->preview.get(); + setupContent(previewRaw); + previewRaw->setAttribute(Qt::WA_TransparentForMouseEvents); + + state->clickable = base::make_unique_q(mainwidget); + state->clickable->paintOn([=](QPainter &p) { + p.fillRect(state->clickable->rect(), st::stickerPreviewBg); + }); + + const auto hideAll = [=] { + state->clickable->setAttribute(Qt::WA_TransparentForMouseEvents); + if (state->menu) { + state->menu->hideAnimated(); + } + base::call_delayed( + st::defaultToggle.duration, + [s = state] { + s->preview.reset(); + s->menu.reset(); + s->clickable.reset(); + }); + }; + SetupOverlayHideOnEscape(state->clickable.get(), hideAll); + + state->menu = base::make_unique_q( + mainwidget, + st::dropdownMenuWithIcons); + state->menu->setAutoHiding(false); + state->menu->setHiddenCallback( + crl::guard(state->clickable.get(), hideAll)); + fillMenu(state->menu.get()); + + const auto menuRaw = state->menu.get(); + state->clickable->show(); + previewRaw->show(); + + const auto fullW = previewRaw->width(); + const auto fullH = previewRaw->height(); + + mainwidget->sizeValue() | rpl::on_next([=](QSize size) { + state->clickable->setGeometry(Rect(size)); + state->clickable->raise(); + + const auto gap = st::defaultMenu.itemPadding.top(); + const auto totalH = fullH + gap + menuRaw->height(); + const auto previewY = (size.height() - totalH) / 2; + previewRaw->move((size.width() - fullW) / 2, previewY); + previewRaw->raise(); + + menuRaw->move( + (size.width() - menuRaw->width()) / 2, + previewY + fullH + gap); + menuRaw->showAnimated(Ui::PanelAnimation::Origin::TopLeft); + menuRaw->raise(); + }, previewRaw->lifetime()); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_reaction_preview.h b/Telegram/SourceFiles/history/view/history_view_reaction_preview.h index bdfc079aa6..e02cf53048 100644 --- a/Telegram/SourceFiles/history/view/history_view_reaction_preview.h +++ b/Telegram/SourceFiles/history/view/history_view_reaction_preview.h @@ -12,6 +12,7 @@ class PhotoData; namespace Ui { class DropdownMenu; +class RpWidget; } // namespace Ui namespace Data { @@ -36,6 +37,11 @@ bool ShowPhotoPreview( not_null photo, Fn)> fillMenu = nullptr); +void ShowWidgetPreview( + not_null controller, + Fn)> setupContent, + Fn)> fillMenu); + bool ShowReactionPreview( not_null controller, FullMsgId origin, diff --git a/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.cpp b/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.cpp index f0ac33cbb6..421d70011c 100644 --- a/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.cpp +++ b/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.cpp @@ -23,17 +23,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_group_call_bar.h" #include "history/view/history_view_reaction_preview.h" #include "lang/lang_keys.h" +#include "layout/layout_document_generic_preview.h" #include "main/main_session.h" #include "mainwidget.h" #include "storage/localimageloader.h" #include "storage/storage_media_prepare.h" #include "ui/chat/attach/attach_prepare.h" #include "ui/painter.h" +#include "ui/rect.h" +#include "ui/text/format_values.h" #include "ui/widgets/dropdown_menu.h" #include "ui/widgets/menu/menu_action.h" +#include "ui/widgets/shadow.h" #include "window/window_session_controller.h" #include "styles/style_boxes.h" #include "styles/style_chat.h" +#include "styles/style_layers.h" +#include "styles/style_media_view.h" #include "styles/style_menu_icons.h" #include "styles/style_widgets.h" @@ -287,6 +293,124 @@ void ShowPollPhotoPreview( }); } +void ShowPollDocumentPreview( + not_null controller, + not_null document, + Fn replace, + Fn remove) { + const auto docGeneric = Layout::DocumentGenericPreview::Create( + document); + const auto docIcon = docGeneric.icon(); + const auto docIconColor = docGeneric.color; + const auto docExt = [&] { + auto ext = docGeneric.ext; + const auto maxW = st::mediaviewFileIconSize + - st::mediaviewFileExtPadding * 2; + if (st::mediaviewFileExtFont->width(ext) > maxW) { + ext = st::mediaviewFileExtFont->elided(ext, maxW, Qt::ElideMiddle); + } + return ext; + }(); + + const auto maxTextW = st::mediaviewFileSize.width() + - st::mediaviewFileIconSize + - st::mediaviewFilePadding * 3; + const auto docName = [&] { + auto name = document->filename().isEmpty() + ? tr::lng_mediaview_doc_image(tr::now) + : document->filename(); + if (st::mediaviewFileNameFont->width(name) > maxTextW) { + name = st::mediaviewFileNameFont->elided(name, maxTextW, Qt::ElideMiddle); + } + return name; + }(); + const auto docSize = [&] { + auto text = Ui::FormatSizeText(document->size); + if (st::mediaviewFont->width(text) > maxTextW) { + text = st::mediaviewFont->elided(text, maxTextW); + } + return text; + }(); + + ShowWidgetPreview(controller, [=](not_null preview) { + const auto shadowExtend = st::boxRoundShadow.extend; + const auto fullW = st::mediaviewFileSize.width() + + rect::m::sum::h(shadowExtend); + const auto fullH = st::mediaviewFileSize.height() + + rect::m::sum::v(shadowExtend); + preview->resize(fullW, fullH); + preview->paintRequest() | rpl::on_next([=] { + auto p = Painter(preview); + const auto outer = preview->rect() - shadowExtend; + + Ui::Shadow::paint( + p, + outer, + preview->width(), + st::boxRoundShadow); + { + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(st::windowBg); + p.drawRoundedRect(outer, st::boxRadius, st::boxRadius); + } + + const auto padding = st::mediaviewFilePadding; + const auto iconSize = st::mediaviewFileIconSize; + const auto iconRect = QRect( + outer.x() + padding, + outer.y() + padding, + iconSize, + iconSize); + + p.fillRect(iconRect, docIconColor); + if (docIcon) { + docIcon->paint( + p, + iconRect.x() + (iconRect.width() - docIcon->width()), + iconRect.y(), + preview->width()); + } + if (!docExt.isEmpty()) { + p.setPen(st::activeButtonFg); + p.setFont(st::mediaviewFileExtFont); + const auto extW = st::mediaviewFileExtFont->width(docExt); + p.drawText( + iconRect.x() + (iconRect.width() - extW) / 2, + iconRect.y() + + st::mediaviewFileExtTop + + st::mediaviewFileExtFont->ascent, + docExt); + } + + const auto textX = outer.x() + 2 * padding + iconSize; + p.setPen(st::windowFg); + p.setFont(st::mediaviewFileNameFont); + p.drawText( + textX, + outer.y() + padding + + st::mediaviewFileNameTop + + st::mediaviewFileNameFont->ascent, + docName); + + p.setPen(st::windowSubTextFg); + p.setFont(st::mediaviewFont); + p.drawText( + textX, + outer.y() + padding + + st::mediaviewFileSizeTop + + st::mediaviewFont->ascent, + docSize); + }, preview->lifetime()); + }, [=](not_null menu) { + menu->addAction( + tr::lng_attach_replace(tr::now), + replace, + &st::menuIconReplace); + AddRemoveAction(menu, remove); + }); +} + void EditPollPhoto( not_null controller, not_null photo, diff --git a/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.h b/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.h index bdf8feaec0..51e12dfa39 100644 --- a/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.h +++ b/Telegram/SourceFiles/history/view/media/menu/history_view_poll_menu.h @@ -43,6 +43,12 @@ void ShowPollPhotoPreview( Fn edit, Fn remove); +void ShowPollDocumentPreview( + not_null controller, + not_null document, + Fn replace, + Fn remove); + void EditPollPhoto( not_null controller, not_null photo,