mirror of https://github.com/procxx/kepka.git
				
				
				
			Alpha 1.0.4: Click and drag to reorder pinned chats.
This commit is contained in:
		
							parent
							
								
									b21f72fef0
								
							
						
					
					
						commit
						d1b9b8e3a3
					
				|  | @ -34,8 +34,8 @@ IDI_ICON1               ICON                    "..\\art\\icon256.ico" | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 1,0,3,0 |  FILEVERSION 1,0,4,0 | ||||||
|  PRODUCTVERSION 1,0,3,0 |  PRODUCTVERSION 1,0,4,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -51,10 +51,10 @@ BEGIN | ||||||
|         BLOCK "040904b0" |         BLOCK "040904b0" | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Telegram Messenger LLP" |             VALUE "CompanyName", "Telegram Messenger LLP" | ||||||
|             VALUE "FileVersion", "1.0.3.0" |             VALUE "FileVersion", "1.0.4.0" | ||||||
|             VALUE "LegalCopyright", "Copyright (C) 2014-2017" |             VALUE "LegalCopyright", "Copyright (C) 2014-2017" | ||||||
|             VALUE "ProductName", "Telegram Desktop" |             VALUE "ProductName", "Telegram Desktop" | ||||||
|             VALUE "ProductVersion", "1.0.3.0" |             VALUE "ProductVersion", "1.0.4.0" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
|  | @ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 1,0,3,0 |  FILEVERSION 1,0,4,0 | ||||||
|  PRODUCTVERSION 1,0,3,0 |  PRODUCTVERSION 1,0,4,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -43,10 +43,10 @@ BEGIN | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Telegram Messenger LLP" |             VALUE "CompanyName", "Telegram Messenger LLP" | ||||||
|             VALUE "FileDescription", "Telegram Updater" |             VALUE "FileDescription", "Telegram Updater" | ||||||
|             VALUE "FileVersion", "1.0.3.0" |             VALUE "FileVersion", "1.0.4.0" | ||||||
|             VALUE "LegalCopyright", "Copyright (C) 2014-2017" |             VALUE "LegalCopyright", "Copyright (C) 2014-2017" | ||||||
|             VALUE "ProductName", "Telegram Desktop" |             VALUE "ProductName", "Telegram Desktop" | ||||||
|             VALUE "ProductVersion", "1.0.3.0" |             VALUE "ProductVersion", "1.0.4.0" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
|  | @ -1069,8 +1069,8 @@ void AppClass::checkMapVersion() { | ||||||
|     if (Local::oldMapVersion() < AppVersion) { |     if (Local::oldMapVersion() < AppVersion) { | ||||||
| 		if (Local::oldMapVersion()) { | 		if (Local::oldMapVersion()) { | ||||||
| 			QString versionFeatures; | 			QString versionFeatures; | ||||||
| 			if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000003) { | 			if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000004) { | ||||||
| 				versionFeatures = QString::fromUtf8("\xe2\x80\x94 Audio device is opened only when some sound is played.\n\xe2\x80\x94 On Windows Vista and later audio device should switch after the system default changes."); | 				versionFeatures = QString::fromUtf8("\xe2\x80\x94 Click and drag to reorder pinned chats."); | ||||||
| 			} else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000002) { | 			} else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000002) { | ||||||
| 				versionFeatures = langNewVersionText(); | 				versionFeatures = langNewVersionText(); | ||||||
| 			} else { | 			} else { | ||||||
|  |  | ||||||
|  | @ -330,7 +330,7 @@ void SessionsBox::Inner::onTerminateAll() { | ||||||
| 			_terminateBox->closeBox(); | 			_terminateBox->closeBox(); | ||||||
| 			_terminateBox = nullptr; | 			_terminateBox = nullptr; | ||||||
| 		} | 		} | ||||||
| //		MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail));
 | 		MTP::send(MTPauth_ResetAuthorizations(), rpcDone(&Inner::terminateAllDone), rpcFail(&Inner::terminateAllFail)); | ||||||
| 		emit terminateAll(); | 		emit terminateAll(); | ||||||
| 	})), KeepOtherLayers); | 	})), KeepOtherLayers); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -860,7 +860,7 @@ void StickersBox::Inner::onUpdateSelected() { | ||||||
| 		} | 		} | ||||||
| 		_rows[_dragging]->yadd = anim::value(local.y() - _dragStart.y(), local.y() - _dragStart.y()); | 		_rows[_dragging]->yadd = anim::value(local.y() - _dragStart.y(), local.y() - _dragStart.y()); | ||||||
| 		_animStartTimes[_dragging] = 0; | 		_animStartTimes[_dragging] = 0; | ||||||
| 		_a_shifting.step(getms(), true); | 		_a_shifting.step(ms, true); | ||||||
| 
 | 
 | ||||||
