diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index 9c3295adc..6b9e20791 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -73,7 +73,11 @@ QByteArray AuthSessionData::serialize() const { } stream << qint32(_variables.thirdSectionInfoEnabled ? 1 : 0); stream << qint32(_variables.smallDialogsList ? 1 : 0); - stream << qint32(snap(qRound(_variables.dialogsWidthRatio.current() * 1000000), 0, 1000000)); + stream << qint32(snap( + qRound(_variables.dialogsWidthRatio.current() * 1000000), + 0, + 1000000)); + stream << qint32(_variables.thirdColumnWidth.current()); } return result; } @@ -96,6 +100,7 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { qint32 thirdSectionInfoEnabled = 0; qint32 smallDialogsList = 0; float64 dialogsWidthRatio = _variables.dialogsWidthRatio.current(); + int thirdColumnWidth = _variables.thirdColumnWidth.current(); stream >> selectorTab; stream >> lastSeenWarningSeen; if (!stream.atEnd()) { @@ -137,6 +142,9 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { qint32 value = 0; stream >> value; dialogsWidthRatio = snap(value / 1000000., 0., 1.); + + stream >> value; + thirdColumnWidth = value; } if (stream.status() != QDataStream::Ok) { LOG(("App Error: Bad data for AuthSessionData::constructFromSerialized()")); @@ -170,6 +178,7 @@ void AuthSessionData::constructFromSerialized(const QByteArray &serialized) { _variables.thirdSectionInfoEnabled = thirdSectionInfoEnabled; _variables.smallDialogsList = smallDialogsList; _variables.dialogsWidthRatio = dialogsWidthRatio; + _variables.thirdColumnWidth = thirdColumnWidth; if (_variables.thirdSectionInfoEnabled) { _variables.tabbedSelectorSectionEnabled = false; } diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index 5f3ec219b..0074ce2e5 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -224,6 +224,15 @@ public: rpl::producer dialogsWidthRatioChanges() const { return _variables.dialogsWidthRatio.changes(); } + void setThirdColumnWidth(int width) { + _variables.thirdColumnWidth = width; + } + int thirdColumnWidth() const { + return _variables.thirdColumnWidth.current(); + } + rpl::producer thirdColumnWidthChanges() const { + return _variables.thirdColumnWidth.changes(); + } void markStickersUpdated() { _stickersUpdated.fire({}); @@ -321,6 +330,7 @@ private: Variables(); static constexpr auto kDefaultDialogsWidthRatio = 5. / 14; + static constexpr auto kDefaultThirdColumnWidth = 0; bool lastSeenWarningSeen = false; ChatHelpers::SelectorTab selectorTab; // per-window @@ -332,7 +342,10 @@ private: base::flat_set groupStickersSectionHidden; bool thirdSectionInfoEnabled = true; // per-window bool smallDialogsList = false; // per-window - rpl::variable dialogsWidthRatio = kDefaultDialogsWidthRatio; // per-window + rpl::variable dialogsWidthRatio + = kDefaultDialogsWidthRatio; // per-window + rpl::variable thirdColumnWidth + = kDefaultThirdColumnWidth; // per-window }; bool stickersUpdateNeeded(TimeMs lastUpdate, TimeMs now) const { diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 32e6f7758..0b042e4c5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -51,8 +51,6 @@ dialogsImportantBarHeight: 37px; dialogsSkip: 8px; -dialogsWidthMin: 260px; -dialogsWidthMax: 540px; dialogsWidthDuration: 120; dialogsTextWidthMin: 150px; dialogsScroll: ScrollArea(defaultScrollArea) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d06d66b43..cfe6556cf 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_search_from_controllers.h" #include "styles/style_dialogs.h" #include "styles/style_chat_helpers.h" +#include "styles/style_window.h" #include "ui/widgets/buttons.h" #include "ui/widgets/popup_menu.h" #include "data/data_drafts.h" @@ -959,7 +960,7 @@ void DialogsInner::setSearchedPressed(int pressed) { void DialogsInner::resizeEvent(QResizeEvent *e) { _addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2); - auto widthForCancelButton = qMax(width() + otherWidth(), st::dialogsWidthMin); + auto widthForCancelButton = qMax(width() + otherWidth(), st::columnMinimalWidthLeft); _cancelSearchInPeer->moveToLeft(widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInPeer->width(), st::searchedBarHeight + (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2); _cancelSearchFromUser->moveToLeft(widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width(), st::searchedBarHeight + st::dialogsSearchInHeight + st::lineWidth + (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index e11217a91..eca1bdff7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "dialogs/dialogs_inner_widget.h" #include "dialogs/dialogs_search_from_controllers.h" #include "styles/style_dialogs.h" +#include "styles/style_window.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" #include "ui/wrap/fade_wrap.h" @@ -64,7 +65,7 @@ private: DialogsWidget::UpdateButton::UpdateButton(QWidget *parent) : RippleButton(parent, st::dialogsUpdateButton.ripple) , _text(lang(lng_update_telegram).toUpper()) , _st(st::dialogsUpdateButton) { - resize(st::dialogsWidthMin, _st.height); + resize(st::columnMinimalWidthLeft, _st.height); } void DialogsWidget::UpdateButton::onStateChanged(State was, StateChangeSource source) { @@ -84,7 +85,7 @@ void DialogsWidget::UpdateButton::paintEvent(QPaintEvent *e) { p.setRenderHint(QPainter::TextAntialiasing); p.setPen(isOver() ? _st.overColor : _st.color); - if (width() >= st::dialogsWidthMin) { + if (width() >= st::columnMinimalWidthLeft) { r.setTop(_st.textTop); p.drawText(r, _text, style::al_top); } else { @@ -221,10 +222,16 @@ void DialogsWidget::startWidthAnimation() { return; } auto scrollGeometry = _scroll->geometry(); - auto grabGeometry = QRect(scrollGeometry.x(), scrollGeometry.y(), st::dialogsWidthMin, scrollGeometry.height()); + auto grabGeometry = QRect( + scrollGeometry.x(), + scrollGeometry.y(), + st::columnMinimalWidthLeft, + scrollGeometry.height()); _scroll->setGeometry(grabGeometry); myEnsureResized(_scroll); - auto image = QImage(grabGeometry.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + auto image = QImage( + grabGeometry.size() * cIntRetinaFactor(), + QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(cRetinaFactor()); image.fill(Qt::transparent); _scroll->render(&image, QPoint(0, 0), QRect(QPoint(0, 0), grabGeometry.size()), QWidget::DrawChildren | QWidget::IgnoreMask); @@ -974,10 +981,10 @@ void DialogsWidget::updateControlsGeometry() { filterAreaTop += st::dialogsForwardHeight; } auto smallLayoutWidth = (st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x()); - auto smallLayoutRatio = (width() < st::dialogsWidthMin) ? (st::dialogsWidthMin - width()) / float64(st::dialogsWidthMin - smallLayoutWidth) : 0.; + auto smallLayoutRatio = (width() < st::columnMinimalWidthLeft) ? (st::columnMinimalWidthLeft - width()) / float64(st::columnMinimalWidthLeft - smallLayoutWidth) : 0.; auto filterLeft = st::dialogsFilterPadding.x() + _mainMenuToggle->width() + st::dialogsFilterPadding.x(); auto filterRight = (Global::LocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x(); - auto filterWidth = qMax(width(), st::dialogsWidthMin) - filterLeft - filterRight; + auto filterWidth = qMax(width(), st::columnMinimalWidthLeft) - filterLeft - filterRight; auto filterAreaHeight = st::dialogsFilterPadding.y() + _mainMenuToggle->height() + st::dialogsFilterPadding.y(); auto filterTop = filterAreaTop + (filterAreaHeight - _filter->height()) / 2; filterLeft = anim::interpolate(filterLeft, smallLayoutWidth, smallLayoutRatio); diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index c64913dbd..58be62ec0 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -36,6 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_dialogs.h" #include "styles/style_widgets.h" #include "styles/style_history.h" +#include "styles/style_window.h" #include "window/notifications_manager.h" #include "observer_peer.h" #include "storage/storage_shared_media.h" @@ -46,7 +47,7 @@ constexpr auto kPinnedMessageTextLimit = 16; inline void initTextOptions() { _historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir(); - _textDlgOptions.maxw = st::dialogsWidthMax * 2; + _textDlgOptions.maxw = st::columnMaximalWidthLeft * 2; } style::color fromNameFg(int index) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index e3c6b0253..21eebce69 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include +#include #include #include "data/data_photo.h" #include "data/data_document.h" @@ -225,7 +226,8 @@ MainWidget::MainWidget( not_null controller) : RpWidget(parent) , _controller(controller) -, _dialogsWidth(st::dialogsWidthMin) +, _dialogsWidth(st::columnMinimalWidthLeft) +, _thirdColumnWidth(st::columnMinimalWidthThird) , _sideShadow(this) , _dialogs(this, _controller) , _history(this, _controller) @@ -262,7 +264,11 @@ MainWidget::MainWidget( subscribe(_controller->dialogsListDisplayForced(), [this](bool) { updateDialogsWidthAnimated(); }); - Auth().data().dialogsWidthRatioChanges() + rpl::merge( + Auth().data().dialogsWidthRatioChanges() + | rpl::map([] { return rpl::empty_value(); }), + Auth().data().thirdColumnWidthChanges() + | rpl::map([] { return rpl::empty_value(); })) | rpl::start_with_next( [this] { updateControlsGeometry(); }, lifetime()); @@ -2773,7 +2779,11 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation( auto sectionTop = getMainSectionTop(); if (selectingPeer() && Adaptive::OneColumn()) { - result.oldContentCache = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); + result.oldContentCache = myGrab(this, QRect( + 0, + sectionTop, + _dialogsWidth, + height() - sectionTop)); } else if (_mainSection) { result.oldContentCache = _mainSection->grabForShowAnimation(result); } else { @@ -2785,13 +2795,21 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation( _history->grabStart(); } if (Adaptive::OneColumn()) { - result.oldContentCache = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); + result.oldContentCache = myGrab(this, QRect( + 0, + sectionTop, + _dialogsWidth, + height() - sectionTop)); } else { _sideShadow->hide(); if (_thirdShadow) { _thirdShadow->hide(); } - result.oldContentCache = myGrab(this, QRect(_dialogsWidth, sectionTop, width() - _dialogsWidth, height() - sectionTop)); + result.oldContentCache = myGrab(this, QRect( + _dialogsWidth, + sectionTop, + width() - _dialogsWidth, + height() - sectionTop)); _sideShadow->show(); if (_thirdShadow) { _thirdShadow->show(); @@ -3118,13 +3136,21 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶m auto sectionTop = getMainSectionTop(); if (Adaptive::OneColumn()) { - result = myGrab(this, QRect(0, sectionTop, _dialogsWidth, height() - sectionTop)); + result = myGrab(this, QRect( + 0, + sectionTop, + _dialogsWidth, + height() - sectionTop)); } else { _sideShadow->hide(); if (_thirdShadow) { _thirdShadow->hide(); } - result = myGrab(this, QRect(_dialogsWidth, sectionTop, width() - _dialogsWidth, height() - sectionTop)); + result = myGrab(this, QRect( + _dialogsWidth, + sectionTop, + width() - _dialogsWidth, + height() - sectionTop)); _sideShadow->show(); if (_thirdShadow) { _thirdShadow->show(); @@ -3423,11 +3449,9 @@ void MainWidget::updateControlsGeometry() { _history->setGeometry(mainSectionGeometry); if (_hider) _hider->setGeometry(0, 0, dialogsWidth, height()); } else { - auto thirdSectionWidth = _thirdSection ? _thirdSection->width() : 0; + auto thirdSectionWidth = _thirdSection ? _thirdColumnWidth : 0; if (_thirdSection) { auto thirdSectionTop = getThirdSectionTop(); - accumulate_min(thirdSectionWidth, width() - st::columnMinimalWidthMain - st::columnMinimalWidthLeft); - accumulate_max(thirdSectionWidth, st::columnMinimalWidthThird); _thirdSection->setGeometry( width() - thirdSectionWidth, thirdSectionTop, @@ -3517,14 +3541,16 @@ void MainWidget::ensureFirstColumnResizeAreaCreated() { } auto moveLeftCallback = [=](int globalLeft) { auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x(); - auto newRatio = (newWidth < st::dialogsWidthMin / 2) + auto newRatio = (newWidth < st::columnMinimalWidthLeft / 2) ? 0. : float64(newWidth) / width(); Auth().data().setDialogsWidthRatio(newRatio); }; auto moveFinishedCallback = [=] { - if (!Adaptive::OneColumn() - && Auth().data().dialogsWidthRatio() > 0) { + if (Adaptive::OneColumn()) { + return; + } + if (Auth().data().dialogsWidthRatio() > 0) { Auth().data().setDialogsWidthRatio( float64(_dialogsWidth) / width()); } @@ -3541,9 +3567,18 @@ void MainWidget::ensureThirdColumnResizeAreaCreated() { return; } auto moveLeftCallback = [=](int globalLeft) { + auto newWidth = mapToGlobal(QPoint(width(), 0)).x() - globalLeft; + Auth().data().setThirdColumnWidth(newWidth); }; auto moveFinishedCallback = [=] { - + if (!Adaptive::ThreeColumn() || !_thirdSection) { + return; + } + Auth().data().setThirdColumnWidth(snap( + Auth().data().thirdColumnWidth(), + st::columnMinimalWidthThird, + st::columnMaximalWidthThird)); + Local::writeUserSettings(); }; createResizeArea( _thirdColumnResizeArea, @@ -3739,6 +3774,7 @@ void MainWidget::updateWindowAdaptiveLayout() { _dialogsWidth = useSmallColumnWidth ? _controller->dialogsSmallColumnWidth() : layout.dialogsWidth; + _thirdColumnWidth = layout.thirdWidth; if (layout.windowLayout != Global::AdaptiveWindowLayout()) { Global::SetAdaptiveWindowLayout(layout.windowLayout); Adaptive::Changed().notify(true); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 2502f73bd..036622f3f 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -583,7 +583,8 @@ private: bool _showBack = false; QPixmap _cacheUnder, _cacheOver; - int _dialogsWidth; + int _dialogsWidth = 0; + int _thirdColumnWidth = 0; Animation _a_dialogsWidth; object_ptr _sideShadow; diff --git a/Telegram/SourceFiles/window/window.style b/Telegram/SourceFiles/window/window.style index 1b7d83d85..c1c1114b2 100644 --- a/Telegram/SourceFiles/window/window.style +++ b/Telegram/SourceFiles/window/window.style @@ -31,8 +31,10 @@ windowShadow: icon {{ "window_shadow", windowShadowFg }}; windowShadowShift: 1px; columnMinimalWidthLeft: 260px; +columnMaximalWidthLeft: 540px; columnMinimalWidthMain: 380px; columnMinimalWidthThird: 292px;//345px; +columnMaximalWidthThird: 345px; adaptiveChatWideWidth: 880px; diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 37a5d639e..c48734741 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -108,23 +108,63 @@ Controller::ColumnLayout Controller::computeColumnLayout() const { dialogsWidth = chatWidth = bodyWidth; } else if (useNormalLayout()) { layout = Adaptive::WindowLayout::Normal; - dialogsWidth = qRound(bodyWidth * Auth().data().dialogsWidthRatio()); - accumulate_max(dialogsWidth, st::columnMinimalWidthLeft); + dialogsWidth = countDialogsWidthFromRatio(bodyWidth); accumulate_min(dialogsWidth, bodyWidth - st::columnMinimalWidthMain); chatWidth = bodyWidth - dialogsWidth; } else { layout = Adaptive::WindowLayout::ThreeColumn; - dialogsWidth = qRound(bodyWidth * Auth().data().dialogsWidthRatio()); - accumulate_max(dialogsWidth, st::columnMinimalWidthLeft); - thirdWidth = st::columnMinimalWidthThird; - accumulate_min( + dialogsWidth = countDialogsWidthFromRatio(bodyWidth); + thirdWidth = countThirdColumnWidthFromRatio(bodyWidth); + auto shrink = shrinkDialogsAndThirdColumns( dialogsWidth, - bodyWidth - thirdWidth - st::columnMinimalWidthMain); + thirdWidth, + bodyWidth); + dialogsWidth = shrink.dialogsWidth; + thirdWidth = shrink.thirdWidth; + chatWidth = bodyWidth - dialogsWidth - thirdWidth; } return { bodyWidth, dialogsWidth, chatWidth, thirdWidth, layout }; } +int Controller::countDialogsWidthFromRatio(int bodyWidth) const { + auto result = qRound(bodyWidth * Auth().data().dialogsWidthRatio()); + accumulate_max(result, st::columnMinimalWidthLeft); + accumulate_min(result, st::columnMaximalWidthLeft); + return result; +} + +int Controller::countThirdColumnWidthFromRatio(int bodyWidth) const { + auto result = Auth().data().thirdColumnWidth(); + accumulate_max(result, st::columnMinimalWidthThird); + accumulate_min(result, st::columnMaximalWidthThird); + return result; +} + +Controller::ShrinkResult Controller::shrinkDialogsAndThirdColumns( + int dialogsWidth, + int thirdWidth, + int bodyWidth) const { + auto chatWidth = st::columnMinimalWidthMain; + if (dialogsWidth + thirdWidth + chatWidth <= bodyWidth) { + return { dialogsWidth, thirdWidth }; + } + auto thirdWidthNew = ((bodyWidth - chatWidth) * thirdWidth) + / (dialogsWidth + thirdWidth); + auto dialogsWidthNew = ((bodyWidth - chatWidth) * dialogsWidth) + / (dialogsWidth + thirdWidth); + if (thirdWidthNew < st::columnMinimalWidthThird) { + thirdWidthNew = st::columnMinimalWidthThird; + dialogsWidthNew = bodyWidth - thirdWidthNew - chatWidth; + Assert(dialogsWidthNew >= st::columnMinimalWidthLeft); + } else if (dialogsWidthNew < st::columnMinimalWidthLeft) { + dialogsWidthNew = st::columnMinimalWidthLeft; + thirdWidthNew = bodyWidth - dialogsWidthNew - chatWidth; + Assert(thirdWidthNew >= st::columnMinimalWidthThird); + } + return { dialogsWidthNew, thirdWidthNew }; +} + bool Controller::canShowThirdSection() const { auto currentLayout = computeColumnLayout(); auto extendBy = minimalThreeColumnWidth() diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 7f10978ad..7f36f8e92 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -189,6 +189,16 @@ public: private: int minimalThreeColumnWidth() const; not_null chats() const; + int countDialogsWidthFromRatio(int bodyWidth) const; + int countThirdColumnWidthFromRatio(int bodyWidth) const; + struct ShrinkResult { + int dialogsWidth; + int thirdWidth; + }; + ShrinkResult shrinkDialogsAndThirdColumns( + int dialogsWidth, + int thirdWidth, + int bodyWidth) const; not_null _window;