This commit is contained in:
John Preston 2015-02-03 18:06:19 +03:00
commit b8b4a81576
28 changed files with 1098 additions and 58 deletions

View File

@ -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:";

View File

@ -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;
}

View File

@ -78,6 +78,13 @@ namespace {
LastPhotosList lastPhotos;
typedef QHash<PhotoData*, LastPhotosList::iterator> 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;
}

View File

@ -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<WallPaper> WallPapers;
DeclareSetting(WallPapers, ServerBackgrounds);
};

View File

@ -833,6 +833,12 @@ Application::~Application() {
delete window;
delete cChatBackground();
cSetChatBackground(0);
delete cChatDogImage();
cSetChatDogImage(0);
style::stopManager();
Local::stop();

View File

@ -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<MTPWallPaper> &result) {
App::WallPapers wallpapers;
wallpapers.push_back(App::WallPaper(0, ImagePtr(st::msgBG), ImagePtr(st::msgBG)));
const QVector<MTPWallPaper> &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<MTPPhotoSize> &sizes(d.vsizes.c_vector().v);
const MTPPhotoSize *thumb = 0, *full = 0;
int32 thumbLevel = -1, fullLevel = -1;
for (QVector<MTPPhotoSize>::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() {
}

View File

@ -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<MTPWallPaper> &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;
};

View File

@ -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) {

View File

@ -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();
}

View File

@ -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);

View File

@ -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(" )"));

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -442,6 +442,7 @@ namespace {
lskStickers, // data: StorageKey location
lskAudios, // data: StorageKey location
lskRecentStickers, // no data
lskBackground, // no data
};
typedef QMap<PeerId, FileKey> DraftsMap;
@ -457,6 +458,9 @@ namespace {
FileKey _locationsKey = 0;
FileKey _recentStickersKey = 0;
FileKey _backgroundKey = 0;
bool _backgroundWasRead = false;
typedef QPair<FileKey, qint32> FileDesc; // file, size
typedef QMap<StorageKey, FileDesc> 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;

View File

@ -121,4 +121,7 @@ namespace Local {
void writeRecentStickers();
void readRecentStickers();
void writeBackground(int32 id, const QImage &img);
bool readBackground();
};

View File

@ -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);

View File

@ -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;
};

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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:

View File

@ -256,6 +256,7 @@ enum DataBlockId {
dbiCompressPastedImage = 30,
dbiLang = 31,
dbiLangFile = 32,
dbiTileBackground = 33,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,

View File

@ -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 {

View File

@ -170,6 +170,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_backgroundbox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_button.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -394,6 +398,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_backgroundbox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_button.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -627,6 +635,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_backgroundbox.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_button.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -834,6 +846,7 @@
<ClCompile Include="SourceFiles\boxes\aboutbox.cpp" />
<ClCompile Include="SourceFiles\boxes\addcontactbox.cpp" />
<ClCompile Include="SourceFiles\boxes\addparticipantbox.cpp" />
<ClCompile Include="SourceFiles\boxes\backgroundbox.cpp" />
<ClCompile Include="SourceFiles\boxes\confirmbox.cpp" />
<ClCompile Include="SourceFiles\boxes\connectionbox.cpp" />
<ClCompile Include="SourceFiles\boxes\contactsbox.cpp" />
@ -1164,6 +1177,20 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(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"</Command>
</CustomBuild>
<CustomBuild Include="SourceFiles\boxes\backgroundbox.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing backgroundbox.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(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"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing backgroundbox.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(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"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing backgroundbox.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(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"</Command>
</CustomBuild>
<ClInclude Include="SourceFiles\config.h" />
<CustomBuild Include="SourceFiles\gui\animation.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing animation.h...</Message>

View File

@ -777,6 +777,18 @@
<ClCompile Include="GeneratedFiles\Release\moc_languagebox.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\boxes\backgroundbox.cpp">
<Filter>boxes</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_backgroundbox.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_backgroundbox.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_backgroundbox.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -1037,6 +1049,9 @@
<CustomBuild Include="SourceFiles\boxes\languagebox.h">
<Filter>boxes</Filter>
</CustomBuild>
<CustomBuild Include="SourceFiles\boxes\backgroundbox.h">
<Filter>boxes</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="SourceFiles\art\icon256.ico" />