From db7fa9ba2fc7a98bac8a9e00d8784c06c9936a91 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 20 Aug 2014 23:13:00 +0400
Subject: [PATCH] multi select in media overview done properly

---
 .../SourceFiles/boxes/addparticipantbox.cpp   |  14 +-
 .../SourceFiles/boxes/addparticipantbox.h     |   1 +
 Telegram/SourceFiles/boxes/newgroupbox.cpp    |  14 +-
 Telegram/SourceFiles/boxes/newgroupbox.h      |   1 +
 Telegram/SourceFiles/historywidget.cpp        |   7 +-
 Telegram/SourceFiles/mainwidget.cpp           |   4 +
 Telegram/SourceFiles/mainwidget.h             |   1 +
 Telegram/SourceFiles/overviewwidget.cpp       | 139 ++++++++++++++----
 Telegram/SourceFiles/overviewwidget.h         |   4 +
 Telegram/SourceFiles/window.cpp               |   1 +
 10 files changed, 127 insertions(+), 59 deletions(-)

diff --git a/Telegram/SourceFiles/boxes/addparticipantbox.cpp b/Telegram/SourceFiles/boxes/addparticipantbox.cpp
index 5659c657c..d9db93b38 100644
--- a/Telegram/SourceFiles/boxes/addparticipantbox.cpp
+++ b/Telegram/SourceFiles/boxes/addparticipantbox.cpp
@@ -242,18 +242,7 @@ void AddParticipantInner::chooseParticipant() {
 		changeCheckState(row);
 
 		PeerData *peer = row->history->peer;
-		updateFilter();
-
-		for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) {
-			if (_sel->history->peer == peer) {
-				break;
-			}
-		}
-		if (_sel == _contacts->list.end) {
-			_sel = 0;
-		} else {
-			emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
-		}
+		emit selectAllQuery();
 	}
 	parentWidget()->update();
 }
@@ -530,6 +519,7 @@ AddParticipantBox::AddParticipantBox(ChatData *chat) :
 	connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
 	connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose()));
 	connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
+	connect(&_inner, SIGNAL(selectAllQuery()), &_filter, SLOT(selectAll()));
 
 	showAll();
 	_cache = myGrab(this, rect());
diff --git a/Telegram/SourceFiles/boxes/addparticipantbox.h b/Telegram/SourceFiles/boxes/addparticipantbox.h
index 966ab1778..8f797997b 100644
--- a/Telegram/SourceFiles/boxes/addparticipantbox.h
+++ b/Telegram/SourceFiles/boxes/addparticipantbox.h
@@ -50,6 +50,7 @@ public:
 signals:
 
 	void mustScrollTo(int ymin, int ymax);
+	void selectAllQuery();
 
 public slots:
 
diff --git a/Telegram/SourceFiles/boxes/newgroupbox.cpp b/Telegram/SourceFiles/boxes/newgroupbox.cpp
index a2822e94a..d93e3518c 100644
--- a/Telegram/SourceFiles/boxes/newgroupbox.cpp
+++ b/Telegram/SourceFiles/boxes/newgroupbox.cpp
@@ -233,18 +233,7 @@ void NewGroupInner::chooseParticipant() {
 		changeCheckState(row);
 
 		PeerData *peer = row->history->peer;
-		updateFilter();
-
-		for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) {
-			if (_sel->history->peer == peer) {
-				break;
-			}
-		}
-		if (_sel == _contacts->list.end) {
-			_sel = 0;
-		} else {
-			emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
-		}
+		emit selectAllQuery();
 	}
 
 	parentWidget()->update();
@@ -469,6 +458,7 @@ NewGroupBox::NewGroupBox() : _scroll(this, st::newGroupScroll), _inner(),
 	connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
 	connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose()));
 	connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
+	connect(&_inner, SIGNAL(selectAllQuery()), &_filter, SLOT(selectAll()));
 
 	showAll();
 	_cache = myGrab(this, rect());
diff --git a/Telegram/SourceFiles/boxes/newgroupbox.h b/Telegram/SourceFiles/boxes/newgroupbox.h
index f08804f13..7cb856eca 100644
--- a/Telegram/SourceFiles/boxes/newgroupbox.h
+++ b/Telegram/SourceFiles/boxes/newgroupbox.h
@@ -50,6 +50,7 @@ public:
 signals:
 
 	void mustScrollTo(int ymin, int ymax);
