Alpha 1.0.4: Click and drag to reorder pinned chats.

This commit is contained in:
John Preston 2017-01-30 18:27:13 +03:00
parent b21f72fef0
commit d1b9b8e3a3
20 changed files with 473 additions and 70 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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 {

View File

@ -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);
} }

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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++;

View File

@ -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);

View File

@ -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 &region, 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 &region, 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()) {

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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;
} }

View File

@ -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();
} }

View File

@ -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();

View File

@ -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 {

View File

@ -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;

View File

@ -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();

View File

@ -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