Extract a reusable Ui::ResizeArea class.

This commit is contained in:
John Preston 2017-11-12 19:41:00 +04:00
parent 3a25313e61
commit bca9b3ca3f
5 changed files with 194 additions and 42 deletions

View File

@ -38,6 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "data/data_drafts.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/focus_persister.h"
#include "ui/resize_area.h"
#include "chat_helpers/message_field.h"
#include "chat_helpers/stickers.h"
#include "observer_peer.h"
@ -226,7 +227,6 @@ MainWidget::MainWidget(
, _controller(controller)
, _dialogsWidth(st::dialogsWidthMin)
, _sideShadow(this)
, _sideResizeArea(this)
, _dialogs(this, _controller)
, _history(this, _controller)
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist)
@ -292,8 +292,6 @@ MainWidget::MainWidget(
_webPageOrGameUpdater.setSingleShot(true);
connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate()));
_sideResizeArea->setCursor(style::cur_sizehor);
using Update = Window::Theme::BackgroundUpdate;
subscribe(Window::Theme::Background(), [this](const Update &update) {
if (update.type == Update::Type::New || update.type == Update::Type::Changed) {
@ -354,8 +352,6 @@ MainWidget::MainWidget(
orderWidgets();
_sideResizeArea->installEventFilter(this);
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::startUpdateCheck();
#endif // !TDESKTOP_DISABLE_AUTOUPDATE
@ -3078,7 +3074,12 @@ void MainWidget::orderWidgets() {
if (_thirdShadow) {
_thirdShadow->raise();
}
_sideResizeArea->raise();
if (_firstColumnResizeArea) {
_firstColumnResizeArea->raise();
}
if (_thirdColumnResizeArea) {
_thirdColumnResizeArea->raise();
}
_playerPlaylist->raise();
_playerPanel->raise();
for (auto &instance : _playerFloats) {
@ -3458,22 +3459,12 @@ void MainWidget::updateControlsGeometry() {
_hider->setGeometryToLeft(dialogsWidth, 0, mainSectionWidth, height());
}
}
_sideResizeArea->setGeometryToLeft(_history->x(), 0, st::historyResizeWidth, height());
auto isSideResizeAreaVisible = [this] {
if (width() < st::columnMinimalWidthLeft + st::columnMinimalWidthMain) {
return false;
}
if (Adaptive::OneColumn() && !isMainSectionShown()) {
return false;
}
return true;
};
_sideResizeArea->setVisible(isSideResizeAreaVisible());
if (_mainSection) {
auto mainSectionGeometry = QRect(_history->x(), mainSectionTop, _history->width(), height() - mainSectionTop);
_mainSection->setGeometryWithTopMoved(mainSectionGeometry, _contentScrollAddToY);
}
if (_overview) _overview->setGeometry(_history->geometry());
refreshResizeAreas();
updateMediaPlayerPosition();
updateMediaPlaylistPosition(_playerPlaylist->x());
_contentScrollAddToY = 0;
@ -3482,6 +3473,84 @@ void MainWidget::updateControlsGeometry() {
}
}
void MainWidget::refreshResizeAreas() {
if (!Adaptive::OneColumn()) {
ensureFirstColumnResizeAreaCreated();
_firstColumnResizeArea->setGeometryToLeft(
_history->x(),
0,
st::historyResizeWidth,
height());
} else if (_firstColumnResizeArea) {
_firstColumnResizeArea.destroy();
}
if (Adaptive::ThreeColumn() && _thirdSection) {
ensureThirdColumnResizeAreaCreated();
_thirdColumnResizeArea->setGeometryToLeft(
_thirdSection->x(),
0,
st::historyResizeWidth,
height());
} else if (_thirdColumnResizeArea) {
_thirdColumnResizeArea.destroy();
}
}
template <typename MoveCallback, typename FinishCallback>
void MainWidget::createResizeArea(
object_ptr<Ui::ResizeArea> &area,
MoveCallback &&moveCallback,
FinishCallback &&finishCallback) {
area.create(this);
area->show();
area->addMoveLeftCallback(
std::forward<MoveCallback>(moveCallback));
area->addMoveFinishedCallback(
std::forward<FinishCallback>(finishCallback));
orderWidgets();
}
void MainWidget::ensureFirstColumnResizeAreaCreated() {
if (_firstColumnResizeArea) {
return;
}
auto moveLeftCallback = [=](int globalLeft) {
auto newWidth = globalLeft - mapToGlobal(QPoint(0, 0)).x();
auto newRatio = (newWidth < st::dialogsWidthMin / 2)
? 0.
: float64(newWidth) / width();
Auth().data().setDialogsWidthRatio(newRatio);
};
auto moveFinishedCallback = [=] {
if (!Adaptive::OneColumn()
&& Auth().data().dialogsWidthRatio() > 0) {
Auth().data().setDialogsWidthRatio(
float64(_dialogsWidth) / width());
}
Local::writeUserSettings();
};
createResizeArea(
_firstColumnResizeArea,
std::move(moveLeftCallback),
std::move(moveFinishedCallback));
}
void MainWidget::ensureThirdColumnResizeAreaCreated() {
if (_thirdColumnResizeArea) {
return;
}
auto moveLeftCallback = [=](int globalLeft) {
};
auto moveFinishedCallback = [=] {
};
createResizeArea(
_thirdColumnResizeArea,
std::move(moveLeftCallback),
std::move(moveFinishedCallback));
}
void MainWidget::updateDialogsWidthAnimated() {
if (Auth().data().dialogsWidthRatio() > 0) {
return;
@ -3581,27 +3650,7 @@ void MainWidget::keyPressEvent(QKeyEvent *e) {
}
bool MainWidget::eventFilter(QObject *o, QEvent *e) {
if (o == _sideResizeArea) {
auto mouseLeft = [this, e] {
return mapFromGlobal(static_cast<QMouseEvent*>(e)->globalPos()).x();
};
if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) {
_resizingSide = true;
_resizingSideShift = mouseLeft() - (Adaptive::OneColumn() ? 0 : _dialogsWidth);
} else if (e->type() == QEvent::MouseButtonRelease) {
_resizingSide = false;
if (!Adaptive::OneColumn()
&& Auth().data().dialogsWidthRatio() > 0) {
Auth().data().setDialogsWidthRatio(
float64(_dialogsWidth) / width());
}
Local::writeUserSettings();
} else if (e->type() == QEvent::MouseMove && _resizingSide) {
auto newWidth = mouseLeft() - _resizingSideShift;
auto newRatio = (newWidth < st::dialogsWidthMin / 2) ? 0. : float64(newWidth) / width();
Auth().data().setDialogsWidthRatio(newRatio);
}
} else if (e->type() == QEvent::FocusIn) {
if (e->type() == QEvent::FocusIn) {
if (auto widget = qobject_cast<QWidget*>(o)) {
if (_history == widget || _history->isAncestorOf(widget)
|| (_overview && (_overview == widget || _overview->isAncestorOf(widget)))

View File

@ -44,6 +44,7 @@ class Float;
} // namespace Media
namespace Ui {
class ResizeArea;
class PlainShadow;
class DropdownMenu;
template <typename Widget>
@ -558,6 +559,15 @@ private:
void viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint> &result, mtpRequestId req);
bool viewsIncrementFail(const RPCError &error, mtpRequestId req);
void refreshResizeAreas();
template <typename MoveCallback, typename FinishCallback>
void createResizeArea(
object_ptr<Ui::ResizeArea> &area,
MoveCallback &&moveCallback,
FinishCallback &&finishCallback);
void ensureFirstColumnResizeAreaCreated();
void ensureThirdColumnResizeAreaCreated();
not_null<Window::Controller*> _controller;
bool _started = false;
@ -578,7 +588,8 @@ private:
object_ptr<Ui::PlainShadow> _sideShadow;
object_ptr<Ui::PlainShadow> _thirdShadow = { nullptr };
object_ptr<TWidget> _sideResizeArea;
object_ptr<Ui::ResizeArea> _firstColumnResizeArea = { nullptr };
object_ptr<Ui::ResizeArea> _thirdColumnResizeArea = { nullptr };
object_ptr<DialogsWidget> _dialogs;
object_ptr<HistoryWidget> _history;
object_ptr<Window::SectionWidget> _mainSection = { nullptr };
@ -670,7 +681,7 @@ private:
std::unique_ptr<App::WallPaper> _background;
bool _resizingSide = false;
int _resizingSideShift = 0;
bool _firstColumnResizing = false;
int _firstColumnResizingShift = 0;
};

View File

@ -0,0 +1,91 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/rp_widget.h"
namespace Ui {
class ResizeArea : public RpWidget {
public:
ResizeArea(QWidget *parent) : RpWidget(parent) {
setCursor(style::cur_sizehor);
}
rpl::producer<int> moveLeft() const {
return _moveLeft.events();
}
template <typename Callback>
void addMoveLeftCallback(Callback &&callback) {
moveLeft()
| rpl::start_with_next(
std::forward<Callback>(callback),
lifetime());
}
rpl::producer<> moveFinished() const {
return _moveFinished.events();
}
template <typename Callback>
void addMoveFinishedCallback(Callback &&callback) {
moveFinished()
| rpl::start_with_next(
std::forward<Callback>(callback),
lifetime());
}
~ResizeArea() {
moveFinish();
}
protected:
void mousePressEvent(QMouseEvent *e) override {
if (e->button() == Qt::LeftButton) {
_moving = true;
_moveStartLeft = e->pos().x();
}
}
void mouseReleaseEvent(QMouseEvent *e) override {
if (e->button() == Qt::LeftButton) {
moveFinish();
}
}
void mouseMoveEvent(QMouseEvent *e) override {
if (_moving) {
_moveLeft.fire(e->globalPos().x() - _moveStartLeft);
}
}
private:
void moveFinish() {
if (base::take(_moving)) {
_moveFinished.fire({});
}
}
rpl::event_stream<int> _moveLeft;
rpl::event_stream<> _moveFinished;
int _moveStartLeft = 0;
bool _moving = false;
};
} // namespace Ui

View File

@ -32,7 +32,7 @@ windowShadowShift: 1px;
columnMinimalWidthLeft: 260px;
columnMinimalWidthMain: 380px;
columnMinimalWidthThird: 345px;//292px;//345px;
columnMinimalWidthThird: 292px;//345px;
adaptiveChatWideWidth: 880px;

View File

@ -609,6 +609,7 @@
<(src_loc)/ui/focus_persister.h
<(src_loc)/ui/images.cpp
<(src_loc)/ui/images.h
<(src_loc)/ui/resize_area.h
<(src_loc)/ui/rp_widget.h
<(src_loc)/ui/search_field_controller.cpp
<(src_loc)/ui/search_field_controller.h