+	void selectAllQuery();
 
 public slots:
 
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 138d7e00d..3cd5ac269 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -467,7 +467,7 @@ void HistoryList::itemRemoved(HistoryItem *item) {
 	SelectedItems::iterator i = _selected.find(item);
 	if (i != _selected.cend()) {
 		_selected.erase(i);
-		update();
+		historyWidget->updateTopBarSelection();
 	}
 
 	onUpdateSelected();
@@ -475,8 +475,6 @@ void HistoryList::itemRemoved(HistoryItem *item) {
 	if (_dragSelFrom == item) _dragSelFrom = 0;
 	if (_dragSelTo == item) _dragSelTo = 0;
 	updateDragSelection(_dragSelFrom, _dragSelTo, _dragSelecting, true);
-
-	parentWidget()->update();
 }
 
 void HistoryList::dragActionFinish(const QPoint &screenPos, Qt::MouseButton button) {
@@ -1154,8 +1152,8 @@ void HistoryList::applyDragSelection() {
 				HistoryBlock *block = (*hist)[fromblock];
 				for (int32 cnt = (fromblock < toblock) ? block->size() : (toitem + 1); fromitem < cnt; ++fromitem) {
 					HistoryItem *item = (*block)[fromitem];
+					SelectedItems::iterator i = _selected.find(item);
 					if (item->id > 0 && !item->serviceMsg()) {
-						SelectedItems::iterator i = _selected.find(item);
 						if (i == _selected.cend()) {
 							if (_selected.size() >= MaxSelectedItems) break;
 							_selected.insert(item, FullItemSel);
@@ -1163,7 +1161,6 @@ void HistoryList::applyDragSelection() {
 							*i = FullItemSel;
 						}
 					} else {
-						SelectedItems::iterator i = _selected.find(item);
 						if (i != _selected.cend()) {
 							_selected.erase(i);
 						}
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 3f3c7e0f2..9b3cf8aa9 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -642,6 +642,10 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer) {
 	if (overview) overview->mediaOverviewUpdated(peer);
 }
 
+void MainWidget::changingMsgId(HistoryItem *row, MsgId newId) {
+	if (overview) overview->changingMsgId(row, newId);
+}
+
 bool MainWidget::overviewFailed(PeerData *peer, const RPCError &error, mtpRequestId req) {
 	MediaOverviewType type = OverviewCount;
 	for (int32 i = 0; i < OverviewCount; ++i) {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 6dc6fc966..e41b2325e 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -271,6 +271,7 @@ public:
 	void searchMessages(const QString &query);
 	void preloadOverviews(PeerData *peer);
 	void mediaOverviewUpdated(PeerData *peer);
+	void changingMsgId(HistoryItem *row, MsgId newId);
 
 	void loadMediaBack(PeerData *peer, MediaOverviewType type, bool many = false);
 
diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp
index e1678d4cc..a16e9d5e3 100644
--- a/Telegram/SourceFiles/overviewwidget.cpp
+++ b/Telegram/SourceFiles/overviewwidget.cpp
@@ -161,26 +161,20 @@ bool OverviewInner::itemHasPoint(MsgId msgId, int32 index, int32 x, int32 y) con
 	if (index < 0) return false;
 
 	if (_type == OverviewPhotos) {
-		int32 row = (_photosToAdd + index) / _photosInRow, col = (_photosToAdd + index) % _photosInRow, vsize = _vsize + st::overviewPhotoSkip;
-		if (y >= _addToY + row * vsize + st::overviewPhotoSkip && y < _addToY + (row + 1) * vsize) {
-			float64 w = (_width - st::overviewPhotoSkip) / float64(_photosInRow);
-			if (x >= int32(col * w + st::overviewPhotoSkip) && x < int32(col * w + vsize)) {
-				return true;
-			}
+		if (x >= 0 && x < _vsize && y >= 0 && y < _vsize) {
+			return true;
 		}
 	} else {
 		HistoryItem *item = App::histItemById(msgId);
 		HistoryMedia *media = item ? item->getMedia(true) : 0;
 		if (media) {
 			int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
-			y -= _addToY + (_height - _items[index].y);
 			bool out = item->out();
 			int32 mw = media->maxWidth(), left = (out ? st::msgMargin.right() : st::msgMargin.left()) + (out && mw < w ? (w - mw) : 0);
 			if (!out && _hist->peer->chat) {
 				left += st::msgPhotoSkip;
 			}
-			x -= left;
-			return media->hasPoint(x, y, w);
+			return media->hasPoint(x - left, y - st::msgMargin.top(), w);
 		}
 	}
 	return false;
@@ -485,11 +479,17 @@ void OverviewInner::applyDragSelection() {
 			if (!msgid) continue;
 
 			SelectedItems::iterator j = _selected.find(msgid);
-			if (j == _selected.cend()) {
-				if (_selected.size() >= MaxSelectedItems) break;
-				_selected.insert(msgid, FullItemSel);
-			} else if (j.value() != FullItemSel) {
-				*j = FullItemSel;
+			if (msgid > 0) {
+				if (j == _selected.cend()) {
+					if (_selected.size() >= MaxSelectedItems) break;
+					_selected.insert(msgid, FullItemSel);
+				} else if (j.value() != FullItemSel) {
+					*j = FullItemSel;
+				}
+			} else {
+				if (j != _selected.cend()) {
+					_selected.erase(j);
+				}
 			}
 		}
 	} else {
@@ -514,7 +514,7 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) {
 	if (_type == OverviewPhotos) {
 		int32 row = (_photosToAdd + itemIndex) / _photosInRow, col = (_photosToAdd + itemIndex) % _photosInRow;
 		float64 w = (_width - st::overviewPhotoSkip) / float64(_photosInRow);
-		p.setX(p.x() - col * int32(w) - st::overviewPhotoSkip);
+		p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip);
 		p.setY(p.y() - _addToY - row * (_vsize + st::overviewPhotoSkip) - st::overviewPhotoSkip);
 	} else {
 		p.setY(p.y() - _addToY - (_height - _items[itemIndex].y));
@@ -616,7 +616,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
 					}
 
 					uint32 sel = 0;
-					if (count - index - 1 >= selfrom && count - index - 1 <= selto) {
+					if (index >= selfrom && index <= selto) {
 						sel = (_dragSelecting && item->id > 0) ? FullItemSel : 0;
 					} else if (hasSel) {
 						SelectedItems::const_iterator i = _selected.constFind(item->id);
@@ -713,8 +713,8 @@ void OverviewInner::onUpdateSelected() {
 	int32 index = -1;
 	if (_type == OverviewPhotos) {
 		float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow);
-		int32 inRow = int32(m.x() / w), vsize = (_vsize + st::overviewPhotoSkip);
-		int32 row = int32((m.y() - _addToY) / vsize);
+		int32 inRow = int32((m.x() - (st::overviewPhotoSkip / 2)) / w), vsize = (_vsize + st::overviewPhotoSkip);
+		int32 row = int32((m.y() - _addToY - (st::overviewPhotoSkip / 2)) / vsize);
 		if (inRow < 0) inRow = 0;
 		if (row < 0) row = 0;
 		bool upon = true;
@@ -761,9 +761,11 @@ void OverviewInner::onUpdateSelected() {
 					if (i > 0 && ((y + h / 2) < m.y() || i == _items.size() - 1)) {
 						--i;
 						if (!_items[i].msgid) break; // wtf
+						y = _addToY + _height - _items[i].y;
 					} else if (i < _items.size() - 1 && ((y + h / 2) >= m.y() || !i)) {
 						++i;
 						if (!_items[i].msgid) break; // wtf
+						y = _addToY + _height - _items[i].y;
 					} else {
 						break; // wtf
 					}
@@ -816,7 +818,7 @@ void OverviewInner::onUpdateSelected() {
 			cur = style::cur_pointer;
 		}
 	} else {
-		if (_dragItemIndex < 0 || _mousedItem < 0) {
+		if (_dragItemIndex < 0 || _mousedItemIndex < 0) {
 			_dragAction = NoDrag;
 			return;
 		}
@@ -829,28 +831,52 @@ void OverviewInner::onUpdateSelected() {
 		}
 		cur = textlnkDown() ? style::cur_pointer : style::cur_default;
 		if (_dragAction == Selecting) {
-			bool selectingDown = (_mousedItemIndex < _dragItemIndex) || (_mousedItemIndex == _dragItemIndex && _dragStartPos.y() < m.y());
+			bool selectingDown = (_type == OverviewPhotos ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && (_type == OverviewPhotos ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
 			MsgId dragSelFrom = _dragItem, dragSelTo = _mousedItem;
 			int32 dragSelFromIndex = _dragItemIndex, dragSelToIndex = _mousedItemIndex;
 			if (!itemHasPoint(dragSelFrom, dragSelFromIndex, _dragStartPos.x(), _dragStartPos.y())) { // maybe exclude dragSelFrom
 				if (selectingDown) {
-					if (_dragStartPos.y() >= ((_type == OverviewPhotos) ? _vsize : (itemHeight(dragSelFrom, dragSelFromIndex) - st::msgMargin.bottom())) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
-						moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
+					if (_type == OverviewPhotos) {
+						if (_dragStartPos.x() >= _vsize || ((_mousedItem == dragSelFrom) && (m.x() < _dragStartPos.x() + QApplication::startDragDistance()))) {
+							moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
+						}
+					} else {
+						if (_dragStartPos.y() >= (itemHeight(dragSelFrom, dragSelFromIndex) - st::msgMargin.bottom()) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
+							moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
+						}
 					}
 				} else {
-					if (_dragStartPos.y() < ((_type == OverviewPhotos ? 0 : st::msgMargin.top())) || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
-						moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
+					if (_type == OverviewPhotos) {
+						if (_dragStartPos.x() < 0 || ((_mousedItem == dragSelFrom) && (m.x() >= _dragStartPos.x() - QApplication::startDragDistance()))) {
+							moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
+						}
+					} else {
+						if (_dragStartPos.y() < st::msgMargin.top() || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
+							moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
+						}
 					}
 				}
 			}
 			if (_dragItem != _mousedItem) { // maybe exclude dragSelTo
 				if (selectingDown) {
-					if (m.y() < ((_type == OverviewPhotos) ? 0 : st::msgMargin.top())) {
-						moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
+					if (_type == OverviewPhotos) {
+						if (m.x() < 0) {
+							moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
+						}
+					} else {
+						if (m.y() < st::msgMargin.top()) {
+							moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
+						}
 					}
 				} else {
-					if (m.y() >= ((_type == OverviewPhotos) ? _vsize : (itemHeight(dragSelTo, dragSelToIndex) - st::msgMargin.bottom()))) {
-						moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
+					if (_type == OverviewPhotos) {
+						if (m.x() >= _vsize) {
+							moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
+						}
+					} else {
+						if (m.y() >= itemHeight(dragSelTo, dragSelToIndex) - st::msgMargin.bottom()) {
+							moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
+						}
 					}
 				}
 			}
@@ -858,7 +884,7 @@ void OverviewInner::onUpdateSelected() {
 			MsgId dragFirstAffected = dragSelFrom;
 			int32 dragFirstAffectedIndex = dragSelFromIndex;
 			while (dragFirstAffectedIndex >= 0 && dragFirstAffected <= 0) {
-				moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, selectingDown ? -1 : 1);
+				moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, ((selectingDown && (_type == OverviewPhotos)) || (!selectingDown && (_type != OverviewPhotos))) ? -1 : 1);
 			}
 			if (dragFirstAffectedIndex >= 0) {
 				SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected);
@@ -1132,7 +1158,7 @@ void OverviewInner::fillSelectedItems(SelectedItemSet &sel, bool forDelete) {
 	for (SelectedItems::const_iterator i = _selected.cbegin(), e = _selected.cend(); i != e; ++i) {
 		HistoryItem *item = App::histItemById(i.key());
 		if (item && item->itemType() == HistoryItem::MsgType && ((item->id > 0 && !item->serviceMsg()) || forDelete)) {
-			sel.insert(item->y + item->block()->y, item);
+			sel.insert(item->id, item);
 		}
 	}
 }
@@ -1251,6 +1277,53 @@ void OverviewInner::mediaOverviewUpdated() {
 	}
 }
 
+void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) {
+	if (_dragSelFrom == row->id) _dragSelFrom = newId;
+	if (_dragSelTo == row->id) _dragSelTo = newId;
+	if (_mousedItem == row->id) _mousedItem = newId;
+	if (_dragItem == row->id) _dragItem = newId;
+	for (SelectedItems::iterator i = _selected.begin(), e = _selected.end(); i != e; ++i) {
+		if (i.key() == row->id) {
+			uint32 sel = i.value();
+			_selected.erase(i);
+			_selected.insert(newId, sel);
+			break;
+		}
+	}
+	for (CachedItems::iterator i = _items.begin(), e = _items.end(); i != e; ++i) {
+		if (i->msgid == row->id) {
+			i->msgid = newId;
+			break;
+		}
+	}
+}
+
+void OverviewInner::itemRemoved(HistoryItem *item) {
+	if (_dragItem == item->id) {
+		dragActionCancel();
+	}
+
+	SelectedItems::iterator i = _selected.find(item->id);
+	if (i != _selected.cend()) {
+		_selected.erase(i);
+		_overview->updateTopBarSelection();
+	}
+
+	onUpdateSelected();
+
+	if (_dragSelFrom == item->id) {
+		_dragSelFrom = 0;
+		_dragSelFromIndex = -1;
+	}
+	if (_dragSelTo == item->id) {
+		_dragSelTo = 0;
+		_dragSelToIndex = -1;
+	}
+	updateDragSelection(_dragSelFrom, _dragSelFromIndex, _dragSelTo, _dragSelToIndex, _dragSelecting);
+
+	parentWidget()->update();
+}
+
 void OverviewInner::msgUpdated(HistoryItem *msg) {
 	if (!msg || _hist != msg->history()) return;
 	MsgId msgid = msg->id;
@@ -1507,6 +1580,12 @@ void OverviewWidget::mediaOverviewUpdated(PeerData *p) {
 	}
 }
 
+void OverviewWidget::changingMsgId(HistoryItem *row, MsgId newId) {
+	if (peer() == row->history()->peer) {
+		_inner.changingMsgId(row, newId);
+	}
+}
+
 void OverviewWidget::msgUpdated(PeerId p, HistoryItem *msg) {
 	if (peer()->id == p) {
 		_inner.msgUpdated(msg);
diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h
index 26f2059d7..bbe3084bd 100644
--- a/Telegram/SourceFiles/overviewwidget.h
+++ b/Telegram/SourceFiles/overviewwidget.h
@@ -56,6 +56,7 @@ public:
 	void switchType(MediaOverviewType type);
 
 	void mediaOverviewUpdated();
+	void changingMsgId(HistoryItem *row, MsgId newId);
 	void msgUpdated(HistoryItem *msg);
 
 	void getSelectionState(int32 &selectedForForward, int32 &selectedForDelete) const;
@@ -82,6 +83,8 @@ public slots:
 	void onTouchSelect();
 	void onTouchScrollTimer();
 
+	void itemRemoved(HistoryItem *item);
+
 private:
 
 	void fixItemIndex(int32 &current, MsgId msgId) const;
@@ -208,6 +211,7 @@ public:
 	bool animStep(float64 ms);
 
 	void mediaOverviewUpdated(PeerData *peer);
+	void changingMsgId(HistoryItem *row, MsgId newId);
 	void msgUpdated(PeerId peer, HistoryItem *msg);
 
 	QPoint clampMousePosition(QPoint point);
diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp
index fc79a3d73..206b2d9b2 100644
--- a/Telegram/SourceFiles/window.cpp
+++ b/Telegram/SourceFiles/window.cpp
@@ -1214,6 +1214,7 @@ void Window::mediaOverviewUpdated(PeerData *peer) {
 }
 
 void Window::changingMsgId(HistoryItem *row, MsgId newId) {
+	if (main) main->changingMsgId(row, newId);
 	if (!_mediaView || _mediaView->isHidden()) return;
 	_mediaView->changingMsgId(row, newId);
 }