2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-09-03 16:15:13 +00:00

New way of working with boxes (layers).

Now the background of boxes is separated to another widget.
This will allow to use a special layer widget (like settings)
together with the usual layers-boxes upon it, moving the special
widget behind the dark background when a usual layer-box is shown.
This commit is contained in:
John Preston
2016-08-16 19:53:10 +03:00
parent 05697374c5
commit 392984f276
54 changed files with 770 additions and 990 deletions

View File

@@ -28,167 +28,357 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "ui/filedialog.h"
BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : TWidget(parent)
, w(w)
, a_bg(0)
, _a_background(animation(this, &BackgroundWidget::step_background))
, hiding(false)
, shadow(st::boxShadow) {
w->setParent(this);
if (App::app()) App::app()->mtpPause();
setGeometry(0, 0, App::wnd()->width(), App::wnd()->height());
a_bg.start(1);
_a_background.start();
show();
connect(w, SIGNAL(closed()), this, SLOT(onInnerClose()));
connect(w, SIGNAL(resized()), this, SLOT(update()));
connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
w->setFocus();
}
void BackgroundWidget::showFast() {
_a_background.step(getms() + st::layerSlideDuration + 1);
update();
}
void BackgroundWidget::paintEvent(QPaintEvent *e) {
if (!w) return;
bool trivial = (rect() == e->rect());
QPainter p(this);
if (!trivial) {
p.setClipRect(e->rect());
void LayerWidget::setInnerFocus() {
auto focused = App::wnd()->focusWidget();
if (!isAncestorOf(focused)) {
doSetInnerFocus();
}
p.setOpacity(st::layerAlpha * a_bg.current());
p.fillRect(rect(), st::layerBg->b);
p.setOpacity(a_bg.current());
shadow.paint(p, w->geometry(), st::boxShadowShift);
}
void BackgroundWidget::keyPressEvent(QKeyEvent *e) {
class LayerStackWidget::BackgroundWidget : public TWidget {
public:
BackgroundWidget(QWidget *parent) : TWidget(parent)
, _shadow(st::boxShadow) {
}
void setLayerBox(const QRect &box) {
_box = box;
update();
}
void setOpacity(float64 opacity) {
_opacity = opacity;
}
protected:
void paintEvent(QPaintEvent *e) override {
Painter p(this);
p.setOpacity(st::layerAlpha * _opacity);
if (_box.isNull()) {
p.fillRect(rect(), st::layerBg);
} else {
auto clip = QRegion(rect()) - _box;
for (auto &r : clip.rects()) {
p.fillRect(r, st::layerBg);
}
p.setClipRegion(clip);
p.setOpacity(_opacity);
_shadow.paint(p, _box, st::boxShadowShift);
}
}
private:
QRect _box;
float64 _opacity = 0.;
BoxShadow _shadow;
};
LayerStackWidget::LayerStackWidget(QWidget *parent) : TWidget(parent)
, _background(this)
, a_bg(0)
, a_layer(0)
, _a_background(animation(this, &LayerStackWidget::step_background)) {
setGeometry(parentWidget()->rect());
hide();
}
void LayerStackWidget::paintEvent(QPaintEvent *e) {
if (!layer() && !_specialLayer && _layerCache.isNull()) {
return;
}
if (!_layerCache.isNull()) {
Painter p(this);
p.setClipRect(rect());
p.setOpacity(a_layer.current());
p.drawPixmap(_layerCacheBox.topLeft(), _layerCache);
}
}
void LayerStackWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
onClose();
}
}
void BackgroundWidget::mousePressEvent(QMouseEvent *e) {
void LayerStackWidget::mousePressEvent(QMouseEvent *e) {
onClose();
}
void BackgroundWidget::onClose() {
void LayerStackWidget::onClose() {
startHide();
}
bool BackgroundWidget::onInnerClose() {
if (_hidden.isEmpty()) {
void LayerStackWidget::onLayerClosed(LayerWidget *l) {
l->deleteLater();
if (l == _specialLayer) {
onClose();
_specialLayer = nullptr;
} else if (l == layer()) {
_layers.pop_back();
if (auto newLayer = layer()) {
l->hide();
newLayer->parentResized();
if (!_a_background.animating()) {
newLayer->show();
}
} else if (_specialLayer) {
l->hide();
} else {
_layers.push_back(l); // For animation cache grab.
onClose();
_layers.pop_back();
}
fixOrder();
if (App::wnd()) App::wnd()->setInnerFocus();
updateLayerBox();
} else {
for (auto i = _layers.begin(), e = _layers.end(); i != e; ++i) {
if (l == *i) {
_layers.erase(i);
break;
}
}
}
}
void LayerStackWidget::onLayerResized() {
updateLayerBox();
}
void LayerStackWidget::updateLayerBox() {
auto getLayerBox = [this]() {
if (!_layerCache.isNull()) {
return _layerCacheBox;
} else if (auto l = layer()) {
return l->geometry();
} else if (_specialLayer) {
return _specialLayer->geometry();
}
return QRect();
};
_background->setLayerBox(getLayerBox());
update();
}
void LayerStackWidget::startShow() {
startAnimation(1);
show();
}
void LayerStackWidget::showFast() {
if (_a_background.animating()) {
_a_background.step(getms() + st::layerSlideDuration + 1);
}
}
void LayerStackWidget::startHide() {
if (isHidden() || _hiding) {
return;
}
_hiding = true;
startAnimation(0);
}
void LayerStackWidget::startAnimation(float64 toOpacity) {
if (App::app()) App::app()->mtpPause();
a_bg.start(toOpacity);
a_layer.start(toOpacity);
_a_background.start();
if (_layerCache.isNull()) {
if (auto cacheLayer = layer() ? layer() : _specialLayer) {
_layerCache = myGrab(cacheLayer);
_layerCacheBox = cacheLayer->geometry();
}
}
if (_specialLayer) {
_specialLayer->hide();
}
if (auto l = layer()) {
l->hide();
}
updateLayerBox();
if (App::wnd()) App::wnd()->setInnerFocus();
}
bool LayerStackWidget::canSetFocus() const {
return (layer() || _specialLayer) && !_hiding;
}
void LayerStackWidget::setInnerFocus() {
if (_a_background.animating()) {
setFocus();
} else if (auto l = layer()) {
l->setInnerFocus();
} else if (_specialLayer) {
_specialLayer->setInnerFocus();
}
}
bool LayerStackWidget::contentOverlapped(const QRect &globalRect) {
if (isHidden()) {
return false;
}
if (_specialLayer && _specialLayer->overlaps(globalRect)) {
return true;
}
w->hide();
w->deleteLater();
w = _hidden.back();
_hidden.pop_back();
w->show();
resizeEvent(0);
w->showStep(1);
update();
if (auto l = layer()) {
return l->overlaps(globalRect);
}
return false;
}
void BackgroundWidget::startHide() {
if (hiding) return;
if (App::app()) App::app()->mtpPause();
hiding = true;
if (App::wnd()) App::wnd()->setInnerFocus();
a_bg.start(0);
_a_background.start();
w->startHide();
void LayerStackWidget::resizeEvent(QResizeEvent *e) {
_background->setGeometry(rect());
if (_specialLayer) {
_specialLayer->parentResized();
}
if (auto l = layer()) {
l->parentResized();
}
updateLayerBox();
}
bool BackgroundWidget::canSetFocus() const {
return w && !hiding;
void LayerStackWidget::updateAdaptiveLayout() {
}
void BackgroundWidget::setInnerFocus() {
if (w) {
w->setInnerFocus();
void LayerStackWidget::showLayer(LayerWidget *l) {
clearLayers();
appendLayer(l);
}
void LayerStackWidget::showSpecialLayer(LayerWidget *l) {
clearLayers();
if (_specialLayer) {
_specialLayer->hide();
_specialLayer->deleteLater();
}
_specialLayer = l;
activateLayer(l);
}
void LayerStackWidget::appendLayer(LayerWidget *l) {
if (auto oldLayer = layer()) {
oldLayer->hide();
}
_layers.push_back(l);
activateLayer(l);
}
void LayerStackWidget::prependLayer(LayerWidget *l) {
if (_layers.empty()) {
showLayer(l);
} else {
l->hide();
_layers.push_front(l);
initChildLayer(l);
}
}
bool BackgroundWidget::contentOverlapped(const QRect &globalRect) {
if (isHidden()) return false;
return w && w->overlaps(globalRect);
void LayerStackWidget::clearLayers() {
for_const (auto oldLayer, _layers) {
oldLayer->hide();
oldLayer->deleteLater();
}
_layers.clear();
}
void BackgroundWidget::resizeEvent(QResizeEvent *e) {
w->parentResized();
void LayerStackWidget::initChildLayer(LayerWidget *l) {
l->setParent(this);
connect(l, SIGNAL(closed(LayerWidget*)), this, SLOT(onLayerClosed(LayerWidget*)));
connect(l, SIGNAL(resized()), this, SLOT(onLayerResized()));
connect(l, SIGNAL(destroyed(QObject*)), this, SLOT(onLayerDestroyed(QObject*)));
l->parentResized();
fixOrder();
}
void BackgroundWidget::updateAdaptiveLayout() {
void LayerStackWidget::activateLayer(LayerWidget *l) {
initChildLayer(l);
if (isHidden()) {
startShow();
} else {
l->show();
if (App::wnd()) App::wnd()->setInnerFocus();
updateLayerBox();
}
fixOrder();
}
void BackgroundWidget::replaceInner(LayeredWidget *n) {
_hidden.push_back(w);
w->hide();
w = n;
w->setParent(this);
connect(w, SIGNAL(closed()), this, SLOT(onInnerClose()));
connect(w, SIGNAL(resized()), this, SLOT(update()));
connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
w->show();
resizeEvent(0);
w->showStep(1);
update();
void LayerStackWidget::fixOrder() {
if (auto l = layer()) {
_background->raise();
l->raise();
} else if (_specialLayer) {
_specialLayer->raise();
}
}
void BackgroundWidget::showLayerLast(LayeredWidget *n) {
_hidden.push_front(n);
n->setParent(this);
connect(n, SIGNAL(closed()), this, SLOT(onInnerClose()));
connect(n, SIGNAL(resized()), this, SLOT(update()));
connect(n, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
n->parentResized();
n->showStep(1);
n->hide();
update();
}
void BackgroundWidget::step_background(float64 ms, bool timer) {
float64 dt = ms / (hiding ? st::layerHideDuration : st::layerSlideDuration);
w->showStep(dt);
void LayerStackWidget::step_background(float64 ms, bool timer) {
float64 dt = ms / (_hiding ? st::layerHideDuration : st::layerSlideDuration);
if (dt >= 1) {
a_bg.finish();
if (hiding) {
App::wnd()->layerFinishedHide(this);
}
a_layer.finish();
_a_background.stop();
_layerCache = QPixmap();
if (_hiding) {
App::wnd()->layerFinishedHide(this);
} else {
if (_specialLayer) {
_specialLayer->show();
_specialLayer->showDone();
}
if (auto l = layer()) {
l->show();
l->showDone();
}
fixOrder();
if (App::wnd()) App::wnd()->setInnerFocus();
}
updateLayerBox();
if (App::app()) App::app()->mtpUnpause();
} else {
a_bg.update(dt, anim::easeOutCirc);
a_layer.update(dt, anim::linear);
}
_background->setOpacity(a_bg.current());
if (timer) {
_background->update();
update();
}
if (timer) update();
}
void BackgroundWidget::boxDestroyed(QObject *obj) {
if (obj == w) {
if (App::wnd()) App::wnd()->layerFinishedHide(this);
w = 0;
void LayerStackWidget::onLayerDestroyed(QObject *obj) {
if (obj == _specialLayer) {
_specialLayer = nullptr;
onClose();
} else if (obj == layer()) {
_layers.pop_back();
if (auto newLayer = layer()) {
newLayer->parentResized();
if (!_a_background.animating()) {
newLayer->show();
}
} else if (!_specialLayer) {
onClose();
}
fixOrder();
if (App::wnd()) App::wnd()->setInnerFocus();
updateLayerBox();
} else {
int32 index = _hidden.indexOf(static_cast<LayeredWidget*>(obj));
if (index >= 0) {
_hidden.removeAt(index);
for (auto i = _layers.begin(), e = _layers.end(); i != e; ++i) {
if (obj == *i) {
_layers.erase(i);
break;
}
}
}
}
BackgroundWidget::~BackgroundWidget() {
if (App::wnd()) App::wnd()->noBox(this);
w->deleteLater();
for (HiddenLayers::const_iterator i = _hidden.cbegin(), e = _hidden.cend(); i != e; ++i) {
(*i)->deleteLater();
}
LayerStackWidget::~LayerStackWidget() {
if (App::wnd()) App::wnd()->noLayerStack(this);
}
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)