diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index ab57a34428..67aaae7389 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -192,7 +192,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_settings_send_enter" = "Send by Enter"; "lng_settings_send_ctrlenter" = "Send by Ctrl+Enter"; "lng_settings_send_cmdenter" = "Send by Cmd+Enter"; -"lng_settings_cats_and_dogs" = "Allow cats and dogs"; + +"lng_settings_section_background" = "Chat background"; +"lng_settings_bg_from_gallery" = "Choose from gallery"; +"lng_settings_bg_from_file" = "Choose from file"; +"lng_settings_bg_tile" = "Tile background"; + +"lng_backgrounds_header" = "Choose your new chat background"; "lng_download_path_dont_ask" = "Don't ask download path for each file"; "lng_download_path_label" = "Download path:"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 54e9174dbd..03ed38905c 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -350,8 +350,7 @@ introPointTop: 3px; introPointDelta: 10px; introPointColor: rgb(0, 0, 0); introPointAlpha: 0.5; -introPointHoverColor: rgb(47, 158, 218); -introPointHoverAlpha: 0.5; +introPointHoverColor: #86b4e3; introPointStepT: transition(sineInOut); introPointAlphaT: transition(linear); introPointShowStepT: transition(easeOutCirc); @@ -554,6 +553,8 @@ setErrHeight: 30px; setErrFont: font(fsize); setGoodColor: #008000; +setBackgroundSize: 120px; + btnSetUpload: flatButton(btnDefNext, btnDefBig) { width: 206px; height: 42px; @@ -736,8 +737,6 @@ topBarActionButton: flatButton(btnDefNext, btnDefBig) { } topBarActionSkip: 13px; -historyBG: #dfe4e8; - historyToEnd: iconedButton(btnDefIconed) { bgColor: transparent; overBgColor: transparent; @@ -1688,3 +1687,9 @@ langButton: flatCheckbox(rbDefFlat) { langsCloseButton: flatButton(aboutCloseButton) { width: langsWidth; } + +backgroundPadding: 10px; +backgroundSize: size(108px, 193px); +backgroundScroll: flatScroll(newGroupScroll) { + topsh: -2px; +} diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 71564db4df..e63dc5f4bf 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -78,6 +78,13 @@ namespace { LastPhotosList lastPhotos; typedef QHash LastPhotosMap; LastPhotosMap lastPhotosMap; + + style::color _msgServiceBG; + style::color _historyScrollBarColor; + style::color _historyScrollBgColor; + style::color _historyScrollBarOverColor; + style::color _historyScrollBgOverColor; + style::color _introPointHoverColor; } namespace App { @@ -1390,6 +1397,7 @@ namespace App { clearAllImages(); } else { clearStorageImages(); + cSetServerBackgrounds(WallPapers()); } serviceImageCacheSize = imageCacheSize(); @@ -1684,7 +1692,7 @@ namespace App { } stream << quint32(dbiSendKey) << qint32(cCtrlEnter() ? dbiskCtrlEnter : dbiskEnter); - stream << quint32(dbiCatsAndDogs) << qint32(cCatsAndDogs() ? 1 : 0); + stream << quint32(dbiTileBackground) << qint32(cTileBackground() ? 1 : 0); stream << quint32(dbiReplaceEmojis) << qint32(cReplaceEmojis() ? 1 : 0); stream << quint32(dbiDefaultAttach) << qint32(cDefaultAttach()); stream << quint32(dbiSoundNotify) << qint32(cSoundNotify()); @@ -1823,7 +1831,12 @@ namespace App { case dbiCatsAndDogs: { qint32 v; stream >> v; - cSetCatsAndDogs(v == 1); + } break; + + case dbiTileBackground: { + qint32 v; + stream >> v; + cSetTileBackground(v == 1); } break; case dbiReplaceEmojis: { @@ -2140,4 +2153,171 @@ namespace App { } } + void initBackground(int32 id, const QImage &p, bool nowrite) { + if (Local::readBackground()) return; + + QImage img(p); + if (p.isNull()) { + img.load(st::msgBG); + id = 0; + } + if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied && img.format() != QImage::Format_RGB32) { + img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } + + if (!nowrite) Local::writeBackground(id, img); + + delete cChatBackground(); + cSetChatBackground(new QPixmap(QPixmap::fromImage(img, Qt::ColorOnly))); + cSetChatBackgroundId(id); + + if (App::main()) App::main()->clearCachedBackground(); + + uint64 components[3] = { 0 }, componentsScroll[3] = { 0 }, componentsPoint[3] = { 0 }; + int w = img.width(), h = img.height(), size = w * h; + const uchar *pix = img.constBits(); + if (pix) { + for (int32 i = 0, l = size * 4; i < l; i += 4) { + components[2] += pix[i + 0]; + components[1] += pix[i + 1]; + components[0] += pix[i + 2]; + } + } + if (size) { + for (int32 i = 0; i < 3; ++i) components[i] /= size; + } + int maxtomin[3] = { 0, 1, 2 }; + if (components[maxtomin[0]] < components[maxtomin[1]]) { + qSwap(maxtomin[0], maxtomin[1]); + } + if (components[maxtomin[1]] < components[maxtomin[2]]) { + qSwap(maxtomin[1], maxtomin[2]); + if (components[maxtomin[0]] < components[maxtomin[1]]) { + qSwap(maxtomin[0], maxtomin[1]); + } + } + + uint64 max = qMax(1ULL, components[maxtomin[0]]), mid = qMax(1ULL, components[maxtomin[1]]), min = qMax(1ULL, components[maxtomin[2]]); + + QImage dog = App::sprite().toImage().copy(st::msgDogImg); + QImage::Format f = dog.format(); + if (f != QImage::Format_ARGB32 && f != QImage::Format_ARGB32_Premultiplied) { + dog = dog.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } + uchar *dogBits = dog.bits(); + if (max != min) { + float64 coef = float64(mid - min) / float64(max - min); + for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { + int dogmaxtomin[3] = { i, i + 1, i + 2 }; + if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { + qSwap(dogmaxtomin[0], dogmaxtomin[1]); + } + if (dogBits[dogmaxtomin[1]] < dogBits[dogmaxtomin[2]]) { + qSwap(dogmaxtomin[1], dogmaxtomin[2]); + if (dogBits[dogmaxtomin[0]] < dogBits[dogmaxtomin[1]]) { + qSwap(dogmaxtomin[0], dogmaxtomin[1]); + } + } + uchar result[3]; + result[maxtomin[0]] = dogBits[dogmaxtomin[0]]; + result[maxtomin[2]] = dogBits[dogmaxtomin[2]]; + result[maxtomin[1]] = uchar(qRound(result[maxtomin[2]] + (result[maxtomin[0]] - result[maxtomin[2]]) * coef)); + dogBits[i] = result[2]; + dogBits[i + 1] = result[1]; + dogBits[i + 2] = result[0]; + } + } else { + for (int i = 0, s = dog.width() * dog.height() * 4; i < s; i += 4) { + uchar b = dogBits[i], g = dogBits[i + 1], r = dogBits[i + 2]; + dogBits[i] = dogBits[i + 1] = dogBits[i + 2] = (r + r + b + g + g + g) / 6; + } + } + delete cChatDogImage(); + cSetChatDogImage(new QPixmap(QPixmap::fromImage(dog))); + + memcpy(componentsScroll, components, sizeof(components)); + memcpy(componentsPoint, components, sizeof(components)); + + if (max != min) { + if (min > qRound(0.77 * max)) { + uint64 newmin = qRound(0.77 * max); // min saturation 23% + uint64 newmid = max - ((max - mid) * (max - newmin)) / (max - min); + components[maxtomin[1]] = newmid; + components[maxtomin[2]] = newmin; + } + uint64 newmin = qRound(0.77 * max); // saturation 23% for scroll + uint64 newmid = max - ((max - mid) * (max - newmin)) / (max - min); + componentsScroll[maxtomin[1]] = newmid; + componentsScroll[maxtomin[2]] = newmin; + + uint64 pmax = 227; // 89% brightness + uint64 pmin = qRound(0.75 * pmax); // 41% saturation + uint64 pmid = pmax - ((max - mid) * (pmax - pmin)) / (max - min); + componentsPoint[maxtomin[0]] = pmax; + componentsPoint[maxtomin[1]] = pmid; + componentsPoint[maxtomin[2]] = pmin; + } else { + componentsPoint[0] = componentsPoint[1] = componentsPoint[2] = 227; // 89% brightness + } + + float64 luminance = 0.299 * componentsScroll[0] + 0.587 * componentsScroll[1] + 0.114 * componentsScroll[2]; + uint64 maxScroll = max; + if (luminance < 0.5 * 0xFF) { + maxScroll += qRound(0.2 * 0xFF); + } else { + maxScroll -= qRound(0.2 * 0xFF); + } + componentsScroll[maxtomin[2]] = qMin(uint64(float64(componentsScroll[maxtomin[2]]) * maxScroll / float64(componentsScroll[maxtomin[0]])), 0xFFULL); + componentsScroll[maxtomin[1]] = qMin(uint64(float64(componentsScroll[maxtomin[1]]) * maxScroll / float64(componentsScroll[maxtomin[0]])), 0xFFULL); + componentsScroll[maxtomin[0]] = qMin(maxScroll, 0xFFULL); + + if (max > qRound(0.2 * 0xFF)) { // brightness greater than 20% + max -= qRound(0.2 * 0xFF); + } else { + max = 0; + } + components[maxtomin[2]] = uint64(float64(components[maxtomin[2]]) * max / float64(components[maxtomin[0]])); + components[maxtomin[1]] = uint64(float64(components[maxtomin[1]]) * max / float64(components[maxtomin[0]])); + components[maxtomin[0]] = max; + + uchar r = uchar(components[0]), g = uchar(components[1]), b = uchar(components[2]); + _msgServiceBG = style::color(r, g, b, qRound(st::msgServiceBG->c.alphaF() * 0xFF)); + + uchar rScroll = uchar(componentsScroll[0]), gScroll = uchar(componentsScroll[1]), bScroll = uchar(componentsScroll[2]); + _historyScrollBarColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.barColor->c.alphaF() * 0xFF)); + _historyScrollBgColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.bgColor->c.alphaF() * 0xFF)); + _historyScrollBarOverColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.barOverColor->c.alphaF() * 0xFF)); + _historyScrollBgOverColor = style::color(rScroll, gScroll, bScroll, qRound(st::historyScroll.bgOverColor->c.alphaF() * 0xFF)); + + uchar rPoint = uchar(componentsPoint[0]), gPoint = uchar(componentsPoint[1]), bPoint = uchar(componentsPoint[2]); + _introPointHoverColor = style::color(rPoint, gPoint, bPoint); + if (App::main()) App::main()->updateScrollColors(); + } + + style::color msgServiceBG() { + return _msgServiceBG; + } + + style::color historyScrollBarColor() { + return _historyScrollBarColor; + } + + style::color historyScrollBgColor() { + return _historyScrollBgColor; + } + + style::color historyScrollBarOverColor() { + return _historyScrollBarOverColor; + } + + style::color historyScrollBgOverColor() { + return _historyScrollBgOverColor; + } + + style::color introPointHoverColor() { + return _introPointHoverColor; + } + + WallPapers gServerBackgrounds; + } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index d44076b0e2..c5dd461c08 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -81,6 +81,8 @@ namespace App { void feedMessageMedia(MsgId msgId, const MTPMessage &msg); int32 maxMsgId(); + ImagePtr image(const MTPPhotoSize &size); + PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0); PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0); @@ -191,4 +193,23 @@ namespace App { void openUserByName(const QString &username); void openLocalUrl(const QString &url); + void initBackground(int32 id = 0, const QImage &p = QImage(), bool nowrite = false); + + style::color msgServiceBG(); + style::color historyScrollBarColor(); + style::color historyScrollBgColor(); + style::color historyScrollBarOverColor(); + style::color historyScrollBgOverColor(); + style::color introPointHoverColor(); + + struct WallPaper { + WallPaper(int32 id, ImagePtr thumb, ImagePtr full) : id(id), thumb(thumb), full(full) { + } + int32 id; + ImagePtr thumb; + ImagePtr full; + }; + typedef QList WallPapers; + DeclareSetting(WallPapers, ServerBackgrounds); + }; diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 556a5dd695..7f66e763c1 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -833,6 +833,12 @@ Application::~Application() { delete window; + delete cChatBackground(); + cSetChatBackground(0); + + delete cChatDogImage(); + cSetChatDogImage(0); + style::stopManager(); Local::stop(); diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp new file mode 100644 index 0000000000..4e24b7cf62 --- /dev/null +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -0,0 +1,285 @@ +/* +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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "lang.h" + +#include "backgroundbox.h" +#include "mainwidget.h" +#include "window.h" +#include "settingswidget.h" + +BackgroundInner::BackgroundInner() : +_bgCount(0), _rows(0), _over(-1), _overDown(-1) { + if (App::cServerBackgrounds().isEmpty()) { + resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); + MTP::send(MTPaccount_GetWallPapers(), rpcDone(&BackgroundInner::gotWallpapers)); + } else { + updateWallpapers(); + } + setMouseTracking(true); +} + +void BackgroundInner::gotWallpapers(const MTPVector &result) { + App::WallPapers wallpapers; + + wallpapers.push_back(App::WallPaper(0, ImagePtr(st::msgBG), ImagePtr(st::msgBG))); + const QVector &v(result.c_vector().v); + for (int i = 0, l = v.size(); i < l; ++i) { + const MTPWallPaper w(v.at(i)); + switch (w.type()) { + case mtpc_wallPaper: { + const MTPDwallPaper &d(w.c_wallPaper()); + const QVector &sizes(d.vsizes.c_vector().v); + const MTPPhotoSize *thumb = 0, *full = 0; + int32 thumbLevel = -1, fullLevel = -1; + for (QVector::const_iterator j = sizes.cbegin(), e = sizes.cend(); j != e; ++j) { + char size = 0; + int32 w = 0, h = 0; + switch (j->type()) { + case mtpc_photoSize: { + const string &s(j->c_photoSize().vtype.c_string().v); + if (s.size()) size = s[0]; + w = j->c_photoSize().vw.v; + h = j->c_photoSize().vh.v; + } break; + + case mtpc_photoCachedSize: { + const string &s(j->c_photoCachedSize().vtype.c_string().v); + if (s.size()) size = s[0]; + w = j->c_photoCachedSize().vw.v; + h = j->c_photoCachedSize().vh.v; + } break; + } + if (!size || !w || !h) continue; + + int32 newThumbLevel = qAbs(st::backgroundSize.width() - w), newFullLevel = qAbs(2560 - w); + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &(*j); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &(*j); + } + } + if (thumb && full && full->type() != mtpc_photoSizeEmpty) { + wallpapers.push_back(App::WallPaper(d.vid.v, App::image(*thumb), App::image(*full))); + } + } break; + + case mtpc_wallPaperSolid: { + const MTPDwallPaperSolid &d(w.c_wallPaperSolid()); + } break; + } + } + + App::cSetServerBackgrounds(wallpapers); + updateWallpapers(); +} + +void BackgroundInner::updateWallpapers() { + _bgCount = App::cServerBackgrounds().size(); + _rows = _bgCount / BackgroundsInRow; + if (_bgCount % BackgroundsInRow) ++_rows; + + resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, _rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding); + for (int i = 0; i < BackgroundsInRow * 3; ++i) { + if (i >= _bgCount) break; + + App::cServerBackgrounds().at(i).thumb->load(); + } +} + +void BackgroundInner::paintEvent(QPaintEvent *e) { + QRect r(e->rect()); + QPainter p(this); + + if (_rows) { + for (int i = 0; i < _rows; ++i) { + if ((st::backgroundSize.height() + st::backgroundPadding) * (i + 1) <= r.top()) continue; + for (int j = 0; j < BackgroundsInRow; ++j) { + int index = i * BackgroundsInRow + j; + if (index >= _bgCount) break; + + const App::WallPaper &paper(App::cServerBackgrounds().at(index)); + paper.thumb->load(); + + int x = st::backgroundPadding + j * (st::backgroundSize.width() + st::backgroundPadding); + int y = st::backgroundPadding + i * (st::backgroundSize.height() + st::backgroundPadding); + + const QPixmap &pix(paper.thumb->pix(st::backgroundSize.width(), st::backgroundSize.height())); + p.drawPixmap(x, y, pix); + + if (paper.id == cChatBackgroundId()) { + p.drawPixmap(QPoint(x + st::backgroundSize.width() - st::overviewPhotoChecked.pxWidth(), y + st::backgroundSize.height() - st::overviewPhotoChecked.pxHeight()), App::sprite(), st::overviewPhotoChecked); + } + } + } + } else { + p.setFont(st::noContactsFont->f); + p.setPen(st::noContactsColor->p); + p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); + } +} + +void BackgroundInner::mouseMoveEvent(QMouseEvent *e) { + int x = e->pos().x(), y = e->pos().y(); + int row = int((y - st::backgroundPadding) / (st::backgroundSize.height() + st::backgroundPadding)); + if (y - row * (st::backgroundSize.height() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.height()) row = _rows + 1; + + int col = int((x - st::backgroundPadding) / (st::backgroundSize.width() + st::backgroundPadding)); + if (x - col * (st::backgroundSize.width() + st::backgroundPadding) > st::backgroundPadding + st::backgroundSize.width()) row = _rows + 1; + + int newOver = row * BackgroundsInRow + col; + if (newOver >= _bgCount) newOver = -1; + if (newOver != _over) { + _over = newOver; + setCursor((_over >= 0 || _overDown >= 0) ? style::cur_pointer : style::cur_default); + } +} + +void BackgroundInner::mousePressEvent(QMouseEvent *e) { + _overDown = _over; +} + +void BackgroundInner::mouseReleaseEvent(QMouseEvent *e) { + if (_overDown == _over && _over >= 0) { + emit backgroundChosen(_over); + } else if (_over < 0) { + setCursor(style::cur_default); + } +} + +BackgroundInner::~BackgroundInner() { +} + +void BackgroundInner::resizeEvent(QResizeEvent *e) { +} + +BackgroundBox::BackgroundBox() : _scroll(this, st::backgroundScroll), _inner(), +_close(this, lang(lng_contacts_done), st::contactsClose), +_hiding(false), a_opacity(0, 1) { + + _width = st::participantWidth; + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + + resize(_width, _height); + resizeEvent(0); + + _scroll.setWidget(&_inner); + _scroll.setFocusPolicy(Qt::NoFocus); + + connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int))); + + showAll(); + _cache = myGrab(this, rect()); + hideAll(); +} + +void BackgroundBox::hideAll() { + _scroll.hide(); + _close.hide(); +} + +void BackgroundBox::showAll() { + _scroll.show(); + _close.show(); + _close.raise(); +} + +void BackgroundBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Escape) { + onClose(); + } else { + e->ignore(); + } +} + +void BackgroundBox::parentResized() { + QSize s = parentWidget()->size(); + _height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom(); + if (_height > st::participantMaxHeight) _height = st::participantMaxHeight; + setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height); + update(); +} + +void BackgroundBox::paintEvent(QPaintEvent *e) { + QPainter p(this); + if (_cache.isNull()) { + if (!_hiding || a_opacity.current() > 0.01) { + // fill bg + p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b); + + // draw box title / text + p.setFont(st::boxFont->f); + p.setPen(st::boxGrayTitle->p); + p.drawText(QRect(st::addContactTitlePos.x(), st::addContactTitlePos.y(), _width - 2 * st::addContactTitlePos.x(), st::boxFont->height), lang(lng_backgrounds_header), style::al_top); + } + } else { + p.setOpacity(a_opacity.current()); + p.drawPixmap(0, 0, _cache); + } +} + +void BackgroundBox::resizeEvent(QResizeEvent *e) { + LayeredWidget::resizeEvent(e); + _inner.resize(_width, _inner.height()); + _scroll.resize(_width, _height - st::boxFont->height - st::newGroupNamePadding.top() - st::newGroupNamePadding.bottom() - _close.height()); + _scroll.move(0, st::boxFont->height + st::newGroupNamePadding.top() + st::newGroupNamePadding.bottom()); + _close.move(0, _height - _close.height()); +} + +void BackgroundBox::animStep(float64 dt) { + if (dt >= 1) { + a_opacity.finish(); + _cache = QPixmap(); + if (!_hiding) { + showAll(); + } + } else { + a_opacity.update(dt, anim::linear); + } + update(); +} + +void BackgroundBox::startHide() { + _hiding = true; + if (_cache.isNull()) { + _cache = myGrab(this, rect()); + hideAll(); + } + a_opacity.start(0); +} + +void BackgroundBox::onBackgroundChosen(int index) { + if (index >= 0 && index < App::cServerBackgrounds().size()) { + const App::WallPaper &paper(App::cServerBackgrounds().at(index)); + if (App::main()) App::main()->setChatBackground(paper); + if (App::settings()) App::settings()->needBackgroundUpdate(!paper.id); + } + emit closed(); +} + +void BackgroundBox::onClose() { + emit closed(); +} + +BackgroundBox::~BackgroundBox() { + +} diff --git a/Telegram/SourceFiles/boxes/backgroundbox.h b/Telegram/SourceFiles/boxes/backgroundbox.h new file mode 100644 index 0000000000..441678fe26 --- /dev/null +++ b/Telegram/SourceFiles/boxes/backgroundbox.h @@ -0,0 +1,84 @@ +/* +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. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "layerwidget.h" + +class BackgroundInner : public QWidget, public RPCSender { + Q_OBJECT + +public: + + BackgroundInner(); + + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void resizeEvent(QResizeEvent *e); + + ~BackgroundInner(); + +signals: + + void backgroundChosen(int index); + +private: + + void gotWallpapers(const MTPVector &result); + void updateWallpapers(); + + int32 _bgCount, _rows; + int32 _over, _overDown; + +}; + +class BackgroundBox : public LayeredWidget, public RPCSender { + Q_OBJECT + +public: + + BackgroundBox(); + void parentResized(); + void animStep(float64 dt); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void startHide(); + ~BackgroundBox(); + +public slots: + + void onBackgroundChosen(int index); + void onClose(); + +private: + + void hideAll(); + void showAll(); + + ScrollArea _scroll; + BackgroundInner _inner; + int32 _width, _height; + BottomButton _close; + bool _hiding; + + QPixmap _cache; + + anim::fvalue a_opacity; +}; diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 545bfd16c7..b67af9f336 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -116,6 +116,9 @@ enum { HiddenIsOnlineAfterMessage = 30, // user with hidden last seen stays online for such amount of seconds in the interface ServiceUserId = 777000, + + CacheBackgroundTimeout = 3000, // cache background scaled image after 3s + BackgroundsInRow = 3, }; inline bool isServiceUser(uint64 id) { diff --git a/Telegram/SourceFiles/gui/scrollarea.cpp b/Telegram/SourceFiles/gui/scrollarea.cpp index dec922e3db..57ef063e1d 100644 --- a/Telegram/SourceFiles/gui/scrollarea.cpp +++ b/Telegram/SourceFiles/gui/scrollarea.cpp @@ -105,8 +105,8 @@ void ScrollBar::updateBar() { void ScrollBar::onHideTimer() { _hideIn = -1; - a_bg.start(st::transparent->c); - a_bar.start(st::transparent->c); + a_bg.start(QColor(a_bg.current().red(), a_bg.current().green(), a_bg.current().blue(), 0)); + a_bar.start(QColor(a_bar.current().red(), a_bar.current().green(), a_bar.current().blue(), 0)); anim::start(this); } @@ -603,3 +603,12 @@ void ScrollArea::setWidget(QWidget *w) { void ScrollArea::rangeChanged(int oldMax, int newMax, bool vertical) { } + +void ScrollArea::updateColors(const style::color &bar, const style::color &bg, const style::color &barOver, const style::color &bgOver) { + _st.barColor = bar; + _st.bgColor = bg; + _st.barOverColor = barOver; + _st.bgOverColor = bgOver; + hor.update(); + vert.update(); +} diff --git a/Telegram/SourceFiles/gui/scrollarea.h b/Telegram/SourceFiles/gui/scrollarea.h index d3d619a81c..17057db893 100644 --- a/Telegram/SourceFiles/gui/scrollarea.h +++ b/Telegram/SourceFiles/gui/scrollarea.h @@ -128,6 +128,8 @@ public: void rangeChanged(int oldMax, int newMax, bool vertical); + void updateColors(const style::color &bar, const style::color &bg, const style::color &barOver, const style::color &bgOver); + public slots: void scrollToY(int toTop, int toBottom = -1); diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 55131a3685..fb14d77e8b 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -2661,7 +2661,8 @@ QString Text::original(uint16 selectedFrom, uint16 selectedTo, bool expandLinks) if (url.isEmpty() || !expandLinks || lnkFrom != rangeFrom || blockFrom != rangeTo) { result += r; } else { - if (r.size() > 3 && _text.midRef(lnkFrom, r.size() - 3) == url.midRef(0, r.size() - 3)) { // same link + QUrl u(url); + if (r.size() > 3 && _text.midRef(lnkFrom, r.size() - 3) == (u.isValid() ? u.toDisplayString() : url).midRef(0, r.size() - 3)) { // same link result += url; } else { result.append(r).append(qsl(" ( ")).append(url).append(qsl(" )")); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 29d7c5ec8e..9ac117437f 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -4649,9 +4649,9 @@ void HistoryServiceMsg::draw(QPainter &p, uint32 selection) const { } // QRect r(0, st::msgServiceMargin.top(), _history->width, height); QRect r(left, st::msgServiceMargin.top(), width, height); - p.setBrush(st::msgServiceBG->b); + p.setBrush(App::msgServiceBG()->b); p.setPen(Qt::NoPen); -// p.fillRect(r, st::msgServiceBG->b); +// p.fillRect(r, App::msgServiceBG()->b); p.drawRoundedRect(r, st::msgServiceRadius, st::msgServiceRadius); if (selection == FullItemSel) { p.setBrush(st::msgServiceSelectBG->b); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 6066a08ec1..33392b9648 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -94,7 +94,7 @@ void HistoryList::paintEvent(QPaintEvent *e) { if (hist->isEmpty()) { QPoint dogPos((width() - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9); - p.drawPixmap(dogPos, App::sprite(), st::msgDogImg); + p.drawPixmap(dogPos, *cChatDogImage()); } else { adjustCurrent(r.top()); HistoryBlock *block = (*hist)[currentBlock]; @@ -1567,7 +1567,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent) , confirmImageId(0) , confirmWithText(false) , titlePeerTextWidth(0) -, bg(st::msgBG) , hiderOffered(false) , _scrollDelta(0) , _typingRequest(0) @@ -3267,6 +3266,10 @@ void HistoryWidget::itemResized(HistoryItem *row) { updateListSize(0, false, false, row); } +void HistoryWidget::updateScrollColors() { + _scroll.updateColors(App::historyScrollBarColor(), App::historyScrollBgColor(), App::historyScrollBarOverColor(), App::historyScrollBgOverColor()); +} + void HistoryWidget::updateListSize(int32 addToY, bool initial, bool loadedDown, HistoryItem *resizedItem) { if (!hist || (!_histInited && !initial)) return; @@ -3629,17 +3632,36 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { p.drawPixmap(a_coord.current(), 0, _animCache); return; } - if (cCatsAndDogs()) { - int32 i_from = r.left() / bg.width(), i_to = (r.left() + r.width() - 1) / bg.width() + 1; - int32 j_from = r.top() / bg.height(), j_to = (r.top() + r.height() - 1) / bg.height() + 1; - for (int32 i = i_from; i < i_to; ++i) { - for (int32 j = j_from; j < j_to; ++j) { - p.drawPixmap(i * bg.width(), j * bg.height(), bg); - } + + bool hasTopBar = !App::main()->topBar()->isHidden(); + if (cTileBackground()) { + int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height(); + if (right > 0 && bottom > 0) { + QRect fill(left, top + (hasTopBar ? st::topBarHeight : 0), right, bottom + (hasTopBar ? st::topBarHeight : 0)); + + if (hasTopBar) p.translate(0, -st::topBarHeight); + p.fillRect(fill, QBrush(*cChatBackground())); + if (hasTopBar) p.translate(0, st::topBarHeight); } } else { - p.fillRect(r, st::historyBG->b); + QRect fill(0, 0, width(), App::main()->height()); + int fromy = hasTopBar ? (-st::topBarHeight) : 0, x = 0, y = 0; + QPixmap cached = App::main()->cachedBackground(fill, x, y); + if (cached.isNull()) { + bool smooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform); + p.setRenderHint(QPainter::SmoothPixmapTransform); + + QRect to, from; + App::main()->backgroundParams(fill, to, from); + to.moveTop(to.top() + fromy); + p.drawPixmap(to, *cChatBackground(), from); + + if (!smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false); + } else { + p.drawPixmap(x, fromy + y, cached); + } } + if (_list) { if (!_scroll.isHidden()) { if (!_field.isHidden()) { @@ -3647,15 +3669,14 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { } } else { QPoint dogPos((width() - st::msgDogImg.pxWidth()) / 2, ((height() - _field.height() - 2 * st::sendPadding - st::msgDogImg.pxHeight()) * 4) / 9); - p.drawPixmap(dogPos, App::sprite(), st::msgDogImg); + p.drawPixmap(dogPos, *cChatDogImage()); int32 pointsCount = 8, w = pointsCount * (st::introPointWidth + 2 * st::introPointDelta), h = st::introPointHeight; int32 pointsLeft = (width() - w) / 2 + st::introPointDelta - st::introPointLeft, pointsTop = dogPos.y() + (st::msgDogImg.pxHeight() * 6) / 5; int32 curPoint = histRequestsCount % pointsCount; - p.setOpacity(st::introPointHoverAlpha); - p.fillRect(pointsLeft + curPoint * (st::introPointWidth + 2 * st::introPointDelta), pointsTop, st::introPointHoverWidth, st::introPointHoverHeight, st::introPointHoverColor->b); + p.fillRect(pointsLeft + curPoint * (st::introPointWidth + 2 * st::introPointDelta), pointsTop, st::introPointHoverWidth, st::introPointHoverHeight, App::introPointHoverColor()->b); // points p.setOpacity(st::introPointAlpha); @@ -3670,7 +3691,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { int32 w = font->m.width(lang(lng_willbe_history)) + st::msgPadding.left() + st::msgPadding.right(), h = font->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + 2; QRect tr((width() - w) / 2, (height() - _field.height() - 2 * st::sendPadding - h) / 2, w, h); p.setPen(Qt::NoPen); - p.setBrush(st::msgServiceBG->b); + p.setBrush(App::msgServiceBG()->b); p.drawRoundedRect(tr, st::msgServiceRadius, st::msgServiceRadius); p.setPen(st::msgServiceColor->p); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index b878e5f6a0..c0215fe9d1 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -341,6 +341,8 @@ public: void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem); void itemResized(HistoryItem *item); + void updateScrollColors(); + ~HistoryWidget(); signals: @@ -471,8 +473,6 @@ private: QString titlePeerText; int32 titlePeerTextWidth; - QPixmap bg; - bool hiderOffered; QPixmap _animCache, _bgAnimCache, _animTopBarCache, _bgAnimTopBarCache; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index cf94ad174a..fcf5c7530d 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -442,6 +442,7 @@ namespace { lskStickers, // data: StorageKey location lskAudios, // data: StorageKey location lskRecentStickers, // no data + lskBackground, // no data }; typedef QMap DraftsMap; @@ -457,6 +458,9 @@ namespace { FileKey _locationsKey = 0; FileKey _recentStickersKey = 0; + + FileKey _backgroundKey = 0; + bool _backgroundWasRead = false; typedef QPair FileDesc; // file, size typedef QMap StorageMap; @@ -584,7 +588,7 @@ namespace { DraftsNotReadMap draftsNotReadMap; StorageMap imagesMap, stickersMap, audiosMap; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; - quint64 locationsKey = 0, recentStickersKey = 0; + quint64 locationsKey = 0, recentStickersKey = 0, backgroundKey = 0; while (!map.stream.atEnd()) { quint32 keyType; map.stream >> keyType; @@ -652,6 +656,9 @@ namespace { case lskRecentStickers: { map.stream >> recentStickersKey; } break; + case lskBackground: { + map.stream >> backgroundKey; + } break; default: LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType)); return Local::ReadMapFailed; @@ -675,6 +682,7 @@ namespace { _locationsKey = locationsKey; _recentStickersKey = recentStickersKey; + _backgroundKey = backgroundKey; _oldMapVersion = mapData.version; if (_oldMapVersion < AppVersion) { _mapChanged = true; @@ -732,6 +740,7 @@ namespace { if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_recentStickersKey) mapSize += sizeof(quint32) + sizeof(quint64); + if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64); EncryptedDescriptor mapData(mapSize); if (!_draftsMap.isEmpty()) { mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size()); @@ -769,6 +778,9 @@ namespace { if (_recentStickersKey) { mapData.stream << quint32(lskRecentStickers) << quint64(_recentStickersKey); } + if (_backgroundKey) { + mapData.stream << quint32(lskBackground) << quint64(_backgroundKey); + } map.writeEncrypted(mapData); map.finish(); @@ -1282,6 +1294,53 @@ namespace Local { cSetRecentStickers(recent); } + void writeBackground(int32 id, const QImage &img) { + if (!_working()) return; + + QByteArray png; + { + QBuffer buf(&png); + if (!img.save(&buf, "BMP")) return; + } + if (!_backgroundKey) { + _backgroundKey = genKey(); + _mapChanged = true; + _writeMap(WriteMapFast); + } + quint32 size = sizeof(qint32) + sizeof(quint32) + sizeof(quint32) + png.size(); + EncryptedDescriptor data(size); + data.stream << qint32(id) << png; + + FileWriteDescriptor file(_backgroundKey); + file.writeEncrypted(data); + } + + bool readBackground() { + if (_backgroundWasRead) return false; + _backgroundWasRead = true; + + FileReadDescriptor bg; + if (!readEncryptedFile(bg, toFilePart(_backgroundKey))) { + clearKey(_backgroundKey); + _backgroundKey = 0; + _writeMap(); + return false; + } + + QByteArray pngData; + qint32 id; + bg.stream >> id >> pngData; + + QImage img; + QBuffer buf(&pngData); + QImageReader reader(&buf); + if (reader.read(&img)) { + App::initBackground(id, img, true); + return true; + } + return false; + } + struct ClearManagerData { QThread *thread; StorageMap images, stickers, audios; diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 36a8bd4560..765a4477ef 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -121,4 +121,7 @@ namespace Local { void writeRecentStickers(); void readRecentStickers(); + void writeBackground(int32 id, const QImage &img); + bool readBackground(); + }; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8926836a08..661f7af4a8 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -351,9 +351,11 @@ MainWidget *TopBarWidget::main() { MainWidget::MainWidget(Window *window) : QWidget(window), _started(0), failedObjId(0), _dialogsWidth(st::dlgMinWidth), dialogs(this), history(this), profile(0), overview(0), _topBar(this), _forwardConfirm(0), hider(0), _mediaType(this), _mediaTypeMask(0), updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), _onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false), -_failDifferenceTimeout(1), _lastUpdateTime(0) { +_failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _background(0) { setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); + App::initBackground(); + connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled())); connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate())); @@ -374,6 +376,8 @@ _failDifferenceTimeout(1), _lastUpdateTime(0) { connect(audioVoice(), SIGNAL(stopped(AudioData*)), this, SLOT(audioPlayProgress(AudioData*))); } + connect(&_cacheBackgroundTimer, SIGNAL(timeout()), this, SLOT(onCacheBackground())); + dialogs.show(); if (cWideMode()) { history.show(); @@ -712,6 +716,16 @@ void MainWidget::onCancelResend() { } } +void MainWidget::onCacheBackground() { + const QPixmap &bg(*cChatBackground()); + QRect to, from; + backgroundParams(_willCacheFor, to, from); + _cachedX = to.x(); + _cachedY = to.y(); + _cachedBackground = QPixmap::fromImage(bg.toImage().copy(from).scaled(to.width(), to.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + _cachedFor = _willCacheFor; +} + void MainWidget::forwardSelectedItems() { if (overview) { overview->onForwardSelected(); @@ -1279,6 +1293,83 @@ bool MainWidget::isIdle() const { return _isIdle; } +void MainWidget::clearCachedBackground() { + _cachedBackground = QPixmap(); + _cacheBackgroundTimer.stop(); +} + +QPixmap MainWidget::cachedBackground(const QRect &forRect, int &x, int &y) { + if (!_cachedBackground.isNull() && forRect == _cachedFor) { + x = _cachedX; + y = _cachedY; + return _cachedBackground; + } + if (_willCacheFor != forRect || !_cacheBackgroundTimer.isActive()) { + _willCacheFor = forRect; + _cacheBackgroundTimer.start(CacheBackgroundTimeout); + } + return QPixmap(); +} + +void MainWidget::backgroundParams(const QRect &forRect, QRect &to, QRect &from) const { + const QSize &bg(cChatBackground()->size()); + if (uint64(bg.width()) * forRect.height() > uint64(bg.height()) * forRect.width()) { + float64 pxsize = forRect.height() / float64(bg.height()); + int takewidth = qCeil(forRect.width() / pxsize); + if (takewidth > bg.width()) { + takewidth = bg.width(); + } else if ((bg.width() % 2) != (takewidth % 2)) { + ++takewidth; + } + to = QRect(int((forRect.width() - takewidth * pxsize) / 2.), 0, qCeil(takewidth * pxsize), forRect.height()); + from = QRect((bg.width() - takewidth) / 2, 0, takewidth, bg.height()); + } else { + float64 pxsize = forRect.width() / float64(bg.width()); + int takeheight = qCeil(forRect.height() / pxsize); + if (takeheight > bg.height()) { + takeheight = bg.height(); + } else if ((bg.height() % 2) != (takeheight % 2)) { + ++takeheight; + } + to = QRect(0, int((forRect.height() - takeheight * pxsize) / 2.), forRect.width(), qCeil(takeheight * pxsize)); + from = QRect(0, (bg.height() - takeheight) / 2, bg.width(), takeheight); + } +} + +void MainWidget::updateScrollColors() { + history.updateScrollColors(); + if (overview) overview->updateScrollColors(); +} + +void MainWidget::setChatBackground(const App::WallPaper &wp) { + _background = new App::WallPaper(wp); + _background->full->load(); + checkChatBackground(); +} + +bool MainWidget::chatBackgroundLoading() { + return !!_background; +} + +void MainWidget::checkChatBackground() { + if (_background) { + if (_background->full->loaded()) { + if (_background->full->isNull()) { + App::initBackground(); + } else { + App::initBackground(_background->id, _background->full->pix().toImage()); + } + delete _background; + _background = 0; + QTimer::singleShot(0, this, SLOT(update())); + } + } +} + +ImagePtr MainWidget::newBackgroundThumb() { + return _background ? _background->thumb : ImagePtr(); +} + void MainWidget::setInnerFocus() { if (hider || !history.peer()) { if (hider && hider->wasOffered()) { @@ -1794,6 +1885,8 @@ bool MainWidget::animStep(float64 ms) { } void MainWidget::paintEvent(QPaintEvent *e) { + if (_background) checkChatBackground(); + QPainter p(this); if (animating()) { p.setOpacity(a_bgAlpha.current()); @@ -2438,6 +2531,8 @@ int32 MainWidget::dlgsWidth() const { MainWidget::~MainWidget() { if (App::main() == this) history.showPeer(0, 0, true); + delete _background; + delete hider; MTP::clearGlobalHandlers(); App::deinitMedia(false); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index aa241d6a88..7c0f29f537 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -315,6 +315,16 @@ public: bool serviceHistoryFail(const RPCError &error); bool isIdle() const; + + void clearCachedBackground(); + QPixmap cachedBackground(const QRect &forRect, int &x, int &y); + void backgroundParams(const QRect &forRect, QRect &to, QRect &from) const; + void updateScrollColors(); + + void setChatBackground(const App::WallPaper &wp); + bool chatBackgroundLoading(); + void checkChatBackground(); + ImagePtr newBackgroundThumb(); ~MainWidget(); @@ -368,6 +378,8 @@ public slots: void onResendAsDocument(); void onCancelResend(); + void onCacheBackground(); + private: void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result); @@ -453,4 +465,12 @@ private: SingleTimer _failDifferenceTimer; uint64 _lastUpdateTime; + + QPixmap _cachedBackground; + QRect _cachedFor, _willCacheFor; + int _cachedX, _cachedY; + SingleTimer _cacheBackgroundTimer; + + App::WallPaper *_background; + }; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 925076363b..44cd4664ed 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -576,7 +576,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { if (_hist->_overview[_type].isEmpty()) { QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9); - p.drawPixmap(dogPos, App::sprite(), st::msgDogImg); + p.drawPixmap(dogPos, *cChatDogImage()); return; } @@ -721,7 +721,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { width = strwidth; QRect r(left, st::msgServiceMargin.top(), width, height); - p.setBrush(st::msgServiceBG->b); + p.setBrush(App::msgServiceBG()->b); p.setPen(Qt::NoPen); p.drawRoundedRect(r, st::msgServiceRadius, st::msgServiceRadius); @@ -1533,10 +1533,9 @@ OverviewInner::~OverviewInner() { } OverviewWidget::OverviewWidget(QWidget *parent, const PeerData *peer, MediaOverviewType type) : QWidget(parent) -, _scroll(this, st::setScroll, false) +, _scroll(this, st::historyScroll, false) , _inner(this, &_scroll, peer, type) , _noDropResizeIndex(false) -, _bg(st::msgBG) , _showing(false) , _scrollSetAfterShow(0) , _scrollDelta(0) @@ -1591,19 +1590,36 @@ void OverviewWidget::paintEvent(QPaintEvent *e) { return; } + bool hasTopBar = !App::main()->topBar()->isHidden(); QRect r(e->rect()); if (type() == OverviewPhotos) { p.fillRect(r, st::white->b); - } else if (cCatsAndDogs()) { - int32 i_from = r.left() / _bg.width(), i_to = (r.left() + r.width() - 1) / _bg.width() + 1; - int32 j_from = r.top() / _bg.height(), j_to = (r.top() + r.height() - 1) / _bg.height() + 1; - for (int32 i = i_from; i < i_to; ++i) { - for (int32 j = j_from; j < j_to; ++j) { - p.drawPixmap(i * _bg.width(), j * _bg.height(), _bg); - } + } else if (cTileBackground()) { + int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height(); + if (right > 0 && bottom > 0) { + QRect fill(left, top + (hasTopBar ? st::topBarHeight : 0), right, bottom + (hasTopBar ? st::topBarHeight : 0)); + + if (hasTopBar) p.translate(0, -st::topBarHeight); + p.fillRect(fill, QBrush(*cChatBackground())); + if (hasTopBar) p.translate(0, st::topBarHeight); } } else { - p.fillRect(r, st::historyBG->b); + QRect fill(0, 0, width(), App::main()->height()); + int fromy = hasTopBar ? (-st::topBarHeight) : 0, x = 0, y = 0; + QPixmap cached = App::main()->cachedBackground(fill, x, y); + if (cached.isNull()) { + bool smooth = p.renderHints().testFlag(QPainter::SmoothPixmapTransform); + p.setRenderHint(QPainter::SmoothPixmapTransform); + + QRect to, from; + App::main()->backgroundParams(fill, to, from); + to.moveTop(to.top() + fromy); + p.drawPixmap(to, *cChatBackground(), from); + + if (!smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, false); + } else { + p.drawPixmap(x, fromy + y, cached); + } } } @@ -1772,6 +1788,10 @@ void OverviewWidget::fillSelectedItems(SelectedItemSet &sel, bool forDelete) { _inner.fillSelectedItems(sel, forDelete); } +void OverviewWidget::updateScrollColors() { + _scroll.updateColors(App::historyScrollBarColor(), App::historyScrollBgColor(), App::historyScrollBarOverColor(), App::historyScrollBgOverColor()); +} + OverviewWidget::~OverviewWidget() { onClearSelected(); updateTopBarSelection(); diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 22b7c75506..3ffb59b659 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -225,6 +225,8 @@ public: void fillSelectedItems(SelectedItemSet &sel, bool forDelete); + void updateScrollColors(); + ~OverviewWidget(); public slots: @@ -246,8 +248,6 @@ private: OverviewInner _inner; bool _noDropResizeIndex; - QPixmap _bg; - QString _header; bool _showing; diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index f97fe603f0..4abd65ab64 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -65,7 +65,12 @@ QString gDownloadPath; bool gNeedConfigResave = false; bool gCtrlEnter = false; -bool gCatsAndDogs = true; + +QPixmapPointer gChatBackground = 0; +int32 gChatBackgroundId = 0; +QPixmapPointer gChatDogImage = 0; +bool gTileBackground = true; +QColor gBackgroundColor = QColor(0, 0, 0); uint32 gConnectionsInSession = 1; QString gLoggedPhoneNumber; diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h index 43c6d65fab..9e13806b08 100644 --- a/Telegram/SourceFiles/settings.h +++ b/Telegram/SourceFiles/settings.h @@ -63,7 +63,14 @@ inline const QString &cDialogHelperPathFinal() { return cDialogHelperPath().isEmpty() ? cExeDir() : cDialogHelperPath(); } DeclareSetting(bool, CtrlEnter); -DeclareSetting(bool, CatsAndDogs); + +typedef QPixmap *QPixmapPointer; +DeclareSetting(QPixmapPointer, ChatBackground); +DeclareSetting(int32, ChatBackgroundId); +DeclareSetting(QPixmapPointer, ChatDogImage); +DeclareSetting(bool, TileBackground); +DeclareSetting(QColor, BackgroundColor); + DeclareSetting(bool, SoundNotify); DeclareSetting(bool, NeedConfigResave); DeclareSetting(bool, DesktopNotify); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index 8c046b78ab..50ab8277c1 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -24,6 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "application.h" #include "boxes/photocropbox.h" #include "boxes/connectionbox.h" +#include "boxes/backgroundbox.h" #include "boxes/addcontactbox.h" #include "boxes/emojibox.h" #include "boxes/confirmbox.h" @@ -158,7 +159,11 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent), _tempDirClearedWidth(st::linkFont->m.width(lang(lng_download_path_cleared))), _tempDirClearFailedWidth(st::linkFont->m.width(lang(lng_download_path_clear_failed))), - _catsAndDogs(this, lang(lng_settings_cats_and_dogs), cCatsAndDogs()), + // chat background + _backFromGallery(this, lang(lng_settings_bg_from_gallery)), + _backFromFile(this, lang(lng_settings_bg_from_file)), + _tileBackground(this, lang(lng_settings_bg_tile), cTileBackground()), + _needBackgroundUpdate(false), // local storage _localStorageClear(this, lang(lng_local_storage_clear)), @@ -248,7 +253,12 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent), connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); - connect(&_catsAndDogs, SIGNAL(changed()), this, SLOT(onCatsAndDogs())); + // chat background + if (!cChatBackground()) App::initBackground(); + updateChatBackground(); + connect(&_backFromGallery, SIGNAL(clicked()), this, SLOT(onBackFromGallery())); + connect(&_backFromFile, SIGNAL(clicked()), this, SLOT(onBackFromFile())); + connect(&_tileBackground, SIGNAL(changed()), this, SLOT(onTileBackground())); // local storage connect(&_localStorageClear, SIGNAL(clicked()), this, SLOT(onLocalStorageClear())); @@ -309,6 +319,18 @@ void SettingsInner::peerUpdated(PeerData *data) { } void SettingsInner::paintEvent(QPaintEvent *e) { + bool animateBackground = false; + if (App::main() && App::main()->chatBackgroundLoading()) { + App::main()->checkChatBackground(); + if (App::main()->chatBackgroundLoading()) { + animateBackground = true; + } else { + updateChatBackground(); + } + } else if (_needBackgroundUpdate) { + updateChatBackground(); + } + QPainter p(this); p.setClipRect(e->rect()); @@ -477,7 +499,44 @@ void SettingsInner::paintEvent(QPaintEvent *e) { } top += st::setSectionSkip; - top += _catsAndDogs.height(); + // chat background + p.setFont(st::setHeaderFont->f); + p.setPen(st::setHeaderColor->p); + p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_background)); + top += st::setHeaderSkip; + + if (animateBackground) { + const QPixmap &pix = App::main()->newBackgroundThumb()->pixBlurred(st::setBackgroundSize); + + p.drawPixmap(_left, top, st::setBackgroundSize, st::setBackgroundSize, pix, 0, (pix.height() - st::setBackgroundSize) / 2, st::setBackgroundSize, st::setBackgroundSize); + + uint64 dt = getms(); + int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta); + + int32 x = _left + (st::setBackgroundSize - st::mediaviewLoader.width()) / 2; + int32 y = top + (st::setBackgroundSize - st::mediaviewLoader.height()) / 2; + p.fillRect(x, y, st::mediaviewLoader.width(), st::mediaviewLoader.height(), st::photoLoaderBg->b); + + x += (st::mediaviewLoader.width() - cnt * st::mediaviewLoaderPoint.width() - (cnt - 1) * st::mediaviewLoaderSkip) / 2; + y += (st::mediaviewLoader.height() - st::mediaviewLoaderPoint.height()) / 2; + QColor c(st::white->c); + QBrush b(c); + for (int32 i = 0; i < cnt; ++i) { + t -= delta; + while (t < 0) t += period; + + float64 alpha = (t >= st::photoLoaderDuration1 + st::photoLoaderDuration2) ? 0 : ((t > st::photoLoaderDuration1 ? ((st::photoLoaderDuration1 + st::photoLoaderDuration2 - t) / st::photoLoaderDuration2) : (t / st::photoLoaderDuration1))); + c.setAlphaF(st::photoLoaderAlphaMin + alpha * (1 - st::photoLoaderAlphaMin)); + b.setColor(c); + p.fillRect(x + i * (st::mediaviewLoaderPoint.width() + st::mediaviewLoaderSkip), y, st::mediaviewLoaderPoint.width(), st::mediaviewLoaderPoint.height(), b); + } + QTimer::singleShot(AnimationTimerDelta, this, SLOT(updateBackgroundRect())); + } else { + p.drawPixmap(_left, top, _background); + } + top += st::setBackgroundSize; + top += st::setLittleSkip; + top += _tileBackground.height(); // local storage p.setFont(st::setHeaderFont->f); @@ -607,7 +666,15 @@ void SettingsInner::resizeEvent(QResizeEvent *e) { top += _downloadPathEdit.height(); } top += st::setSectionSkip; - _catsAndDogs.move(_left, top); top += _catsAndDogs.height(); + + // chat background + top += st::setHeaderSkip; + _backFromGallery.move(_left + st::setBackgroundSize + st::setLittleSkip, top); + _backFromFile.move(_left + st::setBackgroundSize + st::setLittleSkip, top + _backFromGallery.height() + st::setLittleSkip); + top += st::setBackgroundSize; + + top += st::setLittleSkip; + _tileBackground.move(_left, top); top += _tileBackground.height(); // local storage _localStorageClear.move(_left + st::setWidth - _localStorageClear.width(), top + st::setHeaderTop + st::setHeaderFont->ascent - st::linkFont->ascent); @@ -717,6 +784,10 @@ void SettingsInner::updateConnectionType() { } } +void SettingsInner::updateBackgroundRect() { + update(_left, _tileBackground.y() - st::setLittleSkip - st::setBackgroundSize, st::setBackgroundSize, st::setBackgroundSize); +} + void SettingsInner::gotFullSelf(const MTPUserFull &selfFull) { if (!self()) return; App::feedPhoto(selfFull.c_userFull().vprofile_photo); @@ -820,7 +891,6 @@ void SettingsInner::showAll() { } _enterSend.show(); _ctrlEnterSend.show(); - _catsAndDogs.show(); _dontAskDownloadPath.show(); if (cAskDownloadPath()) { _downloadPathEdit.hide(); @@ -839,12 +909,22 @@ void SettingsInner::showAll() { _viewEmojis.hide(); _enterSend.hide(); _ctrlEnterSend.hide(); - _catsAndDogs.hide(); _dontAskDownloadPath.hide(); _downloadPathEdit.hide(); _downloadPathClear.hide(); } + // chat background + if (self()) { + _backFromGallery.show(); + _backFromFile.show(); + _tileBackground.show(); + } else { + _backFromGallery.hide(); + _backFromFile.hide(); + _tileBackground.hide(); + } + // local storage if (self() && _storageClearState == TempDirExists) { _localStorageClear.show(); @@ -1195,9 +1275,67 @@ void SettingsInner::onCtrlEnterSend() { } } -void SettingsInner::onCatsAndDogs() { - cSetCatsAndDogs(_catsAndDogs.checked()); - App::writeUserConfig(); +void SettingsInner::onBackFromGallery() { + BackgroundBox *box = new BackgroundBox(); + App::wnd()->showLayer(box); +} + +void SettingsInner::onBackFromFile() { + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } + + if (img.isNull() || img.width() <= 0 || img.height() <= 0) return; + + if (img.width() > 4096 * img.height()) { + img = img.copy((img.width() - 4096 * img.height()) / 2, 0, 4096 * img.height(), img.height()); + } else if (img.height() > 4096 * img.width()) { + img = img.copy(0, (img.height() - 4096 * img.width()) / 2, img.width(), 4096 * img.width()); + } + + App::initBackground(-1, img); + _tileBackground.setChecked(false); + updateChatBackground(); +} + +void SettingsInner::updateChatBackground() { + QImage back(st::setBackgroundSize, st::setBackgroundSize, QImage::Format_ARGB32_Premultiplied); + { + QPainter p(&back); + const QPixmap &pix(*cChatBackground()); + int sx = (pix.width() > pix.height()) ? ((pix.width() - pix.height()) / 2) : 0; + int sy = (pix.height() > pix.width()) ? ((pix.height() - pix.width()) / 2) : 0; + int s = (pix.width() > pix.height()) ? pix.height() : pix.width(); + p.setRenderHint(QPainter::SmoothPixmapTransform); + p.drawPixmap(0, 0, st::setBackgroundSize, st::setBackgroundSize, pix, sx, sy, s, s); + } + _background = QPixmap::fromImage(back); + _needBackgroundUpdate = false; +} + +void SettingsInner::needBackgroundUpdate(bool tile) { + _needBackgroundUpdate = true; + _tileBackground.setChecked(tile); + updateChatBackground(); +} + +void SettingsInner::onTileBackground() { + if (cTileBackground() != _tileBackground.checked()) { + cSetTileBackground(_tileBackground.checked()); + App::writeUserConfig(); + } } void SettingsInner::onDontAskDownloadPath() { @@ -1470,6 +1608,14 @@ void SettingsWidget::usernameChanged() { _inner.usernameChanged(); } +void SettingsWidget::setInnerFocus() { + _inner.setFocus(); +} + +void SettingsWidget::needBackgroundUpdate(bool tile) { + _inner.needBackgroundUpdate(tile); +} + SettingsWidget::~SettingsWidget() { if (App::wnd()) App::wnd()->noSettings(this); } diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index 675d0a588e..11d99b77a5 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -78,11 +78,16 @@ public: void showAll(); + void updateChatBackground(); + void needBackgroundUpdate(bool tile); + public slots: void usernameChanged(); void updateConnectionType(); + void updateBackgroundRect(); + void peerUpdated(PeerData *data); void onUpdatePhoto(); @@ -125,7 +130,9 @@ public slots: void onTempDirCleared(int task); void onTempDirClearFailed(int task); - void onCatsAndDogs(); + void onBackFromGallery(); + void onBackFromFile(); + void onTileBackground(); void onLocalStorageClear(); @@ -222,7 +229,12 @@ private: TempDirCleared = 4, }; TempDirClearState _tempDirClearState; - FlatCheckbox _catsAndDogs; + + // chat background + QPixmap _background; + LinkButton _backFromGallery, _backFromFile; + FlatCheckbox _tileBackground; + bool _needBackgroundUpdate; // local storage LinkButton _localStorageClear; @@ -267,6 +279,9 @@ public: void rpcInvalidate(); void usernameChanged(); + void setInnerFocus(); + void needBackgroundUpdate(bool tile); + ~SettingsWidget(); public slots: diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index 989ce12dda..75821c3d99 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -256,6 +256,7 @@ enum DataBlockId { dbiCompressPastedImage = 30, dbiLang = 31, dbiLangFile = 32, + dbiTileBackground = 33, dbiEncryptedWithSalt = 333, dbiEncrypted = 444, diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 862e7efb83..2610907d9c 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -740,7 +740,11 @@ void Window::layerHidden() { } layerBG = 0; if (_mediaView && !_mediaView->isHidden()) _mediaView->hide(); - if (main) main->setInnerFocus(); + if (settings) { + settings->setInnerFocus(); + } else if (main) { + main->setInnerFocus(); + } } QRect Window::clientRect() const { diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index ea5438c7cb..b8a385a68a 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -170,6 +170,10 @@ true true + + true + true + true true @@ -394,6 +398,10 @@ true true + + true + true + true true @@ -627,6 +635,10 @@ true true + + true + true + true true @@ -834,6 +846,7 @@ + @@ -1164,6 +1177,20 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/languagebox.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing backgroundbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/backgroundbox.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing backgroundbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/backgroundbox.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing backgroundbox.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/backgroundbox.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui" + Moc%27ing animation.h... diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 6636f186f9..2a3ce62281 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -777,6 +777,18 @@ Generated Files\Release + + boxes + + + Generated Files\Deploy + + + Generated Files\Debug + + + Generated Files\Release + @@ -1037,6 +1049,9 @@ boxes + + boxes +