Merge branch 'dev'

This commit is contained in:
John Preston 2016-04-19 17:02:55 +03:00
commit 10bd2b680d
127 changed files with 9099 additions and 8395 deletions

View file

@ -636,7 +636,7 @@
"/usr/local/Qt-5.5.1/plugins/platforms", "/usr/local/Qt-5.5.1/plugins/platforms",
"/usr/local/Qt-5.5.1/plugins/imageformats", "/usr/local/Qt-5.5.1/plugins/imageformats",
); );
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.8;
OBJROOT = ./../Mac/ReleaseIntermediateStyle; OBJROOT = ./../Mac/ReleaseIntermediateStyle;
OTHER_CFLAGS = ( OTHER_CFLAGS = (
"-pipe", "-pipe",
@ -727,7 +727,7 @@
"/usr/local/Qt-5.5.1/plugins/platforms", "/usr/local/Qt-5.5.1/plugins/platforms",
"/usr/local/Qt-5.5.1/plugins/imageformats", "/usr/local/Qt-5.5.1/plugins/imageformats",
); );
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.8;
OBJROOT = ./../Mac/DebugIntermediateStyle; OBJROOT = ./../Mac/DebugIntermediateStyle;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = ( OTHER_CFLAGS = (

View file

@ -383,7 +383,7 @@ to link the code of portions of this program with the OpenSSL library.\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n"; */\n";
tout << "#pragma once\n\n#include \"ui/style.h\"\n\nnamespace style {\n"; tout << "#pragma once\n\n#include \"ui/style_core.h\"\n\nnamespace style {\n";
for (int i = 0, l = byIndex.size(); i < l; ++i) { for (int i = 0, l = byIndex.size(); i < l; ++i) {
ClassData &cls(byIndex[i]); ClassData &cls(byIndex[i]);
classes.insert(cls.name, cls); classes.insert(cls.name, cls);
@ -513,7 +513,7 @@ typedef QPair<ScalarType, ScalarValue> ScalarData;
typedef QPair<string, ScalarData> Scalar; typedef QPair<string, ScalarData> Scalar;
typedef QMap<string, ScalarData> Fields; typedef QMap<string, ScalarData> Fields;
typedef QPair<string, Fields> ObjectData; typedef QPair<string, Fields> ObjectData;
typedef QPair<string, ObjectData> Object; typedef QPair<string, ObjectData> Object;
typedef QVector<Object> Objects; typedef QVector<Object> Objects;
typedef QVector<Scalar> Scalars; typedef QVector<Scalar> Scalars;
@ -636,7 +636,7 @@ ScalarValue prepareNumber(int variant, const string &token, const char *&text, c
ScalarValue prepareColorRGB(int variant, const string &name, const char *&text, const char *end) { ScalarValue prepareColorRGB(int variant, const string &name, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rgb() cons!").arg(type));
@ -675,7 +675,7 @@ ScalarValue prepareColorRGB(int variant, const string &name, const char *&text,
ScalarValue prepareColorRGBA(int variant, const string &name, const char *&text, const char *end) { ScalarValue prepareColorRGBA(int variant, const string &name, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rgba() cons!").arg(type));
@ -721,7 +721,7 @@ ScalarValue prepareColorRGBA(int variant, const string &name, const char *&text,
ScalarValue prepareRect(int variant, const char *&text, const char *end) { ScalarValue prepareRect(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rect() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading rect() cons!").arg(type));
@ -859,7 +859,7 @@ ScalarValue prepareSprite(int variant, const char *&text, const char *end) {
ScalarValue preparePoint(int variant, const char *&text, const char *end) { ScalarValue preparePoint(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading point() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading point() cons!").arg(type));
@ -892,7 +892,7 @@ ScalarValue preparePoint(int variant, const char *&text, const char *end) {
ScalarValue prepareSize(int variant, const char *&text, const char *end) { ScalarValue prepareSize(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading size() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading size() cons!").arg(type));
@ -925,7 +925,7 @@ ScalarValue prepareSize(int variant, const char *&text, const char *end) {
ScalarValue prepareTransition(int variant, const char *&text, const char *end) { ScalarValue prepareTransition(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading transition() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading transition() cons!").arg(type));
@ -942,7 +942,7 @@ ScalarValue prepareTransition(int variant, const char *&text, const char *end) {
ScalarValue prepareCursor(int variant, const char *&text, const char *end) { ScalarValue prepareCursor(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading cursor() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading cursor() cons!").arg(type));
@ -959,7 +959,7 @@ ScalarValue prepareCursor(int variant, const char *&text, const char *end) {
ScalarValue prepareAlign(int variant, const char *&text, const char *end) { ScalarValue prepareAlign(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading align() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading align() cons!").arg(type));
@ -976,7 +976,7 @@ ScalarValue prepareAlign(int variant, const char *&text, const char *end) {
ScalarValue prepareMargins(int variant, const char *&text, const char *end) { ScalarValue prepareMargins(int variant, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
readStyleGenToken(text, end, type, token); readStyleGenToken(text, end, type, token);
if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading margins() cons!").arg(type)); if (type != stConsStart) throw Exception(QString("Unexpected token %1 while reading margins() cons!").arg(type));
@ -1049,7 +1049,7 @@ QMap<int, Fonts> fonts;
ScalarValue prepareFont(int variant, const string &name, const char *&text, const char *end) { ScalarValue prepareFont(int variant, const string &name, const char *&text, const char *end) {
StyleGenTokenType type; StyleGenTokenType type;
string token; string token;
ScalarValue sizeScalar, familyScalar; ScalarValue sizeScalar, familyScalar;
string size, family; string size, family;
@ -1534,7 +1534,7 @@ to link the code of portions of this program with the OpenSSL library.\n\
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE\n\
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
*/\n"; */\n";
tout << "#pragma once\n\n#include \"ui/style.h\"\n\nnamespace st {\n"; tout << "#pragma once\n\n#include \"ui/style_core.h\"\n\nnamespace st {\n";
tcpp << "\ tcpp << "\
/*\n\ /*\n\
Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\n\ Created from \'/Resources/style.txt\' by \'/MetaStyle\' project\n\
@ -1594,7 +1594,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org\n\
tcpp << "\tColorDatas _colorsMap;\n"; tcpp << "\tColorDatas _colorsMap;\n";
tcpp << "\tint _spriteWidth = " << spriteWidths[0] << ";\n\n"; tcpp << "\tint _spriteWidth = " << spriteWidths[0] << ";\n\n";
tcpp << "\tvoid startManager() {\n"; tcpp << "\tvoid startManager() {\n";
tcpp << "\n\t\tif (cRetina()) {\n"; tcpp << "\n\t\tif (cRetina()) {\n";
tcpp << "\t\t\tcSetRealScale(dbisOne);\n"; tcpp << "\t\t\tcSetRealScale(dbisOne);\n";
tcpp << "\t\t\t_spriteWidth = " << spriteWidths[variantsCount - 1] << ";\n\n"; tcpp << "\t\t\t_spriteWidth = " << spriteWidths[variantsCount - 1] << ";\n\n";

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "lang.h" #include "lang.h"
#include "application.h" #include "application.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "apiwrap.h" #include "apiwrap.h"

View file

@ -31,7 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <libexif/exif-data.h> #include <libexif/exif-data.h>
#endif #endif
#include "localstorage.h" #include "localstorage.h"
#include "apiwrap.h"
#include "numbers.h" #include "numbers.h"
namespace { namespace {
@ -146,23 +146,29 @@ namespace App {
return AppClass::app(); return AppClass::app();
} }
Window *wnd() { MainWindow *wnd() {
return AppClass::wnd(); return AppClass::wnd();
} }
MainWidget *main() { MainWidget *main() {
Window *w(wnd()); if (auto w = wnd()) {
return w ? w->mainWidget() : 0; return w->mainWidget();
}
return nullptr;
} }
SettingsWidget *settings() { SettingsWidget *settings() {
Window *w(wnd()); if (auto w = wnd()) {
return w ? w->settingsWidget() : 0; return w->settingsWidget();
}
return nullptr;
} }
bool passcoded() { bool passcoded() {
Window *w(wnd()); if (auto w = wnd()) {
return w ? w->passcodeWidget() : 0; return w->passcodeWidget();
}
return false;
} }
FileUploader *uploader() { FileUploader *uploader() {
@ -181,7 +187,7 @@ namespace {
if (audioPlayer()) { if (audioPlayer()) {
audioPlayer()->stopAndClear(); audioPlayer()->stopAndClear();
} }
if (Window *w = wnd()) { if (auto w = wnd()) {
w->tempDirDelete(Local::ClearManagerAll); w->tempDirDelete(Local::ClearManagerAll);
w->notifyClearFast(); w->notifyClearFast();
w->setupIntro(true); w->setupIntro(true);
@ -196,7 +202,7 @@ namespace {
globalNotifyChatsPtr = UnknownNotifySettings; globalNotifyChatsPtr = UnknownNotifySettings;
if (App::uploader()) App::uploader()->clear(); if (App::uploader()) App::uploader()->clear();
clearStorageImages(); clearStorageImages();
if (Window *w = wnd()) { if (auto w = wnd()) {
w->getTitle()->updateBackButton(); w->getTitle()->updateBackButton();
w->updateTitleStatus(); w->updateTitleStatus();
w->getTitle()->resizeEvent(0); w->getTitle()->resizeEvent(0);
@ -1762,22 +1768,22 @@ namespace {
void historyItemDetached(HistoryItem *item) { void historyItemDetached(HistoryItem *item) {
if (::hoveredItem == item) { if (::hoveredItem == item) {
hoveredItem(0); hoveredItem(nullptr);
} }
if (::pressedItem == item) { if (::pressedItem == item) {
pressedItem(0); pressedItem(nullptr);
} }
if (::hoveredLinkItem == item) { if (::hoveredLinkItem == item) {
hoveredLinkItem(0); hoveredLinkItem(nullptr);
} }
if (::pressedLinkItem == item) { if (::pressedLinkItem == item) {
pressedLinkItem(0); pressedLinkItem(nullptr);
} }
if (::contextItem == item) { if (::contextItem == item) {
contextItem(0); contextItem(nullptr);
} }
if (::mousedItem == item) { if (::mousedItem == item) {
mousedItem(0); mousedItem(nullptr);
} }
if (App::wnd()) { if (App::wnd()) {
App::wnd()->notifyItemRemoved(item); App::wnd()->notifyItemRemoved(item);

View file

@ -20,10 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
class AppClass; class AppClass;
class Window; class MainWindow;
class MainWidget; class MainWidget;
class SettingsWidget; class SettingsWidget;
class ApiWrap; class ApiWrap;
@ -48,7 +48,7 @@ class LayeredWidget;
namespace App { namespace App {
AppClass *app(); AppClass *app();
Window *wnd(); MainWindow *wnd();
MainWidget *main(); MainWidget *main();
SettingsWidget *settings(); SettingsWidget *settings();
bool passcoded(); bool passcoded();

View file

@ -20,20 +20,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "application.h" #include "application.h"
#include "ui/style.h" #include "ui/style.h"
#include "shortcuts.h" #include "shortcuts.h"
#include "pspecific.h" #include "pspecific.h"
#include "fileuploader.h" #include "fileuploader.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "lang.h" #include "lang.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "langloaderplain.h" #include "langloaderplain.h"
#include "localstorage.h" #include "localstorage.h"
#include "autoupdater.h" #include "autoupdater.h"
namespace { namespace {
@ -90,14 +86,7 @@ namespace {
AppClass *AppObject = 0; AppClass *AppObject = 0;
Application::Application(int &argc, char **argv) : QApplication(argc, argv) Application::Application(int &argc, char **argv) : QApplication(argc, argv) {
, _secondInstance(false)
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _updateReply(0)
, _updateThread(0)
, _updateChecker(0)
#endif
{
QByteArray d(QFile::encodeName(QDir(cWorkingDir()).absolutePath())); QByteArray d(QFile::encodeName(QDir(cWorkingDir()).absolutePath()));
char h[33] = { 0 }; char h[33] = { 0 };
hashMd5Hex(d.constData(), d.size(), h); hashMd5Hex(d.constData(), d.size(), h);
@ -718,7 +707,7 @@ AppClass::AppClass() : QObject()
QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database
_window = new Window(); _window = new MainWindow();
_window->createWinId(); _window->createWinId();
_window->init(); _window->init();
@ -905,6 +894,12 @@ void AppClass::call_handleHistoryUpdate() {
Notify::handlePendingHistoryUpdate(); Notify::handlePendingHistoryUpdate();
} }
void AppClass::call_handleUnreadCounterUpdate() {
if (auto w = App::wnd()) {
w->updateUnreadCounter();
}
}
void AppClass::killDownloadSessions() { void AppClass::killDownloadSessions() {
uint64 ms = getms(), left = MTPAckSendWaiting + MTPKillFileSessionTimeout; uint64 ms = getms(), left = MTPAckSendWaiting + MTPKillFileSessionTimeout;
for (QMap<int32, uint64>::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) { for (QMap<int32, uint64>::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) {
@ -1035,8 +1030,8 @@ void AppClass::checkMapVersion() {
if (Local::oldMapVersion()) { if (Local::oldMapVersion()) {
QString versionFeatures; QString versionFeatures;
if ((cDevVersion() || cBetaVersion()) && Local::oldMapVersion() < 9041) { if ((cDevVersion() || cBetaVersion()) && Local::oldMapVersion() < 9041) {
// versionFeatures = QString::fromUtf8("\xe2\x80\x94 Design improvements\n\xe2\x80\x94 Bug fixes and other minor improvements"); versionFeatures = QString::fromUtf8("\xe2\x80\x94 Select and copy text in photo / video captions and web page previews\n\xe2\x80\x94 Media player shortcuts are enabled only when player is opened");
versionFeatures = langNewVersionText(); // versionFeatures = langNewVersionText();
} else if (Local::oldMapVersion() < 9041) { } else if (Local::oldMapVersion() < 9041) {
versionFeatures = langNewVersionText(); versionFeatures = langNewVersionText();
} else { } else {
@ -1053,7 +1048,7 @@ void AppClass::checkMapVersion() {
AppClass::~AppClass() { AppClass::~AppClass() {
Shortcuts::finish(); Shortcuts::finish();
if (Window *w = _window) { if (auto w = _window) {
_window = 0; _window = 0;
delete w; delete w;
} }
@ -1086,7 +1081,7 @@ AppClass *AppClass::app() {
return AppObject; return AppObject;
} }
Window *AppClass::wnd() { MainWindow *AppClass::wnd() {
return AppObject ? AppObject->_window : 0; return AppObject ? AppObject->_window : 0;
} }

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "window.h" #include "mainwindow.h"
#include "pspecific.h" #include "pspecific.h"
class UpdateChecker; class UpdateChecker;
@ -56,7 +56,7 @@ private:
QLocalServer _localServer; QLocalServer _localServer;
QLocalSocket _localSocket; QLocalSocket _localSocket;
LocalClients _localClients; LocalClients _localClients;
bool _secondInstance; bool _secondInstance = false;
void singleInstanceChecked(); void singleInstanceChecked();
@ -98,10 +98,10 @@ public slots:
private: private:
SingleTimer _updateCheckTimer; SingleTimer _updateCheckTimer;
QNetworkReply *_updateReply; QNetworkReply *_updateReply = nullptr;
QNetworkAccessManager _updateManager; QNetworkAccessManager _updateManager;
QThread *_updateThread; QThread *_updateThread = nullptr;
UpdateChecker *_updateChecker; UpdateChecker *_updateChecker = nullptr;
#endif #endif
}; };
@ -153,7 +153,7 @@ public:
~AppClass(); ~AppClass();
static AppClass *app(); static AppClass *app();
static Window *wnd(); static MainWindow *wnd();
static MainWidget *main(); static MainWidget *main();
FileUploader *uploader(); FileUploader *uploader();
@ -202,6 +202,7 @@ public slots:
void onAppStateChanged(Qt::ApplicationState state); void onAppStateChanged(Qt::ApplicationState state);
void call_handleHistoryUpdate(); void call_handleHistoryUpdate();
void call_handleUnreadCounterUpdate();
private: private:
@ -212,7 +213,7 @@ private:
uint64 _lastActionTime; uint64 _lastActionTime;
Window *_window; MainWindow *_window;
FileUploader *_uploader; FileUploader *_uploader;
Translator *_translator; Translator *_translator;

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
void audioInit(); void audioInit();
bool audioWorks(); bool audioWorks();

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "aboutbox.h" #include "aboutbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "autoupdater.h" #include "autoupdater.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"

View file

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "abstractbox.h" #include "abstractbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
void BlueTitleShadow::paintEvent(QPaintEvent *e) { void BlueTitleShadow::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);

View file

@ -28,7 +28,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "photocropbox.h" #include "photocropbox.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "apiwrap.h"
AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth) AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth)
, _user(0) , _user(0)

View file

@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "autolockbox.h" #include "autolockbox.h"
#include "confirmbox.h" #include "confirmbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
AutoLockBox::AutoLockBox() : AutoLockBox::AutoLockBox() :
_close(this, lang(lng_box_ok), st::defaultBoxButton) { _close(this, lang(lng_box_ok), st::defaultBoxButton) {

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "backgroundbox.h" #include "backgroundbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "settingswidget.h" #include "settingswidget.h"
BackgroundInner::BackgroundInner() : BackgroundInner::BackgroundInner() :

View file

@ -23,9 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "confirmbox.h" #include "confirmbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "apiwrap.h"
#include "application.h" #include "application.h"
#include "core/click_handler_types.h"
TextParseOptions _confirmBoxTextOptions = { TextParseOptions _confirmBoxTextOptions = {
TextParseLinks | TextParseMultiline | TextParseRichText, // flags TextParseLinks | TextParseMultiline | TextParseRichText, // flags
@ -118,10 +119,10 @@ void ConfirmBox::updateHover() {
QPoint m(mapFromGlobal(_lastMousePos)); QPoint m(mapFromGlobal(_lastMousePos));
textstyleSet(&st::boxTextStyle); textstyleSet(&st::boxTextStyle);
ClickHandlerPtr handler = _text.linkLeft(m.x() - st::boxPadding.left(), m.y() - st::boxPadding.top(), _textWidth, width(), style::al_left); auto state = _text.getStateLeft(m.x() - st::boxPadding.left(), m.y() - st::boxPadding.top(), _textWidth, width());
textstyleRestore(); textstyleRestore();
ClickHandler::setActive(handler, this); ClickHandler::setActive(state.link, this);
} }
void ConfirmBox::closePressed() { void ConfirmBox::closePressed() {

View file

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "connectionbox.h" #include "connectionbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth) ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth)
, _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), cConnectionProxy().host) , _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), cConnectionProxy().host)

View file

@ -26,11 +26,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/addcontactbox.h" #include "boxes/addcontactbox.h"
#include "boxes/contactsbox.h" #include "boxes/contactsbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "boxes/photocropbox.h" #include "boxes/photocropbox.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "apiwrap.h"
QString cantInviteError() { QString cantInviteError() {
return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info))); return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)));
@ -956,7 +957,6 @@ void ContactsInner::peopleReceived(const QString &query, const QVector<MTPPeer>
if (p->asUser()->botInfo->cantJoinGroups) continue; if (p->asUser()->botInfo->cantJoinGroups) continue;
} }
if (_channel) { if (_channel) {
if (_channel->isMegagroup() && _membersFilter == MembersFilterAdmins) continue;
if (!_channel->isMegagroup() && _membersFilter != MembersFilterAdmins) continue; if (!_channel->isMegagroup() && _membersFilter != MembersFilterAdmins) continue;
} }
} }

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "emojibox.h" #include "emojibox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
namespace { namespace {
// copied from genemoji.cpp // copied from genemoji.cpp

View file

@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "languagebox.h" #include "languagebox.h"
#include "confirmbox.h" #include "confirmbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "langloaderplain.h" #include "langloaderplain.h"

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "passcodebox.h" #include "passcodebox.h"
#include "confirmbox.h" #include "confirmbox.h"
#include "window.h" #include "mainwindow.h"
#include "localstorage.h" #include "localstorage.h"

View file

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "sessionsbox.h" #include "sessionsbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "countries.h" #include "countries.h"
#include "confirmbox.h" #include "confirmbox.h"

View file

@ -23,10 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stickersetbox.h" #include "stickersetbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "settingswidget.h" #include "settingswidget.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "apiwrap.h"
#include "localstorage.h" #include "localstorage.h"
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget()

View file

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "application.h" #include "application.h"
#include "usernamebox.h" #include "usernamebox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
UsernameBox::UsernameBox() : AbstractBox(st::boxWidth), UsernameBox::UsernameBox() : AbstractBox(st::boxWidth),
_save(this, lang(lng_settings_save), st::defaultBoxButton), _save(this, lang(lng_settings_save), st::defaultBoxButton),

View file

@ -20,9 +20,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
static const int32 AppVersion = 9042; static const int32 AppVersion = 9043;
static const wchar_t *AppVersionStr = L"0.9.42"; static const wchar_t *AppVersionStr = L"0.9.43";
static const bool DevVersion = false; static const bool DevVersion = true;
//#define BETA_VERSION (9040128ULL) // just comment this line to build public version //#define BETA_VERSION (9040128ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";

View file

@ -0,0 +1,63 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "core/click_handler.h"
ClickHandlerHost::~ClickHandlerHost() {
ClickHandler::hostDestroyed(this);
}
NeverFreedPointer<ClickHandlerPtr> ClickHandler::_active;
NeverFreedPointer<ClickHandlerPtr> ClickHandler::_pressed;
ClickHandlerHost *ClickHandler::_activeHost = nullptr;
ClickHandlerHost *ClickHandler::_pressedHost = nullptr;
bool ClickHandler::setActive(const ClickHandlerPtr &p, ClickHandlerHost *host) {
if ((_active && (*_active == p)) || (!_active && !p)) {
return false;
}
// emit clickHandlerActiveChanged only when there is no
// other pressed click handler currently, if there is
// this method will be called when it is unpressed
if (_active && *_active) {
bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active);
ClickHandlerPtr wasactive = *_active;
(*_active).clear();
if (_activeHost) {
if (emitClickHandlerActiveChanged) {
_activeHost->clickHandlerActiveChanged(wasactive, false);
}
_activeHost = nullptr;
}
}
if (p) {
_active.makeIfNull();
*_active = p;
if ((_activeHost = host)) {
bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active);
if (emitClickHandlerActiveChanged) {
_activeHost->clickHandlerActiveChanged(*_active, true);
}
}
}
return true;
}

View file

@ -0,0 +1,158 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
class ClickHandler;
using ClickHandlerPtr = QSharedPointer<ClickHandler>;
class ClickHandlerHost {
protected:
virtual void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
}
virtual void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) {
}
virtual ~ClickHandlerHost() = 0;
friend class ClickHandler;
};
class ClickHandler {
public:
virtual void onClick(Qt::MouseButton) const = 0;
virtual QString tooltip() const {
return QString();
}
virtual void copyToClipboard() const {
}
virtual QString copyToClipboardContextItem() const {
return QString();
}
virtual QString text() const {
return QString();
}
virtual QString dragText() const {
return text();
}
virtual ~ClickHandler() {
}
// this method should be called on mouse over a click handler
// it returns true if something was changed or false otherwise
static bool setActive(const ClickHandlerPtr &p, ClickHandlerHost *host = nullptr);
// this method should be called when mouse leaves the host
// it returns true if something was changed or false otherwise
static bool clearActive(ClickHandlerHost *host = nullptr) {
if (host && _activeHost != host) {
return false;
}
return setActive(ClickHandlerPtr(), host);
}
// this method should be called on mouse pressed
static void pressed() {
unpressed();
if (!_active || !*_active) {
return;
}
_pressed.makeIfNull();
*_pressed = *_active;
if ((_pressedHost = _activeHost)) {
_pressedHost->clickHandlerPressedChanged(*_pressed, true);
}
}
// this method should be called on mouse released
// the activated click handler is returned
static ClickHandlerPtr unpressed() {
if (_pressed && *_pressed) {
bool activated = (_active && *_active == *_pressed);
ClickHandlerPtr waspressed = *_pressed;
(*_pressed).clear();
if (_pressedHost) {
_pressedHost->clickHandlerPressedChanged(waspressed, false);
_pressedHost = nullptr;
}
if (activated) {
return *_active;
} else if (_active && *_active && _activeHost) {
// emit clickHandlerActiveChanged for current active
// click handler, which we didn't emit while we has
// a pressed click handler
_activeHost->clickHandlerActiveChanged(*_active, true);
}
}
return ClickHandlerPtr();
}
static ClickHandlerPtr getActive() {
return _active ? *_active : ClickHandlerPtr();
}
static ClickHandlerPtr getPressed() {
return _pressed ? *_pressed : ClickHandlerPtr();
}
static bool showAsActive(const ClickHandlerPtr &p) {
if (!p || !_active || p != *_active) {
return false;
}
return !_pressed || !*_pressed || (p == *_pressed);
}
static bool showAsPressed(const ClickHandlerPtr &p) {
if (!p || !_active || p != *_active) {
return false;
}
return _pressed && (p == *_pressed);
}
static void hostDestroyed(ClickHandlerHost *host) {
if (_activeHost == host) {
_activeHost = nullptr;
}
if (_pressedHost == host) {
_pressedHost = nullptr;
}
}
private:
static NeverFreedPointer<ClickHandlerPtr> _active;
static NeverFreedPointer<ClickHandlerPtr> _pressed;
static ClickHandlerHost *_activeHost;
static ClickHandlerHost *_pressedHost;
};
class LeftButtonClickHandler : public ClickHandler {
public:
void onClick(Qt::MouseButton button) const override final {
if (button != Qt::LeftButton) return;
onClickImpl();
}
protected:
virtual void onClickImpl() const = 0;
};

View file

@ -0,0 +1,139 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "core/click_handler_types.h"
#include "lang.h"
#include "pspecific.h"
#include "boxes/confirmbox.h"
QString UrlClickHandler::copyToClipboardContextItem() const {
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
}
namespace {
QString tryConvertUrlToLocal(const QString &url) {
QRegularExpressionMatch telegramMeUser = QRegularExpression(qsl("^https?://telegram\\.me/([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), QRegularExpression::CaseInsensitiveOption).match(url);
QRegularExpressionMatch telegramMeGroup = QRegularExpression(qsl("^https?://telegram\\.me/joinchat/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption).match(url);
QRegularExpressionMatch telegramMeStickers = QRegularExpression(qsl("^https?://telegram\\.me/addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption).match(url);
QRegularExpressionMatch telegramMeShareUrl = QRegularExpression(qsl("^https?://telegram\\.me/share/url\\?(.+)$"), QRegularExpression::CaseInsensitiveOption).match(url);
if (telegramMeGroup.hasMatch()) {
return qsl("tg://join?invite=") + myUrlEncode(telegramMeGroup.captured(1));
} else if (telegramMeStickers.hasMatch()) {
return qsl("tg://addstickers?set=") + myUrlEncode(telegramMeStickers.captured(1));
} else if (telegramMeShareUrl.hasMatch()) {
return qsl("tg://msg_url?") + telegramMeShareUrl.captured(1);
} else if (telegramMeUser.hasMatch()) {
QString params = url.mid(telegramMeUser.captured(0).size()), postParam;
if (QRegularExpression(qsl("^/\\d+/?(?:\\?|$)")).match(telegramMeUser.captured(2)).hasMatch()) {
postParam = qsl("&post=") + telegramMeUser.captured(3);
}
return qsl("tg://resolve/?domain=") + myUrlEncode(telegramMeUser.captured(1)) + postParam + (params.isEmpty() ? QString() : '&' + params);
}
return url;
}
} // namespace
void UrlClickHandler::doOpen(QString url) {
PopupTooltip::Hide();
if (isEmail(url)) {
QUrl u(qstr("mailto:") + url);
if (!QDesktopServices::openUrl(u)) {
psOpenFile(u.toString(QUrl::FullyEncoded), true);
}
return;
}
url = tryConvertUrlToLocal(url);
if (url.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
App::openLocalUrl(url);
} else {
QDesktopServices::openUrl(url);
}
}
void HiddenUrlClickHandler::onClick(Qt::MouseButton button) const {
QString u = url();
u = tryConvertUrlToLocal(u);
if (u.startsWith(qstr("tg://"))) {
App::openLocalUrl(u);
} else {
Ui::showLayer(new ConfirmLinkBox(u));
}
}
QString LocationClickHandler::copyToClipboardContextItem() const {
return lang(lng_context_copy_link);
}
void LocationClickHandler::onClick(Qt::MouseButton button) const {
if (!psLaunchMaps(_coords)) {
QDesktopServices::openUrl(_text);
}
}
void LocationClickHandler::setup() {
QString latlon(qsl("%1,%2").arg(_coords.lat).arg(_coords.lon));
_text = qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16");
}
QString MentionClickHandler::copyToClipboardContextItem() const {
return lang(lng_context_copy_mention);
}
void MentionClickHandler::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
App::openPeerByName(_tag.mid(1), ShowAtProfileMsgId);
}
}
QString HashtagClickHandler::copyToClipboardContextItem() const {
return lang(lng_context_copy_hashtag);
}
void HashtagClickHandler::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
App::searchByHashtag(_tag, Ui::getPeerForMouseAction());
}
}
void BotCommandClickHandler::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
if (PeerData *peer = Ui::getPeerForMouseAction()) {
UserData *bot = peer->isUser() ? peer->asUser() : nullptr;
if (auto item = App::hoveredLinkItem()) {
if (!bot) {
bot = item->fromOriginal()->asUser(); // may return nullptr
}
}
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
App::sendBotCommand(peer, bot, _cmd);
} else {
App::insertBotCommand(_cmd);
}
}
}

View file

@ -0,0 +1,181 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "core/click_handler.h"
class TextClickHandler : public ClickHandler {
public:
TextClickHandler(bool fullDisplayed = true) : _fullDisplayed(fullDisplayed) {
}
void copyToClipboard() const override {
QString u = url();
if (!u.isEmpty()) {
QApplication::clipboard()->setText(u);
}
}
QString tooltip() const override {
return _fullDisplayed ? QString() : readable();
}
void setFullDisplayed(bool full) {
_fullDisplayed = full;
}
protected:
virtual QString url() const = 0;
virtual QString readable() const {
return url();
}
bool _fullDisplayed;
};
class UrlClickHandler : public TextClickHandler {
public:
UrlClickHandler(const QString &url, bool fullDisplayed = true) : TextClickHandler(fullDisplayed), _url(url) {
if (isEmail()) {
_readable = _url;
} else {
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
_readable = good.isValid() ? good.toDisplayString() : _url;
}
}
QString copyToClipboardContextItem() const override;
QString text() const override {
return _url;
}
QString dragText() const override {
return url();
}
static void doOpen(QString url);
void onClick(Qt::MouseButton button) const override {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
doOpen(url());
}
}
protected:
QString url() const override {
if (isEmail()) {
return _url;
}
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url);
if (!QRegularExpression(qsl("^[a-zA-Z]+:")).match(result).hasMatch()) { // no protocol
return qsl("http://") + result;
}
return result;
}
QString readable() const override {
return _readable;
}
private:
static bool isEmail(const QString &url) {
int at = url.indexOf('@'), slash = url.indexOf('/');
return ((at > 0) && (slash < 0 || slash > at));
}
bool isEmail() const {
return isEmail(_url);
}
QString _url, _readable;
};
typedef QSharedPointer<TextClickHandler> TextClickHandlerPtr;
class HiddenUrlClickHandler : public UrlClickHandler {
public:
HiddenUrlClickHandler(QString url) : UrlClickHandler(url, false) {
}
void onClick(Qt::MouseButton button) const override;
};
class MentionClickHandler : public TextClickHandler {
public:
MentionClickHandler(const QString &tag) : _tag(tag) {
}
QString copyToClipboardContextItem() const override;
QString text() const override {
return _tag;
}
void onClick(Qt::MouseButton button) const override;
protected:
QString url() const override {
return _tag;
}
private:
QString _tag;
};
class HashtagClickHandler : public TextClickHandler {
public:
HashtagClickHandler(const QString &tag) : _tag(tag) {
}
QString copyToClipboardContextItem() const override;
QString text() const override {
return _tag;
}
void onClick(Qt::MouseButton button) const override;
protected:
QString url() const override {
return _tag;
}
private:
QString _tag;
};
class BotCommandClickHandler : public TextClickHandler {
public:
BotCommandClickHandler(const QString &cmd) : _cmd(cmd) {
}
QString text() const override {
return _cmd;
}
void onClick(Qt::MouseButton button) const override;
protected:
QString url() const override {
return _cmd;
}
private:
QString _cmd;
};

View file

@ -93,7 +93,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, int w, bool activ
p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), *check); p.drawSprite(QPoint(rectForName.left() + rectForName.width() + st::dlgCheckLeft, rectForName.top() + st::dlgCheckTop), *check);
} }
paintItemCallback(nameleft, namewidth); paintItemCallback(nameleft, namewidth, item);
} }
if (history->peer->isUser() && history->peer->isVerified()) { if (history->peer->isUser() && history->peer->isVerified()) {
@ -132,10 +132,10 @@ QImage colorizeCircleHalf(int size, int half, int xoffset, style::color color) {
int a = color->c.alpha() + 1; int a = color->c.alpha() + 1;
int fg_r = color->c.red() * a, fg_g = color->c.green() * a, fg_b = color->c.blue() * a, fg_a = 255 * a; int fg_r = color->c.red() * a, fg_g = color->c.green() * a, fg_b = color->c.blue() * a, fg_a = 255 * a;
QImage result(size, size, QImage::Format_ARGB32_Premultiplied); QImage result(half, size, QImage::Format_ARGB32_Premultiplied);
uchar *bits = result.bits(), *maskbits = unreadBadgeStyle->circle.bits(); uchar *bits = result.bits(), *maskbits = unreadBadgeStyle->circle.bits();
int bpl = result.bytesPerLine(), maskbpl = unreadBadgeStyle->circle.bytesPerLine(); int bpl = result.bytesPerLine(), maskbpl = unreadBadgeStyle->circle.bytesPerLine();
for (int x = 0; x < size; ++x) { for (int x = 0; x < half; ++x) {
for (int y = 0; y < size; ++y) { for (int y = 0; y < size; ++y) {
int s = y * bpl + (x * 4); int s = y * bpl + (x * 4);
int o = maskbits[y * maskbpl + x + xoffset] + 1; int o = maskbits[y * maskbpl + x + xoffset] + 1;
@ -194,7 +194,7 @@ void paintUnreadCount(Painter &p, const QString &text, int top, int w, bool acti
void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) {
auto history = row->history(); auto history = row->history();
auto item = history->lastMsg; auto item = history->lastMsg;
paintRow(p, history, item, w, active, selected, onlyBackground, [&p, w, active, history, item](int nameleft, int namewidth) { paintRow(p, history, item, w, active, selected, onlyBackground, [&p, w, active, history](int nameleft, int namewidth, HistoryItem *item) {
int32 unread = history->unreadCount(); int32 unread = history->unreadCount();
if (history->peer->migrateFrom()) { if (history->peer->migrateFrom()) {
if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) { if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) {
@ -219,7 +219,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground) { void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground) {
auto item = row->item(); auto item = row->item();
auto history = item->history(); auto history = item->history();
paintRow(p, history, item, w, active, selected, onlyBackground, [&p, row, active, item](int nameleft, int namewidth) { paintRow(p, history, item, w, active, selected, onlyBackground, [&p, row, active](int nameleft, int namewidth, HistoryItem *item) {
int lastWidth = namewidth, texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep; int lastWidth = namewidth, texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep;
item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dlgFont->height), active, row->_cacheFor, row->_cache); item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dlgFont->height), active, row->_cacheFor, row->_cache);
}); });

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "ui/text.h" #include "ui/text/text.h"
class History; class History;
class HistoryItem; class HistoryItem;

View file

@ -26,13 +26,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/style.h" #include "ui/style.h"
#include "lang.h" #include "lang.h"
#include "application.h" #include "application.h"
#include "window.h" #include "mainwindow.h"
#include "dialogswidget.h" #include "dialogswidget.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "boxes/addcontactbox.h" #include "boxes/addcontactbox.h"
#include "boxes/contactsbox.h" #include "boxes/contactsbox.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "localstorage.h" #include "localstorage.h"
#include "apiwrap.h"
DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(parent) DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(parent)
, dialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date)) , dialogs(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Date))
@ -1027,7 +1028,7 @@ void DialogsInner::dialogsReceived(const QVector<MTPDialog> &added) {
} }
} }
if (App::wnd()) App::wnd()->updateCounter(); Notify::unreadCounterUpdated();
if (!_sel && !shownDialogs()->isEmpty()) { if (!_sel && !shownDialogs()->isEmpty()) {
_sel = *shownDialogs()->cbegin(); _sel = *shownDialogs()->cbegin();
_importantSwitchSel = false; _importantSwitchSel = false;
@ -1935,7 +1936,7 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) { if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) {
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h);
if (d.vunread_count.v >= h->unreadCount()) { if (d.vunread_count.v >= h->unreadCount()) {
h->setUnreadCount(d.vunread_count.v, false); h->setUnreadCount(d.vunread_count.v);
h->inboxReadBefore = d.vread_inbox_max_id.v + 1; h->inboxReadBefore = d.vread_inbox_max_id.v + 1;
} }
} }
@ -1953,14 +1954,13 @@ void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h);
int32 unreadCount = h->isMegagroup() ? d.vunread_count.v : d.vunread_important_count.v; int32 unreadCount = h->isMegagroup() ? d.vunread_count.v : d.vunread_important_count.v;
if (unreadCount >= h->unreadCount()) { if (unreadCount >= h->unreadCount()) {
h->setUnreadCount(unreadCount, false); h->setUnreadCount(unreadCount);
h->inboxReadBefore = d.vread_inbox_max_id.v + 1; h->inboxReadBefore = d.vread_inbox_max_id.v + 1;
} }
} }
} break; } break;
} }
} }
if (App::wnd()) App::wnd()->updateCounter();
} }
void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpRequestId req) { void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpRequestId req) {

View file

@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "historywidget.h" #include "historywidget.h"
#include "localstorage.h" #include "localstorage.h"
#include "lang.h" #include "lang.h"
#include "window.h" #include "mainwindow.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "mainwidget.h" #include "mainwidget.h"
@ -1349,7 +1349,7 @@ void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) {
int w = item->width(); int w = item->width();
if (left + w > fromx) { if (left + w > fromx) {
p.translate(left, top); p.translate(left, top);
item->paint(p, r.translated(-left, -top), 0, &context); item->paint(p, r.translated(-left, -top), &context);
p.translate(-left, -top); p.translate(-left, -top);
} }
left += w; left += w;

View file

@ -20,12 +20,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "application.h" #include "application.h"
#include "core/click_handler_types.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "layerwidget.h" #include "layerwidget.h"
#include "lang.h" #include "lang.h"
@ -34,12 +33,16 @@ Q_DECLARE_METATYPE(Qt::MouseButton);
namespace App { namespace App {
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) {
if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo); if (auto m = main()) {
m->sendBotCommand(peer, bot, cmd, replyTo);
}
} }
bool insertBotCommand(const QString &cmd, bool specialGif) { bool insertBotCommand(const QString &cmd, bool specialGif) {
if (MainWidget *m = main()) return m->insertBotCommand(cmd, specialGif); if (auto m = main()) {
return m->insertBotCommand(cmd, specialGif);
}
return false; return false;
} }
@ -60,7 +63,7 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) {
// Copy string before passing it to the sending method // Copy string before passing it to the sending method
// because the original button can be destroyed inside. // because the original button can be destroyed inside.
MsgId replyTo = (msg->id > 0) ? msg->id : 0; MsgId replyTo = (msg->id > 0) ? msg->id : 0;
sendBotCommand(msg->history()->peer, QString(button->text), replyTo); sendBotCommand(msg->history()->peer, msg->fromOriginal()->asUser(), QString(button->text), replyTo);
} break; } break;
case HistoryMessageReplyMarkup::Button::Callback: { case HistoryMessageReplyMarkup::Button::Callback: {
@ -136,13 +139,13 @@ void removeDialog(History *history) {
} }
void showSettings() { void showSettings() {
if (Window *w = wnd()) { if (auto w = wnd()) {
w->showSettings(); w->showSettings();
} }
} }
void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
if (Window *w = wnd()) { if (auto w = wnd()) {
qRegisterMetaType<ClickHandlerPtr>(); qRegisterMetaType<ClickHandlerPtr>();
qRegisterMetaType<Qt::MouseButton>(); qRegisterMetaType<Qt::MouseButton>();
QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button)); QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button));
@ -150,7 +153,7 @@ void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
} }
void logOutDelayed() { void logOutDelayed() {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection); QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection);
} }
} }
@ -160,25 +163,25 @@ void logOutDelayed() {
namespace Ui { namespace Ui {
void showMediaPreview(DocumentData *document) { void showMediaPreview(DocumentData *document) {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
w->ui_showMediaPreview(document); w->ui_showMediaPreview(document);
} }
} }
void showMediaPreview(PhotoData *photo) { void showMediaPreview(PhotoData *photo) {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
w->ui_showMediaPreview(photo); w->ui_showMediaPreview(photo);
} }
} }
void hideMediaPreview() { void hideMediaPreview() {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
w->ui_hideMediaPreview(); w->ui_hideMediaPreview();
} }
} }
void showLayer(LayeredWidget *box, ShowLayerOptions options) { void showLayer(LayeredWidget *box, ShowLayerOptions options) {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
w->ui_showLayer(box, options); w->ui_showLayer(box, options);
} else { } else {
delete box; delete box;
@ -186,16 +189,16 @@ void showLayer(LayeredWidget *box, ShowLayerOptions options) {
} }
void hideLayer(bool fast) { void hideLayer(bool fast) {
if (Window *w = App::wnd()) w->ui_showLayer(0, ShowLayerOptions(CloseOtherLayers) | (fast ? ForceFastShowLayer : AnimatedShowLayer)); if (auto w = App::wnd()) w->ui_showLayer(0, ShowLayerOptions(CloseOtherLayers) | (fast ? ForceFastShowLayer : AnimatedShowLayer));
} }
bool isLayerShown() { bool isLayerShown() {
if (Window *w = App::wnd()) return w->ui_isLayerShown(); if (auto w = App::wnd()) return w->ui_isLayerShown();
return false; return false;
} }
bool isMediaViewShown() { bool isMediaViewShown() {
if (Window *w = App::wnd()) return w->ui_isMediaViewShown(); if (auto w = App::wnd()) return w->ui_isMediaViewShown();
return false; return false;
} }
@ -236,7 +239,7 @@ void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) {
} }
PeerData *getPeerForMouseAction() { PeerData *getPeerForMouseAction() {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
return w->ui_getPeerForMouseAction(); return w->ui_getPeerForMouseAction();
} }
return nullptr; return nullptr;
@ -244,7 +247,7 @@ PeerData *getPeerForMouseAction() {
bool hideWindowNoQuit() { bool hideWindowNoQuit() {
if (!App::quitting()) { if (!App::quitting()) {
if (Window *w = App::wnd()) { if (auto w = App::wnd()) {
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
return w->minimizeToTray(); return w->minimizeToTray();
} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { } else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
@ -327,6 +330,10 @@ void handlePendingHistoryUpdate() {
Global::RefPendingRepaintItems().clear(); Global::RefPendingRepaintItems().clear();
} }
void unreadCounterUpdated() {
Global::RefHandleUnreadCounterUpdate().call();
}
} // namespace Notify } // namespace Notify
#define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \ #define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \
@ -480,6 +487,7 @@ namespace internal {
struct Data { struct Data {
uint64 LaunchId = 0; uint64 LaunchId = 0;
SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" }; SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" };
SingleDelayedCall HandleUnreadCounterUpdate = { App::app(), "call_handleUnreadCounterUpdate" };
Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout; Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout;
bool AdaptiveForWide = true; bool AdaptiveForWide = true;
@ -542,6 +550,7 @@ void finish() {
DefineReadOnlyVar(Global, uint64, LaunchId); DefineReadOnlyVar(Global, uint64, LaunchId);
DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate); DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate);
DefineRefVar(Global, SingleDelayedCall, HandleUnreadCounterUpdate);
DefineVar(Global, Adaptive::Layout, AdaptiveLayout); DefineVar(Global, Adaptive::Layout, AdaptiveLayout);
DefineVar(Global, bool, AdaptiveForWide); DefineVar(Global, bool, AdaptiveForWide);

View file

@ -24,7 +24,7 @@ class LayeredWidget;
namespace App { namespace App {
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo = 0); void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo = 0);
bool insertBotCommand(const QString &cmd, bool specialGif = false); bool insertBotCommand(const QString &cmd, bool specialGif = false);
void activateBotCommand(const HistoryItem *msg, int row, int col); void activateBotCommand(const HistoryItem *msg, int row, int col);
void searchByHashtag(const QString &tag, PeerData *inPeer); void searchByHashtag(const QString &tag, PeerData *inPeer);
@ -116,6 +116,7 @@ void historyMuteUpdated(History *history);
// handle pending resize() / paint() on history items // handle pending resize() / paint() on history items
void handlePendingHistoryUpdate(); void handlePendingHistoryUpdate();
void unreadCounterUpdated();
} // namespace Notify } // namespace Notify
@ -184,6 +185,7 @@ void finish();
DeclareReadOnlyVar(uint64, LaunchId); DeclareReadOnlyVar(uint64, LaunchId);
DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate); DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate);
DeclareRefVar(SingleDelayedCall, HandleUnreadCounterUpdate);
DeclareVar(Adaptive::Layout, AdaptiveLayout); DeclareVar(Adaptive::Layout, AdaptiveLayout);
DeclareVar(bool, AdaptiveForWide); DeclareVar(bool, AdaptiveForWide);

File diff suppressed because it is too large Load diff

View file

@ -255,7 +255,7 @@ public:
int unreadCount() const { int unreadCount() const {
return _unreadCount; return _unreadCount;
} }
void setUnreadCount(int newUnreadCount, bool psUpdate = true); void setUnreadCount(int newUnreadCount);
bool mute() const { bool mute() const {
return _mute; return _mute;
} }
@ -642,7 +642,7 @@ private:
HistoryItem *findPrevItem(HistoryItem *item) const; HistoryItem *findPrevItem(HistoryItem *item) const;
void switchMode(); void switchMode();
void cleared(); void cleared(bool leaveItems);
bool _onlyImportant; bool _onlyImportant;
@ -729,7 +729,7 @@ protected:
}; };
class HistoryMessage; // dynamic_cast optimize class HistoryMessage;
enum HistoryCursorState { enum HistoryCursorState {
HistoryDefaultCursorState, HistoryDefaultCursorState,
@ -738,6 +738,36 @@ enum HistoryCursorState {
HistoryInForwardedCursorState, HistoryInForwardedCursorState,
}; };
struct HistoryTextState {
HistoryTextState() = default;
HistoryTextState(const Text::StateResult &state)
: cursor(state.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState)
, link(state.link)
, afterSymbol(state.afterSymbol)
, symbol(state.symbol) {
}
HistoryTextState &operator=(const Text::StateResult &state) {
cursor = state.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState;
link = state.link;
afterSymbol = state.afterSymbol;
symbol = state.symbol;
return *this;
}
HistoryCursorState cursor = HistoryDefaultCursorState;
ClickHandlerPtr link;
bool afterSymbol = false;
uint16 symbol = 0;
};
struct HistoryStateRequest {
Text::StateRequest::Flags flags = Text::StateRequest::Flag::LookupLink;
Text::StateRequest forText() const {
Text::StateRequest result;
result.flags = flags;
return result;
}
};
enum InfoDisplayType { enum InfoDisplayType {
InfoDisplayDefault, InfoDisplayDefault,
InfoDisplayOverImage, InfoDisplayOverImage,
@ -936,7 +966,7 @@ public:
int naturalHeight() const; int naturalHeight() const;
void paint(Painter &p, const QRect &clip) const; void paint(Painter &p, const QRect &clip) const;
void getState(ClickHandlerPtr &lnk, int x, int y) const; ClickHandlerPtr getState(int x, int y) const;
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active); void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active);
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed); void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed);
@ -1052,6 +1082,14 @@ private:
}; };
namespace internal {
TextSelection unshiftSelection(TextSelection selection, const Text &byText);
TextSelection shiftSelection(TextSelection selection, const Text &byText);
} // namespace internal
class HistoryItem : public HistoryElem, public Composer, public ClickHandlerHost { class HistoryItem : public HistoryElem, public Composer, public ClickHandlerHost {
public: public:
@ -1068,7 +1106,7 @@ public:
} }
return resizeGetHeight_(width); return resizeGetHeight_(width);
} }
virtual void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const = 0; virtual void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const = 0;
virtual void dependencyItemRemoved(HistoryItem *dependency) { virtual void dependencyItemRemoved(HistoryItem *dependency) {
} }
@ -1216,17 +1254,11 @@ public:
virtual bool hasPoint(int x, int y) const { virtual bool hasPoint(int x, int y) const {
return false; return false;
} }
virtual void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const {
lnk.clear(); virtual HistoryTextState getState(int x, int y, HistoryStateRequest request) const = 0;
state = HistoryDefaultCursorState;
} virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const {
virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { // from text return selection;
upon = hasPoint(x, y);
symbol = upon ? 0xFFFF : 0;
after = false;
}
virtual uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const {
return (from << 16) | to;
} }
// ClickHandlerHost interface // ClickHandlerHost interface
@ -1251,7 +1283,7 @@ public:
} }
virtual void previousItemChanged(); virtual void previousItemChanged();
virtual QString selectedText(uint32 selection) const { virtual QString selectedText(TextSelection selection) const {
return qsl("[-]"); return qsl("[-]");
} }
virtual QString inDialogsText() const { virtual QString inDialogsText() const {
@ -1514,6 +1546,13 @@ protected:
return const_cast<ReplyKeyboard*>(static_cast<const HistoryItem*>(this)->inlineReplyKeyboard()); return const_cast<ReplyKeyboard*>(static_cast<const HistoryItem*>(this)->inlineReplyKeyboard());
} }
TextSelection toMediaSelection(TextSelection selection) const {
return internal::unshiftSelection(selection, _text);
}
TextSelection fromMediaSelection(TextSelection selection) const {
return internal::shiftSelection(selection, _text);
}
Text _text = { int(st::msgMinWidth) }; Text _text = { int(st::msgMinWidth) };
int32 _textWidth, _textHeight; int32 _textWidth, _textHeight;
@ -1609,8 +1648,8 @@ public:
HistoryMedia &operator=(const HistoryMedia &other) = delete; HistoryMedia &operator=(const HistoryMedia &other) = delete;
virtual HistoryMediaType type() const = 0; virtual HistoryMediaType type() const = 0;
virtual const QString inDialogsText() const = 0; virtual QString inDialogsText() const = 0;
virtual const QString inHistoryText() const = 0; virtual QString selectedText(TextSelection selection) const = 0;
bool hasPoint(int x, int y) const { bool hasPoint(int x, int y) const {
return (x >= 0 && y >= 0 && x < _width && y < _height); return (x >= 0 && y >= 0 && x < _width && y < _height);
@ -1624,8 +1663,8 @@ public:
_width = qMin(width, _maxw); _width = qMin(width, _maxw);
return _height; return _height;
} }
virtual void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const = 0; virtual void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const = 0;
virtual void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const = 0; virtual HistoryTextState getState(int x, int y, HistoryStateRequest request) const = 0;
// if we are in selecting items mode perhaps we want to // if we are in selecting items mode perhaps we want to
// toggle selection instead of activating the pressed link // toggle selection instead of activating the pressed link
@ -1636,6 +1675,10 @@ public:
return false; return false;
} }
virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const {
return selection;
}
// if we press and drag this link should we drag the item // if we press and drag this link should we drag the item
virtual bool dragItemByHandler(const ClickHandlerPtr &p) const = 0; virtual bool dragItemByHandler(const ClickHandlerPtr &p) const = 0;
@ -1829,11 +1872,15 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
const QString inDialogsText() const override; TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
const QString inHistoryText() const override; return _caption.adjustSelection(selection, type);
}
QString inDialogsText() const override;
QString selectedText(TextSelection selection) const override;
PhotoData *photo() const { PhotoData *photo() const {
return _data; return _data;
@ -1902,11 +1949,15 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
const QString inDialogsText() const override; TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
const QString inHistoryText() const override; return _caption.adjustSelection(selection, type);
}
QString inDialogsText() const override;
QString selectedText(TextSelection selection) const override;
DocumentData *getDocument() override { DocumentData *getDocument() override {
return _data; return _data;
@ -2015,11 +2066,18 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
const QString inDialogsText() const override; TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
const QString inHistoryText() const override; if (auto captioned = Get<HistoryDocumentCaptioned>()) {
return captioned->_caption.adjustSelection(selection, type);
}
return selection;
}
QString inDialogsText() const override;
QString selectedText(TextSelection selection) const override;
bool uploading() const override { bool uploading() const override {
return _data->uploading(); return _data->uploading();
@ -2095,11 +2153,15 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
const QString inDialogsText() const override; TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
const QString inHistoryText() const override; return _caption.adjustSelection(selection, type);
}
QString inDialogsText() const override;
QString selectedText(TextSelection selection) const override;
bool uploading() const override { bool uploading() const override {
return _data->uploading(); return _data->uploading();
@ -2183,8 +2245,8 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return true; return true;
@ -2196,8 +2258,8 @@ public:
return true; return true;
} }
const QString inDialogsText() const override; QString inDialogsText() const override;
const QString inHistoryText() const override; QString selectedText(TextSelection selection) const override;
DocumentData *getDocument() override { DocumentData *getDocument() override {
return _data; return _data;
@ -2255,8 +2317,8 @@ public:
void initDimensions() override; void initDimensions() override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return true; return true;
@ -2265,8 +2327,8 @@ public:
return true; return true;
} }
const QString inDialogsText() const override; QString inDialogsText() const override;
const QString inHistoryText() const override; QString selectedText(TextSelection selection) const override;
void attachToParent() override; void attachToParent() override;
void detachFromParent() override; void detachFromParent() override;
@ -2318,8 +2380,10 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return _attach && _attach->toggleSelectionByHandlerClick(p); return _attach && _attach->toggleSelectionByHandlerClick(p);
@ -2328,8 +2392,8 @@ public:
return _attach && _attach->dragItemByHandler(p); return _attach && _attach->dragItemByHandler(p);
} }
const QString inDialogsText() const override; QString inDialogsText() const override;
const QString inHistoryText() const override; QString selectedText(TextSelection selection) const override;
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
@ -2376,6 +2440,13 @@ public:
~HistoryWebPage(); ~HistoryWebPage();
private: private:
TextSelection toDescriptionSelection(TextSelection selection) const {
return internal::unshiftSelection(selection, _title);
}
TextSelection fromDescriptionSelection(TextSelection selection) const {
return internal::shiftSelection(selection, _title);
}
WebPageData *_data; WebPageData *_data;
ClickHandlerPtr _openl; ClickHandlerPtr _openl;
HistoryMedia *_attach; HistoryMedia *_attach;
@ -2396,17 +2467,8 @@ void initImageLinkManager();
void reinitImageLinkManager(); void reinitImageLinkManager();
void deinitImageLinkManager(); void deinitImageLinkManager();
struct LocationData { struct LocationCoords;
LocationData(const LocationCoords &coords) : coords(coords), loading(false) { struct LocationData;
}
LocationCoords coords;
ImagePtr thumb;
bool loading;
void load();
};
class LocationManager : public QObject { class LocationManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
@ -2449,8 +2511,10 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int32 width) override; int resizeGetHeight(int32 width) override;
void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
return p == _link; return p == _link;
@ -2459,8 +2523,8 @@ public:
return p == _link; return p == _link;
} }
const QString inDialogsText() const override; QString inDialogsText() const override;
const QString inHistoryText() const override; QString selectedText(TextSelection selection) const override;
bool needsBubble() const override { bool needsBubble() const override {
if (!_title.isEmpty() || !_description.isEmpty()) { if (!_title.isEmpty() || !_description.isEmpty()) {
@ -2476,6 +2540,13 @@ public:
} }
private: private:
TextSelection toDescriptionSelection(TextSelection selection) const {
return internal::unshiftSelection(selection, _title);
}
TextSelection fromDescriptionSelection(TextSelection selection) const {
return internal::shiftSelection(selection, _title);
}
LocationData *_data; LocationData *_data;
Text _title, _description; Text _title, _description;
ClickHandlerPtr _link; ClickHandlerPtr _link;
@ -2547,7 +2618,7 @@ public:
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override; void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
void setViewsCount(int32 count) override; void setViewsCount(int32 count) override;
void setId(MsgId newId) override; void setId(MsgId newId) override;
void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void dependencyItemRemoved(HistoryItem *dependency) override; void dependencyItemRemoved(HistoryItem *dependency) override;
@ -2556,12 +2627,9 @@ public:
bool hasPoint(int x, int y) const override; bool hasPoint(int x, int y) const override;
bool pointInTime(int32 right, int32 bottom, int x, int y, InfoDisplayType type) const override; bool pointInTime(int32 right, int32 bottom, int x, int y, InfoDisplayType type) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const override; TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override {
return _text.adjustSelection(from, to, type);
}
// ClickHandlerHost interface // ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override { void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
@ -2569,7 +2637,7 @@ public:
HistoryItem::clickHandlerActiveChanged(p, active); HistoryItem::clickHandlerActiveChanged(p, active);
} }
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override { void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override {
if (_media) _media->clickHandlerActiveChanged(p, pressed); if (_media) _media->clickHandlerPressedChanged(p, pressed);
HistoryItem::clickHandlerPressedChanged(p, pressed); HistoryItem::clickHandlerPressedChanged(p, pressed);
} }
@ -2582,7 +2650,7 @@ public:
int32 addToOverview(AddToOverviewMethod method) override; int32 addToOverview(AddToOverviewMethod method) override;
void eraseFromOverview(); void eraseFromOverview();
QString selectedText(uint32 selection) const override; QString selectedText(TextSelection selection) const override;
QString inDialogsText() const override; QString inDialogsText() const override;
HistoryMedia *getMedia() const override; HistoryMedia *getMedia() const override;
void setText(const QString &text, const EntitiesInText &entities) override; void setText(const QString &text, const EntitiesInText &entities) override;
@ -2772,12 +2840,12 @@ public:
void countPositionAndSize(int32 &left, int32 &width) const; void countPositionAndSize(int32 &left, int32 &width) const;
void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
bool hasPoint(int x, int y) const override; bool hasPoint(int x, int y) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const override;
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override { TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
return _text.adjustSelection(from, to, type); return _text.adjustSelection(selection, type);
} }
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override { void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override {
@ -2798,7 +2866,7 @@ public:
bool serviceMsg() const override { bool serviceMsg() const override {
return true; return true;
} }
QString selectedText(uint32 selection) const override; QString selectedText(TextSelection selection) const override;
QString inDialogsText() const override; QString inDialogsText() const override;
QString inReplyText() const override; QString inReplyText() const override;
@ -2833,16 +2901,12 @@ public:
return _create(history, newItem, date); return _create(history, newItem, date);
} }
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const {
symbol = 0xFFFF; QString selectedText(TextSelection selection) const override {
after = false;
upon = false;
}
QString selectedText(uint32 selection) const {
return QString(); return QString();
} }
HistoryItemType type() const { HistoryItemType type() const override {
return HistoryItemGroup; return HistoryItemGroup;
} }
void uniteWith(MsgId minId, MsgId maxId, int32 count); void uniteWith(MsgId minId, MsgId maxId, int32 count);
@ -2886,17 +2950,13 @@ public:
return _create(history, wasMinId, date); return _create(history, wasMinId, date);
} }
void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const; HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const {
symbol = 0xFFFF; QString selectedText(TextSelection selection) const override {
after = false;
upon = false;
}
QString selectedText(uint32 selection) const {
return QString(); return QString();
} }
HistoryItemType type() const { HistoryItemType type() const override {
return HistoryItemCollapse; return HistoryItemCollapse;
} }
MsgId wasMinId() const { MsgId wasMinId() const {

View file

@ -0,0 +1,28 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
enum DragState {
DragStateNone = 0x00,
DragStateFiles = 0x01,
DragStatePhotoFiles = 0x02,
DragStateImage = 0x03,
};

View file

@ -30,12 +30,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "lang.h" #include "lang.h"
#include "application.h" #include "application.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "passcodewidget.h" #include "passcodewidget.h"
#include "window.h" #include "mainwindow.h"
#include "fileuploader.h" #include "fileuploader.h"
#include "audio.h" #include "audio.h"
#include "localstorage.h" #include "localstorage.h"
#include "apiwrap.h"
#include "window/top_bar_widget.h"
#include "playerwidget.h"
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -249,11 +252,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p.save(); p.save();
p.translate(0, y); p.translate(0, y);
if (r.y() < y + item->height()) while (y < drawToY) { if (r.y() < y + item->height()) while (y < drawToY) {
uint32 sel = 0; TextSelection sel;
if (y >= selfromy && y < seltoy) { if (y >= selfromy && y < seltoy) {
sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullSelection : 0; if (_dragSelecting && !item->serviceMsg() && item->id > 0) {
sel = FullSelection;
}
} else if (hasSel) { } else if (hasSel) {
SelectedItems::const_iterator i = _selected.constFind(item); auto i = _selected.constFind(item);
if (i != selEnd) { if (i != selEnd) {
sel = i.value(); sel = i.value();
} }
@ -294,11 +299,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
while (y < drawToY) { while (y < drawToY) {
int32 h = item->height(); int32 h = item->height();
if (historyRect.y() < y + h && hdrawtop < y + h) { if (historyRect.y() < y + h && hdrawtop < y + h) {
uint32 sel = 0; TextSelection sel;
if (y >= selfromy && y < seltoy) { if (y >= selfromy && y < seltoy) {
sel = (_dragSelecting && !item->serviceMsg() && item->id > 0) ? FullSelection : 0; if (_dragSelecting && !item->serviceMsg() && item->id > 0) {
sel = FullSelection;
}
} else if (hasSel) { } else if (hasSel) {
SelectedItems::const_iterator i = _selected.constFind(item); auto i = _selected.constFind(item);
if (i != selEnd) { if (i != selEnd) {
sel = i.value(); sel = i.value();
} }
@ -585,19 +592,20 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
} }
} }
if (_dragAction == NoDrag && _dragItem) { if (_dragAction == NoDrag && _dragItem) {
bool afterDragSymbol, uponSymbol; HistoryTextState dragState;
uint16 symbol;
if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) {
_dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); HistoryStateRequest request;
if (uponSymbol) { request.flags = Text::StateRequest::Flag::LookupSymbol;
uint32 selStatus = (symbol << 16) | symbol; dragState = _dragItem->getState(_dragStartPos.x(), _dragStartPos.y(), request);
if (dragState.cursor == HistoryInTextCursorState) {
TextSelection selStatus = { dragState.symbol, dragState.symbol };
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
repaintItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
_selected.clear(); _selected.clear();
} }
_selected.insert(_dragItem, selStatus); _selected.insert(_dragItem, selStatus);
_dragSymbol = symbol; _dragSymbol = dragState.symbol;
_dragAction = Selecting; _dragAction = Selecting;
_dragSelType = TextSelectParagraphs; _dragSelType = TextSelectParagraphs;
dragActionUpdate(_dragPos); dragActionUpdate(_dragPos);
@ -605,12 +613,14 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
} }
} }
} else if (App::pressedItem()) { } else if (App::pressedItem()) {
_dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); HistoryStateRequest request;
request.flags = Text::StateRequest::Flag::LookupSymbol;
dragState = _dragItem->getState(_dragStartPos.x(), _dragStartPos.y(), request);
} }
if (_dragSelType != TextSelectParagraphs) { if (_dragSelType != TextSelectParagraphs) {
if (App::pressedItem()) { if (App::pressedItem()) {
_dragSymbol = symbol; _dragSymbol = dragState.symbol;
bool uponSelected = uponSymbol; bool uponSelected = (dragState.cursor == HistoryInTextCursorState);
if (uponSelected) { if (uponSelected) {
if (_selected.isEmpty() || if (_selected.isEmpty() ||
_selected.cbegin().value() == FullSelection || _selected.cbegin().value() == FullSelection ||
@ -618,7 +628,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
) { ) {
uponSelected = false; uponSelected = false;
} else { } else {
uint16 selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; uint16 selFrom = _selected.cbegin().value().from, selTo = _selected.cbegin().value().to;
if (_dragSymbol < selFrom || _dragSymbol >= selTo) { if (_dragSymbol < selFrom || _dragSymbol >= selTo) {
uponSelected = false; uponSelected = false;
} }
@ -630,8 +640,8 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt
if (dynamic_cast<HistorySticker*>(App::pressedItem()->getMedia()) || _dragCursorState == HistoryInDateCursorState) { if (dynamic_cast<HistorySticker*>(App::pressedItem()->getMedia()) || _dragCursorState == HistoryInDateCursorState) {
_dragAction = PrepareDrag; // start sticker drag or by-date drag _dragAction = PrepareDrag; // start sticker drag or by-date drag
} else { } else {
if (afterDragSymbol) ++_dragSymbol; if (dragState.afterSymbol) ++_dragSymbol;
uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; TextSelection selStatus = { _dragSymbol, _dragSymbol };
if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
repaintItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
@ -672,12 +682,13 @@ void HistoryInner::onDragExec() {
bool uponSelected = false; bool uponSelected = false;
if (_dragItem) { if (_dragItem) {
bool afterDragSymbol;
uint16 symbol;
if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) {
uponSelected = _selected.contains(_dragItem); uponSelected = _selected.contains(_dragItem);
} else { } else {
_dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); HistoryStateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = _dragItem->getState(_dragStartPos.x(), _dragStartPos.y(), request);
uponSelected = (dragState.cursor == HistoryInTextCursorState);
if (uponSelected) { if (uponSelected) {
if (_selected.isEmpty() || if (_selected.isEmpty() ||
_selected.cbegin().value() == FullSelection || _selected.cbegin().value() == FullSelection ||
@ -685,8 +696,8 @@ void HistoryInner::onDragExec() {
) { ) {
uponSelected = false; uponSelected = false;
} else { } else {
uint16 selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; uint16 selFrom = _selected.cbegin().value().from, selTo = _selected.cbegin().value().to;
if (symbol < selFrom || symbol >= selTo) { if (dragState.symbol < selFrom || dragState.symbol >= selTo) {
uponSelected = false; uponSelected = false;
} }
} }
@ -838,8 +849,8 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but
applyDragSelection(); applyDragSelection();
_dragSelFrom = _dragSelTo = 0; _dragSelFrom = _dragSelTo = 0;
} else if (!_selected.isEmpty() && !_dragWasInactive) { } else if (!_selected.isEmpty() && !_dragWasInactive) {
uint32 sel = _selected.cbegin().value(); auto sel = _selected.cbegin().value();
if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { if (sel != FullSelection && sel.from == sel.to) {
_selected.clear(); _selected.clear();
if (App::wnd()) App::wnd()->setInnerFocus(); if (App::wnd()) App::wnd()->setInnerFocus();
} }
@ -864,15 +875,15 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) {
dragActionStart(e->globalPos(), e->button()); dragActionStart(e->globalPos(), e->button());
if (((_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) || (_dragAction == NoDrag && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection))) && _dragSelType == TextSelectLetters && _dragItem) { if (((_dragAction == Selecting && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) || (_dragAction == NoDrag && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection))) && _dragSelType == TextSelectLetters && _dragItem) {
bool afterDragSymbol, uponSelected; HistoryStateRequest request;
uint16 symbol; request.flags |= Text::StateRequest::Flag::LookupSymbol;
_dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); auto dragState = _dragItem->getState(_dragStartPos.x(), _dragStartPos.y(), request);
if (uponSelected) { if (dragState.cursor == HistoryInTextCursorState) {
_dragSymbol = symbol; _dragSymbol = dragState.symbol;
_dragSelType = TextSelectWords; _dragSelType = TextSelectWords;
if (_dragAction == NoDrag) { if (_dragAction == NoDrag) {
_dragAction = Selecting; _dragAction = Selecting;
uint32 selStatus = (symbol << 16) | symbol; TextSelection selStatus = { dragState.symbol, dragState.symbol };
if (!_selected.isEmpty()) { if (!_selected.isEmpty()) {
repaintItem(_selected.cbegin().key()); repaintItem(_selected.cbegin().key());
_selected.clear(); _selected.clear();
@ -912,13 +923,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
isUponSelected = -2; isUponSelected = -2;
} }
} else { } else {
uint16 symbol, selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; uint16 selFrom = _selected.cbegin().value().from, selTo = _selected.cbegin().value().to;
hasSelected = (selTo > selFrom) ? 1 : 0; hasSelected = (selTo > selFrom) ? 1 : 0;
if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) {
QPoint mousePos(mapMouseToItem(mapFromGlobal(_dragPos), App::mousedItem())); QPoint mousePos(mapMouseToItem(mapFromGlobal(_dragPos), App::mousedItem()));
bool afterDragSymbol, uponSymbol; HistoryStateRequest request;
App::mousedItem()->getSymbol(symbol, afterDragSymbol, uponSymbol, mousePos.x(), mousePos.y()); request.flags |= Text::StateRequest::Flag::LookupSymbol;
if (uponSymbol && symbol >= selFrom && symbol < selTo) { auto dragState = App::mousedItem()->getState(mousePos.x(), mousePos.y(), request);
if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) {
isUponSelected = 1; isUponSelected = 1;
} }
} }
@ -1054,7 +1066,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
} }
} }
QString contextMenuText = item->selectedText(FullSelection); QString contextMenuText = item->selectedText(FullSelection);
if (!contextMenuText.isEmpty() && (!msg || !msg->getMedia() || (msg->getMedia()->type() != MediaTypeSticker && msg->getMedia()->type() != MediaTypeGif))) { if (!contextMenuText.isEmpty() && msg && !msg->getMedia()) {
_menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true); _menu->addAction(lang(lng_context_copy_text), this, SLOT(copyContextText()))->setEnabled(true);
} }
} }
@ -1489,7 +1501,7 @@ void HistoryInner::updateSize() {
void HistoryInner::enterEvent(QEvent *e) { void HistoryInner::enterEvent(QEvent *e) {
dragActionUpdate(QCursor::pos()); dragActionUpdate(QCursor::pos());
return QWidget::enterEvent(e); // return QWidget::enterEvent(e);
} }
void HistoryInner::leaveEvent(QEvent *e) { void HistoryInner::leaveEvent(QEvent *e) {
@ -1522,6 +1534,7 @@ void HistoryInner::adjustCurrent(int32 y) const {
} }
void HistoryInner::adjustCurrent(int32 y, History *history) const { void HistoryInner::adjustCurrent(int32 y, History *history) const {
t_assert(!history->isEmpty());
_curHistory = history; _curHistory = history;
if (_curBlock >= history->blocks.size()) { if (_curBlock >= history->blocks.size()) {
_curBlock = history->blocks.size() - 1; _curBlock = history->blocks.size() - 1;
@ -1681,57 +1694,13 @@ void HistoryInner::onUpdateSelected() {
dragActionCancel(); dragActionCancel();
} }
ClickHandlerPtr lnk; HistoryTextState dragState;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
HistoryCursorState cursorState = HistoryDefaultCursorState; bool selectingText = (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection);
if (point.y() < _historyOffset) { if (point.y() < _historyOffset) {
if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) { if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
bool inText = false; dragState = _botAbout->info->text.getState(point.x() - _botAbout->rect.left() - st::msgPadding.left(), point.y() - _botAbout->rect.top() - st::msgPadding.top() - st::botDescSkip - st::msgNameFont->height, _botAbout->width);
_botAbout->info->text.getState(lnk, inText, point.x() - _botAbout->rect.left() - st::msgPadding.left(), point.y() - _botAbout->rect.top() - st::msgPadding.top() - st::botDescSkip - st::msgNameFont->height, _botAbout->width);
lnkhost = _botAbout.get(); lnkhost = _botAbout.get();
cursorState = inText ? HistoryInTextCursorState : HistoryDefaultCursorState;
}
} else if (item) {
item->getState(lnk, cursorState, m.x(), m.y());
lnkhost = item;
if (!lnk && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) {
if (HistoryMessage *msg = item->toHistoryMessage()) {
if (msg->hasFromPhoto()) {
enumerateUserpics([&lnk, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
// stop enumeration if the userpic is above our point
if (userpicTop + st::msgPhotoSize <= point.y()) {
return false;
}
// stop enumeration if we've found a userpic under the cursor
if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) {
lnk = message->from()->openLink();
lnkhost = message;
return false;
}
return true;
});
}
}
}
}
bool lnkChanged = ClickHandler::setActive(lnk, lnkhost);
if (lnkChanged || cursorState != _dragCursorState) {
PopupTooltip::Hide();
}
if (lnk || cursorState == HistoryInDateCursorState || cursorState == HistoryInForwardedCursorState) {
PopupTooltip::Show(1000, this);
}
Qt::CursorShape cur = style::cur_default;
if (_dragAction == NoDrag) {
_dragCursorState = cursorState;
if (lnk) {
cur = style::cur_pointer;
} else if (_dragCursorState == HistoryInTextCursorState && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
cur = style::cur_text;
} else if (_dragCursorState == HistoryInDateCursorState) {
// cur = style::cur_cross;
} }
} else if (item) { } else if (item) {
if (item != _dragItem || (m - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()) { if (item != _dragItem || (m - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()) {
@ -1742,19 +1711,68 @@ void HistoryInner::onUpdateSelected() {
_dragAction = Selecting; _dragAction = Selecting;
} }
} }
HistoryStateRequest request;
if (_dragAction == Selecting) { if (_dragAction == Selecting) {
bool canSelectMany = (_history != 0); request.flags |= Text::StateRequest::Flag::LookupSymbol;
if (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { } else {
bool afterSymbol, uponSymbol; selectingText = false;
uint16 second; }
_dragItem->getSymbol(second, afterSymbol, uponSymbol, m.x(), m.y()); dragState = item->getState(m.x(), m.y(), request);
if (afterSymbol && _dragSelType == TextSelectLetters) ++second; lnkhost = item;
uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType); if (!dragState.link && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) {
if (HistoryMessage *msg = item->toHistoryMessage()) {
if (msg->hasFromPhoto()) {
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
// stop enumeration if the userpic is above our point
if (userpicTop + st::msgPhotoSize <= point.y()) {
return false;
}
// stop enumeration if we've found a userpic under the cursor
if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) {
dragState.link = message->from()->openLink();
lnkhost = message;
return false;
}
return true;
});
}
}
}
}
bool lnkChanged = ClickHandler::setActive(dragState.link, lnkhost);
if (lnkChanged || dragState.cursor != _dragCursorState) {
PopupTooltip::Hide();
}
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) {
PopupTooltip::Show(1000, this);
}
Qt::CursorShape cur = style::cur_default;
if (_dragAction == NoDrag) {
_dragCursorState = dragState.cursor;
if (dragState.link) {
cur = style::cur_pointer;
} else if (_dragCursorState == HistoryInTextCursorState && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) {
cur = style::cur_text;
} else if (_dragCursorState == HistoryInDateCursorState) {
// cur = style::cur_cross;
}
} else if (item) {
if (_dragAction == Selecting) {
bool canSelectMany = (_history != nullptr);
if (selectingText) {
uint16 second = dragState.symbol;
if (dragState.afterSymbol && _dragSelType == TextSelectLetters) {
++second;
}
auto selState = _dragItem->adjustSelection({ qMin(second, _dragSymbol), qMax(second, _dragSymbol) }, _dragSelType);
if (_selected[_dragItem] != selState) { if (_selected[_dragItem] != selState) {
_selected[_dragItem] = selState; _selected[_dragItem] = selState;
repaintItem(_dragItem); repaintItem(_dragItem);
} }
if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) { if (!_wasSelectedText && (selState == FullSelection || selState.from != selState.to)) {
_wasSelectedText = true; _wasSelectedText = true;
setFocus(); setFocus();
} }
@ -2005,7 +2023,7 @@ QString HistoryInner::tooltipText() const {
} else if (_dragCursorState == HistoryInForwardedCursorState && _dragAction == NoDrag) { } else if (_dragCursorState == HistoryInForwardedCursorState && _dragAction == NoDrag) {
if (App::hoveredItem()) { if (App::hoveredItem()) {
if (HistoryMessageForwarded *fwd = App::hoveredItem()->Get<HistoryMessageForwarded>()) { if (HistoryMessageForwarded *fwd = App::hoveredItem()->Get<HistoryMessageForwarded>()) {
return fwd->_text.original(0, 0xFFFF, Text::ExpandLinksNone); return fwd->_text.original(AllTextSelection, Text::ExpandLinksNone);
} }
} }
} else if (ClickHandlerPtr lnk = ClickHandler::getActive()) { } else if (ClickHandlerPtr lnk = ClickHandler::getActive()) {
@ -2242,8 +2260,7 @@ void BotKeyboard::enterEvent(QEvent *e) {
} }
void BotKeyboard::leaveEvent(QEvent *e) { void BotKeyboard::leaveEvent(QEvent *e) {
_lastMousePos = QPoint(-1, -1); clearSelection();
updateSelected();
} }
void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
@ -2257,44 +2274,43 @@ void BotKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres
} }
bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) { bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) {
if (to && to->definesReplyKeyboard()) { if (!to || !to->definesReplyKeyboard()) {
if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) { if (_wasForMsgId.msg) {
return false; _maximizeSize = _singleUse = _forceReply = false;
_wasForMsgId = FullMsgId();
_impl = nullptr;
return true;
} }
return false;
_wasForMsgId = FullMsgId(to->channelId(), to->id);
clearSelection();
auto markupFlags = to->replyKeyboardFlags();
_forceReply = markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply;
_maximizeSize = !(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_resize);
_singleUse = _forceReply || (markupFlags & MTPDreplyKeyboardMarkup::Flag::f_single_use);
_impl = nullptr;
if (auto markup = to->Get<HistoryMessageReplyMarkup>()) {
if (!markup->rows.isEmpty()) {
_impl.reset(new ReplyKeyboard(to, std_::make_unique<Style>(this, *_st)));
}
}
updateStyle();
_height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0);
if (_maximizeSize) _height = qMax(_height, _maxOuterHeight);
if (height() != _height) {
resize(width(), _height);
} else {
resizeEvent(0);
}
return true;
} }
if (_wasForMsgId.msg) {
_maximizeSize = _singleUse = _forceReply = false; if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) {
_wasForMsgId = FullMsgId(); return false;
clearSelection();
_impl = nullptr;
return true;
} }
return false;
_wasForMsgId = FullMsgId(to->channelId(), to->id);
auto markupFlags = to->replyKeyboardFlags();
_forceReply = markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply;
_maximizeSize = !(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_resize);
_singleUse = _forceReply || (markupFlags & MTPDreplyKeyboardMarkup::Flag::f_single_use);
_impl = nullptr;
if (auto markup = to->Get<HistoryMessageReplyMarkup>()) {
if (!markup->rows.isEmpty()) {
_impl.reset(new ReplyKeyboard(to, std_::make_unique<Style>(this, *_st)));
}
}
updateStyle();
_height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0);
if (_maximizeSize) _height = qMax(_height, _maxOuterHeight);
if (height() != _height) {
resize(width(), _height);
} else {
resizeEvent(nullptr);
}
return true;
} }
bool BotKeyboard::hasMarkup() const { bool BotKeyboard::hasMarkup() const {
@ -2333,7 +2349,10 @@ void BotKeyboard::updateStyle(int32 w) {
void BotKeyboard::clearSelection() { void BotKeyboard::clearSelection() {
if (_impl) { if (_impl) {
_impl->clearSelection(); if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
PopupTooltip::Hide();
setCursor(style::cur_default);
}
} }
} }
@ -2363,11 +2382,10 @@ void BotKeyboard::updateSelected() {
QPoint p(mapFromGlobal(_lastMousePos)); QPoint p(mapFromGlobal(_lastMousePos));
int x = rtl() ? st::botKbScroll.width : _st->margin; int x = rtl() ? st::botKbScroll.width : _st->margin;
ClickHandlerPtr lnk; auto link = _impl->getState(p.x() - x, p.y() - _st->margin);
_impl->getState(lnk, p.x() - x, p.y() - _st->margin); if (ClickHandler::setActive(link, this)) {
if (ClickHandler::setActive(lnk, this)) {
PopupTooltip::Hide(); PopupTooltip::Hide();
setCursor(lnk ? style::cur_pointer : style::cur_default); setCursor(link ? style::cur_pointer : style::cur_default);
} }
} }
@ -2891,7 +2909,7 @@ void HistoryWidget::onStickersUpdated() {
void HistoryWidget::onMentionHashtagOrBotCommandInsert(QString str) { void HistoryWidget::onMentionHashtagOrBotCommandInsert(QString str) {
if (str.at(0) == '/') { // bot command if (str.at(0) == '/') { // bot command
App::sendBotCommand(_peer, str); App::sendBotCommand(_peer, nullptr, str);
setFieldText(_field.getLastText().mid(_field.textCursor().position())); setFieldText(_field.getLastText().mid(_field.textCursor().position()));
} else { } else {
_field.onMentionHashtagOrBotCommandInsert(str); _field.onMentionHashtagOrBotCommandInsert(str);
@ -4835,7 +4853,7 @@ void HistoryWidget::onBotStart() {
QString token = _peer->asUser()->botInfo->startToken; QString token = _peer->asUser()->botInfo->startToken;
if (token.isEmpty()) { if (token.isEmpty()) {
sendBotCommand(_peer, qsl("/start"), 0); sendBotCommand(_peer, _peer->asUser(), qsl("/start"), 0);
} else { } else {
uint64 randomId = rand_value<uint64>(); uint64 randomId = rand_value<uint64>();
MTP::send(MTPmessages_StartBot(_peer->asUser()->inputUser, MTP_inputPeerEmpty(), MTP_long(randomId), MTP_string(token)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _peer->asUser())); MTP::send(MTPmessages_StartBot(_peer->asUser()->inputUser, MTP_inputPeerEmpty(), MTP_long(randomId), MTP_string(token)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _peer->asUser()));
@ -5269,14 +5287,15 @@ void HistoryWidget::stopRecording(bool send) {
_a_record.start(); _a_record.start();
} }
void HistoryWidget::sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from cmd links void HistoryWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from cmd links
if (!_peer || _peer != peer) return; if (!_peer || _peer != peer) return;
bool lastKeyboardUsed = (_keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard.forMsgId() == FullMsgId(_channel, replyTo)); bool lastKeyboardUsed = (_keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard.forMsgId() == FullMsgId(_channel, replyTo));
QString toSend = cmd; QString toSend = cmd;
PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? App::hoveredLinkItem()->fromOriginal() : 0); if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) {
if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) bot = 0; bot = nullptr;
}
QString username = bot ? bot->asUser()->username : QString(); QString username = bot ? bot->asUser()->username : QString();
int32 botStatus = _peer->isChat() ? _peer->asChat()->botStatus : (_peer->isMegagroup() ? _peer->asChannel()->mgInfo->botStatus : -1); int32 botStatus = _peer->isChat() ? _peer->asChat()->botStatus : (_peer->isMegagroup() ? _peer->asChannel()->mgInfo->botStatus : -1);
if (!replyTo && toSend.indexOf('@') < 2 && !username.isEmpty() && (botStatus == 0 || botStatus == 2)) { if (!replyTo && toSend.indexOf('@') < 2 && !username.isEmpty() && (botStatus == 0 || botStatus == 2)) {
@ -5333,10 +5352,10 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC
if (answerData.has_message()) { if (answerData.has_message()) {
if (answerData.is_alert()) { if (answerData.is_alert()) {
Ui::showLayer(new InformBox(qs(answerData.vmessage))); Ui::showLayer(new InformBox(qs(answerData.vmessage)));
} else { } else if (App::wnd()) {
Ui::Toast::Config toast; Ui::Toast::Config toast;
toast.text = qs(answerData.vmessage); toast.text = qs(answerData.vmessage);
Ui::Toast::Show(toast); Ui::Toast::Show(App::wnd(), toast);
} }
} }
} }
@ -5923,6 +5942,7 @@ void HistoryWidget::inlineBotChanged() {
_inlineBotCancel = std_::make_unique<IconedButton>(this, st::inlineBotCancel); _inlineBotCancel = std_::make_unique<IconedButton>(this, st::inlineBotCancel);
connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel())); connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel()));
_inlineBotCancel->setGeometry(_send.geometry()); _inlineBotCancel->setGeometry(_send.geometry());
_attachEmoji.raise();
updateFieldSubmitSettings(); updateFieldSubmitSettings();
updateControlsVisibility(); updateControlsVisibility();
} else if (!isInlineBot && _inlineBotCancel) { } else if (!isInlineBot && _inlineBotCancel) {
@ -8043,7 +8063,7 @@ void HistoryWidget::drawPinnedBar(Painter &p) {
p.drawText(left, st::msgReplyPadding.top() + st::msgServiceNameFont->ascent, lang(lng_pinned_message)); p.drawText(left, st::msgReplyPadding.top() + st::msgServiceNameFont->ascent, lang(lng_pinned_message));
p.setPen((((_pinnedBar->msg->toHistoryMessage() && _pinnedBar->msg->toHistoryMessage()->emptyText()) || _pinnedBar->msg->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p); p.setPen((((_pinnedBar->msg->toHistoryMessage() && _pinnedBar->msg->toHistoryMessage()->emptyText()) || _pinnedBar->msg->serviceMsg()) ? st::msgInDateFg : st::msgColor)->p);
_pinnedBar->text.drawElided(p, left, st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - left -_fieldBarCancel.width() - st::msgReplyPadding.right()); _pinnedBar->text.drawElided(p, left, st::msgReplyPadding.top() + st::msgServiceNameFont->height, width() - left - _pinnedBar->cancel.width() - st::msgReplyPadding.right());
} else { } else {
p.setFont(st::msgDateFont); p.setFont(st::msgDateFont);
p.setPen(st::msgInDateFg); p.setPen(st::msgInDateFg);

View file

@ -22,15 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localimageloader.h" #include "localimageloader.h"
#include "ui/boxshadow.h" #include "ui/boxshadow.h"
#include "dropdown.h" #include "dropdown.h"
#include "history/history_common.h"
enum DragState {
DragStateNone = 0x00,
DragStateFiles = 0x01,
DragStatePhotoFiles = 0x02,
DragStateImage = 0x03,
};
class HistoryWidget; class HistoryWidget;
class HistoryInner : public TWidget, public AbstractTooltipShower { class HistoryInner : public TWidget, public AbstractTooltipShower {
@ -181,7 +174,7 @@ private:
bool _firstLoading = false; bool _firstLoading = false;
style::cursor _cursor = style::cur_default; style::cursor _cursor = style::cur_default;
typedef QMap<HistoryItem*, uint32> SelectedItems; using SelectedItems = QMap<HistoryItem*, TextSelection>;
SelectedItems _selected; SelectedItems _selected;
void applyDragSelection(); void applyDragSelection();
void applyDragSelection(SelectedItems *toItems) const; void applyDragSelection(SelectedItems *toItems) const;
@ -629,7 +622,7 @@ public:
void onListEscapePressed(); void onListEscapePressed();
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo); void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
bool insertBotCommand(const QString &cmd, bool specialGif); bool insertBotCommand(const QString &cmd, bool specialGif);
bool eventFilter(QObject *obj, QEvent *e) override; bool eventFilter(QObject *obj, QEvent *e) override;

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "lang.h" #include "lang.h"
#include "playerwidget.h"
namespace InlineBots { namespace InlineBots {
namespace Layout { namespace Layout {
@ -124,7 +125,7 @@ void DeleteSavedGifClickHandler::onClickImpl() const {
if (App::main()) emit App::main()->savedGifsUpdated(); if (App::main()) emit App::main()->savedGifsUpdated();
} }
void Gif::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
DocumentData *document = getShownDocument(); DocumentData *document = getShownDocument();
document->automaticLoad(nullptr); document->automaticLoad(nullptr);
@ -380,7 +381,7 @@ void Sticker::preload() const {
} }
} }
void Sticker::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
bool loaded = getShownDocument()->loaded(); bool loaded = getShownDocument()->loaded();
float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current(); float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current();
@ -472,7 +473,7 @@ void Photo::initDimensions() {
_minh = st::inlineMediaHeight + st::inlineResultsSkip; _minh = st::inlineMediaHeight + st::inlineResultsSkip;
} }
void Photo::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Photo::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 height = st::inlineMediaHeight; int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize(); QSize frame = countFrameSize();
@ -590,7 +591,7 @@ void Video::initDimensions() {
_minh += st::inlineRowMargin * 2 + st::inlineRowBorder; _minh += st::inlineRowMargin * 2 + st::inlineRowBorder;
} }
void Video::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Video::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int left = st::inlineThumbSize + st::inlineThumbSkip; int left = st::inlineThumbSize + st::inlineThumbSkip;
bool withThumb = !content_thumb()->isNull(); bool withThumb = !content_thumb()->isNull();
@ -693,7 +694,7 @@ void File::initDimensions() {
_minh += st::inlineRowMargin * 2 + st::inlineRowBorder; _minh += st::inlineRowMargin * 2 + st::inlineRowBorder;
} }
void File::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void File::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 left = st::msgFileSize + st::inlineThumbSkip; int32 left = st::msgFileSize + st::inlineThumbSkip;
DocumentData *document = getShownDocument(); DocumentData *document = getShownDocument();
@ -941,7 +942,7 @@ int32 Contact::resizeGetHeight(int32 width) {
return _height; return _height;
} }
void Contact::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Contact::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft; int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
left = st::msgFileSize + st::inlineThumbSkip; left = st::msgFileSize + st::inlineThumbSkip;
@ -1050,7 +1051,7 @@ int32 Article::resizeGetHeight(int32 width) {
return _height; return _height;
} }
void Article::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void Article::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft; int32 left = st::emojiPanHeaderLeft - st::inlineResultsLeft;
if (_withThumb) { if (_withThumb) {
left = st::inlineThumbSize + st::inlineThumbSkip; left = st::inlineThumbSize + st::inlineThumbSkip;

View file

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_layout_item.h"
#include "ui/text.h" #include "ui/text/text.h"
namespace InlineBots { namespace InlineBots {
namespace Layout { namespace Layout {
@ -70,7 +70,7 @@ public:
return true; return true;
} }
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
@ -135,7 +135,7 @@ public:
return true; return true;
} }
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private: private:
@ -165,7 +165,7 @@ public:
} }
void preload() const override; void preload() const override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
@ -190,7 +190,7 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private: private:
@ -238,7 +238,7 @@ public:
void initDimensions() override; void initDimensions() override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
// ClickHandlerHost interface // ClickHandlerHost interface
@ -302,7 +302,7 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private: private:
@ -321,7 +321,7 @@ public:
void initDimensions() override; void initDimensions() override;
int resizeGetHeight(int width) override; int resizeGetHeight(int width) override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override; void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private: private:

View file

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_layout_item.h"
#include "core/click_handler_types.h"
#include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_result.h"
#include "inline_bots/inline_bot_layout_internal.h" #include "inline_bots/inline_bot_layout_internal.h"
#include "localstorage.h" #include "localstorage.h"

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "layout.h" #include "layout.h"
#include "structs.h" #include "structs.h"
#include "ui/text.h" #include "ui/text/text.h"
namespace InlineBots { namespace InlineBots {
class Result; class Result;
@ -58,7 +58,7 @@ public:
//ItemBase(PhotoData *photo) : _photo(photo) { //ItemBase(PhotoData *photo) : _photo(photo) {
//} //}
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0; virtual void paint(Painter &p, const QRect &clip, const PaintContext *context) const = 0;
virtual void setPosition(int32 position); virtual void setPosition(int32 position);
int32 position() const; int32 position() const;

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
#include "structs.h" #include "structs.h"
#include "mtproto/core_types.h" #include "mtproto/core_types.h"

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
#include "structs.h" #include "structs.h"
#include "mtproto/core_types.h" #include "mtproto/core_types.h"

View file

@ -31,49 +31,22 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "intro/introsignup.h" #include "intro/introsignup.h"
#include "intro/intropwdcheck.h" #include "intro/intropwdcheck.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "ui/text.h" #include "ui/text/text.h"
namespace {
IntroWidget *signalEmitOn = 0;
QString countryForReg;
void gotNearestDC(const MTPNearestDc &result) {
const auto &nearest(result.c_nearestDc());
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
MTP::setdc(result.c_nearestDc().vnearest_dc.v, true);
if (countryForReg != nearest.vcountry.c_string().v.c_str()) {
countryForReg = nearest.vcountry.c_string().v.c_str();
emit signalEmitOn->countryChanged();
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::startUpdateCheck();
#endif
}
}
IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent) IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
, _langChangeTo(0)
, _a_stage(animation(this, &IntroWidget::step_stage)) , _a_stage(animation(this, &IntroWidget::step_stage))
, _cacheHideIndex(0)
, _cacheShowIndex(0)
, _a_show(animation(this, &IntroWidget::step_show)) , _a_show(animation(this, &IntroWidget::step_show))
, _callStatus({ CallDisabled, 0 }) , _back(this, st::setClose) {
, _registered(false)
, _hasRecovery(false)
, _codeByTelegram(false)
, _back(this, st::setClose)
, _backFrom(0)
, _backTo(0) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
connect(&_back, SIGNAL(clicked()), this, SLOT(onBack())); connect(&_back, SIGNAL(clicked()), this, SLOT(onBack()));
_back.hide(); _back.hide();
countryForReg = psCurrentCountry(); _countryForReg = psCurrentCountry();
MTP::send(MTPhelp_GetNearestDc(), rpcDone(gotNearestDC)); MTP::send(MTPhelp_GetNearestDc(), rpcDone(&IntroWidget::gotNearestDC));
signalEmitOn = this;
_stepHistory.push_back(new IntroStart(this)); _stepHistory.push_back(new IntroStart(this));
_back.raise(); _back.raise();
@ -86,6 +59,10 @@ IntroWidget::IntroWidget(QWidget *parent) : TWidget(parent)
cSetPasswordRecovered(false); cSetPasswordRecovered(false);
_back.move(st::setClosePos.x(), st::setClosePos.y()); _back.move(st::setClosePos.x(), st::setClosePos.y());
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
Sandbox::startUpdateCheck();
#endif
} }
void IntroWidget::langChangeTo(int32 langId) { void IntroWidget::langChangeTo(int32 langId) {
@ -173,6 +150,16 @@ void IntroWidget::pushStep(IntroStep *step, MoveType type) {
historyMove(type); historyMove(type);
} }
void IntroWidget::gotNearestDC(const MTPNearestDc &result) {
const auto &nearest(result.c_nearestDc());
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
MTP::setdc(result.c_nearestDc().vnearest_dc.v, true);
if (_countryForReg != nearest.vcountry.c_string().v.c_str()) {
_countryForReg = nearest.vcountry.c_string().v.c_str();
emit countryChanged();
}
}
QPixmap IntroWidget::grabStep(int skip) { QPixmap IntroWidget::grabStep(int skip) {
return myGrab(step(skip), QRect(st::introSlideShift, 0, st::introSize.width(), st::introSize.height())); return myGrab(step(skip), QRect(st::introSlideShift, 0, st::introSize.width(), st::introSize.height()));
} }
@ -297,7 +284,7 @@ QRect IntroWidget::innerRect() const {
} }
QString IntroWidget::currentCountry() const { QString IntroWidget::currentCountry() const {
return countryForReg; return _countryForReg;
} }
void IntroWidget::setPhone(const QString &phone, const QString &phone_hash, bool registered) { void IntroWidget::setPhone(const QString &phone, const QString &phone_hash, bool registered) {

View file

@ -20,8 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "mtproto/rpc_sender.h"
class IntroStep; class IntroStep;
class IntroWidget final : public TWidget { class IntroWidget : public TWidget, public RPCSender {
Q_OBJECT Q_OBJECT
public: public:
@ -72,7 +74,7 @@ public:
void finish(const MTPUser &user, const QImage &photo = QImage()); void finish(const MTPUser &user, const QImage &photo = QImage());
void rpcClear(); void rpcClear() override;
void langChangeTo(int32 langId); void langChangeTo(int32 langId);
void nextStep(IntroStep *step) { void nextStep(IntroStep *step) {
@ -99,11 +101,12 @@ private:
QPixmap grabStep(int skip = 0); QPixmap grabStep(int skip = 0);
int _langChangeTo; int _langChangeTo = 0;
Animation _a_stage; Animation _a_stage;
QPixmap _cacheHide, _cacheShow; QPixmap _cacheHide, _cacheShow;
int _cacheHideIndex, _cacheShowIndex; int _cacheHideIndex = 0;
int _cacheShowIndex = 0;
anim::ivalue a_coordHide, a_coordShow; anim::ivalue a_coordHide, a_coordShow;
anim::fvalue a_opacityHide, a_opacityShow; anim::fvalue a_opacityHide, a_opacityShow;
@ -125,20 +128,26 @@ private:
void historyMove(MoveType type); void historyMove(MoveType type);
void pushStep(IntroStep *step, MoveType type); void pushStep(IntroStep *step, MoveType type);
void gotNearestDC(const MTPNearestDc &dc);
QString _countryForReg;
QString _phone, _phone_hash; QString _phone, _phone_hash;
CallStatus _callStatus; CallStatus _callStatus = { CallDisabled, 0 };
bool _registered; bool _registered = false;
QString _code; QString _code;
QByteArray _pwdSalt; QByteArray _pwdSalt;
bool _hasRecovery, _codeByTelegram; bool _hasRecovery = false;
bool _codeByTelegram = false;
QString _pwdHint; QString _pwdHint;
QString _firstname, _lastname; QString _firstname, _lastname;
IconedButton _back; IconedButton _back;
float64 _backFrom, _backTo; float64 _backFrom = 0.;
float64 _backTo = 0.;
}; };

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "layerwidget.h" #include "layerwidget.h"
#include "application.h" #include "application.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
static const uint32 FullSelection = 0xFFFFFFFF; static constexpr TextSelection FullSelection = { 0xFFFF, 0xFFFF };
extern TextParseOptions _textNameOptions, _textDlgOptions; extern TextParseOptions _textNameOptions, _textDlgOptions;
extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions; extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions;
@ -91,12 +91,13 @@ public:
}; };
class LayoutMediaItemBase;
class LayoutItemBase : public Composer, public ClickHandlerHost { class LayoutItemBase : public Composer, public ClickHandlerHost {
public: public:
LayoutItemBase() { LayoutItemBase() {
} }
LayoutItemBase &operator=(const LayoutItemBase &) = delete;
LayoutItemBase(const LayoutItemBase &other) = delete;
LayoutItemBase &operator=(const LayoutItemBase &other) = delete;
int32 maxWidth() const { int32 maxWidth() const {
return _maxw; return _maxw;
@ -142,311 +143,3 @@ protected:
int _minh = 0; int _minh = 0;
}; };
class PaintContextOverview : public PaintContextBase {
public:
PaintContextOverview(uint64 ms, bool selecting) : PaintContextBase(ms, selecting), isAfterDate(false) {
}
bool isAfterDate;
};
class LayoutOverviewItemBase : public LayoutItemBase {
public:
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const = 0;
virtual LayoutMediaItemBase *toLayoutMediaItem() {
return nullptr;
}
virtual const LayoutMediaItemBase *toLayoutMediaItem() const {
return nullptr;
}
virtual HistoryItem *getItem() const {
return nullptr;
}
virtual DocumentData *getDocument() const {
return nullptr;
}
MsgId msgId() const {
const HistoryItem *item = getItem();
return item ? item->id : 0;
}
};
class LayoutMediaItemBase : public LayoutOverviewItemBase {
public:
LayoutMediaItemBase(HistoryItem *parent) : _parent(parent) {
}
LayoutMediaItemBase *toLayoutMediaItem() override {
return this;
}
const LayoutMediaItemBase *toLayoutMediaItem() const override {
return this;
}
HistoryItem *getItem() const override {
return _parent;
}
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool active) override;
protected:
HistoryItem *_parent;
};
class LayoutRadialProgressItem : public LayoutMediaItemBase {
public:
LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItemBase(parent)
, _radial(0)
, a_iconOver(0, 0)
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
}
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool active) override;
~LayoutRadialProgressItem();
protected:
ClickHandlerPtr _openl, _savel, _cancell;
void setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell);
void setDocumentLinks(DocumentData *document) {
ClickHandlerPtr save;
if (document->voice()) {
save.reset(new DocumentOpenClickHandler(document));
} else {
save.reset(new DocumentSaveClickHandler(document));
}
setLinks(MakeShared<DocumentOpenClickHandler>(document), std_::move(save), MakeShared<DocumentCancelClickHandler>(document));
}
void step_iconOver(float64 ms, bool timer);
void step_radial(uint64 ms, bool timer);
void ensureRadial() const;
void checkRadialFinished();
bool isRadialAnimation(uint64 ms) const {
if (!_radial || !_radial->animating()) return false;
_radial->step(ms);
return _radial && _radial->animating();
}
virtual float64 dataProgress() const = 0;
virtual bool dataFinished() const = 0;
virtual bool dataLoaded() const = 0;
virtual bool iconAnimated() const {
return false;
}
mutable RadialAnimation *_radial;
anim::fvalue a_iconOver;
mutable Animation _a_iconOver;
private:
LayoutRadialProgressItem(const LayoutRadialProgressItem &other);
};
class LayoutAbstractFileItem : public LayoutRadialProgressItem {
public:
LayoutAbstractFileItem(HistoryItem *parent) : LayoutRadialProgressItem(parent) {
}
protected:
// >= 0 will contain download / upload string, _statusSize = loaded bytes
// < 0 will contain played string, _statusSize = -(seconds + 1) played
// 0x7FFFFFF0 will contain status for not yet downloaded file
// 0x7FFFFFF1 will contain status for already downloaded file
// 0x7FFFFFF2 will contain status for failed to download / upload file
mutable int32 _statusSize;
mutable QString _statusText;
// duration = -1 - no duration, duration = -2 - "GIF" duration
void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
};
struct OverviewItemInfo : public BaseComponent<OverviewItemInfo> {
int top = 0;
};
class LayoutOverviewDate : public LayoutOverviewItemBase {
public:
LayoutOverviewDate(const QDate &date, bool month);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
private:
QDate _date;
QString _text;
};
class LayoutOverviewPhoto : public LayoutMediaItemBase {
public:
LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
PhotoData *_data;
ClickHandlerPtr _link;
mutable QPixmap _pix;
mutable bool _goodLoaded;
};
class LayoutOverviewVideo : public LayoutAbstractFileItem {
public:
LayoutOverviewVideo(DocumentData *video, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return true;
}
private:
DocumentData *_data;
QString _duration;
mutable QPixmap _pix;
mutable bool _thumbLoaded;
void updateStatusText() const;
};
class LayoutOverviewVoice : public LayoutAbstractFileItem {
public:
LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return true;
}
private:
DocumentData *_data;
ClickHandlerPtr _namel;
mutable Text _name, _details;
mutable int32 _nameVersion;
void updateName() const;
bool updateStatusText() const;
};
class LayoutOverviewDocument : public LayoutAbstractFileItem {
public:
LayoutOverviewDocument(DocumentData *document, HistoryItem *parent);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
virtual DocumentData *getDocument() const override {
return _data;
}
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return _data->song() || !_data->loaded() || (_radial && _radial->animating());
}
private:
DocumentData *_data;
ClickHandlerPtr _msgl, _namel;
mutable bool _thumbForLoaded;
mutable QPixmap _thumb;
QString _name, _date, _ext;
int32 _namew, _datew, _extw;
int32 _thumbw, _colorIndex;
bool withThumb() const {
return !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height();
}
bool updateStatusText() const;
};
class LayoutOverviewLink : public LayoutMediaItemBase {
public:
LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
ClickHandlerPtr _photol;
QString _title, _letter;
int _titlew = 0;
WebPageData *_page = nullptr;
int _pixw = 0;
int _pixh = 0;
Text _text = { int(st::msgMinWidth) };
struct Link {
Link() : width(0) {
}
Link(const QString &url, const QString &text);
QString text;
int32 width;
TextClickHandlerPtr lnk;
};
QVector<Link> _links;
};

View file

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/photosendbox.h" #include "boxes/photosendbox.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "lang.h" #include "lang.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"

View file

@ -25,10 +25,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "serialize/serialize_document.h" #include "serialize/serialize_document.h"
#include "serialize/serialize_common.h" #include "serialize/serialize_common.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "lang.h" #include "lang.h"
#include "playerwidget.h"
#include "apiwrap.h"
namespace { namespace {
typedef quint64 FileKey; typedef quint64 FileKey;

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
namespace _local_inner { namespace _local_inner {

File diff suppressed because it is too large Load diff

View file

@ -20,107 +20,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "apiwrap.h" #include "localimageloader.h"
#include "dialogswidget.h" #include "history/history_common.h"
#include "historywidget.h"
#include "profilewidget.h"
#include "overviewwidget.h"
#include "playerwidget.h"
#include "ui/buttons/peer_avatar_button.h"
class Window; namespace Dialogs {
class Row;
} // namespace Dialogs
namespace Ui {
class PeerAvatarButton;
} // namespace Ui
namespace Window {
class TopBarWidget;
} // namespace Window
class MainWindow;
class ApiWrap; class ApiWrap;
class MainWidget;
class ConfirmBox; class ConfirmBox;
class DialogsWidget; class DialogsWidget;
class HistoryWidget; class HistoryWidget;
class ProfileWidget; class ProfileWidget;
class OverviewWidget; class OverviewWidget;
class PlayerWidget; class PlayerWidget;
class HistoryHider;
namespace Dialogs { class Dropdown;
class Row;
} // namespace Dialogs
class TopBarWidget : public TWidget {
Q_OBJECT
public:
TopBarWidget(MainWidget *w);
void enterEvent(QEvent *e) override;
void enterFromChildEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
void leaveToChildEvent(QEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void step_appearance(float64 ms, bool timer);
void enableShadow(bool enable = true);
void startAnim();
void stopAnim();
void showAll();
void showSelected(uint32 selCount, bool canDelete = false);
void updateAdaptiveLayout();
FlatButton *mediaTypeButton();
void grabStart() override {
_sideShadow.hide();
}
void grabFinish() override {
_sideShadow.setVisible(!Adaptive::OneColumn());
}
public slots:
void onForwardSelection();
void onDeleteSelection();
void onClearSelection();
void onInfoClicked();
void onAddContact();
void onEdit();
void onDeleteContact();
void onDeleteContactSure();
void onDeleteAndExit();
void onDeleteAndExitSure();
void onSearch();
signals:
void clicked();
private:
MainWidget *main();
anim::fvalue a_over;
Animation _a_appearance;
PeerData *_selPeer;
uint32 _selCount;
bool _canDelete;
QString _selStr;
int32 _selStrLeft, _selStrWidth;
bool _animating;
FlatButton _clearSelection;
FlatButton _forward, _delete;
int32 _selectionButtonsWidth, _forwardDeleteWidth;
PeerAvatarButton _info;
FlatButton _edit, _leaveGroup, _addContact, _deleteContact;
FlatButton _mediaType;
IconedButton _search;
PlainShadow _sideShadow;
};
enum StackItemType { enum StackItemType {
HistoryStackItem, HistoryStackItem,
@ -220,7 +144,7 @@ class MainWidget : public TWidget, public RPCSender {
public: public:
MainWidget(Window *window); MainWidget(MainWindow *window);
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
@ -230,7 +154,7 @@ public:
bool needBackButton(); bool needBackButton();
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
TopBarWidget *topBar(); Window::TopBarWidget *topBar();
PlayerWidget *player(); PlayerWidget *player();
int contentScrollAddToY() const; int contentScrollAddToY() const;
@ -365,7 +289,7 @@ public:
uint64 animActiveTimeStart(const HistoryItem *msg) const; uint64 animActiveTimeStart(const HistoryItem *msg) const;
void stopAnimActive(); void stopAnimActive();
void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo); void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
bool insertBotCommand(const QString &cmd, bool specialGif); bool insertBotCommand(const QString &cmd, bool specialGif);
void searchMessages(const QString &query, PeerData *inPeer); void searchMessages(const QString &query, PeerData *inPeer);
@ -448,6 +372,8 @@ public:
bool isItemVisible(HistoryItem *item); bool isItemVisible(HistoryItem *item);
void closePlayer();
void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col); void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col);
void ui_repaintHistoryItem(const HistoryItem *item); void ui_repaintHistoryItem(const HistoryItem *item);
@ -498,7 +424,6 @@ public slots:
void documentPlayProgress(const SongMsgId &songId); void documentPlayProgress(const SongMsgId &songId);
void inlineResultLoadProgress(FileLoader *loader); void inlineResultLoadProgress(FileLoader *loader);
void inlineResultLoadFailed(FileLoader *loader, bool started); void inlineResultLoadFailed(FileLoader *loader, bool started);
void hidePlayer();
void dialogsCancelled(); void dialogsCancelled();
@ -623,14 +548,14 @@ private:
int _dialogsWidth = st::dlgMinWidth; int _dialogsWidth = st::dlgMinWidth;
DialogsWidget dialogs; ChildWidget<DialogsWidget> _dialogs;
HistoryWidget history; ChildWidget<HistoryWidget> _history;
ProfileWidget* profile = nullptr; ChildWidget<ProfileWidget> _profile = { nullptr };
OverviewWidget* overview = nullptr; ChildWidget<OverviewWidget> _overview = { nullptr };
PlayerWidget _player; ChildWidget<PlayerWidget> _player;
TopBarWidget _topBar; ChildWidget<Window::TopBarWidget> _topBar;
ConfirmBox *_forwardConfirm = nullptr; // for single column layout ConfirmBox *_forwardConfirm = nullptr; // for single column layout
HistoryHider *_hider = nullptr; ChildWidget<HistoryHider> _hider = { nullptr };
StackItems _stack; StackItems _stack;
PeerData *_peerInStack = nullptr; PeerData *_peerInStack = nullptr;
MsgId _msgIdInStack = 0; MsgId _msgIdInStack = 0;
@ -638,7 +563,7 @@ private:
int _playerHeight = 0; int _playerHeight = 0;
int _contentScrollAddToY = 0; int _contentScrollAddToY = 0;
Dropdown _mediaType; ChildWidget<Dropdown> _mediaType;
int32 _mediaTypeMask = 0; int32 _mediaTypeMask = 0;
int32 updDate = 0; int32 updDate = 0;
@ -711,8 +636,8 @@ private:
void viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint> &result, mtpRequestId req); void viewsIncrementDone(QVector<MTPint> ids, const MTPVector<MTPint> &result, mtpRequestId req);
bool viewsIncrementFail(const RPCError &error, mtpRequestId req); bool viewsIncrementFail(const RPCError &error, mtpRequestId req);
App::WallPaper *_background = nullptr; std_::unique_ptr<App::WallPaper> _background;
ApiWrap *_api; std_::unique_ptr<ApiWrap> _api;
}; };

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "window.h" #include "mainwindow.h"
#include "zip.h" #include "zip.h"
@ -364,7 +364,7 @@ NotifyWindow::~NotifyWindow() {
if (App::wnd()) App::wnd()->notifyShowNext(this); if (App::wnd()) App::wnd()->notifyShowNext(this);
} }
Window::Window(QWidget *parent) : PsMainWindow(parent) { MainWindow::MainWindow(QWidget *parent) : PsMainWindow(parent) {
icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation); icon16 = icon256.scaledToWidth(16, Qt::SmoothTransformation);
icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation);
icon64 = icon256.scaledToWidth(64, Qt::SmoothTransformation); icon64 = icon256.scaledToWidth(64, Qt::SmoothTransformation);
@ -400,7 +400,7 @@ Window::Window(QWidget *parent) : PsMainWindow(parent) {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
} }
void Window::inactivePress(bool inactive) { void MainWindow::inactivePress(bool inactive) {
_inactivePress = inactive; _inactivePress = inactive;
if (_inactivePress) { if (_inactivePress) {
_inactiveTimer.start(200); _inactiveTimer.start(200);
@ -409,15 +409,15 @@ void Window::inactivePress(bool inactive) {
} }
} }
bool Window::inactivePress() const { bool MainWindow::inactivePress() const {
return _inactivePress; return _inactivePress;
} }
void Window::onInactiveTimer() { void MainWindow::onInactiveTimer() {
inactivePress(false); inactivePress(false);
} }
void Window::stateChanged(Qt::WindowState state) { void MainWindow::stateChanged(Qt::WindowState state) {
psUserActionDone(); psUserActionDone();
updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout()); updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout());
@ -429,7 +429,7 @@ void Window::stateChanged(Qt::WindowState state) {
psSavePosition(state); psSavePosition(state);
} }
void Window::init() { void MainWindow::init() {
psInitFrameless(); psInitFrameless();
setWindowIcon(wndIcon); setWindowIcon(wndIcon);
@ -446,7 +446,7 @@ void Window::init() {
psInitSize(); psInitSize();
} }
void Window::firstShow() { void MainWindow::firstShow() {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
trayIconMenu = new PopupMenu(); trayIconMenu = new PopupMenu();
trayIconMenu->deleteOnHide(false); trayIconMenu->deleteOnHide(false);
@ -472,11 +472,11 @@ void Window::firstShow() {
updateTrayMenu(); updateTrayMenu();
} }
QWidget *Window::filedialogParent() { QWidget *MainWindow::filedialogParent() {
return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView : (QWidget*)this; return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView : (QWidget*)this;
} }
void Window::clearWidgets() { void MainWindow::clearWidgets() {
Ui::hideLayer(true); Ui::hideLayer(true);
if (_passcode) { if (_passcode) {
_passcode->hide(); _passcode->hide();
@ -511,7 +511,7 @@ void Window::clearWidgets() {
updateGlobalMenu(); updateGlobalMenu();
} }
QPixmap Window::grabInner() { QPixmap MainWindow::grabInner() {
QPixmap result; QPixmap result;
if (settings) { if (settings) {
result = myGrab(settings); result = myGrab(settings);
@ -525,7 +525,7 @@ QPixmap Window::grabInner() {
return result; return result;
} }
void Window::clearPasscode() { void MainWindow::clearPasscode() {
if (!_passcode) return; if (!_passcode) return;
QPixmap bg = grabInner(); QPixmap bg = grabInner();
@ -546,7 +546,7 @@ void Window::clearPasscode() {
updateGlobalMenu(); updateGlobalMenu();
} }
void Window::setupPasscode(bool anim) { void MainWindow::setupPasscode(bool anim) {
QPixmap bg = grabInner(); QPixmap bg = grabInner();
if (_passcode) { if (_passcode) {
@ -570,7 +570,7 @@ void Window::setupPasscode(bool anim) {
updateGlobalMenu(); updateGlobalMenu();
} }
void Window::checkAutoLockIn(int msec) { void MainWindow::checkAutoLockIn(int msec) {
if (_autoLockTimer.isActive()) { if (_autoLockTimer.isActive()) {
int remain = _autoLockTimer.remainingTime(); int remain = _autoLockTimer.remainingTime();
if (remain > 0 && remain <= msec) return; if (remain > 0 && remain <= msec) return;
@ -578,7 +578,7 @@ void Window::checkAutoLockIn(int msec) {
_autoLockTimer.start(msec); _autoLockTimer.start(msec);
} }
void Window::checkAutoLock() { void MainWindow::checkAutoLock() {
if (!cHasPasscode() || App::passcoded()) return; if (!cHasPasscode() || App::passcoded()) return;
App::app()->checkLocalTime(); App::app()->checkLocalTime();
@ -591,7 +591,7 @@ void Window::checkAutoLock() {
} }
} }
void Window::setupIntro(bool anim) { void MainWindow::setupIntro(bool anim) {
cSetContactsReceived(false); cSetContactsReceived(false);
cSetDialogsReceived(false); cSetDialogsReceived(false);
if (intro && !intro->isHidden() && !main) return; if (intro && !intro->isHidden() && !main) return;
@ -616,11 +616,11 @@ void Window::setupIntro(bool anim) {
} }
} }
void Window::getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait) { void MainWindow::getNotifySetting(const MTPInputNotifyPeer &peer, uint32 msWait) {
MTP::send(MTPaccount_GetNotifySettings(peer), main->rpcDone(&MainWidget::gotNotifySetting, peer), main->rpcFail(&MainWidget::failNotifySetting, peer), 0, msWait); MTP::send(MTPaccount_GetNotifySettings(peer), main->rpcDone(&MainWidget::gotNotifySetting, peer), main->rpcFail(&MainWidget::failNotifySetting, peer), 0, msWait);
} }
void Window::serviceNotification(const QString &msg, const MTPMessageMedia &media, bool force) { void MainWindow::serviceNotification(const QString &msg, const MTPMessageMedia &media, bool force) {
History *h = (main && App::userLoaded(ServiceUserId)) ? App::history(ServiceUserId) : 0; History *h = (main && App::userLoaded(ServiceUserId)) ? App::history(ServiceUserId) : 0;
if (!h || (!force && h->isEmpty())) { if (!h || (!force && h->isEmpty())) {
_delayedServiceMsgs.push_back(DelayedServiceMsg(msg, media)); _delayedServiceMsgs.push_back(DelayedServiceMsg(msg, media));
@ -630,7 +630,7 @@ void Window::serviceNotification(const QString &msg, const MTPMessageMedia &medi
main->serviceNotification(msg, media); main->serviceNotification(msg, media);
} }
void Window::showDelayedServiceMsgs() { void MainWindow::showDelayedServiceMsgs() {
QVector<DelayedServiceMsg> toAdd = _delayedServiceMsgs; QVector<DelayedServiceMsg> toAdd = _delayedServiceMsgs;
_delayedServiceMsgs.clear(); _delayedServiceMsgs.clear();
for (QVector<DelayedServiceMsg>::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) { for (QVector<DelayedServiceMsg>::const_iterator i = toAdd.cbegin(), e = toAdd.cend(); i != e; ++i) {
@ -638,7 +638,7 @@ void Window::showDelayedServiceMsgs() {
} }
} }
void Window::sendServiceHistoryRequest() { void MainWindow::sendServiceHistoryRequest() {
if (!main || !main->started() || _delayedServiceMsgs.isEmpty() || _serviceHistoryRequest) return; if (!main || !main->started() || _delayedServiceMsgs.isEmpty() || _serviceHistoryRequest) return;
UserData *user = App::userLoaded(ServiceUserId); UserData *user = App::userLoaded(ServiceUserId);
@ -649,7 +649,7 @@ void Window::sendServiceHistoryRequest() {
_serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail)); _serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), main->rpcDone(&MainWidget::serviceHistoryDone), main->rpcFail(&MainWidget::serviceHistoryFail));
} }
void Window::setupMain(bool anim, const MTPUser *self) { void MainWindow::setupMain(bool anim, const MTPUser *self) {
QPixmap bg = anim ? grabInner() : QPixmap(); QPixmap bg = anim ? grabInner() : QPixmap();
clearWidgets(); clearWidgets();
main = new MainWidget(this); main = new MainWidget(this);
@ -673,14 +673,14 @@ void Window::setupMain(bool anim, const MTPUser *self) {
_mediaView = new MediaView(); _mediaView = new MediaView();
} }
void Window::updateCounter() { void MainWindow::updateUnreadCounter() {
if (!Global::started() || App::quitting()) return; if (!Global::started() || App::quitting()) return;
psUpdateCounter();
title->updateCounter(); title->updateCounter();
psUpdateCounter();
} }
void Window::showSettings() { void MainWindow::showSettings() {
if (_passcode) return; if (_passcode) return;
if (isHidden()) showFromTray(); if (isHidden()) showFromTray();
@ -705,7 +705,7 @@ void Window::showSettings() {
fixOrder(); fixOrder();
} }
void Window::hideSettings(bool fast) { void MainWindow::hideSettings(bool fast) {
if (!settings || _passcode) return; if (!settings || _passcode) return;
if (fast) { if (fast) {
@ -738,14 +738,14 @@ void Window::hideSettings(bool fast) {
fixOrder(); fixOrder();
} }
void Window::mtpStateChanged(int32 dc, int32 state) { void MainWindow::mtpStateChanged(int32 dc, int32 state) {
if (dc == MTP::maindc()) { if (dc == MTP::maindc()) {
updateTitleStatus(); updateTitleStatus();
if (settings) settings->updateConnectionType(); if (settings) settings->updateConnectionType();
} }
} }
void Window::updateTitleStatus() { void MainWindow::updateTitleStatus() {
int32 state = MTP::dcstate(); int32 state = MTP::dcstate();
if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) { if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) {
if (main || getms() > 5000 || _connecting) { if (main || getms() > 5000 || _connecting) {
@ -759,48 +759,48 @@ void Window::updateTitleStatus() {
} }
} }
IntroWidget *Window::introWidget() { IntroWidget *MainWindow::introWidget() {
return intro; return intro;
} }
MainWidget *Window::mainWidget() { MainWidget *MainWindow::mainWidget() {
return main; return main;
} }
SettingsWidget *Window::settingsWidget() { SettingsWidget *MainWindow::settingsWidget() {
return settings; return settings;
} }
PasscodeWidget *Window::passcodeWidget() { PasscodeWidget *MainWindow::passcodeWidget() {
return _passcode; return _passcode;
} }
void Window::showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item) { void MainWindow::showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item) {
return lnk->peer() ? showPhoto(lnk->photo(), lnk->peer()) : showPhoto(lnk->photo(), item); return lnk->peer() ? showPhoto(lnk->photo(), lnk->peer()) : showPhoto(lnk->photo(), item);
} }
void Window::showPhoto(PhotoData *photo, HistoryItem *item) { void MainWindow::showPhoto(PhotoData *photo, HistoryItem *item) {
if (_mediaView->isHidden()) Ui::hideLayer(true); if (_mediaView->isHidden()) Ui::hideLayer(true);
_mediaView->showPhoto(photo, item); _mediaView->showPhoto(photo, item);
_mediaView->activateWindow(); _mediaView->activateWindow();
_mediaView->setFocus(); _mediaView->setFocus();
} }
void Window::showPhoto(PhotoData *photo, PeerData *peer) { void MainWindow::showPhoto(PhotoData *photo, PeerData *peer) {
if (_mediaView->isHidden()) Ui::hideLayer(true); if (_mediaView->isHidden()) Ui::hideLayer(true);
_mediaView->showPhoto(photo, peer); _mediaView->showPhoto(photo, peer);
_mediaView->activateWindow(); _mediaView->activateWindow();
_mediaView->setFocus(); _mediaView->setFocus();
} }
void Window::showDocument(DocumentData *doc, HistoryItem *item) { void MainWindow::showDocument(DocumentData *doc, HistoryItem *item) {
if (_mediaView->isHidden()) Ui::hideLayer(true); if (_mediaView->isHidden()) Ui::hideLayer(true);
_mediaView->showDocument(doc, item); _mediaView->showDocument(doc, item);
_mediaView->activateWindow(); _mediaView->activateWindow();
_mediaView->setFocus(); _mediaView->setFocus();
} }
void Window::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) { void MainWindow::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) {
if (box) { if (box) {
bool fast = (options.testFlag(ForceFastShowLayer)) || Ui::isLayerShown(); bool fast = (options.testFlag(ForceFastShowLayer)) || Ui::isLayerShown();
if (layerBg) { if (layerBg) {
@ -837,15 +837,15 @@ void Window::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) {
} }
} }
bool Window::ui_isLayerShown() { bool MainWindow::ui_isLayerShown() {
return !!layerBg; return !!layerBg;
} }
bool Window::ui_isMediaViewShown() { bool MainWindow::ui_isMediaViewShown() {
return _mediaView && !_mediaView->isHidden(); return _mediaView && !_mediaView->isHidden();
} }
void Window::ui_showMediaPreview(DocumentData *document) { void MainWindow::ui_showMediaPreview(DocumentData *document) {
if (!document || ((!document->isAnimation() || !document->loaded()) && !document->sticker())) return; if (!document || ((!document->isAnimation() || !document->loaded()) && !document->sticker())) return;
if (!_mediaPreview) { if (!_mediaPreview) {
_mediaPreview = std_::make_unique<MediaPreviewWidget>(this); _mediaPreview = std_::make_unique<MediaPreviewWidget>(this);
@ -857,7 +857,7 @@ void Window::ui_showMediaPreview(DocumentData *document) {
_mediaPreview->showPreview(document); _mediaPreview->showPreview(document);
} }
void Window::ui_showMediaPreview(PhotoData *photo) { void MainWindow::ui_showMediaPreview(PhotoData *photo) {
if (!photo) return; if (!photo) return;
if (!_mediaPreview) { if (!_mediaPreview) {
_mediaPreview = std_::make_unique<MediaPreviewWidget>(this); _mediaPreview = std_::make_unique<MediaPreviewWidget>(this);
@ -869,12 +869,12 @@ void Window::ui_showMediaPreview(PhotoData *photo) {
_mediaPreview->showPreview(photo); _mediaPreview->showPreview(photo);
} }
void Window::ui_hideMediaPreview() { void MainWindow::ui_hideMediaPreview() {
if (!_mediaPreview) return; if (!_mediaPreview) return;
_mediaPreview->hidePreview(); _mediaPreview->hidePreview();
} }
PeerData *Window::ui_getPeerForMouseAction() { PeerData *MainWindow::ui_getPeerForMouseAction() {
if (_mediaView && !_mediaView->isHidden()) { if (_mediaView && !_mediaView->isHidden()) {
return _mediaView->ui_getPeerForMouseAction(); return _mediaView->ui_getPeerForMouseAction();
} else if (main) { } else if (main) {
@ -883,7 +883,7 @@ PeerData *Window::ui_getPeerForMouseAction() {
return nullptr; return nullptr;
} }
void Window::showConnecting(const QString &text, const QString &reconnect) { void MainWindow::showConnecting(const QString &text, const QString &reconnect) {
if (_connecting) { if (_connecting) {
_connecting->set(text, reconnect); _connecting->set(text, reconnect);
} else { } else {
@ -895,11 +895,11 @@ void Window::showConnecting(const QString &text, const QString &reconnect) {
if (settings) settings->update(); if (settings) settings->update();
} }
bool Window::connectingVisible() const { bool MainWindow::connectingVisible() const {
return _connecting && !_connecting->isHidden(); return _connecting && !_connecting->isHidden();
} }
void Window::hideConnecting() { void MainWindow::hideConnecting() {
if (_connecting) { if (_connecting) {
_connecting->deleteLater(); _connecting->deleteLater();
_connecting = 0; _connecting = 0;
@ -907,18 +907,18 @@ void Window::hideConnecting() {
if (settings) settings->update(); if (settings) settings->update();
} }
bool Window::historyIsActive() const { bool MainWindow::historyIsActive() const {
return isActive(false) && main && main->historyIsActive() && (!settings || !settings->isVisible()); return isActive(false) && main && main->historyIsActive() && (!settings || !settings->isVisible());
} }
void Window::checkHistoryActivation() { void MainWindow::checkHistoryActivation() {
if (main && MTP::authedId() && historyIsActive()) { if (main && MTP::authedId() && historyIsActive()) {
main->historyWasRead(); main->historyWasRead();
} }
QTimer::singleShot(1, this, SLOT(updateTrayMenu())); QTimer::singleShot(1, this, SLOT(updateTrayMenu()));
} }
void Window::layerHidden() { void MainWindow::layerHidden() {
if (layerBg) { if (layerBg) {
layerBg->hide(); layerBg->hide();
layerBg->deleteLater(); layerBg->deleteLater();
@ -928,7 +928,7 @@ void Window::layerHidden() {
setInnerFocus(); setInnerFocus();
} }
void Window::hideMediaview() { void MainWindow::hideMediaview() {
if (_mediaView && !_mediaView->isHidden()) { if (_mediaView && !_mediaView->isHidden()) {
_mediaView->hide(); _mediaView->hide();
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64 #if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
@ -939,13 +939,13 @@ void Window::hideMediaview() {
} }
} }
bool Window::contentOverlapped(const QRect &globalRect) { bool MainWindow::contentOverlapped(const QRect &globalRect) {
if (main && main->contentOverlapped(globalRect)) return true; if (main && main->contentOverlapped(globalRect)) return true;
if (layerBg && layerBg->contentOverlapped(globalRect)) return true; if (layerBg && layerBg->contentOverlapped(globalRect)) return true;
return false; return false;
} }
void Window::setInnerFocus() { void MainWindow::setInnerFocus() {
if (layerBg && layerBg->canSetFocus()) { if (layerBg && layerBg->canSetFocus()) {
layerBg->setInnerFocus(); layerBg->setInnerFocus();
} else if (_passcode) { } else if (_passcode) {
@ -957,11 +957,11 @@ void Window::setInnerFocus() {
} }
} }
QRect Window::clientRect() const { QRect MainWindow::clientRect() const {
return QRect(0, st::titleHeight, width(), height() - st::titleHeight); return QRect(0, st::titleHeight, width(), height() - st::titleHeight);
} }
QRect Window::photoRect() const { QRect MainWindow::photoRect() const {
if (settings) { if (settings) {
return settings->geometry(); return settings->geometry();
} else if (main) { } else if (main) {
@ -973,15 +973,15 @@ QRect Window::photoRect() const {
return QRect(0, 0, 0, 0); return QRect(0, 0, 0, 0);
} }
void Window::wStartDrag(QMouseEvent *e) { void MainWindow::wStartDrag(QMouseEvent *e) {
dragStart = e->globalPos() - frameGeometry().topLeft(); dragStart = e->globalPos() - frameGeometry().topLeft();
dragging = true; dragging = true;
} }
void Window::paintEvent(QPaintEvent *e) { void MainWindow::paintEvent(QPaintEvent *e) {
} }
HitTestType Window::hitTest(const QPoint &p) const { HitTestType MainWindow::hitTest(const QPoint &p) const {
int x(p.x()), y(p.y()), w(width()), h(height()); int x(p.x()), y(p.y()), w(width()), h(height());
const int32 raw = psResizeRowWidth(); const int32 raw = psResizeRowWidth();
@ -1015,11 +1015,11 @@ HitTestType Window::hitTest(const QPoint &p) const {
return HitTestNone; return HitTestNone;
} }
QRect Window::iconRect() const { QRect MainWindow::iconRect() const {
return QRect(st::titleIconPos + title->geometry().topLeft(), st::titleIconImg.pxSize()); return QRect(st::titleIconPos + title->geometry().topLeft(), st::titleIconImg.pxSize());
} }
bool Window::eventFilter(QObject *obj, QEvent *e) { bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
switch (e->type()) { switch (e->type()) {
case QEvent::MouseButtonPress: case QEvent::MouseButtonPress:
case QEvent::KeyPress: case QEvent::KeyPress:
@ -1088,7 +1088,7 @@ bool Window::eventFilter(QObject *obj, QEvent *e) {
return PsMainWindow::eventFilter(obj, e); return PsMainWindow::eventFilter(obj, e);
} }
void Window::mouseMoveEvent(QMouseEvent *e) { void MainWindow::mouseMoveEvent(QMouseEvent *e) {
if (e->buttons() & Qt::LeftButton) { if (e->buttons() & Qt::LeftButton) {
if (dragging) { if (dragging) {
if (windowState().testFlag(Qt::WindowMaximized)) { if (windowState().testFlag(Qt::WindowMaximized)) {
@ -1104,11 +1104,11 @@ void Window::mouseMoveEvent(QMouseEvent *e) {
} }
} }
void Window::mouseReleaseEvent(QMouseEvent *e) { void MainWindow::mouseReleaseEvent(QMouseEvent *e) {
dragging = false; dragging = false;
} }
bool Window::minimizeToTray() { bool MainWindow::minimizeToTray() {
if (App::quitting() || !psHasTrayIcon()) return false; if (App::quitting() || !psHasTrayIcon()) return false;
hide(); hide();
@ -1123,7 +1123,7 @@ bool Window::minimizeToTray() {
return true; return true;
} }
void Window::updateTrayMenu(bool force) { void MainWindow::updateTrayMenu(bool force) {
if (!trayIconMenu || (cPlatform() == dbipWindows && !force)) return; if (!trayIconMenu || (cPlatform() == dbipWindows && !force)) return;
bool active = isActive(false); bool active = isActive(false);
@ -1153,25 +1153,25 @@ void Window::updateTrayMenu(bool force) {
psTrayMenuUpdated(); psTrayMenuUpdated();
} }
void Window::onShowAddContact() { void MainWindow::onShowAddContact() {
if (isHidden()) showFromTray(); if (isHidden()) showFromTray();
if (main) main->showAddContact(); if (main) main->showAddContact();
} }
void Window::onShowNewGroup() { void MainWindow::onShowNewGroup() {
if (isHidden()) showFromTray(); if (isHidden()) showFromTray();
if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupGroup, false), KeepOtherLayers); if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupGroup, false), KeepOtherLayers);
} }
void Window::onShowNewChannel() { void MainWindow::onShowNewChannel() {
if (isHidden()) showFromTray(); if (isHidden()) showFromTray();
if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupChannel, false), KeepOtherLayers); if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupChannel, false), KeepOtherLayers);
} }
void Window::onLogout() { void MainWindow::onLogout() {
if (isHidden()) showFromTray(); if (isHidden()) showFromTray();
ConfirmBox *box = new ConfirmBox(lang(lng_sure_logout), lang(lng_settings_logout), st::attentionBoxButton); ConfirmBox *box = new ConfirmBox(lang(lng_sure_logout), lang(lng_settings_logout), st::attentionBoxButton);
@ -1179,25 +1179,21 @@ void Window::onLogout() {
Ui::showLayer(box); Ui::showLayer(box);
} }
void Window::onLogoutSure() { void MainWindow::onLogoutSure() {
if (MTP::authedId()) { App::logOut();
App::logOut();
} else {
setupIntro(true);
}
} }
void Window::updateGlobalMenu() { void MainWindow::updateGlobalMenu() {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
psMacUpdateMenu(); psMacUpdateMenu();
#endif #endif
} }
void Window::quitFromTray() { void MainWindow::quitFromTray() {
App::quit(); App::quit();
} }
void Window::activate() { void MainWindow::activate() {
bool wasHidden = !isVisible(); bool wasHidden = !isVisible();
setWindowState(windowState() & ~Qt::WindowMinimized); setWindowState(windowState() & ~Qt::WindowMinimized);
setVisible(true); setVisible(true);
@ -1211,54 +1207,54 @@ void Window::activate() {
} }
} }
void Window::noIntro(IntroWidget *was) { void MainWindow::noIntro(IntroWidget *was) {
if (was == intro) { if (was == intro) {
intro = 0; intro = 0;
} }
} }
void Window::noSettings(SettingsWidget *was) { void MainWindow::noSettings(SettingsWidget *was) {
if (was == settings) { if (was == settings) {
settings = 0; settings = 0;
} }
checkHistoryActivation(); checkHistoryActivation();
} }
void Window::noMain(MainWidget *was) { void MainWindow::noMain(MainWidget *was) {
if (was == main) { if (was == main) {
main = 0; main = 0;
} }
} }
void Window::noBox(BackgroundWidget *was) { void MainWindow::noBox(BackgroundWidget *was) {
if (was == layerBg) { if (was == layerBg) {
layerBg = 0; layerBg = 0;
} }
} }
void Window::layerFinishedHide(BackgroundWidget *was) { void MainWindow::layerFinishedHide(BackgroundWidget *was) {
if (was == layerBg) { if (was == layerBg) {
QTimer::singleShot(0, this, SLOT(layerHidden())); QTimer::singleShot(0, this, SLOT(layerHidden()));
} }
} }
void Window::fixOrder() { void MainWindow::fixOrder() {
title->raise(); title->raise();
if (layerBg) layerBg->raise(); if (layerBg) layerBg->raise();
if (_mediaPreview) _mediaPreview->raise(); if (_mediaPreview) _mediaPreview->raise();
if (_connecting) _connecting->raise(); if (_connecting) _connecting->raise();
} }
void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) { void MainWindow::showFromTray(QSystemTrayIcon::ActivationReason reason) {
if (reason != QSystemTrayIcon::Context) { if (reason != QSystemTrayIcon::Context) {
QTimer::singleShot(1, this, SLOT(updateTrayMenu())); QTimer::singleShot(1, this, SLOT(updateTrayMenu()));
QTimer::singleShot(1, this, SLOT(updateGlobalMenu())); QTimer::singleShot(1, this, SLOT(updateGlobalMenu()));
activate(); activate();
updateCounter(); Notify::unreadCounterUpdated();
} }
} }
void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) { void MainWindow::toggleTray(QSystemTrayIcon::ActivationReason reason) {
if ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) && isActive(false)) return; if ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) && isActive(false)) return;
if (reason == QSystemTrayIcon::Context) { if (reason == QSystemTrayIcon::Context) {
updateTrayMenu(true); updateTrayMenu(true);
@ -1272,7 +1268,7 @@ void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) {
} }
} }
void Window::toggleDisplayNotifyFromTray() { void MainWindow::toggleDisplayNotifyFromTray() {
if (App::passcoded()) { if (App::passcoded()) {
if (!isActive()) showFromTray(); if (!isActive()) showFromTray();
Ui::showLayer(new InformBox(lang(lng_passcode_need_unblock))); Ui::showLayer(new InformBox(lang(lng_passcode_need_unblock)));
@ -1290,7 +1286,7 @@ void Window::toggleDisplayNotifyFromTray() {
} }
} }
void Window::closeEvent(QCloseEvent *e) { void MainWindow::closeEvent(QCloseEvent *e) {
if (MTP::authedId() && !Sandbox::isSavingSession() && Ui::hideWindowNoQuit()) { if (MTP::authedId() && !Sandbox::isSavingSession() && Ui::hideWindowNoQuit()) {
e->ignore(); e->ignore();
} else { } else {
@ -1298,11 +1294,11 @@ void Window::closeEvent(QCloseEvent *e) {
} }
} }
TitleWidget *Window::getTitle() { TitleWidget *MainWindow::getTitle() {
return title; return title;
} }
void Window::resizeEvent(QResizeEvent *e) { void MainWindow::resizeEvent(QResizeEvent *e) {
if (!title) return; if (!title) return;
Adaptive::Layout layout = Adaptive::OneColumnLayout; Adaptive::Layout layout = Adaptive::OneColumnLayout;
@ -1322,7 +1318,7 @@ void Window::resizeEvent(QResizeEvent *e) {
emit resized(QSize(width(), height() - st::titleHeight)); emit resized(QSize(width(), height() - st::titleHeight));
} }
void Window::updateAdaptiveLayout() { void MainWindow::updateAdaptiveLayout() {
title->updateAdaptiveLayout(); title->updateAdaptiveLayout();
if (main) main->updateAdaptiveLayout(); if (main) main->updateAdaptiveLayout();
if (settings) settings->updateAdaptiveLayout(); if (settings) settings->updateAdaptiveLayout();
@ -1330,25 +1326,25 @@ void Window::updateAdaptiveLayout() {
if (layerBg) layerBg->updateAdaptiveLayout(); if (layerBg) layerBg->updateAdaptiveLayout();
} }
bool Window::needBackButton() { bool MainWindow::needBackButton() {
return !!settings; return !!settings;
} }
Window::TempDirState Window::tempDirState() { MainWindow::TempDirState MainWindow::tempDirState() {
if (_clearManager && _clearManager->hasTask(Local::ClearManagerDownloads)) { if (_clearManager && _clearManager->hasTask(Local::ClearManagerDownloads)) {
return TempDirRemoving; return TempDirRemoving;
} }
return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty; return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty;
} }
Window::TempDirState Window::localStorageState() { MainWindow::TempDirState MainWindow::localStorageState() {
if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) { if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
return TempDirRemoving; return TempDirRemoving;
} }
return (Local::hasImages() || Local::hasStickers() || Local::hasWebFiles() || Local::hasAudios()) ? TempDirExists : TempDirEmpty; return (Local::hasImages() || Local::hasStickers() || Local::hasWebFiles() || Local::hasAudios()) ? TempDirExists : TempDirEmpty;
} }
void Window::tempDirDelete(int task) { void MainWindow::tempDirDelete(int task) {
if (_clearManager) { if (_clearManager) {
if (_clearManager->addTask(task)) { if (_clearManager->addTask(task)) {
return; return;
@ -1364,7 +1360,7 @@ void Window::tempDirDelete(int task) {
_clearManager->start(); _clearManager->start();
} }
void Window::onClearFinished(int task, void *manager) { void MainWindow::onClearFinished(int task, void *manager) {
if (manager && manager == _clearManager) { if (manager && manager == _clearManager) {
_clearManager->deleteLater(); _clearManager->deleteLater();
_clearManager = 0; _clearManager = 0;
@ -1372,7 +1368,7 @@ void Window::onClearFinished(int task, void *manager) {
emit tempDirCleared(task); emit tempDirCleared(task);
} }
void Window::onClearFailed(int task, void *manager) { void MainWindow::onClearFailed(int task, void *manager) {
if (manager && manager == _clearManager) { if (manager && manager == _clearManager) {
_clearManager->deleteLater(); _clearManager->deleteLater();
_clearManager = 0; _clearManager = 0;
@ -1380,7 +1376,7 @@ void Window::onClearFailed(int task, void *manager) {
emit tempDirClearFailed(task); emit tempDirClearFailed(task);
} }
void Window::notifySchedule(History *history, HistoryItem *item) { void MainWindow::notifySchedule(History *history, HistoryItem *item) {
if (App::quitting() || !history->currentNotification() || !main) return; if (App::quitting() || !history->currentNotification() || !main) return;
PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0; PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0;
@ -1451,11 +1447,11 @@ void Window::notifySchedule(History *history, HistoryItem *item) {
} }
} }
void Window::notifyFire() { void MainWindow::notifyFire() {
notifyShowNext(); notifyShowNext();
} }
void Window::notifyClear(History *history) { void MainWindow::notifyClear(History *history) {
if (!history) { if (!history) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->unlinkHistory(); (*i)->unlinkHistory();
@ -1480,7 +1476,7 @@ void Window::notifyClear(History *history) {
notifyShowNext(); notifyShowNext();
} }
void Window::notifyClearFast() { void MainWindow::notifyClearFast() {
notifyWaiters.clear(); notifyWaiters.clear();
notifySettingWaiters.clear(); notifySettingWaiters.clear();
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
@ -1492,7 +1488,7 @@ void Window::notifyClearFast() {
notifyWhenAlerts.clear(); notifyWhenAlerts.clear();
} }
void Window::notifySettingGot() { void MainWindow::notifySettingGot() {
int32 t = unixtime(); int32 t = unixtime();
for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) { for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) {
History *history = i.key(); History *history = i.key();
@ -1534,7 +1530,7 @@ void Window::notifySettingGot() {
notifyShowNext(); notifyShowNext();
} }
void Window::notifyShowNext(NotifyWindow *remove) { void MainWindow::notifyShowNext(NotifyWindow *remove) {
if (App::quitting()) return; if (App::quitting()) return;
int32 count = NotifyWindowsCount; int32 count = NotifyWindowsCount;
@ -1711,7 +1707,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
} }
} }
void Window::notifyItemRemoved(HistoryItem *item) { void MainWindow::notifyItemRemoved(HistoryItem *item) {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->itemRemoved(item); (*i)->itemRemoved(item);
@ -1719,7 +1715,7 @@ void Window::notifyItemRemoved(HistoryItem *item) {
} }
} }
void Window::notifyStopHiding() { void MainWindow::notifyStopHiding() {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->stopHiding(); (*i)->stopHiding();
@ -1727,7 +1723,7 @@ void Window::notifyStopHiding() {
} }
} }
void Window::notifyStartHiding() { void MainWindow::notifyStartHiding() {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->startHiding(); (*i)->startHiding();
@ -1735,7 +1731,7 @@ void Window::notifyStartHiding() {
} }
} }
void Window::notifyUpdateAllPhotos() { void MainWindow::notifyUpdateAllPhotos() {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updatePeerPhoto(); (*i)->updatePeerPhoto();
@ -1744,11 +1740,11 @@ void Window::notifyUpdateAllPhotos() {
if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls(); if (_mediaView && !_mediaView->isHidden()) _mediaView->updateControls();
} }
void Window::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { void MainWindow::app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) {
handler->onClick(button); handler->onClick(button);
} }
void Window::notifyUpdateAll() { void MainWindow::notifyUpdateAll() {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
(*i)->updateNotifyDisplay(); (*i)->updateNotifyDisplay();
@ -1757,7 +1753,7 @@ void Window::notifyUpdateAll() {
psClearNotifies(); psClearNotifies();
} }
void Window::notifyActivateAll() { void MainWindow::notifyActivateAll() {
if (cCustomNotifies()) { if (cCustomNotifies()) {
for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) {
psActivateNotify(*i); psActivateNotify(*i);
@ -1765,11 +1761,11 @@ void Window::notifyActivateAll() {
} }
} }
QImage Window::iconLarge() const { QImage MainWindow::iconLarge() const {
return iconbig256; return iconbig256;
} }
void Window::placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) { void MainWindow::placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) {
QPainter p(&img); QPainter p(&img);
QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 10, 1, 10, QChar('0')); QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 10, 1, 10, QChar('0'));
@ -1807,7 +1803,7 @@ void Window::placeSmallCounter(QImage &img, int size, int count, style::color bg
} }
QImage Window::iconWithCounter(int size, int count, style::color bg, bool smallIcon) { QImage MainWindow::iconWithCounter(int size, int count, style::color bg, bool smallIcon) {
bool layer = false; bool layer = false;
if (size < 0) { if (size < 0) {
size = -size; size = -size;
@ -1874,7 +1870,7 @@ QImage Window::iconWithCounter(int size, int count, style::color bg, bool smallI
return img; return img;
} }
void Window::sendPaths() { void MainWindow::sendPaths() {
if (App::passcoded()) return; if (App::passcoded()) return;
hideMediaview(); hideMediaview();
if (settings) { if (settings) {
@ -1887,35 +1883,35 @@ void Window::sendPaths() {
} }
} }
void Window::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { void MainWindow::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
if (main) main->mediaOverviewUpdated(peer, type); if (main) main->mediaOverviewUpdated(peer, type);
if (!_mediaView || _mediaView->isHidden()) return; if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->mediaOverviewUpdated(peer, type); _mediaView->mediaOverviewUpdated(peer, type);
} }
void Window::documentUpdated(DocumentData *doc) { void MainWindow::documentUpdated(DocumentData *doc) {
if (!_mediaView || _mediaView->isHidden()) return; if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->documentUpdated(doc); _mediaView->documentUpdated(doc);
} }
void Window::changingMsgId(HistoryItem *row, MsgId newId) { void MainWindow::changingMsgId(HistoryItem *row, MsgId newId) {
if (main) main->changingMsgId(row, newId); if (main) main->changingMsgId(row, newId);
if (!_mediaView || _mediaView->isHidden()) return; if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->changingMsgId(row, newId); _mediaView->changingMsgId(row, newId);
} }
bool Window::isActive(bool cached) const { bool MainWindow::isActive(bool cached) const {
if (cached) return _isActive; if (cached) return _isActive;
return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized);
} }
void Window::updateIsActive(int timeout) { void MainWindow::updateIsActive(int timeout) {
if (timeout) return _isActiveTimer.start(timeout); if (timeout) return _isActiveTimer.start(timeout);
_isActive = isActive(false); _isActive = isActive(false);
if (main) main->updateOnline(); if (main) main->updateOnline();
} }
Window::~Window() { MainWindow::~MainWindow() {
notifyClearFast(); notifyClearFast();
delete _clearManager; delete _clearManager;
delete _connecting; delete _connecting;

View file

@ -123,12 +123,12 @@ typedef QList<NotifyWindow*> NotifyWindows;
class MediaPreviewWidget; class MediaPreviewWidget;
class Window : public PsMainWindow { class MainWindow : public PsMainWindow {
Q_OBJECT Q_OBJECT
public: public:
Window(QWidget *parent = 0); MainWindow(QWidget *parent = 0);
~Window(); ~MainWindow();
void init(); void init();
void firstShow(); void firstShow();
@ -228,6 +228,8 @@ public:
bool isActive(bool cached = true) const; bool isActive(bool cached = true) const;
void hideMediaview(); void hideMediaview();
void updateUnreadCounter();
bool contentOverlapped(const QRect &globalRect); bool contentOverlapped(const QRect &globalRect);
bool contentOverlapped(QWidget *w, QPaintEvent *e) { bool contentOverlapped(QWidget *w, QPaintEvent *e) {
return contentOverlapped(QRect(w->mapToGlobal(e->rect().topLeft()), e->rect().size())); return contentOverlapped(QRect(w->mapToGlobal(e->rect().topLeft()), e->rect().size()));
@ -250,7 +252,6 @@ public slots:
void stateChanged(Qt::WindowState state); void stateChanged(Qt::WindowState state);
void checkHistoryActivation(); void checkHistoryActivation();
void updateCounter();
void checkAutoLock(); void checkAutoLock();

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mediaview.h" #include "mediaview.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
@ -1781,13 +1781,14 @@ bool MediaView::updateOverState(OverState newState) {
void MediaView::updateOver(QPoint pos) { void MediaView::updateOver(QPoint pos) {
ClickHandlerPtr lnk; ClickHandlerPtr lnk;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
bool inText;
if (_saveMsgStarted && _saveMsg.contains(pos)) { if (_saveMsgStarted && _saveMsg.contains(pos)) {
_saveMsgText.getState(lnk, inText, pos.x() - _saveMsg.x() - st::medviewSaveMsgPadding.left(), pos.y() - _saveMsg.y() - st::medviewSaveMsgPadding.top(), _saveMsg.width() - st::medviewSaveMsgPadding.left() - st::medviewSaveMsgPadding.right()); auto textState = _saveMsgText.getState(pos.x() - _saveMsg.x() - st::medviewSaveMsgPadding.left(), pos.y() - _saveMsg.y() - st::medviewSaveMsgPadding.top(), _saveMsg.width() - st::medviewSaveMsgPadding.left() - st::medviewSaveMsgPadding.right());
lnk = textState.link;
lnkhost = this; lnkhost = this;
} else if (_captionRect.contains(pos)) { } else if (_captionRect.contains(pos)) {
_caption.getState(lnk, inText, pos.x() - _captionRect.x(), pos.y() - _captionRect.y(), _captionRect.width()); auto textState = _caption.getState(pos.x() - _captionRect.x(), pos.y() - _captionRect.y(), _captionRect.width());
lnk = textState.link;
lnkhost = this; lnkhost = this;
} }

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
namespace MTP { namespace MTP {

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mtproto/file_download.h" #include "mtproto/file_download.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "localstorage.h" #include "localstorage.h"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,337 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "layout.h"
#include "core/click_handler_types.h"
namespace Overview {
namespace Layout {
class PaintContext : public PaintContextBase {
public:
PaintContext(uint64 ms, bool selecting) : PaintContextBase(ms, selecting), isAfterDate(false) {
}
bool isAfterDate;
};
class ItemBase;
class AbstractItem : public LayoutItemBase {
public:
virtual void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const = 0;
virtual ItemBase *toMediaItem() {
return nullptr;
}
virtual const ItemBase *toMediaItem() const {
return nullptr;
}
virtual HistoryItem *getItem() const {
return nullptr;
}
virtual DocumentData *getDocument() const {
return nullptr;
}
MsgId msgId() const {
const HistoryItem *item = getItem();
return item ? item->id : 0;
}
};
class ItemBase : public AbstractItem {
public:
ItemBase(HistoryItem *parent) : _parent(parent) {
}
ItemBase *toMediaItem() override {
return this;
}
const ItemBase *toMediaItem() const override {
return this;
}
HistoryItem *getItem() const override {
return _parent;
}
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool active) override;
protected:
HistoryItem *_parent;
};
class RadialProgressItem : public ItemBase {
public:
RadialProgressItem(HistoryItem *parent) : ItemBase(parent)
, _radial(0)
, a_iconOver(0, 0)
, _a_iconOver(animation(this, &RadialProgressItem::step_iconOver)) {
}
RadialProgressItem(const RadialProgressItem &other) = delete;
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool active) override;
~RadialProgressItem();
protected:
ClickHandlerPtr _openl, _savel, _cancell;
void setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell);
void setDocumentLinks(DocumentData *document) {
ClickHandlerPtr save;
if (document->voice()) {
save.reset(new DocumentOpenClickHandler(document));
} else {
save.reset(new DocumentSaveClickHandler(document));
}
setLinks(MakeShared<DocumentOpenClickHandler>(document), std_::move(save), MakeShared<DocumentCancelClickHandler>(document));
}
void step_iconOver(float64 ms, bool timer);
void step_radial(uint64 ms, bool timer);
void ensureRadial() const;
void checkRadialFinished();
bool isRadialAnimation(uint64 ms) const {
if (!_radial || !_radial->animating()) return false;
_radial->step(ms);
return _radial && _radial->animating();
}
virtual float64 dataProgress() const = 0;
virtual bool dataFinished() const = 0;
virtual bool dataLoaded() const = 0;
virtual bool iconAnimated() const {
return false;
}
mutable RadialAnimation *_radial;
anim::fvalue a_iconOver;
mutable Animation _a_iconOver;
};
class FileBase : public RadialProgressItem {
public:
FileBase(HistoryItem *parent) : RadialProgressItem(parent) {
}
protected:
// >= 0 will contain download / upload string, _statusSize = loaded bytes
// < 0 will contain played string, _statusSize = -(seconds + 1) played
// 0x7FFFFFF0 will contain status for not yet downloaded file
// 0x7FFFFFF1 will contain status for already downloaded file
// 0x7FFFFFF2 will contain status for failed to download / upload file
mutable int32 _statusSize;
mutable QString _statusText;
// duration = -1 - no duration, duration = -2 - "GIF" duration
void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
};
struct Info : public BaseComponent<Info> {
int top = 0;
};
class Date : public AbstractItem {
public:
Date(const QDate &date, bool month);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
private:
QDate _date;
QString _text;
};
class Photo : public ItemBase {
public:
Photo(PhotoData *photo, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
PhotoData *_data;
ClickHandlerPtr _link;
mutable QPixmap _pix;
mutable bool _goodLoaded;
};
class Video : public FileBase {
public:
Video(DocumentData *video, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return true;
}
private:
DocumentData *_data;
QString _duration;
mutable QPixmap _pix;
mutable bool _thumbLoaded;
void updateStatusText() const;
};
class Voice : public FileBase {
public:
Voice(DocumentData *voice, HistoryItem *parent);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return true;
}
private:
DocumentData *_data;
ClickHandlerPtr _namel;
mutable Text _name, _details;
mutable int32 _nameVersion;
void updateName() const;
bool updateStatusText() const;
};
class Document : public FileBase {
public:
Document(DocumentData *document, HistoryItem *parent);
void initDimensions() override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
virtual DocumentData *getDocument() const override {
return _data;
}
protected:
float64 dataProgress() const override {
return _data->progress();
}
bool dataFinished() const override {
return !_data->loading();
}
bool dataLoaded() const override {
return _data->loaded();
}
bool iconAnimated() const override {
return _data->song() || !_data->loaded() || (_radial && _radial->animating());
}
private:
DocumentData *_data;
ClickHandlerPtr _msgl, _namel;
mutable bool _thumbForLoaded;
mutable QPixmap _thumb;
QString _name, _date, _ext;
int32 _namew, _datew, _extw;
int32 _thumbw, _colorIndex;
bool withThumb() const {
return !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height();
}
bool updateStatusText() const;
};
class Link : public ItemBase {
public:
Link(HistoryMedia *media, HistoryItem *parent);
void initDimensions() override;
int32 resizeGetHeight(int32 width) override;
void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
private:
ClickHandlerPtr _photol;
QString _title, _letter;
int _titlew = 0;
WebPageData *_page = nullptr;
int _pixw = 0;
int _pixh = 0;
Text _text = { int(st::msgMinWidth) };
struct LinkEntry {
LinkEntry() : width(0) {
}
LinkEntry(const QString &url, const QString &text);
QString text;
int32 width;
TextClickHandlerPtr lnk;
};
QVector<LinkEntry> _links;
};
} // namespace Layout
} // namespace Overview

View file

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "lang.h" #include "lang.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "overviewwidget.h" #include "overviewwidget.h"
#include "boxes/addcontactbox.h" #include "boxes/addcontactbox.h"
@ -29,6 +29,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/photocropbox.h" #include "boxes/photocropbox.h"
#include "application.h" #include "application.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "playerwidget.h"
#include "window/top_bar_widget.h"
#include "overview/overview_layout.h"
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -333,7 +336,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
} }
index += delta; index += delta;
while (index >= 0 && index < _items.size() && !_items.at(index)->toLayoutMediaItem()) { while (index >= 0 && index < _items.size() && !_items.at(index)->toMediaItem()) {
index += (delta > 0) ? 1 : -1; index += (delta > 0) ? 1 : -1;
} }
if (index < 0 || index >= _items.size()) { if (index < 0 || index >= _items.size()) {
@ -354,7 +357,7 @@ void OverviewInner::repaintItem(MsgId itemId, int32 itemIndex) {
int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow; int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow;
update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize); update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize);
} else { } else {
int32 top = _items.at(itemIndex)->Get<OverviewItemInfo>()->top; int32 top = _items.at(itemIndex)->Get<Overview::Layout::Info>()->top;
if (_reversed) top = _height - top; if (_reversed) top = _height - top;
update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(itemIndex)->height()); update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(itemIndex)->height());
} }
@ -563,8 +566,8 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu
if (_dragSelFrom && _dragSelTo) { if (_dragSelFrom && _dragSelTo) {
applyDragSelection(); applyDragSelection();
} else if (!_selected.isEmpty() && !_dragWasInactive) { } else if (!_selected.isEmpty() && !_dragWasInactive) {
uint32 sel = _selected.cbegin().value(); auto sel = _selected.cbegin().value();
if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { if (sel != FullSelection && sel.from == sel.to) {
_selected.clear(); _selected.clear();
App::main()->activate(); App::main()->activate();
} }
@ -698,7 +701,7 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) {
p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip); p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip);
p.setY(p.y() - _marginTop - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip); p.setY(p.y() - _marginTop - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip);
} else { } else {
int32 top = _items.at(itemIndex)->Get<OverviewItemInfo>()->top; int32 top = _items.at(itemIndex)->Get<Overview::Layout::Info>()->top;
if (_reversed) top = _height - top; if (_reversed) top = _height - top;
p.setY(p.y() - _marginTop - top); p.setY(p.y() - _marginTop - top);
} }
@ -734,7 +737,7 @@ int32 OverviewInner::itemTop(const FullMsgId &msgId) const {
int32 itemIndex = -1; int32 itemIndex = -1;
fixItemIndex(itemIndex, (msgId.channel == _channel) ? msgId.msg : ((_migrated && msgId.channel == _migrated->channelId()) ? -msgId.msg : 0)); fixItemIndex(itemIndex, (msgId.channel == _channel) ? msgId.msg : ((_migrated && msgId.channel == _migrated->channelId()) ? -msgId.msg : 0));
if (itemIndex >= 0) { if (itemIndex >= 0) {
int32 top = _items.at(itemIndex)->Get<OverviewItemInfo>()->top; int32 top = _items.at(itemIndex)->Get<Overview::Layout::Info>()->top;
if (_reversed) top = _height - top; if (_reversed) top = _height - top;
return _marginTop + top; return _marginTop + top;
} }
@ -779,15 +782,15 @@ bool OverviewInner::preloadLocal() {
return true; return true;
} }
uint32 OverviewInner::itemSelectedValue(int32 index) const { TextSelection OverviewInner::itemSelectedValue(int32 index) const {
int32 selfrom = -1, selto = -1; int32 selfrom = -1, selto = -1;
if (_dragSelFromIndex >= 0 && _dragSelToIndex >= 0) { if (_dragSelFromIndex >= 0 && _dragSelToIndex >= 0) {
selfrom = _dragSelToIndex; selfrom = _dragSelToIndex;
selto = _dragSelFromIndex; selto = _dragSelFromIndex;
} }
if (_items.at(index)->toLayoutMediaItem()) { // draw item if (_items.at(index)->toMediaItem()) { // draw item
if (index >= _dragSelToIndex && index <= _dragSelFromIndex && _dragSelToIndex >= 0) { if (index >= _dragSelToIndex && index <= _dragSelFromIndex && _dragSelToIndex >= 0) {
return (_dragSelecting && _items.at(index)->msgId() > 0) ? FullSelection : 0; return (_dragSelecting && _items.at(index)->msgId() > 0) ? FullSelection : TextSelection{ 0, 0 };
} else if (!_selected.isEmpty()) { } else if (!_selected.isEmpty()) {
SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(index)->getItem())); SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(index)->getItem()));
if (j != _selected.cend()) { if (j != _selected.cend()) {
@ -795,7 +798,7 @@ uint32 OverviewInner::itemSelectedValue(int32 index) const {
} }
} }
} }
return 0; return { 0, 0 };
} }
void OverviewInner::paintEvent(QPaintEvent *e) { void OverviewInner::paintEvent(QPaintEvent *e) {
@ -809,7 +812,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r); p.setClipRect(r);
} }
uint64 ms = getms(); uint64 ms = getms();
PaintContextOverview context(ms, _selMode); Overview::Layout::PaintContext context(ms, _selMode);
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) { if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9); QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
@ -854,15 +857,15 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
int32 y = 0, w = _rowWidth; int32 y = 0, w = _rowWidth;
for (int32 j = 0, l = _items.size(); j < l; ++j) { for (int32 j = 0, l = _items.size(); j < l; ++j) {
int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1);
int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->Get<OverviewItemInfo>()->top; int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->Get<Overview::Layout::Info>()->top;
if (_reversed) nextItemTop = _height - nextItemTop; if (_reversed) nextItemTop = _height - nextItemTop;
if (_marginTop + nextItemTop > r.top()) { if (_marginTop + nextItemTop > r.top()) {
OverviewItemInfo *info = _items.at(i)->Get<OverviewItemInfo>(); auto info = _items.at(i)->Get<Overview::Layout::Info>();
int32 curY = info->top; int32 curY = info->top;
if (_reversed) curY = _height - curY; if (_reversed) curY = _height - curY;
if (_marginTop + curY >= r.y() + r.height()) break; if (_marginTop + curY >= r.y() + r.height()) break;
context.isAfterDate = (j > 0) ? !_items.at(j - 1)->toLayoutMediaItem() : false; context.isAfterDate = (j > 0) ? !_items.at(j - 1)->toMediaItem() : false;
p.translate(0, curY - y); p.translate(0, curY - y);
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context); _items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context);
y = curY; y = curY;
@ -908,7 +911,7 @@ void OverviewInner::onUpdateSelected() {
upon = false; upon = false;
} }
if (i >= 0) { if (i >= 0) {
if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) { if (auto media = _items.at(i)->toMediaItem()) {
item = media->getItem(); item = media->getItem();
index = i; index = i;
if (upon) { if (upon) {
@ -921,23 +924,23 @@ void OverviewInner::onUpdateSelected() {
for (int32 j = 0, l = _items.size(); j < l; ++j) { for (int32 j = 0, l = _items.size(); j < l; ++j) {
bool lastItem = (j + 1 == l); bool lastItem = (j + 1 == l);
int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1);
int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->Get<OverviewItemInfo>()->top; int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->Get<Overview::Layout::Info>()->top;
if (_reversed) nextItemTop = _height - nextItemTop; if (_reversed) nextItemTop = _height - nextItemTop;
if (_marginTop + nextItemTop > m.y() || lastItem) { if (_marginTop + nextItemTop > m.y() || lastItem) {
int32 top = _items.at(i)->Get<OverviewItemInfo>()->top; int32 top = _items.at(i)->Get<Overview::Layout::Info>()->top;
if (_reversed) top = _height - top; if (_reversed) top = _height - top;
if (!_items.at(i)->toLayoutMediaItem()) { // day item if (!_items.at(i)->toMediaItem()) { // day item
int32 h = _items.at(i)->height(); int32 h = _items.at(i)->height();
bool beforeItem = (_marginTop + top + h / 2) >= m.y(); bool beforeItem = (_marginTop + top + h / 2) >= m.y();
if (_reversed) beforeItem = !beforeItem; if (_reversed) beforeItem = !beforeItem;
if (i > 0 && (beforeItem || i == _items.size() - 1)) { if (i > 0 && (beforeItem || i == _items.size() - 1)) {
--i; --i;
if (!_items.at(i)->toLayoutMediaItem()) break; // wtf if (!_items.at(i)->toMediaItem()) break; // wtf
top = _items.at(i)->Get<OverviewItemInfo>()->top; top = _items.at(i)->Get<Overview::Layout::Info>()->top;
} else if (i < _items.size() - 1 && (!beforeItem || !i)) { } else if (i < _items.size() - 1 && (!beforeItem || !i)) {
++i; ++i;
if (!_items.at(i)->toLayoutMediaItem()) break; // wtf if (!_items.at(i)->toMediaItem()) break; // wtf
top = _items.at(i)->Get<OverviewItemInfo>()->top; top = _items.at(i)->Get<Overview::Layout::Info>()->top;
} else { } else {
break; // wtf break; // wtf
} }
@ -945,7 +948,7 @@ void OverviewInner::onUpdateSelected() {
j = _reversed ? (l - i - 1) : i; j = _reversed ? (l - i - 1) : i;
} }
if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) { if (auto media = _items.at(i)->toMediaItem()) {
item = media->getItem(); item = media->getItem();
index = i; index = i;
media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top); media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top);
@ -1007,7 +1010,7 @@ void OverviewInner::onUpdateSelected() {
if (_mousedItem == _dragItem && lnk && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { if (_mousedItem == _dragItem && lnk && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) {
bool afterSymbol = false, uponSymbol = false; bool afterSymbol = false, uponSymbol = false;
uint16 second = 0; uint16 second = 0;
_selected[_dragItem] = 0; _selected[_dragItem] = { 0, 0 };
updateDragSelection(0, -1, 0, -1, false); updateDragSelection(0, -1, 0, -1, false);
} else if (canSelectMany) { } else if (canSelectMany) {
bool selectingDown = (_reversed ? (_mousedItemIndex < _dragItemIndex) : (_mousedItemIndex > _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y()))); bool selectingDown = (_reversed ? (_mousedItemIndex < _dragItemIndex) : (_mousedItemIndex > _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
@ -1325,7 +1328,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh
for (int32 i = 0, l = _items.size(); i < l; ++i) { for (int32 i = 0, l = _items.size(); i < l; ++i) {
int32 h = _items.at(i)->resizeGetHeight(_rowWidth); int32 h = _items.at(i)->resizeGetHeight(_rowWidth);
if (resize) { if (resize) {
_items.at(i)->Get<OverviewItemInfo>()->top = _height + (_reversed ? h : 0); _items.at(i)->Get<Overview::Layout::Info>()->top = _height + (_reversed ? h : 0);
_height += h; _height += h;
} }
} }
@ -1632,7 +1635,7 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false; allGood = false;
} }
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItemBase *layout = layoutPrepare(item); auto layout = layoutPrepare(item);
if (!layout) continue; if (!layout) continue;
setLayoutItem(index, layout, 0); setLayoutItem(index, layout, 0);
@ -1658,17 +1661,17 @@ void OverviewInner::mediaOverviewUpdated() {
if (allGood) { if (allGood) {
if (_items.size() > index && complexMsgId(_items.at(index)->getItem()) == msgid) { if (_items.size() > index && complexMsgId(_items.at(index)->getItem()) == msgid) {
if (withDates) prevDate = _items.at(index)->getItem()->date.date(); if (withDates) prevDate = _items.at(index)->getItem()->date.date();
top = _items.at(index)->Get<OverviewItemInfo>()->top; top = _items.at(index)->Get<Overview::Layout::Info>()->top;
if (!_reversed) { if (!_reversed) {
top += _items.at(index)->height(); top += _items.at(index)->height();
} }
++index; ++index;
continue; continue;
} }
if (_items.size() > index + 1 && !_items.at(index)->toLayoutMediaItem() && complexMsgId(_items.at(index + 1)->getItem()) == msgid) { // day item if (_items.size() > index + 1 && !_items.at(index)->toMediaItem() && complexMsgId(_items.at(index + 1)->getItem()) == msgid) { // day item
++index; ++index;
if (withDates) prevDate = _items.at(index)->getItem()->date.date(); if (withDates) prevDate = _items.at(index)->getItem()->date.date();
top = _items.at(index)->Get<OverviewItemInfo>()->top; top = _items.at(index)->Get<Overview::Layout::Info>()->top;
if (!_reversed) { if (!_reversed) {
top += _items.at(index)->height(); top += _items.at(index)->height();
} }
@ -1678,7 +1681,7 @@ void OverviewInner::mediaOverviewUpdated() {
allGood = false; allGood = false;
} }
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
LayoutMediaItemBase *layout = layoutPrepare(item); auto layout = layoutPrepare(item);
if (!layout) continue; if (!layout) continue;
if (withDates) { if (withDates) {
@ -1726,7 +1729,7 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) {
if (_selectedMsgId == oldId) _selectedMsgId = newId; if (_selectedMsgId == oldId) _selectedMsgId = newId;
for (SelectedItems::iterator i = _selected.begin(), e = _selected.end(); i != e; ++i) { for (SelectedItems::iterator i = _selected.begin(), e = _selected.end(); i != e; ++i) {
if (i.key() == oldId) { if (i.key() == oldId) {
uint32 sel = i.value(); auto sel = i.value();
_selected.erase(i); _selected.erase(i);
_selected.insert(newId, sel); _selected.insert(newId, sel);
break; break;
@ -1795,7 +1798,7 @@ void OverviewInner::repaintItem(const HistoryItem *msg) {
if (history == _migrated) msgid = -msgid; if (history == _migrated) msgid = -msgid;
for (int32 i = 0, l = _items.size(); i != l; ++i) { for (int32 i = 0, l = _items.size(); i != l; ++i) {
if (complexMsgId(_items.at(i)->getItem()) == msgid) { if (complexMsgId(_items.at(i)->getItem()) == msgid) {
int32 top = _items.at(i)->Get<OverviewItemInfo>()->top; int32 top = _items.at(i)->Get<Overview::Layout::Info>()->top;
if (_reversed) top = _height - top; if (_reversed) top = _height - top;
update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(i)->height()); update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(i)->height());
break; break;
@ -1840,7 +1843,7 @@ void OverviewInner::recountMargins() {
} }
} }
LayoutMediaItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { Overview::Layout::ItemBase *OverviewInner::layoutPrepare(HistoryItem *item) {
if (!item) return nullptr; if (!item) return nullptr;
LayoutItems::const_iterator i = _layoutItems.cend(); LayoutItems::const_iterator i = _layoutItems.cend();
@ -1848,59 +1851,59 @@ LayoutMediaItemBase *OverviewInner::layoutPrepare(HistoryItem *item) {
if (_type == OverviewPhotos) { if (_type == OverviewPhotos) {
if (media && media->type() == MediaTypePhoto) { if (media && media->type() == MediaTypePhoto) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewPhoto(static_cast<HistoryPhoto*>(media)->photo(), item)); i = _layoutItems.insert(item, new Overview::Layout::Photo(static_cast<HistoryPhoto*>(media)->photo(), item));
i.value()->initDimensions(); i.value()->initDimensions();
} }
} }
} else if (_type == OverviewVideos) { } else if (_type == OverviewVideos) {
if (media && media->type() == MediaTypeVideo) { if (media && media->type() == MediaTypeVideo) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewVideo(media->getDocument(), item)); i = _layoutItems.insert(item, new Overview::Layout::Video(media->getDocument(), item));
i.value()->initDimensions(); i.value()->initDimensions();
} }
} }
} else if (_type == OverviewVoiceFiles) { } else if (_type == OverviewVoiceFiles) {
if (media && (media->type() == MediaTypeVoiceFile)) { if (media && (media->type() == MediaTypeVoiceFile)) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewVoice(media->getDocument(), item)); i = _layoutItems.insert(item, new Overview::Layout::Voice(media->getDocument(), item));
i.value()->initDimensions(); i.value()->initDimensions();
} }
} }
} else if (_type == OverviewFiles || _type == OverviewMusicFiles) { } else if (_type == OverviewFiles || _type == OverviewMusicFiles) {
if (media && (media->type() == MediaTypeFile || media->type() == MediaTypeMusicFile || media->type() == MediaTypeGif)) { if (media && (media->type() == MediaTypeFile || media->type() == MediaTypeMusicFile || media->type() == MediaTypeGif)) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewDocument(media->getDocument(), item)); i = _layoutItems.insert(item, new Overview::Layout::Document(media->getDocument(), item));
i.value()->initDimensions(); i.value()->initDimensions();
} }
} }
} else if (_type == OverviewLinks) { } else if (_type == OverviewLinks) {
if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) {
i = _layoutItems.insert(item, new LayoutOverviewLink(media, item)); i = _layoutItems.insert(item, new Overview::Layout::Link(media, item));
i.value()->initDimensions(); i.value()->initDimensions();
} }
} }
return (i == _layoutItems.cend()) ? nullptr : i.value(); return (i == _layoutItems.cend()) ? nullptr : i.value();
} }
LayoutOverviewItemBase *OverviewInner::layoutPrepare(const QDate &date, bool month) { Overview::Layout::AbstractItem *OverviewInner::layoutPrepare(const QDate &date, bool month) {
int32 key = date.year() * 100 + date.month(); int32 key = date.year() * 100 + date.month();
if (!month) key = key * 100 + date.day(); if (!month) key = key * 100 + date.day();
LayoutDates::const_iterator i = _layoutDates.constFind(key); LayoutDates::const_iterator i = _layoutDates.constFind(key);
if (i == _layoutDates.cend()) { if (i == _layoutDates.cend()) {
i = _layoutDates.insert(key, new LayoutOverviewDate(date, month)); i = _layoutDates.insert(key, new Overview::Layout::Date(date, month));
i.value()->initDimensions(); i.value()->initDimensions();
} }
return i.value(); return i.value();
} }
int32 OverviewInner::setLayoutItem(int32 index, LayoutOverviewItemBase *item, int32 top) { int32 OverviewInner::setLayoutItem(int32 index, Overview::Layout::AbstractItem *item, int32 top) {
if (_items.size() > index) { if (_items.size() > index) {
_items[index] = item; _items[index] = item;
} else { } else {
_items.push_back(item); _items.push_back(item);
} }
int32 h = item->resizeGetHeight(_rowWidth); int32 h = item->resizeGetHeight(_rowWidth);
if (OverviewItemInfo *info = item->Get<OverviewItemInfo>()) { if (auto info = item->Get<Overview::Layout::Info>()) {
info->top = top + (_reversed ? h : 0); info->top = top + (_reversed ? h : 0);
} }
return h; return h;

View file

@ -20,6 +20,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
namespace Overview {
namespace Layout {
class AbstractItem;
class ItemBase;
class Date;
} // namespace Layout
} // namespace Overview
class OverviewWidget; class OverviewWidget;
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender { class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender {
Q_OBJECT Q_OBJECT
@ -148,19 +158,19 @@ private:
ChannelId _channel; ChannelId _channel;
bool _selMode; bool _selMode;
uint32 itemSelectedValue(int32 index) const; TextSelection itemSelectedValue(int32 index) const;
int32 _rowsLeft, _rowWidth; int32 _rowsLeft, _rowWidth;
typedef QVector<LayoutOverviewItemBase*> Items; typedef QVector<Overview::Layout::AbstractItem*> Items;
Items _items; Items _items;
typedef QMap<HistoryItem*, LayoutMediaItemBase*> LayoutItems; typedef QMap<HistoryItem*, Overview::Layout::ItemBase*> LayoutItems;
LayoutItems _layoutItems; LayoutItems _layoutItems;
typedef QMap<int32, LayoutOverviewDate*> LayoutDates; typedef QMap<int32, Overview::Layout::Date*> LayoutDates;
LayoutDates _layoutDates; LayoutDates _layoutDates;
LayoutMediaItemBase *layoutPrepare(HistoryItem *item); Overview::Layout::ItemBase *layoutPrepare(HistoryItem *item);
LayoutOverviewItemBase *layoutPrepare(const QDate &date, bool month); Overview::Layout::AbstractItem *layoutPrepare(const QDate &date, bool month);
int32 setLayoutItem(int32 index, LayoutOverviewItemBase *item, int32 top); int32 setLayoutItem(int32 index, Overview::Layout::AbstractItem *item, int32 top);
FlatInput _search; FlatInput _search;
IconedButton _cancelSearch; IconedButton _cancelSearch;
@ -199,7 +209,7 @@ private:
// selection support, like in HistoryWidget // selection support, like in HistoryWidget
Qt::CursorShape _cursor; Qt::CursorShape _cursor;
HistoryCursorState _cursorState; HistoryCursorState _cursorState;
typedef QMap<MsgId, uint32> SelectedItems; using SelectedItems = QMap<MsgId, TextSelection>;
SelectedItems _selected; SelectedItems _selected;
enum DragAction { enum DragAction {
NoDrag = 0x00, NoDrag = 0x00,

View file

@ -25,9 +25,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
#include "passcodewidget.h" #include "passcodewidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "ui/text.h" #include "ui/text/text.h"
PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent) PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
, _a_show(animation(this, &PasscodeWidget::step_show)) , _a_show(animation(this, &PasscodeWidget::step_show))

View file

@ -19,41 +19,21 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "playerwidget.h"
#include "shortcuts.h"
#include "ui/style.h" #include "ui/style.h"
#include "lang.h" #include "lang.h"
#include "boxes/addcontactbox.h" #include "boxes/addcontactbox.h"
#include "application.h" #include "application.h"
#include "window.h" #include "mainwindow.h"
#include "playerwidget.h" #include "playerwidget.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "localstorage.h" #include "localstorage.h"
#include "audio.h" #include "audio.h"
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent) PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent)
, _prevAvailable(false)
, _nextAvailable(false)
, _fullAvailable(false)
, _over(OverNone)
, _down(OverNone)
, _downCoord(0)
, _downFrequency(AudioVoiceMsgFrequency)
, _downProgress(0.)
, _a_state(animation(this, &PlayerWidget::step_state)) , _a_state(animation(this, &PlayerWidget::step_state))
, _msgmigrated(false)
, _index(-1)
, _migrated(0)
, _history(0)
, _timeWidth(0)
, _repeat(false)
, _showPause(false)
, _position(0)
, _duration(0)
, _loaded(0)
, a_progress(0., 0.)
, a_loadProgress(0., 0.)
, _a_progress(animation(this, &PlayerWidget::step_progress)) , _a_progress(animation(this, &PlayerWidget::step_progress))
, _sideShadow(this, st::shadowColor) { , _sideShadow(this, st::shadowColor) {
resize(st::wndMinWidth, st::playerHeight); resize(st::wndMinWidth, st::playerHeight);
@ -372,6 +352,29 @@ bool PlayerWidget::seekingSong(const SongMsgId &song) const {
return (_down == OverPlayback) && (song == _song); return (_down == OverPlayback) && (song == _song);
} }
void PlayerWidget::openPlayer() {
_playerOpened = true;
Shortcuts::enableMediaShortcuts();
}
bool PlayerWidget::isOpened() const {
return _playerOpened;
}
void PlayerWidget::closePlayer() {
_playerOpened = false;
Shortcuts::disableMediaShortcuts();
}
void PlayerWidget::showPlayer() {
TWidget::show();
}
void PlayerWidget::hidePlayer() {
clearSelection();
TWidget::hide();
}
void PlayerWidget::step_state(uint64 ms, bool timer) { void PlayerWidget::step_state(uint64 ms, bool timer) {
for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) { for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) {
int32 over = qAbs(i.key()); int32 over = qAbs(i.key());
@ -463,7 +466,7 @@ void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) {
} }
update(); update();
} else if (_down == OverClose && _over == OverClose) { } else if (_down == OverClose && _over == OverClose) {
stopPressed(); closePressed();
} }
_down = OverNone; _down = OverNone;
} }
@ -545,7 +548,11 @@ void PlayerWidget::stopPressed() {
if (!_song || isHidden()) return; if (!_song || isHidden()) return;
audioPlayer()->stop(OverviewFiles); audioPlayer()->stop(OverviewFiles);
if (App::main()) App::main()->hidePlayer(); }
void PlayerWidget::closePressed() {
stopPressed();
if (App::main()) App::main()->closePlayer();
} }
void PlayerWidget::resizeEvent(QResizeEvent *e) { void PlayerWidget::resizeEvent(QResizeEvent *e) {

View file

@ -42,6 +42,7 @@ public:
void prevPressed(); void prevPressed();
void nextPressed(); void nextPressed();
void stopPressed(); void stopPressed();
void closePressed();
void step_progress(float64 ms, bool timer); void step_progress(float64 ms, bool timer);
void step_state(uint64 ms, bool timer); void step_state(uint64 ms, bool timer);
@ -55,12 +56,23 @@ public:
bool seekingSong(const SongMsgId &song) const; bool seekingSong(const SongMsgId &song) const;
void openPlayer();
bool isOpened() const;
void closePlayer();
void showPlayer();
void hidePlayer();
signals: signals:
void playerSongChanged(const FullMsgId &msgId); void playerSongChanged(const FullMsgId &msgId);
private: private:
// Use startPlayer()/stopPlayer() or showPlayer()/hidePlayer() instead.
void show();
void hide();
enum OverState { enum OverState {
OverNone = 0, OverNone = 0,
OverPrev, OverPrev,
@ -87,12 +99,17 @@ private:
QPoint _lastMousePos; QPoint _lastMousePos;
void updateSelected(); void updateSelected();
bool _prevAvailable, _nextAvailable, _fullAvailable; bool _playerOpened = false;
OverState _over, _down;
int32 _downCoord; bool _prevAvailable = false;
bool _nextAvailable = false;
bool _fullAvailable = false;
OverState _over = OverNone;
OverState _down = OverNone;
int32 _downCoord = 0;
int64 _downDuration; int64 _downDuration;
int32 _downFrequency; int32 _downFrequency = AudioVoiceMsgFrequency;
float64 _downProgress; float64 _downProgress = 0.;
float64 _stateHovers[OverStateCount]; float64 _stateHovers[OverStateCount];
typedef QMap<int32, uint64> StateAnimations; typedef QMap<int32, uint64> StateAnimations;
@ -100,20 +117,23 @@ private:
Animation _a_state; Animation _a_state;
SongMsgId _song; SongMsgId _song;
bool _msgmigrated; bool _msgmigrated = false;
int32 _index; int32 _index = -1;
History *_migrated, *_history; History *_migrated = nullptr;
History *_history = nullptr;
QRect _playRect, _prevRect, _nextRect, _playbackRect; QRect _playRect, _prevRect, _nextRect, _playbackRect;
QRect _closeRect, _volumeRect, _fullRect, _repeatRect, _infoRect; QRect _closeRect, _volumeRect, _fullRect, _repeatRect, _infoRect;
int32 _timeWidth; int32 _timeWidth = 0;
bool _repeat; bool _repeat = false;
QString _time; QString _time;
Text _name; Text _name;
bool _showPause; bool _showPause = false;
int64 _position, _duration; int64 _position = 0;
int32 _loaded; int64 _duration = 0;
int32 _loaded = 0;
anim::fvalue a_progress, a_loadProgress; anim::fvalue a_progress = { 0., 0. };
anim::fvalue a_loadProgress = { 0., 0. };
Animation _a_progress; Animation _a_progress;
PlainShadow _sideShadow; PlainShadow _sideShadow;

View file

@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "lang.h" #include "lang.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "profilewidget.h" #include "profilewidget.h"
#include "boxes/addcontactbox.h" #include "boxes/addcontactbox.h"
@ -30,6 +30,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "application.h" #include "application.h"
#include "boxes/contactsbox.h" #include "boxes/contactsbox.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "apiwrap.h"
#include "window/top_bar_widget.h"
ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData *peer) : TWidget(0) ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData *peer) : TWidget(0)
, _profile(profile) , _profile(profile)
@ -573,7 +575,7 @@ void ProfileInner::onBotSettings() {
QString cmd = _peerUser->botInfo->commands.at(i).command; QString cmd = _peerUser->botInfo->commands.at(i).command;
if (!cmd.compare(qsl("settings"), Qt::CaseInsensitive)) { if (!cmd.compare(qsl("settings"), Qt::CaseInsensitive)) {
Ui::showPeerHistory(_peer, ShowAtTheEndMsgId); Ui::showPeerHistory(_peer, ShowAtTheEndMsgId);
App::sendBotCommand(_peerUser, '/' + cmd); App::sendBotCommand(_peerUser, _peerUser, '/' + cmd);
return; return;
} }
} }
@ -587,7 +589,7 @@ void ProfileInner::onBotHelp() {
QString cmd = _peerUser->botInfo->commands.at(i).command; QString cmd = _peerUser->botInfo->commands.at(i).command;
if (!cmd.compare(qsl("help"), Qt::CaseInsensitive)) { if (!cmd.compare(qsl("help"), Qt::CaseInsensitive)) {
Ui::showPeerHistory(_peer, ShowAtTheEndMsgId); Ui::showPeerHistory(_peer, ShowAtTheEndMsgId);
App::sendBotCommand(_peerUser, '/' + cmd); App::sendBotCommand(_peerUser, _peerUser, '/' + cmd);
return; return;
} }
} }
@ -1118,9 +1120,9 @@ void ProfileInner::updateSelected() {
ClickHandlerPtr lnk; ClickHandlerPtr lnk;
ClickHandlerHost *lnkhost = nullptr; ClickHandlerHost *lnkhost = nullptr;
bool inText = false;
if (!_about.isEmpty() && lp.y() >= _aboutTop && lp.y() < _aboutTop + _aboutHeight && lp.x() >= _left && lp.x() < _left + _width) { if (!_about.isEmpty() && lp.y() >= _aboutTop && lp.y() < _aboutTop + _aboutHeight && lp.x() >= _left && lp.x() < _left + _width) {
_about.getState(lnk, inText, lp.x() - _left, lp.y() - _aboutTop, _width); auto textState = _about.getState(lp.x() - _left, lp.y() - _aboutTop, _width);
lnk = textState.link;
lnkhost = this; lnkhost = this;
} }
ClickHandler::setActive(lnk, lnkhost); ClickHandler::setActive(lnk, lnkhost);

View file

@ -488,7 +488,7 @@ namespace {
} }
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
Window *wnd = App::wnd(); auto wnd = App::wnd();
if (!wnd) return false; if (!wnd) return false;
return false; return false;

View file

@ -40,7 +40,7 @@ namespace {
} }
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
Window *wnd = AppClass::wnd(); auto wnd = AppClass::wnd();
if (!wnd) return false; if (!wnd) return false;
return wnd->psFilterNativeEvent(message); return wnd->psFilterNativeEvent(message);
@ -57,9 +57,7 @@ void MacPrivate::activeSpaceChanged() {
} }
void MacPrivate::darkModeChanged() { void MacPrivate::darkModeChanged() {
if (App::wnd()) { Notify::unreadCounterUpdated();
App::wnd()->updateCounter();
}
} }
void MacPrivate::notifyClicked(unsigned long long peer, int msgid) { void MacPrivate::notifyClicked(unsigned long long peer, int msgid) {

View file

@ -18,9 +18,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "pspecific_mac_p.h" #include "pspecific_mac_p.h"
#include "window.h" #include "mainwindow.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "application.h" #include "application.h"
#include "playerwidget.h"
#include "lang.h" #include "lang.h"

View file

@ -802,7 +802,7 @@ namespace {
} }
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
Window *wnd = App::wnd(); auto wnd = App::wnd();
if (!wnd) return false; if (!wnd) return false;
MSG *msg = (MSG*)message; MSG *msg = (MSG*)message;

View file

@ -802,7 +802,7 @@ namespace {
} }
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
Window *wnd = App::wnd(); auto wnd = App::wnd();
if (!wnd) return false; if (!wnd) return false;
MSG *msg = (MSG*)message; MSG *msg = (MSG*)message;

View file

@ -41,9 +41,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "boxes/stickersetbox.h" #include "boxes/stickersetbox.h"
#include "langloaderplain.h" #include "langloaderplain.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "apiwrap.h"
#include "autoupdater.h" #include "autoupdater.h"
#include "localstorage.h" #include "localstorage.h"
Slider::Slider(QWidget *parent, const style::slider &st, int32 count, int32 sel) : QWidget(parent), Slider::Slider(QWidget *parent, const style::slider &st, int32 count, int32 sel) : QWidget(parent),
@ -291,9 +290,9 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent)
connect(&_downloadPathEdit, SIGNAL(clicked()), this, SLOT(onDownloadPathEdit())); connect(&_downloadPathEdit, SIGNAL(clicked()), this, SLOT(onDownloadPathEdit()));
connect(&_downloadPathClear, SIGNAL(clicked()), this, SLOT(onDownloadPathClear())); connect(&_downloadPathClear, SIGNAL(clicked()), this, SLOT(onDownloadPathClear()));
switch (App::wnd()->tempDirState()) { switch (App::wnd()->tempDirState()) {
case Window::TempDirEmpty: _tempDirClearState = TempDirEmpty; break; case MainWindow::TempDirEmpty: _tempDirClearState = TempDirEmpty; break;
case Window::TempDirExists: _tempDirClearState = TempDirExists; break; case MainWindow::TempDirExists: _tempDirClearState = TempDirExists; break;
case Window::TempDirRemoving: _tempDirClearState = TempDirClearing; break; case MainWindow::TempDirRemoving: _tempDirClearState = TempDirClearing; break;
} }
connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int)));
connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int)));
@ -302,9 +301,9 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent)
// local storage // local storage
connect(&_localStorageClear, SIGNAL(clicked()), this, SLOT(onLocalStorageClear())); connect(&_localStorageClear, SIGNAL(clicked()), this, SLOT(onLocalStorageClear()));
switch (App::wnd()->localStorageState()) { switch (App::wnd()->localStorageState()) {
case Window::TempDirEmpty: _storageClearState = TempDirEmpty; break; case MainWindow::TempDirEmpty: _storageClearState = TempDirEmpty; break;
case Window::TempDirExists: _storageClearState = TempDirExists; break; case MainWindow::TempDirExists: _storageClearState = TempDirExists; break;
case Window::TempDirRemoving: _storageClearState = TempDirClearing; break; case MainWindow::TempDirRemoving: _storageClearState = TempDirClearing; break;
} }
// chat background // chat background
@ -1516,7 +1515,7 @@ void SettingsInner::onSoundNotify() {
void SettingsInner::onIncludeMuted() { void SettingsInner::onIncludeMuted() {
cSetIncludeMuted(_includeMuted.checked()); cSetIncludeMuted(_includeMuted.checked());
if (App::wnd()) App::wnd()->updateCounter(); Notify::unreadCounterUpdated();
Local::writeUserSettings(); Local::writeUserSettings();
} }
@ -1836,7 +1835,7 @@ void SettingsInner::onPhotoUpdateDone(PeerId peer) {
update(); update();
} }
SettingsWidget::SettingsWidget(Window *parent) : TWidget(parent) SettingsWidget::SettingsWidget(MainWindow *parent) : TWidget(parent)
, _a_show(animation(this, &SettingsWidget::step_show)) , _a_show(animation(this, &SettingsWidget::step_show))
, _scroll(this, st::setScroll) , _scroll(this, st::setScroll)
, _inner(this) , _inner(this)

View file

@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
class Window; class MainWindow;
class Settings; class Settings;
class Slider : public QWidget { class Slider : public QWidget {
@ -313,7 +313,7 @@ class SettingsWidget : public TWidget {
public: public:
SettingsWidget(Window *parent); SettingsWidget(MainWindow *parent);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);

View file

@ -19,421 +19,458 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "shortcuts.h" #include "shortcuts.h"
#include "window.h" #include "mainwindow.h"
#include "passcodewidget.h" #include "passcodewidget.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "playerwidget.h"
namespace ShortcutCommands { namespace ShortcutCommands {
typedef void(*Handler)();
void lock_telegram() { typedef void(*Handler)();
if (Window *w = App::wnd()) {
if (App::passcoded()) { void lock_telegram() {
w->passcodeWidget()->onSubmit(); if (auto w = App::wnd()) {
} else if (cHasPasscode()) { if (App::passcoded()) {
w->setupPasscode(true); w->passcodeWidget()->onSubmit();
} } else if (cHasPasscode()) {
w->setupPasscode(true);
} }
} }
void minimize_telegram() {
if (Window *w = App::wnd()) {
if (cWorkMode() == dbiwmTrayOnly) {
w->minimizeToTray();
} else {
w->setWindowState(Qt::WindowMinimized);
}
}
}
void close_telegram() {
if (!Ui::hideWindowNoQuit()) {
if (Window *w = App::wnd()) {
App::wnd()->close();
}
}
}
void quit_telegram() {
App::quit();
}
//void start_stop_recording() {
//}
//void cancel_recording() {
//}
void media_play() {
if (MainWidget *m = App::main()) {
m->player()->playPressed();
}
}
void media_pause() {
if (MainWidget *m = App::main()) {
m->player()->pausePressed();
}
}
void media_playpause() {
if (MainWidget *m = App::main()) {
m->player()->playPausePressed();
}
}
void media_stop() {
if (MainWidget *m = App::main()) {
m->player()->stopPressed();
}
}
void media_previous() {
if (MainWidget *m = App::main()) {
m->player()->prevPressed();
}
}
void media_next() {
if (MainWidget *m = App::main()) {
m->player()->nextPressed();
}
}
void search() {
if (MainWidget *m = App::main()) {
m->cmd_search();
}
}
void previous_chat() {
if (MainWidget *m = App::main()) {
m->cmd_previous_chat();
}
}
void next_chat() {
if (MainWidget *m = App::main()) {
m->cmd_next_chat();
}
}
// other commands here
} }
void minimize_telegram() {
if (auto w = App::wnd()) {
if (cWorkMode() == dbiwmTrayOnly) {
w->minimizeToTray();
} else {
w->setWindowState(Qt::WindowMinimized);
}
}
}
void close_telegram() {
if (!Ui::hideWindowNoQuit()) {
if (auto w = App::wnd()) {
w->close();
}
}
}
void quit_telegram() {
App::quit();
}
//void start_stop_recording() {
//}
//void cancel_recording() {
//}
void media_play() {
if (MainWidget *m = App::main()) {
m->player()->playPressed();
}
}
void media_pause() {
if (MainWidget *m = App::main()) {
m->player()->pausePressed();
}
}
void media_playpause() {
if (MainWidget *m = App::main()) {
m->player()->playPausePressed();
}
}
void media_stop() {
if (MainWidget *m = App::main()) {
m->player()->stopPressed();
}
}
void media_previous() {
if (MainWidget *m = App::main()) {
m->player()->prevPressed();
}
}
void media_next() {
if (MainWidget *m = App::main()) {
m->player()->nextPressed();
}
}
void search() {
if (MainWidget *m = App::main()) {
m->cmd_search();
}
}
void previous_chat() {
if (MainWidget *m = App::main()) {
m->cmd_previous_chat();
}
}
void next_chat() {
if (MainWidget *m = App::main()) {
m->cmd_next_chat();
}
}
// other commands here
} // namespace ShortcutCommands
inline bool qMapLessThanKey(const ShortcutCommands::Handler &a, const ShortcutCommands::Handler &b) { inline bool qMapLessThanKey(const ShortcutCommands::Handler &a, const ShortcutCommands::Handler &b) {
return a < b; return a < b;
} }
namespace Shortcuts { namespace Shortcuts {
// inspired by https://github.com/sindresorhus/strip-json-comments // inspired by https://github.com/sindresorhus/strip-json-comments
QByteArray _stripJsonComments(const QByteArray &json) { QByteArray _stripJsonComments(const QByteArray &json) {
enum InsideComment { enum InsideComment {
InsideCommentNone, InsideCommentNone,
InsideCommentSingleLine, InsideCommentSingleLine,
InsideCommentMultiLine, InsideCommentMultiLine,
}; };
InsideComment insideComment = InsideCommentNone; InsideComment insideComment = InsideCommentNone;
bool insideString = false; bool insideString = false;
QByteArray result; QByteArray result;
const char *b = json.cbegin(), *e = json.cend(), *offset = b; const char *b = json.cbegin(), *e = json.cend(), *offset = b;
for (const char *ch = offset; ch != e; ++ch) { for (const char *ch = offset; ch != e; ++ch) {
char currentChar = *ch; char currentChar = *ch;
char nextChar = (ch + 1 == e) ? 0 : *(ch + 1); char nextChar = (ch + 1 == e) ? 0 : *(ch + 1);
if (insideComment == InsideCommentNone && currentChar == '"') { if (insideComment == InsideCommentNone && currentChar == '"') {
bool escaped = ((ch > b) && *(ch - 1) == '\\') && ((ch - 1 < b) || *(ch - 2) != '\\'); bool escaped = ((ch > b) && *(ch - 1) == '\\') && ((ch - 1 < b) || *(ch - 2) != '\\');
if (!escaped) { if (!escaped) {
insideString = !insideString; insideString = !insideString;
}
}
if (insideString) {
continue;
}
if (insideComment == InsideCommentNone && currentChar == '/' && nextChar == '/') {
if (ch > offset) {
if (result.isEmpty()) result.reserve(json.size() - 2);
result.append(offset, ch - offset);
offset = ch;
}
insideComment = InsideCommentSingleLine;
++ch;
} else if (insideComment == InsideCommentSingleLine && currentChar == '\r' && nextChar == '\n') {
if (ch > offset) {
offset = ch;
}
++ch;
insideComment = InsideCommentNone;
} else if (insideComment == InsideCommentSingleLine && currentChar == '\n') {
if (ch > offset) {
offset = ch;
}
insideComment = InsideCommentNone;
} else if (insideComment == InsideCommentNone && currentChar == '/' && nextChar == '*') {
if (ch > offset) {
if (result.isEmpty()) result.reserve(json.size() - 2);
result.append(offset, ch - offset);
offset = ch;
}
insideComment = InsideCommentMultiLine;
++ch;
} else if (insideComment == InsideCommentMultiLine && currentChar == '*' && nextChar == '/') {
if (ch > offset) {
offset = ch;
}
++ch;
insideComment = InsideCommentNone;
} }
} }
if (insideComment == InsideCommentNone && e > offset && !result.isEmpty()) { if (insideString) {
result.append(offset, e - offset); continue;
}
if (insideComment == InsideCommentNone && currentChar == '/' && nextChar == '/') {
if (ch > offset) {
if (result.isEmpty()) result.reserve(json.size() - 2);
result.append(offset, ch - offset);
offset = ch;
}
insideComment = InsideCommentSingleLine;
++ch;
} else if (insideComment == InsideCommentSingleLine && currentChar == '\r' && nextChar == '\n') {
if (ch > offset) {
offset = ch;
}
++ch;
insideComment = InsideCommentNone;
} else if (insideComment == InsideCommentSingleLine && currentChar == '\n') {
if (ch > offset) {
offset = ch;
}
insideComment = InsideCommentNone;
} else if (insideComment == InsideCommentNone && currentChar == '/' && nextChar == '*') {
if (ch > offset) {
if (result.isEmpty()) result.reserve(json.size() - 2);
result.append(offset, ch - offset);
offset = ch;
}
insideComment = InsideCommentMultiLine;
++ch;
} else if (insideComment == InsideCommentMultiLine && currentChar == '*' && nextChar == '/') {
if (ch > offset) {
offset = ch;
}
++ch;
insideComment = InsideCommentNone;
} }
return result.isEmpty() ? json : result;
} }
struct DataStruct; if (insideComment == InsideCommentNone && e > offset && !result.isEmpty()) {
DataStruct *DataPtr = nullptr; result.append(offset, e - offset);
}
return result.isEmpty() ? json : result;
}
void _createCommand(const QString &command, ShortcutCommands::Handler handler); struct DataStruct;
QKeySequence _setShortcut(const QString &keys, const QString &command); DataStruct *DataPtr = nullptr;
struct DataStruct {
DataStruct() {
t_assert(DataPtr == nullptr);
DataPtr = this;
#define DeclareAlias(keys, command) _setShortcut(qsl(keys), qsl(#command)) namespace {
#define DeclareCommand(keys, command) _createCommand(qsl(#command), ShortcutCommands::command); DeclareAlias(keys, command)
DeclareCommand("ctrl+w", close_telegram); void createCommand(const QString &command, ShortcutCommands::Handler handler);
DeclareAlias("ctrl+f4", close_telegram); QKeySequence setShortcut(const QString &keys, const QString &command);
DeclareCommand("ctrl+l", lock_telegram); void destroyShortcut(QShortcut *shortcut);
DeclareCommand("ctrl+m", minimize_telegram);
DeclareCommand("ctrl+q", quit_telegram);
//DeclareCommand("ctrl+r", start_stop_recording); } // namespace
//DeclareCommand("ctrl+shift+r", cancel_recording);
//DeclareCommand("media record", start_stop_recording);
DeclareCommand("media play", media_play); struct DataStruct {
DeclareCommand("media pause", media_pause); DataStruct() {
DeclareCommand("toggle media play/pause", media_playpause); t_assert(DataPtr == nullptr);
DeclareCommand("media stop", media_stop); DataPtr = this;
DeclareCommand("media previous", media_previous);
DeclareCommand("media next", media_next);
DeclareCommand("ctrl+f", search); #define DeclareAlias(keys, command) setShortcut(qsl(keys), qsl(#command))
DeclareAlias("search", search); #define DeclareCommand(keys, command) createCommand(qsl(#command), ShortcutCommands::command); DeclareAlias(keys, command)
DeclareAlias("find", search);
DeclareCommand("ctrl+pgdown", next_chat); DeclareCommand("ctrl+w", close_telegram);
DeclareAlias("alt+down", next_chat); DeclareAlias("ctrl+f4", close_telegram);
DeclareCommand("ctrl+pgup", previous_chat); DeclareCommand("ctrl+l", lock_telegram);
DeclareAlias("alt+up", previous_chat); DeclareCommand("ctrl+m", minimize_telegram);
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { DeclareCommand("ctrl+q", quit_telegram);
DeclareAlias("meta+tab", next_chat);
DeclareAlias("meta+shift+tab", previous_chat);
DeclareAlias("meta+backtab", previous_chat);
} else {
DeclareAlias("ctrl+tab", next_chat);
DeclareAlias("ctrl+shift+tab", previous_chat);
DeclareAlias("ctrl+backtab", previous_chat);
}
// other commands here //DeclareCommand("ctrl+r", start_stop_recording);
//DeclareCommand("ctrl+shift+r", cancel_recording);
//DeclareCommand("media record", start_stop_recording);
DeclareCommand("media play", media_play);
DeclareCommand("media pause", media_pause);
DeclareCommand("toggle media play/pause", media_playpause);
DeclareCommand("media stop", media_stop);
DeclareCommand("media previous", media_previous);
DeclareCommand("media next", media_next);
DeclareCommand("ctrl+f", search);
DeclareAlias("search", search);
DeclareAlias("find", search);
DeclareCommand("ctrl+pgdown", next_chat);
DeclareAlias("alt+down", next_chat);
DeclareCommand("ctrl+pgup", previous_chat);
DeclareAlias("alt+up", previous_chat);
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
DeclareAlias("meta+tab", next_chat);
DeclareAlias("meta+shift+tab", previous_chat);
DeclareAlias("meta+backtab", previous_chat);
} else {
DeclareAlias("ctrl+tab", next_chat);
DeclareAlias("ctrl+shift+tab", previous_chat);
DeclareAlias("ctrl+backtab", previous_chat);
}
// other commands here
#undef DeclareCommand #undef DeclareCommand
#undef DeclareAlias #undef DeclareAlias
} }
QStringList errors; QStringList errors;
QMap<QString, ShortcutCommands::Handler> commands; QMap<QString, ShortcutCommands::Handler> commands;
QMap<ShortcutCommands::Handler, QString> commandnames; QMap<ShortcutCommands::Handler, QString> commandnames;
QMap<QKeySequence, QShortcut*> sequences; QMap<QKeySequence, QShortcut*> sequences;
QMap<int, ShortcutCommands::Handler> handlers; QMap<int, ShortcutCommands::Handler> handlers;
QSet<QString> autoRepeatCommands = { QSet<QShortcut*> mediaShortcuts;
qsl("media_previous"),
qsl("media_next"), QSet<QString> autoRepeatCommands = {
qsl("next_chat"), qsl("media_previous"),
qsl("previous_chat"), qsl("media_next"),
}; qsl("next_chat"),
qsl("previous_chat"),
}; };
void _createCommand(const QString &command, ShortcutCommands::Handler handler) { QSet<QString> mediaCommands = {
t_assert(DataPtr != nullptr); qsl("media_play"),
t_assert(!command.isEmpty()); qsl("media_pause"),
qsl("media_playpause"),
qsl("media_stop"),
qsl("media_previous"),
qsl("media_next")
};
};
DataPtr->commands.insert(command, handler); namespace {
DataPtr->commandnames.insert(handler, command);
}
QKeySequence _setShortcut(const QString &keys, const QString &command) { void createCommand(const QString &command, ShortcutCommands::Handler handler) {
t_assert(DataPtr != nullptr); t_assert(DataPtr != nullptr);
t_assert(!command.isEmpty()); t_assert(!command.isEmpty());
if (keys.isEmpty()) return QKeySequence();
QKeySequence seq(keys, QKeySequence::PortableText); DataPtr->commands.insert(command, handler);
if (seq.isEmpty()) { DataPtr->commandnames.insert(handler, command);
DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys)); }
QKeySequence setShortcut(const QString &keys, const QString &command) {
t_assert(DataPtr != nullptr);
t_assert(!command.isEmpty());
if (keys.isEmpty()) return QKeySequence();
QKeySequence seq(keys, QKeySequence::PortableText);
if (seq.isEmpty()) {
DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys));
} else {
auto it = DataPtr->commands.constFind(command);
if (it == DataPtr->commands.cend()) {
LOG(("Warning: could not find shortcut command handler '%1'").arg(command));
} else { } else {
auto it = DataPtr->commands.constFind(command); auto shortcut = std_::make_unique<QShortcut>(seq, App::wnd(), nullptr, nullptr, Qt::ApplicationShortcut);
if (it == DataPtr->commands.cend()) { if (!DataPtr->autoRepeatCommands.contains(command)) {
LOG(("Warning: could not find shortcut command handler '%1'").arg(command)); shortcut->setAutoRepeat(false);
}
auto isMediaShortcut = DataPtr->mediaCommands.contains(command);
if (isMediaShortcut) {
shortcut->setEnabled(false);
}
int shortcutId = shortcut->id();
if (!shortcutId) {
DataPtr->errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
} else { } else {
QShortcut *shortcut(new QShortcut(seq, App::wnd(), nullptr, nullptr, Qt::ApplicationShortcut)); auto seqIt = DataPtr->sequences.find(seq);
if (!DataPtr->autoRepeatCommands.contains(command)) { if (seqIt == DataPtr->sequences.cend()) {
shortcut->setAutoRepeat(false); seqIt = DataPtr->sequences.insert(seq, shortcut.release());
}
int shortcutId = shortcut->id();
if (!shortcutId) {
DataPtr->errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
} else { } else {
QMap<QKeySequence, QShortcut*>::iterator seqIt = DataPtr->sequences.find(seq); auto oldShortcut = seqIt.value();
if (seqIt == DataPtr->sequences.cend()) { seqIt.value() = shortcut.release();
seqIt = DataPtr->sequences.insert(seq, shortcut); destroyShortcut(oldShortcut);
} else { }
DataPtr->handlers.remove(seqIt.value()->id()); DataPtr->handlers.insert(shortcutId, it.value());
delete seqIt.value(); if (isMediaShortcut) {
seqIt.value() = shortcut; DataPtr->mediaShortcuts.insert(seqIt.value());
}
DataPtr->handlers.insert(shortcutId, it.value());
} }
} }
} }
return seq;
} }
return seq;
}
QKeySequence _removeShortcut(const QString &keys) { QKeySequence removeShortcut(const QString &keys) {
t_assert(DataPtr != nullptr); t_assert(DataPtr != nullptr);
if (keys.isEmpty()) return QKeySequence(); if (keys.isEmpty()) return QKeySequence();
QKeySequence seq(keys, QKeySequence::PortableText); QKeySequence seq(keys, QKeySequence::PortableText);
if (seq.isEmpty()) { if (seq.isEmpty()) {
DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys)); DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys));
} else { } else {
QMap<QKeySequence, QShortcut*>::iterator seqIt = DataPtr->sequences.find(seq); auto seqIt = DataPtr->sequences.find(seq);
if (seqIt != DataPtr->sequences.cend()) { if (seqIt != DataPtr->sequences.cend()) {
DataPtr->handlers.remove(seqIt.value()->id()); auto shortcut = seqIt.value();
delete seqIt.value(); DataPtr->sequences.erase(seqIt);
DataPtr->sequences.erase(seqIt); destroyShortcut(shortcut);
}
} }
return seq;
} }
return seq;
}
void start() { void destroyShortcut(QShortcut *shortcut) {
t_assert(Global::started()); t_assert(DataPtr != nullptr);
new DataStruct(); DataPtr->handlers.remove(shortcut->id());
DataPtr->mediaShortcuts.remove(shortcut);
delete shortcut;
}
// write default shortcuts to a file if they are not there already } // namespace
bool defaultValid = false;
QFile defaultFile(cWorkingDir() + qsl("tdata/shortcuts-default.json"));
if (defaultFile.open(QIODevice::ReadOnly)) {
QJsonParseError error = { 0, QJsonParseError::NoError };
QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(defaultFile.readAll()), &error);
defaultFile.close();
if (error.error == QJsonParseError::NoError && doc.isArray()) { void start() {
QJsonArray shortcuts(doc.array()); t_assert(Global::started());
if (!shortcuts.isEmpty() && (*shortcuts.constBegin()).isObject()) {
QJsonObject versionObject((*shortcuts.constBegin()).toObject()); new DataStruct();
QJsonObject::const_iterator version = versionObject.constFind(qsl("version"));
if (version != versionObject.constEnd() && (*version).isString() && (*version).toString() == QString::number(AppVersion)) { // write default shortcuts to a file if they are not there already
defaultValid = true; bool defaultValid = false;
} QFile defaultFile(cWorkingDir() + qsl("tdata/shortcuts-default.json"));
if (defaultFile.open(QIODevice::ReadOnly)) {
QJsonParseError error = { 0, QJsonParseError::NoError };
QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(defaultFile.readAll()), &error);
defaultFile.close();
if (error.error == QJsonParseError::NoError && doc.isArray()) {
QJsonArray shortcuts(doc.array());
if (!shortcuts.isEmpty() && (*shortcuts.constBegin()).isObject()) {
QJsonObject versionObject((*shortcuts.constBegin()).toObject());
QJsonObject::const_iterator version = versionObject.constFind(qsl("version"));
if (version != versionObject.constEnd() && (*version).isString() && (*version).toString() == QString::number(AppVersion)) {
defaultValid = true;
} }
} }
} }
if (!defaultValid && defaultFile.open(QIODevice::WriteOnly)) { }
const char *defaultHeader = "\ if (!defaultValid && defaultFile.open(QIODevice::WriteOnly)) {
const char *defaultHeader = "\
// This is a list of default shortcuts for Telegram Desktop\n\ // This is a list of default shortcuts for Telegram Desktop\n\
// Please don't modify it, its content is not used in any way\n\ // Please don't modify it, its content is not used in any way\n\
// You can place your own shortcuts in the 'shortcuts-custom.json' file\n\n"; // You can place your own shortcuts in the 'shortcuts-custom.json' file\n\n";
defaultFile.write(defaultHeader); defaultFile.write(defaultHeader);
QJsonArray shortcuts; QJsonArray shortcuts;
QJsonObject version; QJsonObject version;
version.insert(qsl("version"), QString::number(AppVersion)); version.insert(qsl("version"), QString::number(AppVersion));
shortcuts.push_back(version); shortcuts.push_back(version);
for (QMap<QKeySequence, QShortcut*>::const_iterator i = DataPtr->sequences.cbegin(), e = DataPtr->sequences.cend(); i != e; ++i) { for (auto i = DataPtr->sequences.cbegin(), e = DataPtr->sequences.cend(); i != e; ++i) {
QMap<int, ShortcutCommands::Handler>::const_iterator h = DataPtr->handlers.constFind(i.value()->id()); auto h = DataPtr->handlers.constFind(i.value()->id());
if (h != DataPtr->handlers.cend()) { if (h != DataPtr->handlers.cend()) {
QMap<ShortcutCommands::Handler, QString>::const_iterator n = DataPtr->commandnames.constFind(h.value()); auto n = DataPtr->commandnames.constFind(h.value());
if (n != DataPtr->commandnames.cend()) { if (n != DataPtr->commandnames.cend()) {
QJsonObject entry; QJsonObject entry;
entry.insert(qsl("keys"), i.key().toString().toLower()); entry.insert(qsl("keys"), i.key().toString().toLower());
entry.insert(qsl("command"), n.value()); entry.insert(qsl("command"), n.value());
shortcuts.append(entry); shortcuts.append(entry);
}
} }
} }
QJsonDocument doc;
doc.setArray(shortcuts);
defaultFile.write(doc.toJson(QJsonDocument::Indented));
defaultFile.close();
} }
// read custom shortcuts from file if it exists or write an empty custom shortcuts file QJsonDocument doc;
QFile customFile(cWorkingDir() + qsl("tdata/shortcuts-custom.json")); doc.setArray(shortcuts);
if (customFile.exists()) { defaultFile.write(doc.toJson(QJsonDocument::Indented));
if (customFile.open(QIODevice::ReadOnly)) { defaultFile.close();
QJsonParseError error = { 0, QJsonParseError::NoError }; }
QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(customFile.readAll()), &error);
customFile.close();
if (error.error != QJsonParseError::NoError) { // read custom shortcuts from file if it exists or write an empty custom shortcuts file
DataPtr->errors.push_back(qsl("Failed to parse! Error: %2").arg(error.errorString())); QFile customFile(cWorkingDir() + qsl("tdata/shortcuts-custom.json"));
} else if (!doc.isArray()) { if (customFile.exists()) {
DataPtr->errors.push_back(qsl("Failed to parse! Error: array expected")); if (customFile.open(QIODevice::ReadOnly)) {
} else { QJsonParseError error = { 0, QJsonParseError::NoError };
QJsonArray shortcuts = doc.array(); QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(customFile.readAll()), &error);
int limit = ShortcutsCountLimit; customFile.close();
for (QJsonArray::const_iterator i = shortcuts.constBegin(), e = shortcuts.constEnd(); i != e; ++i) {
if (!(*i).isObject()) { if (error.error != QJsonParseError::NoError) {
DataPtr->errors.push_back(qsl("Bad entry! Error: object expected")); DataPtr->errors.push_back(qsl("Failed to parse! Error: %2").arg(error.errorString()));
} else if (!doc.isArray()) {
DataPtr->errors.push_back(qsl("Failed to parse! Error: array expected"));
} else {
QJsonArray shortcuts = doc.array();
int limit = ShortcutsCountLimit;
for (QJsonArray::const_iterator i = shortcuts.constBegin(), e = shortcuts.constEnd(); i != e; ++i) {
if (!(*i).isObject()) {
DataPtr->errors.push_back(qsl("Bad entry! Error: object expected"));
} else {
QKeySequence seq;
QJsonObject entry((*i).toObject());
QJsonObject::const_iterator keys = entry.constFind(qsl("keys")), command = entry.constFind(qsl("command"));
if (keys == entry.constEnd() || command == entry.constEnd() || !(*keys).isString() || (!(*command).isString() && !(*command).isNull())) {
DataPtr->errors.push_back(qsl("Bad entry! {\"keys\": \"...\", \"command\": [ \"...\" | null ]} expected"));
} else if ((*command).isNull()) {
seq = removeShortcut((*keys).toString());
} else { } else {
QKeySequence seq; seq = setShortcut((*keys).toString(), (*command).toString());
QJsonObject entry((*i).toObject()); }
QJsonObject::const_iterator keys = entry.constFind(qsl("keys")), command = entry.constFind(qsl("command")); if (!--limit) {
if (keys == entry.constEnd() || command == entry.constEnd() || !(*keys).isString() || (!(*command).isString() && !(*command).isNull())) { DataPtr->errors.push_back(qsl("Too many entries! Limit is %1").arg(ShortcutsCountLimit));
DataPtr->errors.push_back(qsl("Bad entry! {\"keys\": \"...\", \"command\": [ \"...\" | null ]} expected")); break;
} else if ((*command).isNull()) {
seq = _removeShortcut((*keys).toString());
} else {
seq = _setShortcut((*keys).toString(), (*command).toString());
}
if (!--limit) {
DataPtr->errors.push_back(qsl("Too many entries! Limit is %1").arg(ShortcutsCountLimit));
break;
}
} }
} }
} }
} else {
DataPtr->errors.push_back(qsl("Could not read the file!"));
} }
if (!DataPtr->errors.isEmpty()) { } else {
DataPtr->errors.push_front(qsl("While reading file '%1'...").arg(customFile.fileName())); DataPtr->errors.push_back(qsl("Could not read the file!"));
} }
} else if (customFile.open(QIODevice::WriteOnly)) { if (!DataPtr->errors.isEmpty()) {
const char *customContent = "\ DataPtr->errors.push_front(qsl("While reading file '%1'...").arg(customFile.fileName()));
}
} else if (customFile.open(QIODevice::WriteOnly)) {
const char *customContent = "\
// This is a list of your own shortcuts for Telegram Desktop\n\ // This is a list of your own shortcuts for Telegram Desktop\n\
// You can see full list of commands in the 'shortcuts-default.json' file\n\ // You can see full list of commands in the 'shortcuts-default.json' file\n\
// Place a null value instead of a command string to switch the shortcut off\n\n\ // Place a null value instead of a command string to switch the shortcut off\n\n\
@ -447,41 +484,55 @@ namespace Shortcuts {
// \"keys\": \"ctrl+q\"\n\ // \"keys\": \"ctrl+q\"\n\
// }\n\ // }\n\
]\n"; ]\n";
customFile.write(customContent); customFile.write(customContent);
customFile.close(); customFile.close();
}
} }
const QStringList &errors() {
t_assert(DataPtr != nullptr);
return DataPtr->errors;
}
bool launch(int shortcutId) {
t_assert(DataPtr != nullptr);
QMap<int, ShortcutCommands::Handler>::const_iterator it = DataPtr->handlers.constFind(shortcutId);
if (it == DataPtr->handlers.cend()) {
return false;
}
(*it.value())();
return true;
}
bool launch(const QString &command) {
t_assert(DataPtr != nullptr);
QMap<QString, ShortcutCommands::Handler>::const_iterator it = DataPtr->commands.constFind(command);
if (it == DataPtr->commands.cend()) {
return false;
}
(*it.value())();
return true;
}
void finish() {
delete DataPtr;
DataPtr = nullptr;
}
} }
const QStringList &errors() {
t_assert(DataPtr != nullptr);
return DataPtr->errors;
}
bool launch(int shortcutId) {
t_assert(DataPtr != nullptr);
auto it = DataPtr->handlers.constFind(shortcutId);
if (it == DataPtr->handlers.cend()) {
return false;
}
(*it.value())();
return true;
}
bool launch(const QString &command) {
t_assert(DataPtr != nullptr);
auto it = DataPtr->commands.constFind(command);
if (it == DataPtr->commands.cend()) {
return false;
}
(*it.value())();
return true;
}
void enableMediaShortcuts() {
if (!DataPtr) return;
for_const (auto shortcut, DataPtr->mediaShortcuts) {
shortcut->setEnabled(true);
}
}
void disableMediaShortcuts() {
if (!DataPtr) return;
for_const (auto shortcut, DataPtr->mediaShortcuts) {
shortcut->setEnabled(false);
}
}
void finish() {
delete DataPtr;
DataPtr = nullptr;
}
} // namespace Shortcuts

View file

@ -28,6 +28,12 @@ namespace Shortcuts {
bool launch(int shortcutId); bool launch(int shortcutId);
bool launch(const QString &command); bool launch(const QString &command);
// Media shortcuts are not enabled by default, because other
// applications also use them. They are enabled only when
// the in-app player is active and disabled back after.
void enableMediaShortcuts();
void disableMediaShortcuts();
void finish(); void finish();
} }

View file

@ -21,22 +21,39 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#define NOMINMAX // no min() and max() macro declarations #define NOMINMAX // no min() and max() macro declarations
#define __HUGE #define __HUGE
#define __STDC_FORMAT_MACROS // fix breakpad for mac
// Fix Google Breakpad build for Mac App Store version
#ifdef Q_OS_MAC
#define __STDC_FORMAT_MACROS
#endif // Q_OS_MAC
#ifdef __cplusplus #ifdef __cplusplus
#include <cmath> #include <cmath>
// False positive warning in clang for QMap member function value:
// const T QMap<Key, T>::value(const Key &akey, const T &adefaultValue)
// fires with "Returning address of local temporary object" which is not true.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-stack-address"
#endif // __clang__
#include <QtCore/QtCore> #include <QtCore/QtCore>
#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__
#include <QtWidgets/QtWidgets> #include <QtWidgets/QtWidgets>
#include <QtNetwork/QtNetwork> #include <QtNetwork/QtNetwork>
#include "basic_types.h" #include "core/basic_types.h"
#include "config.h" #include "config.h"
#include "mtproto/facade.h" #include "mtproto/facade.h"
#include "ui/style_core.h" #include "ui/style.h"
#include "ui/twidget.h" #include "ui/twidget.h"
#include "ui/animation.h" #include "ui/animation.h"
#include "ui/flatinput.h" #include "ui/flatinput.h"
@ -46,7 +63,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/popupmenu.h" #include "ui/popupmenu.h"
#include "ui/scrollarea.h" #include "ui/scrollarea.h"
#include "ui/images.h" #include "ui/images.h"
#include "ui/text.h" #include "ui/text/text.h"
#include "ui/flatlabel.h" #include "ui/flatlabel.h"
#include "app.h" #include "app.h"

View file

@ -28,11 +28,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwidget.h" #include "mainwidget.h"
#include "application.h" #include "application.h"
#include "fileuploader.h" #include "fileuploader.h"
#include "window.h" #include "mainwindow.h"
#include "ui/filedialog.h" #include "ui/filedialog.h"
#include "apiwrap.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "audio.h" #include "audio.h"
#include "localstorage.h" #include "localstorage.h"

View file

@ -1312,3 +1312,63 @@ struct MessageCursor {
inline bool operator==(const MessageCursor &a, const MessageCursor &b) { inline bool operator==(const MessageCursor &a, const MessageCursor &b) {
return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll); return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll);
} }
struct LocationCoords {
LocationCoords() : lat(0), lon(0) {
}
LocationCoords(float64 lat, float64 lon) : lat(lat), lon(lon) {
}
LocationCoords(const MTPDgeoPoint &point) : lat(point.vlat.v), lon(point.vlong.v) {
}
float64 lat, lon;
};
inline bool operator==(const LocationCoords &a, const LocationCoords &b) {
return (a.lat == b.lat) && (a.lon == b.lon);
}
inline bool operator<(const LocationCoords &a, const LocationCoords &b) {
return (a.lat < b.lat) || ((a.lat == b.lat) && (a.lon < b.lon));
}
inline uint qHash(const LocationCoords &t, uint seed = 0) {
return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed);
}
struct LocationData {
LocationData(const LocationCoords &coords) : coords(coords), loading(false) {
}
LocationCoords coords;
ImagePtr thumb;
bool loading;
void load();
};
class LocationClickHandler : public ClickHandler {
public:
LocationClickHandler(const LocationCoords &coords) : _coords(coords) {
setup();
}
QString copyToClipboardContextItem() const override;
void copyToClipboard() const override {
if (!_text.isEmpty()) {
QApplication::clipboard()->setText(_text);
}
}
QString tooltip() const override {
return QString();
}
QString text() const override {
return _text;
}
void onClick(Qt::MouseButton button) const override;
private:
void setup();
LocationCoords _coords;
QString _text;
};

View file

@ -111,7 +111,7 @@ void SysBtn::step_color(float64 ms, bool timer) {
if (timer) update(); if (timer) update();
} }
MinimizeBtn::MinimizeBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysMin), wnd(window) { MinimizeBtn::MinimizeBtn(QWidget *parent, MainWindow *window) : SysBtn(parent, st::sysMin), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }
@ -119,7 +119,7 @@ void MinimizeBtn::onClick() {
wnd->setWindowState(Qt::WindowMinimized); wnd->setWindowState(Qt::WindowMinimized);
} }
MaximizeBtn::MaximizeBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysMax), wnd(window) { MaximizeBtn::MaximizeBtn(QWidget *parent, MainWindow *window) : SysBtn(parent, st::sysMax), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }
@ -127,7 +127,7 @@ void MaximizeBtn::onClick() {
wnd->setWindowState(Qt::WindowMaximized); wnd->setWindowState(Qt::WindowMaximized);
} }
RestoreBtn::RestoreBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysRes), wnd(window) { RestoreBtn::RestoreBtn(QWidget *parent, MainWindow *window) : SysBtn(parent, st::sysRes), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }
@ -135,7 +135,7 @@ void RestoreBtn::onClick() {
wnd->setWindowState(Qt::WindowNoState); wnd->setWindowState(Qt::WindowNoState);
} }
CloseBtn::CloseBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysCls), wnd(window) { CloseBtn::CloseBtn(QWidget *parent, MainWindow *window) : SysBtn(parent, st::sysCls), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }
@ -143,7 +143,7 @@ void CloseBtn::onClick() {
wnd->close(); wnd->close();
} }
UpdateBtn::UpdateBtn(QWidget *parent, Window *window, const QString &text) : SysBtn(parent, st::sysUpd, text), wnd(window) { UpdateBtn::UpdateBtn(QWidget *parent, MainWindow *window, const QString &text) : SysBtn(parent, st::sysUpd, text), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }
@ -161,7 +161,7 @@ void UpdateBtn::onClick() {
App::quit(); App::quit();
} }
LockBtn::LockBtn(QWidget *parent, Window *window) : SysBtn(parent, st::sysLock), wnd(window) { LockBtn::LockBtn(QWidget *parent, MainWindow *window) : SysBtn(parent, st::sysLock), wnd(window) {
connect(this, SIGNAL(clicked()), this, SLOT(onClick())); connect(this, SIGNAL(clicked()), this, SLOT(onClick()));
} }

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/animation.h" #include "ui/animation.h"
#include "ui/button.h" #include "ui/button.h"
class Window; class MainWindow;
class SysBtn : public Button { class SysBtn : public Button {
Q_OBJECT Q_OBJECT
@ -62,7 +62,7 @@ class MinimizeBtn : public SysBtn {
public: public:
MinimizeBtn(QWidget *parent, Window *window); MinimizeBtn(QWidget *parent, MainWindow *window);
public slots: public slots:
@ -70,7 +70,7 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };
class MaximizeBtn : public SysBtn { class MaximizeBtn : public SysBtn {
@ -78,7 +78,7 @@ class MaximizeBtn : public SysBtn {
public: public:
MaximizeBtn(QWidget *parent, Window *window); MaximizeBtn(QWidget *parent, MainWindow *window);
public slots: public slots:
@ -86,7 +86,7 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };
class RestoreBtn : public SysBtn { class RestoreBtn : public SysBtn {
@ -94,7 +94,7 @@ class RestoreBtn : public SysBtn {
public: public:
RestoreBtn(QWidget *parent, Window *window); RestoreBtn(QWidget *parent, MainWindow *window);
public slots: public slots:
@ -102,7 +102,7 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };
class CloseBtn : public SysBtn { class CloseBtn : public SysBtn {
@ -110,7 +110,7 @@ class CloseBtn : public SysBtn {
public: public:
CloseBtn(QWidget *parent, Window *window); CloseBtn(QWidget *parent, MainWindow *window);
public slots: public slots:
@ -118,7 +118,7 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };
class UpdateBtn : public SysBtn { class UpdateBtn : public SysBtn {
@ -126,7 +126,7 @@ class UpdateBtn : public SysBtn {
public: public:
UpdateBtn(QWidget *parent, Window *window, const QString &text = QString()); UpdateBtn(QWidget *parent, MainWindow *window, const QString &text = QString());
public slots: public slots:
@ -134,7 +134,7 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };
class LockBtn : public SysBtn { class LockBtn : public SysBtn {
@ -142,7 +142,7 @@ class LockBtn : public SysBtn {
public: public:
LockBtn(QWidget *parent, Window *window); LockBtn(QWidget *parent, MainWindow *window);
public slots: public slots:
@ -150,5 +150,5 @@ public slots:
private: private:
Window *wnd; MainWindow *wnd;
}; };

View file

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "title.h" #include "title.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "boxes/contactsbox.h" #include "boxes/contactsbox.h"
#include "boxes/aboutbox.h" #include "boxes/aboutbox.h"
@ -49,7 +49,7 @@ void TitleHider::setLevel(float64 level) {
update(); update();
} }
TitleWidget::TitleWidget(Window *window) : TWidget(window) TitleWidget::TitleWidget(MainWindow *window) : TWidget(window)
, wnd(window) , wnd(window)
, hideLevel(0) , hideLevel(0)
, hider(0) , hider(0)

View file

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
#include "sysbuttons.h" #include "sysbuttons.h"
class Window; class MainWindow;
class TitleHider : public QWidget { class TitleHider : public QWidget {
public: public:
@ -44,7 +44,7 @@ class TitleWidget : public TWidget {
public: public:
TitleWidget(Window *parent); TitleWidget(MainWindow *parent);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);
@ -78,7 +78,7 @@ signals:
private: private:
Window *wnd; MainWindow *wnd;
style::color statusColor; style::color statusColor;

View file

@ -30,7 +30,7 @@ extern "C" {
} }
#include "mainwidget.h" #include "mainwidget.h"
#include "window.h" #include "mainwindow.h"
namespace { namespace {
AnimationManager *_manager = 0; AnimationManager *_manager = 0;

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "basic_types.h" #include "core/basic_types.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QColor> #include <QtGui/QColor>

View file

@ -21,6 +21,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "ui/buttons/peer_avatar_button.h" #include "ui/buttons/peer_avatar_button.h"
#include "structs.h"
namespace Ui {
PeerAvatarButton::PeerAvatarButton(QWidget *parent, PeerData *peer, const style::PeerAvatarButton &st) : Button(parent) PeerAvatarButton::PeerAvatarButton(QWidget *parent, PeerData *peer, const style::PeerAvatarButton &st) : Button(parent)
, _peer(peer) , _peer(peer)
, _st(st) { , _st(st) {
@ -33,3 +37,5 @@ void PeerAvatarButton::paintEvent(QPaintEvent *e) {
_peer->paintUserpic(p, _st.photoSize, (_st.size - _st.photoSize) / 2, (_st.size - _st.photoSize) / 2); _peer->paintUserpic(p, _st.photoSize, (_st.size - _st.photoSize) / 2, (_st.size - _st.photoSize) / 2);
} }
} }
} // namespace Ui

View file

@ -22,7 +22,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/button.h" #include "ui/button.h"
#include "ui/style.h" #include "ui/style.h"
#include "structs.h"
class PeerData;
namespace Ui {
class PeerAvatarButton : public Button { class PeerAvatarButton : public Button {
public: public:
@ -38,3 +41,5 @@ private:
const style::PeerAvatarButton &_st; const style::PeerAvatarButton &_st;
}; };
} // namespace Ui

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "ui/text.h" #include "ui/text/text.h"
void emojiInit(); void emojiInit();
EmojiPtr emojiGet(uint32 code); EmojiPtr emojiGet(uint32 code);

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/style.h" #include "ui/style.h"
#include "flatinput.h" #include "flatinput.h"
#include "window.h" #include "mainwindow.h"
#include "countryinput.h" #include "countryinput.h"
#include "lang.h" #include "lang.h"

View file

@ -31,14 +31,14 @@ public:
FlatInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString()); FlatInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString());
bool event(QEvent *e); bool event(QEvent *e) override;
void touchEvent(QTouchEvent *e); void touchEvent(QTouchEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e) override;
void focusInEvent(QFocusEvent *e); void focusInEvent(QFocusEvent *e) override;
void focusOutEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e) override;
void keyPressEvent(QKeyEvent *e); void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e); void contextMenuEvent(QContextMenuEvent *e) override;
void notaBene(); void notaBene();
@ -52,8 +52,8 @@ public:
void step_appearance(float64 ms, bool timer); void step_appearance(float64 ms, bool timer);
QSize sizeHint() const; QSize sizeHint() const override;
QSize minimumSizeHint() const; QSize minimumSizeHint() const override;
void customUpDown(bool isCustom); void customUpDown(bool isCustom);
const QString &getLastText() const { const QString &getLastText() const {
@ -507,14 +507,14 @@ public:
MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder = QString(), const QString &val = QString()); MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder = QString(), const QString &val = QString());
bool event(QEvent *e); bool event(QEvent *e) override;
void touchEvent(QTouchEvent *e); void touchEvent(QTouchEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e) override;
void focusInEvent(QFocusEvent *e); void focusInEvent(QFocusEvent *e) override;
void focusOutEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e) override;
void keyPressEvent(QKeyEvent *e); void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e); void contextMenuEvent(QContextMenuEvent *e) override;
void showError(); void showError();
@ -528,8 +528,8 @@ public:
void step_placeholderShift(float64 ms, bool timer); void step_placeholderShift(float64 ms, bool timer);
void step_border(float64 ms, bool timer); void step_border(float64 ms, bool timer);
QSize sizeHint() const; QSize sizeHint() const override;
QSize minimumSizeHint() const; QSize minimumSizeHint() const override;
void customUpDown(bool isCustom); void customUpDown(bool isCustom);
const QString &getLastText() const { const QString &getLastText() const {

View file

@ -110,10 +110,12 @@ void FlatLabel::updateHover() {
QPoint m(mapFromGlobal(_lastMousePos)); QPoint m(mapFromGlobal(_lastMousePos));
textstyleSet(&_tst); textstyleSet(&_tst);
ClickHandlerPtr handler = _text.link(m.x(), m.y(), width(), _st.align); Text::StateRequest request;
request.align = _st.align;
auto state = _text.getState(m.x(), m.y(), width(), request);
textstyleRestore(); textstyleRestore();
ClickHandler::setActive(handler, this); ClickHandler::setActive(state.link, this);
} }
void FlatLabel::setOpacity(float64 o) { void FlatLabel::setOpacity(float64 o) {

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "flattextarea.h" #include "flattextarea.h"
#include "ui/style.h" #include "ui/style.h"
#include "window.h" #include "mainwindow.h"
FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent) FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent)
, _oldtext(v) , _oldtext(v)

View file

@ -35,16 +35,16 @@ public:
FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &ph = QString(), const QString &val = QString()); FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &ph = QString(), const QString &val = QString());
bool viewportEvent(QEvent *e); bool viewportEvent(QEvent *e) override;
void touchEvent(QTouchEvent *e); void touchEvent(QTouchEvent *e);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e) override;
void focusInEvent(QFocusEvent *e); void focusInEvent(QFocusEvent *e) override;
void focusOutEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e) override;
void keyPressEvent(QKeyEvent *e); void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e) override;
void mousePressEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e) override;
void dropEvent(QDropEvent *e); void dropEvent(QDropEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e); void contextMenuEvent(QContextMenuEvent *e) override;
void setMaxLength(int32 maxLength); void setMaxLength(int32 maxLength);
void setMinHeight(int32 minHeight); void setMinHeight(int32 minHeight);
@ -62,8 +62,8 @@ public:
void step_appearance(float64 ms, bool timer); void step_appearance(float64 ms, bool timer);
QSize sizeHint() const; QSize sizeHint() const override;
QSize minimumSizeHint() const; QSize minimumSizeHint() const override;
EmojiPtr getSingleEmoji() const; EmojiPtr getSingleEmoji() const;
QString getMentionHashtagBotCommandPart(bool &start) const; QString getMentionHashtagBotCommandPart(bool &start) const;
@ -82,9 +82,9 @@ public:
void parseLinks(); void parseLinks();
QStringList linksList() const; QStringList linksList() const;
void insertFromMimeData(const QMimeData *source); void insertFromMimeData(const QMimeData *source) override;
QMimeData *createMimeDataFromSelection() const; QMimeData *createMimeDataFromSelection() const override;
enum class SubmitSettings { enum class SubmitSettings {
None, None,
@ -125,7 +125,7 @@ protected:
void insertEmoji(EmojiPtr emoji, QTextCursor c); void insertEmoji(EmojiPtr emoji, QTextCursor c);
QVariant loadResource(int type, const QUrl &name); QVariant loadResource(int type, const QUrl &name) override;
void checkContentHeight(); void checkContentHeight();

View file

@ -17,7 +17,7 @@
*/ */
#pragma once #pragma once
#include "text.h" #include "ui/text/text.h"
class PopupMenu : public TWidget { class PopupMenu : public TWidget {
Q_OBJECT Q_OBJECT

View file

@ -20,5 +20,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "../GeneratedFiles/style_classes.h" #include "ui/style_core.h"
#include "../GeneratedFiles/style_auto.h" #include "GeneratedFiles/style_classes.h"
#include "GeneratedFiles/style_auto.h"

View file

@ -134,24 +134,13 @@ namespace style {
return *this; return *this;
} }
void Color::set(const QColor &newv) { namespace {
if (!owner) { inline uint32 colorKey(uchar r, uchar g, uchar b, uchar a) {
ptr = new ColorData(*ptr); return (((((uint32(r) << 8) | uint32(g)) << 8) | uint32(b)) << 8) | uint32(a);
owner = true;
}
ptr->set(newv);
} }
void Color::set(uchar r, uchar g, uchar b, uchar a) {
if (!owner) {
ptr = new ColorData(*ptr);
owner = true;
}
ptr->set(QColor(r, g, b, a));
} }
void Color::init(uchar r, uchar g, uchar b, uchar a) { void Color::init(uchar r, uchar g, uchar b, uchar a) {
uint32 key = _colorKey(r, g, b, a); uint32 key = colorKey(r, g, b, a);
ColorDatas::const_iterator i = _colorsMap.constFind(key); ColorDatas::const_iterator i = _colorsMap.constFind(key);
if (i == _colorsMap.cend()) { if (i == _colorsMap.cend()) {
i = _colorsMap.insert(key, new ColorData(r, g, b, a)); i = _colorsMap.insert(key, new ColorData(r, g, b, a));

View file

@ -46,7 +46,7 @@ inline QRect centerrect(const QRect &inRect, const QRect &rect) {
} }
namespace style { namespace style {
class FontData; class FontData;
class Font { class Font {
public: public:
@ -189,7 +189,7 @@ namespace style {
bool owner; bool owner;
void init(uchar r, uchar g, uchar b, uchar a); void init(uchar r, uchar g, uchar b, uchar a);
friend void startManager(); friend void startManager();
Color(ColorData *p) : ptr(p) { Color(ColorData *p) : ptr(p) {
@ -213,7 +213,7 @@ namespace style {
ColorData(uchar r, uchar g, uchar b, uchar a); ColorData(uchar r, uchar g, uchar b, uchar a);
void set(const QColor &c); void set(const QColor &c);
friend class Color; friend class Color;
}; };

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more