diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index c73defa5b..4c2760266 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -457,6 +457,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_profile_shared_links_header" = "Shared links overview"; "lng_profile_copy_phone" = "Copy phone number"; "lng_profile_copy_fullname" = "Copy name"; +"lng_profile_drop_area_title" = "Drop your image here"; +"lng_profile_drop_area_subtitle" = "to set it as a group photo"; "lng_channel_add_admins" = "New administrator"; "lng_channel_add_members" = "Add members"; diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style index 756d40781..5173d4e17 100644 --- a/Telegram/SourceFiles/profile/profile.style +++ b/Telegram/SourceFiles/profile/profile.style @@ -76,6 +76,16 @@ profileSecondaryButton: BoxButton(profilePrimaryButton) { textBgOver: #f2f7fa; } +profileDropAreaBg: profileBg; +profileDropAreaFg: #3fb0e4; +profileDropAreaPadding: margins(30px, 20px, 30px, 20px); +profileDropAreaTitleFont: font(24px); +profileDropAreaTitleTop: 36px; +profileDropAreaSubtitleFont: font(16px); +profileDropAreaSubtitleTop: 72px; +profileDropAreaBorderFg: profileDropAreaFg; +profileDropAreaBorderWidth: 3px; + profileDividerFg: black; profileDividerLeft: icon { { "profile_divider_left", profileDividerFg }, diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index d1bc03036..0a1c8556c 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -123,6 +123,50 @@ private: }; +class DropArea : public TWidget { +public: + DropArea(QWidget *parent) : TWidget(parent) { + } + + void showAnimated() { + show(); + } + +protected: + void paintEvent(QPaintEvent *e) override { + Painter p(this); + p.fillRect(e->rect(), st::profileDropAreaBg); + + if (width() < st::profileDropAreaPadding.left() + st::profileDropAreaPadding.right()) return; + if (height() < st::profileDropAreaPadding.top() + st::profileDropAreaPadding.bottom()) return; + + auto border = st::profileDropAreaBorderWidth; + auto &borderFg = st::profileDropAreaBorderFg; + auto inner = rect().marginsRemoved(st::profileDropAreaPadding); + p.fillRect(inner.x(), inner.y(), inner.width(), border, borderFg); + p.fillRect(inner.x(), inner.y() + inner.height() - border, inner.width(), border, borderFg); + p.fillRect(inner.x(), inner.y() + border, border, inner.height() - 2 * border, borderFg); + p.fillRect(inner.x() + inner.width() - border, inner.y() + border, border, inner.height() - 2 * border, borderFg); + + auto title = lang(lng_profile_drop_area_title); + int titleWidth = st::profileDropAreaTitleFont->width(title); + int titleLeft = inner.x() + (inner.width() - titleWidth) / 2; + int titleTop = inner.y() + st::profileDropAreaTitleTop + st::profileDropAreaTitleFont->ascent; + p.setFont(st::profileDropAreaTitleFont); + p.setPen(st::profileDropAreaFg); + p.drawText(titleLeft, titleTop, title); + + auto subtitle = lang(lng_profile_drop_area_subtitle); + int subtitleWidth = st::profileDropAreaSubtitleFont->width(subtitle); + int subtitleLeft = inner.x() + (inner.width() - subtitleWidth) / 2; + int subtitleTop = inner.y() + st::profileDropAreaSubtitleTop + st::profileDropAreaSubtitleFont->ascent; + p.setFont(st::profileDropAreaSubtitleFont); + p.setPen(st::profileDropAreaFg); + p.drawText(subtitleLeft, subtitleTop, subtitle); + } + +}; + CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent) , _peer(peer) , _peerUser(peer->asUser()) @@ -132,6 +176,7 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent) , _photoButton(this, peer) , _name(this, QString(), st::profileNameLabel) { setAttribute(Qt::WA_OpaquePaintEvent); + setAcceptDrops(true); _name.setSelectable(true); _name.setContextCopyText(lang(lng_profile_copy_fullname)); @@ -204,6 +249,23 @@ void CoverWidget::paintEvent(QPaintEvent *e) { paintDivider(p); } +void CoverWidget::dragEnterEvent(QDragEnterEvent *e) { + _dropArea = new DropArea(this); + _dropArea->setGeometry(0, 0, width(), _dividerTop); + _dropArea->showAnimated(); + e->accept(); +} + +void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { + delete _dropArea; + _dropArea = nullptr; +} + +void CoverWidget::dropEvent(QDropEvent *e) { + delete _dropArea; + _dropArea = nullptr; +} + void CoverWidget::paintDivider(Painter &p) { st::profileDividerLeft.paint(p, QPoint(st::lineWidth, _dividerTop), width()); diff --git a/Telegram/SourceFiles/profile/profile_cover.h b/Telegram/SourceFiles/profile/profile_cover.h index d0392a451..b5b67ef24 100644 --- a/Telegram/SourceFiles/profile/profile_cover.h +++ b/Telegram/SourceFiles/profile/profile_cover.h @@ -36,6 +36,7 @@ namespace Profile { class BackButton; class PhotoButton; +class DropArea; class CoverWidget final : public TWidget, public Notify::Observer { Q_OBJECT @@ -58,6 +59,9 @@ private slots: protected: void paintEvent(QPaintEvent *e) override; + void dragEnterEvent(QDragEnterEvent *e) override; + void dragLeaveEvent(QDragLeaveEvent *e) override; + void dropEvent(QDropEvent *e) override; private: // Observed notifications. @@ -85,8 +89,8 @@ private: ChannelData *_peerChannel; ChannelData *_peerMegagroup; - // Cover content ChildWidget _photoButton; + ChildWidget _dropArea = { nullptr }; FlatLabel _name; diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp index 57f2e272d..a4894247c 100644 --- a/Telegram/SourceFiles/ui/flatlabel.cpp +++ b/Telegram/SourceFiles/ui/flatlabel.cpp @@ -120,6 +120,7 @@ Text::StateResult FlatLabel::dragActionStart(const QPoint &p, Qt::MouseButton bu if (_dragWasInactive) App::wnd()->inactivePress(false); if (ClickHandler::getPressed()) { + _dragStartPosition = mapFromGlobal(_lastMousePos); _dragAction = PrepareDrag; } if (!_selectable || _dragAction != NoDrag) { @@ -147,6 +148,7 @@ Text::StateResult FlatLabel::dragActionStart(const QPoint &p, Qt::MouseButton bu } } if (uponSelected) { + _dragStartPosition = mapFromGlobal(_lastMousePos); _dragAction = PrepareDrag; // start text drag } else if (!_dragWasInactive) { if (state.afterSymbol) ++_dragSymbol; @@ -391,6 +393,33 @@ void FlatLabel::onContextMenuDestroy(QObject *obj) { } } +void FlatLabel::onExecuteDrag() { + if (_dragAction != Dragging) return; + + auto state = getTextState(_dragStartPosition); + bool uponSelected = state.uponSymbol && _selection.from <= state.symbol; + if (uponSelected) { + if (_dragSymbol < _selection.from || _dragSymbol >= _selection.to) { + uponSelected = false; + } + } + + ClickHandlerPtr pressedHandler = ClickHandler::getPressed(); + QString selectedText; + if (uponSelected) { + selectedText = _text.originalText(_selection, ExpandLinksAll); + } else if (pressedHandler) { + selectedText = pressedHandler->dragText(); + } + if (!selectedText.isEmpty()) { + auto mimeData = new QMimeData(); + mimeData->setText(selectedText); + auto drag = new QDrag(App::wnd()); + drag->setMimeData(mimeData); + drag->exec(Qt::CopyAction); + } +} + void FlatLabel::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) { update(); } @@ -400,10 +429,15 @@ void FlatLabel::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool a } Text::StateResult FlatLabel::dragActionUpdate() { - QPoint m(mapFromGlobal(_lastMousePos)); - LOG(("DRAG ACTION UPDATE: %1 %2").arg(m.x()).arg(m.y())); + auto m = mapFromGlobal(_lastMousePos); auto state = getTextState(m); updateHover(state); + + if (_dragAction == PrepareDrag && (m - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { + _dragAction = Dragging; + QTimer::singleShot(1, this, SLOT(onExecuteDrag())); + } + return state; } diff --git a/Telegram/SourceFiles/ui/flatlabel.h b/Telegram/SourceFiles/ui/flatlabel.h index 159ddf6a0..592065229 100644 --- a/Telegram/SourceFiles/ui/flatlabel.h +++ b/Telegram/SourceFiles/ui/flatlabel.h @@ -64,6 +64,8 @@ private slots: void onTouchSelect(); void onContextMenuDestroy(QObject *obj); + void onExecuteDrag(); + private: Text::StateResult dragActionUpdate(); Text::StateResult dragActionStart(const QPoint &p, Qt::MouseButton button); @@ -100,10 +102,10 @@ private: NoDrag = 0x00, PrepareDrag = 0x01, Dragging = 0x02, - PrepareSelect = 0x03, Selecting = 0x04, }; DragAction _dragAction = NoDrag; + QPoint _dragStartPosition; uint16 _dragSymbol = 0; bool _dragWasInactive = false;