| 		auto countDraggingScrollDelta = [this, local] { | 		auto countDraggingScrollDelta = [this, local] { | ||||||
| 			if (local.y() < _visibleTop) { | 			if (local.y() < _visibleTop) { | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | ||||||
| 
 | 
 | ||||||
| #define BETA_VERSION_MACRO (0ULL) | #define BETA_VERSION_MACRO (0ULL) | ||||||
| 
 | 
 | ||||||
| constexpr int AppVersion = 1000003; | constexpr int AppVersion = 1000004; | ||||||
| constexpr str_const AppVersionStr = "1.0.3"; | constexpr str_const AppVersionStr = "1.0.4"; | ||||||
| constexpr bool AppAlphaVersion = true; | constexpr bool AppAlphaVersion = true; | ||||||
| constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; | constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; | ||||||
|  |  | ||||||
|  | @ -81,6 +81,25 @@ void IndexedList::moveToTop(PeerData *peer) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void IndexedList::movePinned(Row *row, int deltaSign) { | ||||||
|  | 	auto swapPinnedIndexWith = find(row); | ||||||
|  | 	t_assert(swapPinnedIndexWith != cend()); | ||||||
|  | 	if (deltaSign > 0) { | ||||||
|  | 		++swapPinnedIndexWith; | ||||||
|  | 	} else { | ||||||
|  | 		t_assert(swapPinnedIndexWith != cbegin()); | ||||||
|  | 		--swapPinnedIndexWith; | ||||||
|  | 	} | ||||||
|  | 	auto history1 = row->history(); | ||||||
|  | 	auto history2 = (*swapPinnedIndexWith)->history(); | ||||||
|  | 	t_assert(history1->isPinnedDialog()); | ||||||
|  | 	t_assert(history2->isPinnedDialog()); | ||||||
|  | 	auto index1 = history1->getPinnedIndex(); | ||||||
|  | 	auto index2 = history2->getPinnedIndex(); | ||||||
|  | 	history1->setPinnedIndex(index2); | ||||||
|  | 	history2->setPinnedIndex(index1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { | void IndexedList::peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { | ||||||
| 	t_assert(_sortMode != SortMode::Date); | 	t_assert(_sortMode != SortMode::Date); | ||||||
| 	if (_sortMode == SortMode::Name) { | 	if (_sortMode == SortMode::Name) { | ||||||
|  |  | ||||||
|  | @ -36,6 +36,9 @@ public: | ||||||
| 	void adjustByPos(const RowsByLetter &links); | 	void adjustByPos(const RowsByLetter &links); | ||||||
| 	void moveToTop(PeerData *peer); | 	void moveToTop(PeerData *peer); | ||||||
| 
 | 
 | ||||||
|  | 	// row must belong to this indexed list all().
 | ||||||
|  | 	void movePinned(Row *row, int deltaSign); | ||||||
|  | 
 | ||||||
| 	// For sortMode != SortMode::Date
 | 	// For sortMode != SortMode::Date
 | ||||||
| 	void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); | 	void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -47,20 +47,6 @@ void List::adjustCurrent(int32 y, int32 h) const { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void List::paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground, TimeMs ms) const { |  | ||||||
| 	adjustCurrent(hFrom, st::dialogsRowHeight); |  | ||||||
| 
 |  | ||||||
| 	Row *row = _current; |  | ||||||
| 	p.translate(0, row->_pos * st::dialogsRowHeight); |  | ||||||
| 	while (row != _end && row->_pos * st::dialogsRowHeight < hTo) { |  | ||||||
| 		bool active = (row->history()->peer == act) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == act); |  | ||||||
| 		bool selected = (row->history()->peer == sel); |  | ||||||
| 		Layout::RowPainter::paint(p, row, w, active, selected, onlyBackground, ms); |  | ||||||
| 		row = row->_next; |  | ||||||
| 		p.translate(0, st::dialogsRowHeight); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Row *List::addToEnd(History *history) { | Row *List::addToEnd(History *history) { | ||||||
| 	Row *result = new Row(history, _end->_prev, _end, _end->_pos); | 	Row *result = new Row(history, _end->_prev, _end, _end->_pos); | ||||||
| 	_end->_pos++; | 	_end->_pos++; | ||||||
|  |  | ||||||
|  | @ -51,7 +51,6 @@ public: | ||||||
| 		return *i; | 		return *i; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void paint(Painter &p, int32 w, int32 hFrom, int32 hTo, PeerData *act, PeerData *sel, bool onlyBackground, TimeMs ms) const; |  | ||||||
| 	Row *addToEnd(History *history); | 	Row *addToEnd(History *history); | ||||||
| 	Row *adjustByName(const PeerData *peer); | 	Row *adjustByName(const PeerData *peer); | ||||||
| 	Row *addByName(History *history); | 	Row *addByName(History *history); | ||||||
|  |  | ||||||
|  | @ -44,10 +44,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org | ||||||
| #include "ui/widgets/input_fields.h" | #include "ui/widgets/input_fields.h" | ||||||
| #include "window/window_theme.h" | #include "window/window_theme.h" | ||||||
| #include "autoupdater.h" | #include "autoupdater.h" | ||||||
|  | #include "observer_peer.h" | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
| constexpr auto kHashtagResultsLimit = 5; | constexpr auto kHashtagResultsLimit = 5; | ||||||
|  | constexpr auto kStartReorderThreshold = 30; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
| 
 | 
 | ||||||
|  | @ -73,6 +75,7 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare | ||||||
| , _dialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date)) | , _dialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date)) | ||||||
| , _contactsNoDialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name)) | , _contactsNoDialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name)) | ||||||
| , _contacts(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name)) | , _contacts(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Name)) | ||||||
|  | , _a_pinnedShifting(animation(this, &DialogsInner::step_pinnedShifting)) | ||||||
| , _addContactLnk(this, lang(lng_add_contact_button)) | , _addContactLnk(this, lang(lng_add_contact_button)) | ||||||
| , _cancelSearchInPeer(this, st::dialogsCancelSearchInPeer) { | , _cancelSearchInPeer(this, st::dialogsCancelSearchInPeer) { | ||||||
| 	if (Global::DialogsModeEnabled()) { | 	if (Global::DialogsModeEnabled()) { | ||||||
|  | @ -101,6 +104,10 @@ DialogsInner::DialogsInner(QWidget *parent, QWidget *main) : SplittedWidget(pare | ||||||
| 		} | 		} | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
|  | 	subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::PinnedChanged, [this](const Notify::PeerUpdate &update) { | ||||||
|  | 		stopReorderPinned(); | ||||||
|  | 	})); | ||||||
|  | 
 | ||||||
| 	refresh(); | 	refresh(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -135,18 +142,60 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO | ||||||
| 	auto fullWidth = getFullWidth(); | 	auto fullWidth = getFullWidth(); | ||||||
| 	auto ms = getms(); | 	auto ms = getms(); | ||||||
| 	if (_state == DefaultState) { | 	if (_state == DefaultState) { | ||||||
| 		QRect dialogsClip = r; | 		auto rows = shownDialogs(); | ||||||
|  | 		auto dialogsClip = r; | ||||||
| 		if (_dialogsImportant) { | 		if (_dialogsImportant) { | ||||||
| 			auto selected = isPressed() ? _importantSwitchPressed : _importantSwitchSelected; | 			auto selected = isPressed() ? _importantSwitchPressed : _importantSwitchSelected; | ||||||
| 			Dialogs::Layout::paintImportantSwitch(p, Global::DialogsMode(), fullWidth, selected, paintingOther); | 			Dialogs::Layout::paintImportantSwitch(p, Global::DialogsMode(), fullWidth, selected, paintingOther); | ||||||
| 			dialogsClip.translate(0, -st::dialogsImportantBarHeight); | 			dialogsClip.translate(0, -st::dialogsImportantBarHeight); | ||||||
| 			p.translate(0, st::dialogsImportantBarHeight); | 			p.translate(0, st::dialogsImportantBarHeight); | ||||||
| 		} | 		} | ||||||
| 		auto otherStart = shownDialogs()->size() * st::dialogsRowHeight; | 		auto otherStart = rows->size() * st::dialogsRowHeight; | ||||||
| 		auto active = App::main()->activePeer(); | 		auto active = App::main()->activePeer(); | ||||||
| 		auto selected = _menuPeer ? _menuPeer : (isPressed() ? (_pressed ? _pressed->history()->peer : nullptr) : (_selected ? _selected->history()->peer : nullptr)); | 		auto selected = _menuPeer ? _menuPeer : (isPressed() ? (_pressed ? _pressed->history()->peer : nullptr) : (_selected ? _selected->history()->peer : nullptr)); | ||||||
| 		if (otherStart) { | 		if (otherStart) { | ||||||
| 			shownDialogs()->all().paint(p, fullWidth, dialogsClip.top(), dialogsClip.top() + dialogsClip.height(), active, selected, paintingOther, ms); | 			auto reorderingPinned = (_aboveIndex >= 0 && !_pinnedRows.isEmpty()); | ||||||
|  | 			auto &list = rows->all(); | ||||||
|  | 			if (reorderingPinned) { | ||||||
|  | 				dialogsClip = dialogsClip.marginsAdded(QMargins(0, st::dialogsRowHeight, 0, st::dialogsRowHeight)); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			auto i = list.cfind(dialogsClip.top(), st::dialogsRowHeight); | ||||||
|  | 			if (i != list.cend()) { | ||||||
|  | 				auto lastPaintedPos = (*i)->pos(); | ||||||
|  | 
 | ||||||
|  | 				// If we're reordering pinned chats we need to fill this area background first.
 | ||||||
|  | 				if (reorderingPinned) { | ||||||
|  | 					p.fillRect(0, 0, fullWidth, st::dialogsRowHeight * _pinnedRows.size(), st::dialogsBg); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				p.translate(0, lastPaintedPos * st::dialogsRowHeight); | ||||||
|  | 				for (auto e = list.cend(); i != e; ++i) { | ||||||
|  | 					auto row = (*i); | ||||||
|  | 					lastPaintedPos = row->pos(); | ||||||
|  | 					if (lastPaintedPos * st::dialogsRowHeight >= dialogsClip.top() + dialogsClip.height()) { | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// Skip currently dragged chat to paint it above others after.
 | ||||||
|  | 					if (lastPaintedPos != _aboveIndex) { | ||||||
|  | 						paintDialog(p, row, fullWidth, active, selected, paintingOther, ms); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					p.translate(0, st::dialogsRowHeight); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				// Paint the dragged chat above all others.
 | ||||||
|  | 				if (_aboveIndex >= 0) { | ||||||
|  | 					auto i = list.cfind(_aboveIndex, 1); | ||||||
|  | 					auto pos = (i == list.cend()) ? -1 : (*i)->pos(); | ||||||
|  | 					if (pos == _aboveIndex) { | ||||||
|  | 						p.translate(0, (pos - lastPaintedPos) * st::dialogsRowHeight); | ||||||
|  | 						paintDialog(p, *i, fullWidth, active, selected, paintingOther, ms); | ||||||
|  | 						p.translate(0, (lastPaintedPos - pos) * st::dialogsRowHeight); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		if (!otherStart) { | 		if (!otherStart) { | ||||||
| 			p.fillRect(dialogsClip, st::dialogsBg); | 			p.fillRect(dialogsClip, st::dialogsBg); | ||||||
|  | @ -294,6 +343,19 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void DialogsInner::paintDialog(Painter &p, Dialogs::Row *row, int fullWidth, PeerData *active, PeerData *selected, bool onlyBackground, TimeMs ms) { | ||||||
|  | 	auto pos = row->pos(); | ||||||
|  | 	auto xadd = 0, yadd = 0; | ||||||
|  | 	if (pos < _pinnedRows.size()) { | ||||||
|  | 		yadd = qRound(_pinnedRows[pos].yadd.current()); | ||||||
|  | 	} | ||||||
|  | 	if (xadd || yadd) p.translate(xadd, yadd); | ||||||
|  | 	auto isActive = (row->history()->peer == active) || (row->history()->peer->migrateTo() && row->history()->peer->migrateTo() == active); | ||||||
|  | 	auto isSelected = (row->history()->peer == selected); | ||||||
|  | 	Dialogs::Layout::RowPainter::paint(p, row, fullWidth, isActive, isSelected, onlyBackground, ms); | ||||||
|  | 	if (xadd || yadd) p.translate(-xadd, -yadd); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void DialogsInner::paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) const { | void DialogsInner::paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) const { | ||||||
| 	QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight); | 	QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight); | ||||||
| 	p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); | 	p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); | ||||||
|  | @ -399,7 +461,12 @@ void DialogsInner::clearIrrelevantState() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::updateSelected(QPoint localPos) { | void DialogsInner::updateSelected(QPoint localPos) { | ||||||
| 	if (!_mouseSelection) return; | 	if (updateReorderPinned(localPos)) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	if (!_mouseSelection) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	int w = width(), mouseY = localPos.y(); | 	int w = width(), mouseY = localPos.y(); | ||||||
| 	clearIrrelevantState(); | 	clearIrrelevantState(); | ||||||
|  | @ -495,6 +562,7 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) { | ||||||
| 		row->addRipple(e->pos() - QPoint(0, dialogsOffset() + _pressed->pos() * st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight), [row] { | 		row->addRipple(e->pos() - QPoint(0, dialogsOffset() + _pressed->pos() * st::dialogsRowHeight), QSize(getFullWidth(), st::dialogsRowHeight), [row] { | ||||||
| 			row->history()->updateChatListEntry(); | 			row->history()->updateChatListEntry(); | ||||||
| 		}); | 		}); | ||||||
|  | 		_dragStart = e->pos(); | ||||||
| 	} else if (_hashtagPressed >= 0 && _hashtagPressed < _hashtagResults.size() && !_hashtagDeletePressed) { | 	} else if (_hashtagPressed >= 0 && _hashtagPressed < _hashtagResults.size() && !_hashtagDeletePressed) { | ||||||
| 		auto row = &_hashtagResults[_hashtagPressed]->row; | 		auto row = &_hashtagResults[_hashtagPressed]->row; | ||||||
| 		row->addRipple(e->pos(), QSize(getFullWidth(), st::mentionHeight), [this, index = _hashtagPressed] { | 		row->addRipple(e->pos(), QSize(getFullWidth(), st::mentionHeight), [this, index = _hashtagPressed] { | ||||||
|  | @ -523,11 +591,233 @@ void DialogsInner::mousePressEvent(QMouseEvent *e) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void DialogsInner::checkReorderPinnedStart(QPoint localPosition) { | ||||||
|  | 	if (_pressed != nullptr && !_dragging && _state == DefaultState) { | ||||||
|  | 		if (qAbs(localPosition.y() - _dragStart.y()) >= convertScale(kStartReorderThreshold)) { | ||||||
|  | 			_dragging = _pressed; | ||||||
|  | 			if (updateReorderIndexGetCount() < 2) { | ||||||
|  | 				_dragging = nullptr; | ||||||
|  | 			} else { | ||||||
|  | 				_pinnedOrder = App::histories().getPinnedOrder(); | ||||||
|  | 				_pinnedRows[_draggingIndex].yadd = anim::value(0, localPosition.y() - _dragStart.y()); | ||||||
|  | 				_pinnedRows[_draggingIndex].animStartTime = getms(); | ||||||
|  | 				_a_pinnedShifting.start(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int DialogsInner::shownPinnedCount() const { | ||||||
|  | 	auto result = 0; | ||||||
|  | 	for_const (auto row, *shownDialogs()) { | ||||||
|  | 		if (!row->history()->isPinnedDialog()) { | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		++result; | ||||||
|  | 	} | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int DialogsInner::countPinnedIndex(Dialogs::Row *ofRow) { | ||||||
|  | 	if (!ofRow || !ofRow->history()->isPinnedDialog()) { | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	auto result = 0; | ||||||
|  | 	for_const (auto row, *shownDialogs()) { | ||||||
|  | 		if (!row->history()->isPinnedDialog()) { | ||||||
|  | 			break; | ||||||
|  | 		} else if (row == ofRow) { | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  | 		++result; | ||||||
|  | 	} | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogsInner::savePinnedOrder() { | ||||||
|  | 	auto newOrder = App::histories().getPinnedOrder(); | ||||||
|  | 	if (newOrder.size() != _pinnedOrder.size()) { | ||||||
|  | 		return; // Something has changed in the set of pinned chats.
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	auto peers = QVector<MTPInputPeer>(); | ||||||
|  | 	peers.reserve(newOrder.size()); | ||||||
|  | 	for_const (auto history, newOrder) { | ||||||
|  | 		if (_pinnedOrder.indexOf(history) < 0) { | ||||||
|  | 			return; // Something has changed in the set of pinned chats.
 | ||||||
|  | 		} | ||||||
|  | 		peers.push_back(history->peer->input); | ||||||
|  | 	} | ||||||
|  | 	auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force; | ||||||
|  | 	MTP::send(MTPmessages_ReorderPinnedDialogs(MTP_flags(qFlags(flags)), MTP_vector(peers))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogsInner::finishReorderPinned() { | ||||||
|  | 	auto wasDragging = (_dragging != nullptr); | ||||||
|  | 	if (wasDragging) { | ||||||
|  | 		savePinnedOrder(); | ||||||
|  | 		_dragging = nullptr; | ||||||
|  | 	} | ||||||
|  | 	_draggingIndex = -1; | ||||||
|  | 	if (!_a_pinnedShifting.animating()) { | ||||||
|  | 		_pinnedRows.clear(); | ||||||
|  | 		_aboveIndex = -1; | ||||||
|  | 	} | ||||||
|  | 	if (wasDragging) { | ||||||
|  | 		emit draggingScrollDelta(0); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogsInner::stopReorderPinned() { | ||||||
|  | 	_a_pinnedShifting.stop(); | ||||||
|  | 	finishReorderPinned(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int DialogsInner::updateReorderIndexGetCount() { | ||||||
|  | 	auto index = countPinnedIndex(_dragging); | ||||||
|  | 	if (index < 0) { | ||||||
|  | 		finishReorderPinned(); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	auto count = shownPinnedCount(); | ||||||
|  | 	t_assert(index < count); | ||||||
|  | 	if (count < 2) { | ||||||
|  | 		stopReorderPinned(); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_draggingIndex = index; | ||||||
|  | 	_aboveIndex = _draggingIndex; | ||||||
|  | 	while (count > _pinnedRows.size()) { | ||||||
|  | 		_pinnedRows.push_back(PinnedRow()); | ||||||
|  | 	} | ||||||
|  | 	while (count < _pinnedRows.size()) { | ||||||
|  | 		_pinnedRows.pop_back(); | ||||||
|  | 	} | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool DialogsInner::updateReorderPinned(QPoint localPosition) { | ||||||
|  | 	checkReorderPinnedStart(localPosition); | ||||||
|  | 	auto pinnedCount = updateReorderIndexGetCount(); | ||||||
|  | 	if (pinnedCount < 2) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	auto yaddWas = _pinnedRows[_draggingIndex].yadd.current(); | ||||||
|  | 	auto shift = 0; | ||||||
|  | 	auto ms = getms(); | ||||||
|  | 	auto rowHeight = st::dialogsRowHeight; | ||||||
|  | 	if (_dragStart.y() > localPosition.y() && _draggingIndex > 0) { | ||||||
|  | 		shift = -floorclamp(_dragStart.y() - localPosition.y() + (rowHeight / 2), rowHeight, 0, _draggingIndex); | ||||||
|  | 		for (auto from = _draggingIndex, to = _draggingIndex + shift; from > to; --from) { | ||||||
|  | 			shownDialogs()->movePinned(_dragging, -1); | ||||||
|  | 			std_::swap_moveable(_pinnedRows[from], _pinnedRows[from - 1]); | ||||||
|  | 			_pinnedRows[from].yadd = anim::value(_pinnedRows[from].yadd.current() - rowHeight, 0); | ||||||
|  | 			_pinnedRows[from].animStartTime = ms; | ||||||
|  | 		} | ||||||
|  | 	} else if (_dragStart.y() < localPosition.y() && _draggingIndex + 1 < pinnedCount) { | ||||||
|  | 		shift = floorclamp(localPosition.y() - _dragStart.y() + (rowHeight / 2), rowHeight, 0, pinnedCount - _draggingIndex - 1); | ||||||
|  | 		for (auto from = _draggingIndex, to = _draggingIndex + shift; from < to; ++from) { | ||||||
|  | 			shownDialogs()->movePinned(_dragging, 1); | ||||||
|  | 			std_::swap_moveable(_pinnedRows[from], _pinnedRows[from + 1]); | ||||||
|  | 			_pinnedRows[from].yadd = anim::value(_pinnedRows[from].yadd.current() + rowHeight, 0); | ||||||
|  | 			_pinnedRows[from].animStartTime = ms; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (shift) { | ||||||
|  | 		_draggingIndex += shift; | ||||||
|  | 		_aboveIndex = _draggingIndex; | ||||||
|  | 		_dragStart.setY(_dragStart.y() + shift * rowHeight); | ||||||
|  | 		if (!_a_pinnedShifting.animating()) { | ||||||
|  | 			_a_pinnedShifting.start(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	_aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current()); | ||||||
|  | 	_pinnedRows[_draggingIndex].yadd = anim::value(yaddWas - shift * rowHeight, localPosition.y() - _dragStart.y()); | ||||||
|  | 	if (!_pinnedRows[_draggingIndex].animStartTime) { | ||||||
|  | 		_pinnedRows[_draggingIndex].yadd.finish(); | ||||||
|  | 	} | ||||||
|  | 	_a_pinnedShifting.step(ms, true); | ||||||
|  | 
 | ||||||
|  | 	auto countDraggingScrollDelta = [this, localPosition] { | ||||||
|  | 		if (localPosition.y() < _visibleTop) { | ||||||
|  | 			return localPosition.y() - _visibleTop; | ||||||
|  | 		} | ||||||
|  | 		return 0; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	emit draggingScrollDelta(countDraggingScrollDelta()); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogsInner::step_pinnedShifting(TimeMs ms, bool timer) { | ||||||
|  | 	auto animating = false; | ||||||
|  | 	auto updateMin = -1; | ||||||
|  | 	auto updateMax = 0; | ||||||
|  | 	for (auto i = 0, l = _pinnedRows.size(); i != l; ++i) { | ||||||
|  | 		auto start = _pinnedRows[i].animStartTime; | ||||||
|  | 		if (start) { | ||||||
|  | 			if (updateMin < 0) updateMin = i; | ||||||
|  | 			updateMax = i; | ||||||
|  | 			if (start + st::stickersRowDuration > ms && ms >= start) { | ||||||
|  | 				_pinnedRows[i].yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut); | ||||||
|  | 				animating = true; | ||||||
|  | 			} else { | ||||||
|  | 				_pinnedRows[i].yadd.finish(); | ||||||
|  | 				_pinnedRows[i].animStartTime = 0; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (timer) { | ||||||
|  | 		updateReorderIndexGetCount(); | ||||||
|  | 		if (_draggingIndex >= 0) { | ||||||
|  | 			if (updateMin < 0 || updateMin > _draggingIndex) { | ||||||
|  | 				updateMin = _draggingIndex; | ||||||
|  | 			} | ||||||
|  | 			if (updateMax < _draggingIndex) updateMax = _draggingIndex; | ||||||
|  | 		} | ||||||
|  | 		if (updateMin >= 0) { | ||||||
|  | 			auto top = _dialogsImportant ? st::dialogsImportantBarHeight : 0; | ||||||
|  | 			auto updateFrom = top + st::dialogsRowHeight * (updateMin - 1); | ||||||
|  | 			auto updateHeight = st::dialogsRowHeight * (updateMax - updateMin + 3); | ||||||
|  | 			if (_aboveIndex >= 0 && _aboveIndex < _pinnedRows.size()) { | ||||||
|  | 				// Always include currently dragged chat in its current and old positions.
 | ||||||
|  | 				auto aboveRowBottom = top + (_aboveIndex + 1) * st::dialogsRowHeight; | ||||||
|  | 				auto aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current()); | ||||||
|  | 				accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + _aboveTopShift); | ||||||
|  | 				accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + aboveTopShift); | ||||||
|  | 				_aboveTopShift = aboveTopShift; | ||||||
|  | 			} | ||||||
|  | 			update(0, updateFrom, getFullWidth(), updateHeight); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (!animating) { | ||||||
|  | 		_aboveIndex = _draggingIndex; | ||||||
|  | 		_a_pinnedShifting.stop(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void DialogsInner::mouseReleaseEvent(QMouseEvent *e) { | void DialogsInner::mouseReleaseEvent(QMouseEvent *e) { | ||||||
| 	mousePressReleased(e->button()); | 	mousePressReleased(e->button()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::mousePressReleased(Qt::MouseButton button) { | void DialogsInner::mousePressReleased(Qt::MouseButton button) { | ||||||
|  | 	auto wasDragging = (_dragging != nullptr); | ||||||
|  | 	if (wasDragging) { | ||||||
|  | 		updateReorderIndexGetCount(); | ||||||
|  | 		if (_draggingIndex >= 0) { | ||||||
|  | 			auto localPosition = mapFromGlobal(QCursor::pos()); | ||||||
|  | 			_pinnedRows[_draggingIndex].yadd.start(0.); | ||||||
|  | 			_pinnedRows[_draggingIndex].animStartTime = getms(); | ||||||
|  | 			if (!_a_pinnedShifting.animating()) { | ||||||
|  | 				_a_pinnedShifting.start(); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		finishReorderPinned(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	auto importantSwitchPressed = _importantSwitchPressed; | 	auto importantSwitchPressed = _importantSwitchPressed; | ||||||
| 	setImportantSwitchPressed(false); | 	setImportantSwitchPressed(false); | ||||||
| 	auto pressed = _pressed; | 	auto pressed = _pressed; | ||||||
|  | @ -542,8 +832,11 @@ void DialogsInner::mousePressReleased(Qt::MouseButton button) { | ||||||
| 	setPeerSearchPressed(-1); | 	setPeerSearchPressed(-1); | ||||||
| 	auto searchedPressed = _searchedPressed; | 	auto searchedPressed = _searchedPressed; | ||||||
| 	setSearchedPressed(-1); | 	setSearchedPressed(-1); | ||||||
|  | 	if (wasDragging) { | ||||||
|  | 		updateSelected(); | ||||||
|  | 	} | ||||||
| 	updateSelectedRow(); | 	updateSelectedRow(); | ||||||
| 	if (button == Qt::LeftButton) { | 	if (!wasDragging && button == Qt::LeftButton) { | ||||||
| 		if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) { | 		if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) { | ||||||
| 			choosePeer(); | 			choosePeer(); | ||||||
| 		} else if (pressed && pressed == _selected) { | 		} else if (pressed && pressed == _selected) { | ||||||
|  | @ -633,6 +926,13 @@ void DialogsInner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRo | ||||||
| 	if (_pressed == oldRow) { | 	if (_pressed == oldRow) { | ||||||
| 		setPressed(newRow); | 		setPressed(newRow); | ||||||
| 	} | 	} | ||||||
|  | 	if (_dragging == oldRow) { | ||||||
|  | 		if (newRow) { | ||||||
|  | 			_dragging = newRow; | ||||||
|  | 		} else { | ||||||
|  | 			stopReorderPinned(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::createDialog(History *history) { | void DialogsInner::createDialog(History *history) { | ||||||
|  | @ -711,7 +1011,12 @@ void DialogsInner::removeDialog(History *history) { | ||||||
| void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { | void DialogsInner::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { | ||||||
| 	if (_state == DefaultState) { | 	if (_state == DefaultState) { | ||||||
| 		if (Global::DialogsMode() == list) { | 		if (Global::DialogsMode() == list) { | ||||||
| 			update(0, dialogsOffset() + row->pos() * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | 			auto position = row->pos(); | ||||||
|  | 			auto top = dialogsOffset(); | ||||||
|  | 			if (position >= 0 && position < _pinnedRows.size()) { | ||||||
|  | 				top += qRound(_pinnedRows[position].yadd.current()); | ||||||
|  | 			} | ||||||
|  | 			update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | ||||||
| 		} | 		} | ||||||
| 	} else if (_state == FilteredState || _state == SearchedState) { | 	} else if (_state == FilteredState || _state == SearchedState) { | ||||||
| 		if (list == Dialogs::Mode::All) { | 		if (list == Dialogs::Mode::All) { | ||||||
|  | @ -736,7 +1041,12 @@ void DialogsInner::updateDialogRow(PeerData *peer, MsgId msgId, QRect updateRect | ||||||
| 	if (_state == DefaultState) { | 	if (_state == DefaultState) { | ||||||
| 		if (sections & UpdateRowSection::Default) { | 		if (sections & UpdateRowSection::Default) { | ||||||
| 			if (auto row = shownDialogs()->getRow(peer->id)) { | 			if (auto row = shownDialogs()->getRow(peer->id)) { | ||||||
| 				updateRow(dialogsOffset() + row->pos() * st::dialogsRowHeight); | 				auto position = row->pos(); | ||||||
|  | 				auto top = dialogsOffset(); | ||||||
|  | 				if (position >= 0 && position < _pinnedRows.size()) { | ||||||
|  | 					top += qRound(_pinnedRows[position].yadd.current()); | ||||||
|  | 				} | ||||||
|  | 				updateRow(top + position * st::dialogsRowHeight); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else if (_state == FilteredState || _state == SearchedState) { | 	} else if (_state == FilteredState || _state == SearchedState) { | ||||||
|  | @ -782,9 +1092,14 @@ void DialogsInner::enterEvent(QEvent *e) { | ||||||
| void DialogsInner::updateSelectedRow(PeerData *peer) { | void DialogsInner::updateSelectedRow(PeerData *peer) { | ||||||
| 	if (_state == DefaultState) { | 	if (_state == DefaultState) { | ||||||
| 		if (peer) { | 		if (peer) { | ||||||
| 			if (History *h = App::historyLoaded(peer->id)) { | 			if (auto h = App::historyLoaded(peer->id)) { | ||||||
| 				if (h->inChatList(Global::DialogsMode())) { | 				if (h->inChatList(Global::DialogsMode())) { | ||||||
| 					update(0, dialogsOffset() + h->posInChatList(Global::DialogsMode()) * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | 					auto position = h->posInChatList(Global::DialogsMode()); | ||||||
|  | 					auto top = dialogsOffset(); | ||||||
|  | 					if (position >= 0 && position < _pinnedRows.size()) { | ||||||
|  | 						top += qRound(_pinnedRows[position].yadd.current()); | ||||||
|  | 					} | ||||||
|  | 					update(0, top + position * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} else if (_selected) { | 		} else if (_selected) { | ||||||
|  | @ -810,7 +1125,6 @@ void DialogsInner::updateSelectedRow(PeerData *peer) { | ||||||
| 			update(0, searchedOffset() + _searchedSelected * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | 			update(0, searchedOffset() + _searchedSelected * st::dialogsRowHeight, getFullWidth(), st::dialogsRowHeight); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::leaveEvent(QEvent *e) { | void DialogsInner::leaveEvent(QEvent *e) { | ||||||
|  | @ -1081,9 +1395,10 @@ PeerData *DialogsInner::updateFromParentDrag(QPoint globalPos) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { | void DialogsInner::setVisibleTopBottom(int visibleTop, int visibleBottom) { | ||||||
| 	_visibleAreaHeight = visibleBottom - visibleTop; | 	_visibleTop = visibleTop; | ||||||
| 	loadPeerPhotos(visibleTop); | 	_visibleBottom = visibleBottom; | ||||||
| 	if (visibleTop + PreloadHeightsCount * (visibleBottom - visibleTop) >= height()) { | 	loadPeerPhotos(); | ||||||
|  | 	if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) >= height()) { | ||||||
| 		if (_loadMoreCallback) { | 		if (_loadMoreCallback) { | ||||||
| 			_loadMoreCallback(); | 			_loadMoreCallback(); | ||||||
| 		} | 		} | ||||||
|  | @ -1347,8 +1662,9 @@ void DialogsInner::refresh(bool toTop) { | ||||||
| 	} | 	} | ||||||
| 	setHeight(h); | 	setHeight(h); | ||||||
| 	if (toTop) { | 	if (toTop) { | ||||||
|  | 		stopReorderPinned(); | ||||||
| 		emit mustScrollTo(0, 0); | 		emit mustScrollTo(0, 0); | ||||||
| 		loadPeerPhotos(0); | 		loadPeerPhotos(); | ||||||
| 	} | 	} | ||||||
| 	Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true); | 	Global::RefDialogsListDisplayForced().set(_searchInPeer || !_filter.isEmpty(), true); | ||||||
| 	update(); | 	update(); | ||||||
|  | @ -1563,11 +1879,11 @@ void DialogsInner::selectSkipPage(int32 pixels, int32 direction) { | ||||||
| 	update(); | 	update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogsInner::loadPeerPhotos(int visibleTop) { | void DialogsInner::loadPeerPhotos() { | ||||||
| 	if (!parentWidget()) return; | 	if (!parentWidget()) return; | ||||||
| 
 | 
 | ||||||
| 	auto yFrom = visibleTop; | 	auto yFrom = _visibleTop; | ||||||
| 	auto yTo = visibleTop + _visibleAreaHeight * (PreloadHeightsCount + 1); | 	auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1); | ||||||
| 	MTP::clearLoaderPriorities(); | 	MTP::clearLoaderPriorities(); | ||||||
| 	if (_state == DefaultState) { | 	if (_state == DefaultState) { | ||||||
| 		auto otherStart = shownDialogs()->size() * st::dialogsRowHeight; | 		auto otherStart = shownDialogs()->size() * st::dialogsRowHeight; | ||||||
|  | @ -1945,6 +2261,7 @@ DialogsWidget::DialogsWidget(QWidget *parent) : TWidget(parent) | ||||||
| , _lockUnlock(this, st::dialogsLock) | , _lockUnlock(this, st::dialogsLock) | ||||||
| , _scroll(this, st::dialogsScroll) { | , _scroll(this, st::dialogsScroll) { | ||||||
| 	_inner = _scroll->setOwnedWidget(object_ptr<DialogsInner>(this, parent)); | 	_inner = _scroll->setOwnedWidget(object_ptr<DialogsInner>(this, parent)); | ||||||
|  | 	connect(_inner, SIGNAL(draggingScrollDelta(int)), this, SLOT(onDraggingScrollDelta(int))); | ||||||
| 	connect(_inner, SIGNAL(mustScrollTo(int,int)), _scroll, SLOT(scrollToY(int,int))); | 	connect(_inner, SIGNAL(mustScrollTo(int,int)), _scroll, SLOT(scrollToY(int,int))); | ||||||
| 	connect(_inner, SIGNAL(dialogMoved(int,int)), this, SLOT(onDialogMoved(int,int))); | 	connect(_inner, SIGNAL(dialogMoved(int,int)), this, SLOT(onDialogMoved(int,int))); | ||||||
| 	connect(_inner, SIGNAL(searchMessages()), this, SLOT(onNeedSearchMessages())); | 	connect(_inner, SIGNAL(searchMessages()), this, SLOT(onNeedSearchMessages())); | ||||||
|  | @ -2262,6 +2579,25 @@ bool DialogsWidget::dialogsFailed(const RPCError &error, mtpRequestId requestId) | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void DialogsWidget::onDraggingScrollDelta(int delta) { | ||||||
|  | 	_draggingScrollDelta = _scroll ? delta : 0; | ||||||
|  | 	if (_draggingScrollDelta) { | ||||||
|  | 		if (!_draggingScrollTimer) { | ||||||
|  | 			_draggingScrollTimer.create(this); | ||||||
|  | 			_draggingScrollTimer->setSingleShot(false); | ||||||
|  | 			connect(_draggingScrollTimer, SIGNAL(timeout()), this, SLOT(onDraggingScrollTimer())); | ||||||
|  | 		} | ||||||
|  | 		_draggingScrollTimer->start(15); | ||||||
|  | 	} else { | ||||||
|  | 		_draggingScrollTimer.destroy(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DialogsWidget::onDraggingScrollTimer() { | ||||||
|  | 	auto delta = (_draggingScrollDelta > 0) ? qMin(_draggingScrollDelta * 3 / 20 + 1, int32(MaxScrollSpeed)) : qMax(_draggingScrollDelta * 3 / 20 - 1, -int32(MaxScrollSpeed)); | ||||||
|  | 	_scroll->scrollToY(_scroll->scrollTop() + delta); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool DialogsWidget::onSearchMessages(bool searchCache) { | bool DialogsWidget::onSearchMessages(bool searchCache) { | ||||||
| 	QString q = _filter->getLastText().trimmed(); | 	QString q = _filter->getLastText().trimmed(); | ||||||
| 	if (q.isEmpty()) { | 	if (q.isEmpty()) { | ||||||
|  |  | ||||||
|  | @ -131,6 +131,7 @@ public slots: | ||||||
| 	void onMenuDestroyed(QObject*); | 	void onMenuDestroyed(QObject*); | ||||||
| 
 | 
 | ||||||
| signals: | signals: | ||||||
|  | 	void draggingScrollDelta(int delta); | ||||||
| 	void mustScrollTo(int scrollToTop, int scrollToBottom); | 	void mustScrollTo(int scrollToTop, int scrollToBottom); | ||||||
| 	void dialogMoved(int movedFrom, int movedTo); | 	void dialogMoved(int movedFrom, int movedTo); | ||||||
| 	void searchMessages(); | 	void searchMessages(); | ||||||
|  | @ -165,7 +166,7 @@ private: | ||||||
| 		updateSelected(mapFromGlobal(QCursor::pos())); | 		updateSelected(mapFromGlobal(QCursor::pos())); | ||||||
| 	} | 	} | ||||||
| 	void updateSelected(QPoint localPos); | 	void updateSelected(QPoint localPos); | ||||||
| 	void loadPeerPhotos(int visibleTop); | 	void loadPeerPhotos(); | ||||||
| 	void setImportantSwitchPressed(bool pressed); | 	void setImportantSwitchPressed(bool pressed); | ||||||
| 	void setPressed(Dialogs::Row *pressed); | 	void setPressed(Dialogs::Row *pressed); | ||||||
| 	void setHashtagPressed(int pressed); | 	void setHashtagPressed(int pressed); | ||||||
|  | @ -196,9 +197,9 @@ private: | ||||||
| 	int peerSearchOffset() const; | 	int peerSearchOffset() const; | ||||||
| 	int searchedOffset() const; | 	int searchedOffset() const; | ||||||
| 
 | 
 | ||||||
| 	void paintDialog(QPainter &p, Dialogs::Row *dialog); | 	void paintDialog(Painter &p, Dialogs::Row *row, int fullWidth, PeerData *active, PeerData *selected, bool onlyBackground, TimeMs ms); | ||||||
| 	void paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int32 w, bool active, bool selected, bool onlyBackground, TimeMs ms) const; | 	void paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) const; | ||||||
| 	void paintSearchInPeer(Painter &p, int32 w, bool onlyBackground) const; | 	void paintSearchInPeer(Painter &p, int fullWidth, bool onlyBackground) const; | ||||||
| 
 | 
 | ||||||
| 	void clearSelection(); | 	void clearSelection(); | ||||||
| 	void clearSearchResults(bool clearPeerSearchResults = true); | 	void clearSearchResults(bool clearPeerSearchResults = true); | ||||||
|  | @ -208,6 +209,16 @@ private: | ||||||
| 		return (Global::DialogsMode() == Dialogs::Mode::Important) ? _dialogsImportant.get() : _dialogs.get(); | 		return (Global::DialogsMode() == Dialogs::Mode::Important) ? _dialogsImportant.get() : _dialogs.get(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void checkReorderPinnedStart(QPoint localPosition); | ||||||
|  | 	int shownPinnedCount() const; | ||||||
|  | 	int updateReorderIndexGetCount(); | ||||||
|  | 	bool updateReorderPinned(QPoint localPosition); | ||||||
|  | 	void finishReorderPinned(); | ||||||
|  | 	void stopReorderPinned(); | ||||||
|  | 	int countPinnedIndex(Dialogs::Row *ofRow); | ||||||
|  | 	void savePinnedOrder(); | ||||||
|  | 	void step_pinnedShifting(TimeMs ms, bool timer); | ||||||
|  | 
 | ||||||
| 	DialogsList _dialogs; | 	DialogsList _dialogs; | ||||||
| 	DialogsList _dialogsImportant; | 	DialogsList _dialogsImportant; | ||||||
| 
 | 
 | ||||||
|  | @ -223,7 +234,23 @@ private: | ||||||
| 	Dialogs::Row *_selected = nullptr; | 	Dialogs::Row *_selected = nullptr; | ||||||
| 	Dialogs::Row *_pressed = nullptr; | 	Dialogs::Row *_pressed = nullptr; | ||||||
| 
 | 
 | ||||||
| 	int _visibleAreaHeight = 0; | 	Dialogs::Row *_dragging = nullptr; | ||||||
|  | 	int _draggingIndex = -1; | ||||||
|  | 	int _aboveIndex = -1; | ||||||
|  | 	QPoint _dragStart; | ||||||
|  | 	struct PinnedRow { | ||||||
|  | 		anim::value yadd; | ||||||
|  | 		TimeMs animStartTime = 0; | ||||||
|  | 	}; | ||||||
|  | 	std_::vector_of_moveable<PinnedRow> _pinnedRows; | ||||||
|  | 	BasicAnimation _a_pinnedShifting; | ||||||
|  | 	QList<History*> _pinnedOrder; | ||||||
|  | 
 | ||||||
|  | 	// Remember the last currently dragged row top shift for updating area.
 | ||||||
|  | 	int _aboveTopShift = -1; | ||||||
|  | 
 | ||||||
|  | 	int _visibleTop = 0; | ||||||
|  | 	int _visibleBottom = 0; | ||||||
| 	QString _filter, _hashtagFilter; | 	QString _filter, _hashtagFilter; | ||||||
| 
 | 
 | ||||||
| 	HashtagResults _hashtagResults; | 	HashtagResults _hashtagResults; | ||||||
|  | @ -322,6 +349,8 @@ signals: | ||||||
| 	void cancelled(); | 	void cancelled(); | ||||||
| 
 | 
 | ||||||
| public slots: | public slots: | ||||||
|  | 	void onDraggingScrollDelta(int delta); | ||||||
|  | 
 | ||||||
| 	void onCancel(); | 	void onCancel(); | ||||||
| 	void onListScroll(); | 	void onListScroll(); | ||||||
| 	void activate(); | 	void activate(); | ||||||
|  | @ -338,8 +367,10 @@ public slots: | ||||||
| 
 | 
 | ||||||
| 	void onChooseByDrag(); | 	void onChooseByDrag(); | ||||||
| 
 | 
 | ||||||
| #ifndef TDESKTOP_DISABLE_AUTOUPDATE |  | ||||||
| private slots: | private slots: | ||||||
|  | 	void onDraggingScrollTimer(); | ||||||
|  | 
 | ||||||
|  | #ifndef TDESKTOP_DISABLE_AUTOUPDATE | ||||||
| 	void onCheckUpdateStatus(); | 	void onCheckUpdateStatus(); | ||||||
| #endif // TDESKTOP_DISABLE_AUTOUPDATE
 | #endif // TDESKTOP_DISABLE_AUTOUPDATE
 | ||||||
| 
 | 
 | ||||||
|  | @ -427,4 +458,7 @@ private: | ||||||
| 
 | 
 | ||||||
| 	QPixmap _widthAnimationCache; | 	QPixmap _widthAnimationCache; | ||||||
| 
 | 
 | ||||||
|  | 	object_ptr<QTimer> _draggingScrollTimer = { nullptr }; | ||||||
|  | 	int _draggingScrollDelta = 0; | ||||||
|  | 
 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -754,6 +754,19 @@ int Histories::pinnedCount() const { | ||||||
| 	return _pinnedDialogs.size(); | 	return _pinnedDialogs.size(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | QList<History*> Histories::getPinnedOrder() const { | ||||||
|  | 	QMap<int, History*> sorter; | ||||||
|  | 	for_const (auto pinned, _pinnedDialogs) { | ||||||
|  | 		sorter.insert(pinned->getPinnedIndex(), pinned); | ||||||
|  | 	} | ||||||
|  | 	QList<History*> result; | ||||||
|  | 	for (auto i = sorter.cend(), e = sorter.cbegin(); i != e;) { | ||||||
|  | 		--i; | ||||||
|  | 		result.push_back(i.value()); | ||||||
|  | 	} | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { | HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { | ||||||
| 	auto msgId = MsgId(0); | 	auto msgId = MsgId(0); | ||||||
| 	switch (msg.type()) { | 	switch (msg.type()) { | ||||||
|  | @ -2129,7 +2142,10 @@ void History::updateChatListEntry() const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void History::setPinnedDialog(bool isPinned) { | void History::setPinnedDialog(bool isPinned) { | ||||||
| 	auto pinnedIndex = isPinned ? (++GlobalPinnedIndex) : 0; | 	setPinnedIndex(isPinned ? (++GlobalPinnedIndex) : 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void History::setPinnedIndex(int pinnedIndex) { | ||||||
| 	if (_pinnedIndex != pinnedIndex) { | 	if (_pinnedIndex != pinnedIndex) { | ||||||
| 		auto wasPinned = isPinnedDialog(); | 		auto wasPinned = isPinnedDialog(); | ||||||
| 		_pinnedIndex = pinnedIndex; | 		_pinnedIndex = pinnedIndex; | ||||||
|  |  | ||||||
|  | @ -82,6 +82,7 @@ public: | ||||||
| 	void setIsPinned(History *history, bool isPinned); | 	void setIsPinned(History *history, bool isPinned); | ||||||
| 	void clearPinned(); | 	void clearPinned(); | ||||||
| 	int pinnedCount() const; | 	int pinnedCount() const; | ||||||
|  | 	QList<History*> getPinnedOrder() const; | ||||||
| 
 | 
 | ||||||
| 	struct SendActionAnimationUpdate { | 	struct SendActionAnimationUpdate { | ||||||
| 		History *history; | 		History *history; | ||||||
|  | @ -288,6 +289,7 @@ public: | ||||||
| 		return (_pinnedIndex > 0); | 		return (_pinnedIndex > 0); | ||||||
| 	} | 	} | ||||||
| 	void setPinnedDialog(bool isPinned); | 	void setPinnedDialog(bool isPinned); | ||||||
|  | 	void setPinnedIndex(int newPinnedIndex); | ||||||
| 	int getPinnedIndex() const { | 	int getPinnedIndex() const { | ||||||
| 		return _pinnedIndex; | 		return _pinnedIndex; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -656,12 +656,12 @@ void MainWidget::hiderLayer(object_ptr<HistoryHider> h) { | ||||||
| 		} | 		} | ||||||
| 		if (_dialogs->isHidden()) { | 		if (_dialogs->isHidden()) { | ||||||
| 			_dialogs->show(); | 			_dialogs->show(); | ||||||
| 			resizeEvent(0); | 			updateControlsGeometry(); | ||||||
| 			_dialogs->showAnimated(Window::SlideDirection::FromLeft, animationParams); | 			_dialogs->showAnimated(Window::SlideDirection::FromLeft, animationParams); | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		_hider->show(); | 		_hider->show(); | ||||||
| 		resizeEvent(0); | 		updateControlsGeometry(); | ||||||
| 		_dialogs->activate(); | 		_dialogs->activate(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -2293,7 +2293,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show | ||||||
| 	} else { | 	} else { | ||||||
| 		if (noPeer) { | 		if (noPeer) { | ||||||
| 			_topBar->hide(); | 			_topBar->hide(); | ||||||
| 			resizeEvent(0); | 			updateControlsGeometry(); | ||||||
| 		} else if (wasActivePeer != activePeer()) { | 		} else if (wasActivePeer != activePeer()) { | ||||||
| 			if (activePeer()->isChannel()) { | 			if (activePeer()->isChannel()) { | ||||||
| 				activePeer()->asChannel()->ptsWaitingForShortPoll(WaitForChannelGetDifference); | 				activePeer()->asChannel()->ptsWaitingForShortPoll(WaitForChannelGetDifference); | ||||||
|  | @ -2421,6 +2421,8 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool | ||||||
| 	if (!back) { | 	if (!back) { | ||||||
| 		saveSectionInStack(); | 		saveSectionInStack(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	setFocus(); // otherwise dialogs widget could be focused.
 | ||||||
| 	if (_overview) { | 	if (_overview) { | ||||||
| 		_overview->hide(); | 		_overview->hide(); | ||||||
| 		_overview->clear(); | 		_overview->clear(); | ||||||
|  | @ -2435,7 +2437,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool | ||||||
| 	_overview.create(this, peer, type); | 	_overview.create(this, peer, type); | ||||||
| 	_mediaTypeMask = 0; | 	_mediaTypeMask = 0; | ||||||
| 	_topBar->show(); | 	_topBar->show(); | ||||||
| 	resizeEvent(nullptr); | 	updateControlsGeometry(); | ||||||
| 
 | 
 | ||||||
| 	// Send a fake update.
 | 	// Send a fake update.
 | ||||||
| 	Notify::PeerUpdate update(peer); | 	Notify::PeerUpdate update(peer); | ||||||
|  | @ -2574,6 +2576,8 @@ void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool | ||||||
| 	if (saveInStack) { | 	if (saveInStack) { | ||||||
| 		saveSectionInStack(); | 		saveSectionInStack(); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	setFocus(); // otherwise dialogs widget could be focused.
 | ||||||
| 	if (_overview) { | 	if (_overview) { | ||||||
| 		_overview->hide(); | 		_overview->hide(); | ||||||
| 		_overview->clear(); | 		_overview->clear(); | ||||||
|  | @ -2588,7 +2592,7 @@ void MainWidget::showNewWideSection(const Window::SectionMemento *memento, bool | ||||||
| 	} | 	} | ||||||
| 	_wideSection = std_::move(newWideSection); | 	_wideSection = std_::move(newWideSection); | ||||||
| 	_topBar->hide(); | 	_topBar->hide(); | ||||||
| 	resizeEvent(0); | 	updateControlsGeometry(); | ||||||
| 	_history->finishAnimation(); | 	_history->finishAnimation(); | ||||||
| 	_history->showHistory(0, 0); | 	_history->showHistory(0, 0); | ||||||
| 	_history->hide(); | 	_history->hide(); | ||||||
|  | @ -2924,7 +2928,7 @@ void MainWidget::showAll() { | ||||||
| 		_player->show(); | 		_player->show(); | ||||||
| 		_playerHeight = _player->contentHeight(); | 		_playerHeight = _player->contentHeight(); | ||||||
| 	} | 	} | ||||||
| 	resizeEvent(0); | 	updateControlsGeometry(); | ||||||
| 
 | 
 | ||||||
| 	App::wnd()->checkHistoryActivation(); | 	App::wnd()->checkHistoryActivation(); | ||||||
| } | } | ||||||
|  | @ -3206,7 +3210,7 @@ void MainWidget::onHistoryShown(History *history, MsgId atMsgId) { | ||||||
| 	} else { | 	} else { | ||||||
| 		_topBar->hide(); | 		_topBar->hide(); | ||||||
| 	} | 	} | ||||||
| 	resizeEvent(0); | 	updateControlsGeometry(); | ||||||
| 	if (_a_show.animating()) { | 	if (_a_show.animating()) { | ||||||
| 		_topBar->hide(); | 		_topBar->hide(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -298,7 +298,7 @@ void InitAudio() { | ||||||
| 	PrepareNotifySound(); | 	PrepareNotifySound(); | ||||||
| 
 | 
 | ||||||
| 	auto loglevel = getenv("ALSOFT_LOGLEVEL"); | 	auto loglevel = getenv("ALSOFT_LOGLEVEL"); | ||||||
| 	LOG(("OpenAL Logging Level: ").arg(loglevel ? loglevel : "(not set)")); | 	LOG(("OpenAL Logging Level: %1").arg(loglevel ? loglevel : "(not set)")); | ||||||
| 
 | 
 | ||||||
| 	EnumeratePlaybackDevices(); | 	EnumeratePlaybackDevices(); | ||||||
| 	EnumerateCaptureDevices(); | 	EnumerateCaptureDevices(); | ||||||
|  |  | ||||||
|  | @ -76,7 +76,7 @@ FontData::FontData(int size, uint32 flags, int family, Font *other) : f(fontFami | ||||||
| 	ascent = m.ascent(); | 	ascent = m.ascent(); | ||||||
| 	descent = m.descent(); | 	descent = m.descent(); | ||||||
| 	spacew = width(QLatin1Char(' ')); | 	spacew = width(QLatin1Char(' ')); | ||||||
| 	elidew = width(QLatin1Char('.')) * 3; | 	elidew = width(qsl("...")); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Font FontData::bold(bool set) const { | Font FontData::bold(bool set) const { | ||||||
|  |  | ||||||
|  | @ -1555,7 +1555,7 @@ public: | ||||||
| 		line.length = lineLength; | 		line.length = lineLength; | ||||||
| 		eShapeLine(line); | 		eShapeLine(line); | ||||||
| 
 | 
 | ||||||
| 		int32 elideWidth = _f->width(_Elide); | 		auto elideWidth = _f->elidew; | ||||||
| 		_wLeft = _w - elideWidth - _elideRemoveFromEnd; | 		_wLeft = _w - elideWidth - _elideRemoveFromEnd; | ||||||
| 
 | 
 | ||||||
| 		int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1); | 		int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1); | ||||||
|  | @ -1654,15 +1654,21 @@ public: | ||||||
| 
 | 
 | ||||||
| 	// COPIED FROM qtextengine.cpp AND MODIFIED
 | 	// COPIED FROM qtextengine.cpp AND MODIFIED
 | ||||||
| 	void eShapeLine(const QScriptLine &line) { | 	void eShapeLine(const QScriptLine &line) { | ||||||
| 		int item = _e->findItem(line.from), end = _e->findItem(line.from + line.length - 1); | 		int item = _e->findItem(line.from); | ||||||
| 		if (item == -1) | 		if (item == -1) | ||||||
| 			return; | 			return; | ||||||
| 
 | 
 | ||||||
|  | #ifdef OS_MAC_OLD | ||||||
|  | 		auto end = _e->findItem(line.from + line.length - 1); | ||||||
|  | #else // OS_MAC_OLD
 | ||||||
|  | 		auto end = _e->findItem(line.from + line.length - 1, item); | ||||||
|  | #endif // OS_MAC_OLD
 | ||||||
|  | 
 | ||||||
| 		int blockIndex = _lineStartBlock; | 		int blockIndex = _lineStartBlock; | ||||||
| 		ITextBlock *currentBlock = _t->_blocks[blockIndex]; | 		ITextBlock *currentBlock = _t->_blocks[blockIndex]; | ||||||
| 		ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; | 		ITextBlock *nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex] : 0; | ||||||
| 		eSetFont(currentBlock); | 		eSetFont(currentBlock); | ||||||
| 		for (item = _e->findItem(line.from); item <= end; ++item) { | 		for (; item <= end; ++item) { | ||||||
| 			QScriptItem &si = _e->layoutData->items[item]; | 			QScriptItem &si = _e->layoutData->items[item]; | ||||||
| 			while (nextBlock && nextBlock->from() <= _localFrom + si.position) { | 			while (nextBlock && nextBlock->from() <= _localFrom + si.position) { | ||||||
| 				currentBlock = nextBlock; | 				currentBlock = nextBlock; | ||||||
|  |  | ||||||
|  | @ -335,8 +335,6 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi | ||||||
| 		SignalHandlers::setCrashAnnotationRef("CrashString", &part); | 		SignalHandlers::setCrashAnnotationRef("CrashString", &part); | ||||||
| 
 | 
 | ||||||
| 		QStackTextEngine engine(part, blockFont->f); | 		QStackTextEngine engine(part, blockFont->f); | ||||||
| 		engine.itemize(); |  | ||||||
| 
 |  | ||||||
| 		QTextLayout layout(&engine); | 		QTextLayout layout(&engine); | ||||||
| 		layout.beginLayout(); | 		layout.beginLayout(); | ||||||
| 		layout.createLine(); | 		layout.createLine(); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| AppVersion         1000003 | AppVersion         1000004 | ||||||
| AppVersionStrMajor 1.0 | AppVersionStrMajor 1.0 | ||||||
| AppVersionStrSmall 1.0.3 | AppVersionStrSmall 1.0.4 | ||||||
| AppVersionStr      1.0.3 | AppVersionStr      1.0.4 | ||||||
| AlphaChannel       1 | AlphaChannel       1 | ||||||
| BetaVersion        0 | BetaVersion        0 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue