From a7c77682d75263013b3cbd3b0a446d8e9ec3df25 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 28 Apr 2018 18:06:59 +0400 Subject: [PATCH] Apply, delete and restore proxies in the box. --- Telegram/SourceFiles/boxes/abstract_box.cpp | 38 +++- Telegram/SourceFiles/boxes/abstract_box.h | 15 +- Telegram/SourceFiles/boxes/boxes.style | 4 +- Telegram/SourceFiles/boxes/connection_box.cpp | 213 ++++++++++++++++-- Telegram/SourceFiles/boxes/connection_box.h | 12 + .../SourceFiles/codegen/style/parsed_file.cpp | 20 +- .../SourceFiles/codegen/style/parsed_file.h | 6 +- Telegram/SourceFiles/storage/localstorage.cpp | 31 ++- Telegram/SourceFiles/ui/wrap/padding_wrap.cpp | 1 + .../SourceFiles/ui/wrap/vertical_layout.cpp | 17 +- .../SourceFiles/ui/wrap/vertical_layout.h | 21 +- 11 files changed, 318 insertions(+), 60 deletions(-) diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index c74c36a144..cd03a5ec97 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -19,12 +19,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "mainwindow.h" -QPointer BoxContent::addButton(base::lambda textFactory, base::lambda clickCallback) { - return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton); +QPointer BoxContent::addButton( + base::lambda textFactory, + base::lambda clickCallback) { + return addButton( + std::move(textFactory), + std::move(clickCallback), + st::defaultBoxButton); } -QPointer BoxContent::addLeftButton(base::lambda textFactory, base::lambda clickCallback) { - return getDelegate()->addLeftButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton); +QPointer BoxContent::addLeftButton( + base::lambda textFactory, + base::lambda clickCallback) { + return getDelegate()->addLeftButton( + std::move(textFactory), + std::move(clickCallback), + st::defaultBoxButton); } void BoxContent::setInner(object_ptr inner) { @@ -117,7 +127,7 @@ void BoxContent::updateShadowsVisibility() { (top > 0 || _innerTopSkip > 0), anim::type::normal); _bottomShadow->toggle( - (top < _scroll->scrollTopMax()), + (top < _scroll->scrollTopMax() || _innerBottomSkip > 0), anim::type::normal); } @@ -145,6 +155,16 @@ void BoxContent::setInnerTopSkip(int innerTopSkip, bool scrollBottomFixed) { } } +void BoxContent::setInnerBottomSkip(int innerBottomSkip) { + if (_innerBottomSkip != innerBottomSkip) { + auto delta = innerBottomSkip - _innerBottomSkip; + _innerBottomSkip = innerBottomSkip; + if (_scroll && width() > 0) { + updateScrollAreaGeometry(); + } + } +} + void BoxContent::setInnerVisible(bool scrollAreaVisible) { if (_scroll) { _scroll->setVisible(scrollAreaVisible); @@ -169,13 +189,15 @@ void BoxContent::resizeEvent(QResizeEvent *e) { } void BoxContent::updateScrollAreaGeometry() { - auto newScrollHeight = height() - _innerTopSkip; + auto newScrollHeight = height() - _innerTopSkip - _innerBottomSkip; auto changed = (_scroll->height() != newScrollHeight); _scroll->setGeometryToLeft(0, _innerTopSkip, width(), newScrollHeight); _topShadow->entity()->resize(width(), st::lineWidth); _topShadow->moveToLeft(0, _innerTopSkip); _bottomShadow->entity()->resize(width(), st::lineWidth); - _bottomShadow->moveToLeft(0, height() - st::lineWidth); + _bottomShadow->moveToLeft( + 0, + height() - _innerBottomSkip - st::lineWidth); if (changed) { updateInnerVisibleTopBottom(); @@ -184,7 +206,7 @@ void BoxContent::updateScrollAreaGeometry() { (top > 0 || _innerTopSkip > 0), anim::type::instant); _bottomShadow->toggle( - (top < _scroll->scrollTopMax()), + (top < _scroll->scrollTopMax() || _innerBottomSkip > 0), anim::type::instant); } } diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 7ffb76dd83..92475fdbe6 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -130,19 +130,29 @@ protected: getDelegate()->setDimensions(newWidth, maxHeight); } void setInnerTopSkip(int topSkip, bool scrollBottomFixed = false); + void setInnerBottomSkip(int bottomSkip); template - QPointer setInnerWidget(object_ptr inner, const style::ScrollArea &st, int topSkip = 0) { + QPointer setInnerWidget( + object_ptr inner, + const style::ScrollArea &st, + int topSkip = 0, + int bottomSkip = 0) { auto result = QPointer(inner.data()); setInnerTopSkip(topSkip); + setInnerBottomSkip(bottomSkip); setInner(std::move(inner), st); return result; } template - QPointer setInnerWidget(object_ptr inner, int topSkip = 0) { + QPointer setInnerWidget( + object_ptr inner, + int topSkip = 0, + int bottomSkip = 0) { auto result = QPointer(inner.data()); setInnerTopSkip(topSkip); + setInnerBottomSkip(bottomSkip); setInner(std::move(inner)); return result; } @@ -183,6 +193,7 @@ private: bool _preparing = false; bool _noContentMargin = false; int _innerTopSkip = 0; + int _innerBottomSkip = 0; object_ptr _scroll = { nullptr }; object_ptr _topShadow = { nullptr }; object_ptr _bottomShadow = { nullptr }; diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 6bf1604cd1..ea63a9ef57 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -712,8 +712,10 @@ sendMediaFileThumbSkip: 10px; sendMediaFileNameTop: 7px; sendMediaFileStatusTop: 37px; +proxyUsePadding: margins(22px, 0px, 22px, 12px); +proxyTryIPv6Padding: margins(22px, 12px, 22px, 0px); proxyRowPadding: margins(22px, 8px, 8px, 8px); -proxyRowIconSkip: 16px; +proxyRowIconSkip: 32px; proxyRowSkip: 2px; proxyRowRipple: RippleAnimation(defaultRippleAnimation) { color: windowBgOver; diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index b3eb073629..a0df40187e 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/wrap/fade_wrap.h" +#include "ui/wrap/padding_wrap.h" #include "ui/wrap/vertical_layout.h" #include "ui/text_options.h" #include "history/history_location_manager.h" @@ -29,6 +30,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { +constexpr auto kSaveSettingsDelayedTimeout = TimeMs(1000); + class ProxyRow : public Ui::RippleButton { public: using View = ProxiesBoxController::ItemView; @@ -72,12 +75,16 @@ protected: private: void setupContent(); + void addNewProxy(); void applyView(View &&view); void setupButtons(int id, not_null button); not_null _controller; - object_ptr _initialInner; - QPointer _inner; + object_ptr> _useProxy; + object_ptr> _tryIPv6; + object_ptr _initialWrap; + QPointer _wrap; + base::flat_map> _rows; }; @@ -145,6 +152,8 @@ void ProxyRow::updateFields(View &&view) { _edit->toggle(!_view.deleted, anim::type::instant); _restore->toggle(_view.deleted, anim::type::instant); + setPointerCursor(!_view.deleted); + update(); } @@ -171,7 +180,6 @@ int ProxyRow::resizeGetHeight(int newWidth) { right -= _edit->width(); _skipRight = right; _skipLeft = st::proxyRowPadding.left() - + st::proxyRowSelectedIcon.width() + st::proxyRowIconSkip; return result; } @@ -240,7 +248,21 @@ ProxiesBox::ProxiesBox( QWidget*, not_null controller) : _controller(controller) -, _initialInner(this) { +, _useProxy( + this, + object_ptr( + this, + lang(lng_proxy_use), + Global::UseProxy()), + st::proxyUsePadding) +, _tryIPv6( + this, + object_ptr( + this, + lang(lng_connection_try_ipv6), + Global::TryIPv6()), + st::proxyTryIPv6Padding) +, _initialWrap(this) { _controller->views( ) | rpl::start_with_next([=](View &&view) { applyView(std::move(view)); @@ -250,40 +272,73 @@ ProxiesBox::ProxiesBox( void ProxiesBox::prepare() { setTitle(langFactory(lng_proxy_settings)); - addButton(langFactory(lng_proxy_add), [=] { - Ui::show(_controller->addNewItemBox(), LayerOption::KeepOther); - }); - addButton(langFactory(lng_close), [=] { - closeBox(); - }); + addButton(langFactory(lng_proxy_add), [=] { addNewProxy(); }); + addButton(langFactory(lng_close), [=] { closeBox(); }); setupContent(); } void ProxiesBox::setupContent() { - _inner = setInnerWidget(std::move(_initialInner)); + _useProxy->resizeToWidth(st::boxWideWidth); + _useProxy->moveToLeft(0, 0); + subscribe(_useProxy->entity()->checkedChanged, [=](bool checked) { + if (!_controller->setProxyEnabled(checked)) { + addNewProxy(); + } + }); + subscribe(Global::RefConnectionTypeChanged(), [=] { + _useProxy->entity()->setChecked(Global::UseProxy()); + }); - _inner->resizeToWidth(st::boxWideWidth); + _tryIPv6->resizeToWidth(st::boxWideWidth); - _inner->heightValue( - ) | rpl::map([](int height) { - return std::min(height, st::boxMaxListHeight); + const auto topSkip = _useProxy->heightNoMargins(); + const auto bottomSkip = _tryIPv6->heightNoMargins(); + const auto inner = setInnerWidget( + object_ptr(this), + topSkip, + bottomSkip); + inner->add(object_ptr( + inner, + st::proxyRowPadding.top())); + _wrap = inner->add(std::move(_initialWrap)); + inner->add(object_ptr( + inner, + st::proxyRowPadding.bottom())); + + inner->resizeToWidth(st::boxWideWidth); + + inner->heightValue( + ) | rpl::map([=](int height) { + return std::min( + topSkip + height + bottomSkip, + st::boxMaxListHeight); }) | rpl::distinct_until_changed( ) | rpl::start_with_next([=](int height) { setDimensions(st::boxWideWidth, height); - }, lifetime()); + }, inner->lifetime()); + + heightValue( + ) | rpl::start_with_next([=](int height) { + _tryIPv6->moveToLeft(0, height - _tryIPv6->heightNoMargins()); + }, _tryIPv6->lifetime()); +} + +void ProxiesBox::addNewProxy() { + Ui::show(_controller->addNewItemBox(), LayerOption::KeepOther); } void ProxiesBox::applyView(View &&view) { const auto id = view.id; const auto i = _rows.find(id); if (i == _rows.end()) { - const auto inner = _inner - ? _inner.data() - : _initialInner.data(); - const auto [i, ok] = _rows.emplace(id, inner->add( + const auto wrap = _wrap + ? _wrap.data() + : _initialWrap.data(); + const auto [i, ok] = _rows.emplace(id, wrap->insert( + 0, object_ptr( - inner, + wrap, std::move(view)))); setupButtons(id, i->second); } else { @@ -306,6 +361,11 @@ void ProxiesBox::setupButtons(int id, not_null button) { ) | rpl::start_with_next([=] { Ui::show(_controller->editItemBox(id), LayerOption::KeepOther); }, button->lifetime()); + + button->clicks( + ) | rpl::start_with_next([=] { + _controller->applyItem(id); + }, button->lifetime()); } ProxyBox::ProxyBox( @@ -346,7 +406,7 @@ void ConnectionBox::ShowApplyProxyConfirmation( *box = Ui::show(Box(text, lang(lng_sure_enable), [=] { auto &proxies = Global::RefProxiesList(); if (ranges::find(proxies, proxy) == end(proxies)) { - proxies.insert(begin(proxies), proxy); + proxies.push_back(proxy); } Global::SetSelectedProxy(proxy); Global::SetUseProxy(true); @@ -662,7 +722,8 @@ void AutoDownloadBox::onSave() { closeBox(); } -ProxiesBoxController::ProxiesBoxController() { +ProxiesBoxController::ProxiesBoxController() +: _saveTimer([] { Local::writeSettings(); }) { _list = ranges::view::all( Global::ProxiesList() ) | ranges::view::transform([&](const ProxyData &proxy) { @@ -679,7 +740,7 @@ object_ptr ProxiesBoxController::CreateOwningBox() { object_ptr ProxiesBoxController::create() { auto result = Box(this); - for (const auto &item : _list) { + for (const auto &item : base::reversed(_list)) { updateView(item); } return std::move(result); @@ -694,6 +755,14 @@ auto ProxiesBoxController::findById(int id) -> std::vector::iterator { return result; } +auto ProxiesBoxController::findByProxy(const ProxyData &proxy) +->std::vector::iterator { + return ranges::find( + _list, + proxy, + [](const Item &item) { return item.data; }); +} + void ProxiesBoxController::deleteItem(int id) { setDeleted(id, true); } @@ -702,9 +771,68 @@ void ProxiesBoxController::restoreItem(int id) { setDeleted(id, false); } +void ProxiesBoxController::applyItem(int id) { + auto item = findById(id); + if (Global::UseProxy() && Global::SelectedProxy() == item->data) { + return; + } else if (item->deleted) { + return; + } + + auto j = findByProxy(Global::SelectedProxy()); + + Global::SetSelectedProxy(item->data); + Global::SetUseProxy(true); + applyChanges(); + + if (j != end(_list)) { + updateView(*j); + } + updateView(*item); +} + void ProxiesBoxController::setDeleted(int id, bool deleted) { auto item = findById(id); item->deleted = deleted; + + if (deleted) { + auto &proxies = Global::RefProxiesList(); + proxies.erase(ranges::remove(proxies, item->data), end(proxies)); + + if (item->data == Global::SelectedProxy()) { + _lastSelectedProxy = base::take(Global::RefSelectedProxy()); + if (Global::UseProxy()) { + _lastSelectedProxyUsed = true; + Global::SetUseProxy(false); + applyChanges(); + } else { + _lastSelectedProxyUsed = false; + } + } + } else { + auto &proxies = Global::RefProxiesList(); + if (ranges::find(proxies, item->data) == end(proxies)) { + auto insertBefore = item + 1; + while (insertBefore != end(_list) && insertBefore->deleted) { + ++insertBefore; + } + auto insertBeforeIt = (insertBefore == end(_list)) + ? end(proxies) + : ranges::find(proxies, insertBefore->data); + proxies.insert(insertBeforeIt, item->data); + } + + if (!Global::SelectedProxy() && _lastSelectedProxy == item->data) { + Assert(!Global::UseProxy()); + + Global::SetSelectedProxy(base::take(_lastSelectedProxy)); + if (base::take(_lastSelectedProxyUsed)) { + Global::SetUseProxy(true); + applyChanges(); + } + } + } + saveDelayed(); updateView(*item); } @@ -749,6 +877,34 @@ object_ptr ProxiesBoxController::addNewItemBox() { }); } +bool ProxiesBoxController::setProxyEnabled(bool enabled) { + if (enabled) { + if (Global::ProxiesList().empty()) { + return false; + } else if (!Global::SelectedProxy()) { + Global::SetSelectedProxy(Global::ProxiesList().back()); + auto j = findByProxy(Global::SelectedProxy()); + if (j != end(_list)) { + updateView(*j); + } + } + } + Global::SetUseProxy(enabled); + applyChanges(); + return true; +} + +void ProxiesBoxController::applyChanges() { + Sandbox::refreshGlobalProxy(); + Global::RefConnectionTypeChanged().notify(); + MTP::restart(); + saveDelayed(); +} + +void ProxiesBoxController::saveDelayed() { + _saveTimer.callOnce(kSaveSettingsDelayedTimeout); +} + auto ProxiesBoxController::views() const -> rpl::producer { return _views.events(); } @@ -779,3 +935,12 @@ void ProxiesBoxController::updateView(const Item &item) { deleted, state }); } + +ProxiesBoxController::~ProxiesBoxController() { + if (_saveTimer.isActive()) { + App::CallDelayed( + kSaveSettingsDelayedTimeout, + QApplication::instance(), + [] { Local::writeSettings(); }); + } +} diff --git a/Telegram/SourceFiles/boxes/connection_box.h b/Telegram/SourceFiles/boxes/connection_box.h index 08fa3b3d09..f920ab38d0 100644 --- a/Telegram/SourceFiles/boxes/connection_box.h +++ b/Telegram/SourceFiles/boxes/connection_box.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "boxes/abstract_box.h" +#include "base/timer.h" namespace Ui { class InputField; @@ -119,11 +120,15 @@ public: void deleteItem(int id); void restoreItem(int id); + void applyItem(int id); object_ptr editItemBox(int id); object_ptr addNewItemBox(); + bool setProxyEnabled(bool enabled); rpl::producer views() const; + ~ProxiesBoxController(); + private: struct Item { int id = 0; @@ -132,12 +137,19 @@ private: }; std::vector::iterator findById(int id); + std::vector::iterator findByProxy(const ProxyData &proxy); void setDeleted(int id, bool deleted); void updateView(const Item &item); + void applyChanges(); + void saveDelayed(); int _idCounter = 0; int _selected = -1; std::vector _list; rpl::event_stream _views; + base::Timer _saveTimer; + + ProxyData _lastSelectedProxy; + bool _lastSelectedProxyUsed = false; }; diff --git a/Telegram/SourceFiles/codegen/style/parsed_file.cpp b/Telegram/SourceFiles/codegen/style/parsed_file.cpp index 94a0d07817..e9c743e1dd 100644 --- a/Telegram/SourceFiles/codegen/style/parsed_file.cpp +++ b/Telegram/SourceFiles/codegen/style/parsed_file.cpp @@ -32,6 +32,7 @@ constexpr int kErrorAlreadyDefined = 805; constexpr int kErrorBadString = 806; constexpr int kErrorIconDuplicate = 807; constexpr int kErrorBadIconModifier = 808; +constexpr int kErrorCyclicDependency = 809; QString findInputFile(const Options &options) { for (const auto &dir : options.includePaths) { @@ -148,14 +149,21 @@ Modifier GetModifier(const QString &name) { return modifiers.value(name); } -ParsedFile::ParsedFile(const Options &options) +ParsedFile::ParsedFile( + const Options &options, + std::vector includeStack) : filePath_(findInputFile(options)) , file_(filePath_) -, options_(options) { +, options_(options) +, includeStack_(includeStack) { } bool ParsedFile::read() { - if (!file_.read()) { + if (std::find(begin(includeStack_), end(includeStack_), filePath_) + != end(includeStack_)) { + logError(kErrorCyclicDependency) << "include cycle detected."; + return false; + } else if (!file_.read()) { return false; } @@ -205,7 +213,11 @@ common::LogStream ParsedFile::logErrorTypeMismatch() { ParsedFile::ModulePtr ParsedFile::readIncluded() { if (auto usingFile = assertNextToken(BasicType::String)) { if (assertNextToken(BasicType::Semicolon)) { - ParsedFile included(includedOptions(tokenValue(usingFile))); + auto includeStack = includeStack_; + includeStack.push_back(filePath_); + ParsedFile included( + includedOptions(tokenValue(usingFile)), + includeStack); if (included.read()) { return included.getResult(); } else { diff --git a/Telegram/SourceFiles/codegen/style/parsed_file.h b/Telegram/SourceFiles/codegen/style/parsed_file.h index 3d8085ffae..cdd26c6d7d 100644 --- a/Telegram/SourceFiles/codegen/style/parsed_file.h +++ b/Telegram/SourceFiles/codegen/style/parsed_file.h @@ -24,7 +24,9 @@ Modifier GetModifier(const QString &name); // Parses an input file to the internal struct. class ParsedFile { public: - explicit ParsedFile(const Options &options); + explicit ParsedFile( + const Options &options, + std::vector includeStack = {}); ParsedFile(const ParsedFile &other) = delete; ParsedFile &operator=(const ParsedFile &other) = delete; @@ -108,6 +110,8 @@ private: bool failed_ = false; ModulePtr module_; + std::vector includeStack_; + QMap typeNames_ = { { "int" , { structure::TypeTag::Int } }, { "double" , { structure::TypeTag::Double } }, diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 3ad18ff445..9a1a3fc96e 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -1184,6 +1184,8 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting Global::SetUseProxy(proxy ? true : false); if (proxy) { Global::SetProxiesList({ 1, proxy }); + } else { + Global::SetProxiesList({}); } Sandbox::refreshGlobalProxy(); } break; @@ -1221,16 +1223,20 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting const auto proxy = readProxy(); if (proxy) { list.push_back(proxy); + } else if (index < -list.size()) { + ++index; + } else if (index > list.size()) { + --index; } } if (!_checkStreamStatus(stream)) { return false; } Global::SetProxiesList(list); - Global::SetUseProxy(index >= 0 && index < count); + Global::SetUseProxy(index > 0 && index <= list.size()); index = std::abs(index); - if (index >= 0 && index < count) { - Global::SetSelectedProxy(list[index]); + if (index > 0 && index <= list.size()) { + Global::SetSelectedProxy(list[index - 1]); } else { Global::SetSelectedProxy(ProxyData()); } @@ -1239,12 +1245,17 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting if (!_checkStreamStatus(stream)) { return false; } - Global::SetProxiesList({ 1, proxy }); - if (connectionType == dbictTcpProxy - || connectionType == dbictHttpProxy) { + if (proxy) { + Global::SetProxiesList({ 1, proxy }); Global::SetSelectedProxy(proxy); - Global::SetUseProxy(true); + if (connectionType == dbictTcpProxy + || connectionType == dbictHttpProxy) { + Global::SetUseProxy(true); + } else { + Global::SetUseProxy(false); + } } else { + Global::SetProxiesList({}); Global::SetSelectedProxy(ProxyData()); Global::SetUseProxy(false); } @@ -2438,8 +2449,8 @@ void writeSettings() { auto proxyIt = ranges::find(proxies, proxy); if (proxy.type != ProxyData::Type::None && proxyIt == end(proxies)) { - proxies.insert(begin(proxies), proxy); - proxyIt = begin(proxies); + proxies.push_back(proxy); + proxyIt = end(proxies) - 1; } size += sizeof(quint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32); for (const auto &proxy : proxies) { @@ -2472,7 +2483,7 @@ void writeSettings() { data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList); data.stream << qint32(proxies.size()); - const auto index = qint32(proxyIt - begin(proxies)); + const auto index = qint32(proxyIt - begin(proxies)) + 1; data.stream << (Global::UseProxy() ? index : -index); for (const auto &proxy : proxies) { data.stream << qint32(kProxyTypeShift + int(proxy.type)); diff --git a/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp index 40d12e90c6..100a986e18 100644 --- a/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp +++ b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp @@ -58,6 +58,7 @@ int PaddingWrap::resizeGetHeight(int newWidth) { weak->resizeToWidth(newWidth - _padding.left() - _padding.right()); + SendPendingMoveResizeEvents(weak); } else { resize(QSize( _padding.left() + newWidth + _padding.right(), diff --git a/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp index afc6dd627a..8904bd488a 100644 --- a/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp +++ b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp @@ -92,12 +92,17 @@ void VerticalLayout::updateChildGeometry( width); } -RpWidget *VerticalLayout::addChild( +RpWidget *VerticalLayout::insertChild( + int atPosition, object_ptr child, const style::margins &margin) { - if (auto weak = AttachParentChild(this, child)) { - _rows.push_back({ std::move(child), margin }); - auto margins = getMargins(); + Expects(atPosition >= 0 && atPosition <= _rows.size()); + + if (const auto weak = AttachParentChild(this, child)) { + _rows.insert( + begin(_rows) + atPosition, + { std::move(child), margin }); + const auto margins = getMargins(); updateChildGeometry( margins, weak, @@ -105,11 +110,11 @@ RpWidget *VerticalLayout::addChild( width() - margins.left() - margins.right(), height() - margins.top() - margins.bottom()); weak->heightValue( - ) | rpl::start_with_next_done([this, weak] { + ) | rpl::start_with_next_done([=] { if (!_inResize) { childHeightUpdated(weak); } - }, [this, weak] { + }, [=] { removeChild(weak); }, lifetime()); return weak; diff --git a/Telegram/SourceFiles/ui/wrap/vertical_layout.h b/Telegram/SourceFiles/ui/wrap/vertical_layout.h index 8e80353125..2d5901d269 100644 --- a/Telegram/SourceFiles/ui/wrap/vertical_layout.h +++ b/Telegram/SourceFiles/ui/wrap/vertical_layout.h @@ -15,6 +15,20 @@ class VerticalLayout : public RpWidget { public: using RpWidget::RpWidget; + template < + typename Widget, + typename = std::enable_if_t< + std::is_base_of_v>> + Widget *insert( + int atPosition, + object_ptr &&child, + const style::margins &margin = style::margins()) { + return static_cast(insertChild( + atPosition, + std::move(child), + margin)); + } + template < typename Widget, typename = std::enable_if_t< @@ -22,9 +36,7 @@ public: Widget *add( object_ptr &&child, const style::margins &margin = style::margins()) { - return static_cast(addChild( - std::move(child), - margin)); + return insert(_rows.size(), std::move(child), margin); } QMargins getMargins() const override; @@ -37,7 +49,8 @@ protected: int visibleBottom) override; private: - RpWidget *addChild( + RpWidget *insertChild( + int addPosition, object_ptr child, const style::margins &margin); void childHeightUpdated(RpWidget *child);