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:
@@ -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)
|
||||
|
Reference in New Issue
Block a user