diff --git a/Telegram/SourceFiles/info/media/info_media_list_section.cpp b/Telegram/SourceFiles/info/media/info_media_list_section.cpp index 96fd7727f2..e73d87805c 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_section.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_section.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/storage_shared_media.h" #include "layout/layout_selection.h" +#include "ui/rect.h" #include "ui/painter.h" #include "styles/style_chat_helpers.h" #include "styles/style_info.h" @@ -45,6 +46,10 @@ int ListSection::top() const { return _top; } +void ListSection::setCanReorder(bool value) { + _canReorder = value; +} + int ListSection::height() const { return _height; } @@ -276,6 +281,15 @@ void ListSection::paint( itemSelection(item, context), &localContext); p.translate(-rect.topLeft()); + + if (_canReorder && isOneColumn()) { + st::stickersReorderIcon.paint( + p, + rect::right(rect) - oneColumnRightPadding(), + (rect.height() - st::stickersReorderIcon.height()) / 2 + + rect.y(), + outerWidth); + } } } } @@ -334,6 +348,14 @@ int ListSection::headerHeight() const { return _header.isEmpty() ? 0 : st::infoMediaHeaderHeight; } +int ListSection::oneColumnRightPadding() const { + return !isOneColumn() + ? 0 + : _canReorder + ? st::stickersReorderIcon.width() + st::infoMediaLeft + : 0; +} + void ListSection::resizeToWidth(int newWidth) { auto minWidth = st::infoMediaMinGridSize + st::infoMediaSkip * 2; if (newWidth < minWidth) { @@ -341,12 +363,13 @@ void ListSection::resizeToWidth(int newWidth) { } auto resizeOneColumn = [&](int itemsLeft, int itemWidth) { + const auto rightPadding = oneColumnRightPadding(); _itemsLeft = itemsLeft; _itemsTop = 0; _itemsInRow = 1; - _itemWidth = itemWidth; + _itemWidth = itemWidth - rightPadding; for (auto &item : _items) { - item->resizeGetHeight(_itemWidth); + item->resizeGetHeight(_itemWidth - rightPadding); } }; switch (_type) { diff --git a/Telegram/SourceFiles/info/media/info_media_list_section.h b/Telegram/SourceFiles/info/media/info_media_list_section.h index bb8064ca8d..1d1468e985 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_section.h +++ b/Telegram/SourceFiles/info/media/info_media_list_section.h @@ -26,11 +26,13 @@ public: void setTop(int top); [[nodiscard]] int top() const; + void setCanReorder(bool); void resizeToWidth(int newWidth); [[nodiscard]] int height() const; [[nodiscard]] int bottom() const; [[nodiscard]] bool isOneColumn() const; + [[nodiscard]] int oneColumnRightPadding() const; bool removeItem(not_null item); void reorderItems(int oldPosition, int newPosition); @@ -89,6 +91,7 @@ private: mutable int _rowsCount = 0; int _top = 0; int _height = 0; + bool _canReorder = false; Mosaic::Layout::MosaicLayout _mosaic; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 6ff581cbe8..8ac6af9396 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -73,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_menu_icons.h" #include "styles/style_chat.h" #include "styles/style_credits.h" // giftBoxHiddenMark +#include "styles/style_chat_helpers.h" #include #include @@ -395,6 +396,8 @@ void ListWidget::restart() { _heavyLayouts.clear(); _provider->restart(); + + _reorderState = {}; } void ListWidget::itemRemoved(not_null item) { @@ -406,6 +409,10 @@ void ListWidget::itemRemoved(not_null item) { _contextItem = nullptr; } + if (_reorderState.item && _reorderState.item->getItem() == item) { + _reorderState = {}; + } + auto needHeightRefresh = false; auto sectionIt = findSectionByItem(item); if (sectionIt != _sections.end()) { @@ -673,6 +680,7 @@ void ListWidget::markStoryMsgsSelected() { void ListWidget::refreshRows() { saveScrollState(); + _reorderState = {}; _sections.clear(); _sections = _provider->fillSections(this); @@ -714,6 +722,7 @@ void ListWidget::restoreState(not_null memento) { int ListWidget::resizeGetHeight(int newWidth) { if (newWidth > 0) { for (auto §ion : _sections) { + section.setCanReorder(canReorder()); section.resizeToWidth(newWidth); } } @@ -985,6 +994,8 @@ void ListWidget::paintEvent(QPaintEvent *e) { if (_mouseAction == MouseAction::Reordering && _reorderState.item) { auto o = ScopedPainterOpacity(p, 0.8); p.translate(_reorderState.currentPos); + const auto isOneColumn = _reorderState.section + && _reorderState.section->isOneColumn(); _reorderState.item->paint( p, QRect( @@ -992,8 +1003,18 @@ void ListWidget::paintEvent(QPaintEvent *e) { 0, _reorderState.item->maxWidth(), _reorderState.item->minHeight()), - FullSelection, + isOneColumn ? TextSelection{} : FullSelection, &context.layoutContext); + + if (isOneColumn) { + st::stickersReorderIcon.paint( + p, + width() + - _reorderState.section->oneColumnRightPadding() * 2, + (_reorderState.item->minHeight() + - st::stickersReorderIcon.height()) / 2, + outerWidth); + } p.translate(-_reorderState.currentPos); } @@ -1769,7 +1790,11 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { auto local = mapFromGlobal(_mousePosition); auto point = clampMousePosition(local); - auto [layout, geometry, inside] = findItemByPoint(point); + auto [foundItem, section] = findItemByPointWithSection(point); + auto [layout, geometry, inside] = std::tie( + foundItem.layout, + foundItem.geometry, + foundItem.exact); auto state = MouseState{ layout->getItem(), geometry.size(), @@ -1783,6 +1808,19 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { } _overState = state; + const auto inDragArea = canReorder() + && section + && section->isOneColumn() + && point.y() >= geometry.y() + && point.y() < geometry.bottom() + && ((point.x() - geometry.x()) + >= (geometry.width() + - section->oneColumnRightPadding() + - st::stickersReorderSkip)); + if (_inDragArea != inDragArea) { + _inDragArea = inDragArea; + } + TextState dragState; ClickHandlerHost *lnkhost = nullptr; auto inTextSelection = _overState.inside @@ -1870,7 +1908,9 @@ void ListWidget::mouseActionUpdate(const QPoint &globalPosition) { } style::cursor ListWidget::computeMouseCursor() const { - if (ClickHandler::getPressed() || ClickHandler::getActive()) { + if (_inDragArea && canReorder()) { + return style::cur_sizeall; + } else if (ClickHandler::getPressed() || ClickHandler::getActive()) { return style::cur_pointer; } else if (!hasSelectedItems() && (_mouseCursorState == CursorState::Text)) { @@ -1955,6 +1995,13 @@ void ListWidget::mouseActionStart( false); } + if (_inDragArea && canReorder() && !hasSelected()) { + startReorder(globalPosition); + if (_mouseAction == MouseAction::PrepareReorder) { + return; + } + } + if (ClickHandler::getPressed() && !hasSelected()) { _mouseAction = MouseAction::PrepareDrag; if (canReorder()) { @@ -2297,16 +2344,23 @@ void ListWidget::startReorder(const QPoint &globalPos) { return; } const auto mapped = mapFromGlobal(globalPos); - const auto index = itemIndexFromPoint(mapped); + const auto foundWithSection = findItemByPointWithSection(mapped); + if (!foundWithSection.section) { + return; + } + if (foundWithSection.section->isOneColumn() + ? !_inDragArea + : !foundWithSection.item.exact) { + return; + } + const auto index = itemIndexFromPoint(mapped + - QPoint(foundWithSection.section->oneColumnRightPadding(), 0)); if (index < 0) { return; } - const auto found = findItemByPoint(mapped); - if (!found.exact) { - return; - } + if (_reorderDescriptor.filter) { - const auto item = found.layout->getItem(); + const auto item = foundWithSection.item.layout->getItem(); if (!_reorderDescriptor.filter(item)) { return; } @@ -2315,8 +2369,10 @@ void ListWidget::startReorder(const QPoint &globalPos) { _reorderState.index = index; _reorderState.targetIndex = index; _reorderState.startPos = globalPos; - _reorderState.dragPoint = mapped - found.geometry.topLeft(); - _reorderState.item = found.layout; + _reorderState.dragPoint = mapped + - foundWithSection.item.geometry.topLeft(); + _reorderState.item = foundWithSection.item.layout; + _reorderState.section = foundWithSection.section; _mouseAction = MouseAction::PrepareReorder; } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index e9f32d5020..e9e4798fe9 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -132,6 +132,7 @@ private: QPoint dragPoint; QPoint currentPos; BaseLayout *item = nullptr; + const Section *section = nullptr; }; struct ShiftAnimation { Ui::Animations::Simple xAnimation; @@ -373,6 +374,7 @@ private: int _activeShiftAnimations = 0; Ui::Animations::Simple _returnAnimation; ReorderDescriptor _reorderDescriptor; + bool _inDragArea = false; };