mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-09-05 00:46:08 +00:00
initial commit for 0.4.18 version of Telegram Desktop
This commit is contained in:
130
Telegram/SourceFiles/boxes/aboutbox.cpp
Normal file
130
Telegram/SourceFiles/boxes/aboutbox.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "aboutbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
AboutBox::AboutBox() : _hiding(false),
|
||||
_text(this, lang(lng_about_text), st::aboutLabel, st::aboutTextStyle),
|
||||
_done(this, lang(lng_about_done), st::aboutCloseButton),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
_width = st::aboutWidth;
|
||||
_height = st::aboutHeight;
|
||||
|
||||
_text.move(0, st::aboutTextTop);
|
||||
|
||||
_headerWidth = st::aboutHeaderFont->m.width(qsl("Telegram "));
|
||||
_subheaderWidth = st::aboutSubheaderFont->m.width(qsl("Desktop"));
|
||||
|
||||
_versionText = lang(lng_about_version).replace(qsl("{version}"), QString::fromWCharArray(AppVersionStr));
|
||||
_versionWidth = st::aboutVersionFont->m.width(_versionText);
|
||||
|
||||
_done.move(0, _height - _done.height());
|
||||
|
||||
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void AboutBox::hideAll() {
|
||||
_done.hide();
|
||||
_text.hide();
|
||||
}
|
||||
|
||||
void AboutBox::showAll() {
|
||||
_done.show();
|
||||
_text.show();
|
||||
}
|
||||
|
||||
void AboutBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
onClose();
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
void AboutBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void AboutBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (_cache.isNull()) {
|
||||
if (!_hiding || a_opacity.current() > 0.01) {
|
||||
// fill bg
|
||||
p.fillRect(0, 0, _width, _height, st::boxBG->b);
|
||||
|
||||
p.drawPixmap(QPoint((_width - st::aboutIcon.width()) / 2, st::aboutIconTop), App::sprite(), st::aboutIcon);
|
||||
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::aboutHeaderFont->f);
|
||||
p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2, st::aboutHeaderTop + st::aboutHeaderFont->ascent, qsl("Telegram"));
|
||||
|
||||
p.setFont(st::aboutSubheaderFont->f);
|
||||
p.drawText((_width - (_headerWidth + _subheaderWidth)) / 2 + _headerWidth, st::aboutHeaderTop + st::aboutSubheaderFont->ascent, qsl("Desktop"));
|
||||
|
||||
p.setFont(st::aboutVersionFont->f);
|
||||
p.setPen(st::aboutVersionColor->p);
|
||||
p.drawText((_width - _versionWidth) / 2, st::aboutVersionTop + st::aboutVersionFont->ascent, _versionText);
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void AboutBox::animStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(ms, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void AboutBox::onClose() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void AboutBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
AboutBox::~AboutBox() {
|
||||
}
|
56
Telegram/SourceFiles/boxes/aboutbox.h
Normal file
56
Telegram/SourceFiles/boxes/aboutbox.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class AboutBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AboutBox();
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~AboutBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onClose();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
int32 _width, _height;
|
||||
BottomButton _done;
|
||||
FlatLabel _text;
|
||||
int32 _headerWidth, _subheaderWidth;
|
||||
|
||||
QString _versionText;
|
||||
int32 _versionWidth;
|
||||
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
};
|
375
Telegram/SourceFiles/boxes/addcontactbox.cpp
Normal file
375
Telegram/SourceFiles/boxes/addcontactbox.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "application.h"
|
||||
#include "addcontactbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
AddContactBox::AddContactBox(QString fname, QString lname, QString phone) :
|
||||
_hiding(false), _peer(0), _addRequest(0), _contactId(0),
|
||||
_firstInput(this, st::inpAddContact, lang(lng_signup_firstname), fname),
|
||||
_lastInput(this, st::inpAddContact, lang(lng_signup_lastname), lname),
|
||||
_phoneInput(this, st::inpAddContact, lang(lng_contact_phone), phone.isEmpty() ? phone : App::formatPhone(phone)),
|
||||
_addButton(this, lang(lng_add_contact), st::btnSelectDone),
|
||||
_retryButton(this, lang(lng_try_other_contact), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
if (!phone.isEmpty()) {
|
||||
_phoneInput.setDisabled(true);
|
||||
}
|
||||
|
||||
initBox();
|
||||
}
|
||||
|
||||
AddContactBox::AddContactBox(PeerData *peer) :
|
||||
_hiding(false), _peer(peer), _addRequest(0), _contactId(0),
|
||||
_firstInput(this, st::inpAddContact, lang(peer->chat ? lng_dlg_new_group_name : lng_signup_firstname), peer->chat ? peer->name : peer->asUser()->firstName),
|
||||
_lastInput(this, st::inpAddContact, lang(lng_signup_lastname), peer->chat ? QString() : peer->asUser()->lastName),
|
||||
_phoneInput(this, st::inpAddContact, lang(lng_contact_phone)),
|
||||
_addButton(this, lang(lng_settings_save), st::btnSelectDone),
|
||||
_retryButton(this, lang(lng_try_other_contact), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
initBox();
|
||||
}
|
||||
|
||||
void AddContactBox::initBox() {
|
||||
_width = st::addContactWidth;
|
||||
if (_peer) {
|
||||
if (_peer->chat) {
|
||||
_boxTitle = lang(lng_edit_group_title);
|
||||
_height = st::addContactTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height();
|
||||
} else {
|
||||
_boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title);
|
||||
_height = st::addContactTitleHeight + st::addContactPadding.top() + 2 * _firstInput.height() + 1 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height();
|
||||
}
|
||||
} else {
|
||||
bool readyToAdd = !_phoneInput.text().isEmpty() && (!_firstInput.text().isEmpty() || !_lastInput.text().isEmpty());
|
||||
_boxTitle = lang(readyToAdd ? lng_confirm_contact_data : lng_enter_contact_data);
|
||||
_height = st::addContactTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height();
|
||||
}
|
||||
_firstInput.setGeometry(st::addContactPadding.left(), st::addContactTitleHeight + st::addContactPadding.top(), _width - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height());
|
||||
_lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _firstInput.width(), _firstInput.height());
|
||||
_phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height());
|
||||
|
||||
int32 buttonTop = (_peer ? (_peer->chat ? _firstInput : _lastInput) : _phoneInput).y() + _phoneInput.height() + st::addContactPadding.bottom();
|
||||
_cancelButton.move(0, buttonTop);
|
||||
_addButton.move(_width - _addButton.width(), buttonTop);
|
||||
_retryButton.move(_width - _retryButton.width(), buttonTop);
|
||||
_retryButton.hide();
|
||||
|
||||
connect(&_addButton, SIGNAL(clicked()), this, SLOT(onSend()));
|
||||
connect(&_retryButton, SIGNAL(clicked()), this, SLOT(onRetry()));
|
||||
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void AddContactBox::hideAll() {
|
||||
_firstInput.hide();
|
||||
_lastInput.hide();
|
||||
_phoneInput.hide();
|
||||
_addButton.hide();
|
||||
_retryButton.hide();
|
||||
_cancelButton.hide();
|
||||
}
|
||||
|
||||
void AddContactBox::showAll() {
|
||||
_firstInput.show();
|
||||
if (_peer && _peer->chat) {
|
||||
_lastInput.hide();
|
||||
} else {
|
||||
_lastInput.show();
|
||||
}
|
||||
if (_peer) {
|
||||
_phoneInput.hide();
|
||||
} else {
|
||||
_phoneInput.show();
|
||||
}
|
||||
_addButton.show();
|
||||
_cancelButton.show();
|
||||
}
|
||||
|
||||
void AddContactBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_firstInput.hasFocus()) {
|
||||
if (_peer && _peer->chat) {
|
||||
if (_firstInput.text().trimmed().isEmpty()) {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
} else {
|
||||
onSend();
|
||||
}
|
||||
} else {
|
||||
_lastInput.setFocus();
|
||||
}
|
||||
} else if (_lastInput.hasFocus()) {
|
||||
if (_peer) {
|
||||
if (_firstInput.text().trimmed().isEmpty()) {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
} else if (_lastInput.text().trimmed().isEmpty()) {
|
||||
_lastInput.setFocus();
|
||||
_lastInput.notaBene();
|
||||
} else {
|
||||
onSend();
|
||||
}
|
||||
} else if (_phoneInput.isEnabled()) {
|
||||
_phoneInput.setFocus();
|
||||
} else {
|
||||
onSend();
|
||||
}
|
||||
} else if (_phoneInput.hasFocus()) {
|
||||
if (_firstInput.text().trimmed().isEmpty()) {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
} else if (_lastInput.text().trimmed().isEmpty()) {
|
||||
_lastInput.setFocus();
|
||||
_lastInput.notaBene();
|
||||
} else {
|
||||
onSend();
|
||||
}
|
||||
}
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void AddContactBox::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);
|
||||
|
||||
// paint shadows
|
||||
if (_retryButton.isHidden()) {
|
||||
p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
}
|
||||
p.fillRect(0, size().height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
if (_retryButton.isHidden()) {
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, _boxTitle);
|
||||
} else {
|
||||
int32 h = size().height() - st::boxPadding.top() * 2 - _retryButton.height() - st::boxPadding.bottom();
|
||||
p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), h), lang(lng_contact_not_joined).replace(qsl("{name}"), _sentName), style::al_topleft);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
if (_firstInput.text().isEmpty() && _lastInput.text().isEmpty() || _phoneInput.isHidden() || !_phoneInput.isEnabled()) {
|
||||
_firstInput.setFocus();
|
||||
} else {
|
||||
_phoneInput.setFocus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void AddContactBox::onSend() {
|
||||
if (_addRequest) return;
|
||||
|
||||
QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(), phone = _phoneInput.text().trimmed();
|
||||
if (firstName.isEmpty() && lastName.isEmpty()) {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
return;
|
||||
} else if (!_peer && !App::isValidPhone(phone)) {
|
||||
_phoneInput.setFocus();
|
||||
_phoneInput.notaBene();
|
||||
return;
|
||||
}
|
||||
if (firstName.isEmpty()) {
|
||||
firstName = lastName;
|
||||
lastName = QString();
|
||||
}
|
||||
_sentName = firstName;
|
||||
if (_peer == App::self()) {
|
||||
_addRequest = MTP::send(MTPaccount_UpdateProfile(MTP_string(firstName), MTP_string(lastName)), rpcDone(&AddContactBox::onSaveSelfDone), rpcFail(&AddContactBox::onSaveSelfFail));
|
||||
} else if (_peer) {
|
||||
if (_peer->chat) {
|
||||
_addRequest = MTP::send(MTPmessages_EditChatTitle(MTP_int(int32(_peer->id & 0xFFFFFFFF)), MTP_string(firstName)), rpcDone(&AddContactBox::onSaveChatDone), rpcFail(&AddContactBox::onSaveFail));
|
||||
} else {
|
||||
_contactId = MTP::nonce<uint64>();
|
||||
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_peer->asUser()->phone), MTP_string(firstName), MTP_string(lastName)));
|
||||
_addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveFail));
|
||||
}
|
||||
} else {
|
||||
_contactId = MTP::nonce<uint64>();
|
||||
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(phone), MTP_string(firstName), MTP_string(lastName)));
|
||||
_addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onImportDone));
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::onSaveSelfDone(const MTPUser &user) {
|
||||
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, user)));
|
||||
emit closed();
|
||||
}
|
||||
|
||||
bool AddContactBox::onSaveSelfFail(const RPCError &error) {
|
||||
QString err(error.type());
|
||||
QString firstName = textOneLine(_firstInput.text()), lastName = textOneLine(_lastInput.text());
|
||||
if (err == "NAME_NOT_MODIFIED") {
|
||||
App::self()->setName(firstName, lastName, firstName + ' ' + lastName);
|
||||
emit closed();
|
||||
return true;
|
||||
} else if (err == "FIRSTNAME_INVALID") {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
return true;
|
||||
} else if (err == "LASTNAME_INVALID") {
|
||||
_lastInput.setFocus();
|
||||
_lastInput.notaBene();
|
||||
return true;
|
||||
}
|
||||
_firstInput.setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddContactBox::onSaveFail(const RPCError &error) {
|
||||
QString err(error.type());
|
||||
QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed();
|
||||
if (err == "CHAT_TITLE_NOT_MODIFIED") {
|
||||
_peer->updateName(firstName, QString());
|
||||
emit closed();
|
||||
return true;
|
||||
} else if (err == "NO_CHAT_TITLE") {
|
||||
_firstInput.setFocus();
|
||||
_firstInput.notaBene();
|
||||
return true;
|
||||
}
|
||||
_firstInput.setFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
|
||||
if (_hiding || !App::main()) return;
|
||||
|
||||
const MTPDcontacts_importedContacts &d(res.c_contacts_importedContacts());
|
||||
App::feedUsers(d.vusers);
|
||||
|
||||
const QVector<MTPImportedContact> &v(d.vimported.c_vector().v);
|
||||
int32 uid = 0;
|
||||
if (!v.isEmpty()) {
|
||||
const MTPDimportedContact &c(v.front().c_importedContact());
|
||||
if (c.vclient_id.v != _contactId) return;
|
||||
|
||||
uid = c.vuser_id.v;
|
||||
if (uid && !App::userLoaded(uid)) {
|
||||
uid = 0;
|
||||
}
|
||||
}
|
||||
if (uid) {
|
||||
App::main()->addNewContact(uid);
|
||||
App::main()->showPeer(App::peerFromUser(uid));
|
||||
App::wnd()->hideLayer();
|
||||
} else {
|
||||
_addButton.hide();
|
||||
_firstInput.hide();
|
||||
_lastInput.hide();
|
||||
_phoneInput.hide();
|
||||
_retryButton.show();
|
||||
int32 theight = st::addContactTitleFont->m.boundingRect(0, 0, _width - st::boxPadding.left() - st::boxPadding.right(), 1, Qt::TextWordWrap, lang(lng_contact_not_joined).replace(qsl("{name}"), _sentName)).height();
|
||||
int32 h = st::boxPadding.top() * 2 + theight + _retryButton.height() + st::boxPadding.bottom();
|
||||
resize(_width, h);
|
||||
_retryButton.move(_retryButton.x(), h - _retryButton.height());
|
||||
_cancelButton.move(_cancelButton.x(), h - _retryButton.height());
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void AddContactBox::onSaveChatDone(const MTPmessages_StatedMessage &result) {
|
||||
App::main()->sentFullDataReceived(0, result);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void AddContactBox::onSaveUserDone(const MTPcontacts_ImportedContacts &res) {
|
||||
const MTPDcontacts_importedContacts &d(res.c_contacts_importedContacts());
|
||||
App::feedUsers(d.vusers);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void AddContactBox::onCancel() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void AddContactBox::onRetry() {
|
||||
_addRequest = 0;
|
||||
_contactId = 0;
|
||||
_addButton.show();
|
||||
_cancelButton.move(_cancelButton.x(), _addButton.y());
|
||||
showAll();
|
||||
_firstInput.setText(QString());
|
||||
_firstInput.updatePlaceholder();
|
||||
_lastInput.setText(QString());
|
||||
_lastInput.updatePlaceholder();
|
||||
_phoneInput.setText(QString());
|
||||
_phoneInput.updatePlaceholder();
|
||||
_phoneInput.setDisabled(false);
|
||||
_retryButton.hide();
|
||||
_firstInput.setFocus();
|
||||
resize(_width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void AddContactBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
AddContactBox::~AddContactBox() {
|
||||
}
|
74
Telegram/SourceFiles/boxes/addcontactbox.h
Normal file
74
Telegram/SourceFiles/boxes/addcontactbox.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class AddContactBox : public LayeredWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AddContactBox(QString fname = QString(), QString lname = QString(), QString phone = QString());
|
||||
AddContactBox(PeerData *peer);
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~AddContactBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onSend();
|
||||
void onRetry();
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
void onImportDone(const MTPcontacts_ImportedContacts &res);
|
||||
|
||||
void onSaveSelfDone(const MTPUser &user);
|
||||
bool onSaveSelfFail(const RPCError &error);
|
||||
|
||||
void onSaveChatDone(const MTPmessages_StatedMessage &result);
|
||||
void onSaveUserDone(const MTPcontacts_ImportedContacts &res);
|
||||
bool onSaveFail(const RPCError &e);
|
||||
|
||||
void initBox();
|
||||
|
||||
PeerData *_peer;
|
||||
QString _boxTitle;
|
||||
|
||||
int32 _width, _height, _thumbw, _thumbh;
|
||||
FlatButton _addButton, _retryButton, _cancelButton;
|
||||
FlatInput _firstInput, _lastInput, _phoneInput;
|
||||
|
||||
uint64 _contactId;
|
||||
|
||||
QPixmap _cache;
|
||||
|
||||
mtpRequestId _addRequest;
|
||||
QString _sentName;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
bool _hiding;
|
||||
};
|
662
Telegram/SourceFiles/boxes/addparticipantbox.cpp
Normal file
662
Telegram/SourceFiles/boxes/addparticipantbox.cpp
Normal file
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "addparticipantbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
AddParticipantInner::AddParticipantInner(ChatData *chat) : _chat(chat), _selCount(0),
|
||||
_contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false) {
|
||||
|
||||
_filter = qsl("a");
|
||||
updateFilter();
|
||||
|
||||
for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) {
|
||||
r->attached = 0;
|
||||
}
|
||||
|
||||
connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *)));
|
||||
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *)));
|
||||
}
|
||||
|
||||
void AddParticipantInner::peerUpdated(PeerData *peer) {
|
||||
if (!peer || peer == _chat) {
|
||||
if (_chat->forbidden) {
|
||||
App::wnd()->hideLayer();
|
||||
} else if (!_chat->participants.isEmpty() || _chat->count <= 0) {
|
||||
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i ) {
|
||||
delete i.value();
|
||||
}
|
||||
_contactsData.clear();
|
||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
||||
row->attached = 0;
|
||||
}
|
||||
if (!_filter.isEmpty()) {
|
||||
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
||||
_filtered[j]->attached = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!peer->chat) {
|
||||
ContactsData::iterator i = _contactsData.find(peer->asUser());
|
||||
if (i != _contactsData.cend()) {
|
||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
||||
if (row->attached == i.value()) row->attached = 0;
|
||||
}
|
||||
if (!_filter.isEmpty()) {
|
||||
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
||||
if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0;
|
||||
}
|
||||
}
|
||||
delete i.value();
|
||||
_contactsData.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void AddParticipantInner::loadProfilePhotos(int32 yFrom) {
|
||||
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
for (
|
||||
DialogRow *preloadFrom = _contacts->list.current;
|
||||
preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo;
|
||||
preloadFrom = preloadFrom->next
|
||||
) {
|
||||
preloadFrom->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
} else if (!_filtered.isEmpty()) {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (yTo / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filtered[from]->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddParticipantInner::ContactData *AddParticipantInner::contactData(DialogRow *row) {
|
||||
ContactData *data = (ContactData*)row->attached;
|
||||
if (!data) {
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactsData::const_iterator i = _contactsData.constFind(user);
|
||||
if (i == _contactsData.cend()) {
|
||||
_contactsData.insert(user, data = new ContactData());
|
||||
data->inchat = _chat->participants.constFind(user) != _chat->participants.cend();
|
||||
data->check = false;
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
row->attached = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void AddParticipantInner::paintDialog(QPainter &p, DialogRow *row, bool sel) {
|
||||
int32 left = st::profileListPadding.width();
|
||||
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactData *data = contactData(row);
|
||||
|
||||
if (data->inchat || data->check || _selCount + _chat->count >= cMaxGroupCount()) {
|
||||
sel = false;
|
||||
}
|
||||
|
||||
if (sel || data->inchat || data->check) {
|
||||
p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, ((data->inchat || data->check) ? st::profileActiveBG : st::profileHoverBG)->b);
|
||||
}
|
||||
|
||||
p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize));
|
||||
|
||||
if (data->inchat || data->check) {
|
||||
p.setPen(st::white->p);
|
||||
} else {
|
||||
p.setPen(st::profileListNameColor->p);
|
||||
}
|
||||
data->name.drawElided(p, left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListNameTop, width() - st::participantDelta - st::profileListPadding.width() * 2 - st::profileListPhotoSize - st::profileListPadding.width() * 2);
|
||||
|
||||
if (sel || data->check) {
|
||||
p.drawPixmap(QPoint(width() - st::profileCheckRect.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.height()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect));
|
||||
}
|
||||
|
||||
p.setFont(st::profileSubFont->f);
|
||||
if (data->inchat || data->check) {
|
||||
p.setPen(st::white->p);
|
||||
} else {
|
||||
p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p);
|
||||
}
|
||||
p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online);
|
||||
}
|
||||
|
||||
void AddParticipantInner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
QPainter p(this);
|
||||
|
||||
_time = unixtime();
|
||||
p.fillRect(r, st::white->b);
|
||||
|
||||
int32 yFrom = r.top();
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
|
||||
DialogRow *drawFrom = _contacts->list.current;
|
||||
p.translate(0, drawFrom->pos * rh);
|
||||
while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) {
|
||||
paintDialog(p, drawFrom, (drawFrom == _sel));
|
||||
p.translate(0, rh);
|
||||
drawFrom = drawFrom->next;
|
||||
}
|
||||
} else {
|
||||
// ..
|
||||
}
|
||||
} else {
|
||||
if (_filtered.isEmpty()) {
|
||||
// ..
|
||||
} else {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (r.bottom() / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
p.translate(0, from * rh);
|
||||
for (; from < to; ++from) {
|
||||
paintDialog(p, _filtered[from], (_filteredSel == from));
|
||||
p.translate(0, rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantInner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void AddParticipantInner::leaveEvent(QEvent *e) {
|
||||
setMouseTracking(false);
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void AddParticipantInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void AddParticipantInner::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
chooseParticipant();
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantInner::chooseParticipant() {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_sel || contactData(_sel)->inchat) return;
|
||||
changeCheckState(_sel);
|
||||
} else {
|
||||
if (_filteredSel < 0 || _filteredSel >= _filtered.size() || contactData(_filtered[_filteredSel])->inchat) return;
|
||||
|
||||
DialogRow *row = _filtered[_filteredSel];
|
||||
changeCheckState(row);
|
||||
|
||||
PeerData *peer = row->history->peer;
|
||||
updateFilter();
|
||||
|
||||
for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) {
|
||||
if (_sel->history->peer == peer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_sel == _contacts->list.end) {
|
||||
_sel = 0;
|
||||
} else {
|
||||
emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
|
||||
}
|
||||
}
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void AddParticipantInner::changeCheckState(DialogRow *row) {
|
||||
if (contactData(row)->check) {
|
||||
contactData(row)->check = false;
|
||||
--_selCount;
|
||||
} else if (_selCount + _chat->count < cMaxGroupCount()) {
|
||||
contactData(row)->check = true;
|
||||
++_selCount;
|
||||
}
|
||||
}
|
||||
|
||||
ChatData *AddParticipantInner::chat() {
|
||||
return _chat;
|
||||
}
|
||||
|
||||
QVector<UserData*> AddParticipantInner::selected() {
|
||||
QVector<UserData*> result;
|
||||
result.reserve(_contactsData.size());
|
||||
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
|
||||
if (i.value()->check) {
|
||||
result.push_back(i.key());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddParticipantInner::updateSel() {
|
||||
if (!_mouseSel) return;
|
||||
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0;
|
||||
if (newSel != _sel) {
|
||||
_sel = newSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
} else {
|
||||
int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1;
|
||||
if (newFilteredSel != _filteredSel) {
|
||||
_filteredSel = newFilteredSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantInner::updateFilter(QString filter) {
|
||||
QStringList f;
|
||||
if (!filter.isEmpty()) {
|
||||
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
|
||||
int l = filterList.size();
|
||||
|
||||
f.reserve(l);
|
||||
for (int i = 0; i < l; ++i) {
|
||||
QString filterName = filterList[i].trimmed();
|
||||
if (filterName.isEmpty()) continue;
|
||||
f.push_back(filterName);
|
||||
}
|
||||
filter = f.join(' ');
|
||||
}
|
||||
if (_filter != filter) {
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
_filter = filter;
|
||||
if (_filter.isEmpty()) {
|
||||
resize(width(), _contacts->list.count * rh);
|
||||
if (_contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
while (_sel->next->next &&& contactData(_sel)->inchat) {
|
||||
_sel = _sel->next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi;
|
||||
|
||||
_filtered.clear();
|
||||
if (!f.isEmpty()) {
|
||||
DialogsList *dialogsToFilter = 0;
|
||||
if (_contacts->list.count) {
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0));
|
||||
if (i == _contacts->index.cend()) {
|
||||
dialogsToFilter = 0;
|
||||
break;
|
||||
}
|
||||
if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) {
|
||||
dialogsToFilter = i.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dialogsToFilter && dialogsToFilter->count) {
|
||||
_filtered.reserve(dialogsToFilter->count);
|
||||
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
|
||||
const PeerData::Names &names(i->history->peer->names);
|
||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
QString filterName(*fi);
|
||||
for (ni = nb; ni != ne; ++ni) {
|
||||
if ((*ni).indexOf(*fi) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ni == ne) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fi == fe) {
|
||||
i->attached = 0;
|
||||
_filtered.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_filteredSel = _filtered.isEmpty() ? -1 : 0;
|
||||
while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) {
|
||||
++_filteredSel;
|
||||
}
|
||||
|
||||
resize(width(), _filtered.size() * rh);
|
||||
}
|
||||
if (parentWidget()) parentWidget()->update();
|
||||
loadProfilePhotos(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
||||
if (!_filter.isEmpty()) {
|
||||
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) {
|
||||
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
||||
if (newRow) {
|
||||
*i = newRow;
|
||||
++i;
|
||||
} else {
|
||||
i = _filtered.erase(i);
|
||||
}
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = -1;
|
||||
}
|
||||
} else {
|
||||
if (_sel == oldRow) {
|
||||
_sel = newRow;
|
||||
}
|
||||
}
|
||||
_mouseSel = false;
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh;
|
||||
resize(width(), newh);
|
||||
}
|
||||
|
||||
AddParticipantInner::~AddParticipantInner() {
|
||||
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) {
|
||||
delete *i;
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantInner::selectSkip(int32 dir) {
|
||||
_mouseSel = false;
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_sel) {
|
||||
if (dir > 0) {
|
||||
while (dir && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
--dir;
|
||||
}
|
||||
while (contactData(_sel)->inchat && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
}
|
||||
if (contactData(_sel)->inchat) {
|
||||
while (contactData(_sel)->inchat && _sel->prev) {
|
||||
_sel = _sel->prev;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (dir && _sel->prev) {
|
||||
_sel = _sel->prev;
|
||||
++dir;
|
||||
}
|
||||
while (contactData(_sel)->inchat && _sel->prev) {
|
||||
_sel = _sel->prev;
|
||||
}
|
||||
if (contactData(_sel)->inchat) {
|
||||
while (contactData(_sel)->inchat && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (dir > 0 && _contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
while (contactData(_sel)->inchat && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
}
|
||||
}
|
||||
if (_sel) {
|
||||
if (contactData(_sel)->inchat) {
|
||||
_sel = 0;
|
||||
} else {
|
||||
emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dir > 0) {
|
||||
if (_filteredSel < 0 && dir > 1) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
_filteredSel += dir;
|
||||
while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) {
|
||||
++_filteredSel;
|
||||
}
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = _filtered.size() - 1;
|
||||
}
|
||||
while (_filteredSel > 0 && contactData(_filtered[_filteredSel])->inchat) {
|
||||
--_filteredSel;
|
||||
}
|
||||
} else if (_filteredSel > 0) {
|
||||
_filteredSel += dir;
|
||||
if (_filteredSel < 0) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
if (_filteredSel < _filtered.size() - 1) {
|
||||
while (_filteredSel > 0 && contactData(_filtered[_filteredSel])->inchat) {
|
||||
--_filteredSel;
|
||||
}
|
||||
}
|
||||
while (_filteredSel < _filtered.size() - 1 && contactData(_filtered[_filteredSel])->inchat) {
|
||||
++_filteredSel;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= 0) {
|
||||
if (contactData(_filtered[_filteredSel])->inchat) {
|
||||
_filteredSel = -1;
|
||||
} else {
|
||||
emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void AddParticipantInner::selectSkipPage(int32 h, int32 dir) {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
int32 points = h / rh;
|
||||
if (!points) return;
|
||||
selectSkip(points * dir);
|
||||
}
|
||||
|
||||
AddParticipantBox::AddParticipantBox(ChatData *chat) : _inner(chat), _hiding(false),
|
||||
_scroll(this, st::newGroupScroll),
|
||||
_filter(this, st::contactsFilter, lang(lng_participant_filter)),
|
||||
_invite(this, lang(lng_participant_invite), st::btnSelectDone),
|
||||
_cancel(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1), af_opacity(anim::linear) {
|
||||
|
||||
_width = st::participantWidth;
|
||||
_height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom();
|
||||
if (_height > st::participantMaxHeight) _height = st::participantMaxHeight;
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
_scroll.setWidget(&_inner);
|
||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
connect(&_invite, SIGNAL(clicked()), this, SLOT(onInvite()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(closed()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void AddParticipantBox::hideAll() {
|
||||
_filter.hide();
|
||||
_scroll.hide();
|
||||
_cancel.hide();
|
||||
_invite.hide();
|
||||
}
|
||||
|
||||
void AddParticipantBox::showAll() {
|
||||
_filter.show();
|
||||
_scroll.show();
|
||||
_cancel.show();
|
||||
_invite.show();
|
||||
}
|
||||
|
||||
void AddParticipantBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
onClose();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
_inner.chooseParticipant();
|
||||
} else if (e->key() == Qt::Key_Down) {
|
||||
_inner.selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantBox::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 AddParticipantBox::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);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, st::participantFilter.height, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_profile_add_participant));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void AddParticipantBox::resizeEvent(QResizeEvent *e) {
|
||||
LayeredWidget::resizeEvent(e);
|
||||
_filter.move(st::newGroupNamePadding.left(), st::contactsAdd.height + st::newGroupNamePadding.top());
|
||||
_inner.resize(_width, _inner.height());
|
||||
_scroll.resize(_width, _height - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancel.height());
|
||||
_scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom());
|
||||
_invite.move(width() - _invite.width(), _height - _invite.height());
|
||||
_cancel.move(0, _height - _cancel.height());
|
||||
}
|
||||
|
||||
void AddParticipantBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
_filter.setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, af_opacity);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void AddParticipantBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
void AddParticipantBox::onFilterUpdate() {
|
||||
_scroll.scrollToY(0);
|
||||
_inner.updateFilter(_filter.text());
|
||||
}
|
||||
|
||||
void AddParticipantBox::onClose() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void AddParticipantBox::onInvite() {
|
||||
QVector<UserData*> users(_inner.selected());
|
||||
if (users.isEmpty()) {
|
||||
_filter.setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
App::main()->addParticipants(_inner.chat(), users);
|
||||
}
|
||||
|
||||
void AddParticipantBox::onScroll() {
|
||||
_inner.loadProfilePhotos(_scroll.scrollTop());
|
||||
}
|
||||
|
||||
AddParticipantBox::~AddParticipantBox() {
|
||||
|
||||
}
|
130
Telegram/SourceFiles/boxes/addparticipantbox.h
Normal file
130
Telegram/SourceFiles/boxes/addparticipantbox.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class AddParticipantInner : public QWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AddParticipantInner(ChatData *chat);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
void paintDialog(QPainter &p, DialogRow *row, bool sel);
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
void chooseParticipant();
|
||||
void changeCheckState(DialogRow *row);
|
||||
|
||||
ChatData *chat();
|
||||
QVector<UserData*> selected();
|
||||
|
||||
~AddParticipantInner();
|
||||
|
||||
signals:
|
||||
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
|
||||
public slots:
|
||||
|
||||
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
|
||||
private:
|
||||
|
||||
ChatData *_chat;
|
||||
|
||||
int32 _time;
|
||||
|
||||
DialogsIndexed *_contacts;
|
||||
DialogRow *_sel;
|
||||
QString _filter;
|
||||
typedef QVector<DialogRow*> FilteredDialogs;
|
||||
FilteredDialogs _filtered;
|
||||
int32 _filteredSel;
|
||||
bool _mouseSel;
|
||||
|
||||
int32 _selCount;
|
||||
|
||||
typedef struct {
|
||||
Text name;
|
||||
QString online;
|
||||
bool inchat;
|
||||
bool check;
|
||||
} ContactData;
|
||||
typedef QMap<UserData*, ContactData*> ContactsData;
|
||||
ContactsData _contactsData;
|
||||
|
||||
ContactData *contactData(DialogRow *row);
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class AddParticipantBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AddParticipantBox(ChatData *chat);
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void startHide();
|
||||
~AddParticipantBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onFilterUpdate();
|
||||
void onClose();
|
||||
void onScroll();
|
||||
void onInvite();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
ScrollArea _scroll;
|
||||
AddParticipantInner _inner;
|
||||
int32 _width, _height;
|
||||
FlatInput _filter;
|
||||
FlatButton _invite, _cancel;
|
||||
|
||||
bool _hiding;
|
||||
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
anim::transition af_opacity;
|
||||
};
|
128
Telegram/SourceFiles/boxes/confirmbox.cpp
Normal file
128
Telegram/SourceFiles/boxes/confirmbox.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "confirmbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
ConfirmBox::ConfirmBox(QString text, QString doneText, QString cancelText) : _hiding(false), _text(100),
|
||||
_confirm(this, doneText.isEmpty() ? lang(lng_continue) : doneText, st::btnSelectDone),
|
||||
_cancel(this, cancelText.isEmpty() ? lang(lng_cancel) : cancelText, st::btnSelectCancel),
|
||||
a_opacity(0, 1), af_opacity(anim::linear) {
|
||||
|
||||
_text.setText(st::boxFont, text, _textPlainOptions);
|
||||
|
||||
_width = st::confirmWidth;
|
||||
_textWidth = _width - st::boxPadding.left() - st::boxPadding.right();
|
||||
_textHeight = _text.countHeight(_textWidth);
|
||||
_height = st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + _confirm.height();
|
||||
|
||||
_confirm.move(_width - _confirm.width(), st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
|
||||
_cancel.move(0, st::boxPadding.top() + _textHeight + st::boxPadding.bottom());
|
||||
|
||||
connect(&_confirm, SIGNAL(clicked()), this, SIGNAL(confirmed()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void ConfirmBox::hideAll() {
|
||||
_confirm.hide();
|
||||
_cancel.hide();
|
||||
}
|
||||
|
||||
void ConfirmBox::showAll() {
|
||||
_confirm.show();
|
||||
_cancel.show();
|
||||
}
|
||||
|
||||
void ConfirmBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
emit confirmed();
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void ConfirmBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (_cache.isNull()) {
|
||||
if (!_hiding || a_opacity.current() > 0.01) {
|
||||
// fill bg
|
||||
p.fillRect(0, 0, _width, _height, st::boxBG->b);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setFont(st::boxFont->f);
|
||||
p.setPen(st::black->p);
|
||||
_text.draw(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, (_text.maxWidth() < _width) ? style::al_center : style::al_left);
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmBox::animStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(ms, af_opacity);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void ConfirmBox::onCancel() {
|
||||
emit cancelled();
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void ConfirmBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
ConfirmBox::~ConfirmBox() {
|
||||
}
|
59
Telegram/SourceFiles/boxes/confirmbox.h
Normal file
59
Telegram/SourceFiles/boxes/confirmbox.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class ConfirmBox : public LayeredWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ConfirmBox(QString text, QString doneText = QString(), QString cancelText = QString());
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~ConfirmBox();
|
||||
|
||||
signals:
|
||||
|
||||
void confirmed();
|
||||
void cancelled();
|
||||
|
||||
public slots:
|
||||
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
int32 _width, _height;
|
||||
FlatButton _confirm, _cancel;
|
||||
Text _text;
|
||||
int32 _textWidth, _textHeight;
|
||||
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
anim::transition af_opacity;
|
||||
};
|
226
Telegram/SourceFiles/boxes/connectionbox.cpp
Normal file
226
Telegram/SourceFiles/boxes/connectionbox.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "connectionbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
ConnectionBox::ConnectionBox() : _hiding(false),
|
||||
_hostInput(this, st::inpConnectionHost, lang(lng_connection_host_ph), cConnectionProxy().host),
|
||||
_portInput(this, st::inpConnectionPort, lang(lng_connection_port_ph), QString::number(cConnectionProxy().port)),
|
||||
_userInput(this, st::inpConnectionUser, lang(lng_connection_user_ph), cConnectionProxy().user),
|
||||
_passwordInput(this, st::inpConnectionPassword, lang(lng_connection_password_ph), cConnectionProxy().password),
|
||||
_saveButton(this, lang(lng_connection_save), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
_autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (cConnectionType() == dbictAuto)),
|
||||
_httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (cConnectionType() == dbictHttpProxy)),
|
||||
_tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
_width = st::addContactWidth;
|
||||
|
||||
connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
connect(&_autoRadio, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
connect(&_httpProxyRadio, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
connect(&_tcpProxyRadio, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
|
||||
_passwordInput.setEchoMode(QLineEdit::Password);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void ConnectionBox::hideAll() {
|
||||
_autoRadio.hide();
|
||||
_httpProxyRadio.hide();
|
||||
_tcpProxyRadio.hide();
|
||||
|
||||
_hostInput.hide();
|
||||
_portInput.hide();
|
||||
_userInput.hide();
|
||||
_passwordInput.hide();
|
||||
|
||||
_saveButton.hide();
|
||||
_cancelButton.hide();
|
||||
}
|
||||
|
||||
void ConnectionBox::showAll() {
|
||||
_autoRadio.show();
|
||||
_httpProxyRadio.show();
|
||||
_tcpProxyRadio.show();
|
||||
|
||||
_autoRadio.move(st::boxPadding.left(), st::addContactTitleHeight + st::connectionSkip);
|
||||
_httpProxyRadio.move(st::boxPadding.left(), _autoRadio.y() + _autoRadio.height() + st::connectionSkip);
|
||||
|
||||
int32 inputy = 0;
|
||||
if (_httpProxyRadio.checked()) {
|
||||
inputy = _httpProxyRadio.y() + _httpProxyRadio.height() + st::boxPadding.top();
|
||||
_tcpProxyRadio.move(st::boxPadding.left(), inputy + st::boxPadding.top() + 2 * _hostInput.height() + st::connectionSkip);
|
||||
} else {
|
||||
_tcpProxyRadio.move(st::boxPadding.left(), _httpProxyRadio.y() + _httpProxyRadio.height() + st::connectionSkip);
|
||||
if (_tcpProxyRadio.checked()) {
|
||||
inputy = _tcpProxyRadio.y() + _tcpProxyRadio.height() + st::boxPadding.top();
|
||||
}
|
||||
}
|
||||
|
||||
if (inputy) {
|
||||
_hostInput.show();
|
||||
_portInput.show();
|
||||
_userInput.show();
|
||||
_passwordInput.show();
|
||||
_hostInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy);
|
||||
_portInput.move(_width - st::boxPadding.right() - _portInput.width(), inputy);
|
||||
_userInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, _hostInput.y() + _hostInput.height() + st::boxPadding.top());
|
||||
_passwordInput.move(_width - st::boxPadding.right() - _passwordInput.width(), _userInput.y());
|
||||
} else {
|
||||
_hostInput.hide();
|
||||
_portInput.hide();
|
||||
_userInput.hide();
|
||||
_passwordInput.hide();
|
||||
}
|
||||
|
||||
_saveButton.show();
|
||||
_cancelButton.show();
|
||||
|
||||
int32 buttony = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::connectionSkip;
|
||||
|
||||
_saveButton.move(_width - _saveButton.width(), buttony);
|
||||
_cancelButton.move(0, buttony);
|
||||
|
||||
_height = _saveButton.y() + _saveButton.height();
|
||||
resize(_width, _height);
|
||||
}
|
||||
|
||||
void ConnectionBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void ConnectionBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (_cache.isNull()) {
|
||||
if (!_hiding || a_opacity.current() > 0.01) {
|
||||
// fill bg
|
||||
p.fillRect(0, 0, _width, _height, st::boxBG->b);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_connection_header));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
if (!_hostInput.isHidden()) {
|
||||
_hostInput.setFocus();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void ConnectionBox::onChange() {
|
||||
showAll();
|
||||
if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) {
|
||||
_hostInput.setFocus();
|
||||
if (_httpProxyRadio.checked() && !_portInput.text().toInt()) {
|
||||
_portInput.setText(qsl("80"));
|
||||
_portInput.updatePlaceholder();
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void ConnectionBox::onSave() {
|
||||
if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) {
|
||||
ConnectionProxy p;
|
||||
p.host = _hostInput.text().trimmed();
|
||||
p.user = _userInput.text().trimmed();
|
||||
p.password = _passwordInput.text().trimmed();
|
||||
p.port = _portInput.text().toInt();
|
||||
if (p.host.isEmpty()) {
|
||||
_hostInput.setFocus();
|
||||
return;
|
||||
} else if (!p.port) {
|
||||
_portInput.setFocus();
|
||||
return;
|
||||
}
|
||||
if (_httpProxyRadio.checked()) {
|
||||
cSetConnectionType(dbictHttpProxy);
|
||||
} else {
|
||||
cSetConnectionType(dbictTcpProxy);
|
||||
}
|
||||
cSetConnectionProxy(p);
|
||||
} else {
|
||||
cSetConnectionType(dbictAuto);
|
||||
cSetConnectionProxy(ConnectionProxy());
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
}
|
||||
App::writeConfig();
|
||||
MTP::restart();
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void ConnectionBox::onCancel() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void ConnectionBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
ConnectionBox::~ConnectionBox() {
|
||||
}
|
58
Telegram/SourceFiles/boxes/connectionbox.h
Normal file
58
Telegram/SourceFiles/boxes/connectionbox.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
#include "gui/phoneinput.h"
|
||||
|
||||
class ConnectionBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ConnectionBox();
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~ConnectionBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onChange();
|
||||
void onSave();
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
FlatButton _saveButton, _cancelButton;
|
||||
FlatInput _hostInput;
|
||||
PortInput _portInput;
|
||||
FlatInput _userInput, _passwordInput;
|
||||
FlatRadiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio;
|
||||
|
||||
int32 _width, _height;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
bool _hiding;
|
||||
};
|
549
Telegram/SourceFiles/boxes/contactsbox.cpp
Normal file
549
Telegram/SourceFiles/boxes/contactsbox.cpp
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "addcontactbox.h"
|
||||
#include "contactsbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
ContactsInner::ContactsInner() : _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false) {
|
||||
|
||||
_filter = qsl("a");
|
||||
updateFilter();
|
||||
|
||||
for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) {
|
||||
r->attached = 0;
|
||||
}
|
||||
|
||||
connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *)));
|
||||
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *)));
|
||||
}
|
||||
|
||||
void ContactsInner::peerUpdated(PeerData *peer) {
|
||||
if (!peer->chat) {
|
||||
ContactsData::iterator i = _contactsData.find(peer->asUser());
|
||||
if (i != _contactsData.cend()) {
|
||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
||||
if (row->attached == i.value()) row->attached = 0;
|
||||
}
|
||||
if (!_filter.isEmpty()) {
|
||||
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
||||
if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0;
|
||||
}
|
||||
}
|
||||
delete i.value();
|
||||
_contactsData.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void ContactsInner::loadProfilePhotos(int32 yFrom) {
|
||||
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
for (
|
||||
DialogRow *preloadFrom = _contacts->list.current;
|
||||
preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo;
|
||||
preloadFrom = preloadFrom->next
|
||||
) {
|
||||
preloadFrom->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
} else if (!_filtered.isEmpty()) {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (yTo / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filtered[from]->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
|
||||
ContactData *data = (ContactData*)row->attached;
|
||||
if (!data) {
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactsData::const_iterator i = _contactsData.constFind(user);
|
||||
if (i == _contactsData.cend()) {
|
||||
_contactsData.insert(user, data = new ContactData());
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
row->attached = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void ContactsInner::paintDialog(QPainter &p, DialogRow *row, bool sel) {
|
||||
int32 left = st::profileListPadding.width();
|
||||
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactData *data = contactData(row);
|
||||
|
||||
if (sel) {
|
||||
p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, st::profileHoverBG->b);
|
||||
}
|
||||
|
||||
p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize));
|
||||
|
||||
p.setPen(st::profileListNameColor->p);
|
||||
data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - st::contactsImg.width());
|
||||
|
||||
if (sel) {
|
||||
p.drawPixmap(QPoint(width() - st::contactsImg.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.height()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg);
|
||||
}
|
||||
|
||||
p.setFont(st::profileSubFont->f);
|
||||
p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p);
|
||||
|
||||
p.drawText(left + st::profileListPhotoSize + st::participantDelta, st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online);
|
||||
}
|
||||
|
||||
void ContactsInner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
QPainter p(this);
|
||||
|
||||
_time = unixtime();
|
||||
p.fillRect(r, st::white->b);
|
||||
|
||||
int32 yFrom = r.top();
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
|
||||
DialogRow *drawFrom = _contacts->list.current;
|
||||
p.translate(0, drawFrom->pos * rh);
|
||||
while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) {
|
||||
paintDialog(p, drawFrom, (drawFrom == _sel));
|
||||
p.translate(0, rh);
|
||||
drawFrom = drawFrom->next;
|
||||
}
|
||||
} else {
|
||||
// ..
|
||||
}
|
||||
} else {
|
||||
if (_filtered.isEmpty()) {
|
||||
// ..
|
||||
} else {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (r.bottom() / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
p.translate(0, from * rh);
|
||||
for (; from < to; ++from) {
|
||||
paintDialog(p, _filtered[from], (_filteredSel == from));
|
||||
p.translate(0, rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsInner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ContactsInner::leaveEvent(QEvent *e) {
|
||||
setMouseTracking(false);
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void ContactsInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void ContactsInner::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
chooseParticipant();
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsInner::chooseParticipant() {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
|
||||
DialogRow *r = 0;
|
||||
if (_filter.isEmpty()) {
|
||||
r = _sel;
|
||||
} else {
|
||||
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return;
|
||||
r = _filtered[_filteredSel];
|
||||
}
|
||||
if (r) {
|
||||
App::wnd()->hideSettings(true);
|
||||
App::main()->showPeer(r->history->peer->id, false, true);
|
||||
App::wnd()->hideLayer();
|
||||
}
|
||||
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void ContactsInner::updateSel() {
|
||||
if (!_mouseSel) return;
|
||||
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
if (_filter.isEmpty()) {
|
||||
DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0;
|
||||
if (newSel != _sel) {
|
||||
_sel = newSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
} else {
|
||||
int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1;
|
||||
if (newFilteredSel != _filteredSel) {
|
||||
_filteredSel = newFilteredSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsInner::updateFilter(QString filter) {
|
||||
QStringList f;
|
||||
if (!filter.isEmpty()) {
|
||||
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
|
||||
int l = filterList.size();
|
||||
|
||||
f.reserve(l);
|
||||
for (int i = 0; i < l; ++i) {
|
||||
QString filterName = filterList[i].trimmed();
|
||||
if (filterName.isEmpty()) continue;
|
||||
f.push_back(filterName);
|
||||
}
|
||||
filter = f.join(' ');
|
||||
}
|
||||
if (_filter != filter) {
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
_filter = filter;
|
||||
if (_filter.isEmpty()) {
|
||||
resize(width(), _contacts->list.count * rh + st::contactsClose.height);
|
||||
if (_contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
}
|
||||
} else {
|
||||
QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi;
|
||||
|
||||
_filtered.clear();
|
||||
if (!f.isEmpty()) {
|
||||
DialogsList *dialogsToFilter = 0;
|
||||
if (_contacts->list.count) {
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0));
|
||||
if (i == _contacts->index.cend()) {
|
||||
dialogsToFilter = 0;
|
||||
break;
|
||||
}
|
||||
if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) {
|
||||
dialogsToFilter = i.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dialogsToFilter && dialogsToFilter->count) {
|
||||
_filtered.reserve(dialogsToFilter->count);
|
||||
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
|
||||
const PeerData::Names &names(i->history->peer->names);
|
||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
QString filterName(*fi);
|
||||
for (ni = nb; ni != ne; ++ni) {
|
||||
if ((*ni).indexOf(*fi) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ni == ne) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fi == fe) {
|
||||
i->attached = 0;
|
||||
_filtered.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_filteredSel = _filtered.isEmpty() ? -1 : 0;
|
||||
|
||||
resize(width(), _filtered.size() * rh + st::contactsClose.height);
|
||||
}
|
||||
if (parentWidget()) parentWidget()->update();
|
||||
loadProfilePhotos(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
||||
if (!_filter.isEmpty()) {
|
||||
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) {
|
||||
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
||||
if (newRow) {
|
||||
*i = newRow;
|
||||
++i;
|
||||
} else {
|
||||
i = _filtered.erase(i);
|
||||
}
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = -1;
|
||||
}
|
||||
} else {
|
||||
if (_sel == oldRow) {
|
||||
_sel = newRow;
|
||||
}
|
||||
}
|
||||
_mouseSel = false;
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh;
|
||||
resize(width(), newh);
|
||||
}
|
||||
|
||||
ContactsInner::~ContactsInner() {
|
||||
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) {
|
||||
delete *i;
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsInner::selectSkip(int32 dir) {
|
||||
_mouseSel = false;
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_sel) {
|
||||
if (dir > 0) {
|
||||
while (dir && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
--dir;
|
||||
}
|
||||
} else {
|
||||
while (dir && _sel->prev) {
|
||||
_sel = _sel->prev;
|
||||
++dir;
|
||||
}
|
||||
}
|
||||
} else if (dir > 0 && _contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
}
|
||||
if (_sel) {
|
||||
emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh + st::contactsClose.height);
|
||||
}
|
||||
} else {
|
||||
if (dir > 0) {
|
||||
if (_filteredSel < 0 && dir > 1) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
_filteredSel += dir;
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = _filtered.size() - 1;
|
||||
}
|
||||
} else if (_filteredSel > 0) {
|
||||
_filteredSel += dir;
|
||||
if (_filteredSel < 0) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= 0) {
|
||||
emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh + st::contactsClose.height);
|
||||
}
|
||||
}
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void ContactsInner::selectSkipPage(int32 h, int32 dir) {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
int32 points = h / rh;
|
||||
if (!points) return;
|
||||
selectSkip(points * dir);
|
||||
}
|
||||
|
||||
ContactsBox::ContactsBox() : _inner(), _hiding(false), _scroll(this, st::newGroupScroll),
|
||||
_addContact(this, lang(lng_add_contact_button), st::contactsAdd),
|
||||
_filter(this, st::contactsFilter, lang(lng_participant_filter)),
|
||||
_close(this, lang(lng_contacts_done), st::contactsClose),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
_width = st::participantWidth;
|
||||
_height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom();
|
||||
if (_height > st::participantMaxHeight) _height = st::participantMaxHeight;
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
_scroll.setWidget(&_inner);
|
||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAdd()));
|
||||
connect(&_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void ContactsBox::hideAll() {
|
||||
_addContact.hide();
|
||||
_filter.hide();
|
||||
_scroll.hide();
|
||||
_close.hide();
|
||||
}
|
||||
|
||||
void ContactsBox::showAll() {
|
||||
_addContact.show();
|
||||
_filter.show();
|
||||
_scroll.show();
|
||||
_close.show();
|
||||
}
|
||||
|
||||
void ContactsBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
onClose();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
if (_filter.hasFocus()) {
|
||||
_inner.chooseParticipant();
|
||||
}
|
||||
} else if (_filter.hasFocus()) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner.selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBox::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 ContactsBox::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);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, _addContact.height(), _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_contacts_header));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBox::resizeEvent(QResizeEvent *e) {
|
||||
LayeredWidget::resizeEvent(e);
|
||||
_addContact.move(_width - _addContact.width(), 0);
|
||||
_filter.move(st::newGroupNamePadding.left(), _addContact.height() + st::newGroupNamePadding.top());
|
||||
_inner.resize(_width, _inner.height());
|
||||
_scroll.resize(_width, _height - _addContact.height() - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom());
|
||||
_scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom());
|
||||
_close.move(0, _height - _close.height());
|
||||
}
|
||||
|
||||
void ContactsBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
_filter.setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void ContactsBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
void ContactsBox::onFilterUpdate() {
|
||||
_scroll.scrollToY(0);
|
||||
_inner.updateFilter(_filter.text());
|
||||
}
|
||||
|
||||
void ContactsBox::onAdd() {
|
||||
App::wnd()->replaceLayer(new AddContactBox());
|
||||
}
|
||||
|
||||
void ContactsBox::onClose() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void ContactsBox::onScroll() {
|
||||
_inner.loadProfilePhotos(_scroll.scrollTop());
|
||||
}
|
||||
|
||||
ContactsBox::~ContactsBox() {
|
||||
|
||||
}
|
123
Telegram/SourceFiles/boxes/contactsbox.h
Normal file
123
Telegram/SourceFiles/boxes/contactsbox.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class ContactsInner : public QWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ContactsInner();
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
void paintDialog(QPainter &p, DialogRow *row, bool sel);
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
|
||||
~ContactsInner();
|
||||
|
||||
signals:
|
||||
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
|
||||
public slots:
|
||||
|
||||
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
|
||||
void chooseParticipant();
|
||||
|
||||
private:
|
||||
|
||||
int32 _time;
|
||||
|
||||
DialogsIndexed *_contacts;
|
||||
DialogRow *_sel;
|
||||
QString _filter;
|
||||
typedef QVector<DialogRow*> FilteredDialogs;
|
||||
FilteredDialogs _filtered;
|
||||
int32 _filteredSel;
|
||||
bool _mouseSel;
|
||||
|
||||
typedef struct {
|
||||
Text name;
|
||||
QString online;
|
||||
} ContactData;
|
||||
typedef QMap<UserData*, ContactData*> ContactsData;
|
||||
ContactsData _contactsData;
|
||||
|
||||
ContactData *contactData(DialogRow *row);
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class ContactsBox : public LayeredWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ContactsBox();
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void startHide();
|
||||
~ContactsBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onFilterUpdate();
|
||||
void onClose();
|
||||
void onScroll();
|
||||
void onAdd();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
void created(const MTPmessages_StatedMessage &result);
|
||||
bool failed(const RPCError &e);
|
||||
|
||||
ScrollArea _scroll;
|
||||
ContactsInner _inner;
|
||||
FlatButton _addContact;
|
||||
int32 _width, _height;
|
||||
FlatInput _filter;
|
||||
BottomButton _close;
|
||||
bool _hiding;
|
||||
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
};
|
192
Telegram/SourceFiles/boxes/downloadpathbox.cpp
Normal file
192
Telegram/SourceFiles/boxes/downloadpathbox.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "downloadpathbox.h"
|
||||
#include "gui/filedialog.h"
|
||||
|
||||
DownloadPathBox::DownloadPathBox() : _hiding(false),
|
||||
_path(cDownloadPath()),
|
||||
_tempRadio(this, qsl("dir_type"), 0, lang(lng_download_path_temp_radio), _path.isEmpty()),
|
||||
_dirRadio(this, qsl("dir_type"), 1, lang(lng_download_path_dir_radio), !_path.isEmpty()),
|
||||
_dirInput(this, st::inpDownloadDir, QString(), QDir::toNativeSeparators(_path)),
|
||||
_saveButton(this, lang(lng_connection_save), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
_width = st::addContactWidth;
|
||||
|
||||
connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
connect(&_tempRadio, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
connect(&_dirRadio, SIGNAL(changed()), this, SLOT(onChange()));
|
||||
|
||||
connect(&_dirInput, SIGNAL(focused()), this, SLOT(onEditPath()));
|
||||
_dirInput.setCursorPosition(0);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void DownloadPathBox::hideAll() {
|
||||
_tempRadio.hide();
|
||||
_dirRadio.hide();
|
||||
|
||||
_dirInput.hide();
|
||||
|
||||
_saveButton.hide();
|
||||
_cancelButton.hide();
|
||||
}
|
||||
|
||||
void DownloadPathBox::showAll() {
|
||||
_tempRadio.show();
|
||||
_dirRadio.show();
|
||||
|
||||
if (_dirRadio.checked()) {
|
||||
_dirInput.show();
|
||||
} else {
|
||||
_dirInput.hide();
|
||||
}
|
||||
|
||||
_saveButton.show();
|
||||
_cancelButton.show();
|
||||
|
||||
_tempRadio.move(st::boxPadding.left(), st::addContactTitleHeight + st::downloadSkip);
|
||||
_dirRadio.move(st::boxPadding.left(), _tempRadio.y() + _tempRadio.height() + st::downloadSkip);
|
||||
int32 inputy = _dirRadio.y() + _dirRadio.height() + st::boxPadding.top();
|
||||
|
||||
_dirInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy);
|
||||
|
||||
int32 buttony = (_dirRadio.checked() ? (_dirInput.y() + _dirInput.height()) : (_dirRadio.y() + _dirRadio.height())) + st::downloadSkip;
|
||||
|
||||
_saveButton.move(_width - _saveButton.width(), buttony);
|
||||
_cancelButton.move(0, buttony);
|
||||
|
||||
_height = _saveButton.y() + _saveButton.height();
|
||||
resize(_width, _height);
|
||||
}
|
||||
|
||||
void DownloadPathBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadPathBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void DownloadPathBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (_cache.isNull()) {
|
||||
if (!_hiding || a_opacity.current() > 0.01) {
|
||||
// fill bg
|
||||
p.fillRect(0, 0, _width, _height, st::boxBG->b);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.setPen(st::black->p);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_download_path_header));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadPathBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void DownloadPathBox::onChange() {
|
||||
if (_dirRadio.checked()) {
|
||||
if (_path.isEmpty()) {
|
||||
_tempRadio.setChecked(true);
|
||||
onEditPath();
|
||||
if (!_path.isEmpty()) {
|
||||
_dirRadio.setChecked(true);
|
||||
}
|
||||
} else {
|
||||
_dirInput.setText(QDir::toNativeSeparators(_path));
|
||||
_dirInput.setCursorPosition(0);
|
||||
}
|
||||
}
|
||||
showAll();
|
||||
update();
|
||||
}
|
||||
|
||||
void DownloadPathBox::onEditPath() {
|
||||
_dirInput.clearFocus();
|
||||
|
||||
filedialogInit();
|
||||
QString path, lastPath = cDialogLastPath();
|
||||
if (!cDownloadPath().isEmpty()) cSetDialogLastPath(cDownloadPath());
|
||||
if (filedialogGetDir(path, lang(lng_download_path_choose))) {
|
||||
if (!path.isEmpty()) {
|
||||
_path = path + '/';
|
||||
_dirInput.setText(QDir::toNativeSeparators(_path));
|
||||
_dirInput.setCursorPosition(0);
|
||||
}
|
||||
}
|
||||
cSetDialogLastPath(lastPath);
|
||||
}
|
||||
|
||||
void DownloadPathBox::onSave() {
|
||||
cSetDownloadPath(_tempRadio.checked() ? QString() : _path);
|
||||
App::writeUserConfig();
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void DownloadPathBox::onCancel() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void DownloadPathBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
DownloadPathBox::~DownloadPathBox() {
|
||||
}
|
59
Telegram/SourceFiles/boxes/downloadpathbox.h
Normal file
59
Telegram/SourceFiles/boxes/downloadpathbox.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
#include "gui/phoneinput.h"
|
||||
|
||||
class DownloadPathBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
DownloadPathBox();
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~DownloadPathBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onChange();
|
||||
void onEditPath();
|
||||
void onSave();
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
QString _path;
|
||||
|
||||
FlatRadiobutton _tempRadio, _dirRadio;
|
||||
FlatInput _dirInput;
|
||||
FlatButton _saveButton, _cancelButton;
|
||||
|
||||
int32 _width, _height;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
bool _hiding;
|
||||
};
|
196
Telegram/SourceFiles/boxes/emojibox.cpp
Normal file
196
Telegram/SourceFiles/boxes/emojibox.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "emojibox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
namespace {
|
||||
// copied from genemoji.cpp
|
||||
struct EmojiReplace {
|
||||
uint32 code;
|
||||
const char *replace;
|
||||
};
|
||||
EmojiReplace replaces[] = {
|
||||
{0xD83DDE0A, ":-)"},
|
||||
{0xD83DDE03, ":-D"},
|
||||
{0xD83DDE09, ";-)"},
|
||||
{0xD83DDE06, "xD"},
|
||||
{0xD83DDE1C, ";-P"},
|
||||
{0xD83DDE0B, ":-p"},
|
||||
{0xD83DDE0D, "8-)"},
|
||||
{0xD83DDE0E, "B-)"},
|
||||
{0xD83DDE12, ":-("},
|
||||
{0xD83DDE0F, ":]"},
|
||||
{0xD83DDE14, "3("},
|
||||
{0xD83DDE22, ":'("},
|
||||
{0xD83DDE2D, ":_("},
|
||||
{0xD83DDE29, ":(("},
|
||||
{0xD83DDE28, ":o"},
|
||||
{0xD83DDE10, ":|"},
|
||||
{0xD83DDE0C, "3-)"},
|
||||
{0xD83DDE20, ">("},
|
||||
{0xD83DDE21, ">(("},
|
||||
{0xD83DDE07, "O:)"},
|
||||
{0xD83DDE30, ";o"},
|
||||
{0xD83DDE33, "8|"},
|
||||
{0xD83DDE32, "8o"},
|
||||
{0xD83DDE37, ":X"},
|
||||
{0xD83DDE1A, ":-*"},
|
||||
{0xD83DDE08, "}:)"},
|
||||
{0x2764, "<3"},
|
||||
{0xD83DDC4D, ":like:"},
|
||||
{0xD83DDC4E, ":dislike:"},
|
||||
{0x261D, ":up:"},
|
||||
{0x270C, ":v:"},
|
||||
{0xD83DDC4C, ":ok:"}
|
||||
};
|
||||
const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 8;
|
||||
}
|
||||
|
||||
EmojiBox::EmojiBox() : _hiding(false),
|
||||
_done(this, lang(lng_about_done), st::aboutCloseButton),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
fillBlocks();
|
||||
|
||||
_blockHeight = st::emojiReplaceInnerHeight;
|
||||
|
||||
_width = _blocks[0].size() * st::emojiReplaceWidth + (st::emojiReplaceWidth - st::emojiSize);
|
||||
|
||||
_height = st::boxPadding.top() + st::boxFont->height;
|
||||
_height += _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight);
|
||||
_height += _done.height();
|
||||
|
||||
_done.setWidth(_width);
|
||||
_header.setText(st::boxFont, lang(lng_settings_emoji_list));
|
||||
|
||||
_done.move(0, _height - _done.height());
|
||||
|
||||
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void EmojiBox::fillBlocks() {
|
||||
BlockRow currentRow;
|
||||
currentRow.reserve(replacesInRow);
|
||||
for (int32 i = 0; i < replacesCount; ++i) {
|
||||
Block block(getEmoji(replaces[i].code), QString::fromUtf8(replaces[i].replace));
|
||||
currentRow.push_back(block);
|
||||
if (currentRow.size() == replacesInRow) {
|
||||
_blocks.push_back(currentRow);
|
||||
currentRow.resize(0);
|
||||
}
|
||||
}
|
||||
if (currentRow.size()) {
|
||||
_blocks.push_back(currentRow);
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiBox::hideAll() {
|
||||
_done.hide();
|
||||
}
|
||||
|
||||
void EmojiBox::showAll() {
|
||||
_done.show();
|
||||
}
|
||||
|
||||
void EmojiBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
onClose();
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void EmojiBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
if (_cache.isNull()) {
|
||||
if (!_hiding || a_opacity.current() > 0.01) {
|
||||
// fill bg
|
||||
p.fillRect(0, 0, _width, _height, st::boxBG->b);
|
||||
|
||||
p.setFont(st::boxFont->f);
|
||||
p.setPen(st::boxGrayTitle->p);
|
||||
_header.draw(p, 0, st::boxPadding.top(), _width, Qt::AlignCenter);
|
||||
|
||||
p.setFont(st::emojiTextFont->f);
|
||||
p.setPen(st::black->p);
|
||||
int32 top = st::boxPadding.top() + st::boxFont->height + (st::emojiReplaceHeight - _blockHeight) / 2;
|
||||
for (Blocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) {
|
||||
int32 rowSize = i->size(), left = (_width - rowSize * st::emojiReplaceWidth) / 2;
|
||||
for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) {
|
||||
if (j->emoji) {
|
||||
QPoint pos(left + (st::emojiReplaceWidth - st::emojiSize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2);
|
||||
p.drawPixmap(pos, App::emojis(), QRect(j->emoji->x, j->emoji->y, st::emojiSize, st::emojiSize));
|
||||
}
|
||||
QRect trect(left, top + (st::emojiReplaceHeight + _blockHeight) / 2 - st::emojiTextFont->height, st::emojiReplaceWidth, st::emojiTextFont->height);
|
||||
p.drawText(trect, j->text, QTextOption(Qt::AlignHCenter | Qt::AlignTop));
|
||||
left += st::emojiReplaceWidth;
|
||||
}
|
||||
top += st::emojiReplaceHeight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiBox::animStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(ms, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void EmojiBox::onClose() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void EmojiBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
EmojiBox::~EmojiBox() {
|
||||
}
|
66
Telegram/SourceFiles/boxes/emojibox.h
Normal file
66
Telegram/SourceFiles/boxes/emojibox.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class EmojiBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
EmojiBox();
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~EmojiBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onClose();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
void fillBlocks();
|
||||
|
||||
int32 _width, _height;
|
||||
BottomButton _done;
|
||||
|
||||
Text _header;
|
||||
|
||||
int32 _blockHeight;
|
||||
struct Block {
|
||||
Block(const EmojiData *emoji = 0, const QString &text = QString()) : emoji(emoji), text(text) {
|
||||
}
|
||||
const EmojiData *emoji;
|
||||
QString text;
|
||||
};
|
||||
typedef QVector<Block> BlockRow;
|
||||
typedef QVector<BlockRow> Blocks;
|
||||
Blocks _blocks;
|
||||
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
};
|
764
Telegram/SourceFiles/boxes/newgroupbox.cpp
Normal file
764
Telegram/SourceFiles/boxes/newgroupbox.cpp
Normal file
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "newgroupbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
NewGroupInner::NewGroupInner() : _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), _mouseSel(false), _selCount(0) {
|
||||
|
||||
_filter = qsl("a");
|
||||
updateFilter();
|
||||
|
||||
for (DialogRow *r = _contacts->list.begin; r != _contacts->list.end; r = r->next) {
|
||||
r->attached = 0;
|
||||
}
|
||||
|
||||
connect(App::main(), SIGNAL(dialogRowReplaced(DialogRow *, DialogRow *)), this, SLOT(onDialogRowReplaced(DialogRow *, DialogRow *)));
|
||||
connect(App::main(), SIGNAL(peerUpdated(PeerData*)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerNameChanged(PeerData *, const PeerData::Names &, const PeerData::NameFirstChars &)), this, SLOT(peerUpdated(PeerData *)));
|
||||
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData *)), this, SLOT(peerUpdated(PeerData *)));
|
||||
}
|
||||
|
||||
void NewGroupInner::peerUpdated(PeerData *peer) {
|
||||
if (!peer->chat) {
|
||||
ContactsData::iterator i = _contactsData.find(peer->asUser());
|
||||
if (i != _contactsData.cend()) {
|
||||
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
|
||||
if (row->attached == i.value()) row->attached = 0;
|
||||
}
|
||||
if (!_filter.isEmpty()) {
|
||||
for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
|
||||
if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0;
|
||||
}
|
||||
}
|
||||
delete i.value();
|
||||
_contactsData.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void NewGroupInner::loadProfilePhotos(int32 yFrom) {
|
||||
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
|
||||
MTP::clearLoaderPriorities();
|
||||
|
||||
if (yTo < 0) return;
|
||||
if (yFrom < 0) yFrom = 0;
|
||||
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
for (
|
||||
DialogRow *preloadFrom = _contacts->list.current;
|
||||
preloadFrom != _contacts->list.end && preloadFrom->pos * rh < yTo;
|
||||
preloadFrom = preloadFrom->next
|
||||
) {
|
||||
preloadFrom->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
} else if (!_filtered.isEmpty()) {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (yTo / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filtered[from]->history->peer->photo->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewGroupInner::ContactData *NewGroupInner::contactData(DialogRow *row) {
|
||||
ContactData *data = (ContactData*)row->attached;
|
||||
if (!data) {
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactsData::const_iterator i = _contactsData.constFind(user);
|
||||
if (i == _contactsData.cend()) {
|
||||
_contactsData.insert(user, data = new ContactData());
|
||||
data->check = false;
|
||||
data->name.setText(st::profileListNameFont, user->name, _textNameOptions);
|
||||
data->online = App::onlineText(user->onlineTill, _time);
|
||||
} else {
|
||||
data = i.value();
|
||||
}
|
||||
row->attached = data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void NewGroupInner::paintDialog(QPainter &p, DialogRow *row, bool sel) {
|
||||
int32 left = st::profileListPadding.width();
|
||||
|
||||
UserData *user = row->history->peer->asUser();
|
||||
ContactData *data = contactData(row);
|
||||
|
||||
if (_selCount >= cMaxGroupCount() && !data->check) {
|
||||
sel = false;
|
||||
}
|
||||
|
||||
if (sel || data->check) {
|
||||
p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, (data->check ? st::profileActiveBG : st::profileHoverBG)->b);
|
||||
}
|
||||
|
||||
p.drawPixmap(left, st::profileListPadding.height(), user->photo->pix(st::profileListPhotoSize));
|
||||
|
||||
if (data->check) {
|
||||
p.setPen(st::white->p);
|
||||
} else {
|
||||
p.setPen(st::profileListNameColor->p);
|
||||
}
|
||||
data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - st::profileListPadding.width() - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - st::profileCheckRect.width());
|
||||
|
||||
if (sel || data->check) {
|
||||
p.drawPixmap(QPoint(width() - st::profileCheckRect.width() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.height()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect));
|
||||
}
|
||||
|
||||
p.setFont(st::profileSubFont->f);
|
||||
if (data->check) {
|
||||
p.setPen(st::white->p);
|
||||
} else {
|
||||
p.setPen((user->onlineTill >= _time ? st::profileOnlineColor : st::profileOfflineColor)->p);
|
||||
}
|
||||
p.drawText(left + st::profileListPhotoSize + st::participantDelta, st::profileListPadding.height() + st::profileListPhotoSize - 6, data->online);
|
||||
}
|
||||
|
||||
void NewGroupInner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
QPainter p(this);
|
||||
|
||||
_time = unixtime();
|
||||
p.fillRect(r, st::white->b);
|
||||
|
||||
int32 yFrom = r.top();
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_contacts->list.count) {
|
||||
_contacts->list.adjustCurrent(yFrom, rh);
|
||||
|
||||
DialogRow *drawFrom = _contacts->list.current;
|
||||
p.translate(0, drawFrom->pos * rh);
|
||||
while (drawFrom != _contacts->list.end && drawFrom->pos * rh < r.bottom()) {
|
||||
paintDialog(p, drawFrom, (drawFrom == _sel));
|
||||
p.translate(0, rh);
|
||||
drawFrom = drawFrom->next;
|
||||
}
|
||||
} else {
|
||||
// ..
|
||||
}
|
||||
} else {
|
||||
if (_filtered.isEmpty()) {
|
||||
// ..
|
||||
} else {
|
||||
int32 from = yFrom / rh;
|
||||
if (from < 0) from = 0;
|
||||
if (from < _filtered.size()) {
|
||||
int32 to = (r.bottom() / rh) + 1;
|
||||
if (to > _filtered.size()) to = _filtered.size();
|
||||
|
||||
p.translate(0, from * rh);
|
||||
for (; from < to; ++from) {
|
||||
paintDialog(p, _filtered[from], (_filteredSel == from));
|
||||
p.translate(0, rh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void NewGroupInner::leaveEvent(QEvent *e) {
|
||||
setMouseTracking(false);
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void NewGroupInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
}
|
||||
|
||||
void NewGroupInner::mousePressEvent(QMouseEvent *e) {
|
||||
_mouseSel = true;
|
||||
_lastMousePos = e->globalPos();
|
||||
updateSel();
|
||||
if (e->button() == Qt::LeftButton) {
|
||||
chooseParticipant();
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::changeCheckState(DialogRow *row) {
|
||||
if (contactData(row)->check) {
|
||||
contactData(row)->check = false;
|
||||
--_selCount;
|
||||
} else if (_selCount < cMaxGroupCount()) {
|
||||
contactData(row)->check = true;
|
||||
++_selCount;
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::chooseParticipant() {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
|
||||
if (_filter.isEmpty()) {
|
||||
if (!_sel) return;
|
||||
changeCheckState(_sel);
|
||||
} else {
|
||||
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return;
|
||||
|
||||
DialogRow *row = _filtered[_filteredSel];
|
||||
changeCheckState(row);
|
||||
|
||||
PeerData *peer = row->history->peer;
|
||||
updateFilter();
|
||||
|
||||
for (_sel = _contacts->list.begin; _sel != _contacts->list.end; _sel = _sel->next) {
|
||||
if (_sel->history->peer == peer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_sel == _contacts->list.end) {
|
||||
_sel = 0;
|
||||
} else {
|
||||
emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
|
||||
}
|
||||
}
|
||||
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void NewGroupInner::updateSel() {
|
||||
if (!_mouseSel) return;
|
||||
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
if (_filter.isEmpty()) {
|
||||
DialogRow *newSel = rect().contains(p) ? _contacts->list.rowAtY(p.y(), rh) : 0;
|
||||
if (newSel != _sel) {
|
||||
_sel = newSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
} else {
|
||||
int32 newFilteredSel = (p.y() >= 0 && rect().contains(p)) ? (p.y() / rh) : -1;
|
||||
if (newFilteredSel != _filteredSel) {
|
||||
_filteredSel = newFilteredSel;
|
||||
parentWidget()->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::updateFilter(QString filter) {
|
||||
QStringList f;
|
||||
if (!filter.isEmpty()) {
|
||||
QStringList filterList = filter.split(cWordSplit(), QString::SkipEmptyParts);
|
||||
int l = filterList.size();
|
||||
|
||||
f.reserve(l);
|
||||
for (int i = 0; i < l; ++i) {
|
||||
QString filterName = filterList[i].trimmed();
|
||||
if (filterName.isEmpty()) continue;
|
||||
f.push_back(filterName);
|
||||
}
|
||||
filter = f.join(' ');
|
||||
}
|
||||
if (_filter != filter) {
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
_filter = filter;
|
||||
if (_filter.isEmpty()) {
|
||||
resize(width(), _contacts->list.count * rh);
|
||||
if (_contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
}
|
||||
} else {
|
||||
QStringList::const_iterator fb = f.cbegin(), fe = f.cend(), fi;
|
||||
|
||||
_filtered.clear();
|
||||
if (!f.isEmpty()) {
|
||||
DialogsList *dialogsToFilter = 0;
|
||||
if (_contacts->list.count) {
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
DialogsIndexed::DialogsIndex::iterator i = _contacts->index.find(fi->at(0));
|
||||
if (i == _contacts->index.cend()) {
|
||||
dialogsToFilter = 0;
|
||||
break;
|
||||
}
|
||||
if (!dialogsToFilter || dialogsToFilter->count > i.value()->count) {
|
||||
dialogsToFilter = i.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dialogsToFilter && dialogsToFilter->count) {
|
||||
_filtered.reserve(dialogsToFilter->count);
|
||||
for (DialogRow *i = dialogsToFilter->begin, *e = dialogsToFilter->end; i != e; i = i->next) {
|
||||
const PeerData::Names &names(i->history->peer->names);
|
||||
PeerData::Names::const_iterator nb = names.cbegin(), ne = names.cend(), ni;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
QString filterName(*fi);
|
||||
for (ni = nb; ni != ne; ++ni) {
|
||||
if ((*ni).indexOf(*fi) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ni == ne) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fi == fe) {
|
||||
i->attached = 0;
|
||||
_filtered.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_filteredSel = _filtered.isEmpty() ? -1 : 0;
|
||||
|
||||
resize(width(), _filtered.size() * rh);
|
||||
}
|
||||
if (parentWidget()) parentWidget()->update();
|
||||
loadProfilePhotos(0);
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
|
||||
if (!_filter.isEmpty()) {
|
||||
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) {
|
||||
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
|
||||
if (newRow) {
|
||||
*i = newRow;
|
||||
++i;
|
||||
} else {
|
||||
i = _filtered.erase(i);
|
||||
}
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = -1;
|
||||
}
|
||||
} else {
|
||||
if (_sel == oldRow) {
|
||||
_sel = newRow;
|
||||
}
|
||||
}
|
||||
_mouseSel = false;
|
||||
int32 rh = (st::profileListPhotoSize + st::profileListPadding.height() * 2);
|
||||
int32 newh = (_filter.isEmpty() ? _contacts->list.count : _filtered.size()) * rh;
|
||||
resize(width(), newh);
|
||||
}
|
||||
|
||||
NewGroupInner::~NewGroupInner() {
|
||||
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) {
|
||||
delete *i;
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupInner::selectSkip(int32 dir) {
|
||||
_mouseSel = false;
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
|
||||
if (_filter.isEmpty()) {
|
||||
if (_sel) {
|
||||
if (dir > 0) {
|
||||
while (dir && _sel->next->next) {
|
||||
_sel = _sel->next;
|
||||
--dir;
|
||||
}
|
||||
} else {
|
||||
while (dir && _sel->prev) {
|
||||
_sel = _sel->prev;
|
||||
++dir;
|
||||
}
|
||||
}
|
||||
} else if (dir > 0 && _contacts->list.count) {
|
||||
_sel = _contacts->list.begin;
|
||||
}
|
||||
if (_sel) {
|
||||
emit mustScrollTo(_sel->pos * rh, (_sel->pos + 1) * rh);
|
||||
}
|
||||
} else {
|
||||
if (dir > 0) {
|
||||
if (_filteredSel < 0 && dir > 1) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
_filteredSel += dir;
|
||||
if (_filteredSel >= _filtered.size()) {
|
||||
_filteredSel = _filtered.size() - 1;
|
||||
}
|
||||
} else if (_filteredSel > 0) {
|
||||
_filteredSel += dir;
|
||||
if (_filteredSel < 0) {
|
||||
_filteredSel = 0;
|
||||
}
|
||||
}
|
||||
if (_filteredSel >= 0) {
|
||||
emit mustScrollTo(_filteredSel * rh, (_filteredSel + 1) * rh);
|
||||
}
|
||||
}
|
||||
parentWidget()->update();
|
||||
}
|
||||
|
||||
void NewGroupInner::selectSkipPage(int32 h, int32 dir) {
|
||||
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
|
||||
int32 points = h / rh;
|
||||
if (!points) return;
|
||||
selectSkip(points * dir);
|
||||
}
|
||||
|
||||
QVector<MTPInputUser> NewGroupInner::selectedInputs() {
|
||||
QVector<MTPInputUser> result;
|
||||
result.reserve(_contactsData.size());
|
||||
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
|
||||
if (i.value()->check) {
|
||||
result.push_back(i.key()->inputUser);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NewGroupBox::NewGroupBox() : _inner(), _hiding(false), _scroll(this, st::newGroupScroll),
|
||||
_filter(this, st::contactsFilter, lang(lng_participant_filter)),
|
||||
_next(this, lang(lng_create_group_next), st::btnSelectDone),
|
||||
_cancel(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
_width = st::participantWidth;
|
||||
_height = App::wnd()->height() - st::boxPadding.top() - st::boxPadding.bottom();
|
||||
if (_height > st::participantMaxHeight) _height = st::participantMaxHeight;
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
_scroll.setWidget(&_inner);
|
||||
_scroll.setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
connect(&_next, SIGNAL(clicked()), this, SLOT(onNext()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SIGNAL(closed()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate()));
|
||||
connect(&_filter, SIGNAL(cancelled()), this, SIGNAL(onClose()));
|
||||
connect(&_inner, SIGNAL(mustScrollTo(int,int)), &_scroll, SLOT(scrollToY(int,int)));
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void NewGroupBox::hideAll() {
|
||||
_filter.hide();
|
||||
_scroll.hide();
|
||||
_next.hide();
|
||||
_cancel.hide();
|
||||
}
|
||||
|
||||
void NewGroupBox::showAll() {
|
||||
_filter.show();
|
||||
_scroll.show();
|
||||
_next.show();
|
||||
_cancel.show();
|
||||
}
|
||||
|
||||
void NewGroupBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
onClose();
|
||||
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
||||
_inner.chooseParticipant();
|
||||
} else if (_filter.hasFocus()) {
|
||||
if (e->key() == Qt::Key_Down) {
|
||||
_inner.selectSkip(1);
|
||||
} else if (e->key() == Qt::Key_Up) {
|
||||
_inner.selectSkip(-1);
|
||||
} else if (e->key() == Qt::Key_PageDown) {
|
||||
_inner.selectSkipPage(_scroll.height(), 1);
|
||||
} else if (e->key() == Qt::Key_PageUp) {
|
||||
_inner.selectSkipPage(_scroll.height(), -1);
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
} else {
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupBox::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 NewGroupBox::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);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, st::participantFilter.height, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_create_new_group));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void NewGroupBox::resizeEvent(QResizeEvent *e) {
|
||||
LayeredWidget::resizeEvent(e);
|
||||
_filter.move(st::newGroupNamePadding.left(), st::contactsAdd.height + st::newGroupNamePadding.top());
|
||||
_inner.resize(_width, _inner.height());
|
||||
_scroll.resize(_width, _height - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancel.height());
|
||||
_scroll.move(0, _filter.y() + _filter.height() + st::newGroupNamePadding.bottom());
|
||||
_next.move(width() - _next.width(), _height - _next.height());
|
||||
_cancel.move(0, _height - _cancel.height());
|
||||
}
|
||||
|
||||
void NewGroupBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
_filter.setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void NewGroupBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
void NewGroupBox::onFilterUpdate() {
|
||||
_scroll.scrollToY(0);
|
||||
_inner.updateFilter(_filter.text());
|
||||
}
|
||||
|
||||
void NewGroupBox::onClose() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void NewGroupBox::onNext() {
|
||||
MTPVector<MTPInputUser> users(MTP_vector<MTPInputUser>(_inner.selectedInputs()));
|
||||
if (users.c_vector().v.isEmpty()) {
|
||||
_filter.setFocus();
|
||||
_filter.notaBene();
|
||||
return;
|
||||
}
|
||||
|
||||
App::wnd()->replaceLayer(new CreateGroupBox(users));
|
||||
}
|
||||
|
||||
void NewGroupBox::onScroll() {
|
||||
_inner.loadProfilePhotos(_scroll.scrollTop());
|
||||
}
|
||||
|
||||
NewGroupBox::~NewGroupBox() {
|
||||
}
|
||||
|
||||
CreateGroupBox::CreateGroupBox(const MTPVector<MTPInputUser> &users) : _users(users),
|
||||
_hiding(false), _createRequestId(0),
|
||||
_name(this, st::newGroupName, lang(lng_dlg_new_group_name)),
|
||||
_create(this, lang(lng_dlg_create_group), st::btnSelectDone),
|
||||
_cancel(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
_width = st::addContactWidth;
|
||||
|
||||
_height = st::addContactTitleHeight + st::addContactPadding.top() + _name.height() + st::addContactPadding.bottom() + _create.height();
|
||||
|
||||
_name.setGeometry(st::addContactPadding.left(), st::addContactTitleHeight + st::addContactPadding.top(), _width - st::addContactPadding.left() - st::addContactPadding.right(), _name.height());
|
||||
|
||||
int32 buttonTop = _name.y() + _name.height() + st::addContactPadding.bottom();
|
||||
_cancel.move(0, buttonTop);
|
||||
_create.move(_width - _create.width(), buttonTop);
|
||||
|
||||
connect(&_create, SIGNAL(clicked()), this, SLOT(onCreate()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
resize(_width, _height);
|
||||
|
||||
showAll();
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
|
||||
void CreateGroupBox::hideAll() {
|
||||
_name.hide();
|
||||
_cancel.hide();
|
||||
_create.hide();
|
||||
}
|
||||
|
||||
void CreateGroupBox::showAll() {
|
||||
_name.show();
|
||||
_cancel.show();
|
||||
_create.show();
|
||||
}
|
||||
|
||||
void CreateGroupBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
if (_name.hasFocus()) {
|
||||
if (_name.text().trimmed().isEmpty()) {
|
||||
_name.setFocus();
|
||||
_name.notaBene();
|
||||
} else {
|
||||
onCreate();
|
||||
}
|
||||
}
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void CreateGroupBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
update();
|
||||
}
|
||||
|
||||
void CreateGroupBox::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);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, st::addContactTitleHeight, _width, st::scrollDef.topsh, st::scrollDef.shColor->b);
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, size().height() - 1);
|
||||
|
||||
// draw box title / text
|
||||
p.setPen(st::black->p);
|
||||
p.setFont(st::addContactTitleFont->f);
|
||||
p.drawText(st::addContactTitlePos.x(), st::addContactTitlePos.y() + st::addContactTitleFont->ascent, lang(lng_create_group_title));
|
||||
}
|
||||
} else {
|
||||
p.setOpacity(a_opacity.current());
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateGroupBox::animStep(float64 dt) {
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
if (!_hiding) {
|
||||
showAll();
|
||||
_name.setFocus();
|
||||
}
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void CreateGroupBox::onCreate() {
|
||||
if (_createRequestId) return;
|
||||
|
||||
QString name = _name.text();
|
||||
if (name.isEmpty()) {
|
||||
_name.setFocus();
|
||||
_name.notaBene();
|
||||
return;
|
||||
}
|
||||
|
||||
_create.setDisabled(true);
|
||||
_name.setDisabled(true);
|
||||
_createRequestId = MTP::send(MTPmessages_CreateChat(_users, MTP_string(_name.text())), rpcDone(&CreateGroupBox::created), rpcFail(&CreateGroupBox::failed));
|
||||
}
|
||||
|
||||
void CreateGroupBox::created(const MTPmessages_StatedMessage &result) {
|
||||
App::main()->sentFullDataReceived(0, result);
|
||||
const QVector<MTPChat> *d = 0;
|
||||
switch (result.type()) {
|
||||
case mtpc_messages_statedMessage: {
|
||||
d = &result.c_messages_statedMessage().vchats.c_vector().v;
|
||||
} break;
|
||||
|
||||
case mtpc_messages_statedMessageLink: {
|
||||
d = &result.c_messages_statedMessageLink().vchats.c_vector().v;
|
||||
} break;
|
||||
}
|
||||
App::wnd()->hideLayer();
|
||||
PeerId peerId = 0;
|
||||
if (d && !d->isEmpty()) {
|
||||
switch (d->first().type()) {
|
||||
case mtpc_chat: peerId = App::peerFromChat(d->first().c_chat().vid); break;
|
||||
case mtpc_chatForbidden: peerId = App::peerFromChat(d->first().c_chatForbidden().vid); break;
|
||||
case mtpc_chatEmpty: peerId = App::peerFromChat(d->first().c_chatEmpty().vid); break;
|
||||
}
|
||||
}
|
||||
if (peerId) {
|
||||
App::main()->showPeer(peerId);
|
||||
}
|
||||
}
|
||||
|
||||
bool CreateGroupBox::failed(const RPCError &e) {
|
||||
_createRequestId = 0;
|
||||
if (e.type() == "NO_CHAT_TITLE") {
|
||||
_name.setFocus();
|
||||
return true;
|
||||
} else if (e.type() == "USERS_TOO_FEW") {
|
||||
emit closed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreateGroupBox::onCancel() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void CreateGroupBox::startHide() {
|
||||
_hiding = true;
|
||||
if (_cache.isNull()) {
|
||||
_cache = grab(rect());
|
||||
hideAll();
|
||||
}
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
CreateGroupBox::~CreateGroupBox() {
|
||||
}
|
166
Telegram/SourceFiles/boxes/newgroupbox.h
Normal file
166
Telegram/SourceFiles/boxes/newgroupbox.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class NewGroupInner : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
NewGroupInner();
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
void paintDialog(QPainter &p, DialogRow *row, bool sel);
|
||||
void updateFilter(QString filter = QString());
|
||||
|
||||
void selectSkip(int32 dir);
|
||||
void selectSkipPage(int32 h, int32 dir);
|
||||
|
||||
QVector<MTPInputUser> selectedInputs();
|
||||
|
||||
void loadProfilePhotos(int32 yFrom);
|
||||
|
||||
void changeCheckState(DialogRow *row);
|
||||
|
||||
~NewGroupInner();
|
||||
|
||||
signals:
|
||||
|
||||
void mustScrollTo(int ymin, int ymax);
|
||||
|
||||
public slots:
|
||||
|
||||
void onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow);
|
||||
|
||||
void updateSel();
|
||||
void peerUpdated(PeerData *peer);
|
||||
|
||||
void chooseParticipant();
|
||||
|
||||
private:
|
||||
|
||||
int32 _time;
|
||||
|
||||
DialogsIndexed *_contacts;
|
||||
DialogRow *_sel;
|
||||
QString _filter;
|
||||
typedef QVector<DialogRow*> FilteredDialogs;
|
||||
FilteredDialogs _filtered;
|
||||
int32 _filteredSel;
|
||||
bool _mouseSel;
|
||||
|
||||
typedef struct {
|
||||
Text name;
|
||||
QString online;
|
||||
bool check;
|
||||
} ContactData;
|
||||
typedef QMap<UserData*, ContactData*> ContactsData;
|
||||
ContactsData _contactsData;
|
||||
int32 _selCount;
|
||||
|
||||
ContactData *contactData(DialogRow *row);
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
};
|
||||
|
||||
class NewGroupBox : public LayeredWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
NewGroupBox();
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void startHide();
|
||||
~NewGroupBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onFilterUpdate();
|
||||
void onClose();
|
||||
void onNext();
|
||||
void onScroll();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
ScrollArea _scroll;
|
||||
NewGroupInner _inner;
|
||||
int32 _width, _height;
|
||||
FlatInput _filter;
|
||||
FlatButton _next, _cancel;
|
||||
bool _hiding;
|
||||
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
};
|
||||
|
||||
class CreateGroupBox : public LayeredWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
CreateGroupBox(const MTPVector<MTPInputUser> &users);
|
||||
void parentResized();
|
||||
void animStep(float64 dt);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~CreateGroupBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onCreate();
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
void created(const MTPmessages_StatedMessage &result);
|
||||
bool failed(const RPCError &e);
|
||||
|
||||
MTPVector<MTPInputUser> _users;
|
||||
|
||||
int32 _createRequestId;
|
||||
|
||||
int32 _width, _height;
|
||||
FlatInput _name;
|
||||
FlatButton _create, _cancel;
|
||||
|
||||
bool _hiding;
|
||||
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
};
|
309
Telegram/SourceFiles/boxes/photocropbox.cpp
Normal file
309
Telegram/SourceFiles/boxes/photocropbox.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "style.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "application.h"
|
||||
#include "mainwidget.h"
|
||||
#include "photocropbox.h"
|
||||
#include "fileuploader.h"
|
||||
|
||||
PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer) : _img(img), _downState(0), _peerId(peer),
|
||||
_sendButton(this, lang(lng_settings_save), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend()));
|
||||
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
if (_peerId) {
|
||||
connect(this, SIGNAL(ready(const QImage &)), this, SLOT(onReady(const QImage &)));
|
||||
}
|
||||
|
||||
int32 s = st::cropBoxWidth - st::boxPadding.left() - st::boxPadding.right();
|
||||
_thumb = QPixmap::fromImage(img.scaled(s, s, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
_thumbw = _thumb.width();
|
||||
_thumbh = _thumb.height();
|
||||
if (_thumbw > _thumbh) {
|
||||
_cropw = _thumbh - 20;
|
||||
} else {
|
||||
_cropw = _thumbw - 20;
|
||||
}
|
||||
_cropx = (_thumbw - _cropw) / 2;
|
||||
_cropy = (_thumbh - _cropw) / 2;
|
||||
_width = st::cropBoxWidth;
|
||||
_height = _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.top() + st::boxPadding.bottom() + _sendButton.height();
|
||||
_thumbx = (_width - _thumbw) / 2;
|
||||
_thumby = st::boxPadding.top() * 2 + st::boxFont->height;
|
||||
setMouseTracking(true);
|
||||
|
||||
resize(_width, _height);
|
||||
}
|
||||
|
||||
void PhotoCropBox::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() != Qt::LeftButton) return;
|
||||
|
||||
_downState = mouseState(e->pos());
|
||||
_fromposx = e->pos().x();
|
||||
_fromposy = e->pos().y();
|
||||
_fromcropx = _cropx;
|
||||
_fromcropy = _cropy;
|
||||
_fromcropw = _cropw;
|
||||
}
|
||||
|
||||
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();
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoCropBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
_sendButton.move(_width - _sendButton.width(), _height - _sendButton.height());
|
||||
_cancelButton.move(0, _height - _cancelButton.height());
|
||||
update();
|
||||
}
|
||||
|
||||
void PhotoCropBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
p.setOpacity(a_opacity.current());
|
||||
|
||||
// fill bg
|
||||
p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1);
|
||||
|
||||
p.setFont(st::boxFont->f);
|
||||
p.setPen(st::boxGrayTitle->p);
|
||||
p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), st::boxFont->height), lang(lng_settings_crop_profile), style::al_center);
|
||||
|
||||
p.translate(_thumbx, _thumby);
|
||||
p.drawPixmap(0, 0, _thumb);
|
||||
p.setOpacity(a_opacity.current() * 0.5);
|
||||
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);
|
||||
}
|
||||
|
||||
void PhotoCropBox::animStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
} else {
|
||||
a_opacity.update(ms, anim::linear);
|
||||
}
|
||||
_sendButton.setOpacity(a_opacity.current());
|
||||
_cancelButton.setOpacity(a_opacity.current());
|
||||
update();
|
||||
}
|
||||
|
||||
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();
|
||||
QImage cropped(from.bits() + offset, iw, iw, from.bytesPerLine(), from.format()), tosend;
|
||||
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);
|
||||
}
|
||||
|
||||
void PhotoCropBox::onReady(const QImage &tosend) {
|
||||
App::app()->uploadProfilePhoto(tosend, _peerId);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void PhotoCropBox::onCancel() {
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void PhotoCropBox::startHide() {
|
||||
_hiding = true;
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
PhotoCropBox::~PhotoCropBox() {
|
||||
}
|
64
Telegram/SourceFiles/boxes/photocropbox.h
Normal file
64
Telegram/SourceFiles/boxes/photocropbox.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
class PhotoCropBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PhotoCropBox(const QImage &img, const PeerId &peer);
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
int32 mouseState(QPoint p);
|
||||
~PhotoCropBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onSend();
|
||||
void onCancel();
|
||||
void onReady(const QImage &tosend);
|
||||
|
||||
signals:
|
||||
|
||||
void ready(const QImage &tosend);
|
||||
|
||||
private:
|
||||
|
||||
int32 _downState;
|
||||
int32 _width, _height, _thumbx, _thumby, _thumbw, _thumbh;
|
||||
int32 _cropx, _cropy, _cropw;
|
||||
int32 _fromposx, _fromposy, _fromcropx, _fromcropy, _fromcropw;
|
||||
FlatButton _sendButton, _cancelButton;
|
||||
QImage _img;
|
||||
QPixmap _thumb;
|
||||
PeerId _peerId;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
|
||||
bool _hiding;
|
||||
|
||||
};
|
131
Telegram/SourceFiles/boxes/photosendbox.cpp
Normal file
131
Telegram/SourceFiles/boxes/photosendbox.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "style.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "mainwidget.h"
|
||||
#include "photosendbox.h"
|
||||
|
||||
PhotoSendBox::PhotoSendBox(const ReadyLocalMedia &img) : _img(img),
|
||||
_sendButton(this, lang(lng_send_button), st::btnSelectDone),
|
||||
_cancelButton(this, lang(lng_cancel), st::btnSelectCancel),
|
||||
a_opacity(0, 1) {
|
||||
|
||||
connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend()));
|
||||
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onCancel()));
|
||||
|
||||
int32 maxW = 0, maxH = 0;
|
||||
for (PreparedPhotoThumbs::const_iterator i = img.photoThumbs.cbegin(), e = img.photoThumbs.cend(); i != e; ++i) {
|
||||
if (i->width() >= maxW && i->height() >= maxH) {
|
||||
_thumb = *i;
|
||||
maxW = _thumb.width();
|
||||
maxH = _thumb.height();
|
||||
}
|
||||
}
|
||||
int32 tw = _thumb.width(), th = _thumb.height();
|
||||
if (!tw || !th) {
|
||||
tw = th = 1;
|
||||
}
|
||||
_width = st::confirmWidth;
|
||||
_thumbw = _width - st::boxPadding.left() - st::boxPadding.right();
|
||||
if (_thumb.width() < _thumbw) {
|
||||
_thumbw = (_thumb.width() > 20) ? _thumb.width() : 20;
|
||||
}
|
||||
int32 maxthumbh = qRound(1.5 * _thumbw);
|
||||
_thumbh = qRound(th * float64(_thumbw) / tw);
|
||||
if (_thumbh > maxthumbh) {
|
||||
_thumbw = qRound(_thumbw * float64(maxthumbh) / _thumbh);
|
||||
_thumbh = maxthumbh;
|
||||
if (_thumbw < 10) {
|
||||
_thumbw = 10;
|
||||
}
|
||||
}
|
||||
_height = _thumbh + st::boxPadding.top() + st::boxFont->height + st::boxPadding.bottom() + st::boxPadding.bottom() + _sendButton.height();
|
||||
|
||||
_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw, _thumbh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
|
||||
resize(_width, _height);
|
||||
}
|
||||
|
||||
void PhotoSendBox::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
||||
onSend();
|
||||
} else if (e->key() == Qt::Key_Escape) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoSendBox::parentResized() {
|
||||
QSize s = parentWidget()->size();
|
||||
setGeometry((s.width() - _width) / 2, (s.height() - _height) / 2, _width, _height);
|
||||
_sendButton.move(_width - _sendButton.width(), _height - _sendButton.height());
|
||||
_cancelButton.move(0, _height - _cancelButton.height());
|
||||
update();
|
||||
}
|
||||
|
||||
void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
p.setOpacity(a_opacity.current());
|
||||
|
||||
// fill bg
|
||||
p.fillRect(QRect(QPoint(0, 0), size()), st::boxBG->b);
|
||||
|
||||
// paint shadows
|
||||
p.fillRect(0, _height - st::btnSelectCancel.height - st::scrollDef.bottomsh, _width, st::scrollDef.bottomsh, st::scrollDef.shColor->b);
|
||||
|
||||
// paint button sep
|
||||
p.setPen(st::btnSelectSep->p);
|
||||
p.drawLine(st::btnSelectCancel.width, _height - st::btnSelectCancel.height, st::btnSelectCancel.width, _height - 1);
|
||||
|
||||
p.setFont(st::boxFont->f);
|
||||
p.setPen(st::boxGrayTitle->p);
|
||||
p.drawText(QRect(st::boxPadding.left(), st::boxPadding.top(), _width - st::boxPadding.left() - st::boxPadding.right(), st::boxFont->height), lang(lng_really_send_image), style::al_center);
|
||||
p.drawPixmap((_width - _thumbw) / 2, st::boxPadding.top() * 2 + st::boxFont->height, _thumb);
|
||||
}
|
||||
|
||||
void PhotoSendBox::animStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
} else {
|
||||
a_opacity.update(ms, anim::linear);
|
||||
}
|
||||
_sendButton.setOpacity(a_opacity.current());
|
||||
_cancelButton.setOpacity(a_opacity.current());
|
||||
update();
|
||||
}
|
||||
|
||||
void PhotoSendBox::onSend() {
|
||||
if (App::main()) App::main()->confirmSendImage(_img);
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void PhotoSendBox::onCancel() {
|
||||
if (App::main()) App::main()->cancelSendImage();
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void PhotoSendBox::startHide() {
|
||||
_hiding = true;
|
||||
a_opacity.start(0);
|
||||
}
|
||||
|
||||
PhotoSendBox::~PhotoSendBox() {
|
||||
if (App::main()) App::main()->cancelSendImage();
|
||||
}
|
52
Telegram/SourceFiles/boxes/photosendbox.h
Normal file
52
Telegram/SourceFiles/boxes/photosendbox.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
an unofficial desktop 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://tdesktop.com
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "layerwidget.h"
|
||||
#include "localimageloader.h"
|
||||
|
||||
class PhotoSendBox : public LayeredWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PhotoSendBox(const ReadyLocalMedia &img);
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void startHide();
|
||||
~PhotoSendBox();
|
||||
|
||||
public slots:
|
||||
|
||||
void onSend();
|
||||
void onCancel();
|
||||
|
||||
private:
|
||||
|
||||
ReadyLocalMedia _img;
|
||||
int32 _width, _height, _thumbw, _thumbh;
|
||||
FlatButton _sendButton, _cancelButton;
|
||||
QPixmap _thumb;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
|
||||
bool _hiding;
|
||||
|
||||
};
|
Reference in New Issue
Block a user