diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index f07ba411f..1439518f5 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -596,7 +596,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_group_invite_create" = "Create an invite link"; "lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link."; "lng_group_invite_create_new" = "Revoke invite link"; -"lng_group_invite_about_new" = "Your previous link will be deactivated\nand we'll generate a new invite link for you."; +"lng_group_invite_about_new" = "Your previous link will be deactivated and we'll generate a new invite link for you."; "lng_group_invite_copied" = "Invite link copied to clipboard."; "lng_group_invite_no_room" = "Unable to join this group because there are too many members in it already."; diff --git a/Telegram/SourceFiles/core/click_handler.h b/Telegram/SourceFiles/core/click_handler.h index 8ceadfb81..61d9f3a56 100644 --- a/Telegram/SourceFiles/core/click_handler.h +++ b/Telegram/SourceFiles/core/click_handler.h @@ -145,9 +145,11 @@ public: } static void hostDestroyed(ClickHandlerHost *host) { if (_activeHost == host) { + if (_active) (*_active).clear(); _activeHost = nullptr; } if (_pressedHost == host) { + if (_pressed) (*_pressed).clear(); _pressedHost = nullptr; } } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 5ad3bd9ce..72d622bf8 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -772,6 +772,9 @@ void HistoryInner::onDragExec() { mimeData->setData(qsl("application/x-td-forward-selected"), "1"); } drag->setMimeData(mimeData); + + // We don't receive mouseReleaseEvent when drag is finished. + ClickHandler::unpressed(); drag->exec(Qt::CopyAction); if (App::main()) App::main()->updateAfterDrag(); return; @@ -806,6 +809,9 @@ void HistoryInner::onDragExec() { } drag->setMimeData(mimeData); + + // We don't receive mouseReleaseEvent when drag is finished. + ClickHandler::unpressed(); drag->exec(Qt::CopyAction); if (App::main()) App::main()->updateAfterDrag(); return; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 6439ad90a..8d8b1651d 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -615,6 +615,9 @@ void OverviewInner::onDragExec() { mimeData->setData(qsl("application/x-td-forward-selected"), "1"); } drag->setMimeData(mimeData); + + // We don't receive mouseReleaseEvent when drag is finished. + ClickHandler::unpressed(); drag->exec(Qt::CopyAction); if (App::main()) App::main()->updateAfterDrag(); return; @@ -643,6 +646,9 @@ void OverviewInner::onDragExec() { } drag->setMimeData(mimeData); + + // We don't receive mouseReleaseEvent when drag is finished. + ClickHandler::unpressed(); drag->exec(Qt::CopyAction); if (App::main()) App::main()->updateAfterDrag(); return; diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style index 186de113d..b26eb6f21 100644 --- a/Telegram/SourceFiles/profile/profile.style +++ b/Telegram/SourceFiles/profile/profile.style @@ -133,3 +133,7 @@ profileBlockOneLineTextPart: flatLabel(profileBlockTextPart) { } profileBlockOneLineSkip: 9px; profileBlockOneLineWidthMax: 240px; + +profileInviteLinkText: flatLabel(profileBlockTextPart) { + width: 1px; // Required for BreakEverywhere +} diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp index ea90d357c..c8a205425 100644 --- a/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp +++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp @@ -22,19 +22,92 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "profile/profile_invite_link_widget.h" #include "styles/style_profile.h" +#include "ui/flatlabel.h" +#include "boxes/confirmbox.h" +#include "observer_peer.h" #include "lang.h" namespace Profile { -InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section)) -{ - show(); +InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section)) { + auto observeEvents = Notify::PeerUpdateFlag::InviteLinkChanged; + Notify::registerPeerObserver(observeEvents, this, &InviteLinkWidget::notifyPeerUpdated); + + refreshLink(); + refreshVisibility(); +} + +void InviteLinkWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { + if (update.peer != peer()) { + return; + } + + if (update.flags & Notify::PeerUpdateFlag::InviteLinkChanged) { + refreshLink(); + refreshVisibility(); + + contentSizeUpdated(); + } } int InviteLinkWidget::resizeGetHeight(int newWidth) { int newHeight = contentTop(); + int marginLeft = st::profileBlockTextPart.margin.left(); + int marginRight = st::profileBlockTextPart.margin.right(); + int left = st::profileBlockTitlePosition.x(); + if (_link) { + int textWidth = _link->naturalWidth(); + int availableWidth = newWidth - left - st::profileBlockMarginRight; + int maxWidth = st::msgMaxWidth; + accumulate_min(textWidth, availableWidth); + accumulate_min(textWidth, st::msgMaxWidth); + _link->resizeToWidth(textWidth + marginLeft + marginRight); + _link->moveToLeft(left - marginLeft, newHeight - st::profileBlockTextPart.margin.top()); + newHeight += _link->height(); + } + + newHeight += st::profileBlockMarginBottom; return newHeight; } +void InviteLinkWidget::refreshVisibility() { + setVisible(_link != nullptr); +} + +QString InviteLinkWidget::getInviteLink() const { + if (auto chat = peer()->asChat()) { + return chat->inviteLink(); + } else if (auto channel = peer()->asChannel()) { + return channel->inviteLink(); + } + return QString(); +}; + +void InviteLinkWidget::refreshLink() { + _link.destroy(); + TextWithEntities linkData = { getInviteLink(), EntitiesInText() }; + if (!linkData.text.isEmpty()) { + _link = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::profileInviteLinkText); + _link->show(); + + linkData.entities.push_back(EntityInText(EntityInTextUrl, 0, linkData.text.size())); + _link->setMarkedText(linkData); + _link->setSelectable(true); + _link->setContextCopyText(QString()); + _link->setClickHandlerHook(func(this, &InviteLinkWidget::clickHandlerHook)); + } +} + +bool InviteLinkWidget::clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { + auto link = getInviteLink(); + if (link.isEmpty()) { + return true; + } + + QApplication::clipboard()->setText(link); + Ui::showLayer(new InformBox(lang(lng_group_invite_copied))); + return false; +} + } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.h b/Telegram/SourceFiles/profile/profile_invite_link_widget.h index c9eada6a2..76f3557c2 100644 --- a/Telegram/SourceFiles/profile/profile_invite_link_widget.h +++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.h @@ -21,10 +21,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "profile/profile_block_widget.h" +#include "core/observer.h" + +class FlatLabel; + +namespace Notify { +struct PeerUpdate; +} // namespace Notify namespace Profile { -class InviteLinkWidget : public BlockWidget { +class InviteLinkWidget : public BlockWidget, public Notify::Observer { public: InviteLinkWidget(QWidget *parent, PeerData *peer); @@ -32,6 +39,18 @@ protected: // Resizes content and counts natural widget height for the desired width. int resizeGetHeight(int newWidth) override; +private: + // Observed notifications. + void notifyPeerUpdated(const Notify::PeerUpdate &update); + + QString getInviteLink() const; + void refreshLink(); + void refreshVisibility(); + + bool clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button); + + ChildWidget _link = { nullptr }; + }; } // namespace Profile diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp index b30fbd94d..195d8f3ec 100644 --- a/Telegram/SourceFiles/ui/flatlabel.cpp +++ b/Telegram/SourceFiles/ui/flatlabel.cpp @@ -108,6 +108,10 @@ void FlatLabel::setExpandLinksMode(ExpandLinksMode mode) { _contextExpandLinksMode = mode; } +void FlatLabel::setBreakEverywhere(bool breakEverywhere) { + _breakEverywhere = breakEverywhere; +} + void FlatLabel::resizeToWidth(int32 width) { textstyleSet(&_tst); _allowedWidth = width; @@ -465,6 +469,9 @@ void FlatLabel::onExecuteDrag() { mimeData->setText(selectedText); auto drag = new QDrag(App::wnd()); drag->setMimeData(mimeData); + + // We don't receive mouseReleaseEvent when drag is finished. + ClickHandler::unpressed(); drag->exec(Qt::CopyAction); } } @@ -563,9 +570,15 @@ Text::StateResult FlatLabel::getTextState(const QPoint &m) const { textstyleSet(&_tst); Text::StateResult state; - if (_st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth())) { + bool heightExceeded = _st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth()); + bool renderElided = _breakEverywhere || heightExceeded; + if (renderElided) { auto lineHeight = qMax(_tst.lineHeight, _st.font->height); - request.lines = qMax(_st.maxHeight / lineHeight, 1); + auto lines = _st.maxHeight ? qMax(_st.maxHeight / lineHeight, 1) : ((height() / lineHeight) + 2); + request.lines = lines; + if (_breakEverywhere) { + request.flags |= Text::StateRequest::Flag::BreakEverywhere; + } state = _text.getStateElided(m.x() - _st.margin.left(), m.y() - _st.margin.top(), textWidth, request); } else { state = _text.getState(m.x() - _st.margin.left(), m.y() - _st.margin.top(), textWidth, request); @@ -587,10 +600,12 @@ void FlatLabel::paintEvent(QPaintEvent *e) { textstyleSet(&_tst); int textWidth = width() - _st.margin.left() - _st.margin.right(); auto selection = _selection.empty() ? (_contextMenu ? _savedSelection : _selection) : _selection; - if (_st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth())) { + bool heightExceeded = _st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth()); + bool renderElided = _breakEverywhere || heightExceeded; + if (renderElided) { auto lineHeight = qMax(_tst.lineHeight, _st.font->height); - auto lines = qMax(_st.maxHeight / lineHeight, 1); - _text.drawElided(p, _st.margin.left(), _st.margin.top(), textWidth, lines, _st.align, e->rect().y(), e->rect().bottom(), 0, false, selection); + auto lines = _st.maxHeight ? qMax(_st.maxHeight / lineHeight, 1) : ((height() / lineHeight) + 2); + _text.drawElided(p, _st.margin.left(), _st.margin.top(), textWidth, lines, _st.align, e->rect().y(), e->rect().bottom(), 0, _breakEverywhere, selection); } else { _text.draw(p, _st.margin.left(), _st.margin.top(), textWidth, _st.align, e->rect().y(), e->rect().bottom(), selection); } diff --git a/Telegram/SourceFiles/ui/flatlabel.h b/Telegram/SourceFiles/ui/flatlabel.h index 097213560..94b1ec88e 100644 --- a/Telegram/SourceFiles/ui/flatlabel.h +++ b/Telegram/SourceFiles/ui/flatlabel.h @@ -41,6 +41,7 @@ public: void setDoubleClickSelectsParagraph(bool doubleClickSelectsParagraph); void setContextCopyText(const QString ©Text); void setExpandLinksMode(ExpandLinksMode mode); + void setBreakEverywhere(bool breakEverywhere); void resizeToWidth(int32 width); int naturalWidth() const; @@ -106,6 +107,7 @@ private: int _allowedWidth = 0; int _fullTextHeight = 0; + bool _breakEverywhere = false; style::cursor _cursor = style::cur_default; bool _selectable = false;