mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-08-31 06:26:18 +00:00
Profile done as a new generic Window::SectionWidget.
Slide animation reimplemented.
This commit is contained in:
33
Telegram/SourceFiles/window/section_memento.h
Normal file
33
Telegram/SourceFiles/window/section_memento.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Window {
|
||||
|
||||
class SectionWidget;
|
||||
|
||||
class SectionMemento {
|
||||
public:
|
||||
virtual SectionWidget *createWidget(QWidget *parent, const QRect &geometry) const = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Window
|
82
Telegram/SourceFiles/window/section_widget.cpp
Normal file
82
Telegram/SourceFiles/window/section_widget.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "window/section_widget.h"
|
||||
|
||||
#include "application.h"
|
||||
|
||||
namespace Window {
|
||||
|
||||
SectionWidget::SectionWidget(QWidget *parent) : TWidget(parent) {
|
||||
}
|
||||
|
||||
void SectionWidget::setGeometryWithTopMoved(const QRect &newGeometry, int topDelta) {
|
||||
_topDelta = topDelta;
|
||||
bool willBeResized = (size() != newGeometry.size());
|
||||
if (geometry() != newGeometry) {
|
||||
setGeometry(newGeometry);
|
||||
}
|
||||
if (!willBeResized) {
|
||||
resizeEvent(nullptr);
|
||||
}
|
||||
_topDelta = 0;
|
||||
}
|
||||
|
||||
void SectionWidget::showAnimated(SlideDirection direction, const SectionSlideParams ¶ms) {
|
||||
t_assert(_showAnimation == nullptr);
|
||||
|
||||
showChildren();
|
||||
auto myContentCache = grabForShowAnimation(params);
|
||||
hideChildren();
|
||||
showAnimatedHook();
|
||||
|
||||
_showAnimation = std_::make_unique<SlideAnimation>();
|
||||
_showAnimation->setDirection(direction);
|
||||
_showAnimation->setRepaintCallback(func(this, &SectionWidget::repaintCallback));
|
||||
_showAnimation->setFinishedCallback(func(this, &SectionWidget::showFinished));
|
||||
_showAnimation->setPixmaps(params.oldContentCache, myContentCache);
|
||||
_showAnimation->setTopBarShadow(params.withTopBarShadow);
|
||||
_showAnimation->start();
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void SectionWidget::paintEvent(QPaintEvent *e) {
|
||||
if (Ui::skipPaintEvent(this, e)) return;
|
||||
|
||||
if (_showAnimation) {
|
||||
Painter p(this);
|
||||
_showAnimation->paintContents(p, e->rect());
|
||||
}
|
||||
}
|
||||
|
||||
void SectionWidget::showFinished() {
|
||||
if (isHidden()) return;
|
||||
|
||||
App::app()->mtpUnpause();
|
||||
|
||||
showChildren();
|
||||
showFinishedHook();
|
||||
|
||||
setInnerFocus();
|
||||
}
|
||||
|
||||
} // namespace Window
|
108
Telegram/SourceFiles/window/section_widget.h
Normal file
108
Telegram/SourceFiles/window/section_widget.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/twidget.h"
|
||||
#include "window/slide_animation.h"
|
||||
|
||||
namespace Window {
|
||||
|
||||
class SectionMemento;
|
||||
|
||||
struct SectionSlideParams {
|
||||
QPixmap oldContentCache;
|
||||
bool withTopBarShadow = false;
|
||||
};
|
||||
|
||||
class SectionWidget : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SectionWidget(QWidget *parent);
|
||||
|
||||
virtual PeerData *peerForDialogs() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// When resizing the widget with top edge moved up or down and we
|
||||
// want to add this top movement to the scroll position, so inner
|
||||
// content will not move.
|
||||
void setGeometryWithTopMoved(const QRect &newGeometry, int topDelta);
|
||||
|
||||
virtual bool hasTopBarShadow() const {
|
||||
return false;
|
||||
}
|
||||
void showAnimated(SlideDirection direction, const SectionSlideParams ¶ms);
|
||||
|
||||
// This can be used to grab with or without top bar shadow.
|
||||
// This will be protected when animation preparation will be done inside.
|
||||
virtual QPixmap grabForShowAnimation(const SectionSlideParams ¶ms) {
|
||||
return myGrab(this);
|
||||
}
|
||||
|
||||
// Attempt to show the required section inside the existing one.
|
||||
// For example if this section already shows exactly the required
|
||||
// memento it can simply return true - it is shown already.
|
||||
virtual bool showInternal(SectionMemento *memento) = 0;
|
||||
|
||||
// Create a memento of that section to store it in the history stack.
|
||||
virtual std_::unique_ptr<SectionMemento> createMemento() const = 0;
|
||||
|
||||
virtual void setInnerFocus() {
|
||||
setFocus();
|
||||
}
|
||||
|
||||
virtual void updateAdaptiveLayout() {
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
// Temp variable used in resizeEvent() implementation, that is passed
|
||||
// to setGeometryWithTopMoved() to adjust the scroll position with the resize.
|
||||
int topDelta() const {
|
||||
return _topDelta;
|
||||
}
|
||||
|
||||
// Called after the hideChildren() call in showAnimated().
|
||||
virtual void showAnimatedHook() {
|
||||
}
|
||||
|
||||
// Called after the showChildren() call in showFinished().
|
||||
virtual void showFinishedHook() {
|
||||
}
|
||||
|
||||
private:
|
||||
// QWidget::update() method is overloaded and we need template deduction.
|
||||
void repaintCallback() {
|
||||
update();
|
||||
}
|
||||
void showFinished();
|
||||
|
||||
std_::unique_ptr<SlideAnimation> _showAnimation;
|
||||
|
||||
// Saving here topDelta in resizeWithTopMoved() to get it passed to resizeEvent().
|
||||
int _topDelta = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Window
|
109
Telegram/SourceFiles/window/slide_animation.cpp
Normal file
109
Telegram/SourceFiles/window/slide_animation.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "window/slide_animation.h"
|
||||
|
||||
namespace Window {
|
||||
|
||||
SlideAnimation::SlideAnimation()
|
||||
: _animation(animation(this, &SlideAnimation::step)) {
|
||||
}
|
||||
|
||||
void SlideAnimation::paintContents(Painter &p, const QRect &update) const {
|
||||
int retina = cIntRetinaFactor();
|
||||
|
||||
_animation.step(getms());
|
||||
if (a_progress.current() < 1) {
|
||||
p.fillRect(update, st::white);
|
||||
int underLeft = a_coordUnder.current();
|
||||
int underWidth = _cacheUnder.width() / retina;
|
||||
int underHeight = _cacheUnder.height() / retina;
|
||||
QRect underDest(0, 0, underWidth + underLeft, underHeight);
|
||||
QRect underSrc(-underLeft * retina, 0, (underWidth + underLeft) * retina, underHeight * retina);
|
||||
p.setOpacity(1. - a_progress.current());
|
||||
p.drawPixmap(underDest, _cacheUnder, underSrc);
|
||||
p.setOpacity(a_progress.current());
|
||||
}
|
||||
p.drawPixmap(a_coordOver.current(), 0, _cacheOver);
|
||||
|
||||
if (_topBarShadowEnabled) {
|
||||
p.setOpacity(1);
|
||||
p.fillRect(0, st::topBarHeight, _cacheOver.width() / retina, st::lineWidth, st::shadowColor);
|
||||
}
|
||||
}
|
||||
|
||||
void SlideAnimation::setDirection(SlideDirection direction) {
|
||||
_direction = direction;
|
||||
}
|
||||
|
||||
void SlideAnimation::setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache) {
|
||||
_cacheUnder = oldContentCache;
|
||||
_cacheOver = newContentCache;
|
||||
}
|
||||
|
||||
void SlideAnimation::setTopBarShadow(bool enabled) {
|
||||
_topBarShadowEnabled = enabled;
|
||||
}
|
||||
|
||||
void SlideAnimation::setRepaintCallback(RepaintCallback &&callback) {
|
||||
_repaintCallback = std_::move(callback);
|
||||
}
|
||||
|
||||
void SlideAnimation::setFinishedCallback(FinishedCallback &&callback) {
|
||||
_finishedCallback = std_::move(callback);
|
||||
}
|
||||
|
||||
void SlideAnimation::start() {
|
||||
int delta = st::slideShift;
|
||||
a_progress = anim::fvalue(0, 1);
|
||||
if (_direction == SlideDirection::FromLeft) {
|
||||
a_coordUnder = anim::ivalue(0, delta);
|
||||
a_coordOver = anim::ivalue(-delta, 0);
|
||||
} else {
|
||||
a_coordUnder = anim::ivalue(0, -delta);
|
||||
a_coordOver = anim::ivalue(delta, 0);
|
||||
}
|
||||
_animation.start();
|
||||
}
|
||||
|
||||
void SlideAnimation::step(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::slideDuration;
|
||||
if (dt >= 1) {
|
||||
dt = 1;
|
||||
if (timer) {
|
||||
_animation.stop();
|
||||
a_coordUnder.finish();
|
||||
a_coordOver.finish();
|
||||
|
||||
_finishedCallback.call();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
a_coordUnder.update(dt, anim::linear);
|
||||
a_coordOver.update(dt, anim::linear);
|
||||
a_progress.update(dt, anim::linear);
|
||||
if (timer) {
|
||||
_repaintCallback.call();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Window
|
64
Telegram/SourceFiles/window/slide_animation.h
Normal file
64
Telegram/SourceFiles/window/slide_animation.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
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-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Window {
|
||||
|
||||
enum class SlideDirection {
|
||||
FromRight,
|
||||
FromLeft,
|
||||
};
|
||||
|
||||
class SlideAnimation {
|
||||
public:
|
||||
SlideAnimation();
|
||||
|
||||
void paintContents(Painter &p, const QRect &update) const;
|
||||
|
||||
void setDirection(SlideDirection direction);
|
||||
void setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache);
|
||||
void setTopBarShadow(bool enabled);
|
||||
|
||||
using RepaintCallback = Function<void>;
|
||||
void setRepaintCallback(RepaintCallback &&callback);
|
||||
|
||||
using FinishedCallback = Function<void>;
|
||||
void setFinishedCallback(FinishedCallback &&callback);
|
||||
|
||||
void start();
|
||||
|
||||
private:
|
||||
void step(float64 ms, bool timer);
|
||||
|
||||
SlideDirection _direction = SlideDirection::FromRight;
|
||||
bool _topBarShadowEnabled = false;
|
||||
|
||||
mutable Animation _animation;
|
||||
QPixmap _cacheUnder, _cacheOver;
|
||||
anim::ivalue a_coordUnder, a_coordOver;
|
||||
anim::fvalue a_progress;
|
||||
|
||||
RepaintCallback _repaintCallback;
|
||||
FinishedCallback _finishedCallback;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Window
|
@@ -81,17 +81,17 @@ void TopBarWidget::onClearSelection() {
|
||||
|
||||
void TopBarWidget::onInfoClicked() {
|
||||
PeerData *p = App::main() ? App::main()->historyPeer() : 0;
|
||||
if (p) App::main()->showPeerProfile(p);
|
||||
if (p) Ui::showPeerProfile(p);
|
||||
}
|
||||
|
||||
void TopBarWidget::onAddContact() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
UserData *u = p ? p->asUser() : 0;
|
||||
if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone));
|
||||
}
|
||||
|
||||
void TopBarWidget::onEdit() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
if (p) {
|
||||
if (p->isChannel()) {
|
||||
Ui::showLayer(new EditChannelBox(p->asChannel()));
|
||||
@@ -104,7 +104,7 @@ void TopBarWidget::onEdit() {
|
||||
}
|
||||
|
||||
void TopBarWidget::onDeleteContact() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
UserData *u = p ? p->asUser() : 0;
|
||||
if (u) {
|
||||
ConfirmBox *box = new ConfirmBox(lng_sure_delete_contact(lt_contact, p->name), lang(lng_box_delete));
|
||||
@@ -114,7 +114,7 @@ void TopBarWidget::onDeleteContact() {
|
||||
}
|
||||
|
||||
void TopBarWidget::onDeleteContactSure() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
UserData *u = p ? p->asUser() : 0;
|
||||
if (u) {
|
||||
Ui::showChatsList();
|
||||
@@ -124,7 +124,7 @@ void TopBarWidget::onDeleteContactSure() {
|
||||
}
|
||||
|
||||
void TopBarWidget::onDeleteAndExit() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
ChatData *c = p ? p->asChat() : 0;
|
||||
if (c) {
|
||||
ConfirmBox *box = new ConfirmBox(lng_sure_delete_and_exit(lt_group, p->name), lang(lng_box_leave), st::attentionBoxButton);
|
||||
@@ -134,7 +134,7 @@ void TopBarWidget::onDeleteAndExit() {
|
||||
}
|
||||
|
||||
void TopBarWidget::onDeleteAndExitSure() {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
ChatData *c = p ? p->asChat() : 0;
|
||||
if (c) {
|
||||
Ui::showChatsList();
|
||||
@@ -181,22 +181,28 @@ void TopBarWidget::step_appearance(float64 ms, bool timer) {
|
||||
void TopBarWidget::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
if (e->rect().top() < st::topBarHeight) { // optimize shadow-only drawing
|
||||
p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b);
|
||||
if (_clearSelection->isHidden()) {
|
||||
p.save();
|
||||
main()->paintTopBar(p, a_over.current(), _info->isHidden() ? 0 : _info->width());
|
||||
p.restore();
|
||||
} else {
|
||||
p.setFont(st::linkFont->f);
|
||||
p.setPen(st::btnDefLink.color->p);
|
||||
p.drawText(_selStrLeft, st::topBarButton.textTop + st::linkFont->ascent, _selStr);
|
||||
p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b);
|
||||
if (_clearSelection->isHidden()) {
|
||||
p.save();
|
||||
int decreaseWidth = 0;
|
||||
if (!_info->isHidden()) {
|
||||
decreaseWidth += _info->width();
|
||||
decreaseWidth -= st::topBarForwardPadding.right();
|
||||
}
|
||||
if (!_search->isHidden()) {
|
||||
decreaseWidth += _search->width();
|
||||
}
|
||||
main()->paintTopBar(p, a_over.current(), decreaseWidth);
|
||||
p.restore();
|
||||
} else {
|
||||
p.setFont(st::linkFont);
|
||||
p.setPen(st::btnDefLink.color);
|
||||
p.drawText(_selStrLeft, st::topBarButton.textTop + st::linkFont->ascent, _selStr);
|
||||
}
|
||||
}
|
||||
|
||||
void TopBarWidget::mousePressEvent(QMouseEvent *e) {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && (p || !_selCount)) {
|
||||
emit clicked();
|
||||
}
|
||||
@@ -289,7 +295,7 @@ void TopBarWidget::showAll() {
|
||||
resizeEvent(0);
|
||||
return;
|
||||
}
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0, *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0;
|
||||
PeerData *p = nullptr/*App::main() ? App::main()->profilePeer() : 0*/, *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0;
|
||||
if (p && (p->isChat() || (p->isUser() && (p->asUser()->contact >= 0 || !App::phoneFromSharedContact(peerToUser(p->id)).isEmpty())))) {
|
||||
if (p->isChat()) {
|
||||
if (p->asChat()->canEdit()) {
|
||||
@@ -362,7 +368,7 @@ void TopBarWidget::showAll() {
|
||||
}
|
||||
|
||||
void TopBarWidget::showSelected(uint32 selCount, bool canDelete) {
|
||||
PeerData *p = App::main() ? App::main()->profilePeer() : 0;
|
||||
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
|
||||
_selPeer = App::main()->overviewPeer() ? App::main()->overviewPeer() : App::main()->peer();
|
||||
_selCount = selCount;
|
||||
_canDelete = canDelete;
|
||||
|
@@ -27,7 +27,6 @@ class PeerAvatarButton;
|
||||
} // namespace Ui
|
||||
class FlatButton;
|
||||
class IconedButton;
|
||||
class PlainShadow;
|
||||
|
||||
namespace Window {
|
||||
|
||||
|
Reference in New Issue
Block a user