2014-05-30 08:53:19 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2014-12-01 10:47:38 +00:00
|
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2015-10-03 13:16:42 +00:00
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
|
2014-05-30 08:53:19 +00:00
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
2016-02-08 10:56:18 +00:00
|
|
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
2014-05-30 08:53:19 +00:00
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
2016-04-21 17:57:29 +00:00
|
|
|
#include "boxes/photocropbox.h"
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2016-04-21 17:57:29 +00:00
|
|
|
#include "lang.h"
|
2014-05-30 08:53:19 +00:00
|
|
|
#include "application.h"
|
|
|
|
#include "mainwidget.h"
|
|
|
|
#include "photocropbox.h"
|
|
|
|
#include "fileuploader.h"
|
|
|
|
|
2015-11-09 09:51:22 +00:00
|
|
|
PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer) : AbstractBox()
|
2015-10-11 08:37:24 +00:00
|
|
|
, _downState(0)
|
|
|
|
, _done(this, lang(lng_settings_save), st::defaultBoxButton)
|
|
|
|
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
|
|
|
, _img(img)
|
|
|
|
, _peerId(peer) {
|
2015-11-09 09:51:22 +00:00
|
|
|
init(img, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PhotoCropBox::PhotoCropBox(const QImage &img, PeerData *peer) : AbstractBox()
|
|
|
|
, _downState(0)
|
|
|
|
, _done(this, lang(lng_settings_save), st::defaultBoxButton)
|
|
|
|
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
|
|
|
, _img(img)
|
|
|
|
, _peerId(peer->id) {
|
|
|
|
init(img, peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::init(const QImage &img, PeerData *peer) {
|
|
|
|
if (peerIsChat(_peerId) || (peer && peer->isMegagroup())) {
|
2015-09-16 13:04:08 +00:00
|
|
|
_title = lang(lng_create_group_crop);
|
2015-11-02 22:33:57 +00:00
|
|
|
} else if (peerIsChannel(_peerId)) {
|
|
|
|
_title = lang(lng_create_channel_crop);
|
2015-09-16 13:04:08 +00:00
|
|
|
} else {
|
|
|
|
_title = lang(lng_settings_crop_profile);
|
|
|
|
}
|
|
|
|
|
2015-10-11 08:37:24 +00:00
|
|
|
connect(&_done, SIGNAL(clicked()), this, SLOT(onSend()));
|
|
|
|
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
2015-11-09 09:51:22 +00:00
|
|
|
if (peerToBareInt(_peerId)) {
|
2015-10-11 08:37:24 +00:00
|
|
|
connect(this, SIGNAL(ready(const QImage&)), this, SLOT(onReady(const QImage&)));
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2015-10-11 08:37:24 +00:00
|
|
|
int32 s = st::boxWideWidth - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
2016-07-13 17:34:57 +00:00
|
|
|
_thumb = App::pixmapFromImageInPlace(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
2014-05-30 08:53:19 +00:00
|
|
|
_thumbw = _thumb.width();
|
|
|
|
_thumbh = _thumb.height();
|
|
|
|
if (_thumbw > _thumbh) {
|
|
|
|
_cropw = _thumbh - 20;
|
|
|
|
} else {
|
|
|
|
_cropw = _thumbw - 20;
|
|
|
|
}
|
|
|
|
_cropx = (_thumbw - _cropw) / 2;
|
|
|
|
_cropy = (_thumbh - _cropw) / 2;
|
2015-04-02 10:33:19 +00:00
|
|
|
|
2015-10-03 10:09:09 +00:00
|
|
|
_thumbx = (st::boxWideWidth - _thumbw) / 2;
|
2015-10-11 08:37:24 +00:00
|
|
|
_thumby = st::boxPhotoPadding.top();
|
2014-05-30 08:53:19 +00:00
|
|
|
setMouseTracking(true);
|
|
|
|
|
2015-10-11 08:37:24 +00:00
|
|
|
resizeMaxHeight(st::boxWideWidth, st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxTextFont->height + st::cropSkip + st::boxButtonPadding.top() + _done.height() + st::boxButtonPadding.bottom());
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::mousePressEvent(QMouseEvent *e) {
|
2015-01-05 20:17:33 +00:00
|
|
|
if (e->button() != Qt::LeftButton) return LayeredWidget::mousePressEvent(e);
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
_downState = mouseState(e->pos());
|
|
|
|
_fromposx = e->pos().x();
|
|
|
|
_fromposy = e->pos().y();
|
|
|
|
_fromcropx = _cropx;
|
|
|
|
_fromcropy = _cropy;
|
|
|
|
_fromcropw = _cropw;
|
2015-01-05 20:17:33 +00:00
|
|
|
|
|
|
|
return LayeredWidget::mousePressEvent(e);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int32 PhotoCropBox::mouseState(QPoint p) {
|
|
|
|
p -= QPoint(_thumbx, _thumby);
|
|
|
|
int32 delta = st::cropPointSize, mdelta(-delta / 2);
|
|
|
|
if (QRect(_cropx + mdelta, _cropy + mdelta, delta, delta).contains(p)) {
|
|
|
|
return 1;
|
|
|
|
} else if (QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta).contains(p)) {
|
|
|
|
return 2;
|
|
|
|
} else if (QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) {
|
|
|
|
return 3;
|
|
|
|
} else if (QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta).contains(p)) {
|
|
|
|
return 4;
|
|
|
|
} else if (QRect(_cropx, _cropy, _cropw, _cropw).contains(p)) {
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::mouseReleaseEvent(QMouseEvent *e) {
|
|
|
|
if (_downState) {
|
|
|
|
_downState = 0;
|
|
|
|
mouseMoveEvent(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::mouseMoveEvent(QMouseEvent *e) {
|
|
|
|
if (_downState && !(e->buttons() & Qt::LeftButton)) {
|
|
|
|
mouseReleaseEvent(e);
|
|
|
|
}
|
|
|
|
if (_downState) {
|
|
|
|
if (_downState == 1) {
|
|
|
|
int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy;
|
|
|
|
if (_fromcropx + d < 0) {
|
|
|
|
d = -_fromcropx;
|
|
|
|
}
|
|
|
|
if (_fromcropy + d < 0) {
|
|
|
|
d = -_fromcropy;
|
|
|
|
}
|
|
|
|
if (_fromcropw - d < st::cropMinSize) {
|
|
|
|
d = _fromcropw - st::cropMinSize;
|
|
|
|
}
|
|
|
|
if (_cropx != _fromcropx + d || _cropy != _fromcropy + d || _cropw != _fromcropw - d) {
|
|
|
|
_cropx = _fromcropx + d;
|
|
|
|
_cropy = _fromcropy + d;
|
|
|
|
_cropw = _fromcropw - d;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
} else if (_downState == 2) {
|
|
|
|
int32 dx = _fromposx - e->pos().x(), dy = e->pos().y() - _fromposy, d = (dx < dy) ? dx : dy;
|
|
|
|
if (_fromcropx + _fromcropw - d > _thumbw) {
|
|
|
|
d = _fromcropx + _fromcropw - _thumbw;
|
|
|
|
}
|
|
|
|
if (_fromcropy + d < 0) {
|
|
|
|
d = -_fromcropy;
|
|
|
|
}
|
|
|
|
if (_fromcropw - d < st::cropMinSize) {
|
|
|
|
d = _fromcropw - st::cropMinSize;
|
|
|
|
}
|
|
|
|
if (_cropy != _fromcropy + d || _cropw != _fromcropw - d) {
|
|
|
|
_cropy = _fromcropy + d;
|
|
|
|
_cropw = _fromcropw - d;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
} else if (_downState == 3) {
|
|
|
|
int32 dx = _fromposx - e->pos().x(), dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy;
|
|
|
|
if (_fromcropx + _fromcropw - d > _thumbw) {
|
|
|
|
d = _fromcropx + _fromcropw - _thumbw;
|
|
|
|
}
|
|
|
|
if (_fromcropy + _fromcropw - d > _thumbh) {
|
|
|
|
d = _fromcropy + _fromcropw - _thumbh;
|
|
|
|
}
|
|
|
|
if (_fromcropw - d < st::cropMinSize) {
|
|
|
|
d = _fromcropw - st::cropMinSize;
|
|
|
|
}
|
|
|
|
if (_cropw != _fromcropw - d) {
|
|
|
|
_cropw = _fromcropw - d;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
} else if (_downState == 4) {
|
|
|
|
int32 dx = e->pos().x() - _fromposx, dy = _fromposy - e->pos().y(), d = (dx < dy) ? dx : dy;
|
|
|
|
if (_fromcropx + d < 0) {
|
|
|
|
d = -_fromcropx;
|
|
|
|
}
|
|
|
|
if (_fromcropy + _fromcropw - d > _thumbh) {
|
|
|
|
d = _fromcropy + _fromcropw - _thumbh;
|
|
|
|
}
|
|
|
|
if (_fromcropw - d < st::cropMinSize) {
|
|
|
|
d = _fromcropw - st::cropMinSize;
|
|
|
|
}
|
|
|
|
if (_cropx != _fromcropx + d || _cropw != _fromcropw - d) {
|
|
|
|
_cropx = _fromcropx + d;
|
|
|
|
_cropw = _fromcropw - d;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
} else if (_downState == 5) {
|
|
|
|
int32 dx = e->pos().x() - _fromposx, dy = e->pos().y() - _fromposy;
|
|
|
|
if (_fromcropx + dx < 0) {
|
|
|
|
dx = -_fromcropx;
|
|
|
|
} else if (_fromcropx + _fromcropw + dx > _thumbw) {
|
|
|
|
dx = _thumbw - _fromcropx - _fromcropw;
|
|
|
|
}
|
|
|
|
if (_fromcropy + dy < 0) {
|
|
|
|
dy = -_fromcropy;
|
|
|
|
} else if (_fromcropy + _fromcropw + dy > _thumbh) {
|
|
|
|
dy = _thumbh - _fromcropy - _fromcropw;
|
|
|
|
}
|
|
|
|
if (_cropx != _fromcropx + dx || _cropy != _fromcropy + dy) {
|
|
|
|
_cropx = _fromcropx + dx;
|
|
|
|
_cropy = _fromcropy + dy;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int32 cursorState = _downState ? _downState : mouseState(e->pos());
|
|
|
|
QCursor cur(style::cur_default);
|
|
|
|
if (cursorState == 1 || cursorState == 3) {
|
|
|
|
cur = style::cur_sizefdiag;
|
|
|
|
} else if (cursorState == 2 || cursorState == 4) {
|
|
|
|
cur = style::cur_sizebdiag;
|
|
|
|
} else if (cursorState == 5) {
|
|
|
|
cur = style::cur_sizeall;
|
|
|
|
}
|
|
|
|
setCursor(cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::keyPressEvent(QKeyEvent *e) {
|
|
|
|
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
|
|
|
onSend();
|
2015-04-02 10:33:19 +00:00
|
|
|
} else {
|
|
|
|
AbstractBox::keyPressEvent(e);
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::paintEvent(QPaintEvent *e) {
|
2015-10-11 08:37:24 +00:00
|
|
|
Painter p(this);
|
2015-04-02 10:33:19 +00:00
|
|
|
if (paint(p)) return;
|
2016-04-21 17:57:29 +00:00
|
|
|
|
2015-10-11 08:37:24 +00:00
|
|
|
p.setFont(st::boxTextFont);
|
|
|
|
p.setPen(st::boxPhotoTextFg);
|
|
|
|
p.drawText(QRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom(), width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), st::boxTextFont->height), _title, style::al_top);
|
2014-05-30 08:53:19 +00:00
|
|
|
|
|
|
|
p.translate(_thumbx, _thumby);
|
|
|
|
p.drawPixmap(0, 0, _thumb);
|
2015-04-02 10:33:19 +00:00
|
|
|
p.setOpacity(0.5);
|
2014-05-30 08:53:19 +00:00
|
|
|
if (_cropy > 0) {
|
|
|
|
p.fillRect(QRect(0, 0, _cropx + _cropw, _cropy), st::black->b);
|
|
|
|
}
|
|
|
|
if (_cropx + _cropw < _thumbw) {
|
|
|
|
p.fillRect(QRect(_cropx + _cropw, 0, _thumbw - _cropx - _cropw, _cropy + _cropw), st::black->b);
|
|
|
|
}
|
|
|
|
if (_cropy + _cropw < _thumbh) {
|
|
|
|
p.fillRect(QRect(_cropx, _cropy + _cropw, _thumbw - _cropx, _thumbh - _cropy - _cropw), st::black->b);
|
|
|
|
}
|
|
|
|
if (_cropx > 0) {
|
|
|
|
p.fillRect(QRect(0, _cropy, _cropx, _thumbh - _cropy), st::black->b);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 delta = st::cropPointSize, mdelta(-delta / 2);
|
|
|
|
p.fillRect(QRect(_cropx + mdelta, _cropy + mdelta, delta, delta), st::white->b);
|
|
|
|
p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + mdelta, delta, delta), st::white->b);
|
|
|
|
p.fillRect(QRect(_cropx + _cropw + mdelta, _cropy + _cropw + mdelta, delta, delta), st::white->b);
|
|
|
|
p.fillRect(QRect(_cropx + mdelta, _cropy + _cropw + mdelta, delta, delta), st::white->b);
|
|
|
|
}
|
|
|
|
|
2015-04-02 10:33:19 +00:00
|
|
|
void PhotoCropBox::resizeEvent(QResizeEvent *e) {
|
2015-10-11 08:37:24 +00:00
|
|
|
_done.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _done.height());
|
|
|
|
_cancel.moveToRight(st::boxButtonPadding.right() + _done.width() + st::boxButtonPadding.left(), _done.y());
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::onSend() {
|
|
|
|
QImage from(_img);
|
|
|
|
if (_img.width() < _thumb.width()) {
|
|
|
|
from = _thumb.toImage();
|
|
|
|
}
|
|
|
|
float64 x = float64(_cropx) / _thumbw, y = float64(_cropy) / _thumbh, w = float64(_cropw) / _thumbw;
|
|
|
|
int32 ix = int32(x * from.width()), iy = int32(y * from.height()), iw = int32(w * from.width());
|
|
|
|
if (ix < 0) {
|
|
|
|
ix = 0;
|
|
|
|
}
|
|
|
|
if (ix + iw > from.width()) {
|
|
|
|
iw = from.width() - ix;
|
|
|
|
}
|
|
|
|
if (iy < 0) {
|
|
|
|
iy = 0;
|
|
|
|
}
|
|
|
|
if (iy + iw > from.height()) {
|
|
|
|
iw = from.height() - iy;
|
|
|
|
}
|
|
|
|
int32 offset = ix * from.depth() / 8 + iy * from.bytesPerLine();
|
2015-11-04 22:12:13 +00:00
|
|
|
QImage cropped(from.constBits() + offset, iw, iw, from.bytesPerLine(), from.format()), tosend;
|
|
|
|
if (from.format() == QImage::Format_Indexed8) {
|
|
|
|
cropped.setColorCount(from.colorCount());
|
|
|
|
cropped.setColorTable(from.colorTable());
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
if (cropped.width() > 1280) {
|
|
|
|
tosend = cropped.scaled(1280, 1280, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
|
|
} else if (cropped.width() < 320) {
|
|
|
|
tosend = cropped.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
|
|
} else {
|
|
|
|
tosend = cropped.copy();
|
|
|
|
}
|
|
|
|
|
|
|
|
emit ready(tosend);
|
2015-09-16 13:04:08 +00:00
|
|
|
onClose();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhotoCropBox::onReady(const QImage &tosend) {
|
|
|
|
App::app()->uploadProfilePhoto(tosend, _peerId);
|
|
|
|
}
|
|
|
|
|
2015-04-02 10:33:19 +00:00
|
|
|
void PhotoCropBox::hideAll() {
|
2015-10-11 08:37:24 +00:00
|
|
|
_done.hide();
|
|
|
|
_cancel.hide();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 10:33:19 +00:00
|
|
|
void PhotoCropBox::showAll() {
|
2015-10-11 08:37:24 +00:00
|
|
|
_done.show();
|
|
|
|
_cancel.show();
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|