From 4f0cff5467af96d1c7651d3b42c38411d57b3fef Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 13 Oct 2016 18:04:40 +0300 Subject: [PATCH] Playlist added in the new media player panel. --- Telegram/SourceFiles/facades.cpp | 25 ++- Telegram/SourceFiles/historywidget.cpp | 2 +- Telegram/SourceFiles/layout.cpp | 16 ++ Telegram/SourceFiles/layout.h | 1 + Telegram/SourceFiles/mainwidget.cpp | 6 + .../media/player/media_player.style | 18 ++ .../media/player/media_player_list.cpp | 191 ++++++++++++++++++ .../media/player/media_player_list.h | 36 +++- .../media/player/media_player_panel.cpp | 90 ++++++--- .../media/player/media_player_panel.h | 15 +- .../player/media_player_volume_controller.cpp | 3 +- Telegram/SourceFiles/overview/overview.style | 31 ++- .../SourceFiles/overview/overview_layout.cpp | 119 +++++------ .../SourceFiles/overview/overview_layout.h | 12 +- Telegram/SourceFiles/overviewwidget.cpp | 4 +- Telegram/SourceFiles/overviewwidget.h | 32 +-- .../ui/widgets/continuous_slider.cpp | 2 + Telegram/SourceFiles/ui/widgets/shadow.h | 19 ++ 18 files changed, 499 insertions(+), 123 deletions(-) diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 4df21fb2c..de5c87220 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -219,34 +219,41 @@ bool isMediaViewShown() { } bool isInlineItemBeingChosen() { - if (MainWidget *m = App::main()) return m->ui_isInlineItemBeingChosen(); + if (auto main = App::main()) { + return main->ui_isInlineItemBeingChosen(); + } return false; } void repaintHistoryItem(const HistoryItem *item) { - if (!item) return; - if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item); + if (auto main = App::main()) { + main->ui_repaintHistoryItem(item); + } } void repaintInlineItem(const InlineBots::Layout::ItemBase *layout) { if (!layout) return; - if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout); + if (auto main = App::main()) { + main->ui_repaintInlineItem(layout); + } } bool isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) { - if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout); + if (auto main = App::main()) { + return main->ui_isInlineItemVisible(layout); + } return false; } void autoplayMediaInlineAsync(const FullMsgId &msgId) { - if (MainWidget *m = App::main()) { - QMetaObject::invokeMethod(m, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg)); + if (auto main = App::main()) { + QMetaObject::invokeMethod(main, "ui_autoplayMediaInlineAsync", Qt::QueuedConnection, Q_ARG(qint32, msgId.channel), Q_ARG(qint32, msgId.msg)); } } void showPeerProfile(const PeerId &peer) { - if (auto m = App::main()) { - m->showWideSection(Profile::SectionMemento(App::peer(peer))); + if (auto main = App::main()) { + main->showWideSection(Profile::SectionMemento(App::peer(peer))); } } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 6554cbf5b..3ddf493b7 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -6302,7 +6302,7 @@ void HistoryWidget::setMembersShowAreaActive(bool active) { void HistoryWidget::onMembersDropdownShow() { if (!_membersDropdown) { - _membersDropdown = new Ui::InnerDropdown(this, st::membersInnerDropdown, st::membersInnerScroll); + _membersDropdown.create(this, st::membersInnerDropdown, st::membersInnerScroll); _membersDropdown->setOwnedWidget(new Profile::MembersWidget(_membersDropdown, _peer, Profile::MembersWidget::TitleVisibility::Hidden)); _membersDropdown->resize(st::membersInnerWidth, _membersDropdown->height()); diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index 87f272096..4aa94953a 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -151,6 +151,22 @@ QString documentName(DocumentData *document) { return song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title); } +TextWithEntities documentNameWithEntities(DocumentData *document) { + TextWithEntities result; + auto song = document->song(); + if (!song || (song->title.isEmpty() && song->performer.isEmpty())) { + result.text = document->name.isEmpty() ? qsl("Unknown File") : document->name; + result.entities.push_back({ EntityInTextBold, 0, result.text.size() }); + } else if (song->performer.isEmpty()) { + result.text = song->title; + result.entities.push_back({ EntityInTextBold, 0, result.text.size() }); + } else { + result.text = song->performer + QString::fromUtf8(" \xe2\x80\x93 ") + (song->title.isEmpty() ? qsl("Unknown Track") : song->title); + result.entities.push_back({ EntityInTextBold, 0, song->performer.size() }); + } + return result; +} + int32 documentColorIndex(DocumentData *document, QString &ext) { int32 colorIndex = 0; diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 6b7d65531..385050401 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -80,6 +80,7 @@ QString formatGifAndSizeText(qint64 size); QString formatPlayedText(qint64 played, qint64 duration); QString documentName(DocumentData *document); +TextWithEntities documentNameWithEntities(DocumentData *document); int32 documentColorIndex(DocumentData *document, QString &ext); style::color documentColor(int32 colorIndex); style::color documentDarkColor(int32 colorIndex); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8c59fd74e..bdb328457 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -489,6 +489,9 @@ void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) { if (item->history()->lastMsg == item) { item->history()->updateChatListEntry(); } + if (_playerPanel && !_playerPanel->isHidden()) { + _playerPanel->ui_repaintHistoryItem(item); + } if (_overview) _overview->ui_repaintHistoryItem(item); } @@ -1364,6 +1367,9 @@ void MainWidget::itemRemoved(HistoryItem *item) { if (_overview && (_overview->peer() == item->history()->peer || (_overview->peer() && _overview->peer() == item->history()->peer->migrateTo()))) { _overview->itemRemoved(item); } + if (_playerPanel) { + _playerPanel->itemRemoved(item); + } if (!_toForward.isEmpty()) { SelectedItemSet::iterator i = _toForward.find(item->id); if (i != _toForward.cend() && i.value() == item) { diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index 2ac05e0ff..a724f65ce 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org using "basic.style"; using "ui/widgets/widgets.style"; +using "overview/overview.style"; MediaPlayerButton { playPosition: point; @@ -231,3 +232,20 @@ mediaPlayerPanelVolumeSkip: 3px; mediaPlayerPanelVolumeWidth: 64px; mediaPlayerPanelVolumeToggleSkip: 0px; mediaPlayerPanelVolumeToggleTop: 57px; + +mediaPlayerScroll: flatScroll(solidScroll) { + deltat: 10px; + deltab: 0px; +} +mediaPlayerListHeightMax: 280px; +mediaPlayerListMarginBottom: 10px; +mediaPlayerScrollShadow: icon {{ "player_playlist_shadow", #000000 }}; + +mediaPlayerListMarginTop: 8px; +mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) { + maxWidth: 344px; + songPadding: margins(17px, 7px, 10px, 6px); + songThumbSize: 36px; + songNameTop: 7px; + songStatusTop: 25px; +} diff --git a/Telegram/SourceFiles/media/player/media_player_list.cpp b/Telegram/SourceFiles/media/player/media_player_list.cpp index a8f62db55..c04f45975 100644 --- a/Telegram/SourceFiles/media/player/media_player_list.cpp +++ b/Telegram/SourceFiles/media/player/media_player_list.cpp @@ -21,8 +21,199 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "media/player/media_player_list.h" +#include "media/player/media_player_instance.h" +#include "overview/overview_layout.h" +#include "styles/style_media_player.h" + namespace Media { namespace Player { +ListWidget::ListWidget() { + setMouseTracking(true); + playlistUpdated(); + if (exists()) { + subscribe(instance()->playlistChangedNotifier(), [this] { playlistUpdated(); }); + } +} + +ListWidget::~ListWidget() { + auto layouts = base::take(_layouts); + for_const (auto layout, layouts) { + delete layout; + } +} + +void ListWidget::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto clip = e->rect(); + Overview::Layout::PaintContext context(getms(), false); + int y = marginTop(); + for_const (auto layout, _list) { + auto layoutHeight = layout->height(); + if (y + layoutHeight > clip.y()) { + if (y >= clip.y() + clip.height()) break; + + p.translate(0, y); + layout->paint(p, clip.translated(0, -y), TextSelection(), &context); + p.translate(0, -y); + } + y += layoutHeight; + } +} + +void ListWidget::mousePressEvent(QMouseEvent *e) { + if (e->button() != Qt::LeftButton) return; + + ClickHandler::pressed(); +} + +void ListWidget::mouseReleaseEvent(QMouseEvent *e) { + ClickHandlerPtr activated = ClickHandler::unpressed(); + if (!ClickHandler::getActive() && _cursor != style::cur_default) { + _cursor = style::cur_default; + setCursor(_cursor); + } + if (activated) { + App::activateClickHandler(activated, e->button()); + return; + } +} + +void ListWidget::mouseMoveEvent(QMouseEvent *e) { + auto m = e->pos(); + + ClickHandlerPtr lnk; + ClickHandlerHost *lnkhost = nullptr; + HistoryItem *item = nullptr; + HistoryCursorState cursorState = HistoryDefaultCursorState; + + int y = marginTop(); + for_const (auto layout, _list) { + auto layoutHeight = layout->height(); + if (y + layoutHeight > m.y()) { + if (y <= m.y()) { + if (auto media = layout->toMediaItem()) { + item = media->getItem(); + media->getState(lnk, cursorState, m.x(), m.y() - y); + lnkhost = media; + } + } + break; + } + y += layoutHeight; + } + + auto cur = lnk ? style::cur_pointer : style::cur_default; + if (cur != _cursor) { + setCursor(_cursor = cur); + } + + auto lnkChanged = ClickHandler::setActive(lnk, lnkhost); + if (item != App::mousedItem()) { + repaintItem(App::mousedItem()); + App::mousedItem(item); + repaintItem(App::mousedItem()); + } +} + +void ListWidget::ui_repaintHistoryItem(const HistoryItem *item) { + repaintItem(item); +} + +void ListWidget::repaintItem(const HistoryItem *item) { + if (!item) return; + + auto layoutIt = _layouts.constFind(item->fullId()); + if (layoutIt != _layouts.cend()) { + int y = 0; + for_const (auto layout, _list) { + auto layoutHeight = layout->height(); + if (layout->getItem() == item) { + update(0, y, width(), layoutHeight); + break; + } + y += layoutHeight; + } + } +} + +void ListWidget::itemRemoved(HistoryItem *item) { + auto layoutIt = _layouts.find(item->fullId()); + if (layoutIt != _layouts.cend()) { + auto layout = layoutIt.value(); + _layouts.erase(layoutIt); + delete layout; + } +} + +int ListWidget::resizeGetHeight(int newWidth) { + auto result = 0; + for_const (auto layout, _list) { + result += layout->resizeGetHeight(newWidth); + } + return (result > 0) ? (marginTop() + result) : 0; +} + +int ListWidget::marginTop() const { + return st::mediaPlayerListMarginTop; +} + +void ListWidget::playlistUpdated() { + auto newHeight = 0; + + const QList emptyPlaylist; + auto &playlist = exists() ? instance()->playlist() : emptyPlaylist; + auto playlistSize = playlist.size(); + auto existingSize = _list.size(); + if (playlistSize > existingSize) { + _list.reserve(playlistSize); + } + + int existingIndex = 0; + for (int i = 0; i != playlistSize; ++i) { + auto &msgId = playlist[i]; + if (existingIndex < existingSize && _list[existingIndex]->getItem()->fullId() == msgId) { + newHeight += _list[existingIndex]->height(); + ++existingIndex; + continue; + } + auto layoutIt = _layouts.constFind(msgId); + if (layoutIt == _layouts.cend()) { + if (auto item = App::histItemById(msgId)) { + if (auto media = item->getMedia()) { + if (media->type() == MediaTypeMusicFile) { + layoutIt = _layouts.insert(msgId, new Overview::Layout::Document(media->getDocument(), item, st::mediaPlayerFileLayout)); + layoutIt.value()->initDimensions(); + } + } + } + } + if (layoutIt != _layouts.cend()) { + auto layout = layoutIt.value(); + if (existingIndex < existingSize) { + _list[existingIndex] = layout; + } else { + _list.push_back(layout); + ++existingSize; + } + ++existingIndex; + newHeight += layout->resizeGetHeight(width()); + } + } + while (existingIndex < existingSize) { + _list.pop_back(); + --existingSize; + } + + if (newHeight > 0) { + newHeight += marginTop(); + } + if (newHeight != height()) { + resize(width(), newHeight); + emit heightUpdated(); + } +} + } // namespace Player } // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player_list.h b/Telegram/SourceFiles/media/player/media_player_list.h index 53410092b..ed8e5dd95 100644 --- a/Telegram/SourceFiles/media/player/media_player_list.h +++ b/Telegram/SourceFiles/media/player/media_player_list.h @@ -20,11 +20,45 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +namespace Overview { +namespace Layout { +class Document; +} // namespace Layout +} // namespace Overview + namespace Media { namespace Player { -class ListWidget : public ScrolledWidget { +class ListWidget : public ScrolledWidget, private base::Subscriber { public: + ListWidget(); + + void ui_repaintHistoryItem(const HistoryItem *item); + void itemRemoved(HistoryItem *item); + + ~ListWidget(); + +protected: + void paintEvent(QPaintEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + + int resizeGetHeight(int newWidth) override; + +private: + int marginTop() const; + void repaintItem(const HistoryItem *item); + void playlistUpdated(); + + using Layout = Overview::Layout::Document; + using Layouts = QMap; + Layouts _layouts; + + using List = QList; + List _list; + + style::cursor _cursor = style::cur_default; }; diff --git a/Telegram/SourceFiles/media/player/media_player_panel.cpp b/Telegram/SourceFiles/media/player/media_player_panel.cpp index 0bbb247e1..24bd7e910 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.cpp +++ b/Telegram/SourceFiles/media/player/media_player_panel.cpp @@ -25,32 +25,35 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "media/player/media_player_list.h" #include "media/player/media_player_instance.h" #include "styles/style_media_player.h" +#include "ui/widgets/shadow.h" #include "mainwindow.h" namespace Media { namespace Player { Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent) -, _shadow(st::defaultInnerDropdown.shadow) { +, _shadow(st::defaultInnerDropdown.shadow) +, _scroll(this, st::mediaPlayerScroll) +, _scrollShadow(this, st::mediaPlayerScrollShadow) { if (layout == Layout::Full) { _cover.create(this); } _hideTimer.setSingleShot(true); connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart())); + auto list = std_::make_unique(); + connect(list.get(), SIGNAL(heightUpdated()), this, SLOT(onListHeightUpdated())); + _scroll->setOwnedWidget(list.release()); + _showTimer.setSingleShot(true); connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart())); - if (_scroll) { - connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); - } - if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); } hide(); - resize(contentLeft() + st::mediaPlayerPanelWidth, st::mediaPlayerCoverHeight + st::mediaPlayerPanelMarginBottom); + onListHeightUpdated(); } bool Panel::overlaps(const QRect &globalRect) { @@ -68,26 +71,59 @@ void Panel::onWindowActiveChanged() { } void Panel::resizeEvent(QResizeEvent *e) { - _cover->resize(width() - contentLeft(), st::mediaPlayerCoverHeight); + auto width = contentWidth(); + _cover->resize(width, st::mediaPlayerCoverHeight); _cover->moveToRight(0, 0); - if (_scroll) { - _scroll->resize(width(), height() - _cover->height()); - _scroll->moveToRight(0, _cover->height()); - _list->resizeToWidth(width()); + + auto scrollTop = _cover->height(); + auto scrollHeight = qMax(contentHeight() - scrollTop - st::mediaPlayerListMarginBottom, 0); + if (scrollHeight > 0) { + _scroll->setGeometryToRight(0, scrollTop, width, scrollHeight); + _scrollShadow->resizeToWidth(width); + _scrollShadow->moveToRight(0, scrollTop); + } + if (auto widget = static_cast(_scroll->widget())) { + widget->resizeToWidth(width); + onScroll(); + } +} + +void Panel::onListHeightUpdated() { + updateSize(); +} + +void Panel::ui_repaintHistoryItem(const HistoryItem *item) { + if (auto list = static_cast(_scroll->widget())) { + list->ui_repaintHistoryItem(item); + } +} + +void Panel::itemRemoved(HistoryItem *item) { + if (auto list = static_cast(_scroll->widget())) { + list->itemRemoved(item); } - //_scroll->setGeometry(rect().marginsRemoved(_st.padding).marginsRemoved(_st.scrollMargin)); - //if (auto widget = static_cast(_scroll->widget())) { - // widget->resizeToWidth(_scroll->width()); - // onScroll(); - //} } void Panel::onScroll() { - //if (auto widget = static_cast(_scroll->widget())) { - // int visibleTop = _scroll->scrollTop(); - // int visibleBottom = visibleTop + _scroll->height(); - // widget->setVisibleTopBottom(visibleTop, visibleBottom); - //} + if (auto widget = static_cast(_scroll->widget())) { + int visibleTop = _scroll->scrollTop(); + int visibleBottom = visibleTop + _scroll->height(); + widget->setVisibleTopBottom(visibleTop, visibleBottom); + } +} + +void Panel::updateSize() { + auto listHeight = 0; + if (auto widget = static_cast(_scroll->widget())) { + listHeight = widget->height(); + } + auto scrollVisible = (listHeight > 0); + auto scrollHeight = scrollVisible ? (qMin(listHeight, st::mediaPlayerListHeightMax) + st::mediaPlayerListMarginBottom) : 0; + auto width = contentLeft() + st::mediaPlayerPanelWidth; + auto height = st::mediaPlayerCoverHeight + scrollHeight + st::mediaPlayerPanelMarginBottom; + resize(width, height); + _scroll->setVisible(scrollVisible); + _scrollShadow->setVisible(scrollVisible); } void Panel::paintEvent(QPaintEvent *e) { @@ -96,8 +132,8 @@ void Panel::paintEvent(QPaintEvent *e) { if (!_cache.isNull()) { bool animating = _a_appearance.animating(getms()); if (animating) { - p.setOpacity(_a_appearance.current(_hiding)); - } else if (_hiding) { + p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.)); + } else if (_hiding || isHidden()) { hidingFinished(); return; } @@ -186,7 +222,7 @@ void Panel::onHideStart() { void Panel::startAnimation() { auto from = _hiding ? 1. : 0.; auto to = _hiding ? 0. : 1.; - if (!_a_appearance.animating()) { + if (_cache.isNull()) { showChildren(); _cache = myGrab(this); } @@ -205,13 +241,17 @@ void Panel::appearanceCallback() { void Panel::hidingFinished() { hide(); - showChildren(); + _cache = QPixmap(); } int Panel::contentLeft() const { return st::mediaPlayerPanelMarginLeft; } +int Panel::contentHeight() const { + return height() - st::mediaPlayerPanelMarginBottom; +} + bool Panel::eventFilter(QObject *obj, QEvent *e) { if (e->type() == QEvent::Enter) { otherEnter(); diff --git a/Telegram/SourceFiles/media/player/media_player_panel.h b/Telegram/SourceFiles/media/player/media_player_panel.h index 179a4a3ac..2f863d5f9 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.h +++ b/Telegram/SourceFiles/media/player/media_player_panel.h @@ -24,6 +24,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org class ScrollArea; +namespace Ui { +class GradientShadow; +} // namespace Ui + namespace Media { namespace Player { @@ -49,6 +53,9 @@ public: using PinCallback = base::lambda_unique; void setPinCallback(PinCallback &&callback); + void ui_repaintHistoryItem(const HistoryItem *item); + void itemRemoved(HistoryItem *item); + ~Panel(); protected: @@ -64,15 +71,19 @@ private slots: void onHideStart(); void onScroll(); + void onListHeightUpdated(); + void onWindowActiveChanged(); private: + void updateSize(); void appearanceCallback(); void hidingFinished(); int contentLeft() const; int contentWidth() const { return width() - contentLeft(); } + int contentHeight() const; void startAnimation(); @@ -85,8 +96,8 @@ private: Ui::RectShadow _shadow; ChildWidget _cover = { nullptr }; - ChildWidget _list = { nullptr }; - ChildWidget _scroll = { nullptr }; + ChildWidget _scroll; + ChildWidget _scrollShadow; }; diff --git a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp index d49f45651..249da8bfd 100644 --- a/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp +++ b/Telegram/SourceFiles/media/player/media_player_volume_controller.cpp @@ -129,7 +129,7 @@ void VolumeWidget::paintEvent(QPaintEvent *e) { bool animating = _a_appearance.animating(getms()); if (animating) { p.setOpacity(_a_appearance.current(_hiding)); - } else if (_hiding) { + } else if (_hiding || isHidden()) { hidingFinished(); return; } @@ -226,7 +226,6 @@ void VolumeWidget::appearanceCallback() { void VolumeWidget::hidingFinished() { hide(); - showChildren(); _cache = QPixmap(); } diff --git a/Telegram/SourceFiles/overview/overview.style b/Telegram/SourceFiles/overview/overview.style index ed8e546bc..50413c17c 100644 --- a/Telegram/SourceFiles/overview/overview.style +++ b/Telegram/SourceFiles/overview/overview.style @@ -20,6 +20,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ using "basic.style"; +OverviewFileLayout { + maxWidth: pixels; + songPadding: margins; + songThumbSize: pixels; + songNameTop: pixels; + songStatusTop: pixels; + filePadding: margins; + fileThumbSize: pixels; + fileNameTop: pixels; + fileStatusTop: pixels; + fileDateTop: pixels; +} + overviewCheckBg: #0006; overviewCheckedBg: #2fa9e2; @@ -36,17 +49,25 @@ overviewPhotoChecked: icon { }; overviewPhotoSelectOverlay: #0a7bb03f; -overviewFilePadding: margins(0px, 3px, 16px, 3px); -overviewFileSize: 70px; -overviewFileNameTop: 7px; -overviewFileStatusTop: 27px; -overviewFileDateTop: 49px; overviewFileChecked: #2fa9e2; overviewFileCheck: #00000066; overviewFileExtPadding: 5px; overviewFileExtTop: 24px; overviewFileExtFont: font(18px semibold); +overviewFileLayout: OverviewFileLayout { + maxWidth: 410px; + songPadding: msgFilePadding; + songThumbSize: msgFileSize; + songNameTop: msgFileNameTop; + songStatusTop: msgFileStatusTop; + filePadding: margins(0px, 3px, 16px, 3px); + fileThumbSize: 70px; + fileNameTop: 7px; + fileStatusTop: 24px; + fileDateTop: 49px; +} + overviewLoader: size(34px, 14px); overviewLoaderPoint: size(4px, 4px); overviewLoaderSkip: 4px; diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 8b66c1f92..b80b53824 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -38,6 +38,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Overview { namespace Layout { +namespace { + +TextParseOptions _documentNameOptions = { + TextParseMultiline | TextParseRichText | TextParseLinks | TextParseHashtags | TextParseMentions | TextParseBotCommands | TextParseMono, // flags + 0, // maxw + 0, // maxh + Qt::LayoutDirectionAuto, // dir +}; + +} // namespace void ItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { App::hoveredLinkItem(active ? _parent : nullptr); @@ -404,8 +414,8 @@ Voice::Voice(DocumentData *voice, HistoryItem *parent) : FileBase(parent) } void Voice::initDimensions() { - _maxw = st::profileMaxWidth; - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::lineWidth; + _maxw = st::overviewFileLayout.maxWidth; + _minh = st::overviewFileLayout.songPadding.top() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.bottom() + st::lineWidth; } void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { @@ -429,16 +439,16 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; + nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right(); + nameright = st::overviewFileLayout.songPadding.left(); + nametop = st::overviewFileLayout.songNameTop; + statustop = st::overviewFileLayout.songStatusTop; if (selected) { p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); } - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + QRect inner(rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width)); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -514,12 +524,12 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; + nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right(); + nameright = st::overviewFileLayout.songPadding.left(); + nametop = st::overviewFileLayout.songNameTop; + statustop = st::overviewFileLayout.songStatusTop; - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + auto inner = rtlrect(st::overviewFileLayout.songPadding.left(), st::overviewFileLayout.songPadding.top(), st::overviewFileLayout.songThumbSize, st::overviewFileLayout.songThumbSize, _width); if (inner.contains(x, y)) { link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); return; @@ -577,16 +587,16 @@ bool Voice::updateStatusText() const { return showPause; } -Document::Document(DocumentData *document, HistoryItem *parent) : FileBase(parent) +Document::Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st) : FileBase(parent) , _data(document) , _msgl(new GoToMessageClickHandler(parent)) , _namel(new DocumentOpenClickHandler(_data)) -, _thumbForLoaded(false) -, _name(documentName(_data)) +, _st(st) , _date(langDateTime(date(_data->date))) -, _namew(st::semiboldFont->width(_name)) , _datew(st::normalFont->width(_date)) , _colorIndex(documentColorIndex(_data, _ext)) { + _name.setMarkedText(st::normalFont, documentNameWithEntities(_data), _documentNameOptions); + AddComponents(Info::Bit()); setDocumentLinks(_data); @@ -597,27 +607,27 @@ Document::Document(DocumentData *document, HistoryItem *parent) : FileBase(paren _data->thumb->load(); int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); if (tw > th) { - _thumbw = (tw * st::overviewFileSize) / th; + _thumbw = (tw * _st.fileThumbSize) / th; } else { - _thumbw = st::overviewFileSize; + _thumbw = _st.fileThumbSize; } } else { _thumbw = 0; } _extw = st::overviewFileExtFont->width(_ext); - if (_extw > st::overviewFileSize - st::overviewFileExtPadding * 2) { - _ext = st::overviewFileExtFont->elided(_ext, st::overviewFileSize - st::overviewFileExtPadding * 2, Qt::ElideMiddle); + if (_extw > _st.fileThumbSize - st::overviewFileExtPadding * 2) { + _ext = st::overviewFileExtFont->elided(_ext, _st.fileThumbSize - st::overviewFileExtPadding * 2, Qt::ElideMiddle); _extw = st::overviewFileExtFont->width(_ext); } } void Document::initDimensions() { - _maxw = st::profileMaxWidth; + _maxw = _st.maxWidth; if (_data->song()) { - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); + _minh = _st.songPadding.top() + _st.songThumbSize + _st.songPadding.bottom(); } else { - _minh = st::overviewFilePadding.top() + st::overviewFileSize + st::overviewFilePadding.bottom() + st::lineWidth; + _minh = _st.filePadding.top() + _st.fileThumbSize + _st.filePadding.bottom() + st::lineWidth; } } @@ -640,16 +650,16 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con bool wthumb = withThumb(); if (_data->song()) { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; + nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); + nameright = _st.songPadding.left(); + nametop = _st.songNameTop; + statustop = _st.songStatusTop; if (selected) { p.fillRect(QRect(0, 0, _width, _height), st::msgInBgSelected); } - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); if (clip.intersects(inner)) { p.setPen(Qt::NoPen); if (selected) { @@ -668,7 +678,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con p.setRenderHint(QPainter::HighQualityAntialiasing, false); if (radial) { - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + auto rinner = inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)); style::color bg(selected ? st::msgInBgSelected : st::msgInBg); _radial->draw(p, rinner, st::msgFileRadialLine, bg); } @@ -686,17 +696,17 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con icon->paintInCenter(p, inner); } } else { - nameleft = st::overviewFileSize + st::overviewFilePadding.right(); - nametop = st::linksBorder + st::overviewFileNameTop; - statustop = st::linksBorder + st::overviewFileStatusTop; - datetop = st::linksBorder + st::overviewFileDateTop; + nameleft = _st.fileThumbSize + _st.filePadding.right(); + nametop = st::linksBorder + _st.fileNameTop; + statustop = st::linksBorder + _st.fileStatusTop; + datetop = st::linksBorder + _st.fileDateTop; QRect border(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width)); if (!context->isAfterDate && clip.intersects(border)) { p.fillRect(clip.intersected(border), st::linksBorderFg); } - QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); + QRect rthumb(rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width)); if (clip.intersects(rthumb)) { if (wthumb) { if (_data->thumb->loaded()) { @@ -704,7 +714,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con _thumbForLoaded = loaded; ImagePixOptions options = ImagePixSmooth; if (!_thumbForLoaded) options |= ImagePixBlurred; - _thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, st::overviewFileSize, st::overviewFileSize); + _thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize); } p.drawPixmap(rthumb.topLeft(), _thumb); } else { @@ -723,7 +733,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con } if (radial || (!loaded && !_data->loading())) { - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + QRect inner(rthumb.x() + (rthumb.width() - _st.songThumbSize) / 2, rthumb.y() + (rthumb.height() - _st.songThumbSize) / 2, _st.songThumbSize, _st.songThumbSize); if (clip.intersects(inner)) { float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1; p.setPen(Qt::NoPen); @@ -772,19 +782,14 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con } } - int32 namewidth = _width - nameleft - nameright; - - if (clip.intersects(rtlrect(nameleft, nametop, qMin(namewidth, _namew), st::semiboldFont->height, _width))) { - p.setFont(st::semiboldFont); + int availwidth = _width - nameleft - nameright; + int namewidth = qMin(availwidth, _name.maxWidth()); + if (clip.intersects(rtlrect(nameleft, nametop, namewidth, st::semiboldFont->height, _width))) { p.setPen(st::black); - if (namewidth < _namew) { - p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(_name, namewidth)); - } else { - p.drawTextLeft(nameleft, nametop, _width, _name, _namew); - } + _name.drawLeftElided(p, nameleft, nametop, namewidth, _width); } - if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { + if (clip.intersects(rtlrect(nameleft, statustop, availwidth, st::normalFont->height, _width))) { p.setFont(st::normalFont); p.setPen(st::mediaInFg); p.drawTextLeft(nameleft, statustop, _width, _statusText); @@ -805,12 +810,12 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x bool wthumb = withThumb(); if (_data->song()) { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; + nameleft = _st.songPadding.left() + _st.songThumbSize + _st.songPadding.right(); + nameright = _st.songPadding.left(); + nametop = _st.songNameTop; + statustop = _st.songStatusTop; - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + auto inner = rtlrect(_st.songPadding.left(), _st.songPadding.top(), _st.songThumbSize, _st.songThumbSize, _width); if (inner.contains(x, y)) { link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); return; @@ -820,12 +825,12 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x return; } } else { - nameleft = st::overviewFileSize + st::overviewFilePadding.right(); - nametop = st::linksBorder + st::overviewFileNameTop; - statustop = st::linksBorder + st::overviewFileStatusTop; - datetop = st::linksBorder + st::overviewFileDateTop; + nameleft = _st.fileThumbSize + _st.filePadding.right(); + nametop = st::linksBorder + _st.fileNameTop; + statustop = st::linksBorder + _st.fileStatusTop; + datetop = st::linksBorder + _st.fileDateTop; - QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); + auto rthumb = rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width); if (rthumb.contains(x, y)) { link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); @@ -843,7 +848,7 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x link = _namel; return; } - if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _namew), st::semiboldFont->height, _width).contains(x, y)) { + if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _name.maxWidth()), st::semiboldFont->height, _width).contains(x, y)) { link = _namel; return; } diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index af49c4bb8..3909487a6 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "layout.h" #include "core/click_handler_types.h" #include "ui/effects/radial_animation.h" +#include "styles/style_overview.h" namespace Overview { namespace Layout { @@ -261,7 +262,7 @@ private: class Document : public FileBase { public: - Document(DocumentData *document, HistoryItem *parent); + Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st); void initDimensions() override; void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override; @@ -289,11 +290,14 @@ private: DocumentData *_data; ClickHandlerPtr _msgl, _namel; - mutable bool _thumbForLoaded; + const style::OverviewFileLayout &_st; + + mutable bool _thumbForLoaded = false; mutable QPixmap _thumb; - QString _name, _date, _ext; - int32 _namew, _datew, _extw; + Text _name; + QString _date, _ext; + int32 _datew, _extw; int32 _thumbw, _colorIndex; bool withThumb() const { diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index cf24529fe..50883ebe9 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -1308,7 +1308,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh } else if (_type == OverviewLinks) { _rowWidth = qMin(_width - st::linksSearchMargin.left() - st::linksSearchMargin.right(), int32(st::linksMaxWidth)); } else { - _rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), int32(st::profileMaxWidth)); + _rowWidth = qMin(_width - st::profilePadding.left() - st::profilePadding.right(), st::overviewFileLayout.maxWidth); } _rowsLeft = (_width - _rowWidth) / 2; @@ -1859,7 +1859,7 @@ Overview::Layout::ItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { } else if (_type == OverviewFiles || _type == OverviewMusicFiles) { if (media && (media->type() == MediaTypeFile || media->type() == MediaTypeMusicFile || media->type() == MediaTypeGif)) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { - i = _layoutItems.insert(item, new Overview::Layout::Document(media->getDocument(), item)); + i = _layoutItems.insert(item, new Overview::Layout::Document(media->getDocument(), item, st::overviewFileLayout)); i.value()->initDimensions(); } } diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index d23146497..e916a98d0 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -50,17 +50,6 @@ public: bool preloadLocal(); void preloadMore(); - bool event(QEvent *e) override; - void touchEvent(QTouchEvent *e); - void paintEvent(QPaintEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void keyPressEvent(QKeyEvent *e) override; - void enterEvent(QEvent *e) override; - void leaveEvent(QEvent *e) override; - void resizeEvent(QResizeEvent *e) override; - void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); void dragActionStart(const QPoint &screenPos, Qt::MouseButton button = Qt::LeftButton); @@ -96,6 +85,18 @@ public: ~OverviewInner(); +protected: + bool event(QEvent *e) override; + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + public slots: void onUpdateSelected(); @@ -256,10 +257,6 @@ public: void clear(); - void resizeEvent(QResizeEvent *e) override; - void paintEvent(QPaintEvent *e) override; - void contextMenuEvent(QContextMenuEvent *e) override; - void scrollBy(int32 add); void scrollReset(); @@ -320,6 +317,11 @@ public: ~OverviewWidget(); +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; + public slots: void activate(); void onScroll(); diff --git a/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp b/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp index 3e5a9a53a..e0fea6107 100644 --- a/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp +++ b/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp @@ -137,6 +137,8 @@ void ContinuousSlider::wheelEvent(QWheelEvent *e) { auto deltaX = e->angleDelta().x(), deltaY = e->angleDelta().y(); if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { deltaY *= -1; + } else { + deltaX *= -1; } if (deltaX * deltaY < 0) { return; diff --git a/Telegram/SourceFiles/ui/widgets/shadow.h b/Telegram/SourceFiles/ui/widgets/shadow.h index 92e1f3443..798a45dd5 100644 --- a/Telegram/SourceFiles/ui/widgets/shadow.h +++ b/Telegram/SourceFiles/ui/widgets/shadow.h @@ -44,4 +44,23 @@ private: }; +class GradientShadow : public TWidget { +public: + GradientShadow(QWidget *parent, const style::icon &icon) : TWidget(parent), _icon(icon) { + } + +protected: + int resizeGetHeight(int newWidth) override { + return _icon.height(); + } + void paintEvent(QPaintEvent *e) override { + Painter p(this); + _icon.fill(p, e->rect()); + } + +private: + const style::icon &_icon; + +}; + } // namespace Ui